页表分配和释放
init_pg_dir页表的主要的作用就是在boot阶段,能够把kernel image的编译时VA(也就是0xffffxxxxxxxxxxxx,但是在使能了CONFIG_RANDOMIZE_BASE会加一个offset)映射成u-boot加载时的PA。 所以这个页表的大小就是根据kernel image所占用空间来决定。
#define EARLY_PAGES(vstart, vend, add) ( 1 /* PGDIR page */ \
+ EARLY_PGDS((vstart), (vend), add) /* each PGDIR needs a next level page table */ \
+ EARLY_PUDS((vstart), (vend), add) /* each PUD needs a next level page table */ \
+ EARLY_PMDS((vstart), (vend), add)) /* each PMD needs a next level page table */
#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end, EXTRA_PAGE))
这里为什么要加一个EXTRA_PAGE? 因为kernel是relocatable,所以如果做了relocate,在最差的情况下,它有可能地址会跨一个page,所以就需要一个额外的页表:
/*
* A relocatable kernel may execute from an address that differs from the one at
* which it was linked. In the worst case, its runtime placement may intersect
* with two adjacent PGDIR entries, which means that an additional page table
* may be needed at each subordinate level.
*/
#define EXTRA_PAGE __is_defined(CONFIG_RELOCATABLE)
这个页表是在Link脚本里面进行分配:
. = ALIGN(PAGE_SIZE);
init_pg_dir = .;
. += INIT_DIR_SIZE;
init_pg_end = .;
在MMU切换到swapper_pg_dir页表之后,会在setup_arch->paging_init 里面进行回收,这样系用就可以重新利用这部分内存:
void __init paging_init(void)
{
pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));
//.......
cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_idmap_pg_dir);
init_mm.pgd = swapper_pg_dir;
memblock_phys_free(__pa_symbol(init_pg_dir),
__pa_symbol(init_pg_end) - __pa_symbol(init_pg_dir));
要建立init_pg_dir页表,就要通过写init_pg_dir这个页表来建立kernel VA到PA的映射。 为了加快boot速度,kernel会在 1:1 mapping完成并打开MMU和cache之后,才开始建立init_pg_dir页表。 所以就需要在1:1页表(init_idmap_pg_dir)中建立init_pg_dir这部分内存的1:1映射. 这部分代码在 primary_entry-> create_idmap:
/* Remap the kernel page tables r/w in the ID map */
adrp x1, _text
adrp x2, init_pg_dir
adrp x3, init_pg_end
bic x4, x2, #SWAPPER_BLOCK_SIZE - 1
mov_q x5, SWAPPER_RW_MMUFLAGS
mov x6, #SWAPPER_BLOCK_SHIFT
bl remap_region
页表建立完成之后,可以看到init_pg_dir区域是可以读写的:
>mmu print EL1N_S1_TTBR0_EL1 TTBR0_EL1=init_idmap_pg_dir
Input Address | Type | Next Level | Output Address | Properties
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ 0x00000000 | TTBR0_EL1 | NP:0x0000000085A90000 | | TBI1=0, TBI0=0, AS=0, IPS=4GB, TG1=4KB, SH1=0x0, ORGN1=0x0, IRGN1=0x0, EPD1=0, A1=0, T1SZ=0, TG0=4KB, SH0=0x0, ORGN0=0x0, IRGN0=0x0, EPD0=0, T0SZ=0, HPD1=0, HPD0=0, HD=0, HA=0, CnP=0, ASID=0
+ 0x00000000 | Level 0 Table | NP:0x0000000085A91000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0x00000000 | Invalid | | |
- 0x40000000 | Invalid | | |
+ 0x80000000 | Level 1 Table | NP:0x0000000085A92000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0x80000000 | Invalid (x32) | | |
- 0x84000000 | Level 2 Block | | NP:0x0000000084000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x84200000 | Level 2 Block | | NP:0x0000000084200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x84400000 | Level 2 Block | | NP:0x0000000084400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x84600000 | Level 2 Block | | NP:0x0000000084600000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x84800000 | Level 2 Block | | NP:0x0000000084800000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x84A00000 | Level 2 Block | | NP:0x0000000084A00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x84C00000 | Level 2 Block | | NP:0x0000000084C00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x84E00000 | Level 2 Block | | NP:0x0000000084E00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x85000000 | Level 2 Block | | NP:0x0000000085000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x85200000 | Level 2 Block | | NP:0x0000000085200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x85400000 | Level 2 Block | | NP:0x0000000085400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x85600000 | Level 2 Block | | NP:0x0000000085600000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x85800000 | Level 2 Block | | NP:0x0000000085800000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x85A00000 | Level 2 Block | | NP:0x0000000085A00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x85C00000 | Level 2 Block | | NP:0x0000000085C00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x85E00000 | Level 2 Block | | NP:0x0000000085E00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x86000000 | Level 2 Block | | NP:0x0000000086000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x86200000 | Level 2 Block | | NP:0x0000000086200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0x86400000 | Level 2 Block | | NP:0x0000000086400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0x86600000 | Level 2 Block | | NP:0x0000000082000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0x86800000 | Level 2 Block | | NP:0x0000000082200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0x86A00000 | Invalid (x459) | | |
- 0xC0000000 | Invalid (x509) | | |
- 0x8000000000 | Invalid (x511) | | |
>p/x init_pg_end
$9 = (unsigned char*) EL1N:0x00000000865DD000
>p/x init_pg_dir
$10 = (unsigned char*) EL1N:0x00000000865DA000
init_pg_dir 页表的创建
在MMU enable之后,就可以开始使用这个页表了。在 FDT的区域的Map过程 ,有提到init_pg_dir会在__primary_switch被临时用来做栈来获取kaslr的offset。
SYM_FUNC_START_LOCAL(__primary_switch)
adrp x1, reserved_pg_dir
adrp x2, init_idmap_pg_dir
bl __enable_mmu
#ifdef CONFIG_RELOCATABLE
adrp x23, KERNEL_START
and x23, x23, MIN_KIMG_ALIGN - 1
#ifdef CONFIG_RANDOMIZE_BASE
mov x0, x22
adrp x1, init_pg_end
mov sp, x1
mov x29, xzr
bl __pi_kaslr_early_init
and x24, x0, #SZ_2M - 1 // capture memstart offset seed
bic x0, x0, #SZ_2M - 1
orr x23, x23, x0 // record kernel offset
#endif
#endif
bl clear_page_tables
bl create_kernel_mapping
在使用完成之后,会调用clear_page_tables 来清除之前可能遗留的内容。 因为没有使用的页表应该初始化成全0. 在create_kernel_mapping函数中,这个KIMAGE_VADDR对应的就是kernel的VA,它的PA应该对应_text。 但是使能了relocation,那么就可以需要加上x23 这个offset。
SYM_FUNC_START_LOCAL(create_kernel_mapping)
adrp x0, init_pg_dir
mov_q x5, KIMAGE_VADDR // compile time __va(_text)
#ifdef CONFIG_RELOCATABLE
add x5, x5, x23 // add KASLR displacement
#endif
adrp x6, _end // runtime __pa(_end)
adrp x3, _text // runtime __pa(_text)
sub x6, x6, x3 // _end - _text
add x6, x6, x5 // runtime __va(_end)
mov_q x7, SWAPPER_RW_MMUFLAGS
map_memory x0, x1, x5, x6, x7, x3, (VA_BITS - PGDIR_SHIFT), x10, x11, x12, x13, x14
dsb ishst // sync with page table walker
ret
SYM_FUNC_END(create_kernel_mapping)
在函数create_kernel_mapping执行完成之后,可以看从_text 到_end的PA都建立了页表,如下:
>mmu print EL1N_S1_TTBR1_EL1 TTBR1_EL1=init_pg_dir
Input Address | Type | Next Level | Output Address | Properties
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ 0xFFFF000000000000 | TTBR1_EL1 | NP:0x00000000865DA000 | | TBI1=1, TBI0=1, AS=1, IPS=256TB, TG1=4KB, SH1=0x3, ORGN1=0x1, IRGN1=0x1, EPD1=0, A1=1, T1SZ=16, TG0=4KB, SH0=0x3, ORGN0=0x1, IRGN0=0x1, EPD0=0, T0SZ=16, HPD1=0, HPD0=0, HD=0, HA=1, CnP=0, ASID=0
- 0xFFFF000000000000 | Invalid (x256) | | |
+ 0xFFFF800000000000 | Level 0 Table | NP:0x00000000865DB000 | | APTable=0x0, UXNTable=0, PXNTable=0
+ 0xFFFF800000000000 | Level 1 Table | NP:0x00000000865DC000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFF800000000000 | Invalid (x64) | | |
- 0xFFFF800008000000 | Level 2 Block | | NP:0x0000000084000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008200000 | Level 2 Block | | NP:0x0000000084200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008400000 | Level 2 Block | | NP:0x0000000084400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008600000 | Level 2 Block | | NP:0x0000000084600000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008800000 | Level 2 Block | | NP:0x0000000084800000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008A00000 | Level 2 Block | | NP:0x0000000084A00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008C00000 | Level 2 Block | | NP:0x0000000084C00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008E00000 | Level 2 Block | | NP:0x0000000084E00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009000000 | Level 2 Block | | NP:0x0000000085000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009200000 | Level 2 Block | | NP:0x0000000085200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009400000 | Level 2 Block | | NP:0x0000000085400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009600000 | Level 2 Block | | NP:0x0000000085600000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009800000 | Level 2 Block | | NP:0x0000000085800000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009A00000 | Level 2 Block | | NP:0x0000000085A00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009C00000 | Level 2 Block | | NP:0x0000000085C00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009E00000 | Level 2 Block | | NP:0x0000000085E00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A000000 | Level 2 Block | | NP:0x0000000086000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A200000 | Level 2 Block | | NP:0x0000000086200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A400000 | Level 2 Block | | NP:0x0000000086400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A600000 | Invalid (x429) | | |
- 0xFFFF800040000000 | Invalid (x511) | | |
- 0xFFFF808000000000 | Invalid (x255) | | |
>p/x _text
$13 = (unsigned char*) EL1N:0x0000000084000000
>p/x $x23
$14 = 0x0
>p/x _end
$15 = (unsigned char*) EL1N:0x00000000865E0000
init_pg_dir 的使能和使用
在创建好了页表之后,在函数primary_entry-> __primary_switch 就可以把这个页表写到TTBR1中了:
SYM_FUNC_START_LOCAL(__primary_switch)
adrp x1, reserved_pg_dir
adrp x2, init_idmap_pg_dir
//.....
bl clear_page_tables
bl create_kernel_mapping
adrp x1, init_pg_dir
load_ttbr1 x1, x1, x2
在设置好了TTBR1之后,kernel就可以跳转到VA(0xffff开头的地址) 之后继续执行,如下这段代码从1:1 的VA转换成kernel真正的VA, __primary_switched就是运行在0xffff开头的VA
SYM_FUNC_START_LOCAL(__primary_switch)
//....
ldr x8, =__primary_switched
adrp x0, KERNEL_START // __pa(KERNEL_START)
br x8
SYM_FUNC_END(__primary_switch)
在执行到__primary_switched之后,1:1的mapping就不在使用。仅仅在切换swapper_pg_dir页表的时候临时使用一次。 参考: Arm64 Linux 下页表 init_idmap_pg_dir的使用 而在 FDT的区域的Map过程 中,有提到在__primary_switched->init_feature_override中会临时使用device tree,要为device tree 临时建立页表。 这里其实也会修改表init_pg_dir 里面的内容:
这时候不可以用init_pg_dir dump页表,因为这个时候mmu已经enable,而变量init_pg_dir就已经是0xffff开头的地址。
>mmu print EL1N_S1_TTBR1_EL1 TTBR1_EL1=0x00000000865DA000
Input Address | Type | Next Level | Output Address | Properties
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ 0xFFFF000000000000 | TTBR1_EL1 | NP:0x00000000865DA000 | | TBI1=1, TBI0=1, AS=1, IPS=256TB, TG1=4KB, SH1=0x3, ORGN1=0x1, IRGN1=0x1, EPD1=0, A1=1, T1SZ=16, TG0=4KB, SH0=0x3, ORGN0=0x1, IRGN0=0x1, EPD0=0, T0SZ=16, HPD1=0, HPD0=0, HD=0, HA=1, CnP=0, ASID=0
- 0xFFFF000000000000 | Invalid (x256) | | |
+ 0xFFFF800000000000 | Level 0 Table | NP:0x00000000865DB000 | | APTable=0x0, UXNTable=0, PXNTable=0
+ 0xFFFF800000000000 | Level 1 Table | NP:0x00000000865DC000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFF800000000000 | Invalid (x64) | | |
- 0xFFFF800008000000 | Level 2 Block | | NP:0x0000000084000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008200000 | Level 2 Block | | NP:0x0000000084200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008400000 | Level 2 Block | | NP:0x0000000084400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008600000 | Level 2 Block | | NP:0x0000000084600000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008800000 | Level 2 Block | | NP:0x0000000084800000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008A00000 | Level 2 Block | | NP:0x0000000084A00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008C00000 | Level 2 Block | | NP:0x0000000084C00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008E00000 | Level 2 Block | | NP:0x0000000084E00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009000000 | Level 2 Block | | NP:0x0000000085000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009200000 | Level 2 Block | | NP:0x0000000085200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009400000 | Level 2 Block | | NP:0x0000000085400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009600000 | Level 2 Block | | NP:0x0000000085600000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009800000 | Level 2 Block | | NP:0x0000000085800000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009A00000 | Level 2 Block | | NP:0x0000000085A00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009C00000 | Level 2 Block | | NP:0x0000000085C00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009E00000 | Level 2 Block | | NP:0x0000000085E00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A000000 | Level 2 Block | | NP:0x0000000086000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A200000 | Level 2 Block | | NP:0x0000000086200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A400000 | Level 2 Block | | NP:0x0000000086400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A600000 | Invalid (x429) | | |
- 0xFFFF800040000000 | Invalid (x511) | | |
- 0xFFFF808000000000 | Invalid (x246) | | |
+ 0xFFFFFB8000000000 | Level 0 Table | NP:0x0000000086542000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFFFB8000000000 | Invalid (x511) | | |
+ 0xFFFFFBFFC0000000 | Level 1 Table | NP:0x0000000086543000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFFFBFFC0000000 | Invalid (x493) | | |
+ 0xFFFFFBFFFDA00000 | Level 2 Table | NP:0x0000000086544000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFFFBFFFDA00000 | Invalid (x512) | | |
- 0xFFFFFBFFFDC00000 | Level 2 Block | | NP:0x0000000082000000 | UXN=1, PXN=1, Contiguous=0, DBM=1, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFFFBFFFDE00000 | Invalid (x17) | | |
- 0xFFFFFC0000000000 | Invalid (x8) | | |
可以发现,后面建立的几个页表不是在init_pg_dir 这个里面,而是在全局变量中:
>p/x init_pg_end
$9 = (unsigned char*) EL1N:0x00000000865DD000
>p/x init_pg_dir
$10 = (unsigned char*) EL1N:0x00000000865DA000
static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __page_aligned_bss;
static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
从init_pg_dir切换到swapper_pg_dir
从__primary_switched 开始到swapper_pg_dir生效,kernel一直使用init_pg_dir这个页表。 期间为了使能串口等调试设备,可以要进行一些IO的mapping,比如:
void __init __no_sanitize_address setup_arch(char **cmdline_p)
{
//....
early_fixmap_init();
early_ioremap_init();
setup_machine_fdt(__fdt_pointer);
//...
parse_early_param();
执行完parse_early_param 之后,我们可以看到在fixe memory map里面有了一些IO的映射,比如地址: 0x000000001C090000就是u-boot的bootargs给的一个地址:
CONFIG_BOOTARGS="console=ttyAMA0 earlycon=pl011,0x1c090000 root=/dev/vda2 rw ip=dhcp debug user_debug=31 loglevel=9"
>mmu print EL1N_S1_TTBR1_EL1 TTBR1_EL1=0x00000000865DA000
Input Address | Type | Next Level | Output Address | Properties
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ 0xFFFF000000000000 | TTBR1_EL1 | NP:0x00000000865DA000 | | TBI1=1, TBI0=1, AS=1, IPS=256TB, TG1=4KB, SH1=0x3, ORGN1=0x1, IRGN1=0x1, EPD1=0, A1=1, T1SZ=16, TG0=4KB, SH0=0x3, ORGN0=0x1, IRGN0=0x1, EPD0=0, T0SZ=16, HPD1=0, HPD0=0, HD=0, HA=1, CnP=0, ASID=0
- 0xFFFF000000000000 | Invalid (x256) | | |
+ 0xFFFF800000000000 | Level 0 Table | NP:0x00000000865DB000 | | APTable=0x0, UXNTable=0, PXNTable=0
+ 0xFFFF800000000000 | Level 1 Table | NP:0x00000000865DC000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFF800000000000 | Invalid (x64) | | |
- 0xFFFF800008000000 | Level 2 Block | | NP:0x0000000084000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008200000 | Level 2 Block | | NP:0x0000000084200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008400000 | Level 2 Block | | NP:0x0000000084400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008600000 | Level 2 Block | | NP:0x0000000084600000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008800000 | Level 2 Block | | NP:0x0000000084800000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008A00000 | Level 2 Block | | NP:0x0000000084A00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008C00000 | Level 2 Block | | NP:0x0000000084C00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800008E00000 | Level 2 Block | | NP:0x0000000084E00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009000000 | Level 2 Block | | NP:0x0000000085000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009200000 | Level 2 Block | | NP:0x0000000085200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009400000 | Level 2 Block | | NP:0x0000000085400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009600000 | Level 2 Block | | NP:0x0000000085600000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009800000 | Level 2 Block | | NP:0x0000000085800000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009A00000 | Level 2 Block | | NP:0x0000000085A00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009C00000 | Level 2 Block | | NP:0x0000000085C00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF800009E00000 | Level 2 Block | | NP:0x0000000085E00000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A000000 | Level 2 Block | | NP:0x0000000086000000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A200000 | Level 2 Block | | NP:0x0000000086200000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A400000 | Level 2 Block | | NP:0x0000000086400000 | UXN=0, PXN=0, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x0
- 0xFFFF80000A600000 | Invalid (x429) | | |
- 0xFFFF800040000000 | Invalid (x511) | | |
- 0xFFFF808000000000 | Invalid (x246) | | |
+ 0xFFFFFB8000000000 | Level 0 Table | NP:0x0000000086542000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFFFB8000000000 | Invalid (x511) | | |
+ 0xFFFFFBFFC0000000 | Level 1 Table | NP:0x0000000086543000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFFFBFFC0000000 | Invalid (x493) | | |
+ 0xFFFFFBFFFDA00000 | Level 2 Table | NP:0x0000000086544000 | | APTable=0x0, UXNTable=0, PXNTable=0
- 0xFFFFFBFFFDA00000 | Invalid (x511) | | |
- 0xFFFFFBFFFDBFF000 | Level 3 Page | | NP:0x000000001C090000 | UXN=1, PXN=1, Contiguous=0, DBM=1, GP=0, nG=0, AF=1, SH=0x3, AP=0x0, AttrIndx=0x4
- 0xFFFFFBFFFDC00000 | Level 2 Block | | NP:0x0000000082000000 | UXN=1, PXN=1, Contiguous=0, DBM=0, GP=0, nG=0, AF=1, SH=0x3, AP=0x2, AttrIndx=0x0
- 0xFFFFFBFFFDE00000 | Invalid (x17) | | |
- 0xFFFFFC0000000000 | Invalid (x8) | | |
当swapper_pg_dir 页表准备好之后,init_task 的init_mm->pgd就会从init_pg_dir 切换成swapper_pg_dir,同时TTBR1设置成 swapper_pg_dir的值。 切换TTBR的时候,会用到前面1:1 的映射:
void __init paging_init(void)
{
pgd_t *pgdp = pgd_set_fixmap(__pa_symbol(swapper_pg_dir));
//....
cpu_replace_ttbr1(lm_alias(swapper_pg_dir), init_idmap_pg_dir);
init_mm.pgd = swapper_pg_dir;
memblock_phys_free(__pa_symbol(init_pg_dir),
__pa_symbol(init_pg_end) - __pa_symbol(init_pg_dir));
完成这些动作之后,init_pg_dir和init_idmap_pg_dir的使命就完成了,第二个CPU boot的时候也不会使用这两个页表。 这个时候可以回收init_pg_dir所占用的空间。 但是前面那些fix map是不会被回收,而是把它们接在swapper_pg_dir里面继续使用。 这个 FDT的区域的Map过程 有提过。
init_idmap_pg_dir的空间的回收利用,参考: Arm64 Linux 下页表 init_idmap_pg_dir的使用
Comments !