1 lowlevel_init
上一节说到在执行cpu_init_crit后,实际执行的是lowlevel_init,这段代码如下所示,位于 arch\arm\cpu\armv7\lowlevel_init.S 中。
.pushsection .text.lowlevel_init, "ax"
WEAK(lowlevel_init)
/*
* Setup a temporary stack. Global data is not available yet.
*/
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =CONFIG_SPL_STACK
#else
ldr sp, =CONFIG_SYS_INIT_SP_ADDR /* 设置栈指针 */
#endif
bic sp, sp, #7 /* 8-byte alignment for ABI compliance 8字节对齐 */
#ifdef CONFIG_SPL_DM
mov r9, #0
#else
/*
* Set up global data for boards that still need it. This will be
* removed soon.
*/
#ifdef CONFIG_SPL_BUILD
ldr r9, =gdata
#else
sub sp, sp, #GD_SIZE /* -248 */
bic sp, sp, #7
mov r9, sp /* 将sp放入到寄存器r9中 */
#endif
#endif
/*
* Save the old lr(passed in ip) and the current lr to stack
*/
push {ip, lr}
/*
* Call the very early init function. This should do only the
* absolute bare minimum to get started. It should not:
*
* - set up DRAM
* - use global_data
* - clear BSS
* - try to start a console
*
* For boards with SPL this should be empty since SPL can do all of
* this init in the SPL board_init_f() function which is called
* immediately after this.
*/
bl s_init
pop {ip, pc}
ENDPROC(lowlevel_init)
.popsection
2 设置栈指针
在代码最开始,设置了栈指针,由于没有定义 CONFIG_SPL_BUILD,所以执行的代码为
ldr sp, =CONFIG_SYS_INIT_SP_ADDR
将宏 CONFIG_SYS_INIT_SP_ADDR 展开为:
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET) (include\configs\mx6ul_14x14_evk.h)
#define CONFIG_SYS_INIT_RAM_ADDR IRAM_BASE_ADDR (include\configs\mx6ul_14x14_evk.h)
#define IRAM_BASE_ADDR 0x00900000 (arch\arm\include\asm\arch-mx6\imx-regs.h)
#define CONFIG_SYS_INIT_SP_OFFSET (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE) (include\configs\mx6ul_14x14_evk.h)
#define CONFIG_SYS_INIT_RAM_SIZE IRAM_SIZE \ (include\configs\mx6ul_14x14_evk.h)
#if !(defined(CONFIG_MX6SX) || defined(CONFIG_MX6UL) || defined(CONFIG_MX6ULL) || defined(CONFIG_MX6SLL) || defined(CONFIG_MX6SL)) \
#define IRAM_SIZE 0x00040000 \
#else \
#define IRAM_SIZE 0x00020000 \
#endif
#define GENERATED_GBL_DATA_SIZE 256 /* (sizeof(struct global_data) + 15) & ~15 */ (include\generated\generic-asm-offsets.h)
最终计算得到 CONFIG_SYS_INIT_SP_ADDR 的地址为:
CONFIG_SYS_INIT_SP_ADDR = CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET
= IRAM_BASE_ADDR + (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
= 0x00900000 + IRAM_SIZE - 256
= 0x00900000 + 0x00020000 - 256
= 0X0091FF00
代码第9行将 CONFIG_SYS_INIT_SP_ADDR 的值赋值给sp指针,第11行将sp按照8字节对齐。查看imx6ull的芯片手册第二章,找到Table2-1,可以看到芯片内部的SRAM的大小如下图所示。
执行代码11行后,芯片内部SRAM德尔地址分配如下图所示:
代码22-24又将 sp 的值减去了 GD_SIZE 的大小,然后8字节对齐后,将 sp 的值放入到了 r9 寄存器中。其中 GD_SIZE 在 include\generated\generic-asm-offsets.h 中进行了定义,定义如下:
#define GD_SIZE 248 /* sizeof(struct global_data) @ */
执行完24行的代码后,内部SRAM的地址分布如下图所示:
在接下来的分析中由于会频繁的接触到ARM内部的寄存器,所以本文将内部寄存器一一列举出来,方便后续的分析。
r0 | r1 | r2 | r3 | r4 | r5 | r6 | r7 | r8 | r9 | r10 |
---|---|---|---|---|---|---|---|---|---|---|
sp |
3 s_init
s_init的代码位于 arch\arm\mach-imx\mx6\soc.c 中,本次使用的是 imx6ull 开发板,所以这个函数会直接返回。
void s_init(void)
{
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
u32 mask480;
u32 mask528;
u32 reg, periph1, periph2;
if (is_mx6sx() || is_mx6ul() || is_mx6ull() || is_mx6sll())
return;
... ...
}
4 跳转到 bl _main
push {ip, lr}
...
pop {ip, pc}
将之前的lr弹给pc,也就是跳到前一个bl的下面,也就是start.S中的 _main。接下来会执行_main函数,跳转到C语言的部分开始执行。
bl _main