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

uboot分析之bootm_start

bootm命令執行過程中調用了bootm_start函數,這個函數比較重要,所以先分析它。

1.common/cmd_bootm.c

 

  1. static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  
  2. {  
  3.     void        *os_hdr;  
  4.     int     ret;  
  5.     memset ((void *)&images, 0, sizeof (images));//images是一個bootm_headers_t類型的全局變量。見下面的分析。   
  6.     images.verify = getenv_yesno ("verify");//從環境變量中檢查是否要對鏡像的數據(不是鏡像頭)進行校驗。   
  7.     bootm_start_lmb();//不做任何有意義的工作,除了定義# define lmb_reserve(lmb, base, size)   
  8.     /* get kernel image header, start address and length */尋找可用的內核鏡像,見下面的分析。主要根據傳入的參數檢查鏡像的合法性並獲取信息。  
  9.     os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,  
  10.             &images, &images.os.image_start, &images.os.image_len);//返回指向內存中鏡像頭的指針   
  11.     if (images.os.image_len == 0) {  
  12.         puts ("ERROR: can't get kernel image!/n");  
  13.         return 1;  
  14.     }  
  15.     /* get image parameters */  
  16.     switch (genimg_get_format (os_hdr)) {//根據鏡像魔數獲取鏡像類型   
  17.     case IMAGE_FORMAT_LEGACY:  
  18.         images.os.type = image_get_type (os_hdr);//鏡像類型   
  19.         images.os.comp = image_get_comp (os_hdr);//壓縮類型   
  20.         images.os.os = image_get_os (os_hdr);//操作系統類型   
  21.         images.os.end = image_get_image_end (os_hdr);//當前鏡像的尾地址   
  22.         images.os.load = image_get_load (os_hdr);//鏡像數據的載入地址   
  23.         break;  
  24.     default:  
  25.         puts ("ERROR: unknown image format type!/n");  
  26.         return 1;  
  27.     }  
  28.     /* find kernel entry point */  
  29.     if (images.legacy_hdr_valid) {//如果鏡像已經通過驗證   
  30.         images.ep = image_get_ep (&images.legacy_hdr_os_copy);//獲取入口地址,填充images.ep 。   
  31.     } else {  
  32.         puts ("Could not find kernel entry point!/n");  
  33.         return 1;  
  34.     }  
  35.     if (((images.os.type == IH_TYPE_KERNEL) ||  
  36.          (images.os.type == IH_TYPE_MULTI)) &&  
  37.         (images.os.os == IH_OS_LINUX)) {  
  38.         /* find ramdisk */3250的配置中這個函數不做任何工作  
  39.         ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,  
  40.                 &images.rd_start, &images.rd_end);  
  41.         if (ret) {  
  42.             puts ("Ramdisk image is corrupt or invalid/n");  
  43.             return 1;  
  44.         }  
  45.     }  
  46.     images.os.start = (ulong)os_hdr;//指向內存中鏡像的頭地址   
  47.     images.state = BOOTM_STATE_START;//標記引導狀態   
  48.     return 0;  
  49. }  
 

總結一下這個函數的主要工作:第一步校驗鏡像的正確性,獲取鏡像的信息(根據鏡像頭),第二部將第一步獲取的信息存入images(主要是填充image_info_t類型的os成員)

