歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> uboot從bootm跳到內核

uboot從bootm跳到內核

日期:2017/3/1 10:49:59   编辑:Linux編程

main_loop中執行的最重要的操作便是引導內核。引導分兩步。第一步先讀取內核鏡像uImage到內存。然後再使用bootm引導內核。

讀取內核只是進行內存復制,因此僅僅需要分析bootm。

  1. /*******************************************************************/
  2. /* bootm - boot application image from image in memory */
  3. /*******************************************************************/
  4. 引導應用程序在內存中的鏡像。
  5. common/cmd_bootm.c
  6. int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
  7. {
  8. ulong iflag;
  9. ulong load_end = 0;
  10. int ret;
  11. boot_os_fn *boot_fn;
  12. /* determine if we have a sub command */檢查是否有子命令
  13. if (argc > 1) {
  14. char *endp;
  15. simple_strtoul(argv[1], &endp, 16); //調用字符串轉無符號整形的函數,endp指向尾字符。
  16. /* endp pointing to NULL means that argv[1] was just a
  17. * valid number, pass it along to the normal bootm processing 以空字符結尾則當作是合法的數,作為正常引導的參數
  18. *
  19. * If endp is ':' or '#' assume a FIT identifier so pass
  20. * along for normal processing.
  21. *
  22. * Right now we assume the first arg should never be '-'
  23. */
  24. if ((*endp != 0) && (*endp != ':') && (*endp != '#')) //是否有子命令。一般不會有,所以這個路徑不會執行。
  25. return do_bootm_subcommand(cmdtp, flag, argc, argv);
  26. }
  27. if (bootm_start(cmdtp, flag, argc, argv)) //bootm_start的分析見下一篇文章。這個函數執行成功返回0,失敗返回1。這個函數主要用於獲取鏡像的信息並存入images。
  28. return 1;
  29. /*
  30. * We have reached the point of no return: we are going to
  31. * overwrite all exception vector code, so we cannot easily
  32. * recover from any failures any more...
  33. */
  34. iflag = disable_interrupts();//禁用中斷。
  35. ret = bootm_load_os(images.os, &load_end, 1);//將鏡像的數據從images.os.image_start復制到images.os.load 打印:Loading Kernel Image ... OK
  36. if (ret < 0) {//上個函數調用失敗才會進入這個路徑
  37. if (ret == BOOTM_ERR_RESET)
  38. do_reset (cmdtp, flag, argc, argv);
  39. if (ret == BOOTM_ERR_OVERLAP) {
  40. if (images.legacy_hdr_valid) {
  41. if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
  42. puts ("WARNING: legacy format multi component "
  43. "image overwritten/n");
  44. } else {
  45. puts ("ERROR: new format image overwritten - "
  46. "must RESET the board to recover/n");
  47. show_boot_progress (-113);
  48. do_reset (cmdtp, flag, argc, argv);
  49. }
  50. }
  51. if (ret == BOOTM_ERR_UNIMPLEMENTED) {
  52. if (iflag)
  53. enable_interrupts();
  54. show_boot_progress (-7);
  55. return 1;
  56. }
  57. }
  58. lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));//由於沒有定義CONFIG_LMB,這個函數調用被定義為一個空的宏。
  59. if (images.os.type == IH_TYPE_STANDALONE) {//處理單獨的程序鏡像。顯然引導內核時不會進入這個路徑。
  60. if (iflag)
  61. enable_interrupts();
  62. /* This may return when 'autostart' is 'no' */
  63. bootm_start_standalone(iflag, argc, argv);
  64. return 0;
  65. }
  66. show_boot_progress (8);
  67. boot_fn = boot_os[images.os.os];//根據操作系統的類型獲取引導操作系統的函數, boot_os代碼如下。
  68. if (boot_fn == NULL) {
  69. if (iflag)
  70. enable_interrupts();
  71. printf ("ERROR: booting os '%s' (%d) is not supported/n",
  72. genimg_get_os_name(images.os.os), images.os.os);
  73. show_boot_progress (-8);
  74. return 1;
  75. }
  76. arch_preboot_os();//禁用中斷,重設中斷向量
  77. boot_fn(0, argc, argv, &images);//調用do_bootm_linux,分析在下面。
  78. show_boot_progress (-9);
  79. #ifdef DEBUG
  80. puts ("/n## Control returned to monitor - resetting.../n");
  81. #endif
  82. do_reset (cmdtp, flag, argc, argv);
  83. return 1;
  84. }

