主要内容:
之前使用的uboot都是直接编译就可以使用了, 但是作为一个愿意折腾的人, 这样的程度显然不够,
于是一如既往的打开了uboot的代码看起来吧!
准备工作
1, Linux 64bit 系统电脑一台
2, 熟悉的编译器, 最好有代码引索功能的, 免得找得蛋疼
3, 下载源代码, 及芯片手册
引导流程从这里开始
寻找srart源头:
折腾过ARM的人必然知道, 系统启动前一定有一段汇编代码, 来设置时钟, 看门狗什么的.
通过前面的文章, 我们了解uboot编译后生成了两个东西是我们需要的, MLO和u-boot.img,
u-boot.img大家都知道, MLO是啥呢? 明显这个是omap4460启动时需要的, 而且是会自动
加载的二进制文件(关于omap4460的自启动过程可以参看手册 <27.1 Initialization Overview>),
那么启动的汇编代码应该就在MLO里了吧, 打开uboot代码的 Makefile (./Makefile), 发现
1
2
3
| ./Makefile:1222
spl/u-boot-spl: tools prepare
$(Q)$(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all
|
spl在uboot里表示第二阶段启动代码, 其实就是芯片内部代码启动完后, 就会加载spl了,
那估计就是我们说的MLO了, 继续看, MLO必然和 scripts/Makefile.spl 文件有关, 查看之
1
2
3
4
| scripts/Makefile.spl:54
libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
libs-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/
libs-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/
|
这里只发现编译选项和编译内容, 貌似没什么线索了, 换一个想法, 编译的时候没看到, 是不是
在连接的时候能够看到点什么呢, 于是飞快敲入:
1
2
3
4
5
6
7
8
| $make V=1 | grep .lds
....
arm-none-linux-gnueabi-ld -r -o spl/lib/built-in.o spl/lib/hashtable.o spl/lib/errno.o spl/lib/display_options.o spl/lib/crc32.o spl/lib/ctype.o spl/lib/div64.o spl/lib/hang.o spl/lib/linux_compat.o spl/lib/linux_string.o spl/lib/string.o spl/lib/time.o spl/lib/uuid.o spl/lib/vsprintf.o
arm-linux-gnueabihf-gcc -E -Wp,-MD,spl/.u-boot-spl.lds.d -D__KERNEL__ -D__UBOOT__ -DCONFIG_SYS_TEXT_BASE=0x80800000 -DCONFIG_SPL_BUILD -D__ARM__ -Wa,-mimplicit-it=always -mthumb -mthumb-interwork -mabi=aapcs-linux -mno-unaligned-access -ffunction-sections -fdata-sections -fno-common -ffixed-r9 -msoft-float -pipe -march=armv7-a -Iinclude -I./arch/arm/include -include ./include/linux/kconfig.h -nostdinc -isystem /mnt/ssd/arm-linux-gnueabihf-5.2/bin/../lib/gcc/arm-linux-gnueabihf/5.2.1/include -include ./include/u-boot/u-boot.lds.h -include ./include/config.h -DCPUDIR=arch/arm/cpu/armv7 -ansi -D__ASSEMBLY__ -x assembler-with-cpp -P -o spl/u-boot-spl.lds arch/arm/cpu/armv7/omap-common/u-boot-spl.lds
(cd spl && arm-none-linux-gnueabi-ld -T u-boot-spl.lds --gc-sections -Bstatic --gc-sections -Ttext 0x40300000 arch/arm/cpu/armv7/start.o --start-group arch/arm/cpu/armv7/built-in.o arch/arm/cpu/built-in.o arch/arm/lib/built-in.o board/ti/panda/built-in.o common/spl/built-in.o common/built-in.o disk/built-in.o drivers/i2c/built-in.o drivers/gpio/built-in.o drivers/mmc/built-in.o drivers/serial/built-in.o fs/built-in.o lib/built-in.o --end-group arch/arm/lib/eabi_compat.o -L /mnt/ssd/arm-2014.05/bin/../lib/gcc/arm-none-linux-gnueabi/4.8.3/thumb2 -lgcc -Map u-boot-spl.map -o u-boot-spl)
....
|
编译时gcc使用 arch/arm/cpu/armv7/omap-common/u-boot-spl.lds 文件生成了 spl/u-boot-spl.lds
u-boot-spl.lds文件使用了许多宏来控制, 具体可以看看编译时的输出信息.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| arch/arm/cpu/armv7/omap-common/u-boot-spl.lds:0
MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
LENGTH = CONFIG_SPL_MAX_SIZE }
MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.text :
{
__start = .;
*(.vectors)
arch/arm/cpu/armv7/start.o (.text*)
*(.text*)
} >.sram
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| spl/u-boot-spl.lds:0
MEMORY { .sram : ORIGIN = 0x40300000, LENGTH = (0x4030C000 - 0x40300000) }
MEMORY { .sdram : ORIGIN = 0x80a00000, LENGTH = 0x80000 }
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.text :
{
__start = .;
*(.vectors)
arch/arm/cpu/armv7/start.o (.text*)
*(.text*)
} >.sram
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
. = ALIGN(4);
.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
. = ALIGN(4);
.u_boot_list : {
KEEP(*(SORT(.u_boot_list*_i2c_*)));
} >.sram
. = ALIGN(4);
__image_copy_end = .;
.end :
{
*(.__end)
}
.bss :
{
. = ALIGN(4);
__bss_start = .;
*(.bss*)
. = ALIGN(4);
__bss_end = .;
} >.sdram
}
|
spl里的0x40300000地址是什么呢?
打开手册我们可以看到: L3 OCM_RAM 0x40300000 56KB 32-bit Ex/R/W
看上去是内部扩展的RAM, 估计是专门用来的boot的, 下面是手册说明.
1
2
3
4
5
6
7
| 15.1.6.3 L3 OCM_RAM
The on-chip L3 OCM_RAM contains 56KB of RAM, and partitioning is defined by the L3 firewall logic. The
device-embedded L3 OCM_RAM has the following characteristics:
• Support for single and burst access transactions:
– Operates at full L3 interconnect clock frequency
– Fully pipelined, one 32-bit access per cycle
• Restricted access support
|
上面定义的两个内存段, 分别是sram, sdram. sram是芯片内部的一段存储区, sdram是DDR
初始化完成后才能使用的地址区域.
.text段代码将全部放在sram中, 其中arch/arm/cpu/armv7/start.o里的.text段代码放在sram的
最开始的地方. 那么start.S就是我们要找的东西啦, 打开一看, 果然就是熟悉而又陌生的汇编代码
映满屏幕, 末要慌张, 听我慢慢分析.
顺流而下, 柳暗花明:
打开start.S文件, 其实里面有很多注释, 已经足够我们去阅读这里的代码, 这里就会有人说了
“里面的汇编代码我不知道具体的含义啊”, 很早之前我也会有这样的问题, 但是我发现, 就算我
当时能够很深入的探究, 当时算是相当明白的, 但是时间一久, 都会有遗忘, 看的时候还是要
重新查, 所以我认为, 在没有很必要的时候我是不会区深入查看这些代码的, 能了解大概在做什么
就好了.
这里也想赞一下国外码农的工程意识, 代码写的很有条理, 注释也非常详细, 值得我们学习.
这里我就列出主要调用流程:
SPL阶段:
/* Allow the board to save important registers */
b save_boot_params // 里实际上就是保存一下函数的返回地址
|- disable interrupts
|- b cpu_init_cp15 ---> |- Invalidate L1 I/D // 无效 指令/数据 缓存
| |- disable MMU // 方便后续的内存访问, 不需要填写TLB
|
|- b cpu_init_crit ---> |- b lowlevel_init --> |- Setup a temporary stack // 设置SP指针, 估计马上要跑C代码了
| |- b s_init --> |- init_omap_revision // 获取芯片ID
| |- watchdog_init // 初始化看门狗
| |- force_emif_self_refresh(); // 初始化DDR
| |- setup_clocks_for_console // 开时钟等工作
|- b _main --> |- setup SP // Set up initial C runtime environment
|- board_init_f_mem // uboot设置内存
|- board_init_f // spl board_init_f
|- board_init_r // spl board_init_r
|- spl_load_image
|- spl_mmc_load_image
|- spl_mmc_do_fs_boot // 这里把uboot.img放到了 0x80800000上
|- jump_to_image_no_args // 跳到uboot上 (0x80800000)
uboot阶段和spl阶段类似, 只是后面有些不一样
...
|- b _main --> |- setup SP // Set up initial C runtime environment
|- relocate_code // 代码从定位
|- relocate_vectors // 设置中断向量
|- clear BSS
|- ldr pc, =board_init_r // 正式进入uboot地界
相关文件地址:
arch/arm/cpu/armv7/start.S
arch/arm/cpu/armv7/lowlevel_init.S
arch/arm/cpu/armv7/omap-common/hwinit-common.c
arch/arm/lib/crt0.S
arch/arm/lib/board.c
上面展示东西不多, 但是包含的东西确是大大滴多啊, 涉及的基础知识很多, 如计算机理论, 编译连接 等,
是不是瞬间有了 “望尽天涯路” 的感觉.
参考资料:
[1]: Universal Boot Loader
[2]: TI omap4460