linux页表,arm linux 页表(转)
最近在看arm linux 的mm部分,看的是2.6.8.1,芯片是INTEL PXA255,參考資料有arm linux演藝、《情景分析》等。一遍看下來只能說似懂非懂。這里有幾個基礎的問題,大家看看我的理解是否正確,另外還有一個小問題我沒有理解。
arm 的mmu支持4K,16K,64K等幾種頁表和1M的段表(section),arm linux用的應該是4K(small page)頁表和1M的section。
1M的段表地址比較簡單,
[31:20] table index, 2048
[19:0] section index, 1M
4K頁表的地址在ARM里是這樣設置的:
[31:20] first-level table index,4096
[19:12] second-level table index,256
[11:0] page index
而在arm linux里PGD, PMD, PT的劃分又如下:
[31:21] PGD, 2048
[20] PMD, 2
[19:12] PT, 512
但這里的PMD又形同虛設,因為PT一次總是操作相隔256的2的表項,高的為linux,低的為H/W
因此
PTRS_PER_PGD = 2048
PTRS_PER_PTE = 512
PERS_PE_PMD = 1
地址轉換的時候,先找到PGD,這是存放在CP15 C2里面的,tssk->mm->pgd里存放每個任務的pgd。switch_mm的時候放入CP15 C2
cpu_switch_mm(next->pgd, next);
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer, r0 = next->pgd
硬件根據CP15 C2的內容找到一個first-level descriptor table,也就是linux里的PGD,其高18位加上虛擬地址va的[31:20] (first-level table index),讀取這個地址的內容(第一次讀取內存),得到first-level descriptor。
如果first-level descriptor的最低2位是10,表示是section descriptor,則高12位加上va[19:0]就是物理地址。
如果first-level descriptor的最低2位是01,表示是Coarse page table descriptor,高22位(second-level table的地址)加上va[19:12](second-level table index),這個地址讀到second-level descriptor(第二次讀取內存),高20位加上va[11:0],就是最后的物理地址。
以上工作都是硬件自動完成的,arm linux 要做的,就是設置PGD表(first-level table)和頁表(second-level table)。
比如內核的PGD,放在swapper_pg_dir數組的下標0項,同時保存在init_task->mm->pgd中。
但是看到分配頁表的函數create_mapping,有個小問題。
static void __init create_mapping(struct map_desc *md)
{
...
while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
alloc_init_page(virt, virt + off, prot_l1, prot_pte);
virt += PAGE_SIZE;
length -= PAGE_SIZE;
}// 如果地址不是1M對齊的,則先給頭上一部分分配頁表,按頁大小(4K)分配、填充頁表
while (length >= (PGDIR_SIZE / 2)) {
alloc_init_section(virt, virt + off, prot_sect);
virt += (PGDIR_SIZE / 2);
length -= (PGDIR_SIZE / 2);
}// 這里的地址已經是1M對齊的了,設置PGD對應項,按1M分配、填充段表
while (length >= PAGE_SIZE) {
alloc_init_page(virt, virt + off, prot_l1, prot_pte);
virt += PAGE_SIZE;
length -= PAGE_SIZE;
}// 1M對齊剩下的尾巴,分配頁表
...
}
這里都要設置descriptor的保護位,也就是沒有被地址用到的那些位,表示一些狀態屬性。
alloc_init_section只需要段保護位prot_sect就可以了,這個沒什么問題,比如我用的板子,
prot_sect = 0x42e
// 010000101110
// section descriptor
// cache and buffer
// domain = 1,kernel
// ap = 01, read/write
而alloc_init_page由于有first-level table 和 second-level table,需要兩個保護位,分別是prot_l1, prot_pte
奇怪的是,代入的兩個數值
prot_pte = 0x0
// 沒有任何設置
prot_l1 = 0x20
// domain = 1,kernel
因為類型為MEMORY的存儲設備,默認的prot_pte和prot_l1都是0。
雖然我用的PXA255開發板,地址是1M對齊的,且后面沒有多余的地址,不需要前后兩段分配頁表(相信多數的處理器和開發板也是這樣),但是既然有這樣的代碼,就應該賦給正確的值。
后面還有一段,映射中斷向量表所在的區域
init_maps->physical = virt_to_phys(init_maps);
init_maps->virtual = vectors_base();
init_maps->length = PAGE_SIZE;
init_maps->type = MT_VECTORS;
create_mapping(init_maps);
這里面的保護位就沒什么問題
prot_pte = 0xcb
// 11001011
// Extended small page base address
// cache not buffer
// read only?
// TEX = 11
prot_l1 = 0x1
// Coarse page table base address
// domain = 0, user
哪位研究過arm linux mm的朋友能解釋一下?
下面是對上面用到的幾個函數的展開分析。
static inline void
alloc_init_section(unsigned long virt, unsigned long phys, int prot)
{
pmd_t *pmdp;
pmdp = pmd_offset(pgd_offset_k(virt), virt);
// 展開為(pmd_t *)init_mm->pgd + (virt) >> 21, the high 11bit of va
// 得到虛擬地址virt 在 first-level table中的位置
if (virt & (1 << 20))
pmdp++; // linux 的 pmd
set_pmd(pmdp, __pmd(phys | prot));
// *pmdp = phys | prot
}
static inline void
alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
{
pmd_t *pmdp;
pte_t *ptep;
pmdp = pmd_offset(pgd_offset_k(virt), virt);
// 展開為(pmd_t *)init_mm->pgd + (virt) >> 21, the high 11bit of va
// 得到虛擬地址virt 在 first-level table中的位置
if (pmd_none(*pmdp)) { // 如果pmdp沒設置過,分配一個second_level table
unsigned long pmdval;
ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
sizeof(pte_t));
// alloc second_level table
pmdval = __pa(ptep) | prot_l1;
pmdp[0] = __pmd(pmdval);
pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t));
// 在這里填充first-level table對應項
flush_pmd_entry(pmdp);
}
ptep = pte_offset_kernel(pmdp, virt);
set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
// str r1, [r0]
// *ptep = pfn_pte(phys >> PAGE_SHIFT, prot),物理地址高20位加上保護位,放到一個second_level table 中的對應項
}
閱讀(1089) | 評論(0) | 轉發(0) |
總結
以上是生活随笔為你收集整理的linux页表,arm linux 页表(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android usb多个,androi
- 下一篇: Android 电视 文件目录,通用的安