uboot启动代码详细讲解
uboot代码完全解析

目录
u-boot-1.1.6 之 cpu/arm920t........................................................................2 u-boot 中.lds 连接脚本文件的分析 ...................................................................................................12 分享一篇我总结的 uboot 学习笔记(转) .....................................................................................15 U-BOOT 内存布局及启动过程浅析 ...................................................................................................22 u-boot 中的命令实现 ..........................................................................................................................25 U-BOOT 环境变量实现 ........................................................................................................................28
U-boot代码解析

u-boot源码解析u-boot介绍Uboot是德国DENX小组的开发用于多种嵌入式CPU的bootloader程序, UBoot不仅仅支持嵌入式Linux系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS 嵌入式操作系统。
UBoot除了支持PowerPC系列的处理器外,还能支持MIPS、 x86、ARM、NIOS、XScale等诸多常用系列的处理器。
board:和一些已有开发板有关的文件。
每一个开发板都以一个子目录出现在当前目录中,子目录中存放与开发板相关的配置文件。
它的每个子文件夹里都有如下文件:makefileconfig.mksmdk2410.c 和板子相关的代码(以smdk2410为例)flash.c Flash操作代码memsetup.s 初始化SDRAM代码u-boot.lds 对应的连接文件common:实现uboot命令行下支持的命令,每一条命令都对应一个文件。
例如bootm命令对应就是cmd_bootm.c。
cpu:与特定CPU架构相关目录,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录arm920t等。
cpu/ 它的每个子文件夹里都有如下文件:makefileconfig.mkcpu.c 和处理器相关的代码interrupts.c 中断处理代码serial.c 串口初始化代码start.s 全局开始启动代码disk:对磁盘的支持。
doc:文档目录。
Uboot有非常完善的文档,推荐大家参考阅读。
drivers:Uboot支持的设备驱动程序都放在该目录,比如各种网卡、支持CFI的Flash、串口和USB等。
fs: 支持的文件系统,Uboot现在支持cramfs、fat、fdos、jffs2和registerfs。
include:Uboot使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。
UBOOT源码分析

UBOOT源码分析UBOOT是一种开放源码的引导加载程序。
作为嵌入式系统启动的第一阶段,它负责初始化硬件设备、设置系统环境变量、加载内核镜像以及跳转到内核开始执行。
Uboot的源码是开放的,让我们可以深入了解其内部工作机制和自定义一些功能。
Uboot源码的文件组织结构非常清晰,主要分为三个大类:目录、文件和配置。
其中目录包含了一系列相关的文件,文件存放具体的源码实现代码,配置文件包含了针对特定硬件平台的配置选项。
Uboot源码的核心部分是启动代码,位于arch目录下的CPU架构相关目录中。
不同的CPU架构拥有不同的启动代码实现,如arm、x86等。
这些启动代码主要包括以下几个关键功能:1. 初始化硬件设备:Uboot首先需要初始化硬件设备,例如设置时钟、中断控制器、串口等设备。
这些初始化操作是在启动代码中完成的。
通过查看该部分代码,我们可以了解硬件的初始化过程,以及如何配置相关寄存器。
2. 设置启动参数:Uboot启动参数存储在一个称为"bd_info"的数据结构中,它包含了一些关键的设备和内存信息,例如DRAM大小、Flash 大小等。
这些参数是在启动代码中设置的,以便内核启动时能够正确识别硬件情况。
3. 加载内核镜像:Uboot负责加载内核镜像到内存中,以便内核可以正确执行。
在启动代码中,会通过读取Flash设备或者网络等方式,将内核镜像加载到指定的内存地址处。
加载过程中,可能会进行一些校验和修正操作,以确保内核数据的完整性。
4. 启动内核:在内核镜像加载完成后,Uboot会设置一些寄存器的值,并执行一个汇编指令,跳转到内核开始执行。
此时,Uboot的使命即结束,控制权交由内核处理。
除了启动代码,Uboot源码中还包含了许多其他功能模块,如命令行解析器、存储设备驱动、网络协议栈等。
这些功能模块可以根据需求进行配置和编译,以满足不同平台的需求。
例如,可以通过配置文件选择启用一些功能模块,或者自定义一些新的功能。
U-boot启动流程分析(三)

