之前的裸机程序,上电需要做的事情在.S
里边,大致步骤:
- 初始化
关看门狗
初始化时钟
初始化SDRAM - 把程序从nand拷贝到SDRAM
- 设置sp(使sp指向main所在内存)
uboot程序上电需要做的事情分为两段,第一段主要是底层的硬件初始化:
- 设为管理模式
- 关闭看门狗
- 屏蔽中断
- 初始化SDRAM(需要配置存储管理器等)
- 设置栈
- 时钟
- 重定位(代码从flash拷贝到SDRAM)
- 清bss段
- 调用start_armboot (c代码,串口/USB/网卡等等 )
cpu/arm920t/start.S
.globl _start
_start: b reset
首先跳转到reset的地方,将cpu设置为管理模式
reset:
/*
* set the cpu to SVC32 mode # 设置为管理模式
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
关闭看门狗
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
屏蔽所有中断
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
读取中_start的地址,与_TEXT_BASE比较:
如果是上电运行,代码的前4K会被自动从nand拷贝到内部的SRAM中,则_start的地址就是0;
如果程序是通过调试器仿真器直接下载到SDRAM,则_start的地址就是链接地址0x33F80000。
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
blne cpu_init_crit
#endif
比较结果不等说明SDRAM还没有被初始化,需要到cpu_init_crit去初始化SDRAM:
- 关flush清空cache
- 关MMU
- 初始化存储控制器(lowlevel_init在board/100ask24x0/lowlevel_init.S)
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 2 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0
...
...
bl lowlevel_init
栈的划分:
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
初始化时钟,usb,系统的时钟
bl clock_init
clock_init在board/100ask24x0/boot_init.c,
void clock_init(void)
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFFFF;
/* configure UPLL */
clk_power->UPLLCON = S3C2410_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure MPLL */
clk_power->MPLLCON = S3C2410_MPLL_200MHZ;
重定位:代码从flash中读到SDRAM中,地址为链接地址,
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq clear_bss
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
#if 1
bl CopyCode2Ram /* r0: source, r1: dest, r2: size */
#else
add r2, r0, r2 /* r2 <- source end address */
CopyCode2Ram在board/100ask24x0/boot_init.c中,
int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
{
unsigned int *pdwDest;
unsigned int *pdwSrc;
int i;
if (bBootFrmNORFlash())
{
pdwDest = (unsigned int *)buf;
pdwSrc = (unsigned int *)start_addr;
/* 从 NOR Flash启动 */
for (i = 0; i < size / 4; i++)
{
pdwDest[i] = pdwSrc[i];
}
return 0;
}
else
{
/* 初始化NAND Flash */
nand_init_ll();
/* 从 NAND Flash启动 */
nand_read_ll_lp(buf, start_addr, (size + NAND_BLOCK_MASK_LP)&~(NAND_BLOCK_MASK_LP));
return 0;
}
}
其中bBootFrmNORFlash是判断从nand启动还是从nor启动,判断方式是看0地址可写与否,如果写进去和读出来的数据同则为nand启动;因为nor不能像RAM一样去写,所以读出来的不等于写进去的数据。
int bBootFrmNORFlash(void)
{
volatile unsigned int *pdw = (volatile unsigned int *)0;
unsigned int dwVal;
/*
* 无论是从NOR Flash还是从NAND Flash启动,
* 地址0处为指令"b Reset", 机器码为0xEA00000B,
* 对于从NAND Flash启动的情况,其开始4KB的代码会复制到CPU内部4K内存中,
* 对于从NOR Flash启动的情况,NOR Flash的开始地址即为0。
* 对于NOR Flash,必须通过一定的命令序列才能写数据,
* 所以可以根据这点差别来分辨是从NAND Flash还是NOR Flash启动:
* 向地址0写入一个数据,然后读出来,如果没有改变的话就是NOR Flash
*/
dwVal = *pdw;
*pdw = 0x12345678; // 重点
if (*pdw != 0x12345678)
{
return 1;
}
else
{
*pdw = dwVal;
return 0;
}
}
清bss段:
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
board/100ask24x0/uboot.lds文件中,意思是存放所有文件的bss段
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
以上都是硬件相关的初始化,是uboot的第一阶段。
启动ARM核:
ldr pc, _start_armboot