全局变量images

上一节讲到,autoboot_command中会默认执行环境变量bootcmd中的启动命令,而基本的boot、bootm、bootz命令都会用一个全局变量images来保存系统镜像的信息。
全局变量images是一个结构体(common/bootm.c),结构主体内容如下:

  1. //common/bootm.c
  2. bootm_headers_t images; /* 指向系统镜像结构体的全局变量 */
  3. //include/image.h
  4. typedef struct bootm_headers {
  5. //...
  6. #ifndef USE_HOSTCC
  7. image_info_t os; /* OS镜像信息*/
  8. ulong ep; /* OS入口点*/
  9. ulong rd_start, rd_end;/* ramdisk开始和结束位置*/
  10. char *ft_addr; /* 设备树地址 */
  11. ulong ft_len; /* 设备树长度 */
  12. ulong initrd_start; //initrd开始地址
  13. ulong initrd_end; //initrd结束地址
  14. ulong cmdline_start;//cmdline开始位置
  15. ulong cmdline_end; //cndline结束位置
  16. struct bd_info *kbd;
  17. #endif
  18. //...
  19. #define BOOTM_STATE_START (0x00000001)
  20. #define BOOTM_STATE_FINDOS (0x00000002)
  21. #define BOOTM_STATE_FINDOTHER (0x00000004)
  22. #define BOOTM_STATE_LOADOS (0x00000008)
  23. #define BOOTM_STATE_RAMDISK (0x00000010)
  24. #define BOOTM_STATE_FDT (0x00000020)
  25. #define BOOTM_STATE_OS_CMDLINE (0x00000040)
  26. #define BOOTM_STATE_OS_BD_T (0x00000080)
  27. #define BOOTM_STATE_OS_PREP (0x00000100)
  28. #define BOOTM_STATE_OS_FAKE_GO (0x00000200) /* 'Almost' run the OS */
  29. #define BOOTM_STATE_OS_GO (0x00000400)
  30. int state; //boot启动的不同阶段状态,具体状态为上面的宏定义
  31. //...
  32. }} bootm_headers_t;
  33. typedef struct image_info {
  34. ulong start, end; /* blob开始和结束位置 */
  35. ulong image_start, image_len; /* 镜像起始地址(包括blob)和长度 */
  36. ulong load; /* 系统镜像加载地址 */
  37. uint8_t comp, type, os; /* 镜像压缩、类型,OS类型 */
  38. uint8_t arch; /* CPU架构 */
  39. } image_info_t;

bootz命令引导过程

我们以bootz命令引导linux内核的过程为例,看看uboot如何引导加载linux系统。其他boot命令流程大体相同。

do_bootz

bootz命令对应的处理函数为do_bootz,位于cmd/bootz.c文件中:
主要有两个函数:

  • bootz_start:初始化全局变量images的成员变量,用于后面使用
  • do_bootm_states:根据不同的BOOT状态执行不同的代码段,通过如下代码来判断BOOT状态:states & BOOTM_STATE_XXX

    //cmd/bootz.c
    int do_bootz(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
    {
      //...
      if (bootz_start(cmdtp, flag, argc, argv, &images))
          return 1;
    
      bootm_disable_interrupts(); //关闭中断
    
      images.os.os = IH_OS_LINUX; //设置系统类型,用于选择具体启动函数
    
      //执行多个boot阶段,用宏指定
      ret = do_bootm_states(cmdtp, flag, argc, argv,
    #ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
                    BOOTM_STATE_RAMDISK |
    #endif
                    BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
                    BOOTM_STATE_OS_GO,
                    &images, 1); //全局变量images
    
      return ret;
    }
    

    bootz_start

    该函数主要功能是查找系统镜像文件和设备树相关信息,填充到image全局变量中:

    //cmd/bootz.c
    static int bootz_start(struct cmd_tbl *cmdtp, int flag, int argc,
                 char *const argv[], bootm_headers_t *images)
    {
     //...
      ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
          images, 1); //执行BOOTM_STATE_START阶段,调用bootm_start清空image
      //...
      if (!argc) {
          images->ep = image_load_addr; //设置系统镜像存储位置
      } else {
          images->ep = simple_strtoul(argv[0], NULL, 16);
      }
      //判断当前images是否是linux镜像,是则返回起始和结束地址
      ret = bootz_setup(images->ep, &zi_start, &zi_end);
      //...
      //查找ramdisk和设备树文件,并保存地址
      if (bootm_find_images(flag, argc, argv, images->ep, zi_end - zi_start))
          return 1;
    
      return 0;
    }
    

    do_bootm_states

    函数 do_bootm_states根据不同的 BOOT状态执行不同的代码段。从do_bootz中我们可以知道,需要按照如下三个标识开始boot内核。
    **BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO**
    所以我们带着这三个标识看看do_bootm_state的执行流程:
    image.png
    之后通过Linux内核的起始地址代码进入内核,uboot的任务就结束了。

总结流程图

image.png