Chinaunix首页 | 论坛 | 博客
  • 博客访问: 211144
  • 博文数量: 90
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-29 10:12
文章分类
文章存档

2015年(2)

2014年(54)

2013年(34)

我的朋友

分类: LINUX

2014-10-16 17:45:13

原文地址:uboot引导kernel分析 作者:crazytyt

uboot 2011.12, powerpc开发板
---------------------------------
1. 从common/cmd_bootm.c ----> do_bootm开始分析,因为多数启动都是用命令bootm kernel_add ramdisk_addr fdt_addr.

2. 先贴函数的代码:

点击(此处)折叠或打开

  1. int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  2. {
  3.     ulong iflag;
  4.     ulong load_end = 0;
  5.     int ret;
  6.     boot_os_fn *boot_fn;
  7. #ifdef CONFIG_NEEDS_MANUAL_RELOC
  8.     static int relocated = 0;

  9.     /* relocate boot function table */
  10.     if (!relocated) {
  11.         int i;
  12.         for (i = 0; i < ARRAY_SIZE(boot_os); i++)
  13.             if (boot_os[i] != NULL)
  14.                 boot_os[i] += gd->reloc_off;
  15.         relocated = 1;
  16.     }
  17. #endif

  18.     /* determine if we have a sub command */
  19.     if (argc > 1) {
  20.         char *endp;

  21.         simple_strtoul(argv[1], &endp, 16);
  22.         /* endp pointing to NULL means that argv[1] was just a
  23.          * valid number, pass it along to the normal bootm processing
  24.          *
  25.          * If endp is ':' or '#' assume a FIT identifier so pass
  26.          * along for normal processing.
  27.          *
  28.          * Right now we assume the first arg should never be '-'
  29.          */
  30.         if ((*endp != 0) && (*endp != ':') && (*endp != '#'))
  31. //此函数为bootm的子命令,在多核系统时,通常通过这些子命令来先动其它核,再启动0核
  32.             return do_bootm_subcommand(cmdtp, flag, argc, argv);
  33.     }
  34. //bootm_start准备内核,并检查内核的完整性
  35.     if (bootm_start(cmdtp, flag, argc, argv))
  36.         return 1;

  37. 点击(此处)折叠或打开

    1. static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
    2. {
    3.     void *os_hdr;
    4.     int ret;

    5.     memset((void *)&images, 0, sizeof(images));
    6.     images.verify = getenv_yesno("verify");

    7. //设置内存信息,此内存信息会被传到linux kernel
    1.     bootm_start_lmb();

    2.     /* get kernel image header, start address and length */
    3. //获取kernel的bin文件,os_hdr是tftp或其它方式下载kernel到内存的地址,images_start是压缩kernel(zImage)的头地址,即uImage头地址+0x40,image_len是长度。
    4. ## Current stack ends at 0x3fe2dbc0
      *  kernel: cmdline image address = 0x01000000
       --- p1_p2_rdb_pc.c show_boot_progress 165 i:1
      ## Booting kernel from Legacy Image at 01000000 ...
       --- p1_p2_rdb_pc.c show_boot_progress 165 i:2
       --- p1_p2_rdb_pc.c show_boot_progress 165 i:3
         Image Name:   Linux-3.0.32-rt52-02290-g11251b1
         Created:      2012-06-06   6:44:40 UTC
         Image Type:   PowerPC Linux Kernel Image (gzip compressed)
         Data Size:    3470673 Bytes = 3.3 MiB
         Load Address: 00000000
         Entry Point:  00000000
         Verifying Checksum ... OK
       --- p1_p2_rdb_pc.c show_boot_progress 165 i:4
       --- p1_p2_rdb_pc.c show_boot_progress 165 i:5
       --- p1_p2_rdb_pc.c show_boot_progress 165 i:6
         kernel data at 0x01000040, len = 0x0034f551 (3470673)

    5.     os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
    6.             &images, &images.os.image_start, &images.os.image_len);
    7.     if (images.os.image_len == 0) {
    8.         puts("ERROR: can't get kernel image!\n");
    9.         return 1;
    10.     }

    11.     /* get image parameters */
    12.     switch (genimg_get_format(os_hdr)) {
    13.     case IMAGE_FORMAT_LEGACY:
    14. //设置image的一些参数,从uImage的64字节头获取
    15.         images.os.type = image_get_type(os_hdr);
    16.         images.os.comp = image_get_comp(os_hdr);
    17.         images.os.os = image_get_os(os_hdr);

    18.         images.os.end = image_get_image_end(os_hdr);
    19.         images.os.load = image_get_load(os_hdr);
    20.         break;
    21. #if defined(CONFIG_FIT)
    22.     case IMAGE_FORMAT_FIT:
    23.         if (fit_image_get_type(images.fit_hdr_os,
    24.                     images.fit_noffset_os, &images.os.type)) {
    25.             puts("Can't get image type!\n");
    26.             show_boot_progress(-109);
    27.             return 1;
    28.         }

    29.         if (fit_image_get_comp(images.fit_hdr_os,
    30.                     images.fit_noffset_os, &images.os.comp)) {
    31.             puts("Can't get image compression!\n");
    32.             show_boot_progress(-110);
    33.             return 1;
    34.         }
    35.         if (fit_image_get_os(images.fit_hdr_os,
    36.                     images.fit_noffset_os, &images.os.os)) {
    37.             puts("Can't get image OS!\n");
    38.             show_boot_progress(-111);
    39.             return 1;
    40.         }

    41.         images.os.end = fit_get_end(images.fit_hdr_os);

    42.         if (fit_image_get_load(images.fit_hdr_os, images.fit_noffset_os,
    43.                     &images.os.load)) {
    44.             puts("Can't get image load address!\n");
    45.             show_boot_progress(-112);
    46.             return 1;
    47.         }
    48.         break;
    49. #endif
    50.     default:
    51.         puts("ERROR: unknown image format type!\n");
    52.         return 1;
    53.     }

    54.     /* find kernel entry point */
    55.     if (images.legacy_hdr_valid) {
    56.  //执行此处,因为64Byte头已经做好了备份,即复制到了另一个头结构体中。获取入口地址,通常为0x0.
    57.         images.ep = image_get_ep(&images.legacy_hdr_os_copy);
    58. #if defined(CONFIG_FIT)
    59.     } else if (images.fit_uname_os) {
    60.         ret = fit_image_get_entry(images.fit_hdr_os,
    61.                 images.fit_noffset_os, &images.ep);
    62.         if (ret) {
    63.             puts("Can't get entry point property!\n");
    64.             return 1;
    65.         }
    66. #endif
    67.     } else {
    68.         puts("Could not find kernel entry point!\n");
    69.         return 1;
    70.     }

    71.     if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
    72.         images.os.load = images.os.image_start;
    73.         images.ep += images.os.load;
    74.     }


    75.     if (((images.os.type == IH_TYPE_KERNEL) ||
    76.          (images.os.type == IH_TYPE_KERNEL_NOLOAD) ||
    77.          (images.os.type == IH_TYPE_MULTI)) &&
    78.         (images.os.os == IH_OS_LINUX)) { //执行此处,因为type == IH_TYPE_KERNEL, os == IH_OS_LINUX
    79.         /* find ramdisk */

    *  ramdisk: cmdline image address = 0x02000000
    ## Loading init Ramdisk from Legacy Image at 02000000 ...
     --- p1_p2_rdb_pc.c show_boot_progress 165 i:9
     --- p1_p2_rdb_pc.c show_boot_progress 165 i:10
       Image Name:   fsl-image-core-p2020rdb-20120406
       Created:      2012-04-06  11:43:16 UTC
       Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
       Data Size:    23085665 Bytes = 22 MiB
       Load Address: 00000000
       Entry Point:  00000000
       Verifying Checksum ... OK
     --- p1_p2_rdb_pc.c show_boot_progress 165 i:11
       ramdisk start = 0x02000040, ramdisk end = 0x036042a1

    1.         ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH,
    2.                 &images.rd_start, &images.rd_end);
    3.         if (ret) {
    4.             puts("Ramdisk image is corrupt or invalid\n");
    5.             return 1;
    6.         }

    7. #if defined(CONFIG_OF_LIBFDT)
    8.         /* find flattened device tree */

    //*  fdt: cmdline image address = 0x00c00000
    ## Checking for 'FDT'/'FDT Image' at 00c00000
    Wrong FIT format: no description
    *  fdt: raw FDT blob
    ## Flattened Device Tree blob at 00c00000
       Booting using the fdt blob at 0x00c00000
       of_flat_tree at 0x00c00000 size 0x000032e8

    1.         ret = boot_get_fdt(flag, argc, argv, &images,
    2.                    &images.ft_addr, &images.ft_len);
    3.         if (ret) {
    4.             puts("Could not find a valid device tree\n");
    5.             return 1;
    6.         }

    7.         set_working_fdt_addr(images.ft_addr);
    8. #endif
    9.     }

    10.     images.os.start = (ulong)os_hdr;
    11.     images.state = BOOTM_STATE_START;

    12.     return 0;
    13. }


