我目前正在编写一个设备驱动程序教育设备在 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()
?