Bootloader系列(三)UBoot解析

    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中也是需要变化的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值