Using hardware MMU to speedup the translation of gva to hpa for QEMU system mode.
Note: pgd , pud, pmd are the table entry, not the table
Reference:
Sample kernel code:
//#include <asm/tlb.h> #include <linux/mm.h> #include <linux/mm_types.h> #include <linux/sched.h> #include <asm/pgalloc.h> //#include <asm/pgtable_types.h> //for struct page #include <asm/tlbflush.h> //vaddr_h: vaddr above 4G long sys_cr3(unsigned long vaddr_h) { unsigned long eax; unsigned long vaddr=0x10000000 | (vaddr_h & 0xfff); pgd_t *pgd; pud_t *pud; pmd_t *pmd, pmd_n; pte_t *pte, *pte_h; struct page *page; pgprot_t pgprot;// = __pgprot(0x67); //pgprot.pgprot=0x67; //set_pte_vaddr(vaddr, ptep); //pte_alloc(); //get origen page above 4G pgd = pgd_offset(current->mm, vaddr_h); pud = pud_offset(pgd, vaddr_h); pmd = pmd_offset(pud, vaddr_h); pgprot = __pgprot(pmd_val(*pmd) & 0xfff); pte_h = pte_offset_map(pmd, vaddr_h); //mapping vaddr_h above 4G to vaddr below 4G //alloc page entry pgd = pgd_offset(current->mm, vaddr); if(pgd_none(*pgd)) { printk("pgd entry not found, alloc new pud and set pgd entry\n"); /* FIXME */ //pud = pud_alloc(current->mm, current->mm->pgd, vaddr); //set_pud(pgd, *pud); pgd = pgd_alloc(current->mm); } pud = pud_offset(pgd, vaddr); if(pud_none(*pud)) { printk("pud entry not found, alloc new pmd and set pud entry\n"); /* FIXME */ pud = pud_alloc(current->mm, pgd, vaddr); } pmd = pmd_offset(pud, vaddr); if(pmd_none(*pmd)) { printk("pmd entry not found, alloc new pte and set pmd entry\n"); //pmd = pmd_alloc(current->mm, pud, vaddr); page = pte_alloc_one(current->mm, vaddr); pmd_n = mk_pmd(page, pgprot); set_pmd(pmd, pmd_n); } /* pte = pte_offset_map(pmd, vaddr); if(!pte) { printk("pte_alloc\n"); //page table entry is not availble, alloc one page table //Note: pte is page table pointer, not page table entry ptep = pte_alloc_map(current->mm, current->mm->mmap, pmd, vaddr); if(!ptep) printk("pte_alloc_map fail\n"); } */ //pte = page table entry pte = pte_offset_map(pmd, vaddr); //printk("vaddr_h: pmd_index:%lu, pte_index:%lu\n", // pmd_index(vaddr_h), pte_index(vaddr_h)); //set new pte as origin pte_h set_pte(pte, *pte_h); //printk("__pa(%lx)=%lx, __pa(12345678)=%lx\n", // vaddr_h, __pa(vaddr_h), __pa(0x12345678)); //update_mmu_cache(current->mm->mmap, vaddr, pte); //flush_tlb_mm(current->mm); __asm__ __volatile__ ( #ifdef CONFIG_X86_64 "mov %%cr3, %%rax" #else "mov %%cr3, %%eax" #endif : "=a" (eax) : /* no input */ : ); return eax; //flush_tlb_page(current->mm->mmap, 0x12345); }