有许多事,需要回到u-boot才能说清楚……
include/configs/XXXX.h中(XXXX视具体平台而定),一般会作类似如下定义:
#define CONFIG_BOOTCOMMAND "mmcinit; fatload mmc 0 0x81c00000 uImage; bootm 0x81c00000"
编译时该宏CONFIG_BOOTCOMMAND传递给一个ENV项bootcmd,而在common/main.c中,函数main_loop取出了该env项,作为boot的过程开始启动kernel:
s = getenv ("bootcmd");
debug ("### main_loop: bootcmd=/"%s/"/n", s ? s : "<UNDEFINED>");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# endif
# ifndef CFG_HUSH_PARSER
run_command (s, 0);
我们关心的是最后一条命令bootm,在文件common/cmd_bootm.c中已经定义:
U_BOOT_CMD(
bootm, CFG_MAXARGS, 1, do_bootm,
"bootm - boot application image from memory/n",
"[addr [arg ...]]/n - boot application image stored in memory/n"
"/tpassing arguments 'arg ...'; when booting a Linux kernel,/n"
"/t'arg' can be the address of an initrd image/n"
);
即,真正要运行的程序是do_bootm。
一些关键的数据结构:
1、gd_t
在文件include/asm-arm/global_data.h中定义,在u-boot中广泛使用,通过宏:
DECLARE_GLOBAL_DATA_PTR;
将该数据结构的指针放入寄存器r8。
gd这个数据结构,在lib-arm/board.c文件中的start_armboot函数中进行初始化,详细分析以后再看。
2、bd_t
在文件include/asm-arm/u-boot.h中定义,作为u-boot的接口。
3、image_header_t
在文件include/image.h中定义,是u-boot即将加载的镜像文件头信息,u-boot将根据该头信息确定镜像文件是否正确,校验,镜像文件的起始地址以及入口地址等信息。
typedef struct image_header {
uint32_t
ih_magic;
/* Image Header Magic Number
*/
uint32_t
ih_hcrc;
/* Image Header CRC Checksum
*/
uint32_t
ih_time;
/* Image Creation Timestamp
*/
uint32_t
ih_size;
/* Image Data Size
*/
uint32_t
ih_load;
/* Data
Load Address
*/
uint32_t
ih_ep;
/* Entry Point Address
*/
uint32_t
ih_dcrc;
/* Image Data CRC Checksum
*/
uint8_t
ih_os;
/* Operating System
*/
uint8_t
ih_arch;
/* CPU architecture
*/
uint8_t
ih_type;
/* Image Type
*/
uint8_t
ih_comp;
/* Compression Type
*/
uint8_t
ih_name[IH_NMLEN];
/* Image Name
*/
} image_header_t;
do_bootm函数会读出即将加载的镜像文件头,填入由该数据结构声明的全局变量header中,do_bootm函数通过对header的分析,确定是一个Linux镜像,则会调用do_bootm_linux函数,开始启动Linux的Kernel。
do_bootm_linux函数(在文件lib_arm/armlinux.c中),目前只关心最后一句:
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
theKernel在前面被定义为:
theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
hdr->ih_ep使用的是do_bootm函数从image头中读取的入口,对于我们的板子来说,就是0x80008000;
bd->bi_arch_number, bd->bi_boot_params两个入口参数在的board_init函数中定义,bd->bi_arch_number赋值为板子的ID,bd->bi_boot_params赋值为0x80000100,该地址保存着do_bootm_linux函数创建的一系列ATAG。
参数的传递要看APCS(ARM过程调用标准),前四个参数会依次放入a1~a4,这是APCS为寄存器起的别名,对应于r0~r3,即,调用到kernel时,寄存器r0为0,r1为1967,r2为0x80000100。
u-boot的事情还远未说清楚,但是与目前有关的,大致差不多了。