Background:
I am currently writing a device driver for Edu device in qemu (RISC-V). From this question, I find that there is already a device driver for such device.
Outline:
I would like to write an 8-byte value to the memory mapped IO register (of Edu device) at address 0x80, and then read the same address to see if we can get the same value.
- Edu device introduction
- The driver code I wrote (for
read()andwrite()) - User mode code for testing
read()andwrite() - Problem I met
Edu device introduction
According to this line of the documentation of Edu device, it says size == 4 or size == 8 accesses are allowed for addresses >= 0x80. Such constraint is shown here for edu_mmio_read() and here for edu_mmio_write() in Edu device source code.
The driver code I wrote
In the driver code, for both read() and write(), it seems that it only handles reading/writing values of size 4 bytes, not 8 bytes. So I added something new to those two functions to support 8-byte values read/write:
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; } User mode code for testing
In my user mode testing code, I did the following:
// 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); Problem I met
However, when I tested the user mode code, it did write the value to address 0x80, but failed to read it. I added some printf statements and noticed that the error occurred in read(), corresponding to this line of code:
kbuf64 = ioread64(mmio + *off); I found this page talking about the differences between IO access functions, and replaced ioread64() with readq(), but still did not solve the problem. The code stopped executing when kbuf64 = ioread64(mmio + *off); is being executed. I also tried to add #define CONFIG_64BIT, but still did not solve the error.
After that, I hit Ctrl+C but was unable to stop the user mode code. All I could do was to Ctrl+A then X to stop QEMU and restart again.
Note that for 4-byte values, read or write works well with ioread32() and iowrite32().
May I know what I did wrong that caused the error of ioread64()?
Related questions 4 Write to QEMU guest system registers & memory? 4 Use 32bit ops to perform ioread/write64 1 ioread32 followed by iowrite32 not giving same value Related questions 4 Write to QEMU guest system registers & memory? 4 Use 32bit ops to perform ioread/write64 1 ioread32 followed by iowrite32 not giving same value 2 Unable to read from Disk in QEmu 0 Linux device driver - memory mapped I/O example discussion 3 Written Buffer to I2C Not Returned when Read 11 Why does /proc/iomem only show zeros instead addresses in 64bit linux? 5 Qemu plugin functions - how to access guest memory and registers 0 c++ memory write bytes to address with Windows kernel driver 1 reading Memory-Mapped IO registers How to (from datasheet) and using them in mmap Load 7 more related questions Show fewer related questions
Reset to default