FSL Imx53 启动流程分析

IMx53上电后,进入的是其内部的Memory,从iMx53RM.pdf  Chapter 2中可以查看到System Memory Map图如下:

 

从片内地址的0x0000_00000x0000_FFFF64KBoot Rom的空间,其固化有Boot CodeIMx53在硬件复位后会强制Arm内核从Boot Rom启动,运行Boot Code

       Boot Code会根据BOOT_MODE[1:0]的寄存器值、eFUSEs状态和GPIO Setting来完成从不同的boot devices启动,Serial Downloader from UART or USBDevice Configuration DataDigital signature based High Assurance BootBoot Devices包括包括NOR FLASHNAND FLASHOneNAND FLASHSD/MMCParmllel ATA/Serial ATA HDDSerial ROM devices(EEPROM)

       BOOT_MODE[1:0]对应PIN脚为C18B20BOOT_MODE的值会在RESET复位的上升沿进行一次采样(仅此一次),并保存在BOOT_MODE寄存器中,之后不论PIN脚电平的变化,均不会改变BOOT_MODE寄存器的值。BOOT_MODE的定义如下图所示:

       BOOT_MODE[1:0]0b00时,选择Internal Boot模式启动,在此模式下,启动设备和参数的选择根据BT_FUSE_SELeFUSEsGPIO Setting来选择启动的设备和参数。当BT_FUSE_SEL1(fuse is blown)boot参数是由eFUSEs决定的,它是第一次烧录时选择的devices和参数的保存值;当BT_FUSE_SEL0(fuse is unblown),此时eFUSEs的部分值将被GPIO pin的状态来覆盖,从而选择不同的devices和参数进行启动。GPIO pin的定义及覆盖的eFUSEs值见下图:

 

        

由于这些GPIO在产品开发时会被使用,飞思卡尔建议Internal Boot模式启动的参数由eFUSEs来决定,只是保留GPIO这种模式用作开发和测试时使用。

       BOOT_MODE[1:0]0b01,保留!

       BOOT_MODE[1:0]0b10,选择Boot From FUSES模式启动,在此模式下,GPIO pin的状态将被忽略,直接选择eFUSEs的设置来进行启动。当BT_FUSE_SEL0时,说明boot devices还没有被烧录,将直接跳到Serial Downloader模式。当BT_FUSE_SEL1时,将按照eFUSEs的设置启动系统。一般选择此模式启动,如果BT_FUSE_SEL1,但是eFUSEs设置对应的设备又不存在时,系统也会自动跳转到Serial Downloader模式,并在重新抄录成功后,改变eFUSEs的值,从而避免硬件boot devices的更改而芯片已经烧录过无法更新eFUSEs的问题。

       BOOT_MODE[1:0]0b11,选择Serial Downloader模式启动。通过USB或者UART进行系统程序下载。

 

eFUSEs的说明见下表:

对应于devices及其参数的选择由BOOT_CFG来决定,在此不再赘述,仅列出通过ESDHC boot的参数如下:

U1       Uboot存放地址

Uboot是是运行完固化的Boot Code后,Boot Code会跳转到选定设备的指定地址去运行,以EMMC为例,见下图

起始的前0x200512BMBR,接着的是预留的Second Image TableBoot Image( uboot)应该放在0x400(1024)的地址,即烧写uboot的时候,就应该烧写在emmc主分区的1024位置,这也和烧录uboot的脚本“sudo dd if=./u-boot.bin of=./u-boot-no-padding.bin bs=1024 skip=1; sync”相对应。

 

2       Uboot启动

Uboot启动一般认为是由两个阶段来运行,一是汇编start.s运行阶段,二是由其他C语言完成的第二阶段,一下做简要分析。

 

2.1 第一阶段分析

第一阶段主要是start.s的运行,主要完成定义入口地址、设置异常向量、设置CPU的频率、初始化内存控制器、加载Uboot第二阶段代码代码到RAM、初始化堆栈、跳转到RAM运行第二阶段程序。按照规定的0x400存放这段代码,BOOT CODE会加载这段代码到内部RAM运行,根据不同的boot device,具体加载的偏移地址和加载程序范围如下图:

可见到,对于emmc来说,加载的偏移地址为0x400,大小为2Kbyte

通过make mx53_smd_android_config配置自己的板子,查看uboot-imx下的Makefile可知

