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

我有一个简单的程序,试图访问用户空间中的内存,第一个结构页面的内存中的物理内存。 在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. */ 

我想我已经发现了这个问题 – 这是在x86上使用/ dev / mem内存映射保护。

Pl参考这篇LWN文章:“x86:用configuration选项介绍/ dev / mem限制” http://lwn.net/Articles/267427/

CONFIG_NONPROMISC_DEVMEM

现在(我在最近的3.2.21内核上testing过),configuration选项好像叫做CONFIG_STRICT_DEVMEM。

我改变了我的内核configuration:

 $ grep DEVMEM .config # CONFIG_STRICT_DEVMEM is not set $ 

当上面的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] 

这是因为内核保护

当内核被重build(使用CONFIG_STRICT_DEVMEM UNSET )并且上面的prg被运行时:

 # ./a.out mmap failed: Invalid argument # 

这是因为“偏移量”参数大于1 MB(在x86上无效)(它是16MB)。

使mmap偏移量在1 MB以内后:

 # ./a.out addr: 0xb7758000 *addr: 138293760 # 

有用! 有关详细信息,请参阅上面的LWN文章。

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

 This check is nedded to avoid cache aliasing when PAT is enabled 

这个检查会导致与上面提到的类似的错误。 例如:

 Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

这个限制可以通过禁用PAT来消除。 可以通过在启动时将“nopat”参数添加到内核命令行来禁用PAT。

在具有PAT支持(页面属性表)的x86架构上,内核可以防止DRAM区域的映射(即使编译时没有设置CONFIG_NONPROMISC_DEVMEM)。

内核源代码中提到的原因是:

 This check is nedded to avoid cache aliasing when PAT is enabled 

这个检查会导致类似的错误出现在dmesg中,正如上面在上面的开湾答案中提到的那样。 例如:

 Program a.out tried to access /dev/mem between [mem 68200000-68201000]. 

这个限制可以通过禁用PAT来消除。

可以通过在启动时将nopat参数添加到内核命令行来禁用PAT。