点击(此处)折叠或打开

  1. iflag = disable_interrupts();

  2. #if defined(CONFIG_CMD_USB)
  3.     /*
  4.      * turn off USB to prevent the host controller from writing to the
  5.      * SDRAM while Linux is booting. This could happen (at least for OHCI
  6.      * controller), because the HCCA (Host Controller Communication Area)
  7.      * lies within the SDRAM and the host controller writes continously to
  8.      * this area (as The HccaFrameNumber is for example
  9.      * updated every 1 ms within the HCCA structure in For more
  10.      * details see the OpenHCI specification.
  11.      */
  12.     usb_stop();
  13. #endif
  14.  
  15.  // 解压缩内核镜相文件,  
  16. Uncompressing Kernel Image ... OK
       kernel loaded at 0x00000000, end = 0x006c3b00
     --- p1_p2_rdb_pc.c show_boot_progress 165 i:7

  1.     ret = bootm_load_os(images.os, &load_end, 1);

  2.     if (ret < 0) { //加载kernel的错误处理
  3.         if (ret == BOOTM_ERR_RESET)
  4.             do_reset(cmdtp, flag, argc, argv);
  5.         if (ret == BOOTM_ERR_OVERLAP) {
  6.             if (images.legacy_hdr_valid) {
  7.                 image_header_t *hdr;
  8.                 hdr = &images.legacy_hdr_os_copy;
  9.                 if (image_get_type(hdr) == IH_TYPE_MULTI)
  10.                     puts("WARNING: legacy format multi "
  11.                         "component image "
  12.                         "overwritten\n");
  13.             } else {
  14.                 puts("ERROR: new format image overwritten - "
  15.                     "must RESET the board to recover\n");
  16.                 show_boot_progress(-113);
  17.                 do_reset(cmdtp, flag, argc, argv);
  18.             }
  19.         }
  20.         if (ret == BOOTM_ERR_UNIMPLEMENTED) {
  21.             if (iflag)
  22.                 enable_interrupts();
  23.             show_boot_progress(-7);
  24.             return 1;
  25.         }
  26.     }

