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
posted @ 2026-05-12 09:33  p_wild  阅读(2)  评论(0)    收藏  举报