mx53_smd_android_config            :unconfig

       $(MKCONFIG) $(@:_config=) arm arm_cortexa8 mx53_smd freescale mx53

2.1.1 链接文件u-boot.lds

在看链接文件之前,我们先看一下,生成的map文件如下(仅截取memory map一部分)

Memory Configuration

Name             Origin             Length             Attributes

*default*        0x00000000         0xffffffff

 

Linker script and memory map

                0x00000000                . = 0x0

                0x00000000                . = ALIGN (0x4)

 

.text           0x77800000    0x258a8

 board/freescale/mx53_mpvceo/flash_header.o(.text.flasheader)

 .text.flasheader

                0x77800000      0x5cc board/freescale/mx53_mpvceo/flash_header.o

 cpu/arm_cortexa8/start.o()

 *fill*         0x778005cc       0x14 00

 .text          0x778005e0      0x440 cpu/arm_cortexa8/start.o

                0x77800620                _end_vect

                0x77800628                _bss_start

                0x7780062c                _bss_end

                0x77800624                _armboot_start

                0x778005e0                _start

                0x77800960                v7_flush_dcache_all

 .data          0x77800a20        0x0 cpu/arm_cortexa8/start.o

 .bss           0x77800a20        0x0 cpu/arm_cortexa8/start.o

 .ARM.attributes

                0x77800a20       0x17 cpu/arm_cortexa8/start.o

 .debug_line    0x77800a37       0xbb cpu/arm_cortexa8/start.o

 .debug_info    0x77800af2       0x95 cpu/arm_cortexa8/start.o

 .debug_abbrev  0x77800b87       0x14 cpu/arm_cortexa8/start.o

 *fill*         0x77800b9b        0x5 00

 .debug_aranges

                0x77800ba0       0x20 cpu/arm_cortexa8/start.o

 .glue_7        0x77800bc0        0x0 cpu/arm_cortexa8/start.o

 .glue_7t       0x77800bc0        0x0 cpu/arm_cortexa8/start.o

 .vfp11_veneer  0x77800bc0        0x0 cpu/arm_cortexa8/start.o

 .v4_bx         0x77800bc0        0x0 cpu/arm_cortexa8/start.o

 board/freescale/mx53_mpvceo/libmx53_mpvceo.a(.text)

 .text          0x77800bc0     0x1a88 board/freescale/mx53_mpvceo/libmx53_mpvceo.a(mx53_mpvceo.o)

                0x77800c74                dram_init

                0x77800c40                get_board_id_from_fuse

                0x77800c1c                __iounmap

                0x77800c20                get_boot_device

                0x778018d4                i2c_failed_handle

                0x77802078                board_mmc_init

                                   ……(省略部分内容)

.text          0x77802648        0x0 board/freescale/mx53_mpvceo/libmx53_mpvceo.a(lowlevel_init.o)

 

下面再来看链接文件:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")设置输出文件是elf格式,32ARM指令,小端;

OUTPUT_ARCH(arm) 设置输出执行平台Arm

ENTRY(_start) 设置入口地址,在map中可知,其地址为0x778005e0

SECTIONS

{

       . = 0x00000000;目标代码段的起始地址;

       . = ALIGN(4);对齐为4字节;

       .text          :代码段,会看到在map中,其值为0x77800000,是由于其被config.mkTEXT_BASE重定向了,即其运行地址在0x77800000

       {

         /* WARNING - the following is hand-optimized to fit within      */

         /* the sector layout of our flash chips!    XXX FIXME XXX    */

         board/freescale/mx53_mpvceo/flash_header.o    (.text.flasheader)这个文件就是启动流程1里面,boot code会完成Device Configuration DataDCD);

         cpu/arm_cortexa8/start.o 运行地址在程序段0x778005e0,虽然其和flash_header.o运行地址在SDRAM中,但是其存放地址是在boot devices的起始地址,所以其均会被boot Code加载,并在start.s把代码拷贝到RAM中的0x77800000中,之后跳转到RAM运行,具体看start.s分析;

         board/freescale/mx53_mpvceo/libmx53_mpvceo.a    (.text)

         lib_arm/libarm.a          (.text)

         net/libnet.a                   (.text)

         drivers/mtd/libmtd.a           (.text)

         drivers/mmc/libmmc.a              (.text)

 

         . = DEFINED(env_offset) ? env_offset : .;

         common/env_embedded.o(.text)

 

         *(.text)

       }

 

       . = ALIGN(4);

       .rodata : { *(.rodata) } 只读data –常量;

 

       . = ALIGN(4);

       .data : { *(.data) } 变量初始化过的;

 

       . = ALIGN(4);

       .got : { *(.got) }

 

       . = .;

       __u_boot_cmd_start = .; Uboot cmd的存放位置;

       .u_boot_cmd : { *(.u_boot_cmd) }

       __u_boot_cmd_end = .;

 

       . = ALIGN(4);

       _end_of_copy = .; /* end_of ROM copy code here */

       __bss_start = .; 未初始化的变量,不用拷贝,未初始化本身就为0

       .bss : { *(.bss) }

       _end = .;

}

