QEMU의 Edu 장치에서 64비트 값에 대한 IO 액세스 문제

QEMU의 Edu 장치에서 64비트 값에 대한 IO 액세스 문제

현재 장치 드라이버를 작성 중입니다.교육 장비qemu(RISC-V)에서. 따라서질문, 이미 하나가 있는 것을 확인했습니다.장치 드라이버그러한 장비의 경우.

~에 따르면Edu 장치 문서의 이 줄이는 주소 >= 0x80이 크기 == 4 또는 크기 == 8 액세스를 허용함을 의미합니다. 이러한 제약 조건은 그림에 나와 있습니다.여기는edu_mmio_read()그리고여기는edu_mmio_write()Edu 장치 소스 코드에서.

내부에드라이버 코드, 및 의 경우 read()8 write()바이트가 아닌 4바이트 크기의 읽기/쓰기 값만 처리하는 것으로 보입니다. 따라서 8바이트 값 읽기/쓰기를 지원하기 위해 이 두 함수에 새로운 것을 추가했습니다.

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    ssize_t ret;
    u32 kbuf32;
    u64 kbuf64;

    if (*off % 4 || len == 0) {
        ret = 0;
    } else {
        switch (len)
        {
        case 4:
            kbuf32 = ioread32(mmio + *off);
            if (copy_to_user(buf, (void *)&kbuf32, len)) {
                ret = -EFAULT;
            } else {
                ret = 4;
                (*off)++;
            }
            break;
        
        case 8:
            kbuf64 = ioread64(mmio + *off);
            if (copy_to_user(buf, (void *)&kbuf64, len)) {
                ret = -EFAULT;
            } else {
                ret = 8;
                (*off)++;
            }
            break;

        default:
            ret = -EFAULT;
            break;
        }
    }
    return ret;
}


static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
    ssize_t ret;
    u32 kbuf32; /* for size == 4 */
    u64 kbuf64; /* for size == 8 */
    
    ret = len;

    if (!(*off % 4)) {
        switch (len) {
        case 4:
            /* copy buf to kbuf32 */
            if (copy_from_user((void *)&kbuf32, buf, len)) {
                ret = -EFAULT;
            } else {
                iowrite32(kbuf32, mmio + *off);
            }
            break;
        
        case 8:
            if (copy_from_user((void *)&kbuf64, buf, len)) {
                ret = -EFAULT;
            } else {
                iowrite64(kbuf64, mmio + *off);
            }
            break;
        
        default:
            ret = -EFAULT;
            break;
        }
    }
    return ret;
}

내 사용자 모드 테스트 코드에서는 다음을 수행합니다.

// open the device - succeed
// fd2 - the file descriptor representing the opened edu device

uint64_t val64 = 0x8b320000; // a random 64-bit value
unsigned long ret = -1; // retval

// write val64 to 0x80
lseek(fd2, 0x80, SEEK_SET); // seek to address 0x80 - dma.src in edu device source code (line 281)
ret = write(fd2, &val64, sizeof(uint64_t));
if(ret == -1) printf("write to dma src failed\n");
else printf("written %llx to dma src\n", val64);

// reset val64
val64 = 0;

// read what we have just written (sanity check)
lseek(fd2, 0x80, SEEK_SET);
ret = read(fd2, &ret64, sizeof(uint64_t));
if(ret == -1) printf("read from dma src failed\n");
else printf("sanity check: read dma src and we get - %llx\n", ret64);

그런데 사용자 모드 코드를 테스트하면 주소에 값을 쓰지만 0x80읽을 수는 없습니다. 몇 가지 printf 문을 추가하고 read()다음 코드 줄에 해당하는 오류가 발생했음을 확인했습니다.

kbuf64 = ioread64(mmio + *off);

나는 이것을 찾았다페이지IO 접근 기능의 차이점에 대해 이야기하고 ioread64()로 대체했지만 readq()여전히 문제가 해결되지 않았습니다. kbuf64 = ioread64(mmio + *off);실행 중에 코드 실행이 중지됩니다. 추가도 시도했지만 #define CONFIG_64BIT여전히 오류가 해결되지 않았습니다.

그런 다음 Ctrl+C를 눌러도 사용자 모드 코드를 중지할 수 없습니다. 내가 할 수 있는 일은 QEMU를 중지하고 Ctrl+A를 누른 다음 X를 눌러 다시 시작하는 것뿐이었습니다.

4바이트 값의 경우 ioread32()및 와 함께 읽기 또는 쓰기를 사용할 수 있습니다 iowrite32().

내가 뭘 잘못해서 오류가 발생했는지 알 수 있나요 ioread64()?

관련 정보