Linux中是否有用于从虚拟地址确定物理地址的API?

Linux中是否有用于从虚拟地址确定物理地址的API?,linux,memory,memory-management,linux-kernel,virtual-address-space,Linux,Memory,Memory Management,Linux Kernel,Virtual Address Space,Linux操作系统中是否有用于从虚拟地址确定物理地址的API?内核和用户空间使用由内存管理硬件映射到物理地址的虚拟地址(也称为线性地址)。此映射由操作系统设置的页表定义 DMA设备使用总线地址。在i386 PC上,总线地址与物理地址相同,但其他体系结构可能具有特殊的地址映射硬件,用于将总线地址转换为物理地址 在Linux中,您可以从asm/io.h使用这些函数: 虚拟物理(虚拟地址) 物理地址 虚拟至虚拟总线(虚拟地址) 总线到虚拟(总线地址) 所有这些都是关于访问普通内存的。PCI或ISA

Linux操作系统中是否有用于从虚拟地址确定物理地址的API?

内核和用户空间使用由内存管理硬件映射到物理地址的虚拟地址(也称为线性地址)。此映射由操作系统设置的页表定义

DMA设备使用总线地址。在i386 PC上,总线地址与物理地址相同,但其他体系结构可能具有特殊的地址映射硬件,用于将总线地址转换为物理地址

在Linux中,您可以从
asm/io.h
使用这些函数:

  • 虚拟物理(虚拟地址)
  • 物理地址
  • 虚拟至虚拟总线(虚拟地址)
  • 总线到虚拟(总线地址)
所有这些都是关于访问普通内存的。PCI或ISA总线上也有“共享内存”。它可以使用ioremap()映射到32位地址空间中,然后通过readb()、writeb()等函数使用

生活是复杂的,因为周围有各种各样的缓存,所以访问同一物理地址的不同方式不必给出相同的结果

此外,虚拟地址后面的实际物理地址也可以更改。更重要的是,在您访问虚拟地址之前,可能没有与虚拟地址关联的地址


至于用户land API,我所知不存在任何问题。

如前所述,普通程序不需要担心物理地址,因为它们在虚拟地址空间中运行,非常方便。此外,并非每个虚拟地址都有物理地址,这些地址可能属于映射文件或交换的页面。然而,有时看到这种映射可能会很有趣,即使是在userland中

为此,Linux内核通过
/proc
中的一组文件公开其到userland的映射。可以找到文档。小结:

  • /proc/$pid/maps
    提供虚拟地址映射列表以及其他信息,例如映射文件的对应文件
  • /proc/$pid/pagemap
    提供有关每个映射页面的更多信息,包括物理地址(如果存在)
  • 提供一个C程序,该程序使用此接口转储所有正在运行的进程的映射,并解释其作用

    我想知道为什么没有用户土地API

    因为用户陆地内存的物理地址未知

    Linux对用户陆地内存使用按需分页。您的用户land对象在被访问之前不会有物理内存。当系统内存不足时,您的用户land对象可能会被调出并丢失物理内存,除非该页为此进程被锁定。当您再次访问该对象时,它将被交换并提供物理内存,但它可能与上一个不同。您可以拍摄页面映射的快照,但不能保证在下一时刻相同

    因此,查找用户土地对象的物理地址通常没有意义。

    /proc//pagemap
    userland最小可运行示例

    virt_to_phys_user.c

    定义源代码700
    #包括/*开放*/
    #包括/*uint64\u t*/
    #包括/*printf*/
    #包括/*尺寸*/
    #include/*pread,sysconf*/
    类型定义结构{
    uint64_t pfn:55;
    无符号整数软_脏:1;
    未签名的整数文件\u页:1;
    未签名整数交换:1;
    无符号整数:1;
    }页面地图输入;
    /*解析给定虚拟地址的pagemap条目。
    *
    *@param[out]entry解析后的条目
    *@param[in]pagemap_fd文件描述符到打开的/proc/pid/pagemap文件
    *@param[in]vaddr虚拟地址以获取条目
    *@成功返回0,失败返回1
    */
    int pagemap\u get\u条目(PagemapEntry*entry,int pagemap\u fd,UINTPTTR\u vaddr)
    {
    尺寸(单位:nread);
    ssize_t ret;
    uint64_t数据;
    uintptr\t vpn;
    vpn=vaddr/sysconf(\u SC\u PAGE\u SIZE);
    nread=0;
    而(nread>55)和1;
    条目->文件页面=(数据>>61)&1;
    条目->交换=(数据>>62)&1;
    输入->当前=(数据>>63)&1;
    返回0;
    }
    /*使用/proc/PID/pagemap将给定的虚拟地址转换为物理地址。
    *
    *@param[out]paddr物理地址
    *@param[in]要转换为的pid进程
    *@param[in]vaddr虚拟地址以获取条目
    *@成功返回0,失败返回1
    */
    int virt_to_phys_用户(uintpttr_t*paddr、pid_t pid、uintptpr_t vaddr)
    {
    char pagemap_文件[BUFSIZ];
    int pagemap_fd;
    snprintf(pagemap_文件,sizeof(pagemap_文件),“/proc/%ju/pagemap”,(uintmax_t)pid);
    pagemap_fd=打开(仅pagemap_文件);
    如果(pagemap_fd<0){
    返回1;
    }
    页面地图输入;
    if(pagemap\u get\u条目(&entry,pagemap\u fd,vaddr)){
    返回1;
    }
    关闭(pagemap_fd);
    *paddr=(entry.pfn*sysconf(_SC_PAGE_SIZE))+(vaddr%sysconf(_SC_PAGE_SIZE));
    返回0;
    }
    int main(int argc,字符**argv)
    {
    pid_t pid;
    uintpttr_t vaddr,paddr=0;
    如果(argc<3){
    printf(“用法:%s pid vaddr\n”,argv[0]);
    返回退出失败;
    }
    pid=strtoull(argv[1],NULL,0);
    vaddr=strtoull(argv[2],NULL,0);
    if(虚拟至物理用户(&paddr、pid、vaddr)){
    fprintf(stderr,“错误:virt_to_phys_user\n”);
    返回退出失败;
    };
    printf(“0x%jx\n”,(uintmax\u t)paddr);
    返回退出成功;
    }
    

    用法:

    sudo./virt\u to\u phys\u user.out
    
    sudo
    必须读取
    /proc//pagemap
    ,即使您拥有文件权限,如以下所述:

    作为承诺
    vaddr 0x600800
    pid 110