u-boot 5、源代码分析

u-boot启动过程:通常有两个阶段。第一阶段使用汇编来实现,它完成一些依赖于CPU体系结构的初始化,并调用第二阶段的代码;第二阶段则通常使用c语言来实现,这样可以实现更复杂的功能,而且代码会有更好的可读性和可移植性。

第一阶段:

1.1、上电后CPU为SVC模式

.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

 

reset:

         /*

          * set the cpu to SVC32 mode

          */

         mrs  r0, cpsr

         bic    r0, r0, #0x1f

         orr    r0, r0, #0xd3

         msr  cpsr,r0

 

1.2、调用cpu_init_crit

         /*the mask ROM code should have PLL and others stable */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

         bl      cpu_init_crit

#endif


cpu_init_crit:

         /*

          * Invalidate L1 I/D

          */

         mov r0, #0                          @set up for MCR

         mcr  p15, 0, r0, c8, c7, 0 @ invalidate TLBs

         mcr  p15, 0, r0, c7, c5, 0 @ invalidate icache

 

         /*

          * disable MMU stuff and caches

          */

         mrc  p15, 0, r0, c1, c0, 0

         bic    r0, r0, #0x00002000         @ clear bits 13 (--V-)

         bic    r0, r0, #0x00000007         @ clear bits 2:0 (-CAM)

         orr    r0, r0, #0x00000002         @ set bit 1 (--A-) Align

         orr    r0, r0, #0x00000800         @ set bit 12 (Z---) BTB

         mcr  p15, 0, r0, c1, c0, 0

 

         /*

          * Jump to board specific initialization...

          * The Mask ROM will have already initialized

          * basic memory. Go here to bump up clock rateand handle

          * wake up conditions.

          */

         mov ip, lr                    @persevere link reg across call

         bl      lowlevel_init              @go setup pll,mux,memory

         mov lr, ip                    @restore link

         mov pc, lr                            @back to my caller

 

1.3、调用lowlevel_init

这个函数在board\freescale\mx6q_sabresd\lowlevel_init.S文件中。

.globl lowlevel_init

lowlevel_init:

         inv_dcache  /* invalidate the D-CACHE */

         init_l2cc    /*Disable L2Cache*/

         init_aips

         init_clock

         movpc, lr

这里并没有memory的初始化,因为在u-boot.lds文件中已经知道最开始执行的是board/freescale/mx6q_sabresd/flash_header.s,这里的代码就是对Memory的初始化。

 

1.4、代码的搬移

 如果当前代码不在链接指定的地址上,则需要把u-boot从当前位置拷贝到RAM指定位置中;

#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  stack_setup

 

         ldr    r2, _armboot_start

         ldr    r3, _bss_start

         sub   r2, r3, r2           @r2 <- size of armboot

         add  r2, r0, r2           @r2 <- source endaddress

 

copy_loop:                                    @copy 32 bytes at a time

         ldmia        r0!, {r3 - r10}             @ copy from source address [r0]

         stmia        r1!, {r3 - r10}             @ copy to   targetaddress [r1]

         cmp r0, r2                           @until source end addreee [r2]

         ble    copy_loop

#endif       /*CONFIG_SKIP_RELOCATE_UBOOT */

 

1.5、栈空间的设置

stack_setup:

         ldr    r0, _TEXT_BASE                 @ upper 128 KiB: relocated uboot

         sub   r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area

         sub   r0, r0, #CONFIG_SYS_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

         and  sp, sp, #~7                 @8 byte alinged for (ldr/str)d

这段代码是用来分配各个栈空间的。包括分配动态内存区,全局数据区,IRQFIQ的栈空间,堆栈是进入C函数前必须初始化。

 

1.6、BSS段的清零

clear_bss:

         ldr    r0, _bss_start           @ find start of bss segment

         ldr    r1, _bss_end             @stop here

         mov r2, #0x00000000               @clear value

clbss_l:

         str    r2, [r0]               @clear BSS location

         cmp r0, r1                           @are we at the end yet

         add  r0, r0, #4           @increment clear index pointer

         bne  clbss_l                        @ keep clearing till at end

 

1.7、跳到c代码的入口函数

         ldr    pc, _start_armboot          @ jump to C code

_start_armboot: .word start_armboot

这个C入口的函数,是在lib_arm\board.c文件中。它标志着后续将全面启动C语言程序,同时它也是整个u-boot的主函数。



第二阶段功能:start_armboot(lib_arm\board.c)

初始化本阶段要使用到的硬件设备。
检测系统内存映射(memory map)。
将内核映像和根文件系统映像从Flash上读到RAM空间中。
为内核设置启动参数。
调用内核。

2.1、为gd与bd分配空间

         /*Pointer is writable since we allocated a register for it */

         gd= (gd_t*)(_armboot_start - CONFIG_SYS_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));

 

         gd->flags|= GD_FLG_RELOC;

 

2.2、执行初始化列表函数

         for(init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

                   if((*init_fnc_ptr)() != 0) {

                            hang();

                   }

         }

init_fnc_t *init_sequence[] = {

#if defined(CONFIG_ARCH_CPU_INIT)

         arch_cpu_init,          /* basic arch cpu dependent setup */

#endif

         board_init,                 /* basic board dependent setup*/

#if defined(CONFIG_USE_IRQ)

         interrupt_init,           /* set up exceptions */

#endif

         timer_init,                 /* initialize timer */

         env_init,            /* initialize environment */

         init_baudrate,          /* initialze baudrate settings */

         serial_init,                 /* serial communications setup*/

         console_init_f,          /* stage 1 init of console */

         display_banner,                 /* say that we are here */

#if defined(CONFIG_DISPLAY_CPUINFO)

         print_cpuinfo,           /* display cpu info (and speed) */

#endif

#if defined(CONFIG_DISPLAY_BOARDINFO)

         checkboard,              /* display board info */

#endif

#if defined(CONFIG_HARD_I2C) ||defined(CONFIG_SOFT_I2C)

         init_func_i2c,

#endif

         dram_init,                  /* configure available RAMbanks */

#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)

         arm_pci_init,

#endif

         display_dram_config,

         NULL,

};

对于这里的初始化函数列表,我们需要注意的是:

board_init:

         /*board id for linux */

         gd->bd->bi_arch_number= MACH_TYPE_MX6Q_SABRESD;

 

         /*address of boot parameters */

         gd->bd->bi_boot_params= PHYS_SDRAM_1 + 0x100;

这两个都是最终要传给linux内核的

 

 

2.3、一部分外设的初始化

在第二阶段的代码中,需要注意的是我们系统镜像存储的外设,是否已经初始化。例如在我自制的板子中,使用的是MMC,对应的宏需要定义

#ifdef CONFIG_GENERIC_MMC

         puts("MMC:   ");

         mmc_initialize(gd->bd);

#endif

 

2.4、main_loop函数(common/main.c)

         for(;;) {

                   main_loop();

         }

整个u-boot的执行就进入等待用户输入命令,解析并执行命令的死循环中

 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值