现在的位置: 首页 > 综合 > 正文

Bootloader系列(三)UBoot解析

2018年02月23日 ⁄ 综合 ⁄ 共 7230字 ⁄ 字号 评论关闭

    U-Boot全称是Universal Bootloader,也是一款开源项目。从名字就可以看出该项目雄心勃勃,希望这个bootloader能够适用于所有的主流CPU。下载地址:ftp://ftp.denx.de/pub/u-boot/ 
    1. 目录结构
/arch Architecture specific files
 /arm Files generic to ARM architecture
   /cpu
CPU specific files
     /arm720t
Files specific to ARM 720 CPUs
     /arm920t
Files specific to ARM 920 CPUs
/at91 Files specific to Atmel AT91RM9200 CPU
/imx Files specific to Freescale MC9328 i.MX CPUs
/s3c24x0
Files specific to Samsung S3C24X0 CPUs
     /arm925t
Files specific to ARM 925 CPUs
     /arm926ejs
Files specific to ARM 926 CPUs
     /arm1136
Files specific to ARM 1136 CPUs
     /ixp
Files specific to Intel XScale IXP CPUs
     /pxa
Files specific to Intel XScale PXA CPUs
     /s3c44b0
Files specific to Samsung S3C44B0 CPUs
     /sa1100
Files specific to Intel StrongARM SA1100 CPUs
   /lib
Architecture specific library files
 /avr32
Files generic to AVR32 architecture
   /cpu
CPU specific files
   /lib
Architecture specific library files
 /blackfin
Files generic to Analog Devices Blackfin architecture
   /cpu
CPU specific files
   /lib
Architecture specific library files
 /x86 Files generic to x86 architecture
   /cpu
CPU specific files
   /lib
Architecture specific library files
 /m68k
Files generic to m68k architecture
   /cpu
CPU specific files
     /mcf52x2
Files specific to Freescale ColdFire MCF52x2 CPUs
     /mcf5227x
Files specific to Freescale ColdFire MCF5227x CPUs
     /mcf532x
Files specific to Freescale ColdFire MCF5329 CPUs
     /mcf5445x
Files specific to Freescale ColdFire MCF5445x CPUs
     /mcf547x_8x
Files specific to Freescale ColdFire MCF547x_8x CPUs
   /lib
Architecture specific library files
 /microblaze
Files generic to microblaze architecture
   /cpu
CPU specific files
   /lib
Architecture specific library files
 /mips
Files generic to MIPS architecture
   /cpu
CPU specific files
     /mips32
Files specific to MIPS32 CPUs
     /xburst
Files specific to Ingenic XBurst CPUs
   /lib
Architecture specific library files
 /nds32
Files generic to NDS32 architecture
   /cpu
CPU specific files
     /n1213
Files specific to Andes Technology N1213 CPUs
   /lib
Architecture specific library files
 /nios2
Files generic to Altera NIOS2 architecture
   /cpu
CPU specific files
   /lib
Architecture specific library files
 /powerpc
Files generic to PowerPC architecture
   /cpu
CPU specific files
     /74xx_7xx
Files specific to Freescale MPC74xx and 7xx CPUs
     /mpc5xx
Files specific to Freescale MPC5xx CPUs
     /mpc5xxx
Files specific to Freescale MPC5xxx CPUs
     /mpc8xx
Files specific to Freescale MPC8xx CPUs
     /mpc8220
Files specific to Freescale MPC8220 CPUs
     /mpc824x
Files specific to Freescale MPC824x CPUs
     /mpc8260
Files specific to Freescale MPC8260 CPUs
     /mpc85xx
Files specific to Freescale MPC85xx CPUs
     /ppc4xx
Files specific to AMCC PowerPC 4xx CPUs
   /lib
Architecture specific library files
 /sh Files generic to SH architecture
   /cpu
CPU specific files
     /sh2
Files specific to sh2 CPUs
     /sh3
Files specific to sh3 CPUs
     /sh4
Files specific to sh4 CPUs
   /lib
Architecture specific library files
 /sparc
Files generic to SPARC architecture
   /cpu
CPU specific files
     /leon2
Files specific to Gaisler LEON2 SPARC CPU
     /leon3
Files specific to Gaisler LEON3 SPARC CPU
   /lib
Architecture specific library files
/api Machine/arch independent API for external apps
/board
Board dependent files
/common
Misc architecture independent functions
/disk Code for disk drive partition handling
/doc Documentation (don't expect too much)
/drivers
Commonly used device drivers
/examples
Example code for standalone applications, etc.
/fs Filesystem code (cramfs, ext2, jffs2, etc.)
/include
Header Files
/lib Files generic to all architectures
 /libfdt
Library files to support flattened device trees
 /lzma
Library files to support LZMA decompression
 /lzo Library files to support LZO decompression
/net Networking code
/post Power On Self Test
/rtc Real Time Clock drivers
/tools
Tools to build S-Record or U-Boot images, etc.

    2. 启动过程
    作为一个Bootloader,无论兼容了多少种硬件,增加了多少种实用的功能。最基本的启动流程仍然会是那些(暂不考虑CP的启动),硬件设备初始化,内存初始化,加载stage2的代码等等等等。
    U-Boot的启动也分成stage1和stage2,stage1使用汇编语言编写,stage2使用C语言编写。

    2.1 stage1
    在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

_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

.balignl 16,0xdeadbeef

1. CPU进入SVC模式
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0

2. 关闭看门狗
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]

        3. 关中断
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
 
