使用者空間的虛擬地址如何轉換得到實際的實體地址
阿新 • • 發佈:2019-01-28
思路:
程序號是一個程序在使用者空間的唯一標示,所以,根據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)); }