Linux 启动流程分析
入口
vmlinux.lds中
ENTRY(stext)
说明入口在stext中,位于 arch/arm/kernel/head.S,如下:
ENTRY(stext)
ARM_BE8(setend be ) @ ensure we are in BE8 mode
THUMB( badr r9, 1f ) @ Kernel is always entered in ARM.
THUMB( bx r9 ) @ If this is a Thumb-2 kernel,
THUMB( .thumb ) @ switch to Thumb now.
THUMB(1: )
#ifdef CONFIG_ARM_VIRT_EXT
bl __hyp_stub_install
#endif
@ ensure svc mode and all interrupts masked
safe_svcmode_maskall r9
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
THUMB( it eq ) @ force fixup-able long branch encoding
beq __error_p @ yes, error 'p'
#ifdef CONFIG_ARM_LPAE
mrc p15, 0, r3, c0, c1, 4 @ read ID_MMFR0
and r3, r3, #0xf @ extract VMSA support
cmp r3, #5 @ long-descriptor translation table format?
THUMB( it lo ) @ force fixup-able long branch encoding
blo __error_lpae @ only classic page table format
#endif
#ifndef CONFIG_XIP_KERNEL
adr r3, 2f
ldmia r3, {r4, r8}
sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET)
add r8, r8, r4 @ PHYS_OFFSET
#else
ldr r8, =PLAT_PHYS_OFFSET @ always constant in this case
#endif
/*
* r1 = machine no, r2 = atags or dtb,
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*/
bl __vet_atags
#ifdef CONFIG_SMP_ON_UP
bl __fixup_smp
#endif
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
bl __fixup_pv_table
#endif
bl __create_page_tables
/*
* The following calls CPU specific code in a position independent
* manner. See arch/arm/mm/proc-*.S for details. r10 = base of
* xxx_proc_info structure selected by __lookup_processor_type
* above.
*
* The processor init function will be called with:
* r1 - machine type
* r2 - boot data (atags/dt) pointer
* r4 - translation table base (low word)
* r5 - translation table base (high word, if LPAE)
* r8 - translation table base 1 (pfn if LPAE)
* r9 - cpuid
* r13 - virtual address for __enable_mmu -> __turn_mmu_on
*
* On return, the CPU will be ready for the MMU to be turned on,
* r0 will hold the CPU control register value, r1, r2, r4, and
* r9 will be preserved. r5 will also be preserved if LPAE.
*/
ldr r13, =__mmap_switched @ address to jump to after
@ mmu has been enabled
badr lr, 1f @ return (PIC) address
#ifdef CONFIG_ARM_LPAE
mov r5, #0 @ high TTBR0
mov r8, r4, lsr #12 @ TTBR1 is swapper_pg_dir pfn
#else
mov r8, r4 @ set TTBR1 to swapper_pg_dir
#endif
ldr r12, [r10, #PROCINFO_INITFUNC]
add r12, r12, r10
ret r12
1: b __enable_mmu
ENDPROC(stext)
在stext中做了这些事情:
- 如果内核使能虚拟化扩展,调用
__hyp_stub_install,这个函数把primary CPU boot mode保存到L__boot_cpu_mode_offset safe_svcmode_maskall让CPU进入SVC状态并关所有中断- 获取CPU ID放在R9,获取的 proc_info_list 放在 R5中,并判断R5是否为0,是的话跳转error_p
- 如果内核配置为 LPAE(大物理地址扩展,可支持 >4GB 内存),则检查硬件是否实际支持
- XIP状态下的offset计算
- 调用
__vet_atags验证dtb或atags的合法性,包括指针对齐、magic number等 - SMP(可选):如果内核配置了 SMP 支持但实际运行在单核 CPU 上,动态修改内核代码,将 SMP 相关的指令(如自旋锁、TLB 广播)替换为 UP 版本,避免性能损失。
- (可选)调用
__fixup_pv_table,动态修正内核符号的虚拟-物理地址转换表。当内核编译时不知道自己的物理地址,这个函数会扫描并修改内核映像中的地址转换代码,使得 virt_to_phys 和 phys_to_virt 能够正确工作 - 创建临时页表
__create_page_tables - 调用
__mmap_switched, 其中会调用start_kernel, __enable_mmu存入lr寄存器,然后ret,导致__enable_mmu被调用,使能mmu

浙公网安备 33010602011771号