sel4 vspace指的是進程的虛擬地址空間。armv8 64位版本的sel4 對應的頁表劃分分爲四級,分別是:pgd(page global directory)、pud(page upper directory)、pd(page directory)和pt(page table)。
本文主要介紹了sel4關於頁表的基本數據結構體、sel4爲初始進程創建頁表的過程解析以及簡要的描述了AArch64架構虛擬地址到物理地址的轉換流程。
基本數據結構
pgd
pgd結構體:
- pud_base_address:指向pud基地址的指針(指向的pud大小爲4K);
block pgde_pud {
padding 16
field_high pud_base_address 36
padding 10
field pgde_type 2 -- must be 0b11
}
pgd cap結構體:
- capPGDMappedASID:進程的ASID(address space Identifiers);
- capPGDBasePtr:指向pgd結構體的指針。
block page_global_directory_cap {
field capPGDMappedASID 16
field_high capPGDBasePtr 48
field capType 5
field capPGDIsMapped 1
padding 58
}
pud
pud結構體:
- pd_base_address:指向pd基地址的指針(指向的pd大小爲4K);
block pude_pd {
padding 16
field_high pd_base_address 36
padding 10
field pude_type 2
}
pud cap結構體:
- capPUDMappedASID:進程的ASID(address space Identifiers);
- capPUDBasePtr:指向pud結構體的指針;
- capPUDMappedAddress:指向映射的虛擬地址。
block page_upper_directory_cap {
field capPUDMappedASID 16
field_high capPUDBasePtr 48
field capType 5
field capPUDIsMapped 1
field_high capPUDMappedAddress 10
padding 48
}
pd
pd結構體:
- pt_base_address:指向pt基地址的指針(指向的pt大小爲4K);
block pde_small {
padding 16
field_high pt_base_address 36
padding 10
field pde_type 2
}
pd cap結構體:
- capPDMappedASID:進程的ASID(address space Identifiers);
- capPDBasePtr:指向pd結構體的指針;
- capPDMappedAddress:指向映射的虛擬地址。
block page_directory_cap {
field capPDMappedASID 16
field_high capPDBasePtr 48
field capType 5
padding 10
field capPDIsMapped 1
field_high capPDMappedAddress 19
padding 29
}
pt
pte結構體:
- 描述頁面屬性;
block pte {
padding 9
field UXN 1
padding 6
field_high page_base_address 36
field nG 1
field AF 1
field SH 2
field AP 2
#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
field AttrIndx 4
#else
padding 1
field AttrIndx 3
#endif
field reserved 2 -- must be 0b11
}
page_table_cap結構體:
- capPTMappedASID:進程的ASID(address space Identifiers);
- capPTBasePtr:指向pt結構體的指針;
- capPTMappedAddress:指向映射的虛擬地址。
block page_table_cap {
field capPTMappedASID 16
field_high capPTBasePtr 48
field capType 5
padding 10
field capPTIsMapped 1
field_high capPTMappedAddress 28
padding 20
}
sel4進程分配地址空間
這裏以初始進程爲例,初始進程的頁表建立過程大致分爲三步:創建內存、建立映射、填充頁表項屬性。具體如下所示:
create_rootserver_objects函數
-
爲vspace分配內存空間,大小爲4k。這片內存用於存放pgd的地址映射關係;
-
爲rootserver.paging分配內存空間,大小爲存放初始進程的鏡像尺寸。這片內存用於存放pud、pd、pt的地址映射關係;
BOOT_CODE void create_rootserver_objects(pptr_t start, v_region_t v_reg, word_t extra_bi_size_bits)
{
...
rootserver.vspace = alloc_rootserver_obj(seL4_VSpaceBits, 1);
/* paging structures are 4k on every arch except aarch32 (1k) */
word_t n = arch_get_n_paging(v_reg);
rootserver.paging.start = alloc_rootserver_obj(seL4_PageTableBits, n);
rootserver.paging.end = rootserver.paging.start + n * BIT(seL4_PageTableBits);
...
}
create_it_address_space函數
-
創建vspace_cap即page_global_directory_cap,他的成員capPGDBasePtr指向create_rootserver_objects爲vspace分配的4k內存首地址,包含個pud表項;
-
爲pud的映射關係表分配內存,其大小爲4K,包含了個pd表項(從rootserver.paging中取出)。capPUDBasePtr指向pud的基地址,capPUDMappedAddress指向映射的虛擬地址。在pgd裏插入該pud表項;
-
爲pd的映射關係表分配內存,其大小爲4K,包含了個pt表項(從rootserver.paging中取出)。capPDBasePtr指向pd的基地址,capPDMappedAddress指向映射的虛擬地址。在pud裏插入該pd表項;
-
爲pt的映射關係表分配內存,其大小爲4K,包含了個表項(從rootserver.paging中取出)。capPTBasePtr指向pt的基地址,capPTMappedAddress指向映射的虛擬地址。在pd裏插入該pT表項;
BOOT_CODE cap_t create_it_address_space(cap_t root_cnode_cap, v_region_t it_v_reg)
{
cap_t vspace_cap;
vptr_t vptr;
seL4_SlotPos slot_pos_before;
seL4_SlotPos slot_pos_after;
/* create the PGD */
vspace_cap = cap_vtable_cap_new(
IT_ASID, /* capPGDMappedASID */
rootserver.vspace, /* capPGDBasePtr */
1 /* capPGDIsMapped */
);
slot_pos_before = ndks_boot.slot_pos_cur;
write_slot(SLOT_PTR(pptr_of_cap(root_cnode_cap), seL4_CapInitThreadVSpace), vspace_cap);
/* Create any PUDs needed for the user land image */
for (vptr = ROUND_DOWN(it_v_reg.start, PGD_INDEX_OFFSET);
vptr < it_v_reg.end;
vptr += BIT(PGD_INDEX_OFFSET)) {
if (!provide_cap(root_cnode_cap, create_it_pud_cap(vspace_cap, it_alloc_paging(), vptr, IT_ASID))) {
return cap_null_cap_new();
}
}
/* Create any PDs needed for the user land image */
for (vptr = ROUND_DOWN(it_v_reg.start, PUD_INDEX_OFFSET);
vptr < it_v_reg.end;
vptr += BIT(PUD_INDEX_OFFSET)) {
if (!provide_cap(root_cnode_cap, create_it_pd_cap(vspace_cap, it_alloc_paging(), vptr, IT_ASID))) {
return cap_null_cap_new();
}
}
/* Create any PTs needed for the user land image */
for (vptr = ROUND_DOWN(it_v_reg.start, PD_INDEX_OFFSET);
vptr < it_v_reg.end;
vptr += BIT(PD_INDEX_OFFSET)) {
if (!provide_cap(root_cnode_cap, create_it_pt_cap(vspace_cap, it_alloc_paging(), vptr, IT_ASID))) {
return cap_null_cap_new();
}
}
slot_pos_after = ndks_boot.slot_pos_cur;
ndks_boot.bi_frame->userImagePaging = (seL4_SlotRegion) {
slot_pos_before, slot_pos_after
};
return vspace_cap;
}
- 最後由函數create_frames_of_region填充頁表的頁表項,具體可以參看pt的結構體;
AArch64架構虛擬地址轉換的簡要過程
虛擬地址轉換成物理地址流程:
- 取虛擬地址高九位結合TTBR_ELx寄存器找到pgd的首地址;
- 再取虛擬地址九位得到pgde,裏面包含pud的首地址;
- 再取九位得到pude,裏面包含pd的首地址;
- 再取九位得到pde,裏面包含pt的首地址;
- 剩餘的低十二位爲頁內地址。
相關鏈接
sel4源碼解析(一) - sel4內核對象
sel4源碼解析(二) - CSpace
sel4源碼解析(三) - sel4系統調用處理流程
sel4源碼解析(四) - ipc
sel4源碼解析(五) - Notification
sel4源碼解析(六) - 進程
sel4源碼解析(七) - vspace