linux内核的启动过程之汇编—1.2

本文详细介绍了Linux内核启动的汇编阶段,包括处理器ID校验、通用寄存器传参、MMU页表创建及启用,以及C语言阶段的进入。通过分析`head.S`、`assembler.h`和`head-common.S`等关键文件,阐述了如何从汇编代码逐步过渡到C语言代码,启动内核的进程。在启动过程中,检查了u-boot传递的参数并进行了校验,确保内核启动的安全性和正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.汇编过程启动简介

内核的汇编阶段其实比uboot要简单点,因为uboot已经做了不少的工作,内核的启动过程主要包含汇编、c语言两个阶段;其中的汇编阶段也主要可以分为两个过程
1).校验处理器的id,以及传过来的r2参数,完成部分通用寄存器的传参;
r1 = machine no, r2 = atags or dtb,
r8 = phys_offset, r9 = cpuid, r10 = procinfo
2).创建mmu的页表__create_page_tables,使能mmu控制器,跳转至c语言阶段,start_kernel。

2.源码分析–汇编的第一阶段

其启动代码主要集中在以下几个文件:
/arch/arm/kernel/head.S
/arch/arm/include/asm/assembler.h
/arch/arm/kernel/head-common.S

//head.S中
ENTRY(stext)
	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
						@ and irqs disabled
	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'

#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
#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
	ldr	r13, =__mmap_switched		@ address to jump to after
						@ mmu has been enabled
	adr	lr, BSYM(1f)			@ return (PIC) address
	mov	r8, r4				@ set TTBR1 to swapper_pg_dir
 ARM(	add	pc, r10, #PROCINFO_INITFUNC	)
 THUMB(	add	r12, r10, #PROCINFO_INITFUNC	)
 THUMB(	mov	pc, r12				)
1:	b	__enable_mmu
ENDPROC(stext)

其中setmode 是汇编宏,在此其实是配置ARM的cpsr_c寄存器;

//assembler.h中
#ifdef CONFIG_THUMB2_KERNEL
	.macro	setmode, mode, reg
	mov	\reg, #\mode
	msr	cpsr_c, \reg
	.endm
#else
	.macro	setmode, mode, reg
	msr	cpsr_c, #\mode
	.endm
#endif

ARM的cpsr作为控制寄存器简介:
1.确保进行SVC模式,并去使能IRQ、FIQ中断位;
2.读取CP15协处理的Main ID Register,存在r9中;
在这里插入图片描述
3.
获取r5 = procinfo;

head-common.S
__lookup_processor_type:
	adr	r3, __lookup_processor_type_data
	ldmia	r3, {r4 - r6}
	sub	r3, r3, r4			@ get offset between virt&phys
	add	r5, r5, r3			@ convert virt addresses to
	add	r6, r6, r3			@ physical address space
1:	ldmia	r5, {r3, r4}			@ value, mask
	and	r4, r4, r9			@ mask wanted bits
	teq	r3, r4
	beq	2f
	add	r5, r5, #PROC_INFO_SZ		@ sizeof(proc_info_list)
	cmp	r5, r6
	blo	1b
	mov	r5, #0				@ unknown processor
2:	mov	pc, lr
ENDPROC(__lookup_processor_type)

bl __lookup_processor_type:
到此为止,r5=procinfo r9=cpuid;
另外在u-boot启动内核是传递了三个参数分别为:
r0 = 0, r1 = machine nr, r2 = atags or dtb pointer.
这也是为何在开始时不用r0-r3的原因,因为操作后会破坏掉u-boot传递过来的参数;
然后将r5存入r10中;
截止head.S第7至此:
r0 = 0;r1=machine nr; r2 = atags or dtb pointer
r9 = cpuid; r10 = procinfo

继续往下执行THUMB it eq是一个条件执行指令,满足则beq跳转之__err_p;
下面的__vet_atg 主要是校验uboot传过来r2参数,如果参数异常,内核也不会启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值