2。boot_os

  1. static boot_os_fn *boot_os[] = {
  2. #ifdef CONFIG_BOOTM_LINUX
  3. [IH_OS_LINUX] = do_bootm_linux,
  4. #endif
  5. #ifdef CONFIG_BOOTM_NETBSD
  6. [IH_OS_NETBSD] = do_bootm_netbsd,
  7. #endif
  8. #ifdef CONFIG_LYNXKDI
  9. [IH_OS_LYNXOS] = do_bootm_lynxkdi,
  10. #endif
  11. #ifdef CONFIG_BOOTM_RTEMS
  12. [IH_OS_RTEMS] = do_bootm_rtems,
  13. #endif
  14. #if defined(CONFIG_CMD_ELF)
  15. [IH_OS_VXWORKS] = do_bootm_vxworks,
  16. [IH_OS_QNX] = do_bootm_qnxelf,
  17. #endif
  18. #ifdef CONFIG_INTEGRITY
  19. [IH_OS_INTEGRITY] = do_bootm_integrity,
  20. #endif
  21. };

3。do_bootm_linux
之前所做的引導工作都是與操作系統無關的,接下來都是針對linux 的。
可以看到,參數flag傳過來的是0。

  1. arch/arm/lib/bootm.c
  2. int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
  3. {
  4. bd_t *bd = gd->bd;
  5. char *s;
  6. int machid = bd->bi_arch_number;
  7. void (*theKernel)(int zero, int arch, uint params);
  8. #ifdef CONFIG_CMDLINE_TAG//如果定義了這個宏,將會把bootargs傳給內核。
  9. char *commandline = getenv ("bootargs");//獲取bootargs環境變量。
  10. #endif
  11. if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
  12. return 1;
  13. theKernel = (void (*)(int, int, uint))images->ep;//鏡像的入口地址處也就是需要執行的函數入口
  14. s = getenv ("machid");
  15. if (s) {
  16. machid = simple_strtoul (s, NULL, 16);
  17. printf ("Using machid 0x%x from environment/n", machid);
  18. }
  19. show_boot_progress (15);
  20. debug ("## Transferring control to Linux (at address %08lx) .../n",
  21. (ulong) theKernel);
  22. //下面將會初始化傳給內核的標簽(tag),這些標簽裡包含了必要的環境變量和參數。
  23. #if defined (CONFIG_SETUP_MEMORY_TAGS) || /
  24. defined (CONFIG_CMDLINE_TAG) || /
  25. defined (CONFIG_INITRD_TAG) || /
  26. defined (CONFIG_SERIAL_TAG) || /
  27. defined (CONFIG_REVISION_TAG)
  28. setup_start_tag (bd);
  29. #ifdef CONFIG_SETUP_MEMORY_TAGS
  30. setup_memory_tags (bd);//內存有關的定義
  31. #endif
  32. #ifdef CONFIG_CMDLINE_TAG
  33. setup_commandline_tag (bd, commandline);//將bootargs傳給tag
  34. #endif
  35. #ifdef CONFIG_INITRD_TAG
  36. if (images->rd_start && images->rd_end)//沒有ramdisk所以不會執行這個路徑
  37. setup_initrd_tag (bd, images->rd_start, images->rd_end);
  38. #endif
  39. setup_end_tag (bd);
  40. #endif
  41. /* we assume that the kernel is in place */
  42. printf ("/nStarting kernel .../n/n");//引導內核之前最後一次打印信息。
  43. cleanup_before_linux ();//禁用中斷和cache.
  44. theKernel (0, machid, bd->bi_boot_params);//跳到內核中執行。<<<<全劇終>>>>
  45. /* does not return */
  46. return 1;
  47. }

