前言:链接脚本
用户态程序不用关心section的具体位置;在用户态,内核会解析elf可执行文件的各个section、然后把它映射到虚拟地址空间。
然而,uboot和linux内核的启动都是从零开始的;所以,需要在编译时指定链接地址、而链接地址一般在lds文件中确定(链接器通过读取lds配置文件来决定)。
uboot/arch/arm/cpu/arm920t/u-boot.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
本uboot基于U-Boot 2011.12;网上分析uboot多基于经典版的U-Boot 2010.06,这时的第一阶段全部由汇编完成。
因此,本分析与经典版略有出入、但本质的东西不会改变;请注意。
一、第一阶段
1.uboot/arch/arm/cpu/arm920t/start.S.globl _start
_start: b start_code
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
//跳转处:
//设置arm工作模式
start_code:
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
//关闭看门狗
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
//关闭所有中断
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
//设置系统频率
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
//设置堆栈
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
2.uboot/arch/arm/lib/board.c
void board_init_f(ulong bootflag)
{
//硬件初始化
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
/*
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f,
#endif
#ifdef CONFIG_OF_CONTROL
fdtdec_check_fdt,
#endif
timer_init,
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init,
init_baudrate,
serial_init,
console_init_f,
display_banner,
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init,
NULL,
};
*/
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
//调用汇编代码
relocate_code(addr_sp, id, addr);
}
3.uboot/arch/arm/cpu/arm920t/start.S
.globl relocate_code
relocate_code:
//bl tank_uboot_print //add by tankai
mov r4, r0/* save addr_sp */
mov r5, r1/* save addr of gd */
mov r6, r2/* save addr of destination */
二、第二阶段
接上述第一阶段中uboot/arch/arm/cpu/arm920t/start.S
1.uboot/arch/arm/cpu/arm920t/start.S
ldr r0, _board_init_r_ofs2.uboot/arch/arm/lib/board.c
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
void board_init_r(ulong bootflag){ for (;;) { main_loop(); }}3.uboot/common/main.c
void main_loop (void){ #ifdef CONFIG_SYS_HUSH_PARSER parse_file_outer(); /* This point is never reached */ for (;;); #else}4.uboot/common/hush.c
int parse_file_outer(void){ rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);}int parse_stream_outer(struct in_str *inp, int flag){ do { //接收uboot命令,并做响应(包括启动内核的)。 rcode = parse_stream(&temp, &ctx, inp, '\n');//读取命令并解析 code = run_list(ctx.list_head); //运行命令 } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP));}5.重点分析执行函数run_list
uboot/common/hush.c
static int run_list(struct pipe *pi)下边看看cmdtp:
{
rcode = run_list_real(pi);
}
static int run_list_real(struct pipe *pi)
{
rcode = run_pipe_real(pi);
}
static int run_pipe_real(struct pipe *pi)
{
if ((cmdtp = find_cmd(child->argv[i])) == NULL) {
printf ("Unknown command '%s' - try 'help'\n", child->argv[i]);
return -1; /* give up after bad command */
}
rcode = (cmdtp->cmd)(cmdtp, flag,child->argc-i,&child->argv[i]);
}
uboot/common/hush.c
cmd_tbl_t *cmdtp;
uboot/include/command.h
typedef struct cmd_tbl_s cmd_tbl_t;常用uboot命令对应处理函数:
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs;/* maximum number of arguments*/
int repeatable;/* autorepeat allowed?*/
/* Implementation function*/
int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
char *usage;/* Usage message(short)*/
#ifdef CONFIG_SYS_LONGHELP
char *help; /* Help message (long)*/
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
bootelf
uboot/common/cmd_elf.c
U_BOOT_CMD(
bootelf, 3, 0, do_bootelf,
go
uboot/common/cmd_boot.c
U_BOOT_CMD(
go, CONFIG_SYS_MAXARGS, 1,do_go,
bootm
uboot/common/cmd_bootm.c
U_BOOT_CMD(
bootm, CONFIG_SYS_MAXARGS, 1,do_bootm,
printenv
uboot/common/cmd_nvedit.c
U_BOOT_CMD_COMPLETE(
printenv, CONFIG_SYS_MAXARGS, 1, do_env_print,