初步了解UBOOT (2)

打开uboot的链接脚本 u-boot.lds , 内容如下:

SECTIONS
{
    . = 0x00000000;

    . = ALIGN(4);
    .text      :
    {
      cpu/arm920t/start.o   (.text)
      *(.text)
    }

    . = ALIGN(4);
    .rodata : { *(.rodata) }

    . = ALIGN(4);
    .data : { *(.data) }

    . = ALIGN(4);
    .got : { *(.got) }

    . = .;
    __u_boot_cmd_start = .;
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;

    . = ALIGN(4);
    __bss_start = .;
    .bss : { *(.bss) }
    _end = .;
}

从这里,可以看出start.o的代码段被链接在最前面,所以start.S会最先被执行,找到start.S,进行分析,则可以进一步了解Uboot的启动过程。

start.S的内容大概如下:

/*
 * the actual reset code
 */

reset:
    /*
     * set the cpu to SVC32 mode
     */
    mrs r0,cpsr
    bic r0,r0,#0x1f
    orr r0,r0,#0xd3
    msr cpsr,r0

/* turn off the watchdog */
...
# define pWTCON     0x53000000
# define INTMSK     0x4A000008  /* Interupt-Controller base addresses */
# define INTSUBMSK  0x4A00001C
# define CLKDIVN    0x4C000014  /* clock divisor register */

...
    /*
     * mask all IRQs by setting all bits in the INTMR - default
     */
    mov r1, #0xffffffff
    ldr r0, =INTMSK
    str r1, [r0]
...
    ldr r1, =0x3ff
    ldr r0, =INTSUBMSK
    str r1, [r0]

    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr r0, =CLKDIVN
    mov r1, #3
    str r1, [r0]

    /*
     * we do sys-critical inits only at reboot,
     * not when booting from ram!
     */

    bl  cpu_init_crit

...

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 end address         */

...

    /* 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    */

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

    ldr pc, _start_armboot

_start_armboot: .word start_armboot

从以上内容可以得出,uboot会做以下事情:
1.设置CPU进入管理模式
2.关闭看门口
3.关中断
4.设置系统时钟
5.与CPU有关的相关初始化 cpu_init_crit
6.将uboot复制到SDRAM上
7.设置栈
8.清BSS段
9.调用start_armboot

至此,Uboot的第一阶段启动就到这里。
而从调用C函数start_armboot之后就进入uboot的第二阶段。

C函数start_armboot大致内容如下:


void start_armboot (void)
{
    ...

    /* 以下是初始化本阶段要使用到的硬件设备 */
    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }

    /* configure available FLASH banks */
    size = flash_init ();
    display_flash_config (size);

    ...

    /* armboot_start is defined in the board-specific linker script */
    mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

    ... 

    nand_init();        /* go init the NAND */

    ...

    /* initialize environment */
    env_relocate ();

    /* IP Address */
    gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

    ...

    /* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
    cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif

    ...

    /* main_loop() can return to retry autoboot, if so just run it again. */
    for (;;) {
        main_loop ();
    }
}

从start_armboot的代码分析可知道uboot进入第二阶段,首先会进行与本阶段相关硬件设备的初始化,执行如下代码可以实现:

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();
        }
    }
其中init_sequence是一个指针数组,它比较重要的内容为:

init_fnc_t *init_sequence[] = {
    cpu_init,       /* basic cpu dependent setup */
    board_init,     /* basic board dependent setup */
    interrupt_init,     /* set up exceptions */
    env_init,       /* initialize environment */
    serial_init,        /* serial communications setup */
    dram_init,      /* configure available RAM banks */
    ...
};

其中很重要的两条信息

    /* arch number of SMDK2440-Board */
        gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
    }

    /* adress of boot parameters */
    gd->bd->bi_boot_params = 0x30000100;

是在board_init函数中实现的。这两个参数会传递给内核,告诉内核该开发板的机器ID,还有告诉内核另一些要传给内核的参数所存放的地址位于哪。

env_init函数进行Uboot环境变量的初始化。设置Uboot命令模式中的环境变量的默认值。Uboot环境变量如下图所示:

这里写图片描述

serial_init函数则是串口的初始化,以用于用户与Uboot的交互。

dram_init函数则是设置SDRAM的起始地址和大小

    gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
    gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

对于本开发板来说,
PHYS_SDRAM_1 = 0x30000000 /* SDRAM Bank #1 */
PHYS_SDRAM_1_SIZE = 0x04000000 /* 64 MB */

接下来在start_armboot函数还会初始化 NOR_FLASH 还有 NAND_FLASH 的一些参数等等,接着就会进入main_loop ()函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值