U-boot 启动流程(Linux 内核)的分析(三)U-boot 属于两阶段的Bootloader ,第一阶段的文件为cpu/arm920t/start.S 和board\samsung\smdk2410/lowlevel_init.S,前者是平台相关的,后者是开发板相关的。
1.U-Boot 第一阶段代码分析(1)硬件设备初始化依次完成如下设置:将CPU 的工作模式设为管理模式(SVC ),关闭WATCHDOG ,设置FCLK ,HCLK ,PCLK 的比例,关闭MMU ,CACHE 。
代码在cpu/arm920t/start.S 中,(2)为加载Bootloader 的第二阶段代码准备RAM 空间。
所谓准备RAM 空间,就是初始化内存芯片,使它可用,对于S3C24x0,通过在Start.S 中调用lowlevel_init 函数来设置存储控制器,使得外接 SDRAM 可用,lowlevel_init.S,文件是与开发板相关的,这表示如果外接的设备不一样,可以修改lowlevel_init.S 文件中的相关的宏。
(3)复制Bootloader 的第二阶段代码到RAM 空间中 这里将整个U-Boot 代码都复制到SDRAM 中,这在cpu/arm920t/start.s 中实现上面这段程序,在使用NANDFlash 启动时,需要修改。
(4)设置好栈 /*栈的设置灵活性很大,只要让sp 寄存器指向一段没有使用的内存即可*/.word TEXT_BASE //这里是获得代码段的起始地址,我的是0x33F80000(在board/xxx/config.mk中//可到找到“TEXT_BASE=0x33F80000”.globl lowlevel_init //这里相当于定义一个全局的lowlevel_init以方便调用lowlevel_init :/* memory control configuration *//* make r0 relative the current location so that it *//* reads SMRDATA out of FLASH rather than memory ! */ldr r0, =SMRDATA //SMDATA表示这 13个寄存器的值存放的开始地址,值为0x33F8xxxx,处于内//存中,这一句的作用是把其值加载到r0中ldr r1, _TEXT_BASE // 把代码的起始地址(0x33F80000)加载到r1中sub r0, r0, r1 //r0减去r1其结果存入r0,也即SMDATA中的起始地址0x33F8xxxx减去//0x33F80000,其结果就是13个寄存器的值在NOR Flash存放的开始地址ldr r1, =BWSCON /* Bus Width Status Controller */ //存储控制器的基地址add r2, r0, #13*4 //在计算出来的存放地址加上#13*4,然后其结果保存在r2中//13 个寄存器,每个寄存器占4个字节0:ldr r3, [r0], #4 //内存中r0的值加载到r3中,然后r0加4,即下一个寄存器的str r3, [r1], #4 //读出寄存器的值保存到r1中,然后r1也偏移4cmp r2, r0 //比较r0与r2的值,如果不等继续返回0:执行,也即13个寄存器的值// 是否读完bne 0b/* everything is fine now */mov pc , lr //程序跳转,返回到cpu_init_crit中.ltorg/* the literal pools origin */SMRDATA :...................relocate : /* 将U-Boot复制到RAM中 */adr r0, _start /* r0:当前代码的开始地址 */ldr r1, _TEXT_BASE /* r1:代码段的连接地址*/cmp r0, r1 /* 测试现在是在FLash中,还在是RAM中,如果要从NandFlash启动的话,这里要根据需要修改 */beq stack_setup /*如果已经在RAM中,则不需要复制*/ldr r2, _armboot_start /*_armboot_start在前面定义,是第一条指令的运行地址*/ldr r3, _bss_start /*在连接脚本U-Boot.lds中定义,是代码段的结束地址*/sub r2, r3, r2 /* r2 <- 代码段长度 */add r2, r0, r2 /* r2 <-代码段的结束地址 */copy_loop :ldmia {r3-r10} /* 从地址[r0]处获得数据 */stmia {r3-r10} /* 复制到地址[r1]处 */cmp r0, r2 /* 判断是否复制完毕 */ble copy_loop /*没有复制完,则继续*/#endif /* CONFIG_SKIP_RELOCATE_UBOOT */ldr r0, _TEXT_BASE /* _TEXT_BASE 为代码段的开始地址,值为0x33F80000 */sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* 代码段下面,留出一段内存以实现malloc */sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* 再留出一段内存,存一些全局参数 */#ifdef CONFIG_USE_IRQsub r0, r0, #(CONFIG_STACKSIZE_IRQ +CONFIG_STACKSIZE_FIQ )#endifsub sp , r0, #12 /* 最后,留出12字节的内存给abort异常 */clear_bss :(5)跳转到第二阶段代码的C 入口点 在跳转之前,还要清除BSS 段(初始值0,无初始值的全局变量,静态变量放在BSS 段。
u-boot整体结构、移植步骤以及启动代码分析

