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

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=1
    
    执行sysctl -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文件的完整信息:
    cat /sys/bus/pci/devices/[你的设备ID]/resource
    
    第一行即为resource0的起始地址和大小,根据实际数值调整代码中的bar_size参数。

内容的提问来源于stack exchange,提问作者dfei

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 23:55:22