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就启动起来了。