本人不是做驱动的,下面内容是查阅一些资料再加上自己的理解总结的,和大家讨论,欢迎指证!
=============================================================
一、什么是Uboot
Uboot是德国DENX小组的开发用于多种
嵌入式cpu的bootloader程序, UBoot不仅仅支持嵌入式Linux系统的
引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统。UBoot除了支持PowerPC系列的处理器外,还能支持
mips、 x86、
arm、NIOS、XScale等诸多常用系列的处理器。
二、Uboot启动过程简介
多数bootloader都分为阶段1(stage1)和阶段2(stage2)两大部分,uboot也不例外。依赖于CPU体系结构的代码(如CPU初 始化代码等)通常都放在阶段1中且通常用汇编语言实现,而阶段2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
第一阶段的功能:
1. 硬件设备初始化
2. 加载U-Boot第二阶段代码到RAM空间
3. 设置好栈
4. 跳转到第二阶段代码入口 第二阶段的功能:
1. 初始化本阶段使用的硬件设备
2. 检测系统内存映射
3. 将内核从Flash读取到RAM中
4.为内核设置启动参数
5. 调用内核
下面重点整理一些硬件相关的过程,以ARM926为例
1. 硬件设备初始化
(1)设置异常向量表
(2)将CPU的工作模式位设置为管理模式SVC
(3)将中断禁止位和快中断禁止位置'1',关闭IRQ和FIQ中断处理
(4)关闭看门狗;
(5)设置时钟相关寄存器MPLLCON,UPLLCON, CLKDIVN。
CPU上电几毫秒后,晶振输出稳定,FCLK=Fin(晶振频率),CPU开始执行指令。但实际上,FCLK可以用软件来启用PLL改变。设置PLL的寄存器后,CPU会停滞一段时间,等待频率稳定后再开 始重新工作,中间停滞等待时间有的处理器通过寄存器设置,有的自动插入,总之这段时间CPU时钟不跳转,处于停滞状态, 由硬件保障CPU的停止和恢复的正确性。
(6)关闭MMU,cache。
数据cache必须关闭,Bootloader主要是装载内核镜像,镜像数据必须真实写回SDRAM中,所以数据cache必须关闭,而对于指令cache,不存在强制性的规定,但在一般情况下,推荐关闭cache和MMU。
(7) 初始化RAM控制寄存器
2. 复制U-Boot第二阶段代码到RAM
/* 判断U-Boot是否是下载到RAM中运行,若是,则不用 再复制到RAM中了,这种情况通常在调试U-Boot时才发生 */
3. 设置堆栈,清除BSS段
4. 跳转到第二阶段代码入口
第二阶段的功能硬件工作人员关心较少,其中初始化本阶段使用的硬件设备主要和硬件有关,例如时钟、串口等外设。
三、重定位Relocate
BootLoader中的重定位(relocate)代码段是将BootLoader自身第二阶段的代码由Flash复制到SDRAM,以便跳转到SDRAM执行。之所以需要进行重定位是因为在Flash中执行速度比较慢,而系统复位后总是从0x00000000地址FLASH取指。
重定位代码,位于/U-Boot/cpu/s3c44b0/start.S :
relocate: /* relocate U-Boot to RAM */
adrr0, _start /* r0 <- current position of code */
ldrr1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldrr2, _armboot_start
ldrr3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop: ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */ ble copy_loop以上代码首先判断是否需要进行重定位(如果是调试状态,代码直接下载到SDRAM就不需要relocate),如果需要的话首先确定复制的源基址、源大小和目标基址,然后以r3 ~ r13为媒介,将BootLoader复制到SDRAM中。分析copy_loop很容易理解,这里主要分析relocate处的前两条指令:
1. adrr0, _start adr是一条伪指令,汇编器总是试图为它产生add/sub这样的指令,(在这里)以pc为基址装载目标寄存器。以下是arm-elf-objdump产生的反汇编代码: c700048: e24f0050 sub r0, pc, #80 ; 0x50e24f0050是指令对应的机器码,c700048是存放该机器码的地址(十六进制表示)。这个地址是怎么来的呢?在/U-Boot/config.mk中有问题的答案: LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)上面的宏指定连接时的命令行参数,-Ttext设定了.text段的地址,而TEXT_BASE在/U-Boot/board/.../config.mk中定义为0x0C700000。这些信息最后都以硬编码的方式记录在程序映像文件中,程序的入口_start = TEXT_BASE = 0x0C700000 : Disassembly of section .text:0c700000 <_start>: c700000: ea00000a b c700030 ...但是,程序映像是烧写到Flash中并开始执行的,而Flash的地址从0x00000000开始。于是,程序映像的第一条指令对齐到0x00000000处。相应的,这条adr指令的地址应对齐到0x00000048处,执行后r0等于0。
2. ldr r1, _TEXT_BASE 以下是arm-elf-objdump产生的反汇编代码: c70004c: e51f1034 ldr r1, [pc, #-52] ; c700020 <_TEXT_BASE>由此可见,这里的ldr并不是简单的将_TEXT_BASE地址处的4字节装载到r1,而同样是以pc为基址计算得到源地址的。这里的pc = 0x4c + 8 = 0x54,于是该指令把0x54 – 52 = 0x20处的4字节(即TEXT_BASE,亦即0x0C700000)装载到r1。
3. 源大小的确定
通过上面的分析,我们已经有了一个概念:程序的实际执行地址与连接时指定的加载地址可能是不一样的。我们已经得到BootLoader代码开始的运行时开始地址,存放于r0,还需要计算它的运行时结束地址。运行时结束地址 = 运行时开始地址 + 代码段大小。代码段大小由.bss段的期望开始地址 - .text段的期望开始地址获得。小结通过连接时的-Ttext选项,将.text段的地址硬编码到程序映像中。虽然程序映像在Flash中执行,其实际执行地址与期望执行地址不一致,但在relocate之前,通过以pc为基址进行相对寻址,使得这些代码的执行与其实际装载的地址无关。
三、重映射Remap
从Remap这个英文单词的构成不难看出,它是对此前已确立的存储器映射的再次修 改。从本质上讲,Map和Remap是一样的,都是将地址编码资源分配给存储器块,只不过二者产生的时间不同:前者在系统上电的时刻发生,是任何计算机系统都必需的;而后者在系统上电后稳定运行的时刻发生,对计算机系统设计人员来说是可选的。典型的8位
单片机系统中,就没有使用Remap技术。
Remap通常始于系统的Bootload过程。具体执行动作为:Bootload将FLASH中的异常向量复制到SDRAM块的一端,然后执行Remap命令,将位于SDRAM异常向量块映射到异常向量表地址空间(原FLASH地址)上。此后,系统若产生异常,CPU将从SDRAM中读取异常向量。Remap的目的就是让CPU可以快速跳入异常处理程序,获得最佳的实时异常响应。(中断向量表的设置要看当前CPU运行的模式。如果是实模式的话,中断向量表就在物理地址00000000h开始。如果是保护模式就复杂了,要用lgdt之类的命令来加载表,教写操作系统的书会有说的。)
Remap由处理器硬件实现,它会允许把内存地址空间的某一段映射到某个位置,ARM中常见的是在上电复位的时候自动把引导加载程序锁在FLASH的地址映射到0x00000000,在引导加载的过程中由软件通过设置某个内存重映射寄存器,然后把主存地址重映射到0x00000000。在这种重映射的情况下,访问映射的地址相当于直接访问对应的FLASH或者主存的地址。
四、Boot与硬件
通常Bootloader存储在Nor Flash上,可以直接运行。那能不能从NAND Flash启动呢?原则上不行,因为NAND Flash读写需要驱动程序的支持,Boot没完成前驱动程序不可用。但是为了解决这个问题,有些处理器在硬件上做了特殊处理,例如三星的S3C2440 有一个内部的 SDRAM 缓存称为“Steppingstone”,当上电 的时候,Nand Flash 的首 4kbyte 会被自动导入到 Steppingstone 并且开始执行。所以,从NAND Flash启动只要保证它不超过4kbyte就好了。
========================================================================
有的硬件系统与上述的有些差别,比如我公司设计的一款芯片,Bootloader第一段代码固化在芯片内部的ROM,Bootloader第二段代码固话在芯片外设SPI接口的Flash存储中,上电后先进行RomBoot,RomBoot执行Relocate任务,将Flash中的代码复制到DRAM中,然后切换时钟后跳转到DDR中执行,Remap最后完成。