简体   繁体   English

UIO 和 msync:为什么即使地址是 PAGESIZE 的倍数,msync 也会返回“无效参数”

[英]UIO and msync: Why does msync return "invalid argument" even though the address is a multiple of PAGESIZE

Linux version: 4.19 Linux 版本:4.19
Platform: Xilinx Ultrascale+ Zynq平台:Xilinx Ultrascale+ Zynq

In the programmable logic I've created a memory mapped device located at physical address 0xA0001000.在可编程逻辑中,我创建了一个位于物理地址 0xA0001000 的内存映射设备。 I'm using uio_pdrv_genirq as my device driver.我使用 uio_pdrv_genirq 作为我的设备驱动程序。 The device shows up as uio0 and I'm ready to read and write to it, using mmap.该设备显示为 uio0,我已准备好使用 mmap 对其进行读写。 I want to be able to guarantee that any writes that I make get written to the device right away instead of waiting for Linux to flush the dirty pages on its own.我希望能够保证我所做的任何写入都会立即写入设备,而不是等待 Linux 自行刷新脏页。 For that I should use msync according to all my research.为此,我应该根据我所有的研究使用 msync。 But I keep getting an error when I do that.但是当我这样做时,我不断收到错误消息。 Here's my test program:这是我的测试程序:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

void main() {
    int fid;
    int rval;
    char *data;
    int idx;

    printf("Open UIO Device \n");
    fid= open("/dev/uio0", O_RDWR | O_SYNC);

    data= mmap(NULL, 0x1000, PROT_WRITE|PROT_READ, MAP_SHARED, fid, 0);
    if(MAP_FAILED == data) {
        printf("Error code when mapping! %s", strerror(errno));
    }
    printf("addr= 0x%8X\n", data);
    printf("pagesize= 0x%4X\n", getpagesize());

    printf("Write some data\n");
    data[11]= 0xDE;
    data[10]= 0xC0;
    data[ 9]= 0xDE;
    data[ 8]= 0xAD;

    rval= msync(data, 0x1000, MS_SYNC);
    if(-1 == rval) {
        printf("Error on msync! %s\n", strerror(errno));
    }

    if(munmap(data, 0x1000) < 0) {
        printf("munmap error! %s\n", strerror(errno));
    }

    printf("Close UIO device\n");
    rval= close(fid);
    if(rval != 0) {
        printf("UIO device close Error!\n");
    }
}

And here's the program output:这是程序输出:

mylinux:~/test-apps$ ./a.out
Open UIO Device
addr= 0xABA05000
pagesize= 0x1000
Write some data
Error on msync! Invalid argument
Close UIO device

I'm not understanding the source of this error.我不明白这个错误的来源。 The msync man pages states that this error can occur if the address is not a multiple of PAGESIZE. msync 手册页指出,如果地址不是 PAGESIZE 的倍数,则会发生此错误。 But as you can see from the example above, it is a multiple.但是正如您从上面的示例中看到的那样,它是一个倍数。 Even the physical address is a multiple of the PAGESIZE.甚至物理地址也是 PAGESIZE 的倍数。

A few other notes:其他一些注意事项:

  1. I get the same error even I remove O_SYNC from the flags to the open function.即使我从标志中删除 O_SYNC 到 open 函数,我也会遇到同样的错误。
  2. The AXI4 bus into the FPGA fabric is 128 bits, which is then converted to 32 bits by Xilinx IP blocks.进入 FPGA 架构的 AXI4 总线是 128 位,然后由 Xilinx IP 模块转换为 32 位。 I don't think this would have anything to do with my problem.我不认为这与我的问题有任何关系。

Thanks for any insights folks can provide.感谢人们提供的任何见解。

I believe the EINVAL error is because the kernel's handler for the msync syscall (in " mm/msync.c ") calls vfs_fsync_range :我相信EINVAL错误是因为内核的msync系统调用处理程序(在“ mm/msync.c ”中)调用vfs_fsync_range

            error = vfs_fsync_range(file, fstart, fend, 1);

and vfs_fsync_range (in " fs/sync.c ") is returning -EINVAL here:并且vfs_fsync_range (在“ fs/sync.c ”中)在此处返回-EINVAL

    if (!file->f_op->fsync)
        return -EINVAL;

because the UIO driver core (in " drivers/uio/uio.c " does not set the fsync file operation handler.因为 UIO 驱动核心(在“ drivers/uio/uio.c ”中没有设置fsync文件操作处理程序。


The physical memory you have mmap ed is mapped as non-cached memory in the page tables, so writes do not need to be flushed.您拥有mmap ed 的物理内存在页表中映射为非缓存内存,因此不需要刷新写入。 However, you should probably use volatile accesses to the memory mapped I/O registers.但是,您可能应该使用对内存映射 I/O 寄存器的volatile访问。 The register access functions such as readb and writeb in the kernel are architecture-specific, but invariably convert the address to a pointer to a volatile integer type (eg volatile unsigned char * , volatile unsigned short * , or volatile unsigned int * depending on the width of the register access) before accessing the memory location.内核中的readbwriteb等寄存器访问函数是特定于体系结构的,但总是将地址转换为指向volatile整数类型的指针(例如volatile unsigned char *volatile unsigned short *volatile unsigned int *取决于访问内存位置之前的寄存器访问宽度)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM