#=================================#
# U-boot配置过程 #
#=================================#
1.make Board_config
2.执行./mkconfig Target Architecture CPU Board [VENDOR] [SOC]
3.$1 = Board
4.创建到平台/开发板相关头文件的链接
ln -s asm-$2 asm
ln -s arch-x86 asm-$2/arch
ln -s proc-armv asm-$2/proc
5.创建顶层Makefile包含的文件include/config.mk
ARCH = $2
CPU = $3
BOARD = $4
VENDOR = $5
SOC = $6
6.创建开发板相关的头文件include/config.h
#include <configs/$1.h>
由此:
(1)应该在include/configs目录下建立一个<board_name.h>存放开发板
<board_name>的配置信息。
(2)在board目录下建立开发板<board_name>的目录。
#=================================#
# U-boot编译过程 #
#=================================#
1.编译cpu/$(CPU)/start.S, 对于不同的CPU,还可能编译CPU/$(CPU)下的其它文件。
BOARDDIR = $(BOARD)
$(OBJS):
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
2.对于平台相关的每个目录、每个通用目录都用它们各自的Makefile编译成相应的库。
$(LIBS):
$(MAKE) -C $(dir $(subst $(obj),,&@))
3.将1,2步生成的.o、.a文件按照board/$(BOARDDIR)/config.mk文件中指定的代码起
始地址、board/$(BOARDDIR)/U-Boot.lds连接脚本进行连接。
LDFLAGS指定了链接方式。
4.第3步得到的是ELF格式的U-Boot,后面Makefile还会将它转换为二进制格式、
S_Record格式。
#=================================#
# U-boot启动过程 #
#=================================#
第一阶段:
1.设置SVC模式
2.关看门狗
3.屏蔽中断
4.初始化SDRAM
调用board/BOARD_NAME/lowlevel.S中的lowlevel_init函数,因此跟开发板有关。
5.设置栈
调用start.S中stack_setup函数,让sp指向一段没有用过的内存。
6.时钟初始化
7.重定位代码 Flash --> SDRAM
8.清BSS段 (未初始化的全局变量和静态变量存放处。编译时不连接,运行时需将
BSS段全部清0)
9.调用start_armboot进入C函数(lib_arm/board.c中定义)
第二阶段:
1.初始化Flash
2.初始化Nand flash
3.初始化环境变量
4.调用main_loop
5.getenv(bootcmd)获取命令。(读出内核,启动内核)
或进入命令行模式
#=================================#
# 命令处理过程 #
#=================================#
U_BOOT_CMD宏添加命令
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = \
{#name, maxargs, rep, cmd, usage, help}
Struct_Section将命令放入.u_boot_cmd段
command table在__uboot_cmd_start地址处存放(定义在u-boot.lds文件中)
#=================================#
# 启动Linux内核过程 #
#=================================#
1.u-boot通过bootm命令来启动内核,而bootm实际上调用do_bootm函数。
2.do_bootm函数会调用do_bootm_linux(lib_arm/bootm.c)函数来设置标记列表和启动内核。
3.do_bootm_linux先后调用
* setup_start_tag
* setup_serial_tag
* setup_revision_tag
* setup_memory_tags
* setup_commandline_tag
* setup_initrd_tag
* setup_videolfb_tag
* setup_end_tag
等函数来为内核设置参数。
调用内核前,CPU必须满足下面的条件:
(1)CPU寄存器的设置
o r0=0
o r1=机器码
o r2=内核参数标记列表在RAM中的起始地址
(2)CPU工作模式
o 禁止IRQ与FIQ中断
o CPU为SVC模式
(3)使数据Cache与指令Cache失效
4.调用cleanup_before_linux()禁用中断和cache
5.theKernel(0, machid, bd->bi_boot_params);
根据ATPCS规则,函数的参数个数不超过4个时,使用r0~r3这4个寄存器来传递参数。
因此theKernel调用会将0放入r0,机器码machid放入r1,内核参数地址bd->bi_boot_params
放入r2,从而完成了寄存器的设置,最后转到内核的入口地址。
#=================================#
# U-boot内存布局 #
#=================================#
-- +--------------------+
/ | : |
/ | : |
| | : |
| |--------------------| _end
| | |
| | BSS段 |
| |--------------------| __bss_start
| | u_boot_cmd |
| |--------------------| __u_boot_cmd_start
| | U-boot映像 |
/ | |
SDRAM / |--------------------| TEXT_BASE(_start)
\ | |
\ | CFG_MALLOC_LEN |
^ | | |
| 地 | |--------------------|
| 址 | | GBL_DATA_SIZE | 全局数据结构体
| 增 | |--------------------| <-- gd_t的指针gd
| 长 | | IRQ&FIQ栈区 |
| 方 | |--------------------| <-- 用户栈顶sp
| 向 | | | |
| \ | 用户栈区 | |
\ | V |
-- +--------------------+ SDRAM_BASE