文章目录1. 前言2. ARM64 Linux 启动流程概要1. 前言限于作者能力水平本文可能存在谬误因此而给读者带来的损失作者不做任何承诺。2. ARM64 Linux 启动流程概要进入内核汇编入口切入 EL1// arch/arm64/kernel/head.S__HEAD _head:/* * DO NOT MODIFY. Image header expected by Linux boot-loaders. */#ifdefCONFIG_EFI/* * This add instruction has no meaningful effect except that * its opcode forms the magic MZ signature required by UEFI. */add x13,x18,#0x16b stext#elseb stext// branch to kernel start, magic.long0// reserved#endif__INIT/* * The following callee saved general purpose registers are used on the * primary lowlevel boot path: * * Register Scope Purpose * x21 stext() .. start_kernel() FDT pointer passed at boot in x0 * x23 stext() .. start_kernel() physical misalignment/KASLR offset * x28 __create_page_tables() callee preserved temp register * x19/x20 __primary_switch() callee preserved temp registers */ENTRY(stext)bl preserve_boot_args// 保存 bootloader 从 x0 .. x3 传递的参数到 boot_args[]bl el2_setup// Drop to EL1, w0cpu_boot_mode (进入 EL1)adrp x23,__PHYS_OFFSET// x23 内核镜像区起始物理地址and x23,x23,MIN_KIMG_ALIGN-1// KASLR offset, defaults to 0bl set_cpu_boot_mode_flag// 创建初始页表:// - 通过 idmap_pg_dir[] 页表 建立 idmap 区间的 idmap 映射// - 通过 swapper_pg_dir[] 页表 建立 内核镜像区 映射bl __create_page_tables/* * The following calls CPU setup code, see arch/arm64/mm/proc.S for * details. * On return, the CPU will be ready for the MMU to be turned on and * the TCR will have been set. */// 设定 TTBR0 和 TTBR1 各自寻址的虚拟地址区间范围 等bl __cpu_setup// initialise processorb __primary_switchENDPROC(stext)创建初始页表__create_page_tables建立内核运行的初始页表映射内核镜像区主要是让 MMU 开启后内核可以正常运行// 创建初始页表:// - 通过 idmap_pg_dir[] 页表 建立 idmap 区间的 idmap 映射// - 通过 swapper_pg_dir[] 页表 建立 内核镜像区 映射__create_page_tables:mov x28,lr/* * Invalidate the idmap and swapper page tables to avoid potential * dirty cache lines being evicted. */adrp x0,idmap_pg_dir ldr x1,(IDMAP_DIR_SIZESWAPPER_DIR_SIZERESERVED_TTBR0_SIZE)bl __inval_dcache_area/* * Clear the idmap and swapper page tables. */// 将 idmap 和 swapper 页表清 0adrp x0,idmap_pg_dir// x0 idmap_pg_dir[] 物理地址ldr x1,(IDMAP_DIR_SIZESWAPPER_DIR_SIZERESERVED_TTBR0_SIZE)1:stp xzr,xzr,[x0],#16stp xzr,xzr,[x0],#16stp xzr,xzr,[x0],#16stp xzr,xzr,[x0],#16subs x1,x1,#64b.ne1b mov x7,SWAPPER_MM_MMUFLAGS/* * Create the identity mapping. */// x0 idmap_pg_dir[] 的物理地址adrp x0,idmap_pg_dir// x3 idmap 代码区 起始位置 物理地址adrp x3,__idmap_text_start// __pa(__idmap_text_start)...// 建立 (__idmap_text_start, __idmap_text_end] 区// (在 idmap_pg_dir[] 页表中的) 的 idmap 映射:// Input Adress(IA) Output Adress(OA)// [pa(__idmap_text_start), pa(__idmap_text_end)] [pa(__idmap_text_start), pa(__idmap_text_end)]create_pgd_entry x0,x3,x5,x6 mov x5,x3// __pa(__idmap_text_start)adr_l x6,__idmap_text_end// __pa(__idmap_text_end)create_block_map x0,x7,x3,x5,x6/* * Map the kernel image (starting with PHYS_OFFSET). */// 建立 内核镜像 (在 swapper_pg_dir[] 页表中的) 的 映射adrp x0,swapper_pg_dir mov_q x5,KIMAGE_VADDRTEXT_OFFSET// compile time __va(_text)add x5,x5,x23// add KASLR displacement// 建立 内核镜像 首个 page 在页表 swapper_pg_dir[] 中的 pgd, (pud, ) pte 各级别页表项create_pgd_entry x0,x5,x3,x6// 建立 内核镜像 剩余 page 在页表 swapper_pg_dir[] 中的 pte 级别剩余页表项.// 内核镜像 在 pgd (pud, ) 页表级别 各 只需要一个 页表项, 剩余绪建立的页// 表项都只在 pte 级别.adrp x6,_end// runtime __pa(_end)adrp x3,_text// runtime __pa(_text)sub x6,x6,x3// _end - _textadd x6,x6,x5// runtime __va(_end)create_block_map x0,x7,x3,x5,x6/* * Since the page tables have been populated with non-cacheable * accesses (MMU disabled), invalidate the idmap and swapper page * tables again to remove any speculatively loaded cache lines. */adrp x0,idmap_pg_dir ldr x1,(IDMAP_DIR_SIZESWAPPER_DIR_SIZERESERVED_TTBR0_SIZE)dmb sy bl __inval_dcache_area ret x28ENDPROC(__create_page_tables).ltorgCPU 初始化主要是为开启 MMU 做准备如清除 TLB设置内存区域属性TTBR1, TTBR1 各自的 VA 寻址区间也间接划定了内核和用户空间各自的 VA 范围TTBR1 寻址内核 VATTBR0 寻址用户空间 VA等工作// arch/arm64/mm/proc.S.pushsection.idmap.text,awxENTRY(__cpu_setup)tlbi vmalle1// Invalidate local TLBdsb nsh mov x0,#320msr cpacr_el1,x0// Enable FP/ASIMDmov x0,#112// Reset mdscr_el1 and disablemsr mdscr_el1,x0// access to the DCC from EL0isb// Unmask debug exceptions now,enable_dbg// since this is per-cpureset_pmuserenr_el0 x0// Disable PMU access from EL0/* * Memory region attributes for LPAE: * * n AttrIndx[2:0] * n MAIR * DEVICE_nGnRnE 000 00000000 * DEVICE_nGnRE 001 00000100 * DEVICE_GRE 010 00001100 * NORMAL_NC 011 01000100 * NORMAL 100 11111111 * NORMAL_WT 101 10111011 */// LPAE 内存属性配置:// DDI0487A_j_armv8_arm.pdf, P2049ldr x5,MAIR(0x00,MT_DEVICE_nGnRnE)|\MAIR(0x04,MT_DEVICE_nGnRE)|\MAIR(0x0c,MT_DEVICE_GRE)|\MAIR(0x44,MT_NORMAL_NC)|\MAIR(0xff,MT_NORMAL)|\MAIR(0xbb,MT_NORMAL_WT)msr mair_el1,x5/* * Prepare SCTLR */// DDI0487A_j_armv8_arm.pdf, P2086// 设置 crval 到 sctlr_el1adr x5,crval ldp w5,w6,[x5]mrs x0,sctlr_el1// x0 sctlr_el1bic x0,x0,x5// clear bitsorr x0,x0,x6// set bits/* * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for * both user and kernel. */// TCR_EL1:// - TCR_TxSZ(VA_BITS 48): 设定 TTBR0 和 TTBR1 寻址区间// TTBR0: [0x0000_0000_0000_0000, 0x0000_FFFF_FFFF_FFFF]// TTBR1: [0xFFFF_0000_0000_0000, 0xFFFF_FFFF_FFFF_FFFF]// - TCR_A1: TTBR1_EL1.ASID 定义 ASID// - 内核 用户 4KB page// - 其它ldr x10,TCR_TxSZ(VA_BITS)|TCR_CACHE_FLAGS|TCR_SMP_FLAGS|\ TCR_TG_FLAGS|TCR_ASID16|TCR_TBI0|TCR_A1// arch/arm64/include/asm/assembler.htcr_set_idmap_t0sz x10,x9// VA_48 下为空操作/* * Read the PARange bits from ID_AA64MMFR0_EL1 and set the IPS bits in * TCR_EL1. */// DDI0487A_j_armv8_arm.pdf, P2022mrs x9,ID_AA64MMFR0_EL1 bfi x10,x9,#32,#3// ??? x10[34:32] x9[34:32]#ifdefCONFIG_ARM64_HW_AFDBM/* * Hardware update of the Access and Dirty bits. */mrs x9,ID_AA64MMFR1_EL1 and x9,x9,#0xfcbz x9,2fcmp x9,#2b.lt1f#ifdefCONFIG_ARM64_ERRATUM_1024718/* Disable hardware DBM on Cortex-A55 r0p0, r0p1 r1p0 */cpu_midr_match MIDR_CORTEX_A55,MIDR_CPU_VAR_REV(0,0),MIDR_CPU_VAR_REV(1,0),x1,x2,x3,x4 cbnz x1,1f#endiforr x10,x10,#TCR_HD// hardware Dirty flag update1:orr x10,x10,#TCR_HA// hardware Access flag update2:#endif/* CONFIG_ARM64_HW_AFDBM */// DDI0487A_j_armv8_arm.pdf, P2101// 设定:// - 某范围的 VA 使用哪个 TTBR 来进行页表遍历// - 页表项格式// - shareability 和 cacheabilitymsr tcr_el1,x10 ret// return to head.SENDPROC(__cpu_setup)启用 MMU进入虚拟地址的世界在语句b __primary_switch之前MMU 处于关闭状态使用的物理寻址现在要开启 MMU开始使用页表进行寻址了__primary_switch:#ifdefCONFIG_RANDOMIZE_BASEmov x19,x0// preserve new SCTLR_EL1 valuemrs x20,sctlr_el1// preserve old SCTLR_EL1 value#endifbl __enable_mmu// 启用 mmu, 期间会设置 TTBR0 TTBR1...ldr x8,__primary_switched adrp x0,__PHYS_OFFSET br x8// 跳转到 __primary_switched 处执行ENDPROC(__primary_switch)进入内核 C 入口做一些进入内核 C 入口的准备工作然后跳转到start_kernel()__primary_switched:// BOOT CPU// 设置 首进程 EL0 栈空间adrp x4,init_thread_union add sp,x4,#THREAD_SIZE adr_l x5,init_task msr sp_el0,x5// Save thread_info// 配置 EL1 异常向量表 (虚拟地址 到 vbar_el1 寄存器)adr_l x8,vectors// load VBAR_EL1 with virtualmsr vbar_el1,x8// vector table addressisb// 设置 首进程 EL1 栈空间stp xzr,x30,[sp,#-16]!// sp[-16] 0, sp[-8] x30(lr), sp - 16 ???mov x29,sp// x29 init_task 内核栈顶指针 - 16// __fdt_pointer FDT 物理地址str_l x21,__fdt_pointer,x5// Save FDT pointer// ENTRY(kimage_vaddr)// .quad _text - TEXT_OFFSET//// x4 kimage_vaddr 虚拟地址// (x4 内核镜像 起始位置 虚拟地址 _text (KERNEL_START) - TEXT_OFFSET)// x4 - x0// (x0 __PHYS_OFFSET,// 即 内核镜像 起始位置 虚拟地址 _text (KERNEL_START) - TEXT_OFFSET 的// 物理地址, 所以// x4 内核虚拟地址 - 内核物理地址// kimage_voffset x4//// ldr_l 和 str_l 定义在 arch/arm64/include/asm/assembler.h 中.ldr_l x4,kimage_vaddr// Save the offset betweensub x4,x4,x0// the kernel virtual andstr_l x4,kimage_voffset,x5// physical mappings// Clear BSSadr_l x0,__bss_start mov x1,xzr adr_l x2,__bss_stop sub x2,x2,x0 bl __pi_memset dsb ishst// Make zero page visible to PTW#ifdefCONFIG_KASAN// 将 kasan 虚拟地址区间 映射到 同一物理页面 kasan_zero_page[]bl kasan_early_init#endif#ifdefCONFIG_RANDOMIZE_BASEtst x23,~(MIN_KIMG_ALIGN-1)// already running randomized?b.ne0fmov x0,x21// pass FDT address in x0bl kaslr_early_init// parse FDT for KASLR optionscbz x0,0f// KASLR disabled? just proceedorr x23,x23,x0// record KASLR offsetldp x29,x30,[sp],#16// we must enable KASLR, returnret// to __primary_switch()0:#endifadd sp,sp,#16mov x29,#0mov x30,#0b start_kernel剩余的工作进入 start_kernel() 后剩下的主要工作是进一步建立完整物理内存管理系统启动非 BOOT CPU内存管理系统的建立可以参考系列文章Linux 内存管理 (2)memblock 子系统的建立Linux 内存管理 (3)fixmapLinux 内存管理 (4)buddy 管理系统的建立Linux 内存管理 (6)slub 分配器启动非 BOOT CPU可参考Linux多核 CPU 启动流程简析
Linux:ARM64 启动流程
文章目录1. 前言2. ARM64 Linux 启动流程概要1. 前言限于作者能力水平本文可能存在谬误因此而给读者带来的损失作者不做任何承诺。2. ARM64 Linux 启动流程概要进入内核汇编入口切入 EL1// arch/arm64/kernel/head.S__HEAD _head:/* * DO NOT MODIFY. Image header expected by Linux boot-loaders. */#ifdefCONFIG_EFI/* * This add instruction has no meaningful effect except that * its opcode forms the magic MZ signature required by UEFI. */add x13,x18,#0x16b stext#elseb stext// branch to kernel start, magic.long0// reserved#endif__INIT/* * The following callee saved general purpose registers are used on the * primary lowlevel boot path: * * Register Scope Purpose * x21 stext() .. start_kernel() FDT pointer passed at boot in x0 * x23 stext() .. start_kernel() physical misalignment/KASLR offset * x28 __create_page_tables() callee preserved temp register * x19/x20 __primary_switch() callee preserved temp registers */ENTRY(stext)bl preserve_boot_args// 保存 bootloader 从 x0 .. x3 传递的参数到 boot_args[]bl el2_setup// Drop to EL1, w0cpu_boot_mode (进入 EL1)adrp x23,__PHYS_OFFSET// x23 内核镜像区起始物理地址and x23,x23,MIN_KIMG_ALIGN-1// KASLR offset, defaults to 0bl set_cpu_boot_mode_flag// 创建初始页表:// - 通过 idmap_pg_dir[] 页表 建立 idmap 区间的 idmap 映射// - 通过 swapper_pg_dir[] 页表 建立 内核镜像区 映射bl __create_page_tables/* * The following calls CPU setup code, see arch/arm64/mm/proc.S for * details. * On return, the CPU will be ready for the MMU to be turned on and * the TCR will have been set. */// 设定 TTBR0 和 TTBR1 各自寻址的虚拟地址区间范围 等bl __cpu_setup// initialise processorb __primary_switchENDPROC(stext)创建初始页表__create_page_tables建立内核运行的初始页表映射内核镜像区主要是让 MMU 开启后内核可以正常运行// 创建初始页表:// - 通过 idmap_pg_dir[] 页表 建立 idmap 区间的 idmap 映射// - 通过 swapper_pg_dir[] 页表 建立 内核镜像区 映射__create_page_tables:mov x28,lr/* * Invalidate the idmap and swapper page tables to avoid potential * dirty cache lines being evicted. */adrp x0,idmap_pg_dir ldr x1,(IDMAP_DIR_SIZESWAPPER_DIR_SIZERESERVED_TTBR0_SIZE)bl __inval_dcache_area/* * Clear the idmap and swapper page tables. */// 将 idmap 和 swapper 页表清 0adrp x0,idmap_pg_dir// x0 idmap_pg_dir[] 物理地址ldr x1,(IDMAP_DIR_SIZESWAPPER_DIR_SIZERESERVED_TTBR0_SIZE)1:stp xzr,xzr,[x0],#16stp xzr,xzr,[x0],#16stp xzr,xzr,[x0],#16stp xzr,xzr,[x0],#16subs x1,x1,#64b.ne1b mov x7,SWAPPER_MM_MMUFLAGS/* * Create the identity mapping. */// x0 idmap_pg_dir[] 的物理地址adrp x0,idmap_pg_dir// x3 idmap 代码区 起始位置 物理地址adrp x3,__idmap_text_start// __pa(__idmap_text_start)...// 建立 (__idmap_text_start, __idmap_text_end] 区// (在 idmap_pg_dir[] 页表中的) 的 idmap 映射:// Input Adress(IA) Output Adress(OA)// [pa(__idmap_text_start), pa(__idmap_text_end)] [pa(__idmap_text_start), pa(__idmap_text_end)]create_pgd_entry x0,x3,x5,x6 mov x5,x3// __pa(__idmap_text_start)adr_l x6,__idmap_text_end// __pa(__idmap_text_end)create_block_map x0,x7,x3,x5,x6/* * Map the kernel image (starting with PHYS_OFFSET). */// 建立 内核镜像 (在 swapper_pg_dir[] 页表中的) 的 映射adrp x0,swapper_pg_dir mov_q x5,KIMAGE_VADDRTEXT_OFFSET// compile time __va(_text)add x5,x5,x23// add KASLR displacement// 建立 内核镜像 首个 page 在页表 swapper_pg_dir[] 中的 pgd, (pud, ) pte 各级别页表项create_pgd_entry x0,x5,x3,x6// 建立 内核镜像 剩余 page 在页表 swapper_pg_dir[] 中的 pte 级别剩余页表项.// 内核镜像 在 pgd (pud, ) 页表级别 各 只需要一个 页表项, 剩余绪建立的页// 表项都只在 pte 级别.adrp x6,_end// runtime __pa(_end)adrp x3,_text// runtime __pa(_text)sub x6,x6,x3// _end - _textadd x6,x6,x5// runtime __va(_end)create_block_map x0,x7,x3,x5,x6/* * Since the page tables have been populated with non-cacheable * accesses (MMU disabled), invalidate the idmap and swapper page * tables again to remove any speculatively loaded cache lines. */adrp x0,idmap_pg_dir ldr x1,(IDMAP_DIR_SIZESWAPPER_DIR_SIZERESERVED_TTBR0_SIZE)dmb sy bl __inval_dcache_area ret x28ENDPROC(__create_page_tables).ltorgCPU 初始化主要是为开启 MMU 做准备如清除 TLB设置内存区域属性TTBR1, TTBR1 各自的 VA 寻址区间也间接划定了内核和用户空间各自的 VA 范围TTBR1 寻址内核 VATTBR0 寻址用户空间 VA等工作// arch/arm64/mm/proc.S.pushsection.idmap.text,awxENTRY(__cpu_setup)tlbi vmalle1// Invalidate local TLBdsb nsh mov x0,#320msr cpacr_el1,x0// Enable FP/ASIMDmov x0,#112// Reset mdscr_el1 and disablemsr mdscr_el1,x0// access to the DCC from EL0isb// Unmask debug exceptions now,enable_dbg// since this is per-cpureset_pmuserenr_el0 x0// Disable PMU access from EL0/* * Memory region attributes for LPAE: * * n AttrIndx[2:0] * n MAIR * DEVICE_nGnRnE 000 00000000 * DEVICE_nGnRE 001 00000100 * DEVICE_GRE 010 00001100 * NORMAL_NC 011 01000100 * NORMAL 100 11111111 * NORMAL_WT 101 10111011 */// LPAE 内存属性配置:// DDI0487A_j_armv8_arm.pdf, P2049ldr x5,MAIR(0x00,MT_DEVICE_nGnRnE)|\MAIR(0x04,MT_DEVICE_nGnRE)|\MAIR(0x0c,MT_DEVICE_GRE)|\MAIR(0x44,MT_NORMAL_NC)|\MAIR(0xff,MT_NORMAL)|\MAIR(0xbb,MT_NORMAL_WT)msr mair_el1,x5/* * Prepare SCTLR */// DDI0487A_j_armv8_arm.pdf, P2086// 设置 crval 到 sctlr_el1adr x5,crval ldp w5,w6,[x5]mrs x0,sctlr_el1// x0 sctlr_el1bic x0,x0,x5// clear bitsorr x0,x0,x6// set bits/* * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for * both user and kernel. */// TCR_EL1:// - TCR_TxSZ(VA_BITS 48): 设定 TTBR0 和 TTBR1 寻址区间// TTBR0: [0x0000_0000_0000_0000, 0x0000_FFFF_FFFF_FFFF]// TTBR1: [0xFFFF_0000_0000_0000, 0xFFFF_FFFF_FFFF_FFFF]// - TCR_A1: TTBR1_EL1.ASID 定义 ASID// - 内核 用户 4KB page// - 其它ldr x10,TCR_TxSZ(VA_BITS)|TCR_CACHE_FLAGS|TCR_SMP_FLAGS|\ TCR_TG_FLAGS|TCR_ASID16|TCR_TBI0|TCR_A1// arch/arm64/include/asm/assembler.htcr_set_idmap_t0sz x10,x9// VA_48 下为空操作/* * Read the PARange bits from ID_AA64MMFR0_EL1 and set the IPS bits in * TCR_EL1. */// DDI0487A_j_armv8_arm.pdf, P2022mrs x9,ID_AA64MMFR0_EL1 bfi x10,x9,#32,#3// ??? x10[34:32] x9[34:32]#ifdefCONFIG_ARM64_HW_AFDBM/* * Hardware update of the Access and Dirty bits. */mrs x9,ID_AA64MMFR1_EL1 and x9,x9,#0xfcbz x9,2fcmp x9,#2b.lt1f#ifdefCONFIG_ARM64_ERRATUM_1024718/* Disable hardware DBM on Cortex-A55 r0p0, r0p1 r1p0 */cpu_midr_match MIDR_CORTEX_A55,MIDR_CPU_VAR_REV(0,0),MIDR_CPU_VAR_REV(1,0),x1,x2,x3,x4 cbnz x1,1f#endiforr x10,x10,#TCR_HD// hardware Dirty flag update1:orr x10,x10,#TCR_HA// hardware Access flag update2:#endif/* CONFIG_ARM64_HW_AFDBM */// DDI0487A_j_armv8_arm.pdf, P2101// 设定:// - 某范围的 VA 使用哪个 TTBR 来进行页表遍历// - 页表项格式// - shareability 和 cacheabilitymsr tcr_el1,x10 ret// return to head.SENDPROC(__cpu_setup)启用 MMU进入虚拟地址的世界在语句b __primary_switch之前MMU 处于关闭状态使用的物理寻址现在要开启 MMU开始使用页表进行寻址了__primary_switch:#ifdefCONFIG_RANDOMIZE_BASEmov x19,x0// preserve new SCTLR_EL1 valuemrs x20,sctlr_el1// preserve old SCTLR_EL1 value#endifbl __enable_mmu// 启用 mmu, 期间会设置 TTBR0 TTBR1...ldr x8,__primary_switched adrp x0,__PHYS_OFFSET br x8// 跳转到 __primary_switched 处执行ENDPROC(__primary_switch)进入内核 C 入口做一些进入内核 C 入口的准备工作然后跳转到start_kernel()__primary_switched:// BOOT CPU// 设置 首进程 EL0 栈空间adrp x4,init_thread_union add sp,x4,#THREAD_SIZE adr_l x5,init_task msr sp_el0,x5// Save thread_info// 配置 EL1 异常向量表 (虚拟地址 到 vbar_el1 寄存器)adr_l x8,vectors// load VBAR_EL1 with virtualmsr vbar_el1,x8// vector table addressisb// 设置 首进程 EL1 栈空间stp xzr,x30,[sp,#-16]!// sp[-16] 0, sp[-8] x30(lr), sp - 16 ???mov x29,sp// x29 init_task 内核栈顶指针 - 16// __fdt_pointer FDT 物理地址str_l x21,__fdt_pointer,x5// Save FDT pointer// ENTRY(kimage_vaddr)// .quad _text - TEXT_OFFSET//// x4 kimage_vaddr 虚拟地址// (x4 内核镜像 起始位置 虚拟地址 _text (KERNEL_START) - TEXT_OFFSET)// x4 - x0// (x0 __PHYS_OFFSET,// 即 内核镜像 起始位置 虚拟地址 _text (KERNEL_START) - TEXT_OFFSET 的// 物理地址, 所以// x4 内核虚拟地址 - 内核物理地址// kimage_voffset x4//// ldr_l 和 str_l 定义在 arch/arm64/include/asm/assembler.h 中.ldr_l x4,kimage_vaddr// Save the offset betweensub x4,x4,x0// the kernel virtual andstr_l x4,kimage_voffset,x5// physical mappings// Clear BSSadr_l x0,__bss_start mov x1,xzr adr_l x2,__bss_stop sub x2,x2,x0 bl __pi_memset dsb ishst// Make zero page visible to PTW#ifdefCONFIG_KASAN// 将 kasan 虚拟地址区间 映射到 同一物理页面 kasan_zero_page[]bl kasan_early_init#endif#ifdefCONFIG_RANDOMIZE_BASEtst x23,~(MIN_KIMG_ALIGN-1)// already running randomized?b.ne0fmov x0,x21// pass FDT address in x0bl kaslr_early_init// parse FDT for KASLR optionscbz x0,0f// KASLR disabled? just proceedorr x23,x23,x0// record KASLR offsetldp x29,x30,[sp],#16// we must enable KASLR, returnret// to __primary_switch()0:#endifadd sp,sp,#16mov x29,#0mov x30,#0b start_kernel剩余的工作进入 start_kernel() 后剩下的主要工作是进一步建立完整物理内存管理系统启动非 BOOT CPU内存管理系统的建立可以参考系列文章Linux 内存管理 (2)memblock 子系统的建立Linux 内存管理 (3)fixmapLinux 内存管理 (4)buddy 管理系统的建立Linux 内存管理 (6)slub 分配器启动非 BOOT CPU可参考Linux多核 CPU 启动流程简析