用户空间和内核空间通过虚拟地址获取物理地址

·1.用户空间
参考:https://blog.csdn.net/crazycoder8848/article/details/38958075

#define page_map_file "/proc/self/pagemap"
typedef unsigned long long uint64_t;
#define PFN_MASK ((((uint64_t)1)<<55)-1)
#define PFN_PRESENT_FLAG (((uint64_t)1)<<63)
int mem_addr_vir2phy(unsigned long vir, unsigned long *phy)
{
    int fd;
    int page_size = getpagesize();
    unsigned long vir_page_idx = vir/page_size;
    unsigned long pfn_item_offset = vir_page_idx*sizeof(uint64_t);
    uint64_t pfn_item;
    fd = open(page_map_file, O_RDONLY);
    if (fd<0)
    {
        printf("open %s failed", page_map_file);
        goto mem_addr_vir2phy_error;
    }
    if ((off_t)-1 == lseek(fd, pfn_item_offset, SEEK_SET))
    {
        printf("lseek %s failed", page_map_file);
        goto mem_addr_vir2phy_error;
    }
    if (sizeof(uint64_t) != read(fd, &pfn_item, sizeof(uint64_t)))
    {
        printf("read %s failed", page_map_file);
        goto mem_addr_vir2phy_error;
    }
    if (0==(pfn_item & PFN_PRESENT_FLAG))
    {
        printf("page is not present");
        goto mem_addr_vir2phy_error;
    }
    *phy = (pfn_item & PFN_MASK)*page_size + vir % page_size;
mem_addr_vir2phy_error:
    close(fd);
    return 0;
}

2.内核空间

参考:
https://blog.csdn.net/hpu11/article/details/52600726

https://communities.vmware.com/thread/565157

pid可以从用户空间获取并通过ioctl 传递下去
static unsigned long vir2phy(int pid, unsigned long va)
{
 unsigned long pa = 0;
 struct task_struct *pcb_tmp;
 pgd_t *pgd_tmp = NULL;
 p4d_t *p4d_tmp = NULL;
 pud_t *pud_tmp = NULL;
 pmd_t *pmd_tmp = NULL;
 pte_t *pte_tmp = NULL;
    debug_printk("---------------va = 0x%lx\n", va);
 debug_printk(KERN_INFO"PAGE_OFFSET = 0x%lx\n",PAGE_OFFSET);
 debug_printk(KERN_INFO"PGDIR_SHIFT = %d\n",PGDIR_SHIFT);
    debug_printk(KERN_INFO"PUD_SHIFT = %d\n",PUD_SHIFT);
    debug_printk(KERN_INFO"PMD_SHIFT = %d\n",PMD_SHIFT);
    debug_printk(KERN_INFO"PAGE_SHIFT = %d\n",PAGE_SHIFT);
    debug_printk(KERN_INFO"PTRS_PER_PGD = %d\n",PTRS_PER_PGD);
    debug_printk(KERN_INFO"PTRS_PER_PUD = %d\n",PTRS_PER_PUD);
    debug_printk(KERN_INFO"PTRS_PER_PMD = %d\n",PTRS_PER_PMD);
    debug_printk(KERN_INFO"PTRS_PER_PTE = %d\n",PTRS_PER_PTE);
    debug_printk(KERN_INFO"PAGE_MASK = 0x%lx\n",PAGE_MASK);

#if 1
  /* 查询当前进程下的虚拟地址 */
         pcb_tmp = current;
#else
        /* 查询指定进程的下的虚拟地址 */
    if (!(pcb_tmp = pid_task(find_vpid(pid), PIDTYPE_PID))) {
        printk("find_vpid error \n");
        return 0;
    }
#endif
 debug_printk(KERN_INFO"pgd = 0x%p\n", pcb_tmp->mm->pgd);
    if(!find_vma(pcb_tmp->mm,va)){
  printk(KERN_INFO"virt_addr 0x%lx not available.\n",va);
        return 0;
    }
 pgd_tmp = pgd_offset(pcb_tmp->mm, va);
    debug_printk(KERN_INFO"pgd_tmp = 0x%p\n",pgd_tmp);
    debug_printk(KERN_INFO"pgd_val(*pgd_tmp) = 0x%lx\n",pgd_val(*pgd_tmp));
    if(pgd_none(*pgd_tmp)){
  printk(KERN_INFO"Not mapped in pgd.\n");
        return 0;
    }
 p4d_tmp = p4d_offset(pgd_tmp, va);
    debug_printk(KERN_INFO"p4d_tmp = 0x%p\n",p4d_tmp);
    debug_printk(KERN_INFO"p4d_val(*p4d_tmp) = 0x%lx\n",p4d_val(*p4d_tmp));
    if(p4d_none(*p4d_tmp)){
  printk(KERN_INFO"Not mapped in p4d.\n");
        return 0;
    }
 pud_tmp = pud_offset(p4d_tmp,va);
    debug_printk(KERN_INFO"pud_tmp = 0x%p\n",pud_tmp);
    debug_printk(KERN_INFO"pud_val(*pud_tmp) = 0x%lx\n",pud_val(*pud_tmp));
    if(pud_none(*pud_tmp)){
  printk(KERN_INFO"Not mapped in pud.\n");
        return 0;
    }
 pmd_tmp = pmd_offset(pud_tmp,va);
    debug_printk(KERN_INFO"pmd_tmp = 0x%p\n",pmd_tmp);
    debug_printk(KERN_INFO"pmd_val(*pmd_tmp) = 0x%lx\n",pmd_val(*pmd_tmp));
    if(pmd_none(*pmd_tmp)){
  printk(KERN_INFO"Not mapped in pmd.\n");
        return 0;
    }
 pte_tmp = pte_offset_kernel(pmd_tmp,va);
    debug_printk(KERN_INFO"pte_tmp = 0x%p\n",pte_tmp);
    debug_printk(KERN_INFO"pte_val(*pte_tmp) = 0x%lx\n",pte_val(*pte_tmp));
    if(pte_none(*pte_tmp)){
  printk(KERN_INFO"Not mapped in pte.\n");
        return 0;
    }
 if(!pte_present(*pte_tmp)){
  printk(KERN_INFO"pte not in RAM.\n");
        return 0;
    }
 pa = (pte_val(*pte_tmp) & PAGE_MASK) |(va & ~PAGE_MASK);
    printk(KERN_INFO"virt_addr 0x%lx in RAM is 0x%lx .\n", va, pa);
    //printk(KERN_INFO"contect in 0x%lx is 0x%lx\n",pa, *(unsigned long *)((char *)pa + PAGE_OFFSET));
    return pa;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值