完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
经过前面的四篇文章的学习,相信我们对u-boot 这个东西已经很熟悉了,
接下来,我们要看看u-boot最核心最重要的一部分: 以hi3516dv300为例,看看如何实现跳转到Kernel。 1. misc_init_r() 配置自启动命令 在 hi3516dv300 板子中,是有提前配置自启动参数的,配置 的函数就是 misc_init_r()。 misc_init_r() 是配置在 init_sequence_r[] 中的,由board_init_r() 解析调用运行。 在misc_init_r() 主要作用就是,配置gd->fdt_blob中的bootcmd为"mmc read 0x0 0x80000000 0x800 0x4800; bootm 0x80000000", 最重要的其实就是 bootm 0x80000000,说明 kernel 内核是从 0x80000000 地址开始运行的。 好,我们先来看看 misc_init_r() 的作用吧。
static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_MISC_INIT_R misc_init_r, /* miscellaneous platform-dependent init */ #endif } # devicehisiliconthird_partyubootu-boot-2020.01boardhisiliconhi3516dv300hi3516dv300.c int misc_init_r(void) { const char cmdBuf[] = "mmc read 0x0 0x80000000 0x800 0x4800; bootm 0x80000000"; env_set("verify", "n"); // 1. 配置环境变量bootargs的内容,保存在g_bootArgsStr 中 if (EmmcInitParam() == -1) { return 0; } // 2. 配置启动参数,如果要进入 recovery则修改启动参数,否则不变 ChangeBootArgs(); ==============> + char *emmcBootArgs = env_get("bootargs"); + int emmcBootArgsLen = strlen(emmcBootArgs); + char *initIndex = strstr(emmcBootArgs, "init"); + char *blkIndex = strstr(emmcBootArgs, "blkdevparts"); + if (!g_isRecovery) { // hos + memset(g_bootArgsStr, 0, ARG_SZ); + memcpy(g_bootArgsStr, emmcBootArgs, emmcBootArgsLen); + printf("@@@ bootArgs final from emmc = %sn", g_bootArgsStr); + } else { + printf("@@@ bootArgs final from misc = %sn", g_bootArgsStr); + } <============== // 3. 设置启动参数bootargs ,及启动命令bootcmd= mmc read 0x0 0x80000000 0x800 0x4800; bootm 0x80000000 env_set("bootargs", g_bootArgsStr); env_set("bootcmd", cmdBuf); return 0; } 1.1 环境变量 bootargs,拼凑 cmdline信息 在 EmmcInitParam() 中主要作用是配置环境变量bootargs的内容,保存在g_bootArgsStr 中,我们来看看它的工作做了啥:
const char defaultUpdaterStr[] = "mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M " "clk_ignore_unused androidboot.selinux=permissive skip_initramfs " "rootdelay=10 init=/updaterinit root=/dev/mmcblk0p3 rootfstype=ext4 rw blkdevparts=mmcblk0:1M(boot)," "15M(kernel),20M(updater),1M(misc),3307M(system),256M(vendor),-(userdata)"; const char updaterHead[] = "mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M clk_ignore_unused " "androidboot.selinux=permissive skip_initramfs " "rootdelay=10 init=/updaterinit root=/dev/mmcblk0p3 rootfstype=ext4 rw blkdevparts="; 如果是正常启动kernel,则往mmcblk0写入defaultRebootStr 及 rebootHead 内容 const char defaultRebootStr[] = "mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M " "clk_ignore_unused androidboot.selinux=permissive skip_initramfs rootdelay=10 init=/init root=/dev/mmcblk0p5 " "rootfstype=ext4 rw blkdevparts=mmcblk0:1M(boot),15M(kernel),20M(updater)," "1M(misc),3307M(system),256M(vendor),-(userdata)"; const char rebootHead[] = "mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M " "clk_ignore_unused androidboot.selinux=permissive skip_initramfs rootdelay=10 init=/init " "root=/dev/mmcblk0p5 rootfstype=ext4 rw blkdevparts="; 最终末尾写入block2 的内容 ,即最开始读取的 5 个扇区的内容 # devicehisiliconthird_partyubootu-boot-2020.01boardhisiliconhi3516dv300hi3516dv300.c char g_bootArgsStr[ARG_SZ]; // #define ARG_SZ 1000 static int EmmcInitParam() // get "boot_updater" string in misc,then set env { const char rebootHead[] = "mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M " "clk_ignore_unused androidboot.selinux=permissive skip_initramfs rootdelay=10 init=/init " "root=/dev/mmcblk0p5 rootfstype=ext4 rw blkdevparts="; const char defaultRebootStr[] = "mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M " "clk_ignore_unused androidboot.selinux=permissive skip_initramfs rootdelay=10 init=/init root=/dev/mmcblk0p5 " "rootfstype=ext4 rw blkdevparts=mmcblk0:1M(boot),15M(kernel),20M(updater)," "1M(misc),3307M(system),256M(vendor),-(userdata)"; const char updaterHead[] = "mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M clk_ignore_unused " "androidboot.selinux=permissive skip_initramfs " "rootdelay=10 init=/updaterinit root=/dev/mmcblk0p3 rootfstype=ext4 rw blkdevparts="; const char defaultUpdaterStr[] = "mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M " "clk_ignore_unused androidboot.selinux=permissive skip_initramfs " "rootdelay=10 init=/updaterinit root=/dev/mmcblk0p3 rootfstype=ext4 rw blkdevparts=mmcblk0:1M(boot)," "15M(kernel),20M(updater),1M(misc),3307M(system),256M(vendor),-(userdata)"; // 1. 从mmcdev 中读取5个扇区的内容 ,即512byte x 5=2.5M的内容 char block2[EMMC_SECTOR_SIZE*EMMC_SECTOR_CNT]; BlkDevRead(block2, MISC_LOCATION*(M_1/EMMC_SECTOR_SIZE), EMMC_SECTOR_CNT); =============> + int devNo = env_get_ulong("mmcdev", NUM_BASE, 0); + mmc = MmcBlkDevInit(devNo); + return MmcBlkRead(mmc, buffer, blk, cnt); <============ struct UpdateMessage *p = (struct UpdateMessage *)block2; block2[MAX_COMMAND_SIZE-1] = block2[MAX_COMMAND_SIZE+MAX_UPDATE_SIZE-1] =block2[EMMC_SECTOR_SIZE*EMMC_SECTOR_CNT-1] = 0; p->command[0] = p->command[0] == ((char)-1) ? 0 : p->command[0]; p->update[0] = p->update[0] == ((char)-1) ? 0 : p->update[0]; block2[EMMC_SECTOR_SIZE * (EMMC_SECTOR_CNT - 1)] = block2[EMMC_SECTOR_SIZE * (EMMC_SECTOR_CNT - 1)] == (char)-1 ? 0 : block2[EMMC_SECTOR_SIZE * (EMMC_SECTOR_CNT - 1)]; g_isRecovery = memcmp(p->command, "boot_updater", UPDATE_BOOT_LENGTH) ? 0 : 1; unsigned int partStrLen = strlen(&block2[EMMC_SECTOR_SIZE*(EMMC_SECTOR_CNT - 1)]); // 2. 如果是 recovery模式,则往mmcblk0写入defaultUpdaterStr 及 updaterHead 内容 // 3. 如果是正常启动kernel,则往mmcblk0写入defaultRebootStr 及 rebootHead 内容 if (memcmp(&block2[EMMC_SECTOR_SIZE*(EMMC_SECTOR_CNT-1)], "mmcblk0", MMC_LENGTH)) { if (g_isRecovery) { memcpy(g_bootArgsStr, defaultUpdaterStr, strlen(defaultUpdaterStr) + 1); } else { memcpy(g_bootArgsStr, defaultRebootStr, strlen(defaultRebootStr) + 1); } } else { if (g_isRecovery) { memcpy(g_bootArgsStr, updaterHead, strlen(updaterHead) + 1); } else { memcpy(g_bootArgsStr, rebootHead, strlen(rebootHead) + 1); } memcpy(g_bootArgsStr + strlen(g_bootArgsStr), &block2[EMMC_SECTOR_SIZE * (EMMC_SECTOR_CNT - 1)], partStrLen + 1); } printf("@@@ g_isRecovery = %dn", g_isRecovery); printf("@@@ bootArgs from misc = %sn", g_bootArgsStr); return g_isRecovery; } 1.2 环境变量 bootcmd const char cmdBuf[] = "mmc read 0x0 0x80000000 0x800 0x4800; bootm 0x80000000"; env_set("bootcmd", cmdBuf); 可以看出,在hi3516dv300 板子上,kernel 是从0x80000000 地址开始启动的。 2. bootm 0x80000000 可以看出,系统启动时,调用的是bootm 命令,传参0x80000000, 最终执行的是 do_bootm() 函数,我们来看看它主要的工作。
# devicehisiliconthird_partyubootu-boot-2020.01cmdbootm.c U_BOOT_CMD(bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,"boot application image from memory", bootm_help_text); int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { // 1. 如果使能了 Security boot功能,则对镜像进行安全检查 #if defined(CONFIG_OHOS_SEC_BOOT_SUPPORT) if (CONFIG_OHOS_SEC_BOOT_ENABLE) { int ret = check_security_boot(CONFIG_OHOS_X509_BIN_START_ADDR); if (ret) { printf("## Check security boot falied, sig_addr:%#Xn", CONFIG_OHOS_X509_BIN_START_ADDR); while (1); } } #endif // 2. 判断是否有额外的子命令需要运行 /* determine if we have a sub command */ argc--; argv++; if (argc > 0) { char *endp; simple_strtoul(argv[0], &endp, 16); if ((*endp != 0) && (*endp != ':') && (*endp != '#')) return do_bootm_subcommand(cmdtp, flag, argc, argv); } // 3. 开始运行 bootm的命令,注意此处 images是用于保存头信息结构体 return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START|BOOTM_STATE_FINDOS|BOOTM_STATE_FINDOTHER | BOOTM_STATE_LOADOS|BOOTM_STATE_RAMDISK|BOOTM_STATE_OS_CMDLINE|BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, &images, 1); } 2.1 do_bootm_states()
# devicehisiliconthird_partyubootu-boot-2020.01configshi3516dv300_emmc_smp_defconfig CONFIG_BOOTM_LINUX=y CONFIG_BOOTM_NETBSD=y # CONFIG_BOOTM_OPENRTOS is not set # CONFIG_BOOTM_OSE is not set CONFIG_BOOTM_PLAN9=y CONFIG_BOOTM_RTEMS=y CONFIG_BOOTM_VXWORKS=y CONFIG_CMD_ELF=y 我们根据宏控处理下boot_os # devicehisiliconthird_partyubootu-boot-2020.01commonbootm_os.c static boot_os_fn *boot_os[] = { [IH_OS_U_BOOT] = do_bootm_standalone, [IH_OS_LINUX] = do_bootm_linux, [IH_OS_NETBSD] = do_bootm_netbsd, [IH_OS_RTEMS] = do_bootm_rtems, [IH_OS_PLAN9] = do_bootm_plan9, [IH_OS_VXWORKS] = do_bootm_vxworks, [IH_OS_QNX] = do_bootm_qnxelf, }; 调用 boot_fn (do_bootm_linux) 函数,开始BOOTM_STATE_OS_PREP 预加载 正式跳转linux 不再返回, 调用的还是boot_fn (do_bootm_linux) 函数, 标志传参BOOTM_STATE_OS_GO # devicehisiliconthird_partyubootu-boot-2020.01commonbootm.c int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], int states, bootm_headers_t *images, int boot_progress) { boot_os_fn *boot_fn; int ret = 0, need_boot_fn; images->state |= states; /* Work through the states and see how far we get. We stop on any error.*/ if (states & BOOTM_STATE_START) ret = bootm_start(cmdtp, flag, argc, argv); ----------------> + images.verify = env_get_yesno("verify"); + bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start"); + images.state = BOOTM_STATE_START; <----------------- // 1. 获得 kernel 头信息,起始地址0x80000000,及长度, img parameters, 根据kernel 镜像类型来配置不同的信息, 映射 kernel 镜像地址保存在images.os.start 中 if (!ret && (states & BOOTM_STATE_FINDOS)) ret = bootm_find_os(cmdtp, flag, argc, argv); ----------------> + os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, &images, &images.os.image_start, &images.os.image_len); + -------->//bootm 0x80000000 中的 0x80000000 就是这被传给img_addr 的。 + // 定义在 # devicehisiliconthird_partyubootu-boot-2020.01includeconfigshi3516dv300.h + img_addr = genimg_get_kernel_addr_fit(argc < 1 ? NULL : argv[0],&fit_uname_config,&fit_uname_kernel); + -----> return kernel_addr = simple_strtoul(img_addr, NULL, 16); + buf = map_sysmem(img_addr, 0); + // 映射 kernel 镜像地址 + images.os.start = map_to_sysmem(os_hdr); <----------------- // 2. 如果images.os.type == IH_TYPE_MULTI的话,说明有多个镜像,查找是否存在ramdisk镜像,device tree镜像,fpga镜像,loadables 等 if (!ret && (states & BOOTM_STATE_FINDOTHER)) ret = bootm_find_other(cmdtp, flag, argc, argv); // 3. 开始加载kernel OS, 加载前先禁止中断 /* Load the OS */ if (!ret && (states & BOOTM_STATE_LOADOS)) { iflag = bootm_disable_interrupts(); ret = bootm_load_os(images, 0); } // 3. 拷贝ramdisk镜像 /* Relocate the ramdisk */ #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH if (!ret && (states & BOOTM_STATE_RAMDISK)) { ulong rd_len = images->rd_end - images->rd_start; ret = boot_ramdisk_high(&images->lmb, images->rd_start,rd_len, &images->initrd_start, &images->initrd_end); if (!ret) { env_set_hex("initrd_start", images->initrd_start); env_set_hex("initrd_end", images->initrd_end); } } #endif // 4. 拷贝device tree镜像 #if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB) if (!ret && (states & BOOTM_STATE_FDT)) { boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); ret = boot_relocate_fdt(&images->lmb, &images->ft_addr,&images->ft_len); } #endif // 5. 获得kernel os 的启动函数入口 /* From now on, we need the OS boot function */ boot_fn = bootm_os_get_boot_func(images->os.os); need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO); // 6. 调用 boot_fn (do_bootm_linux) 函数,开始BOOTM_STATE_OS_PREP 预加载 /* Call various other states that are not generally used */ if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_BD_T)) ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); if (!ret && (states & BOOTM_STATE_OS_PREP)) { if (images->os.os == IH_OS_LINUX) fixup_silent_linux(); ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); } // 7. 正式跳转linux 不再返回, 调用的还是boot_fn (do_bootm_linux) 函数, 标志传参BOOTM_STATE_OS_GO /* Now run the OS! We hope this doesn't return */ if (!ret && (states & BOOTM_STATE_OS_GO)) ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,images, boot_fn); ---------> boot_fn(BOOTM_STATE_OS_GO, argc, argv, images); return ret; } 2.2 linux OS启动函数boot_fn 、 do_bootm_linux() 在前面,分别调用boot_fn ,传参BOOTM_STATE_OS_PREP 和 BOOTM_STATE_OS_GO,主要工作为:
# devicehisiliconthird_partyubootu-boot-2020.01archarmlibbootm.c /* Main Entry point for arm bootm implementation * * Modeled after the powerpc implementation * DIFFERENCE: Instead of calling prep and go at the end * they are called if subcommand is equal 0. */ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images) { // 1. 配置 uboot中需要传给kernel 的所有信息的地址,包括,SERIAL, CMDLINE, REVISION, MEM,INITRD。 if (flag & BOOTM_STATE_OS_PREP) { boot_prep_linux(images); =======================> + char *commandline = env_get("bootargs"); + setup_start_tag(gd->bd); // #define ATAG_CORE 0x54410001 + setup_serial_tag(¶ms); // #define ATAG_SERIAL 0x54410006 + setup_commandline_tag(gd->bd, commandline); // #define ATAG_CMDLINE 0x54410009 + setup_revision_tag(¶ms); // #define ATAG_REVISION 0x54410007 + setup_memory_tags(gd->bd); // #define ATAG_MEM 0x54410002 + setup_initrd_tag(gd->bd, images->initrd_start,images->initrd_end); // #define ATAG_INITRD2 0x54420005 + setup_board_tags(¶ms); + setup_end_tag(gd->bd); // #define ATAG_NONE 0x00000000 + board_prep_linux(images); <======================= return 0; } // 2. 正式开始跳转kernel 不再返回 if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { boot_jump_linux(images, flag); return 0; } boot_prep_linux(images); boot_jump_linux(images, flag); return 0; } 2.3 boot_jump_linux() 在64位系统中的,通过 armv8_switch_to_el2来跳转, 其中可以看出,是在汇编层面直接通过 br x4 跳转到 (u64)images->ep 的地址开始运行,也就 实现了 u-boot 向kernel 的跳转。 而在32位系统中则相对简单,直接 kernel_entry(0, machid, r2); 在C层面以函数调用方式跳转。 # devicehisiliconthird_partyubootu-boot-2020.01archarmcpuarmv8transition.S .pushsection .text.armv8_switch_to_el2, "ax" ENTRY(armv8_switch_to_el2) switch_el x6, 1f, 0f, 0f 0: cmp x5, #ES_TO_AARCH64 b.eq 2f /* When loading 32-bit kernel, it will jump to secure firmware again, and never return.*/ bl armv8_el2_to_aarch32 2: /* x4 is kernel entry point or switch_to_el1 if CONFIG_ARMV8_SWITCH_TO_EL1 is defined. When running in EL2 now, jump to the address saved in x4.*/ br x4 1: armv8_switch_to_el2_m x4, x5, x6 ENDPROC(armv8_switch_to_el2) static void boot_jump_linux(bootm_headers_t *images, int flag) { #ifdef CONFIG_ARM64 void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,void *res2); int fake = (flag & BOOTM_STATE_OS_FAKE_GO); // 1. 获得 kernel 镜像的入口地址 kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,void *res2))images->ep; debug("## Transferring control to Linux (at address %lx)...n",(ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); announce_and_cleanup(fake); if (!fake) { do_nonsec_virt_switch(); update_os_arch_secondary_cores(images->os.arch); if ((IH_ARCH_DEFAULT == IH_ARCH_ARM64) && (images->os.arch == IH_ARCH_ARM)) armv8_switch_to_el2(0, (u64)gd->bd->bi_arch_number, (u64)images->ft_addr, 0, (u64)images->ep, ES_TO_AARCH32); else armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0, images->ep, ES_TO_AARCH64); } #else unsigned long machid = gd->bd->bi_arch_number; char *s; void (*kernel_entry)(int zero, int arch, uint params); unsigned long r2; int fake = (flag & BOOTM_STATE_OS_FAKE_GO); kernel_entry = (void (*)(int, int, uint))images->ep; ulong addr = (ulong)kernel_entry | 1; kernel_entry = (void *)addr; s = env_get("machid"); if (s) { if (strict_strtoul(s, 16, &machid) < 0) { debug("strict_strtoul failed!n"); return; } printf("Using machid 0x%lx from environmentn", machid); } debug("## Transferring control to Linux (at address %08lx)" "...n", (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); announce_and_cleanup(fake); if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; if (!fake) { if (armv7_boot_nonsec()) { armv7_init_nonsec(); secure_ram_addr(_do_nonsec_entry)(kernel_entry, 0, machid, r2); } else kernel_entry(0, machid, r2); } #endif } 好,至此,CPU指针跳转到了kernel OS,U-boot方面的代码分析也到此为止了, 下章我们开始分析Harmony OS 的kernel了,加油! 3. 鸿蒙Kernel镜像 uImage分析 前面的在 do_bootm_states() 中,我们通过boot_get_kernel()来获得kernel的头信息,那我们现在打开一个kernel镜像,来瞧瞧这些头信息到底是啥? 进入我们编译好的harmony 的out目录,找到 kernel 镜像uImage: 通过如下命令实现以16进制查看 uImage: vim -b uImage :%!xxd 打开uImage ok,如下: 结合image_header 结构体: /* * Legacy format image header, * all data in network byte order (aka natural aka bigendian). */ 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; 我们可以知道 : ih_magic = 0x27051956 ih_hcrc = 0xea737f06 ih_time = 0x60c4882c = (10进制) 1,623,492,652 转换成时间为 2021-06-12 18:10:52 ih_size = 0x004940be = (10进制) 4,800,702 -rw-rw-r-- 1 ciellee ciellee 4800766 Jun 12 03:11 uImage 我们看到 uImage大小为4800766,比ih_size多64个字节,这是为什么呢? 其实啊,是因为此处的 ih_size 是不包含头信息的,头信息image_header占用内存为64字节,4800702(ih_size) + 64(header) =4800766,这就对上了。 ih_load = 0x80008000 ih_ep = 0x80008000 kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,void *res2))images->ep; ih_dcrc = 0xb574b5a4 ih_os = 0x05 boot_fn = bootm_os_get_boot_func(images->os.os); 此处 os = 0x05,那看来,我们前面分析有点问题,我们之前默认它跑的是do_bootm_linux, 看来,在鸿蒙OS中,我们应该跑的是do_bootm_vxworks。 # devicehisiliconthird_partyubootu-boot-2020.01commonbootm_os.c static boot_os_fn *boot_os[] = { [IH_OS_U_BOOT] = do_bootm_standalone, [IH_OS_LINUX] = do_bootm_linux, [IH_OS_NETBSD] = do_bootm_netbsd, [IH_OS_RTEMS] = do_bootm_rtems, [IH_OS_PLAN9] = do_bootm_plan9, [IH_OS_VXWORKS] = do_bootm_vxworks, [IH_OS_QNX] = do_bootm_qnxelf, }; ih_arch = 0x02 此入 arch = 0x02 ,我们来看下,还确实,对应着IH_ARCH_ARM # devicehisiliconthird_partyubootu-boot-2020.01includeimage.h enum { IH_ARCH_INVALID = 0, /* Invalid CPU */ IH_ARCH_ALPHA, /* Alpha */ IH_ARCH_ARM, /* ARM */ IH_ARCH_I386, /* Intel x86 */ IH_ARCH_IA64, /* IA64 */ IH_ARCH_MIPS, /* MIPS */ IH_ARCH_MIPS64, /* MIPS 64 Bit */ IH_ARCH_PPC, /* PowerPC */ IH_ARCH_S390, /* IBM S390 */ IH_ARCH_SH, /* SuperH */ IH_ARCH_SPARC, /* Sparc */ IH_ARCH_SPARC64, /* Sparc 64 Bit */ IH_ARCH_M68K, /* M68K */ IH_ARCH_NIOS, /* Nios-32 */ IH_ARCH_MICROBLAZE, /* MicroBlaze */ IH_ARCH_NIOS2, /* Nios-II */ IH_ARCH_BLACKFIN, /* Blackfin */ IH_ARCH_AVR32, /* AVR32 */ IH_ARCH_ST200, /* STMicroelectronics ST200 */ IH_ARCH_SANDBOX, /* Sandbox architecture (test only) */ IH_ARCH_NDS32, /* ANDES Technology - NDS32 */ IH_ARCH_OPENRISC, /* OpenRISC 1000 */ IH_ARCH_ARM64, /* ARM64 */ IH_ARCH_ARC, /* Synopsys DesignWare ARC */ IH_ARCH_X86_64, /* AMD x86_64, Intel and Via */ IH_ARCH_XTENSA, /* Xtensa */ IH_ARCH_RISCV, /* RISC-V */ IH_ARCH_COUNT, }; ih_type = 0x02 此入type = 0x2,对应的就是IH_TYPE_KERNEL,对上了 # devicehisiliconthird_partyubootu-boot-2020.01includeimage.h enum { IH_TYPE_INVALID = 0, /* Invalid Image */ IH_TYPE_STANDALONE, /* Standalone Program */ IH_TYPE_KERNEL, /* OS Kernel Image */ IH_TYPE_RAMDISK, /* RAMDisk Image */ IH_TYPE_MULTI, /* Multi-File Image */ IH_TYPE_FIRMWARE, /* Firmware Image */ IH_TYPE_SCRIPT, /* Script file */ IH_TYPE_FILESYSTEM, /* Filesystem Image (any type) */ IH_TYPE_FLATDT, /* Binary Flat Device Tree Blob */ IH_TYPE_KWBIMAGE, /* Kirkwood Boot Image */ IH_TYPE_IMXIMAGE, /* Freescale IMXBoot Image */ IH_TYPE_UBLIMAGE, /* Davinci UBL Image */ IH_TYPE_OMAPIMAGE, /* TI OMAP Config Header Image */ IH_TYPE_AISIMAGE, /* TI Davinci AIS Image */ /* OS Kernel Image, can run from any load address */ IH_TYPE_KERNEL_NOLOAD, IH_TYPE_PBLIMAGE, /* Freescale PBL Boot Image */ IH_TYPE_MXSIMAGE, /* Freescale MXSBoot Image */ IH_TYPE_GPIMAGE, /* TI Keystone GPHeader Image */ IH_TYPE_ATMELIMAGE, /* ATMEL ROM bootable Image */ IH_TYPE_SOCFPGAIMAGE, /* Altera SOCFPGA CV/AV Preloader */ IH_TYPE_X86_SETUP, /* x86 setup.bin Image */ IH_TYPE_LPC32XXIMAGE, /* x86 setup.bin Image */ IH_TYPE_LOADABLE, /* A list of typeless images */ IH_TYPE_RKIMAGE, /* Rockchip Boot Image */ IH_TYPE_RKSD, /* Rockchip SD card */ IH_TYPE_RKSPI, /* Rockchip SPI image */ IH_TYPE_ZYNQIMAGE, /* Xilinx Zynq Boot Image */ IH_TYPE_ZYNQMPIMAGE, /* Xilinx ZynqMP Boot Image */ IH_TYPE_ZYNQMPBIF, /* Xilinx ZynqMP Boot Image (bif) */ IH_TYPE_FPGA, /* FPGA Image */ IH_TYPE_VYBRIDIMAGE, /* VYBRID .vyb Image */ IH_TYPE_TEE, /* Trusted Execution Environment OS Image */ IH_TYPE_FIRMWARE_IVT, /* Firmware Image with HABv4 IVT */ IH_TYPE_PMMC, /* TI Power Management Micro-Controller Firmware */ IH_TYPE_STM32IMAGE, /* STMicroelectronics STM32 Image */ IH_TYPE_SOCFPGAIMAGE_V1, /* Altera SOCFPGA A10 Preloader */ IH_TYPE_MTKIMAGE, /* MediaTek BootROM loadable Image */ IH_TYPE_IMX8MIMAGE, /* Freescale IMX8MBoot Image */ IH_TYPE_IMX8IMAGE, /* Freescale IMX8Boot Image */ IH_TYPE_COPRO, /* Coprocessor Image for remoteproc*/ IH_TYPE_COUNT, /* Number of image types */ }; ih_comp = 0x00; ih_name = 0x 4c69 6e75 782d 342e 3139 2e31 3535 = Linux-4.19.155 4. boot_fn do_bootm_vxworks() 通过分析编译出来的Kernel 镜像,我们得知ih_os = 0x05 ,结合宏控定义,我们知道了boot_os数组内容如下: # devicehisiliconthird_partyubootu-boot-2020.01commonbootm_os.c static boot_os_fn *boot_os[] = { [IH_OS_U_BOOT] = do_bootm_standalone, [IH_OS_LINUX] = do_bootm_linux, [IH_OS_NETBSD] = do_bootm_netbsd, [IH_OS_RTEMS] = do_bootm_rtems, [IH_OS_PLAN9] = do_bootm_plan9, [IH_OS_VXWORKS] = do_bootm_vxworks, [IH_OS_QNX] = do_bootm_qnxelf, }; 而0x05对应的启动函数是 do_bootm_vxworks(),由此可以前面我们猜测它走 do_bootm_linux 还是有点问题的。 那我们应补充分析下 do_bootm_vxworks()的工作流程,看看和 do_bootm_linux有什么不一样。 # devicehisiliconthird_partyubootu-boot-2020.01archriscvlibbootm.c int do_bootm_vxworks(int flag, int argc, char * const argv[], bootm_headers_t *images) { return do_bootm_linux(flag, argc, argv, images); } 进入代码,发现do_bootm_vxworks 完全就是对 do_bootm_linux 的重新封装, emmmmmmmmmm,好吧! 该做晚饭吃了,本文就写到这吧。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1752 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1611 浏览 1 评论
1052 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
721 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1666 浏览 2 评论
1926浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
711浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
560浏览 3评论
583浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
544浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 18:33 , Processed in 0.723291 second(s), Total 45, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号