u-boot整体结构、移植步骤以及启动代码分析本篇文章首先介绍u-boot的整体代码结构,移植的基本步骤,然后分析启动的代码(start.S)中其中代码结构和移植步骤是参考了下面两个连接的文章,这方面资源比较多,一搜一堆,就不自己发明车轮了阿,呵呵。
/blog/user1/9450/archives/2006/12887.html和老古开发网上面的一篇文章,作者是焦玉全黄乡生鲍玉军,题目是第7540篇:U-Boot在S3C2410上的移植(具体URL忘了,我文章是下载的,知道的朋友告诉一声)一、整体结构首先下载u-boot的源代码(www.denx.de),解压缩,你可以看到下面的目录:- board 目标板相关文件,主要包含SDRAM、FLASH驱动;- common 独立于处理器体系结构的通用代码,如内存大小探测与故障检测;- cpu 与处理器相关的文件。
如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件;- driver 通用设备驱动,如CFI FLASH驱动(目前对INTEL FLASH支持较好)- doc U-Boot的说明文档;- examples可在U-Boot下运行的示例程序;如hello_world.c,timer.c;- include U-Boot头文件;尤其configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;- lib_xxx 处理器体系相关的文件,如lib_ppc, lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;- net 与网络功能相关的文件目录,如bootp,nfs,tftp;- post 上电自检文件目录。
尚有待于进一步完善;- rtc RTC驱动程序;- tools 用于创建U-Boot S-RECORD和BIN镜像文件的工具;二、移植步骤为了使U-Boot支持新的开发板,一种简便的做法是在U-Boot已经支持的开发板中选择一种和目标板接近的,并在其基础上进行修改。
u-boot源码分析之start.s分析

