2012年9月11日 星期二

Add virtual address mapping to current process's page table

Object:
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);
}
Related Posts Plugin for WordPress, Blogger...