【问题标题】:why is the physical address of a mmap value is aways zero?为什么一个map值的物理地址总是为零?
【发布时间】:2018-11-02 13:31:18
【问题描述】:

我写了一个程序来计算给定虚拟地址的物理地址。这个程序总是返回 0。这意味着没有找到特定的页面。为什么该页面不可用?

这段代码的作用是:这段代码创建了一个文件的内存,并且使用我从https://stackoverflow.com/a/28987409/6941772 获取的函数将内存映射的虚拟地址转换为物理地址。

#include <sys/mman.h> 
#include <sys/stat.h>
#include <fcntl.h> // O_RDONLY
//#include <stddef.h> // to get NULL definition. NULL not a built in const. 
#include <string.h> // NULL is also defined in string.h, stdlib.h
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include "inttypes.h"

uint64_t vtop(uint64_t vaddr) {
    FILE *pagemap;
    uint64_t paddr = 0;

    unsigned long long int offset = (vaddr / sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
    uint64_t e;

    // https://www.kernel.org/doc/Documentation/vm/pagemap.txt
    if ((pagemap = fopen("/proc/self/pagemap", "r"))) {
        if (lseek(fileno(pagemap), offset, SEEK_SET) == offset) {
            if (fread(&e, sizeof(uint64_t), 1, pagemap)) {
                if (e & (1ULL << 63)) { // page present ?
                    paddr = e & ((1ULL << 54) - 1); // pfn mask
                    paddr = paddr * sysconf(_SC_PAGESIZE);
                    // add offset within page

                    paddr = paddr | (vaddr & (sysconf(_SC_PAGESIZE) - 1));
                                        printf(" paddr %lu \n", paddr);
                }
                                else {
                                    printf("page not found\n");
                                    }
            }
        }
        fclose(pagemap);
    }

    return paddr;
}

int main() {

    int oflag = O_RDONLY;
    const char *path = "file.json";
    const int fd = open(path, oflag);

    // use stat to find the file size
    struct stat stat;
    int ret = fstat(fd, &stat);

    int mflags = MAP_PRIVATE; // information about handling the mapped data
    int mprot = PROT_READ|PROT_WRITE; // access permissions to the data being mapped 
    size_t size = stat.st_size;
    void *addr = mmap(NULL, size, mprot, mflags, fd, 0);
    printf("virtual addres is %p\n", addr);
    printf("physical addres is %ld\n", vtop((uint64_t)addr));

    return 0;
}

当我使用malloc而不是mmap时,我得到的物理地址是0x670这个数字的特长是什么?

【问题讨论】:

    标签: linux linux-kernel paging mmap virtual-memory


    【解决方案1】:

    我写了一个程序来计算给定的物理地址 虚拟地址。这个程序总是返回 0。

    /proc/self/pagemap 访问物理地址需要以root 权限(sudo) 运行程序。否则,您仍然可以打开 /proc/self/pagemap 并从中读取。只是物理地址似乎都为零。由于您将NULL 传递给mmap 的第一个参数,它将返回一个页面对齐的虚拟地址。所以页面偏移量也为零。因此,vtop 将返回零。

    当我使用 malloc 而不是 mmap 时,我得到的物理地址为 0x670这个号码有什么特点?

    使用malloc 分配内存时,返回的虚拟地址可能不是页面对齐的。因此,页偏移量可能不为零。正在打印的值0x670 只是添加到物理地址为零的页面偏移量。

    这是你需要做的:

    • 确保传递给mmap 的长度参数(文件大小)大于零(文件不能为空)。否则,mmap 返回 -1,errno 设置为 EINVAL
    • 无论程序是否具有 root 权限,如果未触及任何映射页面,默认情况下,不会为它们分配物理页面。该程序将打印page not found。为避免此问题,您可以在调用 vtop 之前读取一个字节 (char c = *((char*)addr);)。
    • 现在,如果您触摸映射区域的第一页,但在没有 root 权限的情况下运行程序,物理地址将为零,但页偏移量可能为零,也可能不为零。因此,您只需获得页面偏移量。使用sudo 运行程序以解决问题。

    【讨论】:

    • 使用 sudo 命令:使用 mmap 时,我仍然将 paddr 设为 0。但是当我使用 malloc 时,我得到一个 8 位六进制地址,例如 0x52508670 为什么只有 8 位十六进制?我期待 12 位十六进制数
    • @BODDUMANOHARREDDY 映射文件时是否打印page not found
    • page not found 未打印
    • @BODDUMANOHARREDDY 这表明在使用 malloc 时它正在工作。但是在打开的文件上使用 mmap 时,它会打印什么?您仔细阅读了我回答的后半部分吗?
    • @BODDUMANOHARREDDY 为什么需要 12 个十六进制数字?物理地址的任何最高有效零位都不会使用%ld 格式打印。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    相关资源
    最近更新 更多