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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11891979/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 14:03:10  来源:igfitidea点击:

How to access mmaped /dev/mem without crashing the Linux kernel?

clinuxlinux-kernelmmap

提问by Vinay

I have a simple program that tries to access the physical memory in user space, where the kernel stores the 1st struct page. On a 64 bit machine this address is:

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

  • kernel virtual address: ffffea0000000000
  • physical address: 0000620000000000
  • 内核虚拟地址:ffffea0000000000
  • 物理地址:0000620000000000

I am trying to access this physical address through mmap in user space. But the following code crashes the kernel.

我正在尝试通过用户空间中的 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. */

采纳答案by kaiwan

I think I've found the issue -- it's to do with /dev/mem memory mapping protection on the x86.

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

Pl refer to this LWN article: "x86: introduce /dev/mem restrictions with a config option" http://lwn.net/Articles/267427/

请参考这篇 LWN 文章:“x86:通过配置选项引入 /dev/mem 限制” http://lwn.net/Articles/267427/

CONFIG_NONPROMISC_DEVMEM

CONFIG_NONPROMISC_DEVMEM

Now (i tested this on a recent 3.2.21 kernel), the config option seems to be called CONFIG_STRICT_DEVMEM.

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

I changed my kernel config:

我更改了内核配置:

$ grep DEVMEM .config
# CONFIG_STRICT_DEVMEM is not set
$ 

When the above prg was run with the previouskernel, with CONFIG_STRICT_DEVMEM SET: dmesg shows:

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

This is because of the kernel protection..

这是因为内核保护..

When the kernel was rebuilt (with the CONFIG_STRICT_DEVMEM UNSET) and the above prg was run :

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

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

This is because the 'offset' parameter is > 1 MB (invalid on x86) (it was 16MB).

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

After making the mmap offset to be within 1 MB:

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

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

It works! See the above LWN article for details.

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

On x86 architectures with PAT support (Page Attribute Table), the kernel still prevents the mapping of DRAM regions. The reason for this as mentioned in the kernel sourceis:

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

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

This check will cause a similar error to the one mentioned above. For example:

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

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

This restriction can be removed by disabling PAT. PAT can be disabled by adding the "nopat" argument to the kernel command line at boot time.

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

回答by Safayet Ahmed

On x86 architectures with PAT support (Page Attribute Table), the kernel can prevent the mapping of DRAM regions (even if it is compiled without setting CONFIG_NONPROMISC_DEVMEM).

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

The reason for this as mentioned in the kernel sourceis:

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

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

This check will cause a similar error to appear in dmesgas the one mentioned in kaiwan's answer above above. For example:

此检查将导致出现与dmesg上面 kaiwan 的回答中提到的错误类似的错误。例如:

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

This restriction can be removed by disabling PAT.

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

PAT can be disabled by adding the nopatargument to the kernel command-line at boot time.

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