23. 基于Cortex-A9 uboot代码启动分析

发布者:chenxiaohong68最新更新时间:2021-07-28 来源: eefocus关键字:Cortex-A9  uboot 手机看文章 扫描二维码
随时随地手机看文章

前言

我们在前面的arm系列课程,已经讲解了arm的架构、汇编指令、异常、常用外设的控制器驱动,那么我们已经具备开发arm系列产品的基本技能。


本篇给大家介绍一款比较常用的bootloader:uboot,通过uboot的介绍以及源代码的详细分析,让大家把之前所有ARM相关的知识点融会贯通起来。


一、uboot

1. 概念

U-Boot 是一个主要用于嵌入式系统的引导加载程序,可以支持多种不同的计算机系统结构,包括PPC、ARM、AVR32、MIPS、x86、68k、Nios与MicroBlaze。这也是一套在GNU通用公共许可证之下发布的自由软件。


U-Boot不仅仅支持嵌入式Linux系统的引导,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS, android嵌入式操作系统。其目前要支持的目标操作系统是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX, RTEMS, ARTOS, android。


2. uboot基本功能

U-Boot可支持的主要功能列表:

  • 系统引导支持NFS挂载、RAMDISK(压缩或非压缩)形式的根文件系统;支持NFS挂载、从FLASH中引导压缩或非压缩系统内核;

  • 基本辅助功能强大的操作系统接口功能;可灵活设置、传递多个关键参数给操作系统,适合系统在不同开发阶段的调试要求与产品发布,尤以Linux支持最为强劲;支持目标板环境参数多种存储方式,如FLASH、NVRAM、EEPROM;

  • CRC32校验可校验FLASH中内核、RAMDISK镜像文件是否完好;

  • 设备驱动串口、SDRAM、FLASH、以太网、LCD、NVRAM、EEPROM、键盘、USB、PCMCIA、PCI、RTC等驱动支持;

  • 上电自检功能SDRAM、FLASH大小自动检测;SDRAM故障检测;CPU型号。

3. 常用命令

uboot命令比较多,下面只列举网络启动要用到的命令:

命令含义
bootdelay执行自动启动(bootcmd中的命令)的等候秒数
baudrate串口控制台的波特率
netmask以太网的网络掩码
ethaddr以太网的MAC地址
bootfile默认的下载文件名
printenv打印Uboot环境变量
setenv设置Uboot环境变量
ipaddr本地的IP地址
serveripTFTP服务器端的IP地址
gateway以太网的网关
bootcmd自动启动时执行命令
bootargs传递给Linux内核的启动参数
bootm引导启动存储在内存中的程序映像。这些内存包括RAM和可以永久保存的Flash。

4. 配置参数举例

以下以网络下载内核、网络挂载nfs为例。


1)ubuntu环境

ubuntu ip:192.168.6.186

nfs配置:

配置文件如下:

/etc/exports


配置信息如下:

nfs


2)开发板设置

开发板ip:192.168.6.187

配置命令:


setenv ipaddr 192.168.6.187      ;板子的ip

setenv serverip 192.168.6.186    ;虚拟机的ip

setenv gatewayip 192.168.1.1     ;网关

saveenv                          ;保存配置


  • 加载内核和设备树

setenv bootcmd tftp 41000000 uImage;tftp 42000000 exynos4412-fs4412.dtb;bootm 41000000 - 42000000


bootcmd:uboot2启动之后,首先先执行找到这个参数,执行后面的命令。
从tftp服务器下载内核镜像uImage到地址41000000,设备树文件exynos4412-fs4412.dtb到42000000,并通过命令bootm加载启动内核。

  • 挂载nfs

setenv bootargs root=/dev/nfs nfsroot=192.168.6.186:/rootfs rw console=ttySAC2,115200 init=/linuxrc ip=192.168.6.187


挂载nfs文件系统,

  • root=/dev/nfs

  • nfsroot=192.168.6.186:/rootfs nfs服务器地址192.168.6.186,目录为/rootfs,

  • rw 文件系统操作权限为可续写

  • console=ttySAC2,115200 串口名称和波特率

  • init=/linuxrc 内核启动后运行的进程为linuxrc

  • ip=192.168.6.187 开发板地址