一、bootloader启动过程1、Stage1start.S代码结构(1)定义入口。
(2)设置异常向量(Exception Vector)。
(3)设置CPU的速度、时钟频率及终端控制寄存器。
(4)初始化内存控制器。
(5)将ROM中的程序复制到RAM中。
(6)初始化堆栈。
(7)转到RAM中执行,该工作可使用指令ldr pc来完成。
2、Stage2C语言代码部分(1)调用一系列的初始化函数。
(2)初始化Flash设备。
(3)初始化系统内存分配函数。
(4)如果目标系统拥有NAND设备,则初始化NAND设备。
(5)如果目标系统有显示设备,则初始化该类设备。
(6)初始化相关网络设备,填写IP、MAC地址等。
(7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。
3、U-Boot的启动顺序二、具体代码分析1.Stage1start.S代码结构1.1定义入口(u-boot.lds)ENTRY(_start)1.2设置异常向量1.3设置全局向量表地址变量和字节对齐方式1.4定义重定位全局变量1.5设置全局搬移地址(falsh->dram)1.6设置中断向量地址1.7设置cpu模式设置cpu工作模式为SVC模式。
1.4中断向量表搬移,时钟设置1.5CPU设置(TBL,icache,MMU)1.6板级初始化1.7boot镜像搬移到SDRAM1.8清除bss段计算出偏移地址:__rel_dyn_start 、__rel_dyn_start 、__dynsym_start1.9跳转到Stage2C 语言部分1.10中断处理程序File :arch/arm/lib/Board.cvoid board_init_r (gd_t *id,ulong dest_addr)。
关于imx51的uboot代码的启动流程分析

关于imx51的uboot代码的启动流程分析2012.11.19baodingsheng1.首先bootrom代码会拷贝uboot的前2KB/4KB到IRAM中去,紧接着就会处理DDR2的配置数据表(即flash_header.S中的DCD段)。
2.执行完后进行CSF check,如果passed,则跳转到app_code_jump_v:.word_start接下来要开始执行的地方就是uboot中的start入口3.接下来在start.S中做的工作是:设置cpu为SVC模式、关闭中断IRQ和FIQ、MMU和L1cache的初始化、GPIO口的初始化、enable L1NEON bit、L2cache的初始化、AIPS的初始化、M4IF的初始化、clock的初始化、relocate U-Boot to RAM、设置堆栈、清除bss段、board_mmu_inint、这里使能了MMU、而后进入C代码段:dr pc,_start_armboot@jump to C codetart_armboot:.word start_armboot4.接下在void start_armboot(void)中做的工作是:a.全局变量gdgd->bd指针指向数据类型为bd_t的结构体,bd_t结构体记录开发板的参数,例如串口波特率、ip地址、机器类型、启动参数、环境变量位置等。
b.定义二级指针init_fnc_ptr指向一个存放函数指针的数组,接下来在for循环中执行的这些函数:init_fnc_t*init_sequence[]={#if defined(CONFIG_ARCH_CPU_INIT)arch_cpu_init,/*basic arch cpu dependent setup*/#endifboard_init,*basic board dependent setup*/#if defined(CONFIG_USE_IRQ)interrupt_init,/*set up exceptions*/#endiftimer_init,/*initialize timer*/env_init,/*initialize environment*/init_baudrate,/*initialze baudrate settings*/serial_init,*serial communications setup*/console_init_f,/*stage1init of console*/display_banner,/*say that we are here*/#if defined(CONFIG_DISPLAY_CPUINFO)print_cpuinfo,/*display cpu info(and speed)*/#endif#if defined(CONFIG_DISPLAY_BOARDINFO)checkboard,/*display board info*/#endif#if defined(CONFIG_HARD_I2C)||defined(CONFIG_SOFT_I2C)init_func_i2c,#endifdram_init,/*configure available RAM banks*/#if defined(CONFIG_CMD_PCI)||defined(CONFIG_PCI)arm_pci_init,#endifdisplay_dram_config,NULL,};c.arch_cpu_init函数的工作是:enable L1icache和dcache、enable L2cached.board_init函数的工作是:选择启动设备、SOC的版本、board的版本、板子的id号(bi_arch_number)、启动参数的地址(bi_boot_params),设置串口、设置nandflash控制器、设置expio、设置FEC(快速以太网控制器)、设置I2Ce.timer_init,设置GPT。
U-boot命令详解

常用的U-boot命令详解帮助与环境变量U-boot发展到现在,他的命令行模式已经非常接近Linux下的shell了,在我编译的U-boot-2009.11中的命令行模式模式下支持“Tab”键的命令补全和命令的历史记录功能。
而且如果你输入的命令的前几个字符和别的命令不重复,那么你就只需要打这几个字符即可,比如我想看这个U-boot的版本号,命令就是“ version”,但是在所有的命令中没有其他任何一个的命令是由“v”开头的,所以只需要输入“v”即可。
TX-2440A> versionU-Boot 1.1.6 (Jan 18 2010 - 10:05:35)TX-2440A> vU-Boot 1.1.6 (Jan 18 2010 - 10:05:35)TX-2440A> baseBase Address: 0x00000000TX-2440A> baBase Address: 0x00000000由于U-boot支持的命令实在太多,一个一个细讲不现实,也没有必要。
所以下面我挑一些烧写和引导常用命令介绍一下,其他的命令大家就举一反三,或者“help”吧!(1)获取帮助命令:help 或?功能:查看当前U-boot版本中支持的所有命令。
T X-2440A>h e l p?-a l i a s f o r'h e l p'a u t o s c r-r u n s c r i p t f r o m m e m o r yb a s e-p r i n t o r s e t a d d r e s s o f f s e tb d i n f o-p r i n t B o a r d I n f o s t r uc t u r eb o o t-b o o t d e f a u l t,i.e.,r u n'b o o tc m d'b o o t_n o o s-b o o t U s e r P r o g r a mb o o t_z I m a g e-b o o t L i n u x's z I m a g eb o o t d-b o o t d e f a u l t,i.e.,r u n'b o o tc m d'b o o t e l f-B o o t f r o m a n E L F i m a g e i n m e m o r yb o o t m-b o o t a p p l ic a t i o n i m a g e f r o m m e m o r yb o o t p-b o o t i m a g e v i a n e t w o r k u s i n g B o o t P/T F T P p r o t oc o lb o o t v x-B o o t v x W o r k s f r o m a n E L F i m a g ec h p a r t-c h a n g e a c t i v e p a r t i t i o nc m p-m e m o r y c o m p a r ec o n i n f o-p r i n t c o n s o l ede v i c e s a n d i nf o r m a t i o nc p-m e m o r y c o p yc r c32-c h e c k s u m c a l c u l a t i o nd a t e-ge t/s e t/r e s e t d a t e&t i m ed c a c h e-e n a b l e o r d i s a b l e d a t a c a c h ee c h o-e c h o a r g s t o c o n s o l ee r a s e-e r a s e F L A S H m e m o r yf l i n f o-p r i n t F L A S H m e m o r y i n f o r m a t i o nf s i n f o-p r i n t i n f o r m a t i o n a b o u t f i l e s y s t e m sf s l o a d-l o a d b i n a r y f i l e f r o m a f i l e s y s t e m i m ag eg o-s t a r t a p p l i c a t i o n a t a d d r e s s'a d d r'h e l p-p r i n t o n l i n e h e l pi c a c h e-e n a b l e o r d i s a b l e i n s t r u c t i o n c a c h ei m i n f o-p r i n t h e a d e r i n f o r m a t i o n f o r a p p l i c a t i o n i m a g ei t e s t-r e t u r n t r u e/f a l s e o n i n t e g e r c o m p a r el o a d b-l o a d b i n a r y f i l e o v e r s e r i a l l i n e(k e r m i t m o d e) l o a d s-l o a d S-R e c o r d f i l e o v e r s e r i a l l i n el o a d x-l o a d b i n a r y f i l e o v e r s e r i a l l i n e(x m o d e m m o d e)l o a d y-l o a d b i n a r y f i l e o v e r s e r i a l l i n e(y m o d e m m o d e) l o o p-i n f i n i t e l o o p o n a d d r e s s r a n g el s-l i s t f i l e s i n a d i r e c t o r y(d e f a u l t/)m d-m e m o r y d i s p l a ym e n u-d i s p l a y a m e n u,t o s e l e c t t h e i t e m s t o d o s o m e t h i n g m m-m e m o r y m o d i f y(a u t o-i n c r e m e n t i n g)m t d p a r t s-d e f i n e f l a s h/n a n d p a r t i t i o n sm t e s t-s i m p l e R A M t e s tm w-m e m o r y w r i t e(f i l l)n a n d-N A N D s u b-s y s t e mn b o o t-b o o t f r o m N A N D d e v i c en m-m e m o r y m o d i f y(c o n s t a n t a d d r e s s)p i n g-s e n d I C M P E C H O_R E Q U E S T t o n e t w o r k h o s tp r i n t e n v-p r i n t e n v i r o n m e n t v a r i a b l e sp r o t e c t-e n a b l e o r d i s a b l e F L A S H w r i t e p r o t e c t i o nr a r p b o o t-b o o t i m a g e v i a n e t w o r k u s i n g R A R P/T F T P p r o t o c o l r e s e t-P e r f o r m R E S E T o f t h e C P Ur u n-r u n c o m m a n d s i n a n e n v i r o n m e n t v a r i a b l es a v e e n v-s a v e e n v i r o n m e n t v a r i a b l e s t o p e r s i s t e n t s t o r a g e s e t e n v-s e t e n v i r o n m e n t v a r i a b l e ss l e e p-d e l a y e x e c u t i o n f o r s o m e t i m et f t p b o o t-b o o t i m a g e v i a n e t w o r k u s i n g T F T P p r o t o c o lu s b s l a v e-g e t f i l e f r o m h o s t(P C)v e r s i o n-p r i n t m o n i t o r v e r s i o n如果你想获取某条命令的更详细的帮助,可以使用:help <你想要查的指令>或者?<你想要查的指令>,甚至h <你想要查的指令缩写>。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
·1 引言在专用的嵌入式板子运行 GNU/Linux 系统已经变得越来越流行。
一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次:1. 引导加载程序。
固化在固件(firmware)中的 boot 代码,也就是 Boot Loader,它的启动通常分为两个阶段。
2. Linux 核。
特定于嵌入式板子的定制核以及核的启动参数。
3. 文件系统。
包括根文件系统和建立于 Flash 存设备之上文件系统,root fs。
4. 用户应用程序。
特定于用户的应用程序。
有时在用户应用程序和核层之间可能还会包括一个嵌入式图形用户界面。
常用的嵌入式 GUI 有:MicroWindows 和 MiniGUI 等。
引导加载程序是系统加电后运行的第一段软件代码。
回忆一下 PC 的体系结构我们可以知道,PC 机中的引导加载程序由 BIOS(其本质就是一段固件程序)和位于硬盘 MBR 中的 OS Boot Loader(比如,LILO 和 GRUB 等)一起组成。
BIOS 在完成硬件检测和资源分配后,将硬盘 MBR 中的 Boot Loader 读到系统的 RAM 中,然后将控制权交给 OS Boot Loader。
Boot Loader 的主要运行任务就是将核映象从硬盘上读到 RAM 中,然后跳转到核的入口点去运行,也即开始启动操作系统。
而在嵌入式系统中,通常并没有像 BIOS 那样的固件程序(注,有的嵌入式 CPU 也会嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由 Boot Loader 来完成。
比如在一个基于 ARM7TDMI core 的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000 处开始执行,而在这个地址处安排的通常就是系统的 Boot Loader 程序。
·2 bootloader简介简单地说,Boot Loader (引导加载程序)就是在操作系统核运行之前运行的一段小程序,它的作用就是加载操作系统,它是系统加电后运行的第一段软件代码。
通过这段代码实现硬件的初始化,建立存空间的映射图,为操作系统核准备好硬件环境并引导核的启动。
如上图所示的那样在设备的启动过程中bootloader位于最底层,首先被运行来引导操作系统运行,很容易可以看出 bootloader是底层程序所以它的实现严重地依赖于硬件,特别是在嵌入式世界。
因此,在嵌入式世界里建立一个通用的BootLoader几乎是不可能的。
尽管如此,一些功能强大、支持硬件环境较多的BootLoader也被广大的使用者和爱好者所支持,从而形成了一些被广泛认可的、较为通用的的bootloader实现。
2.1 Boot Loader 所支持的 CPU 和嵌入式板每种不同的 CPU 体系结构都有不同的 Boot Loader。
有些 Boot Loader 也支持多种体系结构的 CPU,比如 U-Boot 就同时支持 ARM 体系结构和MIPS 体系结构。
除了依赖于 CPU 的体系结构外,Boot Loader 实际上也依赖于具体的嵌入式板级设备的配置。
这也就是说,对于两块不同的嵌入式板而言,即使它们是基于同一种 CPU 而构建的,要想让运行在一块板子上的 Boot Loader 程序也能运行在另一块板子上,通常也都需要修改 Boot Loader 的源程序。
2.2 Boot Loader 的安装媒介(Installation Medium)系统加电或复位后,所有的 CPU 通常都从某个由 CPU 制造商预先安排的地址上取指令。
比如,基于 ARM7TDMI core 的 CPU 在复位时通常都从地址 0x00000000 取它的第一条指令。
而基于 CPU 构建的嵌入式系统通常都有某种类型的固态存储设备(比如:ROM、EEPROM 或 FLASH 等)被映射到这个预先安排的地址上。
因此在系统加电后,CPU 将首先执行 Boot Loader 程序。
下图1就是一个同时装有 Boot Loader、核的启动参数、核映像和根文件系统映像的固态存储设备的典型空间分配结构图:图1 固态存储设备的典型空间分配结构2.3 Boot Loader 的启动过程:单阶段(Single Stage)/多阶段(Multi-Stage)通常多阶段的 Boot Loader 能提供更为复杂的功能,以及更好的可移植性。
从固态存储设备上启动的 Boot Loader 大多都是 2 阶段的启动过程,也即启动过程可以分为 stage1 和 stage2 两部分。
而至于在 stage 1 和 stage 2 具体完成哪些任务将在下面讨论。
2.4 Boot Loader 的操作模式 (Operation Mode)大多数 Boot Loader 都包含两种不同的操作模式:"启动加载"模式和"下载"模式,这种区别仅对于开发人员才有意义。
但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。
启动加载(Boot loading)模式:这种模式也称为"自主"(Autonomous)模式。
也即 Boot Loader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。
这种模式是 Boot Loader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下。
下载(Downloading)模式:在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载核映像和根文件系统映像等。
从主机下载的文件通常首先被 Boot Loader 保存到目标机的 RAM 中,然后再被 Boot Loader 写到目标机上的FLASH 类固态存储设备中。
Boot Loader 的这种模式通常在第一次安装核与根文件系统时被使用;此外,以后的系统更新也会使用 Boot Loader 的这种工作模式。
工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的菜单界面或命令行接口来接收要执行的操作。
像 Blob 或 U-Boot 等这样功能强大的 Boot Loader 通常同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。
比如,Blob 在启动时处于正常的启动加载模式,但是它会延时 10 秒等待终端用户按下任意键而将 blob 切换到下载模式。
如果在 10 秒没有用户按键,则 blob 继续启动 Linux 核。
2.5 常见的Boot LoaderU-BOOT:U-Boot是Das U-Boot的简称,其含义是Universal Boot Loader,是遵循GPL条款的开放源码项目。
uboot是一个庞大的公开源码的软件。
它支持一些系列的arm体系,包含常见的外设的驱动,是一个功能强大的板极支持包。
vivi:vivi是国mizi 公司开发的bootloader, 适用于ARM9处理器。
Vivi也有两种工作模式:启动加载模式和下载模式。
启动加载模式可以在一段时间后(这个时间可更改)自行启动linux核,这是vivi的默认模式。
如果修改或更新需要进入下载模式,在下载模式下,vivi为用户提供一个命令行接口通过接口可以使用vivi提供的一些命令,来实现flash的烧写、管理、操作mtd分区信息、启动系统等功能。
·3 Boot Loader 的主要任务与典型结构框架从操作系统的角度看,Boot Loader 的总目标就是正确地调用核来执行。
另外,由于Boot Loader 的实现依赖于 CPU 的体系结构,因此大多数 Boot Loader 都分为 stage1 和stage2 两大部分。
依赖于 CPU 体系结构的代码,比如设备初始化代码等,通常都放在stage1 中,而且通常都用汇编语言来实现,以达到短小精悍的目的。
而 stage2 则通常用C语言来实现,这样可以实现给复杂的功能,而且代码会具有更好的可读性和可移植性。
以u-boot为例,它启动过程的两个阶段(stage) 如下:·第一阶段(stage 1) cpu/arm920t/start.S依赖于CPU体系结构的代码(如设备初始化代码等),一般用汇编语言来实现。
主要进行以下方面的设置:设置ARM进入SVC模式、禁止IRQ和FIQ、关闭看门狗、屏蔽所有中断。
设置时钟(FCLK,HCLK,PCLK)、清空I/D cache、清空TLB、禁止MMU和cache、配置存控制器、为搬运代码做准备、搬移uboot映像到RAM中(使用copy_loop实现)、分配堆栈、清空bss段(使用clbss_l实现)。
最后通过ldr pc, _start_armboot跳转到第二阶段。
·第二阶段(stage 2) lib_arm/board.c该阶段主要都是用C语言来实现。
start_armboot()进行一系列初始化(cpu, 板卡,中断,串口,控制台等),开启I/D cache。
初始化FLASH,根据系统配置执行其他初始化操作。
打印LOG,使能中断,获取环境变量,初始化网卡。
最后进入main_loop()函数。
综上所述,可简单的归纳两个阶段的功能如下:·第一阶段的功能:硬件设备初始化加载U-Boot第二阶段代码到RAM空间设置好栈跳转到第二阶段代码入口·第二阶段的功能:初始化本阶段使用的硬件设备检测系统存映射将核从Flash读取到RAM中为核设置启动参数调用核U-Boot启动第一阶段流程如下:3.1 u-boot 的 stage1详细分析uboot的第一阶段设计的非常巧妙,几乎都是用汇编语言实现的。
首先我们来看一下它的脚本(u-boot-1.1.6\board\smdk2410\u-boot.lds),通过它我们可以知道它整个程序的各个段是怎么存放的。
它定义了整个程序编译之后的连接过程,决定了一个可执行程序的各个段的存储位置。
/* 指定输出可执行文件是elf 格式,32 位ARM 指令,小端 */OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")/* 指定输出可执行文件的平台架构为ARM架构 */OUTPUT_ARCH(arm)/* 指定输出可执行文件的起始代码段为_start */ENTRY(_start)SECTIONS{. = 0x00000000;//入口地址. = ALIGN(4);//四字节对齐.text ://代码段,上面3行标识是不占任何空间的{cpu/arm920t/start.o (.text)//这里将start.o放在第一位就表示把start.s编译时放在最开始,也就是uboot启动是最先执行start.S*(.text)//所有的其他程序的代码段以四字节对齐放在它后面}. = ALIGN(4); //前面的“.”表示当前值.rodata : { *(.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 = .;//__bss_start赋值为当前位置,即bss段得开始位置.bss : { *(.bss) }_end = .;//把_end赋值为当前位置,即bss段得结束地址}从上面这段代码我们可以看出uboot运行的第一个程序是cpu/arm920t/start.S里面的第一个段_start。