Ubuntu平台root用户mmap PCIe BAR返回-EPERM问题求助
解决Ubuntu下root权限映射PCIe BAR返回-EPERM的问题
问题背景
在Ubuntu平台以root权限执行代码映射PCIe BAR时,mmap始终返回-EPERM Operation not permitted,即使将MAP_SHARED改为MAP_PRIVATE也无效。已确认内核配置CONFIG_STRICT_DEVMEM=y,但另一台同配置机器可成功映射。
目标PCIe设备的Region信息:
Region 0: Memory at 3f900000 (32-bit, non-prefetchable) [size=16K]
Region 0: Memory at 3f904000 (32-bit, non-prefetchable)
使用的代码片段:
int main(int argc, char *argv[]) { int fd; void *base; int bar_size = 16384; char path[256]; if (argc < 2) { fprintf(stderr, "Usage: %s <pci-device-id>\n", argv[0]); return 1; } snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/resource0", argv[1]); fd = open(path, O_RDWR); if (fd == -1) { perror("Error opening file"); return 1; } base = mmap(NULL, bar_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (base == MAP_FAILED) { perror("Error mapping BAR"); close(fd); return 1; } // 代码未完成,省略后续逻辑 }
排查与解决步骤
1. 检查设备是否被内核驱动占用
内核驱动绑定到PCIe设备后,会独占BAR资源,阻止用户态直接映射:
- 执行
lspci -k查看目标设备的驱动信息,例如:
若输出中有lspci -k | grep -A 3 "你的设备ID"Kernel driver in use: xxx,说明驱动已绑定。 - 解绑驱动(替换为你的设备完整ID,如
0000:01:00.0):
解绑后重新运行映射代码测试。echo -n "0000:xx:xx.x" > /sys/bus/pci/devices/0000:xx:xx.x/driver/unbind
2. 验证resource文件权限
以root执行时,/sys下的resource文件权限仍可能异常:
- 查看文件权限:
正常权限应为ls -l /sys/bus/pci/devices/[你的设备ID]/resource0-rw-rw----(root和kmem组可读写),若权限不对可临时修改:chmod 660 /sys/bus/pci/devices/[你的设备ID]/resource0
3. 调整内核devmem限制
CONFIG_STRICT_DEVMEM=y会限制用户态访问物理内存,但可通过sysctl参数临时放宽:
- 查看当前限制:
cat /proc/sys/kernel/devmem_is_allowed- 0:严格禁止访问非RAM内存
- 1:允许访问所有物理内存
- 临时设置为允许:
若需永久生效,编辑echo 1 > /proc/sys/kernel/devmem_is_allowed/etc/sysctl.conf添加:
执行kernel.devmem_is_allowed=1sysctl -p使配置生效。
4. 检查IOMMU是否干扰
IOMMU启用可能导致BAR地址重映射或权限限制:
- 检查系统是否启用IOMMU:
dmesg | grep IOMMU cat /proc/cmdline | grep iommu - 若需临时关闭,编辑
/etc/default/grub,修改GRUB_CMDLINE_LINUX去掉iommu=on或intel_iommu=on等参数,执行update-grub并重启系统。
5. 确认BAR地址未被预留
物理内存地址被内核标记为reserved时,用户态无法映射:
- 查看内存区域分配:
若该地址被标记为cat /proc/iomem | grep -A 5 "3f900000"reserved或被其他设备占用,需检查BIOS设置,调整PCIe BAR分配策略,或更换设备插槽。
6. 修正代码中的BAR大小
从提供的Region信息看,存在两个Region 0地址(3f900000和3f904000),间隔4KB,实际BAR总大小可能大于16KB:
- 查看resource文件的完整信息:
第一行即为resource0的起始地址和大小,根据实际数值调整代码中的cat /sys/bus/pci/devices/[你的设备ID]/resourcebar_size参数。
内容的提问来源于stack exchange,提问作者dfei
相关产品推荐
相关产品推荐