//把kernel解压后所占的内在预留起来,以免其它程序再用,此参数会传到kernel里

  1.     lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));

  2.     if (images.os.type == IH_TYPE_STANDALONE) { //不会执行此处
  3.         if (iflag)
  4.             enable_interrupts();
  5.         /* This may return when 'autostart' is 'no' */
  6.         bootm_start_standalone(iflag, argc, argv);
  7.         return 0;
  8.     }

  9.     show_boot_progress(8);

  10. #ifdef CONFIG_SILENT_CONSOLE
  11.     if (images.os.os == IH_OS_LINUX)
  12.         fixup_silent_linux();
  13. #endif
  14. //获取kernel启动函数,此处为:do_bootm_linux,因为images.os.os==5
  15.     boot_fn = boot_os[images.os.os];

  16.     if (boot_fn == NULL) {
  17.         if (iflag)
  18.             enable_interrupts();
  19.         printf("ERROR: booting os '%s' (%d) is not supported\n",
  20.             genimg_get_os_name(images.os.os), images.os.os);
  21.         show_boot_progress(-8);
  22.         return 1;
  23.     }

  24.     arch_preboot_os();

  25.     boot_fn(0, argc, argv, &images);
  26. ------------->不会执行到这里,因为boot_fn函数会启动kernel

  27.     show_boot_progress(-9);
  28. #ifdef DEBUG
  29.     puts("\n## Control returned to monitor - resetting...\n");
  30. #endif
  31.     do_reset(cmdtp, flag, argc, argv);

  32.     return 1;
  33. }
