How to use ioread64() and iowrite64() for accessing IO memory?

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() and write())
  • User mode code for testing read() and write()
  • 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()?

3

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

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like