几次访问后,mmap 因无法打开 /dev/mem 而死
mmap dies with cannot open /dev/mem after several accesses
我正在编写一些用户-space 驱动程序,在双核 ARM A9 上使用 mmap 来访问 FPGA 中的一些硬件寄存器。我们有一个自定义 SPI 块,它与另一个芯片通信,我们访问该芯片内的硬件寄存器。我为我的 SPI "Driver" 写了一个 C++ class 来基本上分解外部芯片内部的 reads/writes from/to 地址。我使用 mmap 访问 FPGA 内部的 SPI(只占用大约 100 字节的内存space(0xFF20_2000 -> 0xFF20_007F))。
当我调用 SPI class(我只为驱动程序执行一次)时,它会通过并为 SPI 硬件的基地址执行 mmap 打开。
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 硬件寄存器构建为 struct/union 以便于(更高级)位操作(我已经排除了可以被视为专有但与问题无关的东西)。
union spi_regs_reg1 {
struct {
volatile uint32_t xxxx: 32;
} bits;
volatile uint32_t word;
};
union spi_regs_reg2 {
struct {
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
} bits;
volatile uint32_t word;
};
struct spi_regs_regs {
union spi_regs_blockid spi_regs_reg1;
union spi_regs_gnrlsta spi_regs_reg2;
blah blah blah
作为 init/constructor 的一部分,我有一个 spi_regs 结构指针被分配
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) 即可执行操作。
这似乎工作得很好,但偶尔在一堆 read/writes 之后我开始出错
"ERROR: could not open "/dev/mem"...".
现在这是 cfg_mmap() 任务中的内容。但是,我只将其作为构造函数的一部分调用一次。在这个特定的测试中,我正在设置多个不同的设置,并 运行 通过每个设置并重置中间的外部部分(但不是我用 mmap 控制的 SPI)。我基本上有一个 for 循环,但 SPI class 的构造函数先于 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 过载或类似情况?我已经在我的代码中进行了一些搜索,我终其一生都找不到我不止一次调用 SPI class 的地方(程序并没有那么复杂)。
如果我假设你 class 被称为 "spi_op" 你可能需要创建 spi_op::~spi_op() (所谓的 "destructor" ) 与 "munmap(virtual_base,MMAP_PAGE_SIZE)" 和 "close(fd)" 指令。所以它可能是析构函数的主题:例如参见https://www.tutorialspoint.com/cplusplus/cpp_constructor_destructor.htm。如果你正确使用 munmap() 和 close() 你不应该再 运行 进入这个问题了。
我正在编写一些用户-space 驱动程序,在双核 ARM A9 上使用 mmap 来访问 FPGA 中的一些硬件寄存器。我们有一个自定义 SPI 块,它与另一个芯片通信,我们访问该芯片内的硬件寄存器。我为我的 SPI "Driver" 写了一个 C++ class 来基本上分解外部芯片内部的 reads/writes from/to 地址。我使用 mmap 访问 FPGA 内部的 SPI(只占用大约 100 字节的内存space(0xFF20_2000 -> 0xFF20_007F))。
当我调用 SPI class(我只为驱动程序执行一次)时,它会通过并为 SPI 硬件的基地址执行 mmap 打开。
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 硬件寄存器构建为 struct/union 以便于(更高级)位操作(我已经排除了可以被视为专有但与问题无关的东西)。
union spi_regs_reg1 {
struct {
volatile uint32_t xxxx: 32;
} bits;
volatile uint32_t word;
};
union spi_regs_reg2 {
struct {
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
volatile uint32_t xxxx: 1;
} bits;
volatile uint32_t word;
};
struct spi_regs_regs {
union spi_regs_blockid spi_regs_reg1;
union spi_regs_gnrlsta spi_regs_reg2;
blah blah blah
作为 init/constructor 的一部分,我有一个 spi_regs 结构指针被分配
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) 即可执行操作。
这似乎工作得很好,但偶尔在一堆 read/writes 之后我开始出错
"ERROR: could not open "/dev/mem"...".
现在这是 cfg_mmap() 任务中的内容。但是,我只将其作为构造函数的一部分调用一次。在这个特定的测试中,我正在设置多个不同的设置,并 运行 通过每个设置并重置中间的外部部分(但不是我用 mmap 控制的 SPI)。我基本上有一个 for 循环,但 SPI class 的构造函数先于 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 过载或类似情况?我已经在我的代码中进行了一些搜索,我终其一生都找不到我不止一次调用 SPI class 的地方(程序并没有那么复杂)。
如果我假设你 class 被称为 "spi_op" 你可能需要创建 spi_op::~spi_op() (所谓的 "destructor" ) 与 "munmap(virtual_base,MMAP_PAGE_SIZE)" 和 "close(fd)" 指令。所以它可能是析构函数的主题:例如参见https://www.tutorialspoint.com/cplusplus/cpp_constructor_destructor.htm。如果你正确使用 munmap() 和 close() 你不应该再 运行 进入这个问题了。