ARM cpu架构Linux内核启动流程分析
  LvK5Zg9SqSt6 2023年11月02日 61 0

汇编阶段

执行文件:

linux-4.19.y\arch\arm\kernel\head.S

调用同目录下的 head-common.S

明接下来的汇编代码将被汇编为 ARM 指令集,并且 stext 被标识为程序的入口点,根据当前的处理器模式来执行一系列操作,包括确保处理器模式为 BE8 大端字节序、切换到 ARM 模式或 Thumb-2 模式

	.arm		// 用于指示汇编器将接下来的代码汇编为 ARM 指令集的代码。

	__HEAD		// 标识符,通常用于表示代码的起始点或头部
 ENTRY(stext)	// 标识 stext 作为程序的入口点,通常,stext 是操作系统内核的入口点,它会被调用来启动整个系统。
 ARM_BE8(setend	be )			@ ensure we are in BE8 mode  //使用 setend 指令来确保处理器处于 BE8(大端字节序)模式。

 THUMB(	badr	r9, 1f		)	@ Kernel is always entered in ARM.  // 这是一个条件编译宏,用于在 Thumb 模式下执行。它将标签 1f 的地址加载到寄存器 r9 中,标签 1: 位于代码的最后一行
 THUMB(	bx	r9		)	@ If this is a Thumb-2 kernel,  // 在 Thumb 模式下,这行代码使用 bx 指令跳转到寄存器 r9 中保存的地址,这里可能是为了将执行流切换到 ARM 模式。
 THUMB(	.thumb			)	@ switch to Thumb now. // 这行代码用于在 Thumb 模式下切换到 Thumb-2 指令集
 THUMB(1:			)		// 这是标签,用于在之前的条件编译中作为跳转目标。在这个例子中,它没有实际的指令,仅用于标记位

获取处理器ID,检查处理器类型是否有效

mrc	p15, 0, r9, c0, c0		@ get processor id
	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid	//调用__lookup_processor_type函数,其中r5用于传递处理器信息,r9用于传递处理器ID
	movs	r10, r5				@ invalid processor (r5=0)?
 THUMB( it	eq )		@ force fixup-able long branch encoding
	beq	__error_p			@ yes, error 'p'	//处理器ID无效的情况下触发错误处理。

设置物理地址偏移

#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	// 如果不是 xip内核,为一个固定值,目前还未找到对该值的设置
#endif

调用一系列函数,实现验证 ATAGS 数据的有效性创建页表(只设置使内核运行所需的最少量)

bl	__vet_atags		// 验证 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	//创建页表 只设置使内核运行所需的最少量

完成使能mmu的操作,最终调用init/main.c文件中的start_kernel函数

ldr	r13, =__mmap_switched		@ address to jump to after 
	// 当mmu使能之后,跳转到__mmap_switched 函数
	//复制数据段、清楚BSS段、设置栈指针、保存CPU ID
						@ 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		// 使能 mmu,并执行start_kernel
ENDPROC(stext)
	.ltorg
#ifndef CONFIG_XIP_KERNEL
2:	.long	.
	.long	PAGE_OFFSET
#endif

start_kernel 为linux启动过程中的第一个C函数。

汇编流程总结:

处理uboot传入的参数(机器ID 、启动参数)

  1. 判断是否支持这个CPU(架构)
  2. 判断是否支持这个单板(机器ID)
  3. 建立页表(一级页表)
  4. 使能MMU
  5. 复制数据段、清楚BSS段、设置栈指针、保存CPU ID
  6. 跳转到start_kernel


C语言阶段

linux-4.19.y\init\main.c

C语言阶段内核启动流程
start_kernel
	setup_arch			// 解析 uboot传入的启动参数
	setup_command_line	// 解析 uboot传入的启动参数
	parse_early_param
		do_early_param
			//	从__setup_start 到 __setup_end ,调用early函数
	unknown_bootoption
		obsolete_chechsetup
			//	从__setup_start 到 __setup_end ,调用非early函数
	rest_init
		kernel_init
				prepare_namespace
						mount_root	// 挂载根文件系统
				init_post
						//	执行应用

ARM cpu架构Linux内核启动流程分析_Linux内核启动


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论