二、exynos-4412 Soc 启动顺序

要想了解exynos-4412的启动顺序,我们首先需要了解该soc的内存布局。

1. exynos-4412内存布局

通常一款soc的内存在厂家设计的时候就已经规定死了,对于使用者来说,我们无法改变。

memery map我们只关心和启动相关的一个地址,

  1. iROM 在soc内部,出厂时厂家固化了特定的程序,iROM中程序对应用户来说不可改变

  1. iRAM 在soc内部,速度较快,但空间不大

  1. DMC RAM控制器,位于SOC内部,用于驱动RAM,大容量的RAM都需要连接到该控制器

2. Booting Sequence

不同的厂家的启动顺序是不太一样的,本篇主要以三星的exynos-4412 soc为基础,讲解该基于该板子的uboot启动顺序。


根据上图,系统启动的大概顺序:

  • iROM在SOC内部,是一个64KB的ROM,他树池化一些系统启动必须的功能。比如:时钟、栈。

  • iROM负责从特殊的启动外设加载BL1的image到soc内部的256KB的SRAM中。启动的外设由操作按钮来决定的。根据不同按键的值,iROM将会对bl1 的image做不同的校验。

  • BL1初始化系统时钟和DRAM控制器,然后从启动外设加载OS image到DRAM中。根据启动按钮的值的不同,BL1会对OS做不同的校验。

  • 启动完成之后,BL1跳转到操作系统(kernel)。

iROM会根据OM 引脚的不同选择不同的启动设备,对应的OM寄存器需要提供对应的启动信息。


三、内核启动流程概述

1. 内核启动流程 概述

uboot启动流程
如上图所示:

  1. 设备上电之后,先执行iROM中的出厂代码,先进行必要硬件的初始化
    去执行uboot,

  2. 通常把kernel、设备树文件放到flash中

  3. 程序启动之后,往往先从flash启动,运行uboot

  4. 第一步:先进行硬件的初始化(svc模式栈、clock、内存、串口)
    第二步:自搬移:把uboot从flash中拷贝到RAM中,跳转到RAM中执行剩下的uboot代码
    第三步:把内核拷贝到RAM中,执行内核,把控制权交给内核。


2. 内核启动详细流程

开发板从上电到启动内核的过程

四、uboot启动流程代码详解

在三星的SoC中, 启动流程可以分为三个阶段BL0, BL1, BL2, BL3, 三星自己的手册对BL1的解释也不尽相同, 一种是将在iRAM中运行的程序都归结为BL1; 一种是将iRAM中三星加密的代码bl1.bin作为BL1, iRAM中剩余的部分作为BL2, 本文采用后者, 他们的主要分工如下:

  • BL0: ARM的起始地址都是0地址, 三星的芯片一般将0地址映射到iROM中, BL0就是指iROM中固化的启动代码, 主要负责加载BL1

  • BL1: 三星对于bootloader的加密代码bl1.bin, 要放在外设中uboot.bin的头上, 和一部分uboot.bin一起加载到iRAM中运行.

  • BL2: 从(nand/sd/usb)中拷贝的uboot.bin头最大14K到iRAM中代码中除去bl1.bin后剩余的部分, 负责设置CPU为SVC模式, 关闭MMU, 关闭中断, 关闭iCache, 关闭看门狗, 初始化DRAM,初始化时钟, 初始化串口, 设置栈, 校验BL2并将其搬移到DRAM高位地址, 重定位到DRAM中执行BL3

  • BL3:是指在代码重定向后在内存中执行的uboot的完整代码, 负责初始化外设,更新向量表, 清BSS, 准备内核启动参数, 加载并运行OS内核

可以借助下图理解这个流程

img

我们常说的uboot是一个两阶段bootloader,就是指上述的BL2和BL3. BL2主要做硬件直接相关的初始化,使用汇编编写;BL3主要为操作系统的运行准备环境,主要用C编写,这里以ARM平台为例分析其启动流程。下面是启动过程中主要涉及的文件


arch/arm/cpu/armv7/start.S

board/samsung/myboard/lowlevel_init.S

arch/arm/lib/crt0.S

