u-boot启动流程分析

一、 存储器

  1. SDRAM
    同步动态随机存储器。同步时指工作需要时钟;动态是指需要不断刷新来保证数据不丢失;随机说明不是线性存储,而是由指定地址进行数据的读写。如CPU使用的外部内存,即内存条。
  2. SRAM
    Static Ram,是具有静态存取功能的内存,不需要刷电路就能保存存储的数据,比SDRAM速度快,一般用作高速缓冲存储器(Cache)。
  3. Norflash
    非易失性外部存储介质,支持芯片内执行(XIP)。它有地址总线,CPU可以直接从Norflash中取值,直接在Norflash中运行程序。
  4. Nandflash
    非易失性,虽然有数据总线,但没有地址总线,CPU不能够直接从发flash取值运行程序。常用于大量存储,类似硬盘。
二、 地址
1、概念
  • 链接地址:链接脚本里指定的内存地址,编译时指定代码运行时应该所处的内存地址,是绝对地址
  • 运行地址:当前代码实际运行时所处的地址,是相对地址(相对于当前程序开始运行时的内存地址)。
  • 加载地址:程序存储在flash中的地址。
2、 PIC与PDC
  • 位置无关码(PIC,position independent code):依赖于程序当前运行的PC值(程序计数器),进行相对跳转,与位置(内存地址)无关。不管代码加载到任意地址,都能正常执行。如:B、BL、MOV、ADR……
  • 位置有关码:不依赖当前的PC值,是绝对跳转,与位置(内存地址)相关。程序执行时的运行地址和编译链接时给定的链接地址必须相同,才能正常运行。如:LDR PC,=LABEL(LDR伪指令)……
  • 总结:
    • 正常情况下,链接地址==运行地址,此时,程序肯定能正常运行。
    • 当链接地址!=运行地址时,程序运行也不一定出错。如果是位置有关码必然会出错;要是位置无关码便可正常运行,u-boot第一阶段指令能够正常执行的原因就在于此。

三、SDRAM、Norflash、Nandflash地址分配

如图所示,是存储器的地址分配图,总共有8个BANK和一个4KB大小的SRAM。

  • SDRAM:只能够接在BANK6和BANK7(接片选线nGCS6、nGCS7)。
  • Norflash:接在nGCS0上,选择BANK0,地址范围从0x0开始,上电时可以直接取0x0地址中的指令执行。
  • Nandflash:
    • 以页为单位读写,要先写命令,再给地址,才能读到NAND数据。Nandflash接在Nandflash控制器上而不是系统总线上,所以没有在8个BANK中分配地址。
    • Nandfalsh控制器有个特殊功能,系统上电后,可以将Nandflash的前4KB引导程序搬移到SRAM内部。此时SRAM已经映射到了BANK0的0x0地址处,CPU对0x0~0x1000地址进行操作,实际上是在操作SRAM。
  • 不管是Norflash还是Nandflash启动,ARM都是从0x0地址开始执行。在代码小于4KB,当做单片机裸跑程序的时候,就不需要进行代码的搬移等操作了。
    内存分布

四、u-boot总体启动流程

总共有两个阶段,第一阶段执行start.s汇编代码,最终会跳转到第二阶段C代码入口继续执行。

第一阶段:
  • 硬件设备初始化
  • 加载u-boot第二阶段代码到RAM空间
  • 设置好栈
  • 跳转到第二阶段代码入口
第二阶段:
  • 初始化本阶段使用的硬件设备
  • 检测系统内存映射
  • 将内核从Flash读取到RAM中
  • 为内核设置启动参数
  • 调用内核
1、nand flash启动
  • 首先需要将一个正确的bootloader烧写到Nandflash的最低位置,即从0x0开始烧写。
  • 当从Nandflash启动时,硬件上将片内SRAM映射到nGCS0片选空间,即0x0位置,并自动将Nandflash的前4kB代码拷贝到CPU片内SRAM中(SRAM-cache),这个内部RAM称为Stepping stone(垫脚石、起步石)。然后,CPU从SRAM的0x0地址处获取第一条指令开始执行。
  • 网上很多人说是CPU自动将Nandflash的前4kB拷贝到片内SRAM中,其实不然,实际是由Nandflash控制器(控制状态机)完成的,CPU根本没参与。
