QEMU 中的 Edu 设备中 IO 访问 64 位值的问题

QEMU 中的 Edu 设备中 IO 访问 64 位值的问题

我目前正在编写一个设备驱动程序教育设备在 qemu (RISC-V) 中。由此问题,我发现已经有一个设备驱动对于这样的设备。

根据Edu 设备文档的这一行,它表示地址 >= 0x80 允许进行 size == 4 或 size == 8 访问。这样的约束如图所示这里是为了edu_mmio_read()这里是为了edu_mmio_write()在 Edu 设备源代码中。

在里面驱动程序代码,对于 和read()write()它似乎只处理大小为 4 字节的读/写值,而不是 8 字节。因此,我向这两个函数添加了一些新内容以支持 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);

但是,当我测试用户模式代码时,它确实将值写入了 address 0x80,但无法读取它。我添加了一些 printf 语句,并注意到错误发生在read(),对应于这行代码:

kbuf64 = ioread64(mmio + *off);

我找到了这个讲了IO访问函数的区别,并替换ioread64()readq(),但仍然没有解决问题。代码在kbuf64 = ioread64(mmio + *off);执行时停止执行。我也尝试添加#define CONFIG_64BIT,但还是没有解决错误。

之后,我按 Ctrl+C 但无法停止用户模式代码。我所能做的就是按 Ctrl+A 然后按 X 来停止 QEMU 并重新启动。

请注意,对于 4 字节值,读或写可以与ioread32()和配合使用iowrite32()

我可以知道我做错了什么导致了错误吗ioread64()

相关内容