********************************************************************/
Bootloader第二阶段的功能:(运行在内存当中)
********************************************************************/
(1)初始化本阶段要使用到的硬件设备
board_init函数设置MPLL、改变系统时钟,它是开发板相关的函数,在board/smdk2410/smdk2410.c中实现。值得注意的是,board_init函数中还保存了机器类型ID,这将在调用内核时传给内核,代码如下:
串口的初始化函数主要是serial_init,它设置UART控制器,是CPU相关的函数,在cpu/arm920t/s3c24x0/serial.c中实现。
(2)检测系统内存映射(memory map)
int dram_init (void)
{
}
这些设置的参数,将在后面向内核传递参数时用到。
(3)U-Boot命令的格式
即使是内核的启动,也是通过U-Boot命令来实现的。U-Boot中每个命令都通过U_BOOT_CMD宏来定义,格式如下:
U_BOOT_CMD(name,maxargs,repeatable,command,"usage","help")
各项参数的意义为:
① name:命令的名字,注意,它不是一个字符串(不要用双引号括起来)。
② maxargs:最大的参数个数
③ repeatable:命令是否可重复,可重复是指运行一个命令后,下次敲回
④ command:对应的函数指针,类型为(*cmd)(struct cmd_tbl_s *, int,
⑤ usage:简短的使用说明,这是个字符串。
⑥ help:较详细的使用说明,这是个字符串。
宏U_BOOT_CMD在include/command.h中定义:
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep,
Struct_Section也是在include/command.h中定义:
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
比如对于bootm命令,它如此定义:
U_BOOT_CMD(
bootm,CFG_MAXARGS,1,do_bootm,
“string1”,
“string2”
);
宏U_BOOT_CMD扩展开后就是:
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
程序中就是根据命令的名字在内存段__u_boot_cmd_start~__u_boot_cmd_end找到它的cmd_tbl_t结构,然后调用它的函数(请参考common/command.c中的find_cmd函数)。
内核的复制和启动,可以通过如下命令来完成:bootm从内存、ROM、NOR Flash中启动内核,bootp则通过网络来启动,而nboot从NAND Flash启动内核。它们都是先将内核映像从各种媒介中读出,存放在指定的位置;然后设置标记列表以给内核传递参数;最后跳到内核的入口点去执行。具体实现的细节不再描述,有兴趣的读者可以阅读common/cmd_boot.c、common/cmd_net.c、common/cmd_nand.c来了解它们的实现。
(4)为内核设置启动参数
与《Bootloader与内核的交互》所描述的一样,U-Boot也是通过标记列表向内核传递参数。并且,内存标记、命令行标记的示例代码就是取自U-Boot中的setup_memory_tags、setup_commandline_tag函数,它们都是在lib_arm/armlinux.c中定义。一般而言,设置这两个标记就可以了,在配置文件include/configs/smdk2410.h 中增加如下两个配置项即可:
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_CMDLINE_TAG 1
对于ARM架构的CPU,都是通过lib_arm/armlinux.c中的do_bootm_linux函数来启动内核。这个函数中,设置标记列表,最后通过“theKernel (0, bd->bi_arch_number, bd->bi_boot_params)”调用内核。其中,theKernel指向内核存放的地址(对于ARM架构的CPU,通常是 0x30008000),bd->bi_arch_number就是前面board_init函数设置的机器类型ID,而bd-> bi_boot_params就是标记列表的开始地址