nvme用户态驱动-参考02-linux用户态进程获取物理地址

358 阅读1分钟

v2phy示例

#include <sys/user.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

uint64_t virt2phy(const void *addr)
{
    int fd, ret;
    unsigned long virt_pfn;
    off_t offset;
    uint64_t page, phy_addr;

    fd = open("/proc/self/pagemap", O_RDONLY);
    if (fd < 0) {
        printf("Cannot open file /proc/self/pagemap\n");
        return -1;
    }

    virt_pfn = (uint64_t)addr / PAGE_SIZE;
    /* /proc/self/pagemap 8个字节为一个page页索引 */
    offset = sizeof(uint64_t) * virt_pfn;
    if (lseek(fd, offset, SEEK_SET) < 0) {
        printf("lseek failed\n");
        return -1;
    }

    ret = read(fd, &page, sizeof(uint64_t));
    close(fd);
    
    /*
     * the pfn (page frame number) are bits 0-54 (see pagemap.txt in linux Documentation)
     */
    if ((page & 0x7fffffffffffffULL) == 0) {
        printf("get page failed\n");
        return -1;
    }

    phy_addr = (page & 0x7fffffffffffffULL) * PAGE_SIZE + ((uint64_t)addr % PAGE_SIZE);
    return phy_addr;
}

int main(void)
{
    uint8_t *p = malloc(1024 * 1024);

    *(p + 4096) = 10;
    printf("virt:%p phys:%p\n", p + 4096, virt2phy(p + 4096));

    *(p + 2 * 4096) = 10;
    printf("virt:%p phys:%p\n", p + 2 * 4096, virt2phy(p + 2 * 4096));
    return 0;
}

dpdk提供了virt2phy的方法,可以直接使用rte_mem_virt2phy实现虚拟地址到物理地址的转换。

补充:linux用户态获取page_size的方法

  • 法一: 保含#include <sys/user.h>头文件,使用PAGE_SIZE宏
#include <stdio.h>
#include <sys/user.h>

int main(void)
{
    printf("page_size = %ld\n", PAGE_SIZE);
    return 0;
}
  • 法二: 包含#include <unistd.h>,使用getpagesize函数
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    int page_size = getpagesize();
    printf("page_size = %d\n", page_size);
    return 0;
}

参考链接

cloud.tencent.com/developer/a…