arch/arm/lib/board.c

arch/samsung/myboard/myboard.c


1. BL2

BL2的主要文件和任务流程如下


arch/arm/cpu/armv7/start.S

1. 设置CPU为SVC模式

2. 关闭MMU

3. 关闭Cache

4. 跳转到lowlevel_init.S low_level_init

board/samsung/origen/lowlevel_init.S

5. 初始化时钟

6. 初始化内存

7. 初始化串口

8. 关闭看门狗

9. 跳转到crt0.S _main

arch/arm/lib/crt0.S

10. 设置栈

11. 初始化C运行环境

12. 调用board_init_f()

arch/arm/lib/board.c

13. board_init_f对全局信息GD结构体进行填充

arch/arm/lib/crt0.S

14. 代码重定位------------BL2的最后的工作, 执行完就进入DRAM执行BL2


2. lds文件

要想了解uboot整个项目的代码流程,必须首先了解链接脚本【链接脚本参考《7. 从0开始学ARM-GNU伪指令,lds使用》】。


该文件决定了uboot最终生成的镜像文件,各个段的布局。


uboot链接脚本如下:


u-boot-2013.01/arch/arm/cpu/u-boot.lds

文件内容:


26 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

 27 OUTPUT_ARCH(arm)

 28 ENTRY(_start)

 29 SECTIONS 30 {

 31     . = 0x00000000;

 32 

 33     . = ALIGN(4);

 34     .text :

 35     {

 36         __image_copy_start = .;

 37         CPUDIR/start.o (.text*)

 38         *(.text*)

 39     }

 40 

 41     . = ALIGN(4);

 42     .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

 43 

 44     . = ALIGN(4);

 45     .data : {

 46         *(.data*)

 47     }

 48 

 49     . = ALIGN(4);

 50 

 51     . = .;

 52 

 53     . = ALIGN(4);

 54     .u_boot_list : {

 55     #include

 56     }

 57 

 58     . = ALIGN(4);

 59 

 60     __image_copy_end = .;

 61 

 62     .rel.dyn : {

 63         __rel_dyn_start = .;

 64         *(.rel*)

 65         __rel_dyn_end = .;

 66     }

 67 

 68     .dynsym : {

 69         __dynsym_start = .;

 70         *(.dynsym)

 71     }

 72 

 73     _end = .;

 74 

 75     /*

 76      * Deprecated: this MMU section is used by pxa at present but

 77      * should not be used by new boards/CPUs.

 78      */

 79     . = ALIGN(4096);

 80     .mmutable : {

 81         *(.mmutable)

 82     }

 83 

 84     .bss __rel_dyn_start (OVERLAY) : {

 85         __bss_start = .;

 86         *(.bss*)

 87          . = ALIGN(4);

 88         __bss_end__ = .;

 89     }

 90 

 91     /DISCARD/ : { *(.dynstr*) }

 92     /DISCARD/ : { *(.dynamic*) }

 93     /DISCARD/ : { *(.plt*) }

 94     /DISCARD/ : { *(.interp*) }

 95     /DISCARD/ : { *(.gnu*) }

 96 }

 97


