歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

uboot從bootm跳到內核

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 (*)(intint, 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