4.

  1. arch/arm/include/asm
  2. /* The list must start with an ATAG_CORE node */
  3. #define ATAG_CORE 0x54410001
  4. struct tag_core {
  5. u32 flags; /* bit 0 = read-only */
  6. u32 pagesize;
  7. u32 rootdev;
  8. };
  9. /* command line: /0 terminated string */
  10. #define ATAG_CMDLINE 0x54410009
  11. struct tag_cmdline {//bootargs保存在它的後面
  12. char cmdline[1]; /* this is the minimum size */
  13. };
  14. /* describes where the compressed ramdisk image lives (virtual address) */
  15. /*
  16. * this one accidentally used virtual addresses - as such,
  17. * its depreciated.
  18. */
  19. #define ATAG_INITRD 0x54410005
  20. /* describes where the compressed ramdisk image lives (physical address) */
  21. #define ATAG_INITRD2 0x54420005
  22. struct tag_initrd {//描述ramdisk的分布
  23. u32 start; /* physical start address */
  24. u32 size; /* size of compressed ramdisk image in bytes */
  25. };
  26. /* it is allowed to have multiple ATAG_MEM nodes */
  27. #define ATAG_MEM 0x54410002
  28. struct tag_mem32 {
  29. u32 size;
  30. u32 start; /* physical start address */
  31. };
  32. struct tag_header {
  33. u32 size;
  34. u32 tag;
  35. };
  36. struct tag {
  37. struct tag_header hdr;
  38. union {
  39. struct tag_core core;
  40. struct tag_mem32 mem;
  41. struct tag_videotext videotext;
  42. struct tag_ramdisk ramdisk;
  43. struct tag_initrd initrd;
  44. struct tag_serialnr serialnr;
  45. struct tag_revision revision;
  46. struct tag_videolfb videolfb;
  47. struct tag_cmdline cmdline;
  48. /*
  49. * Acorn specific
  50. */
  51. struct tag_acorn acorn;
  52. /*
  53. * DC21285 specific
  54. */
  55. struct tag_memclk memclk;
  56. } u;
  57. };

5

  1. arch/arm/include/asm/setup.h
  2. #define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))//跳到下一個tag地址處
  3. arch/arm/lib/bootm.c
  4. static void setup_start_tag (bd_t *bd)
  5. {
  6. params = (struct tag *) bd->bi_boot_params; //CFG_ENV_ADDR(0x80000100)設置環境變量的頭地址。
  7. params->hdr.tag = ATAG_CORE; //第一個tag默認為 tag_core。ATAG_CORE 是默認的開始類型。
  8. params->hdr.size = tag_size (tag_core);
  9. params->u.core.flags = 0;
  10. params->u.core.pagesize = 0;
  11. params->u.core.rootdev = 0;
  12. params = tag_next (params); //跳到下一個tag地址處
  13. }
  14. #ifdef CONFIG_SETUP_MEMORY_TAGS
  15. static void setup_memory_tags (bd_t *bd)//設置內存分布的tag
  16. {
  17. int i;
  18. for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {//如果有多個內存芯片,則會循環多次。對3250來說,只有一片。
  19. params->hdr.tag = ATAG_MEM;
  20. params->hdr.size = tag_size (tag_mem32);
  21. params->u.mem.start = bd->bi_dram[i].start;//內存塊的開始地址。PHYS_SDRAM_1;在smartarm3250.h中,起始地址(0x80000000)
  22. params->u.mem.size = bd->bi_dram[i].size;//內存塊的大小
  23. params = tag_next (params);//跳到下一個tag地址處
  24. }
  25. }
  26. #endif /* CONFIG_SETUP_MEMORY_TAGS */
  27. static void setup_commandline_tag (bd_t *bd, char *commandline)
  28. {
  29. char *p;
  30. if (!commandline)
  31. return;
  32. /* eat leading white space */
  33. for (p = commandline; *p == ' '; p++);//跳過開頭的空格
  34. /* skip non-existent command lines so the kernel will still
  35. * use its default command line.
  36. */
  37. if (*p == '/0')
  38. return;
  39. params->hdr.tag = ATAG_CMDLINE;
  40. params->hdr.size =
  41. (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
  42. strcpy (params->u.cmdline.cmdline, p);//將bootargs復制到cmdline後面。
  43. params = tag_next (params);//跳到下一個tag地址處
  44. }
  45. #ifdef CONFIG_INITRD_TAG
  46. static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end)
  47. {
  48. /* an ATAG_INITRD node tells the kernel where the compressed
  49. * ramdisk can be found. ATAG_RDIMG is a better name, actually.
  50. */
  51. params->hdr.tag = ATAG_INITRD2;
  52. params->hdr.size = tag_size (tag_initrd);
  53. params->u.initrd.start = initrd_start;
  54. params->u.initrd.size = initrd_end - initrd_start;
  55. params = tag_next (params);
  56. }
  57. #endif /* CONFIG_INITRD_TAG */
  58. static void setup_end_tag (bd_t *bd)
  59. {
  60. params->hdr.tag = ATAG_NONE;//最後一個tag是一個空類型,標志這tag的結束。
  61. params->hdr.size = 0;
  62. }

Copyright © Linux教程網 All Rights Reserved