2. bootm_headers_t

 

  1. typedef struct bootm_headers {  
  2.     /* 
  3.      * Legacy os image header, if it is a multi component image 
  4.      * then boot_get_ramdisk() and get_fdt() will attempt to get 
  5.      * data from second and third component accordingly. 
  6.      */  
  7.     image_header_t    *legacy_hdr_os;        /* image header pointer */  
  8.     image_header_t    legacy_hdr_os_copy;    /* header copy */  
  9.     ulong        legacy_hdr_valid;  
  10. #ifndef USE_HOSTCC   
  11.     image_info_t    os;        /* os image info */  
  12.     ulong        ep;        /* entry point of OS */  
  13.     ulong        rd_start, rd_end;/* ramdisk start/end */  
  14.     ulong        ft_len;        /* length of flat device tree */  
  15.     ulong        initrd_start;  
  16.     ulong        initrd_end;  
  17.     ulong        cmdline_start;  
  18.     ulong        cmdline_end;  
  19.     bd_t        *kbd;  
  20. #endif   
  21.     int        verify;        /* getenv("verify")[0] != 'n' */  
  22. #define    BOOTM_STATE_START        (0x00000001)   
  23. #define    BOOTM_STATE_LOADOS        (0x00000002)   
  24. #define    BOOTM_STATE_RAMDISK    (0x00000004)   
  25. #define    BOOTM_STATE_FDT        (0x00000008)   
  26. #define    BOOTM_STATE_OS_CMDLINE    (0x00000010)   
  27. #define    BOOTM_STATE_OS_BD_T    (0x00000020)   
  28. #define    BOOTM_STATE_OS_PREP    (0x00000040)   
  29. #define    BOOTM_STATE_OS_GO        (0x00000080)   
  30.     int        state;  
  31. } bootm_headers_t;  
  32. /* 
  33.  * Legacy format image header, 
  34.  * all data in network byte order (aka natural aka bigendian). 
  35.  */內核鏡像頭  include/image.h  
  36. typedef struct image_header {  
  37.     uint32_t    ih_magic;        /* Image Header Magic Number    */鏡像頭部幻數,為#define IH_MAGIC    0x27051956  
  38.     uint32_t    ih_hcrc;            /* Image Header CRC Checksum    */鏡像頭部crc校驗碼  
  39.     uint32_t    ih_time;            /* Image Creation Timestamp    */鏡像創建時間戳  
  40.     uint32_t    ih_size;            /* Image Data Size        */鏡像數據大小(不算頭部)1828536  
  41.     uint32_t    ih_load;            /* Data     Load  Address        */數據將要載入的內存地址   80008000  
  42.     uint32_t    ih_ep;            /* Entry Point Address        */鏡像入口地址        80008000             
  43.     uint32_t    ih_dcrc;            /* Image Data CRC Checksum    */鏡像數據校驗碼  
  44.     uint8_t        ih_os;        /* Operating System        */操作系統類型    #define IH_OS_LINUX        5  
  45.     uint8_t        ih_arch;        /* CPU architecture        */CPU架構類型    #define IH_ARCH_ARM        2  
  46.     uint8_t        ih_type;        /* Image Type            */鏡像類型        IH_TYPE_KERNEL  
  47.     uint8_t        ih_comp;    /* Compression Type        */壓縮類型        IH_COMP_NONE  
  48.     uint8_t        ih_name[IH_NMLEN];    /* Image Name        */鏡像名字Linux-2.6.27.8,#define IH_NMLEN        32  
  49. } image_header_t;  
  50. 鏡像信息      include/image.h  
  51. typedef struct image_info {  
  52.     ulong        start, end;            /* start/end of blob */鏡像的起始地址和尾地址  
  53.     ulong        image_start, image_len;         /* start of image within blob, len of image */鏡像數據的開始地址和長度  
  54.     ulong        load;                /* load addr for the image */鏡像數據的裝載地址  
  55.     uint8_t        comp, type, os;            /* compression, type of image, os type */壓縮類型,鏡像類型和操作系統類型  
  56. } image_info_t;  
 

