U-Boot的entry的位置在u-boot-<version>/cpu/<type>/start.S中, 一开始的动作便
是要初始化processor, 因此在start.S中:
.globl _start
_start: b reset
这边直接branch到reset这个label的地方, 这个assembler的函式负责初始系统的
硬件(主要是processor与memory), 然后会jump到start_armboot这个function (这个
function存在于u-boot-<version>/lib_<arch>/board.c中, <arch>为你的processor的架
构, 例如xscale就是lib_arm的目录, 进到start_armboot就大多是C语言而不是
assembler, 感谢上帝&妈祖&众神明...), 让我们以ARM pxa为例来看看这段assembler程
式码 (sorry, 其它的架构不是太熟)。一开始必需让ARM进入superviser mode, 因此必需
设定Current Program Status Register(CPSR)如下:
mrs r0,cpsr /* set the cpu to SVC32 mode */
bic r0,r0,#0x1f /* (superviser mode, M=10011) */
orr r0,r0,#0x13
msr cpsr,r0
ARM的SVC mode必需设定CPSR为100112(请参考ARM的相关数据, 我自己是看Steve
Furber的书『ARM system-on-chip architecture』第108页)。然后u-boot会branch去一
段cpu init的routine, 这边在新版的U-Boot有一点不一样, 旧版的会直接branch过去,
而新版的U-Boot(version 1.1.1)会以一个设定值CONFIG_INIT_CRITICAL来判断要不要执行
这段routine, 这是因为新版的U-Boot可以支持bootloader debug的方式让你方便研发,
但是这个我没试过, 因此有兴趣的人请自行试试。下面是cpu_init_crit这个routine的程
式片断:
cpu_init_crit:
/* mask all IRQs */
ldr r0, IC_BASE
mov r1, #0x00
str r1, [r0, #ICMR]
#if defined(CFG_CPUSPEED)
/* set clock speed */
ldr r0, CC_BASE
ldr r1, cpuspeed
str r1, [r0, #CCCR]
mov r0, #2
mcr p14, 0, r0, c6, c0, 0
setspeed_done:
#endif
/*
* before relocating, we have to setup RAM timing because memory timing is
* board-dependend, you will find a memsetup.S in your board directory.
*/
mov ip, lr
bl memsetup
mov lr, ip
/* Memory interfaces are working. Disable MMU and enable I-cache. */
ldr r0, =0x2001 /* enable access to all coproc. */
mcr p15, 0, r0, c15, c1, 0
CPWAIT
mcr p15, 0, r0, c7, c10, 4 /* drain the write & fill buffers */
CPWAIT
mcr p15, 0, r0, c7, c7, 0 /* flush Icache, Dcache and BTB */
CPWAIT
mcr p15, 0, r0, c8, c7, 0 /* flush instuction and data TLBs */
CPWAIT
mov pc, lr
这段assembler程序代码主要就是透过ARM coprocessor interface来设定Performance
Monitoring Unit(PMU)与Memory Management Unit(MMU), 也就是CP14与CP15这两个
coprocessor, 这段assembler片段有详细的说明(感恩呀...), 因此可以很清楚的看到中间
还有branch到u-boot-<version>/board/<board-type>/memsetup.S里面的memsetup这个
位置, 这个routine会设定GPIO相关设定以及memory controller, 因此在之前提过的硬件
设定檔要加入相关的设定值, 以lubbock为例, 他设定GPIO与memory的部份如下:
#define CFG_GPSR0_VAL 0x00008000
#define CFG_GPSR1_VAL 0x00FC0382
#define CFG_GPSR2_VAL 0x0001FFFF
#define CFG_GPCR0_VAL 0x00000000
#define CFG_GPCR1_VAL 0x00000000
#define CFG_GPCR2_VAL 0x00000000
#define CFG_GPDR0_VAL 0x0060A800
#define CFG_GPDR1_VAL 0x00FF0382
#define CFG_GPDR2_VAL 0x0001C000
#define CFG_GAFR0_L_VAL 0x98400000
#define CFG_GAFR0_U_VAL 0x00002950
#define CFG_GAFR1_L_VAL 0x000A9558
#define CFG_GAFR1_U_VAL 0x0005AAAA
#define CFG_GAFR2_L_VAL 0xA0000000
#define CFG_GAFR2_U_VAL 0x00000002
#define CFG_PSSR_VAL 0x20
#define CFG_MSC0_VAL 0x23F223F2
#define CFG_MSC1_VAL 0x3FF1A441
#define CFG_MSC2_VAL 0x7FF97FF1
#define CFG_MDCNFG_VAL 0x00001AC9
#define CFG_MDREFR_VAL 0x00018018
#define CFG_MDMRS_VAL 0x00000000
这部份的设定也是要根据你的硬件配置与外围, 因此必需跟你的硬件人员研究一下, 当
这些硬件初始的动作作玩后, 我们会回到之前branch到cpu_init_crit的下一个位置(透过
把LR缓存器的值写进PC缓存器), 然后把U-Boot重新寻址到RAM上面, 如下:
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 stack_setup
ldr r2, _armboot_start
ldr r3, _armboot_end
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
最后再设定stack与清除BSS segment就可以跳到start_armboot的地方啦 |