u-boot 第一启动阶段简要分析

1. u-boot 整体启动流程 

bootloader是板子上电到linux系统加载之间的一段执行代码。分为两个启动阶段BL1,BL2。BL1主要用汇编语言编写,做一些初始化工作,并将自身从存储介质如flash拷贝到内存中,然后跳到BL2的c程序入口。BL2加载各个设备的驱动,并提供一个命令行的界面来提供各种操作,最终目的是为了加载linux内核。bootloader将启动参数传递给linux内核让其自举,它的使命也就完成了。下面是s3c6410的启动流程,非常经典。

u-boot 第一启动阶段简要分析_第1张图片

板子自上电开始启动流程供分为4步:

  1. iRom(片内Rom)做一些初始化工作
  2. iRom将flash 或者 SD中的bootloader的前4KB 代码搬移到 stepping stone中。然后这些代码执行bootloader的BL1(第一阶段)
  3. 第一阶段主要初始化系统时钟、uart、SDRAM。然后将存储介质上的整个bootloader代码搬移到SDRAM中,并跳转到BL2(第二阶段)执行
  4. 初始化系统环境为加载os做准备

本文分析的s3c2440启动流程稍有差异。s3c2440支持两种启动方式,NOR flash和NAND flash. 无论是哪种方式启动,板子在上电以后都是从 0x00000000 地址开始运行,但是它们的工作方式或者叫地址的空间映射是不同的。由于NOR flash支持随机存取,当使用它启动时,它的地址直接被映射为0x00000000, 那么就直接从NOR flash运行bootloader. 由于NAND flash不支持随机存取,不能直接运行程序。为了从其启动,s3c2440 配备了片内的4KB SRAM(stepping stone)。 当s3c2440从NAND Flash启动时,NAND flash的头4KB程序被自动的加载到片内的SRAM中运行。然后控制权交由bootloader执行。下面是这个过程的示意图。

u-boot 第一启动阶段简要分析_第2张图片

与s3c6410相比,s3c2440并没有iRom,u-boot的前4KB代码被自动加载到iRAM中运行。接下来就到了u-boot的执行流程了。

 

2. 两大启动阶段

U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下:

(1). 第一阶段的功能

 硬件设备初始化

 加载U-Boot第二阶段代码到RAM空间

 设置好栈

 跳转到第二阶段代码入口

(2). 第二阶段的功能

  初始化本阶段使用的硬件设备

  检测系统内存映射

  将内核从Flash读取到RAM中

  为内核设置启动参数

  调用内核

 

3. 第一阶段代码搬移分析

本文学习的是u-boot启动的第一阶段。主要涉及到两个文件 cpu/arm920t/start.S 和board/samsung/mini2440/lowlevel_init.S  硬件初始化工作都是寄存器的操作,这里重点分析u-boot将SDRAM初始化之后将自身搬移到内存中的代码。下面是u-boot从NOR flash将自身搬移到内存的代码。

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

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

要理解上面的代码先对几个地址要搞清楚。

.globl _start

_start:     

  b       start_code

_start为u-boot执行的开始标号。它的地址取决于当前u-boot在哪里执行。

 

_TEXT_BASE:

         .word        TEXT_BASE

那么去哪里找 TEXT_BASE 呢?它是在./board/samsung/mini2440/config.mk 定义的。如下:

所以如果此时 u-boot 是在内存中运行的话,adr r0, _start 读入的值为程序起始地址即 TEXT_BASE,如果不是在内存中运行,_start 为0,不等于 TEXT_BASE。由此判断当前u-boot是否在内存中,如果在跳转到stack_setup,否则继续往下运行。

 

 .globl _armboot_start

 _armboot_start:

     .word _start

_armboot_start 与 _start 的值是一致的。

 .globl _bss_start

  _bss_start:

     .word __bss_start

__bss_start 是在链接脚本 u-boot.lds 中定义的。是u-boot的BSS段的起始地址。

由于u-boot不在内存中,_start为0,_armboot也为0。_bss_start为BSS段的起始地址。那么它们两者之间的差值正好等于u-boot程序的大小(BSS段不会被编译到u-boot中)。那么接下来就可以进行拷贝了。

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

 

拷贝函数通过 ldmia stmia 完成u-boot代码从nor flash到SDRAM的拷贝。

     ldr pc, _start_armboot

 _start_armboot: .word start_armboot

此后将pc指针指向start_armboot。也就到了u-boot的第二启动阶段。这个下篇文章继续分析。

 

 

你可能感兴趣的:(u-boot 第一启动阶段简要分析)