You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用read()读取/dev/mem?为何基于mmap的读取代码可行但read()实现报“Bad address”错误?

为什么read()访问/dev/mem的PCIe BAR地址会报错,而mmap()可以正常工作?

这个问题的核心在于**/dev/mem对不同类型物理地址的访问机制差异**,以及PCIe设备地址的本质——咱们一步步拆解:

1. 先明确:你要访问的是PCIe设备的MMIO空间

你通过lspci查到的0x387ffa000000是PCIe设备的BAR(基地址寄存器)空间,它不属于系统的常规RAM,而是设备的寄存器/IO区域。这类空间的标准访问方式是内存映射IO(MMIO):把物理地址直接映射到进程的虚拟地址空间,通过读写虚拟地址来操作设备寄存器,而不是像读取普通文件那样做数据拷贝。

2. mmap()为什么能正常工作?

你的mmap实现完全贴合了MMIO的访问逻辑:

  • 代码先将目标物理地址对齐到页边界(这是mmap的要求)
  • 然后通过mmap()调用把这段物理BAR空间映射到你的进程虚拟地址空间
  • 之后你访问mem[page_offset + i]的时候,本质上是直接对PCIe设备的寄存器进行读写——内核只负责建立映射关系,实际的访问由CPU的内存总线直接转发到PCIe设备,这完全符合PCIe设备的访问规范。

比如你的这段核心代码:

unsigned char *mem = mmap(NULL, page_offset + len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, page_base);
// ...
printf("%02x ", (int)mem[page_offset + i]);

3. read()为什么会抛出EFAULT错误?

/dev/mem的read()系统调用是为读取系统RAM的物理地址设计的,它的逻辑是:内核尝试把指定物理地址的RAM内容拷贝到用户空间缓冲区。但你的目标地址是PCIe BAR,不属于系统RAM:

  • 内核没有办法像访问普通内存那样,把设备IO空间的内容"拷贝"到用户缓冲区——这类地址的访问需要直接和硬件交互,而不是内存拷贝操作
  • 因此内核返回EFAULT(Bad address)错误,本质是在告诉你:这个物理地址无法通过常规的read拷贝方式访问。

你提到代码读取普通文本文件正常,那是因为普通文件的内容存储在系统RAM或存储设备上,内核可以处理常规的拷贝逻辑;但PCIe BAR是硬件IO空间,完全是另一种访问模型,read/write这套逻辑根本不适用。

总结

如果要访问PCIe设备的BAR空间,mmap()是正确且标准的方式,read()/write()并不适用于这类非RAM的物理地址访问。

内容的提问来源于stack exchange,提问作者so.very.tired

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 16:09:06