3。boot_get_kernel

 

  1. /** 
  2.  * boot_get_kernel - find kernel image 
  3.  * @os_data: pointer to a ulong variable, will hold os data start address 
  4.  * @os_len: pointer to a ulong variable, will hold os data length 
  5.  * 
  6.  * boot_get_kernel() tries to find a kernel image, verifies its integrity 
  7.  * and locates kernel data. 
  8.  * 
  9.  * returns: 
  10.  *     pointer to image header if valid image was found, plus kernel start 
  11.  *     address and length, otherwise NULL 
  12.  */  
  13. 尋找可用的內核鏡像  
  14. static void *boot_get_kernel (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],  
  15.         bootm_headers_t *images, ulong *os_data, ulong *os_len)  
  16. {  
  17.     image_header_t    *hdr;  
  18.     ulong        img_addr;  
  19.     /* find out kernel image address */  
  20.     if (argc < 2) {//如果參數太少   
  21.         img_addr = load_addr;    //使用默認的鏡像載入地址,這個地址是在配置頭文件中定義的 ulong load_addr = CONFIG_SYS_LOAD_ADDR;   
  22.         debug ("*  kernel: default image load address = 0x%08lx/n",  
  23.                 load_addr);  
  24.     } else {  
  25.         img_addr = simple_strtoul(argv[1], NULL, 16);//參數足夠的話,把第二個參數轉化為16進制作為地址   
  26.         debug ("*  kernel: cmdline image address = 0x%08lx/n", img_addr);  
  27.     }  
  28.     show_boot_progress (1);  
  29.     /* copy from dataflash if needed */  
  30.     img_addr = genimg_get_image (img_addr);//對於3250,這個函數什麼都沒做。因為沒有dataflash.   
  31.     /* check image type, for FIT images get FIT kernel node */  
  32.     *os_data = *os_len = 0;  
  33.     switch (genimg_get_format ((void *)img_addr)) {//根據上面得到的鏡像的地址,獲取鏡像的類型。這個函數根據鏡像頭部的魔數返回類型。   
  34.     case IMAGE_FORMAT_LEGACY:  
  35.         printf ("## Booting kernel from Legacy Image at %08lx .../n",   //打印引導消息   
  36.                 img_addr);  
  37.         hdr = image_get_kernel (img_addr, images->verify);//檢驗鏡像的合法性(校驗碼、魔數、架構類型等),並打印信息。見下面的分析。   
  38.         if (!hdr)  
  39.             return NULL;  
  40.         show_boot_progress (5);  
  41.         /* get os_data and os_len */  
  42.         switch (image_get_type (hdr)) {  
  43.         case IH_TYPE_KERNEL:  
  44.             *os_data = image_get_data (hdr);//鏡像數據的地址,也就是緊挨著鏡像頭的地址。   
  45.             *os_len = image_get_data_size (hdr);//鏡像數據部分大小   
  46.             break;  
  47.         case IH_TYPE_MULTI:  
  48.             image_multi_getimg (hdr, 0, os_data, os_len);  
  49.             break;  
  50.         case IH_TYPE_STANDALONE:  
  51.             *os_data = image_get_data (hdr);  
  52.             *os_len = image_get_data_size (hdr);  
  53.             break;  
  54.         default:  
  55.             printf ("Wrong Image Type for %s command/n", cmdtp->name);  
  56.             show_boot_progress (-5);  
  57.             return NULL;  
  58.         }  
  59.         /* 
  60.          * copy image header to allow for image overwrites during kernel 
  61.          * decompression. 
  62.          */拷貝一份鏡像的頭部到images中。  
  63.         memmove (&images->legacy_hdr_os_copy, hdr, sizeof(image_header_t));  
  64.         /* save pointer to image header */  
  65.         images->legacy_hdr_os = hdr;//images中指針指向鏡像的頭部   
  66.         images->legacy_hdr_valid = 1;//鏡像已經檢驗合格,置標志量   
  67.         show_boot_progress (6);  
  68.         break;  
  69.     default:  
  70.         printf ("Wrong Image Format for %s command/n", cmdtp->name);  
  71.         show_boot_progress (-108);  
  72.         return NULL;  
  73.     }  
  74.     debug ("   kernel data at 0x%08lx, len = 0x%08lx (%ld)/n",  
  75.             *os_data, *os_len, *os_len);  
  76.     return (void *)img_addr;  
  77. }  
 

4。image_get_kernel

 

  1. common/cmd_bootm.c  
  2. static image_header_t *image_get_kernel (ulong img_addr, int verify)  
  3. {  
  4.     image_header_t *hdr = (image_header_t *)img_addr;  
  5.     if (!image_check_magic(hdr)) {    //檢查鏡像頭部的魔數是否等於 IH_MAGIC   
  6.         puts ("Bad Magic Number/n");  
  7.         show_boot_progress (-1);  
  8.         return NULL;  
  9.     }  
  10.     show_boot_progress (2);  
  11.     if (!image_check_hcrc (hdr)) {//檢查鏡像頭部的校驗碼(hcrc為0時鏡像頭的校驗碼)   
  12.         puts ("Bad Header Checksum/n");  
  13.         show_boot_progress (-2);  
  14.         return NULL;  
  15.     }  
  16.     show_boot_progress (3);  
  17.     image_print_contents (hdr);//根據傳入的鏡像頭地址,打印鏡像的信息,見下面的分析。   
  18. /* 
  19.    Image Name:   Linux-2.6.27.8 
  20.    Image Type:   ARM Linux Kernel Image (uncompressed) 
  21.    Data Size:    1828536 Bytes = 1.7 MiB 
  22.    Load Address: 80008000 
  23.    Entry Point:  80008000 
  24. */  
  25.     if (verify) {//是否要對鏡像的數據部分進行校驗   
  26.         puts ("   Verifying Checksum ... ");  
  27.         if (!image_check_dcrc (hdr)) {  
  28.             printf ("Bad Data CRC/n");  
  29.             show_boot_progress (-3);  
  30.             return NULL;  
  31.         }  
  32.         puts ("OK/n");  
  33.     }  
  34.     show_boot_progress (4);  
  35.     if (!image_check_target_arch (hdr)) {//檢查是否是IH_ARCH_ARM架構   
  36.         printf ("Unsupported Architecture 0x%x/n", image_get_arch (hdr));  
  37.         show_boot_progress (-4);  
  38.         return NULL;  
  39.     }  
  40.     return hdr;  
  41. }  
 

Copyright © Linux教程網 All Rights Reserved