重新设置栈
/* get ready to call C functions */
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
- 在u-boot之start.S分析(一)的最后一部分我们已经设置了栈地址,但是
只有不到8K
的大小,这显然是不够的。由于当时我们并没有初始化DDR,所以只能将栈设置到不需要初始化的内部IRAM中。现在我们已经将DDR初始化好了,因此需要重新将栈移动到DDR中,这样可以避免栈溢出的风险 _TEXT_PHY_BASE
是指uboot代码段物理地址的基地址,最后找到了它的出处(如下)
- start.S的开始部分有
CFG_PHY_UBOOT_BASE
的宏定义,但是由于我们定义了CONFIG_ENABLE_MMU
,因此这一关于CFG_PHY_UBOOT_BASE
宏定义的语句不起作用。
#ifndef CONFIG_ENABLE_MMU
#ifndef CFG_PHY_UBOOT_BASE
#define CFG_PHY_UBOOT_BASE CFG_UBOOT_BASE
#endif
#endif
- 最后在头文件中找到了定义,因此最后的值为0x33e00000,在我们的DRAM0内部
#define MEMORY_BASE_ADDRESS 0x30000000
#define CFG_PHY_UBOOT_BASE MEMORY_BASE_ADDRESS + 0x3e00000
- 这里将栈的地址定位到0x33e00000,由于MMU的关系,该地址就是
TEXT_BASE
定义的代码段地址0xc3e00000
(u-boot之内存地址映射)。由于ARM是满减栈,所以栈是从高地址往下栈的,因此不会对代码段产生影响。
判断是否需要重定位
/* when we already run in ram, we don't need to relocate U-Boot.
* and actually, memory controller must be configured before U-Boot
* is running in ram.
*/
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq after_copy /* r0 == r1 then skip flash copy */
- 判断运行地址是在SRAM还是DDR中,以进行uboot的重定位。
- 冷启动时uboot的前一部分开机自动从SD卡加载到SRAM中运行,uboot的第二部分(其实是整个uboot)依然在SD卡中。
- 这里要做的就是将第二部分加载到DDR的链接地址处(0x33e00000)。
SD卡设备判断
#if defined(CONFIG_EVT1)
/* If BL1 was copied from SD/MMC CH2 */
ldr r0, =0xD0037488
ldr r1, [r0]
ldr r2, =0xEB200000
cmp r1, r2
beq mmcsd_boot
#endif
- 0xD0037488地址来源于
《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》
文件,这个地址中的值指示了从哪个SD卡地址启动的。
- SDMMC0,1,2的设备起始地址分别为0xEB00_0000,0xEB10_0000,0xEB20_0000
- 因此
cmp r1, r2
是在检测是否从外部SD卡启动 - 代码最终进入
mmcsd_boot
执行重定位
重定位
void movi_bl2_copy(void)
{
ulong ch;
#if defined(CONFIG_EVT1)
ch = *(volatile u32 *)(0xD0037488);
copy_sd_mmc_to_mem copy_bl2 =
(copy_sd_mmc_to_mem) (*(u32 *) (0xD0037F98));
#if defined(CONFIG_SECURE_BOOT)
ulong rv;
#endif
#else
ch = *(volatile u32 *)(0xD003A508);
copy_sd_mmc_to_mem copy_bl2 =
(copy_sd_mmc_to_mem) (*(u32 *) (0xD003E008));
#endif
u32 ret;
if (ch == 0xEB000000) {
ret = copy_bl2(0, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
CFG_PHY_UBOOT_BASE, 0);
#if defined(CONFIG_SECURE_BOOT)
/* do security check */
rv = Check_Signature( (SecureBoot_CTX *)SECURE_BOOT_CONTEXT_ADDR,
(unsigned char *)CFG_PHY_UBOOT_BASE, (1024*512-128),
(unsigned char *)(CFG_PHY_UBOOT_BASE+(1024*512-128)), 128 );
if (rv != 0){
while(1);
}
#endif
}
else if (ch == 0xEB200000) {
ret = copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
CFG_PHY_UBOOT_BASE, 0);
#if defined(CONFIG_SECURE_BOOT)
/* do security check */
rv = Check_Signature( (SecureBoot_CTX *)SECURE_BOOT_CONTEXT_ADDR,
(unsigned char *)CFG_PHY_UBOOT_BASE, (1024*512-128),
(unsigned char *)(CFG_PHY_UBOOT_BASE+(1024*512-128)), 128 );
if (rv != 0) {
while(1);
}
#endif
}
else
return;
if (ret == 0)
while (1)
;
else
return;
}
- 代码最终通过执行一个长跳转语句
bl movi_bl2_copy
执行C语言程序,经过搜索,此函数位于cpu/s5pc11x/movi.c
文件中
内存管理单元(MMU)
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mmu_on:
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0
- MMU单元在CP15协处理器中进行控制,因此我们要对cp15协处理器的寄存器进行编程
- 要设置地址转换表基地址(translation table base,TTB)并使能MMU
_mmu_table_base
就是转换表基地址,这个最后指示的是mmu_table
,这在lowlevel_init.S
中- 内存地址映射在u-boot之内存地址映射详细分析