u-boot版本:v2009.08
u-boot利用了env裡的cmd來實作調用boot linux的接口, 效果等同于在u-boot中敲"booti xxx..."
start_armboot -> board_late_init:
int board_late_init(void)
{
int ret = 0;
#ifdef MX6Q_SABRESD_ANDROID_H
switch (get_boot_device()) {
case SD_BOOT:
if (!getenv("fastboot_dev"))
setenv("fastboot_dev", "mmc2");
/*本例的boot device是SD,并且device number是2*/
if (!getenv("bootcmd"))
setenv("bootcmd", "booti mmc2");
break;
......
}
#endif
......
return 0;
}
start_armboot ->main_loop:
void main_loop (void)
{
......
/*擷取前面set的bootcmd,值是"booti mmc2"*/
s = getenv ("bootcmd");
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
/*如果u-boot開機階段沒有收到按鍵事件,那麼就去啟動kernel*/
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
......
# ifndef CONFIG_SYS_HUSH_PARSER
/*調用booti mmc2去boot linux*/
run_command (s, 0);
# else
......
}
booti指令對應的定義如下:
U_BOOT_CMD(
booti, 3, 1, do_booti,
"booti - boot android bootimg from memory\n",
"[<addr> | mmc0 | mmc1 | mmc2 | mmcX] [<partition>] \n - boot application image stored in memory or mmc\n"
"\t'addr' should be the address of boot image which is zImage+ramdisk.img\n"
"\t'mmcX' is the mmc device you store your boot.img, which will read the boot.img from 1M offset('/boot' partition)\n"
"\t 'partition' (optional) is the partition id of your device, if no partition give, will going to 'boot' partition\n"
);
do_booti:
int do_booti(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
......
if (mmcc != -1) {
#ifdef CONFIG_MMC
......
/*擷取device資訊*/
mmc = find_mmc_device(mmcc);
if (!mmc) {
printf("booti: cannot find '%d' mmc device\n", mmcc);
goto fail;
}
......
#ifdef CONFIG_ANDROID_BOOT_PARTITION_MMC
#ifdef CONFIG_ANDROID_RECOVERY_PARTITION_MMC
/*開機可能是進入正常boot模式,也可以是進入recovery模式,取決于傳進來的參數,本例是kernel*/
if (!strcmp(ptn, "boot"))
partno = CONFIG_ANDROID_BOOT_PARTITION_MMC;
if (!strcmp(ptn, "recovery"))
partno = CONFIG_ANDROID_RECOVERY_PARTITION_MMC;
/*擷取kernel對應的partition info*/
if (get_partition_info(dev_desc, partno, &info)) {
printf("booti: device don't have such partition:%s\n", ptn);
goto fail;
}
#endif
#endif
#ifdef CONFIG_FASTBOOT
......
#else
/*擷取kernel的hdr,此資訊是在編譯boot.img的時候就存放在它起始的某個固定位置。*/
if (mmc->block_dev.block_read(mmcc, info.start,
1, (void *)hdr) < 0) {
printf("booti: mmc failed to read bootimg header\n");
goto fail;
}
......
sector = info.start + (hdr->page_size / 512);
#endif
/*讀取kernel到RAM中的kernel_addr*/
if (mmc->block_dev.block_read(mmcc, sector,
(hdr->kernel_size / 512) + 1,
(void *)hdr->kernel_addr) < 0) {
printf("booti: mmc failed to read kernel\n");
goto fail;
}
/* flush cache after read */
flush_cache((ulong)hdr->kernel_addr, hdr->kernel_size); /* FIXME */
sector += ALIGN_SECTOR(hdr->kernel_size, hdr->page_size) / 512;
/*讀取ramdisk到kernel的ramdisk_addr*/
if (mmc->block_dev.block_read(mmcc, sector,
(hdr->ramdisk_size / 512) + 1,
(void *)hdr->ramdisk_addr) < 0) {
printf("booti: mmc failed to read kernel\n");
goto fail;
}
/* flush cache after read */
flush_cache((ulong)hdr->ramdisk_addr, hdr->ramdisk_size); /* FIXME */
#else
return -1;
#endif
} else {
......
}
......
/*根據hdr資訊來boot linux*/
do_booti_linux(hdr);
......
}
void do_booti_linux (boot_img_hdr *hdr)
{
ulong initrd_start, initrd_end;
#ifdef CONFIG_SERIAL_TAG
char appended_cmd_line[512];
#endif
void (*theKernel)(int zero, int arch, uint params);
bd_t *bd = gd->bd;
#ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv("bootargs");
/* If no bootargs env, just use hdr command line */
/*本例bootargs沒有定義*/
if (!commandline) {
/*擷取cmdline,此值在device/fsl/imx6/BoardConfigCommon.mk中定義。*/
commandline = (char *)hdr->cmdline;
......
}
#endif
/*kernel address就是boot kernel的函數指針位址了*/
theKernel = (void (*)(int, int, uint))(hdr->kernel_addr);
/*擷取ramdisk start 和 end位址*/
initrd_start = hdr->ramdisk_addr;
initrd_end = initrd_start + hdr->ramdisk_size;
/*将memory,serial,revision,commandline等都放在各自
的struct tag中,kernel啟動之後會解析它們。*/
#if defined (CONFIG_SETUP_MEMORY_TAGS)
setup_start_tag(bd);
#ifdef CONFIG_SERIAL_TAG
setup_serial_tag (¶ms);
#endif
#ifdef CONFIG_REVISION_TAG
setup_revision_tag (¶ms);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (hdr->ramdisk_size)
setup_initrd_tag (bd, initrd_start, initrd_end);
#endif
......
setup_end_tag (bd);
#endif
......
/*啟動kernel, never return back!*/
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
}
注意theKernel()的參數,第二個是machine type,kernel會去比對,如果沒有找到對應的type id,那麼就無法正常啟動kernel.
int board_init(void)
{
......
/* board id for linux */
gd->bd->bi_arch_number = MACH_TYPE_MX6Q_SABRESD;
......
}
第三個參數就是前面的那些tags.
到此,kernel就啟動起來了。