前言:链接脚本
用户态程序不用关心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_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, lr2.uboot/arch/arm/lib/board.c
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) { 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]); }下边看看cmdtp:
uboot/common/hush.c
cmd_tbl_t *cmdtp;
uboot/include/command.h
typedef struct cmd_tbl_s cmd_tbl_t; 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 };常用uboot命令对应处理函数:
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,