在 u-boot shell 中 可以吃的 kernel image 是 uImage, 剛好綱哥他們那一個平台的 可以吃 zImage 因為好奇 所以稍微 trace 一下.
<Trace>
首先我們來來看一下 u-boot header 那 64 bytes 有啥東西...
@include/image.h
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */
uint32_t ih_ep; /* Entry Point Address */
uint32_t ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
typedef struct bootm_headers {
/*
* Legacy os image header, if it is a multi component image
* then boot_get_ramdisk() and get_fdt() will attempt to get
* data from second and third component accordingly.
*/
image_header_t *legacy_hdr_os; /* image header pointer */
image_header_t legacy_hdr_os_copy; /* header copy */
ulong legacy_hdr_valid;
<... 略>
int verify; /* getenv("verify")[0] != 'n' */
struct lmb *lmb; /* for memory mgmt */
} bootm_headers_t;
@common/cmd_bootm.c
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
在這一個 function 裡 其實註解寫的很清楚
/**
* boot_get_kernel - find kernel image
* @os_data: pointer to a ulong variable, will hold os data start address
* @os_len: pointer to a ulong variable, will hold os data length
*
* boot_get_kernel() tries to find a kernel image, verifies its integrity
* and locates kernel data.
*
* returns:
* pointer to image header if valid image was found, plus kernel start
* address and length, otherwise NULL
*/
/* get kernel image header, start address and length */
os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,
&images, &os_data, &os_len);
在 boot_get_kernel 中
1 - 會去 parse 由 u-boot shell 中 tftp 0x2000000 uImage 的 0x2000000 轉存成變數 img_addr
2 - 透過 image_get_kernel 中 將 header (64 bytes) copy legacy_hdr_os_copy
3 - return img_addr
仔細看一下 傳入的 os_data 在這個 boot_get_kernel function 中是會把 64 bytes 的 u-boot header shift 掉的. ( *os_data = image_get_data (hdr) )
接下來
... 略
case IH_COMP_NONE:
if (load_start == (ulong)os_hdr) {
printf (" XIP %s ... ", type_name);
} else {
memmove_wd ((void *)load_start,
(void *)os_data, os_len, CHUNKSZ);
/* 會將 os_data 整個搬到 load_start(0x8000) depends on the architecture */
}
load_end = (load_start) + os_len;
puts("OK\n");
break;
... 略
整個完成後 在呼叫
do_bootm_linux (cmdtp, flag, argc, argv, &images);
上面這一個 function 是一個靜態的.a檔會 based on your architecture 而包進來的 (我的是arm)
所以會在這個 folder 下
@lib_arm/bootm.c
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
bootm_headers_t *images)
{
... 略
if (images->legacy_hdr_valid) {
ep = image_get_ep (&images->legacy_hdr_os_copy);
/* 將由 剛剛搬到的 memory address (0x8000) 指定給 ep */
... 略
theKernel = (void (*)(int, int, uint))ep;
... 略
cleanup_before_linux ();
/* transfer control to the kernel */
theKernel (0, machid, bd->bi_boot_params);
/* does not return */
}
<實作>
那如果我要讓 zImage 也能開機要怎麼做呢?
1. modify common/cmd_bootm.c
將 do_bootm_linux (cmdtp, flag, argc, argv, &images); 加在變數宣告的下面. 只是單純的不讓它去 parse header.
2 . modify lib_arm/bootm.c
do_bootm_linux
... 略
/* find kernel entry point */
if (images->legacy_hdr_valid) {
ep = image_get_ep (&images->legacy_hdr_os_copy)
printf("ep=%x\n\n", ep);
#if defined(CONFIG_FIT)
} else if (images->fit_uname_os) {
ret = fit_image_get_entry (images->fit_hdr_os,
images->fit_noffset_os, &ep);
if (ret) {
puts ("Can't get entry point property!\n");
goto error;
}
#endif
} else {
ep = CFG_LOAD_ADDR;
//puts ("Could not find kernel entry point!\n");
//goto error;
}
... 略
這樣就可以了
CFG_LOAD_ADDR 這個 load 位置是 0x2000000 不過我有試著將它換到 0x8000 也是可以的 我目前還沒有辦法明確的解釋這個 address 知道的人可以share一下喔 ^^
留言列表