2.1.2 Start.s分析

.globl _start 定义全局变量_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

       ……

_TEXT_BASE:

       .word     TEXT_BASE

 

.globl _armboot_start

_armboot_start:

       .word _start 地址为0x778005e0

 

/*

 * These are defined in the board-specific linker script.

 */

.globl _bss_start

_bss_start:

       .word __bss_start 地址为0x778301b4

 

.globl _bss_end

_bss_end:

       .word _end

……

#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绝对地址地址为0x77800624

       ldr   r3, _bss_start绝对地址地址为0x778301b4,即拷贝程序大小为_armboot_start0x778301b4这段空间

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

       add r2, r0, r2              @ r2 <- source end address

 

copy_loop:                         @ copy 32 bytes at a time

       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

#endif    /* CONFIG_SKIP_RELOCATE_UBOOT */

 

       /* Set up the stack */

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

 

       /* Clear BSS (if any). Is below tx (watch load addr - need space) */

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

 

#ifdef CONFIG_ARCH_MMU

       bl board_mmu_init

#endif

       ldr   pc, _start_armboot    @ jump to C code

 

_start_armboot: .word start_armboot 跳转到C start_armboot启动。

2.2 第二阶段分析

lib_arm/board.c中的start_armboot是第二阶段开始的代码,其主要完成系统内核、中断、时钟、接口、设备包括FLASHDISPLAY、网络等的初始化,并进入命令循环,接收用户命令后完成相应的工作。

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

      初始化Global data的数据地址

      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;

              初始化序列

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

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

                     hang ();

                     }

              }

      

              ……

 

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

              for (;;) {

                     main_loop ();

              }

       main_loop中,会不断扫描输入,并根据输入做相应的设置,如果超出delay时间(3S),会自动运行bootcmdevn参数。那么对于从emmc启动的板子,bootcmd的参数为:

"loadaddr=0x70800000\0"

"rd_loadaddr=0x70D00000\0"              \

              "bootargs=console=ttymxc0 init=/init " \

"androidboot.console=ttymxc0 di1_primary calibration video=mxcdi0fb:720P60\0" \

              "bootcmd_SD=mmc read 1 ${loadaddr} 0x800 0x2000;" \

                     "mmc read 1 ${rd_loadaddr} 0x3000 0x300\0" \

              "bootcmd=run bootcmd_SD; bootm ${loadaddr} ${rd_loadaddr}\0"

 

mmc read addr blk cnt 意思是将blk开始的cntblock的内容读取到内存地址的addr处。Bootm addr 启动内存addr出的image文件。由此可以判定,uboot启动之后,将读取设备节点10x800block开始的0x2000block大小的内容到0x70800000地址。在uboot初始化fsl_esdhc_initialize时,ESDHC的初始化时按下面的数组顺序来进行的

struct fsl_esdhc_cfg esdhc_cfg[2] = {

       {MMC_SDHC1_BASE_ADDR, 1, 1},

       {MMC_SDHC3_BASE_ADDR, 1, 1},

}

SDHC3的位置放置的板载EMMCSD卡的位置在SDHC1的位置,所以节点1正好是板载EMMD的节点。而一个block的大小是512,那么0x800正好是1M的大小,也就是烧录kernel的位置。0x3000的位置正好是6M,即是uRamdisk的烧录位置。

$ dd if=$FILE of=/dev/mmcblk0 bs=512 seek=2048

$ dd if=$FILE of=/dev/mmcblk0 bs=6M seek=1

 因此,系统将会在加载完kernel运行后,加载uramdisk并运行

你可能感兴趣的:(u-boot)