3

首先是关于我正在使用的机器的一些背景信息(它是一个带有 SoC 的 SOM,其中包括一个 FPGA 和两个 CPU,其中一个运行着一个 linux 操作系统)。

特征:

  • 板 : Microzed
  • 系统芯片:Zynq 7020
  • 操作系统:Petalinux 2019.2
  • 内核版本:4.19.0-xilinx-v2019.2
  • 处理器类型:ARMv7 处理器 rev 0 v7l (armv7l)

我在 FPGA 上实现了一个自定义外设,它为 BRAM 存储器提供标准 AXI4 接口(感谢这个组件)。该外围设备已在我的设备树中注册,并且可以通过内核的 generic-uio 驱动程序访问(有关此的更多文档)。

BRAM 内存的大小为 32kB。以下是出现在 中的映射特征/sys/class/uio/uioX/maps/map0/

  • 地址 = 0x40000000
  • 偏移量 = 0x0
  • 大小 = 0x00008000

我正在编写一个 C 代码,其目的只是为了读取这个 BRAM 内存并将里面的内容记录在一个文本文件中。为了做到这一点,我使用mmap(这里是它的手册页)来创建位于/dev/uioX(对应于我的设备)中的文件的一些内存投影。

我只想使用我需要的文件页面,更精确地映射每页的文件页面。这是我用来创建一页映射的函数:

/**
 * @brief Get a pointer to the corresponding file page
 * 
 * @param filePage file page number
 * @param fd pointer where the file descriptor will be stored
 * @return int* 
 */
int *getFilePagePointer(int *fd, unsigned int filePage)
{
    // open driver file
    *fd = open("/dev/uio1", O_RDWR);
    if (*fd == -1)
    {
        int errsv = errno;
        fprintf(stderr, "Error while opening /dev/uio1 : errno %d (%s).\n", errsv, strerror(errsv));
        exit(EXIT_FAILURE);
    }

    // choose projection parameters
    int length = sysconf(_SC_PAGE_SIZE);
    int offset = filePage * sysconf(_SC_PAGE_SIZE);

    // create mapping
    void *filePagePointer = mmap((void *)NULL, (size_t)length, PROT_READ, MAP_PRIVATE, *fd, (off_t)offset);
    if (filePagePointer == MAP_FAILED)
    {
        int errsv = errno;
        fprintf(stderr, "Error while mapping file page : errno %d (%s).\n", errsv, strerror(errsv));
        exit(EXIT_FAILURE);
    }

    return (int *)filePagePointer;
}

filePage然后是问题:如果(即偏移)是,它工作得非常好,0但如果它是严格正数,它会失败,并且errno = 22.

除非我错过了手册页中的某些内容,否则所有参数都是有效的(offset是 的倍数sysconf(_SC_PAGE_SIZE)addrNULLlength严格为正且不太大,并且标志是正确的)。那么,为什么是 EINVAL ?...

4

1 回答 1

3

内核驱动程序确实

static int uio_find_mem_index(struct vm_area_struct *vma)
{
    struct uio_device *idev = vma->vm_private_data;

    if (vma->vm_pgoff < MAX_UIO_MAPS) {
        if (idev->info->mem[vma->vm_pgoff].size == 0)
            return -1;
        return (int)vma->vm_pgoff;
    }
    return -1;
}

看起来,offset是地图索引(如 in map0),而不是内存中的位置。

你必须mmap()完整的记忆。

于 2020-07-27T12:35:44.500 回答