4. 初始化系统时钟
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]

        5. cpu_init_crit函数
        主要完成了两个工作:
        首先使ICache and Dcache,TLBs中早期内容失效,再设置p15 control register c1,关闭MMU,Dcache,但是打开了Icache和Fault checking,(要求mmu和Dcache是必须要关闭的,而Icache可以打开可以关闭);
        其次建立对SDRAM的访问时序。

        6. 建立堆栈,调用主板初始化
 
        7. 复制代码,清除bss段,跳转运行代码
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
#ifdef CONFIG_NAND_SPL
ldr     r0, _nand_boot_ofs
mov pc, r0

_nand_boot_ofs:
.word nand_boot
#else
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_ofs:
.word board_init_r - _start
#endif

    2.2 stage2
    第二阶段完成本阶段使用的硬件设备、指定启动参数地址,开启中断,运行命令
    在Board.c文件中的board_init_r函数,根据用户的配置,进行各种初始化之后,打开中断,运行
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop();
}
    这个就是在标准输入设备中接受命令,然后分析、查找和执行。
    去掉所有无关紧要的宏和代码,main_loop()函数如下:
void main_loop()
{
   static char lastcommand[CFG_CBSIZE] = { 0, };
   int len;
   int rc = 1;
   int flag;
   char *s;
   int bootdelay;
 
   s = getenv ("bootdelay");   //自动启动内核等待延时
   bootdelay =
s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

   s = getenv ("bootcmd");  //取得环境中设置的启动命令行
   if (bootdelay != -1 && s && !abortboot(bootdelay)){
    run_command_list(s, -1, 0);
   }

   for (;;) {
len = readline(CFG_PROMPT);
//读取键入的命令行到console_buffer

        flag = 0;       /* assume no special flags for now */
        if (len > 0)
            strcpy (lastcommand, console_buffer);
//拷贝命令行到lastcommand.
        else if (len == 0)
            flag |= CMD_FLAG_REPEAT;

                 if (len == -1)
            puts ("\n");
        else
            rc = run_command (lastcommand, flag); //执行这个命令行。

        if (rc <= 0) {
            /* invalid command or not repeatable, forget it */
            lastcommand[0] = 0;
   }
}
    在上面的main_loop函数中,通常在开发完成的阶段都会设置一个bootcmd的环境变量,然后将延时bootdelay设置成0,这样当u-boot跑到这里的时候就不会因为用户按下了任意键就进入了命令行模式,可以直接运行bootcmd的命令来直接加载kernel的Image然后移交控制权。如果进入了命令行模式,我们也可以手动输入命令来启动系统,输入的命令也是基本和bootcmd一样。

    3. U-Boot和内核的关系
    U-Boot作为bootloader,具备多种引导内核启动的方式.常用的go和bootm命令直接引导内核Image启动.
    go命令的解析函数是do_go()函数.
    bootm命令的解析函数是do_bootm()函数. 这个函数专门用来引导各种操作系统Image,引导Linux时调用do_bootm_linux()函数

static boot_os_fn *boot_os[] = {
#ifdef CONFIG_BOOTM_LINUX
[IH_OS_LINUX] = do_bootm_linux,
#endif
#ifdef CONFIG_BOOTM_NETBSD
[IH_OS_NETBSD] = do_bootm_netbsd,
#endif
#ifdef CONFIG_LYNXKDI
[IH_OS_LYNXOS] = do_bootm_lynxkdi,
#endif
#ifdef CONFIG_BOOTM_RTEMS
[IH_OS_RTEMS] = do_bootm_rtems,
#endif
#if defined(CONFIG_BOOTM_OSE)
[IH_OS_OSE] = do_bootm_ose,
#endif
#if defined(CONFIG_CMD_ELF)
[IH_OS_VXWORKS] = do_bootm_vxworks,
[IH_OS_QNX] = do_bootm_qnxelf,
#endif
#ifdef CONFIG_INTEGRITY
[IH_OS_INTEGRITY] = do_bootm_integrity,
#endif
};

int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
/* No need for those on ARM */
if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
return -1;

if (flag & BOOTM_STATE_OS_PREP) {
boot_prep_linux(images);
return 0;
}

if (flag & BOOTM_STATE_OS_GO) {
boot_jump_linux(images);
return 0;
}

boot_prep_linux(images);
boot_jump_linux(images);
return 0;
}
do_bootm_linux函数最后调用了boot_jump_linux,这个函数最后一句正是kernel_entry(0, machid, r2);

    4. 其他
    U-Boot为了兼容各种CPU,各种操作系统,复杂度确实是比较高的,我也仅仅理解一个皮毛。另外,这里仅仅考虑系统只有AP,但现在越来越多的系统除了AP之外还有CP了,这样的硬件结构,bootloader中也是需要变化的。

抱歉!评论已关闭.