天天看點

使用者空間的虛拟位址如何轉換得到實際的實體位址

思路:

程序号是一個程序在使用者空間的唯一标示,是以,根據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)); 
                           
}