ppc manual paging question
Wang, Baojun
wangbj at lzu.edu.cn
Mon Oct 22 14:03:23 EST 2007
hi,
I've got some qeustion about ppc(ppc44x) paging:
how can I manually map a virtual address to a physical address through a
specific pgd? How does ppc translate virt address to physical one? I think
besides from tlb, the CPU will search the page table entries via the pgd, can
I alter the pgd value to change the memory translation? under i386, it's very
simple, we can just rewrite %%cr3, it even could invalidate all tlb entries
automatically, how can I do this under ppc? I've tried rewrite
current->mm->pgd and current->thread.pgdir, but sounds like it still not
insufficiant, am I missing something vital?
Any hint will be greatly approciated.
Regards,
Wang
P.S:
here is the code:
#define save_pd(pd) ((pd) = (unsigned long)(current->mm->pgd))
#define load_pd(pd) (current->mm->pgd = (pd))
...
static inline pgd_t* __pgd_offset(unsigned long pgd_base, unsigned long va)
{
return (pgd_t*)((pgd_t*)pgd_base + pgd_index(va));
}
static inline pte_t* pte_offset(pmd_t* pte_base, unsigned long va)
{
return (pte_t*)((pte_t*)pte_base + pte_index(va));
}
static inline unsigned long get_free_pages_atomic(int order)
{
return __get_free_pages(GFP_ATOMIC, order);
}
...
unsigned long create_page_directory (unsigned long (*alloc_page) (void)) {
unsigned long pd, c_pd;
unsigned long idx;
save_pd(c_pd);
pd = get_free_pages_atomic(PGD_ORDER);
if(!pd) return 0;
memset((void*)pd, 0, PGD_ORDER << PAGE_SHIFT);
/*
* copy kernel page directies
*/
idx = pgd_index(PAGE_OFFSET);
memcpy((pgd_t*)pd + idx, (pgd_t*)c_pd + idx, (PTRS_PER_PGD - idx) *
sizeof(pgd_t));
printk(KERN_EMERG"create_page_directory return: 0x%lx, c_pd: 0x%lx\n", pd,
c_pd);
return pd;
}
/*
* allocate a user page at @vaddress if possible
* TODO: add tlb/slb/bat for fast page/block address translation
*/
unsigned long allocate_user_page (unsigned long pd,
unsigned long vaddress,
unsigned long (*alloc_page) (void)) {
pgd_t* pgd;
pud_t* pud;
pmd_t* pmd;
pte_t* pte;
unsigned long page = 0;
#define mm_debug printk
mm_debug("allocate_user_page(0x%lx, 0x%lx, 0x%lx)\n", pd, vaddress,
alloc_page);
pgd = __pgd_offset(pd, vaddress);
if(!pgd_present(*pgd) || !(*pgd)){
pud_t* pud_entry = (pud_t*)get_free_pages_atomic(PUD_ORDER);
if(!pud_entry) return 0;
*pgd = __pa(pud_entry) & PAGE_MASK;
mm_debug("!pgd_present, pgd: 0x%lx, *pgd: 0x%lx\n", pgd,
*pgd);
}
pud = pud_offset(pgd, vaddress);
if(!pud_present(*pud) || !(*pud)){
pmd_t* pmd_entry = (pmd_t*)get_free_pages_atomic(PMD_ORDER);
if(!pmd_entry) return 0;
*pud = __pa(pmd_entry) & PAGE_MASK;
mm_debug("!pud_present, pud: 0x%lx, *pud: 0x%lx\n", pud,
*pud);
}
pmd = pmd_offset(pud, vaddress);
if(!pmd_present(*pmd) || !(*pmd)){
pte_t* pte_entry = (pte_t*)get_free_pages_atomic(PTE_ORDER);
if(!pte_entry) return 0;
*pmd = __pa(pte_entry) & PAGE_MASK;
*pmd |= _PMD_PRESENT;
mm_debug("!pmd_present, pmd: 0x%lx, *pmd: 0x%lx\n", pmd,
*pmd);
}
pte = pte_offset(pmd, vaddress);
if(!pte_present(*pte) || !(*pte) || pte_none(*pte)){
unsigned long pfn;
page = get_free_pages_atomic(PAGE_ORDER);
mm_debug("page: 0x%lx\n", page);
pfn = __pa(page) & PAGE_MASK;
mm_debug("pfn: 0x%lx\n", pfn);
set_pte_at(current->mm, page, pte, pfn_pte(pfn >> PAGE_SHIFT,
__pgprot(PAGE_SHARED_X)));
mm_debug("pte_present now?: %lld\n", pte_present(*pte));
mm_debug("!pte_present, pte: 0x%lx\n", pte);
}
mm_debug("allocate_user_page: return 0x%lx\n", page);
#undef mm_debug
return page;
}
--
Wang, Baojun Lanzhou University
Distributed & Embedded System Lab http://dslab.lzu.edu.cn
School of Information Science and Engeneering wangbj at lzu.edu.cn
Tianshui South Road 222. Lanzhou 730000 .P.R.China
Tel:+86-931-8912025 Fax:+86-931-8912022
More information about the Linuxppc-dev
mailing list