日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux页表,arm linux 页表(转)

發布時間:2023/12/18 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 页表(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。