如何在不崩溃Linux内核的情况下访问mmaped/dev/mem?

Vin*_*nay 16 c linux mmap linux-kernel

我有一个简单的程序试图访问用户空间中的物理内存,其中内核存储第一个结构页面.在64位机器上,此地址为:

  • 内核虚拟地址:ffffea0000000000
  • 物理地址:0000620000000000

我试图通过用户空间中的mmap访问此物理地址.但是下面的代码崩溃了内核.

int *addr;
if ((fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0 ) {
    printf("Error opening file. \n");
    close(fd);
    return (-1);
}
/* mmap.  address of first struct page for 64 bit architectures 
 * is 0x0000620000000000.
 */
addr = (int *)mmap(0, num*STRUCT_PAGE_SIZE, PROT_READ, MAP_PRIVATE,
            fd, 0x0000620000000000);
printf("addr: %p \n",addr);
printf("addr: %d \n",*addr); /* CRASH. */
Run Code Online (Sandbox Code Playgroud)

kai*_*wan 20

我想我已经找到了问题 - 它与x86上的/ dev/mem内存映射保护有关.

Pl参考这篇LWN文章:"x86:使用配置选项引入/ dev/mem限制" http://lwn.net/Articles/267427/

CONFIG_NONPROMISC_DEVMEM

现在(我在最近的3.2.21内核上对此进行了测试),配置选项似乎被称为CON​​FIG_STRICT_DEVMEM.

我改变了我的内核配置:

$ grep DEVMEM .config
# CONFIG_STRICT_DEVMEM is not set
$ 
Run Code Online (Sandbox Code Playgroud)

使用上一个内核运行上述prg时,使用CONFIG_STRICT_DEVMEM SET:dmesg显示:

[29537.565599] Program a.out tried to access /dev/mem between 1000000->1001000.
[29537.565663] a.out[13575]: segfault at ffffffff ip 080485bd sp bfb8d640 error 4 in a.out[8048000+1000]
Run Code Online (Sandbox Code Playgroud)

这是因为内核保护..

重建内核时(使用CONFIG_STRICT_DEVMEM UNSET)并运行上面的prg:

# ./a.out 
mmap failed: Invalid argument
# 
Run Code Online (Sandbox Code Playgroud)

这是因为'offset'参数> 1 MB(在x86上无效)(它是16MB).

使mmap偏移量在1 MB以内:

# ./a.out 
addr: 0xb7758000
*addr: 138293760 
# 
Run Code Online (Sandbox Code Playgroud)

有用!有关详细信息,请参阅上述LWN文章.

在支持PAT(页面属性表)的x86架构上,内核仍然阻止了DRAM区域的映射.内核源代码中提到的原因是:

This check is nedded to avoid cache aliasing when PAT is enabled
Run Code Online (Sandbox Code Playgroud)

此检查将导致与上述类似的错误.例如:

Program a.out tried to access /dev/mem between [mem 68200000-68201000].
Run Code Online (Sandbox Code Playgroud)

可以通过禁用PAT来删除此限制.可以通过在引导时将"nopat"参数添加到内核命令行来禁用PAT.

  • @trblnc谢谢!你的实现看起来很简单 - mmap _particular_硬编码的va.我维护了一个更通用的软件,可以用来获得对用户模式的任何内存(MMIO /寄存器/ RAM)的r/w访问; 请查看:https://github.com/kaiwan/device-memory-readwrite (2认同)