skyeye之uboot启动过程分析

前言:链接脚本

  用户态程序不用关心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, lr
2.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,

你可能感兴趣的:(skyeye之uboot启动过程分析)