核心内容解释:


 27 OUTPUT_ARCH(arm)       :    该镜像运行在arm架构的硬件上 28 ENTRY(_start)          :    程序的入口是 _start 29 SECTIONS 30 {

 31  . = 0x00000000;      :   程序的链接地址,不是运行地址【uboot一定是位置无关码】 34     .text :

 35     {

 36         __image_copy_start = .;    : 宏对应整个程序编译好后首地址,自搬移代码的初始位置 37         CPUDIR/start.o (.text*)    : 第一个目标文件CPUDIR/start.o中的代码段 38         *(.text*)                  : 剩下的目标文件的代码段 39     }

 60     __image_copy_end = .;          : 自搬移代码的结束为止

BSS全局未初始化变量、全局初始化为0的变量所在的段:


 84     .bss __rel_dyn_start (OVERLAY) : {

 85         __bss_start = .;

 88         __bss_end__ = .;

 89     }


3. uboot启动代码流程概要

代码只分析到uboot命令行,函数main_loop()位置。

4. 启动代码详细分析

_start入口位于以下文件:


u-boot-2013.01/arch/arm/cpu/armv7/start.S

第一阶段:

第二阶段

第二阶段代码从_main开始:

以上代码详细解释,请结合B站视频同步学习。


五、uboot启动的几个关键知识点

如何判断第一条机器指令的位置?

链接脚本决定了内存的布局。


uboot链接脚本如下:


u-boot-2013.01/arch/arm/cpu/u-boot.lds

文件内容:


 28 ENTRY(_start)

 29 SECTIONS 30 {

 31     . = 0x00000000;

 32

uboot的入口是

链接地址是


uboot如何搬运代码?

代码位于:

u-boot-2013.01/arch/arm/cpu/armv7/start.S

搬移代码如下:


ENTRY(relocate_code)

mov r4, r0 /* save addr_sp */

mov r5, r1 /* save addr of gd */

mov r6, r2 /* save addr of destination */


adr r0, _start

cmp r0, r6

moveq r9, #0/* no relocation. relocation offset(r9) = 0 */

beq relocate_done /* skip relocation */

mov r1, r6 /* r1 <- scratch for copy_loop */

ldr r3, _image_copy_end_ofs

add r2, r0, r3 /* r2 <- source end address     */copy_loop:

ldmia r0!, {r9-r10}/* copy from source address [r0]    */

stmia r1!, {r9-r10}/* copy to   target address [r1]    */

cmp r0, r2 /* until source end address [r2]    */

blo copy_loop


详情参考第四章,第3节。


uboot中,如何判断此次开机是从断电状态开机还是从休眠状态启动的?

board/samsung/fs4412/lowlevel_init.S

代码如下:


 41   lowlevel_init:

 54     /* AFTR wakeup reset */

 55     ldr r2, =S5P_CHECK_DIDLE 56     cmp r1, r2 57     beq exit_wakeup 58 

 59     /* LPA wakeup reset */

 60     ldr r2, =S5P_CHECK_LPA 61     cmp r1, r2 62     beq exit_wakeup 63 

 64     /* Sleep wakeup reset */

 65     ldr r2, =S5P_CHECK_SLEEP 66     cmp r1, r2 67     beq wakeup_reset 112 wakeup_reset:

 113     bl system_clock_init 114     bl mem_ctrl_asm_init 115     bl tzpc_init 116 

 117 exit_wakeup:

 118     /* Load return address and jump to kernel */

[1] [2]
关键字:Cortex-A9  uboot 引用地址:23. 基于Cortex-A9 uboot代码启动分析

上一篇:13. 从0学ARM-Cortex-A9 RTC裸机程序编写
下一篇:15. 从0开始学ARM-位置无关码

推荐阅读最新更新时间:2024-11-04 13:09

ok6410如何从sdram中启动uboot 调试 这是一个猜想还没有验证
1在smdk6410.h中定义宏 //#define CONFIG_SKIP_LOWLEVEL_INIT 1 //#define CONFIG_SKIP_RELOCATE_UBOOT 1 2将编译的uboot.bin下载到text_base的地址 3准备好调试环境之后 指令 gp+地址运行sdram中的uboot
[单片机]
STM32启动文件startup_stm32f10x_hd.s的代码讲解
本文对STM32启动文件startup_stm32f10x_hd.s的代码进行讲解,此文件的代码在任何一个STM32F10x工程中都可以找到。 启动文件使用的ARM汇编指令汇总 Stack——栈 Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN= Stack_Mem SPACE Stack_Size __initial_sp 开辟栈的大小为 0X00000400(1KB),名字为 STACK, NOINIT 即不初始化,可读可写, 8(2^3)字节对齐。 栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部SRA
[单片机]
STM32<font color='red'>启动</font>文件startup_stm32f10x_hd.s的<font color='red'>代码</font>讲解
S3C2410启动代码详解(3)
;================================================================================ ; ENTRY 系统上电后经过一个b ResetHandler就跳转到此处来。在此完成一些相关的软硬件配置工作 1. 屏蔽所有中断,关看门狗。 2. 根据工作频率设置PLL寄存器 3. 初始化存储控制相关寄存器 4. 初始化各模式下的栈指针 5. 设置缺省中断处理函数 6. 将数据段拷贝到RAM中,将零初始化数据段清零 7. 跳转到C 语言Main入口函数中 ;===========================
[单片机]
STM32 启动代码分析详解
1、堆栈存储器 堆栈存储区是在片上存储器中的SRAM(或RAM)中由用户自行开辟的一片数据存储区域,并且堆栈区的大小可根据用户的需要任意指定(只要不超过SRAM或RAM的大小),而堆栈区的位置由编译器指定分配。 Cortex-M3/M4处理器的堆栈指针SP是“满递减,空递增”,呈现向下逆生长的特点。 堆栈区数据的存储特点是“先进后出,后进先出”。 这种特点是由堆栈指针的移动方式决定的,先入栈的数据对应的指针值比较大,后入栈的数据对应的指针值比较小,而出栈时堆栈指针的值是递增的,所以指针值大的数据当然后出栈。 堆栈的作用: 局部变量的存储、函数调用时函数或子程序间数据的传递(形参的保存,其实函数调用一旦结束被
[单片机]
mini2440使用uboot(详细)
使用的mini2440开发板的详细信息: kernel:linux-2.6.29-mini2440-20090708.tgz gcc:arm-linux-gcc-4.3.2.tgz uboot:bootloader.tgz(该压缩包内含有u-boot-1.1.6) roots:root_qtopia-64M.img 问题源于: (1)使用128M NAND Flash mini2440开发板的用户都知道,此时开发板附带的supervivi-64M和supervivi-128M都不再支持“空格”进入supervivi的menu菜单,而是改成了使用开发板上的k1~k6任何一个按键触发进入menu(而我需要空格键触发menu的方式)
[单片机]
arm启动代码详细分析
arm启动代码详细分析 所谓启动代码,就是处理器在启动的时候执行的一段代码,主要任务是初始化处理器模式,设置堆栈,初始化变量等等.由于以上的操作均与处理器体系结构和系统配置密切相关,所以一般由汇编来编写.   具体到S64,启动代码分成两部分,一是与ARM7TDMI内核相关的部分,包括处理器各异常向量的配置,各处理器模式的堆栈设置,如有必要,复制向量到RAM,以便remap之后处理器正确处理异常,初始化数据(包括RW与ZI),最后跳转到Main.二是与处理器外部设备相关的部分,这和厂商的联系比较大.虽然都采用了ARM7TDMI的内核,但是不同的厂家整合了不同的片上外设,需要不同的初始化,其中比较重要的是初始化WDT,初始化各子
[单片机]
2440开发板启动代码学习
2440init.s是启动代码的主文件,包括3个头文件,option.inc,memcfg.inc,2440addr.inc。 option.inc定义了3个堆栈起始地址,总线宽度,时钟相关参数的定义等。其中这个总线宽度将作为一个IF判断量,决定了各Bank的位宽设置,参见memcfg.inc文件及datasheet。 memcfg.inc是存储器Bank的配置文件,定义了存储器相关寄存器位的值。各bank的位宽的设置定义也是在这个文件中,注意bank0的位宽没有相关的定义,因为它的位宽取决于OM 引脚,即启动方式。 2440addr.inc定义了相关寄存器地址,包括存储器控制寄存器,时钟电源管理寄存
[单片机]
arm9(s3c2440)jlink烧写uboot
笔者开发环境:操作系统 win7,开发板GT2440,电脑没有串口,用的u转串口(本文简要摘录,并整理相关资源) 1.连接pc和jlink和开发板 2.安装jlink驱动,配置jlink 3.开发板打到nor flash启动方式,启动开发板 ARM学习笔记之Jlink烧写Uboot: 下载jlink驱动JLINK-V7安装包。解压后找到驱动安装。双击默认安装 安装完后在桌面会出现两个图标 安装完成可以桌面出现两个快捷图标,J-Link ARM 可以用来进行设置和测试,下面我们看一下J-LINK 的测试数据双击J-link ARM在没有连接开发板时出现如下的界面: 如果连接开发板后出现界面如下:说明jlink连上板子
[单片机]
arm9(s3c2440)jlink烧写<font color='red'>uboot</font>
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved