Linux/ARM 通过软件方法遍历页表

原创文章,转载请注明出处.转载自: Li Haifeng's Blog
本文链接地址: Linux/ARM 通过软件方法遍历页表

翻译地址、遍历页表本是硬件MMU所做的工作。如何用软件来模拟出来呢?之前曾经写过一个简单的伪码实现:

unsigned long va2pa(unsigned long address)
{
pgd_t * pgd;
pud_t * pud;
pmd_t * pmd;
pte_t * pte;
pgd=cpu_get_pgd();
pud=pud_offset(pgd,address);
pmd=pmd_offset(pud,address);
pte=pte_offset_map(pmd,address);
pa=(*pte->pte>>12)<<12;
return pa;
}
不曾想,Kernel内部已经有此实现了^_^.
arch/arm/mm/fault.c

 1 /*
2 * This is useful to dump out the page tables associated with
3 * 'addr' in mm 'mm'.
4 */
5 void show_pte(struct mm_struct *mm, unsigned long addr)
6 {
7 pgd_t *pgd;
8
9 if (!mm)
10 mm = &init_mm;
11
12 printk(KERN_ALERT "pgd = %pn", mm->pgd);
13 pgd = pgd_offset(mm, addr);
14 printk(KERN_ALERT "[%08lx] *pgd=%08llx",
15 addr, (long long)pgd_val(*pgd));
16
17 do {
18 pud_t *pud;
19 pmd_t *pmd;
20 pte_t *pte;
21
22 if (pgd_none(*pgd))
23 break;
24
25 if (pgd_bad(*pgd)) {
26 printk("(bad)");
27 break;
28 }
29
30 pud = pud_offset(pgd, addr);
31 if (PTRS_PER_PUD != 1)
32 printk(", *pud=%08llx", (long long)pud_val(*pud));
33
34 if (pud_none(*pud))
35 break;
36
37 if (pud_bad(*pud)) {
38 printk("(bad)");
39 break;
40 }
41
42 pmd = pmd_offset(pud, addr);
43 if (PTRS_PER_PMD != 1)
44 printk(", *pmd=%08llx", (long long)pmd_val(*pmd));
45
46 if (pmd_none(*pmd))
47 break;
48
49 if (pmd_bad(*pmd)) {
50 printk("(bad)");
51 break;
52 }
53
54 /* We must not map this if we have highmem enabled */
55 if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
56 break;
57
58 pte = pte_offset_map(pmd, addr);
59 printk(", *pte=%08llx", (long long)pte_val(*pte));
60 #ifndef CONFIG_ARM_LPAE
61 printk(", *ppte=%08llx",
62 (long long)pte_val(pte[PTE_HWTABLE_PTRS]));
63 #endif
64 pte_unmap(pte);
65 } while(0);
66
67 printk("n");
68 }

From Li Haifeng's Blog, post Linux/ARM 通过软件方法遍历页表

Post Footer automatically generated by wp-posturl plugin for wordpress.

分享到: