am335x嵌入式开发-bootloader启动流程

来源:互联网 发布:php 检验日期格式 编辑:程序博客网 时间:2024/06/05 08:38

bootloader 版本


u-boot-2012.10-psp05.06.00.00

bootloader 启动流程


概述


am335x bootloader整体分为三个部分:rom_code,SPL(Secondary Program Loader)及u-boot。在分析流程之前,先大概浏览以下源代码的结构:

u-boot 源码组织结构

子目录 目录内容 api 存放uboot提供的接口函数 arch 与体系结构相关的代码 board 根据不同开发板所定制的代码 common 通用的代码,涵盖各个方面,以对命令行的处理为主 disk 磁盘分区相关代码 doc 文档,readme drivers 驱动相关代码,每种类型的设备驱动占用一个子目录 examples 示例程序 fs 文件系统,支持嵌入式开发板常见的文件系统 include 头文件,以通用的头文件为主 lib 通用库文件 nand_spl nand存储器相关的代码 net 网络相关的代码,小型的协议栈 onenand_ipl onenand存储器启动的代码 post 上电自检程序 tools 辅助功能程序,用于制作uboot镜像等

需要重点关注的源码

文件名称 路径 u-boot-spl.lds arch\arm\cpu\armv7\omap-common start.S arch\arm\cpu\armv7/ lowlevel_init.S \arch\arm\cpu\armv7\ti81xx/ spl.c \common board.c \arch\arm\cpu\armv7\am33xx am335x_evm.h \include\configs\


bootloader的整体运行流程为:
1. 芯片上电或复位
2. rom_code 运行,从外设或外部存储器中加载二级bootloader(SPL)到内存中运行
3. SPL做CPU和外设的初始化(主要是DDR)并将u-boot加载到内存运行
4. u-boot 继续做其它板载或外设的初始化并加载linux内核
5. linux内核开始启动


rom_code


am335x 系列soc在芯片内部的flash中固化了一段代码,称为rom_code,在芯片上电或复位后首先执行芯片内部固化的这段代码,这段代码的作用为引导二级bootloader(SPL)的镜像文件到内部sram中运行。

  • am335x引导模式

    所谓am335x的引导模式其实就是二级bootloader(SPL)镜像的读取方式,刚才提到rom_code的作用是将二级 bootloader加载到内部的sram运行,那么rom_code从什么地方以及通过什么样的方式获取SPL的可执行镜像文件呢?这就决定于am335x的引导模式了。

    am335x支持两大类的引导模式,分别为memory模式及外设模式。memory模式可以从NAND flash、NOR flash及eeprom中读取SPL镜像文件并加载到内部sram中运行。外设模式是指rom_code可以通过芯片的一些通信接口(比如EMAC、Serial、USB)获取SPL镜像文件并加载到内部sram中运行。

    am335x的引导模式取决于上电或复位时芯片一组引脚的状态,称作SYSBOOT[15:0]共16位。其中SYSBOOT[4:0]决定了芯片的引导顺序。

    这里写图片描述

    上图中可以看出当SYSBOOT[4:0]为00010时,芯片会首先从UART0开始引导,如果失败会尝试SPI0、NAND、NANDI2C。

  • rom_code的运行流程

    参考am335x的芯片技术手册,可以知道rome_code的执行流程如下:

    这里写图片描述

    下面分析rom_code的执行流程:

    1. 芯片复位后PC指针首先跳转到0x20000地址开始执行rom_code并做芯片的简单初始化
    2. rom_code根据SYSBOOT的配置生成引导设备列表
    3. 查看当前的引导类型是memory模式还是外设模式,并通过相应的接口或地址读取SPL
    4. SPL image读取成功,执行SPL镜像,SPL开始运行
    5. SPL image读取失败,尝试启动列表中的下一个外设或接口
    6. 若所有外设都没有正确读取到SPL image,则进入死循环(dead loop)等待看门狗复位
    关于rom_code的运行,有一些重要的地址需要明确,如下表所示: addr 说明 0x20000 rom_code的运行起始地址 0x402F0400 SPL镜像在内部sram中的加载地址,也是内部ram的起始地址


    am335x 内部rom和内部ram的结构如下:

    这里写图片描述

    这里写图片描述


SPL(Secondary Program Loader)


  • SPL的作用

    SPL是紧接着rom_code的第二级bootloader,主要负责板载的部分初始化、加载及运行u-boot

  • SPL运行的起始点

    SPL在芯片的内部sram中运行,那么它是从哪儿开始运行的呢?这需要查看spl在链接的时候的链接文件
    u-boot-spl.lds,下面是 u-boot-spl.lds的文件内容:

# 定义内部sram区块MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\ # 这个定义在/include/configs/am335x_evm.h        LENGTH = CONFIG_SPL_MAX_SIZE }# 定义外部sdram区块       MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \        LENGTH = CONFIG_SPL_BSS_MAX_SIZE }OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)# 定义入口为_startENTRY(_start)SECTIONS{    .text      :    {        __start = .;        arch/arm/cpu/armv7/start.o  (.text) # 首先被执行的地方        *(.text*)    } >.sram # 将代码段搬移到内部sram运行    . = ALIGN(4);    .rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram    . = ALIGN(4);    .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram    . = ALIGN(4);    __image_copy_end = .;    _end = .;    .bss :    {        . = ALIGN(4);        __bss_start = .;        *(.bss*)        . = ALIGN(4);        __bss_end__ = .;    } >.sdram}


上述文件中 ENTRY(_start) 定义了SPL镜像的入口符号为start,它所存在的位置在arch/arm/cpu/armv7/start.o (.text) 中,而start.o是由start.S编译得到的,所以SPL的入口文件为arch/arm/cpu/armv7/start.S,另外SPL执行的地址由 CONFIG_SPL_TEXT_BASE定义得到的,我们看一下位于/include/configs/am335x_evm.h中的定义:

/* Defines for SPL */#define CONFIG_SPL#define CONFIG_SPL_FRAMEWORK#define CONFIG_SPL_TEXT_BASE        0x402F0400 // 定义spl的入口地址#define CONFIG_SPL_MAX_SIZE     (101 * 1024)#define CONFIG_SPL_STACK        CONFIG_SYS_INIT_SP_ADDR#define CONFIG_SPL_LDSCRIPT     "$(CPUDIR)/omap-common/u-boot-spl.lds" // 定义spl的链接文件#define CONFIG_SPL_BSS_START_ADDR   0x80000000#define CONFIG_SPL_BSS_MAX_SIZE     0x80000     /* 512 KB */
  • SPL执行流程
    1. Start.S: bl  lowlevel_init    2. lowlevel_init.S::lowlevel_init  bl s_init    3. arch/arm/cpu/armv7/am33xx/board.c::s_init    • 关闭看门狗    • 初始化PLL    • 初始化控制台串口    • 初始化外设pinmux    • 初始化DDR    4. Start.S: bl board_init_f    5. arch/arm/lib/board::board_init_f    • 初始化堆栈    • 清零bss段    • call board_init_r    6. common/spl/spl.c:: board_init_r    • 设置timer    • call board_init    7. arch/arm/cpu/armv7/am33xx/board.c::board_init    • i2c_init    • Lcd_Init    • gpmc_init    8. common/spl/spl.c:: 继续初始化    • 根据当前的启动设备,加载u-boot到DDR    • 运行并将控制权交给 u-boot    • PC跳转到0x80800000(CONFIG_SYS_TEXT_BASE)执行u-boot  

  • u-boot 执行流程
    0. u-boot的起始点也是start.S    1. Start.S: bl  lowlevel_init    2. lowlevel_init.S::lowlevel_init  bl s_init    3. arch/arm/cpu/armv7/am33xx/board.c::s_init    • 关闭看门狗    • 初始化PLL    • 初始化控制台串口    • 初始化外设pinmux    • 初始化DDR    4. Start.S: bl board_init_f    5. arch/arm/lib/board.C::board_init_f    • 初始化堆栈    • 清零bss段    • call board_init_r    6. arch/arm/lib/board.C::board_init_r    • call board_init    7. \arch\arm\cpu\armv7\am33xx\board.c::board_init    • i2c_init    • lcd_init    • gpmc_init    • dcache_enable    8. arch/arm/lib/board.C::board_init_r    • serial_initialize    • mem_malloc_init    • flash_init    • nand_init    • mmc_initialize    • env_relocate    • console_init_r    • interrupt_init    • enable_interrupts    • eth_initialize    • reset_phy    9. common/main.c::main_loop    • 解析命令,执行命令,boot the linux kernel
1 0
原创粉丝点击