为啥 mmap /dev/mem 返回不同的地址?

Posted

技术标签:

【中文标题】为啥 mmap /dev/mem 返回不同的地址?【英文标题】:Why mmap /dev/mem return different address?为什么 mmap /dev/mem 返回不同的地址? 【发布时间】:2014-02-18 04:41:36 【问题描述】:

这是程序:

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/file.h>
#include <errno.h>

long* mapmem(off_t offset)

    int fd;
    long *ret;

    fd = open("/dev/mem", O_RDWR|O_SYNC);

    if (fd == -1) 
        perror("open");
        return NULL;
    

    printf("offset (pageaddr) is: %ld\n", offset);

    ret = mmap(0, sizeof(long), PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
    if (ret == MAP_FAILED) 
        perror("mmap");
        ret = NULL;
    

    printf("Return address is: %p\n", ret);

    if (close(fd) == -1)
        perror("close");

    return ret;


int main(int argc, char *argv[])

    long *mem = 0;
    volatile long *_mem = 0, dummy;
    long long int addr, offset, pageaddr;
    char *endpt;

    if (argc != 2) 
        fprintf(stderr, "Usage %s <addr>\n", argv[0]);
        return 1;
    

    addr = strtoll(argv[1], &endpt, 16);
    offset = addr % sysconf(_SC_PAGE_SIZE);
    pageaddr = addr - offset;

    printf("addr is: %lld, offset: %lld, pageaddr: %lld\n", addr, offset, pageaddr);

    mem = mapmem(pageaddr);

    return 0;

为什么映射后的物理地址与我们传入的不同?还是返回的地址是映射到对应物理地址的虚拟地址?

我运行上述程序的输出:

 $ sudo ./test 0x12345
addr is: 74565, offset: 837, pageaddr: 73728
offset is: 73728
Return address is: 0x7f3081fc0000

【问题讨论】:

man mem: mem is a character device file that is an image of the main memory of the computer. 我猜这意味着您的程序要求操作系统将主内存的物理地址映射到进程虚拟空间中的某个地址。 为什么你认为虚拟地址应该和物理地址一样? @BasileStarynkevitch 我只是想确认返回的地址在我当前正在运行的程序的虚拟地址空间中,即使是从/dev/mem 映射的。我认为情况就是这样。对于普通地址,我知道它在虚拟地址空间中。 【参考方案1】:

Mmap 返回您可以访问的内存缓冲区的地址:因此,它是一个虚拟地址,也是因为物理地址应该对用户空间不可见。实际上,当前架构总是(但在启动过程的最初几秒内)在启用内存虚拟化的情况下运行。您只能在内核内部看到物理地址,并且只有当您明确使用物理内存时;但是您永远无法直接访问它们,您首先需要将它们映射到虚拟地址。

因此,您在程序中看到的是一个虚拟地址,它有时会有所不同。当您映射时,Linux 会在您的进程的虚拟内存中选择一个空闲的虚拟内存区域,该区域足够大以容纳您请求的映射,并将物理内存映射到该区域。 Linux 选择哪个虚拟内存区域取决于可用性和其他因素,例如地址空间布局随机化 (http://en.wikipedia.org/wiki/Address_space_layout_randomization)。

【讨论】:

以上是关于为啥 mmap /dev/mem 返回不同的地址?的主要内容,如果未能解决你的问题,请参考以下文章

/dev/mem和/dev/kmem的区别

通过devmem访问物理地址

如何将文件映射到内存?

ws2811_init failed with code -5 (mmap() failed)错误解决方案

您如何处理使用 36 位映射的 IO?

linux中ioremap和mmap的区别