歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> uboot分析之bootm_start

uboot分析之bootm_start

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

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