1. 代码流程分析
- 前面已经知道由于UBOOT同时编译两个镜像,代码有一部分重叠复用,需要关注CONFIG_SPL_BUILD宏控;
- 嵌入式中代码的逻辑通常是board->machine -> ARCH -> CPU,在UBOOT中的接口使用类似于重载的概念,使用WEAK修饰;比如在CPU定义一个API并用WEAK修饰,在board中可以重新定义该API并且覆盖前述API,而不会报错;
- 重点关注几个惯例API,如lowlevel_init, board_init_f, board_init_r等等;
以编译am57xx_evm_config为例分析。首先看arch/arm/lib/Makefile
ifdef CONFIG_CPU_V7M
obj-y += vectors_m.o crt0.o
else ifdef CONFIG_ARM64
obj-y += crt0_64.o
else
obj-y += vectors.o crt0.o
endif
我们并没有定义CONFIG_CPU_V7M,所以vectors.S和crt0.S被编译进我们的镜像;其中还会有ifndef CONFIG_SPL_BUILD的定义,即在UBOOT中才会被编译的镜像比如relocate等。而在ectors.S中会定义中断向量表,略过异常处理的中断处理暂不考虑,由于CONFIG_ARCH_K3没有定义,正常重启的处理是reset。
.macro ARM_VECTORS
#ifdef CONFIG_ARCH_K3
ldr pc, _reset
#else
b reset
#endif
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
.endm
找到reset的定义,该代码入口位于 arch/arm/cpu/armv7/start.S,同样是查看其中的makefile
reset:
/* Allow the board to save important registers */
b save_boot_params
save_boot_params_ret:
#ifdef CONFIG_ARMV7_LPAE
/*
* check for Hypervisor support
*/
mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
and r0, r0, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
cmp r0, #(1 << CPUID_ARM_VIRT_SHIFT)
beq switch_to_hypervisor
switch_to_hypervisor_ret:
#endif
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
/*
* Setup vector:
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
#ifdef CONFIG_HAS_VBAR
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
#endif
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
#ifdef CONFIG_CPU_V7A
bl cpu_init_cp15
#endif
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
bl cpu_init_crit
#endif
#endif
bl _main
- save_boot_params,保存ROM code中的parameters(有开机原因等);
- switch_to_hypervisor, 切到hypervisor模式
- cp15协处理器初始化,之后就可以使能MMU等功能;cpu_init_crit 初始化;这两个会调用到板级的定义中。在其中会调用lowlevel_init; lowlevel init设置临时stack,gdata 等;CONFIG_CPU_V7A被定义
- bl _main
前面的过程暂不具体学习,直接到_main函数,这时又回到crt0.S中; _main是一个通用函数,其中通过CONFIG_SPL_BUILD宏控区分SPL和UBOOT。
头文件定义include/config.h
/* Automatically generated - do not edit */
#define CONFIG_BOARDDIR board/ti/am57xx
#include <config_defaults.h>
#include <config_uncmd_spl.h>
#include <configs/am57xx_evm.h>
#include <asm/config.h>
#include <linux/kconfig.h>
#include <config_fallbacks.h>
_main最开始的部分:
调用 board_init_f_alloc_reserve 和 board_init_f_init_reserve 分配并初始化GD; 设置堆栈等C环境,并最终从汇编世界切到C的世界。关于GD,global data,在系统启动