bootloader,称为启动引导程序,是在操作系统内核之前运行的一小段程序,用于完成系统的相关初始化工作,比如初始化硬件,建立内存映射,初始化堆栈等,将系统的软硬件环境带到一个合适的状态,为操作系统的运行做好准备。
bootloader是一个与具体硬件高度相关的裸机程序,设计一款自己的bootloader,可以参考现有的比较成熟的bootloader来设计,这就是uboot。uboot是一款支持多种嵌入式CPU、多种嵌入式系统的启动引导程序。uboot可以工作在两种工作模式,一种是自主模式,一般在嵌入式产品发布之后uboot工作在此模式,用于正常引导装载系统。另一种是开发模式或称为命令模式,此时uboot可以执行相关命令,或是手动下载程序。
bootloader的工作流程需要按照芯片的启动流程与启动机制来设计,故需要先了解一下ARM处理器的启动过程。不同的ARM芯片支持不同的启动方式,比如从SD卡启动,从NandFlash启动等方式,以及不同的地址布局和启动流程。不同的芯片的启动流程既有相同点也有不同点,需要同时对比多款芯片,然后总结规律。
支持从NorFlash(2MB)和NandFlash(256MB) 启动,一般将uboot、内核、文件系统放在Nandflash中,然后设置开发板从Nandflash启动,以下是2440的内存布局。
左侧是从Norfalsh启动时的内存布局,右侧是从Nandflash启动时的内存布局。CPU上电之后从0地址处开始取第一条指令,对于从Nandflash的启动方式而言,0地址安排的是4KB的BootSRAM,这是一块片内RAM,也称为“垫脚石”。ARM启动时会自动把Nandflash上的前4KB启动代码复制到BootSRAM,然后从BootSRAM启动,这小段启动代码会把剩余的启动代码从Nandflash拷贝到片外SDRAM,也就是设备内存,然后跳转到内存,从内存开始启动。这部分在芯片文档的第6章有描述,如下图所示:
支持从SROM,Norflash,OneNAND,MODEM和IROM启动。从SD卡及Nandflash的启动方式被划规到IROM启动下面。
以下是设备的内存布局。
可以看到IROM的地址是0x08000000到0x0BFFFFFF,大小64MB,但实际只有32KB的存储空间,还可以看到从0x0C000000到0x0FFFFFFF是Internal SRAM,也就是垫脚石的内存空间,大小64MB,但实际只有4KB。从0x50000000开始的区域是DRAM,也就是内存的起始地址。
从0x00000000到0x07FFFFFF的128MB空间是设备上电之后最先执行指令的区间,这部分地址空间是动态映射的,内容并不固定,而是根据设备的启动配置的不同进行映射到不同的区域,比如,如果设备设置的是从IROM启动,则IROM的存储空间就会被映射到这段区域。
下面来分析6410从IROM启动时的启动流程,参考文档《S3C6410_Internal_ROM_Booting.pdf》,从IROM启动包含了从SD卡及从Nandflash启动,如下图所示:
从IROM启动的启动流程为:
通过以上过程,就完成了正常系统的启动。
210除了可以从各种存储设备启动外,还可以从USB和串口启动,它的启动配置如下:
从各种存储设备启动的方式统一划分到IROM启动下面,根据不同的引脚设置,再决定从某个具体的存储设备启动。下面是210的内存映射:
S5PV210有64KB的IROM和96KB的IRAM,0地址也是镜像映射区,和6410相类似。内存区域从0x20000000开始。
下面参考文档《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》来分析210从IROM启动时的启动流程,其启动顺序图如下图所示:
S5PV210的IROM启动顺序如下:
注意一点,uboot的链接起始地址不是由u-boot.lds决定的,而是由TEXT_BASE变量决定的,这个可以从uboot根目录下的config.mk文件查看得知:
TEXT_BASE变量在对应开发板目录的config.mk文件中定义,它的内容由配置uboot时生成,生成的方法如下:
make forlinx_nand_ram256_config将调用以下步骤生成对应配置文件
在mkconfig脚本中有如下内容:
其最终值是0XCFE00000,这个值在芯片手册上的内存布局中找不到,因为这个值是打开MMU之后得到的结果。
对u-boot进行反汇编之后可以看到如下内容:
第一条指令的地址是cfe00000,由此推导出其原因。
注意一点,程序真实运行时代码的地址不一定要按照链接地址来规定,以uboot代码为例,_start语句标号是uboot的起始语句,这部分语句在运行时一定是位于0地址附近,更准确一点来说是开头4KB以内的垫脚石里面的,但是其链接地址却超过了4KB,这并不妨碍将这段代码装载到4KB以内的地址处,以及将PC指针指向这段代码。如果这4KB以内的代码里面含有跳转语句,即B和BL指令,那么PC指针跳转的地址也不会按照跳转语句的链接地址进行绝对跳转,而是进行相对跳转,即用跳转处的链接地址减去当前指令的链接地址,用这个差值作为跳转的长度。要相进行决对地址跳转,就必须借助LDR伪指令来完成,这在uboot第二阶段时是非常有用的,因为第二阶段要从垫脚石跳转到内存中去运行。