一、uboot启动原理
1、第一阶段初始化(汇编)
(1)关闭看门狗
(2)初始化时钟
(3)初始化SDRAM
(4)设置堆栈
(5)拷贝第二阶段代码
2、第二阶段初始化(c语言)
(1)实现读写flash
(2)串口通信
(3)网络通信
(4)读取内核,引导内核
二、源码分析
1、第一阶段,硬件相关初始化(arch/arm/cpu/arm920t/start.S)
- 1、向量表
- .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
-
- 2、上电跳转reset启动
-
- (1)设置CPU为SVC32模式
- reset:
- /*
- * set the cpu to SVC32 mode
- */
- mrs r0,cpsr
- bic r0,r0,#0x1f
- orr r0,r0,#0xd3
- msr cpsr,r0
- (2)关闭看门狗
- /* turn off the watchdog */
- #if defined(CONFIG_S3C2400)
- # define pWTCON 0x15300000
- # define INTMSK 0x14400008 /* Interupt-Controller base addresses */
- # define CLKDIVN 0x14800014 /* clock divisor register */
- #elif defined(CONFIG_S3C2410)
- # define pWTCON 0x53000000
- # define INTMOD 0X4A000004
- # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
- # define INTSUBMSK 0x4A00001C
- # define CLKDIVN 0x4C000014 /* clock divisor register */
- #endif
-
- #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
- ldr r0, =pWTCON
- mov r1, #0x0
- str r1, [r0]
- (3)屏蔽所有中断
- /*
- * mask all IRQs by setting all bits in the INTMR - default
- */
- mov r1, #0xffffffff
- ldr r0, =INTMSK
- str r1, [r0]
- # if defined(CONFIG_S3C2410)
- ldr r1, =0x3ff
- ldr r0, =INTSUBMSK
- str r1, [r0]
- # endif
- (4)设置CPU相关设置(cpu_init_crit: 清除I/O caches,初始化存储管理器)
- #ifndef CONFIG_SKIP_LOWLEVEL_INIT
- 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 */
- blne cpu_init_crit
- #endif
- (5)设置栈
- /* Set up the stack */
- stack_setup:
- ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
- sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
- sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo
- #ifdef CONFIG_USE_IRQ
- sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
- #endif
- sub sp, r0, #12 /* leave 3 words for abort-stack */
- (6)初始化时钟
- #ifndef CONFIG_SKIP_LOWLEVEL_INIT
- bl clock_init
- #endif
- (7)重定位,将代码拷贝至内存(SDRAM)
- #ifndef CONFIG_SKIP_RELOCATE_UBOOT
- 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 clear_bss
-
- ldr r2, _armboot_start
- ldr r3, _bss_start
- sub r2, r3, r2 /* r2 <- size of armboot */
- #if 1
- bl CopyCode2Ram /* r0: source, r1: dest, r2: size */
- #else
- 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
- #endif
- #endif /* CONFIG_SKIP_RELOCATE_UBOOT */
- (8)清除bss段
- clear_bss:
- ldr r0, _bss_start /* find start of bss segment */
- ldr r1, _bss_end /* stop here */
- mov r2, #0x00000000 /* clear
- clbss_l:str r2, [r0] /* clear loop... */
- add r0, r0, #4
- cmp r0, r1
- ble clbss_l
- (9)跳转至第二阶段
- ldr pc, _start_armboot
- _start_armboot: .word start_armboot
2、第二阶段,c语言程序(lib_arm/board.c)
(1)lib_arm/board.c
- 1、设置运行环境
- /* Pointer is writable since we allocated a register for it */
- gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
- /* compiler optimization barrier needed for GCC >= 3.4 */
- __asm__ __volatile__("": : :"memory");
-
- memset ((void*)gd, 0, sizeof (gd_t));
- gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
- memset (gd->bd, 0, sizeof (bd_t));
-
- typedef struct global_data {
- bd_t *bd;
- unsigned long flags;
- unsigned long board_type;
- unsigned long baudrate;
- unsigned long have_console; /* serial_init() was called */
- unsigned long ram_size; /* RAM size */
- unsigned long reloc_off; /* Relocation Offset */
- unsigned long env_addr; /* Address of Environment struct */
- unsigned long env_valid; /* Checksum of Environment valid? */
- void **jt; /* jump table */
- } gd_t;
- (2)进一步初始化硬件
- monitor_flash_len = _bss_start - _armboot_start;
-
- for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
- if ((*init_fnc_ptr)() != 0) {
- hang ();
- }
- }
- init_fnc_t *init_sequence[] = {
- cpu_init, /* basic cpu dependent setup */
- board_init, /* basic board dependent setup */
- dram_init, /* configure available RAM banks */
- mem_malloc_init, /* dependant on dram_init */
- interrupt_init, /* set up exceptions */
- timer_init,
- serial_init,
- env_init, /* initialize environment */
- init_baudrate, /* initialze baudrate settings */
- serial_init, /* serial communications setup */
- display_banner,
- display_dram_config,
-
- NULL,
- };
-
- int board_init (void) // board/mini2440/mini2440.c
- {
- S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
- S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
-
- /* set up the I/O ports */
- gpio->GPACON = 0x007FFFFF;
- gpio->GPBCON = 0x00044555;
- gpio->GPBUP = 0x000007FF;
- gpio->GPCCON = 0xAAAAAAAA;
- gpio->GPCUP = 0x0000FFFF;
- gpio->GPDCON = 0xAAAAAAAA;
- gpio->GPDUP = 0x0000FFFF;
- gpio->GPECON = 0xAAAAAAAA;
- gpio->GPEUP = 0x0000FFFF;
- gpio->GPFCON = 0x000055AA;
- gpio->GPFUP = 0x000000FF;
- gpio->GPGCON = 0xFF95FFBA;
- gpio->GPGUP = 0x0000FFFF;
- gpio->GPHCON = 0x002AFAAA;
- gpio->GPHUP = 0x000007FF;
-
- /* support both of S3C2410 and S3C2440, by www.arm9.net */
- if ((gpio->GSTATUS1 == 0x32410000) || (gpio->GSTATUS1 == 0x32410002))
- {
- /* arch number of SMDK2410-Board */
- gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
- }
- else
- {
- /* arch number of SMDK2440-Board */
- gd->bd->bi_arch_number = MACH_TYPE_S3C2440; //机器ID,内核启动时会使用
- }
-
- /* adress of boot parameters */
- gd->bd->bi_boot_params = 0x30000100;
- icache_enable();
- #if 0
- dcache_enable();
- #endif
- return 0;
- }
-
- (3)环境变量初始化(uboot命令行的printenv)
- /* initialize environment */
- env_relocate ();
- (4)uboot主循环
- /* main_loop() can return to retry autoboot, if so just run it again. */
- for (;;) {
- main_loop ();
- }
(2)common/main.c
- 1、获取bootcmd,如果没有命令则启动内核
- s = getenv ("bootcmd");
-
- debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "
" ); -
- if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
- # ifdef CONFIG_AUTOBOOT_KEYED
- int prev = disable_ctrlc(1); /* disable Control C checking */
- # endif
-
- # ifndef CFG_HUSH_PARSER
- #ifdef CONFIG_SURPORT_WINCE
- if (!TOC_Read())
- {
- /* Launch wince */
- char cmd_buf[16];
- printf("Booting wince ...\n");
- strcpy(cmd_buf, "wince");
- run_command(cmd_buf, 0);
- }
- else
- #endif
- {
- printf("Booting Linux ...\n");
- run_command (s, 0);
- }
- # else
- parse_string_outer(s, FLAG_PARSE_SEMICOLON |
- FLAG_EXIT_FROM_LOOP);
- # endif
-
- (2)获取命令行命令,执行命令
- for (;;) {
- #ifdef CONFIG_BOOT_RETRY_TIME
- if (rc >= 0) {
- /* Saw enough of a valid command to
- * restart the timeout.
- */
- reset_cmd_timeout();
- }
- #endif
- len = readline (CFG_PROMPT);
-
- flag = 0; /* assume no special flags for now */
- if (len > 0)
- strcpy (lastcommand, console_buffer);
- else if (len == 0)
- flag |= CMD_FLAG_REPEAT;
- #ifdef CONFIG_BOOT_RETRY_TIME
- else if (len == -2) {
- /* -2 means timed out, retry autoboot
- */
- puts ("\nTimed out waiting for command\n");
- # ifdef CONFIG_RESET_TO_RETRY
- /* Reinit board to run initialization code again */
- do_reset (NULL, 0, 0, NULL);
- # else
- return; /* retry autoboot */
- # endif
- }
- #endif
-
- if (len == -1)
- puts ("
\n" ); - else
- rc = run_command (lastcommand, flag);
-
- if (rc <= 0) {
- /* invalid command or not repeatable, forget it */
- lastcommand[0] = 0;
- }
- }