u-boot版本2010-12
.globl _start
_start: b reset
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
/*定义异常向量入口*/
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
_pad: .word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
/*.word就是把后面的值赋给:前面*/
.balignl 16,0xdeadbeef
/*deadbeef是中断的意思,作用大概
就是为内存做标记,有点儿像个
小旗子,插在那里,表示从这个
位置往后,就是干什么的内存,
这个位置往前,禁止访问*/
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
/*设置CPU为SVC32模式*/
bl cpu_init_crit
/*初始化时钟,内存和串口,使能MMU*/
这个函数有必要看一下
.globl lowlevel_init
lowlevel_init:
/* use iROM stack in bl2 */
ldr sp, =0x02060000
push {lr}
/* check reset status */
ldr r0, =(INF_REG_BASE + INF_REG1_OFFSET)
ldr r1, [r0]
/* Sleep wakeup reset */
ldr r2, =S5P_CHECK_SLEEP
cmp r1, r2
beq wakeup_reset
/* set CP reset to low */
ldr r0, =0x11000C60
ldr r1, [r0]
ldr r2, =0xFFFFFF0F
and r1, r1, r2
orr r1, r1, #0x10
str r1, [r0]
ldr r0, =0x11000C68
ldr r1, [r0]
ldr r2, =0xFFFFFFF3
and r1, r1, r2
orr r1, r1, #0x4
str r1, [r0]
ldr r0, =0x11000C64
ldr r1, [r0]
ldr r2, =0xFFFFFFFD
and r1, r1, r2
str r1, [r0]
/* led (GPM4_0~3) on */
ldr r0, =0x110002E0
ldr r1, =0x00001111
str r1, [r0]
ldr r1, =0x0e
str r1, [r0, #0x04]
/* During sleep/wakeup or AFTR mode, pmic_init function is not available
* and it causes delays. So except for sleep/wakeup and AFTR mode,
* the below function is needed
*/
bl read_om
/* 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 sdram init and u-boot.bin loading */
一些设置,然后代码是否始终在片内内存中运行,如果是则跳过后面的初始化SDRAM
/* init system clock */
bl system_clock_init
/* Memory initialize */
bl mem_ctrl_asm_init
/* init uart for debug */
bl uart_asm_init
初始化时钟,内存和串口
bl tzpc_init
b load_uboot
初始化tzpc,加载uboot
我们来看一下如何加载,从哪里加载到哪里?
load_uboot:
ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET]
cmp r1, #BOOT_NAND
beq nand_boot
cmp r1, #BOOT_ONENAND
beq onenand_boot
cmp r1, #BOOT_MMCSD
beq mmcsd_boot
cmp r1, #BOOT_EMMC
beq emmc_boot
cmp r1, #BOOT_EMMC_4_4
beq emmc_boot_4_4
cmp r1, #BOOT_NOR
beq nor_boot
cmp r1, #BOOT_SEC_DEV
beq mmcsd_boot
比较r1中的值,判断是何种启动,,r1中数值是在前面read_om函数中设置的
mmcsd_boot:
ldr r0, =ELFIN_CLOCK_BASE
ldr r2, =CLK_DIV_FSYS2_OFFSET
ldr r1, [r0, r2]
orr r1, r1, #0xf
str r1, [r0, r2]
bl movi_uboot_copy
b after_copy
在movi_uboot_copy函数中通过
SDMMC_ReadBlocks(MOVI_UBOOT_POS, MOVI_UBOOT_BLKCNT, CONFIG_PHY_UBOOT_BASE);
把u-boot从SD卡读到内存
SDMMC_ReadBlocks(49, 328, 0x43e00000);
从第49块开始读,读328字节,读到0x43e00000
after_copy:
/* led (GPM4_0~3) on */
ldr r0, =0x110002E0
ldr r1, =0x0c
str r1, [r0, #0x04]
/* set up C2C */
ldr r0, =S5PV310_SYSREG_BASE
ldr r2, =GENERAL_CTRL_C2C_OFFSET
ldr r1, [r0, r2]
ldr r3, =0x4000
orr r1, r1, r3
str r1, [r0, r2]
bl enable_mmu
/* store second boot information in u-boot C level variable */
ldr r0, =CONFIG_PHY_UBOOT_BASE
sub r0, r0, #8
ldr r1, [r0]
ldr r0, _second_boot_info
str r1, [r0]
/* Print 'K' */
ldr r0, =S5PV310_UART_CONSOLE_BASE
ldr r1, =0x4b4b4b4b
str r1, [r0, #UTXH_OFFSET]
ldr r0, _board_init_f
mov pc, r0
_board_init_f:
.word board_init_f
_second_boot_info:
.word second_boot_info
这段代码中使能MMU了,之后的地址都要使用虚拟地址了
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f
/*设置栈进入C函数,board_init_f在arch/arm/lib/borad.c中定义*/
我们进入borad.c看一下board_init_f 函数做了什么
void board_init_f(ulong bootflag)
{
bd_t *bd;
init_fnc_t **init_fnc_ptr;
gd_t *id;
ulong addr, addr_sp;
/* Pointer is writable since we allocated a register for it */
gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset((void*)gd, 0, sizeof (gd_t));
gd->mon_len = _bss_end_ofs;
gd为结构体指针,并为这个结构体分配了空间,用于存一些参数
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang();
}
}
循环调用init_sequence函数指针数组中的函数指针,进行一系列的初始化
addr = CONFIG_SYS_LOAD_ADDR;
gd->bd->bi_baudrate = gd->baudrate;
/* Ram ist board specific, so move it to board code ... */
dram_init_banksize();
display_dram_config(); /* and display it */
gd->relocaddr = addr;
gd->start_addr_sp = addr_sp;
gd->reloc_off = addr - _TEXT_BASE;
debug ("relocation Offset is: %08lx\n", gd->reloc_off);
memcpy(id, (void *)gd, sizeof (gd_t));
设置重定位信息,又设置了RAM,把gd复制到新地址
函数dram_init_banksize()百度了一下作用
A、 分配SDRAM高64KB为TLB,用于U-BOOT
B、分配SDRAM下一单元为U-BOOT代码段,数据段,BSS段
relocate_code(addr_sp, id, addr);
返回start.s,并传重定位参数
.globl relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
cmp r0, r6
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r2, _TEXT_BASE
ldr r3, _bss_start_ofs
add r2, r0, r3 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
重定位代码,如果代码所在地址不是链接地址就要拷贝,
jump_2_ram:
ldr r0, _board_init_r_ofs
adr r1, _start
add lr, r0, r1
@ add lr, lr, r9
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
mov pc, lr
跳的重定位后的代码,执行函数board_init_r
void board_init_r(gd_t *id, ulong dest_addr)
{
char *s;
bd_t *bd;
ulong malloc_start;
gd = id;
bd = gd->bd;
gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
monitor_flash_len = _bss_start_ofs;
debug ("monitor flash len: %08lX\n", monitor_flash_len);
board_init(); /* Setup chipselects */
board_init函数是一些关于tiny4412的设置,并且通过判断OmPin的值,知道开发板是何种启动方式并打印
OmPin = INF_REG3_REG;
printf("\n\nChecking Boot Mode ...");
if (OmPin == BOOT_ONENAND) {
printf(" OneNand\n");
} else if (OmPin == BOOT_NAND) {
printf(" NAND\n");
} else if (OmPin == BOOT_MMCSD) {
printf(" SDMMC\n");
} else if (OmPin == BOOT_EMMC) {
printf(" EMMC4.3\n");
} else if (OmPin == BOOT_EMMC_4_4) {
printf(" EMMC4.41\n");
}
这和开发板上电的输出Checking Boot Mode ... SDMMC刚好对应上
接着看board_init_r
/* The Malloc area is immediately below the monitor copy in DRAM */
malloc_start = dest_addr - TOTAL_MALLOC_LEN;
mem_malloc_init(malloc_start, TOTAL_MALLOC_LEN);
实现堆的分配
#if defined(CONFIG_CMD_NAND)
puts("NAND:\t");
nand_init(); /* go init the NAND */
#endif
#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif
#ifdef CONFIG_GENERIC_MMC
mmc_initialize(bd);
#endif
接着是nand,onenand,mmc的初始化,估计这里面就有对SD卡的操作,以后再去搞明白
env_relocate();
初始化环境变量
gd->bd->bi_ip_addr = getenv_IPaddr("ipaddr");
stdio_init(); /* get the devices list going. */
jumptable_init();
/* set up exceptions */
interrupt_init();
/* enable exceptions */
enable_interrupts();
/* set up exceptions */
interrupt_init();
/* enable exceptions */
enable_interrupts();
eth_initialize(gd->bd);
这又是一大堆初始化,以后再细分析
for (;;) {
main_loop();
}
最后死循环,调用main_loop();
main_loop中
</pre><pre name="code" class="cpp"> s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
init_cmd_timeout ();
s = getenv ("bootcmd");
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
int prev = disable_ctrlc(1); /* disable Control C checking */
run_command (s, 0);
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
disable_ctrlc(prev); /* restore Control C checking */
}
这段代码实现了倒计时,如果超时执行run_command(s,o);
如果有输入则继续执行下面的语句
for (;;) {
len = readline (CONFIG_SYS_PROMPT);
flag = 0; /* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
if (len == -1)
puts ("<INTERRUPT>\n");
else
rc = run_command (lastcommand, flag);
if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
}
}
死循环readline,然后解析