基于QEMU的vexpress-a9的初始化代码运行(一)

这个part是想详细走读一下用qemu运行kernel的最初始代码,也就是使用qemu运行kernel代码的详细逻辑,从qemu加载根目录下vmlinux镜像的逻辑,也就是运行arch/arm/kernel/head.S的整个过程,直到跳转到start_kernel,使用的kernel版本还是3.18。

初始运行状态

沿用上回《基于QEMU的vexpress-a9开发调试环境搭建》的最后一部分调试kernel汇编这一个part,我们需要将vmlinux的链接地址设置到0x60008000,设置方法是修改arch/arm/Kconfig中VMSPLIT_2G对应的值到0x60000000,并重新编译kernel,接着就可以直接b *0x60008000,并且执行到arch/arm/kernel/head.S,这样,我们就可以直接通过命令c运行到arch/arm/kernel/head.S的第一句代码(bl __hyp_stub_install),这其中跳过了compressed/vmlinux的解压内核等逻辑,后续章节再补充。
在这里插入图片描述
在这里插入图片描述
在此,我们打印一下运行到此处时的寄存器
在这里插入图片描述

// arch/arm/kernel/head.S主线代码
#ifdef CONFIG_ARM_VIRT_EXT
	bl	__hyp_stub_install    // 1:如有必要,执行hyp模式的初始化配置
#endif
	@ ensure svc mode and all interrupts masked
	safe_svcmode_maskall r9   // 2: 进入SVC模式,屏蔽中断

	mrc	p15, 0, r9, c0, c0		@ get processor id
	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid   // 3.根据CPU id查找cpu执行函数
	movs	r10, r5				@ invalid processor (r5=0)?

1. __hyp_stub_install的执行

如果定义了CONFIG_ARM_VIRT_EXT宏,则进入arch/arm/kernel/head.S的第一行代码就是bl __hyp_stub_install,__hyp_stub_install首先执行store_primary_cpu_mode,这个方法是用来记录主cpu运行模式的, 只有主CPU在初始化时候才会调用这个方法,这个方法其实是将主cpu当前cpsr寄存器中存的cpu模式(bit0-bit4,当前值为0x13,代表SVC_MODE),存入到__boot_cpu_mode的位置。后面__syp_stub_install_secondary其实用来给其他CPU,检查当前cpu模式,如果和主CPU模式一致,并且也是HYP_MODE,则初始化hyp-stub(这个部分我们不展开讨论了,因为不会走到),由于我们主CPU是SVC_MODE,所以不满足第二个条件,所以在执行到114行代码时,就会retne lr,返回head.S的主代码逻辑。

在这里插入图片描述

2. safe_svcmode_maskall的执行

这部分做的是强制让cpu进入SVC模式,并屏蔽中断。

/*
 * Helper macro to enter SVC mode cleanly and mask interrupts. reg is
 * a scratch register for the macro to overwrite.
 *
 * This macro is intended for forcing the CPU into SVC mode at boot time.
 * you cannot return to the original mode.
 */
.macro safe_svcmode_maskall reg:req
#if __LINUX_ARM_ARCH__ >= 6 && !defined(CONFIG_CPU_V7M)
	mrs	\reg , cpsr  //读取cpsr到reg
	eor	\reg, \reg, #HYP_MODE //reg和HYP_MODE(0x14)进行异或,结果存到reg
	tst	\reg, #MODE_MASK // 测试是否与0x1F相同,由于cpsr中是SVC,与HYP异或后上一步结果非0,所以这里cpsr中Z位置0
	bic	\reg , \reg , #MODE_MASK //清除reg中模式位
	orr	\reg , \reg , #PSR_I_BIT | PSR_F_BIT | SVC_MODE //reg中屏蔽中断和快速中断,并设置SVC模式
THUMB(	orr	\reg , \reg , #PSR_T_BIT	)
	bne	1f //由于cpsr中Z为0,跳转到1:的位置。
	orr	\reg, \reg, #PSR_A_BIT //将r0,第8位,exception位清零
	adr	lr, BSYM(2f) //badr是设置lr到2:这个位置,也就是跳出这个函数了。
	msr	spsr_cxsf, \reg //将hyp模式的spsr,设置成新的svc的cpsr
	__MSR_ELR_HYP(14) //这两句是thumb语句,ignore
	__ERET
1:	msr	cpsr_c, \reg //将reg中的结果,设置到cpsr_c,也就是cpsr的低8位里
2:
......

通过上面代码分析可知,如果当前cpu模式为HYP模式,需要额外将新的cpsr设置到HYP模式的spsr中,否则,就只是屏蔽中断/快中断,并让cpu进入svc模式。下面图可以看出HYP模式有自己的spsr寄存器。
在这里插入图片描述

3 __lookup_processor_type的执行

这部分是在.proc.info.init数据中,查找对应cpu的私有执行方法。具体步骤为:

  1. 调用CP15寄存器方法(mrc p15, 0, r9, c0, c0),获得cpu id。
  2. 通过cpu id,到.proc.init段中查找对应的cpu的私有执行方法。
  3. 找到后存入r5寄存器返回
/*
 * Read processor ID register (CP#15, CR0), and look up in the linker-built
 * supported processor list.  Note that we can't use the absolute addresses
 * for the __proc_info lists since we aren't running with the MMU on
 * (and therefore, we are not in the correct address space).  We have to
 * calculate the offset.
 *
 *	r9 = cpuid
 * Returns:
 *	r3, r4, r6 corrupted
 *	r5 = proc_info pointer in physical address space
 *	r9 = cpuid (preserved)
 */
__lookup_processor_type:
	adr	r3, __lookup_processor_type_data // r3存放__lookup_processor_type_data的物理地址
	ldmia	r3, {
   
   r4 - r6}   //r4存放__lookup_processor_type_data的链接地址,r5存放__proc_info_start链接地址,r6存放__proc_info_end链接地址
	sub	r3, r3, r4			@ get offset between virt&phys //用r3-r4,__lookup_processor_type_data的物理地址减去链接地址,r3存放物理地址与链接地址的差值
	add	r5, r5, r3			@ convert virt addresses to//r5存放__proc_info_start物理地址
	add	r6, r6, r3			@ physical address space //r6存放__proc_info_end物理地址
1:	ldmia	r5, {
   
   r3, r4}			@ value, mask // r3存放proc_info的cpu id,r4存掩码
	and
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值