2、 nor flash启动

norflash支持片上执行代码(XIP),只需将bootloader烧写到Norflash的开始地址,由于Norflash会被映射到0x0地址处(nGCS0),上电后CPU会从0x0开始执行,也就是在Norflash中执行u-boot第一阶段,直到跳转到SDRAM中,继续执行第二阶段,也就不需要SRAM辅助运行第一阶段代码了。

五、u-boot.lds分析

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")  
//指定输出可执行文件是elf格式。小端,32位ARM指令
OUTPUT_ARCH(arm)    //指定输出可执行文件的平台为ARM
ENTRY(_start)       //入口点(地址)为_start,在cpu/arm/start.S中定义
SECTIONS
{
/*指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。必须是编译器知道这个地址,通常都是修改此处来完成*/
    . = 0x00000000;         //从0x0位置开始

    . = ALIGN(4);           //代码四字节对齐
    .text :                 //这是程序存放的地方,代码段
    {
        arch/arm/cpu/arm1136_ambarella/start.o  (.text) //start.o被链接到代码段最前面
        *(.text)            //其余代码段
    }

    . = ALIGN(4);           //4字节对齐
    .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }  //指定只读数据段

    . = ALIGN(4);
    .data : { *(.data) }    //指定读、写数据段

    . = ALIGN(4);
    .got : { *(.got) }      //指定got段,got段是uboot自定义的一个段,非标准段

    . = .;
    __u_boot_cmd_start = .;     //把__u_boot_cmd_start赋值为当前位置,即起始位置
    .u_boot_cmd : { *(.u_boot_cmd) } //指定u_boot_cmd段,uboot把所有的uboot命令放在该段
    __u_boot_cmd_end = .;       //把__u_boot_cmd_end赋值为当前位置,即起结束位置

    . = ALIGN(4);
    __bss_start = .;            //把__bass_start赋值为当前位置,即bass段的开始位置
    .bss (NOLOAD) : { *(.bss) . = ALIGN(4); } //指定bass段,告诉加载器不要加载这个段,仅在执行域中才会有这段
    _end = .;                   //把_end赋值为当前位置,即bss段的结束位置
}
  • ENTRY(_start)表示入口地址,程序运行时第一个被执行到的指令的地址便为_start。ld有多种方式设置程序的入口地址,按如下顺序(编号越前,优先级越高):
    1、 ld命令行的-e选项
    2、 链接脚本的ENTRY(SYMBOL)命令
    3、 如果定义了start符号,使用start符号值
    4、 如果存在.text section,使用.text section的首地址
    5、 使用0地址

  • 指定了_start的链接地址为0x0,但编译后,查看System.map会发现,_start的链接地址不是.text的当前地址0x0,原因是编译的时候将其更新了。config.mk中有这么几行:

LDFLAGS += -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS)
ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(TEXT_BASE)
  • 可知,如果TEXT_BASE不为空,在链接时,ld命令会把参数-Ttext指定的地址TEXT_BASE赋给.text。所以指定链接地址的方式有两种:链接脚本u-boot.lds中指定、config.mk中使用ld命令设定,当同时使用时,以ld命令为准。

  • 最终,我们一般指定链接地址为SDRAM的起始地址,因为第二阶段代码会被搬移到SDRAM中执行,需要保证链接地址和运行地址的一致性。但是最初bootloader是被烧写到flash的0x0地址,ARM架构CPU也是从0x0地址取第一条指令执行,这样链接地址就与运行地址(0x0地址)不相等了,程序运行不会出错吗?

  • 这个困扰我很久的问题,其实在本文的第二部分已经解答了。Bootloader第一阶段代码的运行地址确实是0x0地址,与链接地址不相等,但实际上,程序可以正常运行,所以可以断定第一阶段代码都是位置无关码(PIC)。事实也是如此,所有的目标地址寻址都是使用当前PC值加减偏移量的方法(进行相对跳转),因此该阶段代码在任何地址处都可以正常运行。
    uboot内存映射
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值