用户空间的虚拟地址如何转换得到实际的物理地址

思路:

进程号是一个进程在用户空间的唯一标示,所以,根据pid可以从内核中得到一个进程的所有信息,

另外就是知道虚拟地址就可以通过内核物理地址映射到虚拟地址的逆运算就可以还原他的实际物理地址

以上便是虚拟地址转换成所对应的实际物理地址的思路。

大致的代码编写流程:

首先根据pid我们可以得到这个进程的task_struct,进而通过task_struct得到mm,通过mm得到pgd。
好了,现在我们有pgd和virtualaddress.
通过pgd和virtualaddress我们可以得到页表pte.
 
有了pte和virtualaddress,我们就可以计算物理地址了
phyaddress=(pte_val(pte)&PAGE_MASK)|(virtualladdress&~PAGE_MASK)


代码:

#include <linux/sched.h> 
#include <linux/mm.h> 
#include <asm/pgtable.h> 
#include <asm/page.h> 
 
static int v2p(int pid, unsigned long va) 
{ 
    unsigned long pa = 0; 
    struct task_struct *pcb_tmp; 
    pgd_t *pgd_tmp = NULL; 
    pud_t *pud_tmp = NULL; 
    pmd_t *pmd_tmp = NULL; 
    pte_t *pte_tmp = NULL; 
 
    printk(KERN_INFO"PAGE_OFFSET = 0x%lx\n",PAGE_OFFSET); 
    printk(KERN_INFO"PGDIR_SHIFT = %d\n",PGDIR_SHIFT); 
    printk(KERN_INFO"PUD_SHIFT = %d\n",PUD_SHIFT); 
    printk(KERN_INFO"PMD_SHIFT = %d\n",PMD_SHIFT); 
    printk(KERN_INFO"PAGE_SHIFT = %d\n",PAGE_SHIFT); 
 
    printk(KERN_INFO"PTRS_PER_PGD = %d\n",PTRS_PER_PGD); 
    printk(KERN_INFO"PTRS_PER_PUD = %d\n",PTRS_PER_PUD); 
    printk(KERN_INFO"PTRS_PER_PMD = %d\n",PTRS_PER_PMD); 
    printk(KERN_INFO"PTRS_PER_PTE = %d\n",PTRS_PER_PTE); 
 
    printk(KERN_INFO"PAGE_MASK = 0x%lx\n",PAGE_MASK); 
 /* 查询当前进程下的虚拟地址 */
 //   pcb_tmp = current; 
/* 查询指定进程的下的虚拟地址 */
     pcb_tmp = find_task_by_vpid (pid); // 较新一点的内核版本使用这个函数
// pcb_tmp = find_task_by_pid (pid);    // 旧版本的内核版本使用这个函数
    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); 
    printk(KERN_INFO"pgd_tmp = 0x%p\n",pgd_tmp); 
    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; 
    } 
    pud_tmp = pud_offset(pgd_tmp,va); 
    printk(KERN_INFO"pud_tmp = 0x%p\n",pud_tmp); 
    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); 
    printk(KERN_INFO"pmd_tmp = 0x%p\n",pmd_tmp); 
    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); 
 
    printk(KERN_INFO"pte_tmp = 0x%p\n",pte_tmp); 
    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)); 
                           
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值