本文以linaro提供的针对pandaboard的u-boot为例(之后用来加载Android),阐述u-boot编译及代码结构。
- U-boot是神马
简单说来就是嵌入式设备的BIOS, 用来初始化嵌入式设备上的各种硬件资源,并引导linux kernel的加载及启动。
详细描述请从http://www.denx.de/wiki/U-Boot上获得你所想要的一切信息。
另外, http://www.ibm.com/developerworks/cn/linux/l-btloader/也是一篇不可多得的介绍bootloader的文章!
- pandaboard u-boot的编译
相关代码如何下载,请参照《玩转pandaboard之初体验》- 首先通过device/linaro/pandaboard/目录下的各个mk文件把u-boot及对应kernel的编译融入到Android的整个编译体系当中。
这里就不多说了,熟悉Android编译体系结构的同学一看就明白(或者找到相应的变量, 在build/目录下grep,就一定能找到你想要的结果) - 与u-boot编译相关的参数都在BoardConfig.mk中指定了, 从中可以看出, TI已经基本放弃了x-load, 转而使用u-boot自带的SPL来作为second stage的bootloader
(第一是, ROM boot, 第三则是u-boot自身)
UBOOT_CONFIG := omap4_panda_config
TARGET_USE_XLOADER := false
XLOADER_CONFIG := omap4430panda_config
- 首先,使用make omap_panda_config来初始化u-boot的config环境
这里需要注意从Makefile中可以看出, make指令会去解析你所输入的xxxxx_config的参数, 然后找到对应的board的相关配置信息.
比如,这里会调用mkconfig, 读取boards.cfg中的信息, 来确定相关的信息(ARCH, CPU, SoC, Vendor, Target)
- 然后调用, make CROOSS_COMPILE=xxxxx来编译u-boot,
请注意,这里目前使用的最新的Codesourcery的CodeBench, 会有编译错误, 从网上的资料来说是因为它使用了gcc4.6.1, 其中有bug(会导致编译oma4的clock.c出错)
,我又先后尝试了几个之前的版本, 发现arm-2011.03-41-arm-none-linux-gnueabi.bin这个版本的最近的能够编译成功的版本.
- 首先通过device/linaro/pandaboard/目录下的各个mk文件把u-boot及对应kernel的编译融入到Android的整个编译体系当中。
- pandaboard u-boot的代码结构
- 目录结构
/arch Architecture 相关的文件
/arm ARM architecture相关的文件
/cpu CPU 相关
/include
/armv7 Files specific to ARM v7 CPUs
/omap4 omap4相关的一些相关的文件
*.c
...
/lib ARM Architecture相关的库文件
/api Machine/arch无关的与用户提供的app相关的一些接口
/board/ti/panda panda板卡相关的文件
/common 平台独立一些工具
/disk 经过config之后,与平台相关的磁盘分区代码
/doc 简单一些文档
/drivers 设备驱动代码
/examples
/fs 各种嵌入式文件系统的代码
/include
/lib 平台无关的各种库
/libfdt flattened device trees 库
/lzma LZMA decompression 库
/lzo LZO decompression 库
/net 支持network相关的代码
/post 上电之后的自我检测
/rtc Real Time Clock 驱动
/tools 帮助生成uboot image的一些工具, mkimage!
/spl 重用u-boot中既有的驱动, 来生成更小的secondary program loader. 目前omap4就已经使用它取代原来的x-loader. 也就是使用mkimage通过spl的编译结果生成的MLO
/README 重要的文件, 里面有个中板卡及kernel相关的配置的说明. 这个文档中也有简单如何增加新的board支持的说明及uboot各种命令及参数的说明!!!
所有经过make omap4_panda_config之后, 所有的跟板卡相关的设置信息都会在"include/configs/omap4_panda.h".
其中会引用其它一些板卡相关的configs头文件, 两者中包含了CPU/board/Serial port/console/linux内核/内存/autoboot/Device Tree/网络等的设置信息
同时,为其它相关的代码生成对应的.depend,其中包含各种相关的文件引用
- 来看看pandaboard的各种config设定,
include/configs/omap4-common.h include/configs/omap4-panda.h
其中有各种编译参数, 生成的image地址, 硬件端口的设置等
比如, SPL的启用,及mkimage生成uboot.img时指定的TEXT地址都在其中
这里相关的地址为什么定义为这个区间, 是跟各个板卡的RAM map相关的, pandaboard的ram划分参看<OMAP4430_ES2.x_PUBLIC_TRM_vR.pdf>的27.4.2 Memory Maps/* Defines for SPL */ #define CONFIG_SPL #define CONFIG_SPL_TEXT_BASE 0x40303080 #define CONFIG_SPL_MAX_SIZE (38 * 1024) #define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK /* * 64 bytes before this address should be set aside for u-boot.img's * header. That is 80E7FFC0--0x80E80000 should not be used for any * other needs. */ #define CONFIG_SYS_TEXT_BASE 0x80E80000
Table 2-1. Global Memory Space Mapping
- spl相关代码是独立与其它的uboot object来编译的, 有它自己的一些include及相关设定, 并通过mkimage生成对应的MLO
如
/home/test/pandaboard/u-boot-linaro-stable/u-boot-linaro_2012.04.2/tools/mkimage -T omapimage \ -a 0x40303080 -d /home/test/pandaboard/u-boot-linaro-stable/u-boot-linaro_2012.04.2/spl/u-boot-spl.bin /home/
/pandaboard/u-boot-linaro-stable/u-boot-linaro_2012.04.2/ MLOSection CHSETTINGS offset 40 length cCHSETTINGS (c0c0c0c1) valid:0 version:1 reserved:0 flags:0GP Header: Size 8270 LoadAddr 40303080make[1]: Leaving directory `/home/test/pandaboard/u-boot-linaro-stable/u-boot-linaro_2012.04.2/spl'test
- 目录结构
- 关于根目录下的Makefile
请参看<UBOOT中的MAKEFILE详解>
- 关于uboot及spl中用到的ld script
请参看http://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
其中解释下文中作者没明白的事情
注意这个问题是由一个ld与binutil联动生成address map造成的. = .; //这里没有搞清楚为什么要这样做! __u_boot_cmd_start = .; /*把当前位置赋值给__u_boot_cmd_start,即定义了.u_boot_cmd段空间的开始位置 */ .u_boot_cmd : { *(.u_boot_cmd) } __u_boot_cmd_end = .; /*把当前位置赋值给__u_boot_cmd_end,即定义了.u_boot_cmd段空间的结束位置
参见: http://git.linaro.org/gitweb?p=boot/u-boot-linaro-stable.git;a=commit;h=807d5d7319330e336ab34a5623c5e0d73b87d540
及 http://sourceware.org/ml/binutils/2005-08/msg00412.html
最终的解释在gnu ld的官方manual里面就有http://sourceware.org/binutils/docs-2.22/ld/Location-Counter.html#index-dot-outside-sections-517
在两个section之间, 加入以下的赋值, 是为了告诉ld, 在ld工作时(即处理ld script之前), 不会在ld script 中的". = ." 之后的section中, 再插入新的section. 从而导致链接出错误的地址及map
. = .;
以及http://lionwq.spaces.eepw.com.cn/articles/article/item/18928
其中关于链接地址及运行时地址的心得很有用
既然程序有了两种地址,就涉及到一些跳转指令的区别,这里正好写下来,以后万一忘记了也可查看,以前不少东西没记下来现在忘得差不多了。。。 ARM汇编中,常有两种跳转方法:b跳转指令、ldr指令向PC赋值。 我自己经过归纳如下: (1) b step1 :b跳转指令是相对跳转,依赖当前PC的值,偏移量是通过该指令本身的bit[23:0]算出来的,这使得使用b指令的程序不依赖于要跳到的代码 的位置,只看指令本身。 (2) ldr pc, =step1 :该指令是从内存中的某个位置(step1)读出数据并赋给PC,同样依赖当前PC的值,但是偏移量是那个位置(step1)的连接地址 (运行时的地址),所以可以用它实现从Flash到RAM的程序跳转。 (3) 此外,有必要回味一下adr伪指令,U-boot中那段relocate代码就是通过adr实现当前程序是在RAM中还是flash中。仍然用我当时的注释: relocate: /* 把U-Boot重新定位到RAM */ adr r0, _start /* r0是代码的当前位置 */ /* adr伪指令,汇编器自动通过当前PC的值算出 如果执行到_start时PC的值,放到r0中: 当此段在flash中执行时r0 = _start = 0;当此段在RAM中执行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000, 即u-boot在把代码拷贝到RAM中去执行的代码段的开始) */ ldr r1, _TEXT_BASE /* 测试判断是从Flash启动,还是RAM */ /* 此句执行的结果r1始终是0x33FF80000,因为此值是又编译器指定的(ads中设置,或-D设置编译器参数) */ cmp r0, r1 /* 比较r0和r1,调试的时候不要执行重定位 */
pandaboard的uboot的lds在arch/arm/cpu/u-boot.lds(最新的u-boot为所有的arm提供这么一个通用的script, 具体可以参看该文件的git log)及arch/arm/cpu/armv7/omap-common/u-boot-spl.lds
- 各种与pandaboard相关的配置文件
arch/arm/include/asm/arch-omap4/*
arch/arm/cpu/armv7/omap-common/*
board/ti/panda/*
arch/arm/cpu/armv7/omap4/*
arch/arm/cpu/armv7/omap-common/*
include/configs/omap4_common.h, include/configs/omap4_panda.h
详细请参看<玩转pandaboard之u-boot启动过程详述>
其它,
- uboot使用-march=armv5来编译, 而不是使用armv7来编译pandaboard的uboot.
具体原因我没能找到,但是从一些代码注释中,可以看出为了应付armv7的新的指令, uboot是如何做的
参见arch/arm/include/asm/armv7.h
/* * CP15 Barrier instructions * Please note that we have separate barrier instructions in ARMv7 * However, we use the CP15 based instructtions because we use * -march=armv5 in U-Boot */ #define CP15ISB asm volatile ("mcr p15, 0, %0, c7, c5, 4" : : "r" (0)) #define CP15DSB asm volatile ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0)) #define CP15DMB asm volatile ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0))
比如, 这里ISB, DSB, DMB都是armv7才提供的barrier instructions, uboot使用armv5类似的直接控制CP15的方式来实现它们.
- MLO的生成, 是由spl编译出的u-boot-spl.bin等文件, 由mkimage按照omapimage的配置生成的
具体MLO是什么请参照http://www.embedded-bits.co.uk/2011/writeanmlo
请注意beagleboard的spl起始地址是0x40200800, 而pandaboard是0x40303080(see omap4_common.h)
参考资料:
http://free-electrons.com/doc/u-boot.pdf 很好的关于u-boot的介绍
<玩转pandaboard之u-boot再体验>
http://omappedia.org/wiki/Bootloader_Project, 很好一个关于TI的板卡bringup的文章!!!
http://www.denx.de/en/pub/Documents/Presentations/EWC2012_Roeder_Zundel_Fastboot.pdf 关于SPL的比较详细介绍, 同时,代码目录doc/README.SPL也有详细的介绍