3. boot_fn实际上是do_bootm_linux,接下来分析此函数:


点击(此处)折叠或打开

  1. __attribute__((noinline))
  2. int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images)
  3. {
  4.     int ret;

  5.     if (flag & BOOTM_STATE_OS_CMDLINE) {
  6.         boot_cmdline_linux(images);
  7.         return 0;
  8.     }

  9.     if (flag & BOOTM_STATE_OS_BD_T) {
  10.         boot_bd_t_linux(images);
  11.         return 0;
  12.     }

  13.     if (flag & BOOTM_STATE_OS_PREP) {
  14.         boot_prep_linux(images);
  15.         return 0;
  16.     }

  17.     if (flag & BOOTM_STATE_OS_GO) {
  18.         boot_jump_linux(images);
  19.         return 0;
  20.     }
  21. //以上flag的处理多数是为多核准备的。

  22.     boot_prep_linux(images); //flush 相关的cache, 此时cache的数据对内核没用
  23. //分配内存给命令行参数,板子信息,DTB信息等
  24.     ret = boot_body_linux(images);
  25.     if (ret)
  26.         return ret;
  27.     boot_jump_linux(images);

  28.     return 0;
  29. }

点击(此处)折叠或打开

  1. static void boot_jump_linux(bootm_headers_t *images)
  2. {
  3.     void (*kernel)(bd_t *, ulong r4, ulong r5, ulong r6,
  4.               ulong r7, ulong r8, ulong r9);
  5. #ifdef CONFIG_OF_LIBFDT
  6.     char *of_flat_tree = images->ft_addr;
  7. #endif
  8. //获取kernel入口地址,通常为0x0.
  9.     kernel = (void (*)(bd_t *, ulong, ulong, ulong,
  10.                ulong, ulong, ulong))images->ep;
  11.     printf("## Transferring control to Linux (at address %08lx) ...\n",
  12.         (ulong)kernel);

  13.     show_boot_progress (15);

  14. #if defined(CONFIG_SYS_INIT_RAM_LOCK) && !defined(CONFIG_E500)
  15.     unlock_ram_in_cache();
  16. #endif

  17. #if defined(CONFIG_OF_LIBFDT) //执行此处
  18.     if (of_flat_tree) { /* device tree; boot new style */
  19.         /*
  20.          * Linux Kernel Parameters (passing device tree):
  21.          * r3: pointer to the fdt
  22.          * r4: 0
  23.          * r5: 0
  24.          * r6: epapr magic
  25.          * r7: size of IMA in bytes
  26.          * r8: 0
  27.          * r9: 0
  28.          */
  29. #if defined(CONFIG_MPC85xx) || defined(CONFIG_440)
  30.  #define EPAPR_MAGIC (0x45504150)
  31. #else
  32.  #define EPAPR_MAGIC (0x65504150)
  33. #endif

  34.         printf(" Booting using OF flat tree...\n");
  35.         WATCHDOG_RESET ();
  36. //开始执行内核代码
  37.         (*kernel) ((bd_t *)of_flat_tree, 0, 0, EPAPR_MAGIC,
  38.                getenv_bootm_mapsize(), 0, 0);
  39.         /* does not return */
  40.     } else

阅读(1758) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~