ual address range. If multiple entries
* were needed in the previous page table level then the next page table level is assumed
* to be composed of multiple pages. (This effectively scales the end index).
*
* vstart: virtual address of start of range
* vend: virtual address of end of range - we map [vstart, vend]
* shift: shift used to transform virtual address into index
* ptrs: number of entries in page table
* istart: index in table corresponding to vstart
* iend: index in table corresponding to vend
* count: On entry: how many extra entries were required in previous level, scales
* our end index.
* On exit: returns how many extra entries required for next page table level
*
* Preserves: vstart, vend, shift, ptrs
* Returns: istart, iend, count
*/
.macro compute_indices, vstart, vend, shift, ptrs, istart, iend, count
lsr \iend, \vend, \shift
mov \istart, \ptrs
sub \istart, \istart, #1
and \iend, \iend, \istart // iend = (vend >> shift) & (ptrs - 1)
mov \istart, \ptrs
mul \istart, \istart, \count
add \iend, \iend, \istart // iend += count * ptrs
// our entries span multiple tables
lsr \istart, \vstart, \shift
mov \count, \ptrs
sub \count, \count, #1
and \istart, \istart, \count
sub \count, \iend, \istart
.endm
- populate_entries宏的功能:填充索引值index对应的页表项
/*
* Macro to populate page table entries, these entries can be pointers to the next level
* or last level entries pointing to physical memory.
*
* tbl: page table address
* rtbl: pointer to page table or physical memory
* index: start index to write
* eindex: end index to write - [index, eindex] written to
* flags: flags for pagetable entry to or in
* inc: increment to rtbl between each entry
* tmp1: temporary variable
*
* Preserves: tbl, eindex, flags, inc
* Corrupts: index, tmp1
* Returns: rtbl
*/
.macro populate_entries, tbl, rtbl, index, eindex, flags, inc, tmp1
.Lpe\@: phys_to_pte \tmp1, \rtbl
orr \tmp1, \tmp1, \flags // tmp1 = table entry
str \tmp1, [\tbl, \index, lsl #3]
add \rtbl, \rtbl, \inc // rtbl = pa next level
add \index, \index, #1
cmp \index, \eindex
b.ls .Lpe\@
.endm
- 设置PUD页表项 ;
- 设置PMD页表项(因为我们用的是段映射,因此这里是最后一级,没有PTE);
2.4.6 创建内核image的映射
/*
* Map the kernel image (starting with PHYS_OFFSET).
*/
adrp x0, init_pg_dir ---(1)
mov_q x5, KIMAGE_VADDR // compile time __va(_text) ---(2)
add x5, x5, x23 // add KASLR displacement //x23 = __PHYS_OFFSET
mov x4, PTRS_PER_PGD
adrp x6, _end // runtime __pa(_end) ---(3)内核映像结束物理地址
adrp x3, _text // runtime __pa(_text) ---(4)内核映像起始物理地址
sub x6, x6, x3 // _end - _text //内核映像的大小
add x6, x6, x5 // runtime __va(_end) ---(5)内核映像结束地址
map_memory x0, x1, x5, x6, x7, x3, x4, x10, x11, x12, x13, x14 ---(6)
- 这里是加载init_pg_dir的物理地址到x0寄存器,init_pg_dir是kernel image的映射使用的页表起始地址(与恒等映射不同),其定义在vmlinux.lds.S链接文件中。
BSS_SECTION(SBSS_ALIGN, 0, 0)
. = ALIGN(PAGE_SIZE);
init_pg_dir = .;
. += INIT_DIR_SIZE;
init_pg_end = .;
- 加载内核映像虚拟的起始地址KIMAGE_VADDR到x5寄存器,注意这里使用的是mov_q指令。KIMAGE_VADDR定义在vmlinux.lds.S链接文件中。
SECTIONS
{
......
'在5.8内核版本发现TEXT_OFFSET没有任何作用,因此,被重新定义为0x0'
. = KIMAGE_VADDR; '内核映像虚拟的起始地址(在5.8内核之前这里为KIMAGE_VADDR + TEXT_OFFSET)'
.head.text : { '早期汇编代码的text段'
_text = .; '入口地址'
HEAD_TEXT 定义在include/asm-generic/vmlinux.lds.h'#define HEAD_TEXT KEEP(*(.head.text))'
}
- 这里是加载内核映像结束物理地址到x3寄存器;
- 这里是加载内核映像起始物理地址到x6