C++ mmap在多次访问后无法打开/dev/mem

C++ mmap在多次访问后无法打开/dev/mem,c++,c,embedded,embedded-linux,C++,C,Embedded,Embedded Linux,我正在使用双核ARM A9上的mmap编写一些用户空间驱动程序,以访问FPGA中的一些硬件寄存器。我们有一个自定义SPI块,它与另一个芯片对话,我们访问该芯片内的硬件寄存器。我写了一个C++类用于我的SPI“驱动程序”,基本上是从外部芯片中读取/写入/写入地址。我使用mmap访问FPGA内部的SPI(只占用大约100字节的内存空间(0xFF20_2000->0xFF20_007F)) 当我调用SPI类(我只对驱动程序执行一次)时,它会通过并为SPI HW的基址执行mmap open void s

我正在使用双核ARM A9上的mmap编写一些用户空间驱动程序,以访问FPGA中的一些硬件寄存器。我们有一个自定义SPI块,它与另一个芯片对话,我们访问该芯片内的硬件寄存器。我写了一个C++类用于我的SPI“驱动程序”,基本上是从外部芯片中读取/写入/写入地址。我使用mmap访问FPGA内部的SPI(只占用大约100字节的内存空间(0xFF20_2000->0xFF20_007F))

当我调用SPI类(我只对驱动程序执行一次)时,它会通过并为SPI HW的基址执行mmap open

void spi_op::cfg_mmap(){

    if( ( this->fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) ) ) == -1 ) {
        printf( "ERROR: could not open \"/dev/mem\"...\n" );
        this->error = 1;
        return;
    }

    uint32_t map_addr_base = this->addr_base & MMAP_BASE_MASK;

    this->virtual_base = mmap( NULL, MMAP_PAGE_SIZE, ( PROT_READ | PROT_WRITE ), MAP_SHARED, this->fd, map_addr_base );

    if( this->virtual_base == MAP_FAILED ) {
        printf( "ERROR: mmap() failed...\n" );
        close( this->fd );
        this->error = 1;
        return;
    }

    //To initialize to the proper pointer in the event not on a page boundary
    this->virtual_base += (SPI_MASTER_ADDR_BASE - map_addr_base);
}
我将SPI HW寄存器构建为一个结构/并集,以便进行简单(更高层次)的位操作(我已经将一些可以被认为是专有的,但与这个问题无关的东西X了出来)

作为init/constructor的一部分,我有一个spi_regs struct指针,它被赋值

void spi_op::spi_master_init(){

    this->cfg_mmap();

    spi_regs = (struct spi_regs_regs *)(this->virtual_base);


    //an Example of how I can now access the bits in the HW registers
    //Assert the RESET
    spi_regs->spi_regs_reg.bits.spi_reset = 1;
无论何时我想要读或写,我现在只需调用spi.read(addr)或spi.write(addr,data)来执行操作

这似乎工作得很好,但偶尔在读/写了一堆之后,我开始出现错误

"ERROR: could not open "/dev/mem"...". 
这是cfg_mmap()任务中的内容。但是,作为构造函数的一部分,我只调用一次。在这个特定的测试中,我设置了多个不同的设置,并运行其中的每一个设置,并重置中间的外部部分(但不是我用mmap控制的SPI)。我基本上有一个for循环,但是SPI类的构造函数在for循环之前

在键入此命令时,作为快速测试,我将cfg_mmap任务中的错误消息更改为

"ERROR: blah could not open "/dev/mem"..."
然后在跑步过程中我得到了这个

<normal prints from my code>
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: blah could not open "/dev/mem"...
Segmentation fault
root@arria10:~# 

错误:无法打开“/dev/mem”。。。
错误:无法打开“/dev/mem”。。。
错误:无法打开“/dev/mem”。。。
错误:无法打开“/dev/mem”。。。
错误:无法打开“/dev/mem”。。。
错误:blah无法打开“/dev/mem”。。。
分段故障
root@arria10:~# 

有没有可能是/dev/mem过载了呢?我已经在我的代码中做了一些搜索,我一生中都找不到我多次调用SPI类的地方(程序没有那么复杂)

如果我假设您的类被称为“spi_op”,您可能需要使用“munmap(virtual_base,MMAP_PAGE_SIZE)”和“close(fd)”指令创建spi_op::~spi_op()(所谓的“析构函数”)。因此,这可能是析构函数的一个主题:例如,请参见。如果正确使用munmap()和close(),则不应再遇到此问题。

那么具体错误是什么?(提示:使用
strerror(errno)
perror
)使用/dev/mem在安全性方面不是最好的概念/dev/mem可能只允许root用户使用。因此,您必须更改权限。这是不好的…@lkj我同意,但是这是为了验证硬件,不会在生产代码中使用。最终一个真正的软件人(不是我的硬件)会把它转换成更标准的东西。@immibis我会尝试一下。我需要了解一些如何使用它。我得到的错误是“打开的文件太多”。我试图更改代码中的一些内容。我在使用SPI的其他类中创建了一个SPI类,但我只传递了一个指向主SPI类的指针。我仍然不能完全确定到底发生了什么,但是设置
ulimit-n
至少让我现在能够解决这个问题。这不是一个永久性的解决方案,但对于这个特殊的测试,我可以接受。我接受这个,尽管技术上不是我的问题。事实上,我确实让析构函数调用了munmap函数(即使不需要它)。还有一个类正在使用类似的东西,但没有使用我的SPI类。在一些额外的调试过程中,我发现有另一个类调用mmap,但没有取消映射。这最终被视为问题所在。然而,我的大多数调试打印似乎发生在SPI操作期间,这使我相信这是罪魁祸首。谢谢你的帮助
<normal prints from my code>
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: blah could not open "/dev/mem"...
Segmentation fault
root@arria10:~#