U-Boot
U-Boot,全稱 Universal Boot Loader,是遵循GPL條款的開放源碼項目。U-Boot的作用是系統(tǒng)引導。U-Boot從FADSROM、8xxROM、PPCBOOT逐步發(fā)展演化而來。其源碼目錄、編譯形式與Linux內核很相似,事實上,不少U-Boot源碼就是根據(jù)相應的Linux內核源程序進行簡化而形成的,尤其是一些設備的驅動程序,這從U-Boot源碼的注釋中能體現(xiàn)這一點。
U-Boot不僅僅支持嵌入式Linux系統(tǒng)的引導,它還支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS, android嵌入式操作系統(tǒng)。其目前要支持的目標操作系統(tǒng)是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux, SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX, RTEMS, ARTOS, android。這是U-Boot中Universal的一層含義,另外一層含義則是U-Boot除了支持PowerPC系列的處理器外,還能支持MIPS、 x86、ARM、NIOS、XScale等諸多常用系列的處理器。
這兩個特點正是U-Boot項目的開發(fā)目標,即支持盡可能多的嵌入式處理器和嵌入式操作系統(tǒng)。就目前來看,U-Boot對PowerPC系列處理器支持最為豐富,對Linux的支持最完善。其它系列的處理器和操作系統(tǒng)基本是在2002年11 月PPCBOOT改名為U-Boot后逐步擴充的。從PPCBOOT向U-Boot的順利過渡,很大程度上歸功于U-Boot的維護人德國DENX軟件工程中心Wolfgang Denk[以下簡稱W.D]本人精湛專業(yè)水平和執(zhí)著不懈的努力。當前,U-Boot項目正在他的領軍之下,眾多有志于開放源碼BOOT LOADER移植工作的嵌入式開發(fā)人員正如火如荼地將各個不同系列嵌入式處理器的移植工作不斷展開和深入,以支持更多的嵌入式操作系統(tǒng)的裝載與引導。
uboot啟動流程分析
可知程序的入口在_start,在SourceInsight中查找可發(fā)現(xiàn)程序的入口_start在u-boot-2016.05\arch\arm\lib\vectors.S中。
。。。
ENTRY(_start)
SECTIONS
{
。。。
。 = 0x00000000;
。 = ALIGN(4);
.text :
{
*(.__image_copy_start)
*(.vectors)
CPUDIR/start.o (.text*)
*(.text*)
}
。。。
。 = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
。 = ALIGN(4);
.data : {
*(.data*)
}
。 = ALIGN(4);
。 = 。;
。。。
.bss_start __rel_dyn_start (OVERLAY) : {
KEEP(*(.__bss_start));
__bss_base = 。;
}
.bss __bss_base (OVERLAY) : {
*(.bss*)
。 = ALIGN(4);
__bss_limit = 。;
}
.bss_end __bss_limit (OVERLAY) : {
KEEP(*(.__bss_end));
}
。。。
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
進入boot-2016.05\arch\arm\lib\vectors.S中,可以看到從_start開始后就跳轉到reset去執(zhí)行:
。。。
.globl _start
。。。
_start:
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
.word CONFIG_SYS_DV_NOR_BOOT_CFG
#endif
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
。。.12345678910111213141516171819202122
1、從u-boot-2016.05\arch\arm\cpu\arm920t\start.S中reset執(zhí)行
主要執(zhí)行流程:reset -》 cpu_init_crit -》 lowlevel_init -》 _main
reset:
。。。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
bl _main
。。。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
。。。
bl lowlevel_init
。。。
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
1234567891011121314151617181920212223
2、由bl _main跳轉到u-boot-2016.05\arch\arm\lib\crt0.S中從入口_main開始執(zhí)行
主要執(zhí)行流程:board_init_f -》 relocate_code -》 board_init_r
ENTRY(_main)
。。。
bl board_init_f_alloc_reserve
。。。
bl board_init_f_init_reserve
。。。
bl board_init_f
#if ! defined(CONFIG_SPL_BUILD)
。。。
b relocate_code
。。。
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
。。。
#if defined(CONFIG_SYS_THUMB_BUILD)
。。。
#else
ldr pc, =board_init_r
#endif
#endif
ENDPROC(_main)123456789101112131415161718192021222324252627282930313233
這部分有三點說明:
?、拧-boot-2016.05\common\board_f.c:board_init_f通過initcall_run_list(init_sequence_f)函數(shù)執(zhí)行一系列初始化函數(shù)以實現(xiàn)前半部分板級初始化。全局結構體gd在u-boot-2016.05\arch\arm\include\asm\global_data.h中聲明:
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm (“r9”)1
?、啤-boot-2016.05\arch\arm\lib\relocate.S:relocate_code實現(xiàn)uboot代碼的重定位,此部分如果覺得源代碼不是簡單明了可自己改寫。
?、?、去重定位uboot有兩種路徑:
一種是將gd-》flags設為0,在初始化函數(shù)序列init_sequence_f中的jump_to_copy函數(shù)中去跳轉到relocate_code:
static int jump_to_copy(void)
{
if (gd-》flags & GD_FLG_SKIP_RELOC)
return 0;
。。。
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
。。。
#else
relocate_code(gd-》start_addr_sp, gd-》new_gd, gd-》relocaddr);
#endif
return 0;
}1234567891011121314
另一種就是不宏定義CONFIG_SPL_BUILD,然后在u-boot-2016.05\arch\arm\lib\crt0.S中通過
#if ! defined(CONFIG_SPL_BUILD)
。。。
b relocate_code
。。。
#endif123456789
來跳轉到relocate_code。以上兩種方法選其一,另一種就得去掉。
3、在上一步通過ldr pc, =board_init_r指令進入u-boot-2016.05\common\board_r.c:board_init_r函數(shù),進而調用initcall_run_list(init_sequence_r)函數(shù)執(zhí)行一系列初始化函數(shù)以實現(xiàn)后半部分板級初始化,并在initcall_run_list函數(shù)里進入run_main_loop不再返回。
void board_init_r(gd_t *new_gd, ulong dest_addr)
{
。。。
if (initcall_run_list(init_sequence_r))
hang();
/* NOTREACHED - run_main_loop() does not return */
hang();
}
1234567891011
init_sequence_r是一個函數(shù)指針數(shù)組,里面存放了很多初始化函數(shù)指針,里面有兩個重要的函數(shù)指針initr_announce和run_main_loop:
init_fnc_t init_sequence_r[] = {
。。。
initr_announce,
。。。
run_main_loop,
};12345678910
initr_announce函數(shù)聲明從此處開始程序就將跳轉到RAM中運行:
static int initr_announce(void)
{
debug(“Now running in RAM - U-Boot at: %08lx\n”, gd-》relocaddr);
return 0;
}12345
最后一項是run_main_loop ,進入run_main_loop 后便不再返回。
4、在run_main_loop 里會進入u-boot-2016.05\common\main.c:main_loop函數(shù)
static int run_main_loop(void)
{
。。。
for (;;)
main_loop();
return 0;
}12345678
進入main_loop之前就已經(jīng)完成初始化,接下來準備去處理命令
/* We come here after U-Boot is initialised and ready to process commands */
void main_loop(void)
{
const char *s;
bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, “main_loop”);
。。。
/* get environment_variable: s = getenv(“bootcmd”); -》 bootcmd */
s = bootdelay_process();
。。。
autoboot_command(s);
。。。
}123456789101112131415161718
main_loop函數(shù)里有兩個重要的過程:
?、?、首先在bootdelay_process函數(shù)里通過s = getenv(“bootcmd”)得到bootcmd參數(shù)并返回bootcmd參數(shù),
const char *bootdelay_process(void)
{
char *s;
int bootdelay;
。。。
s = getenv(“bootdelay”);
。。。
debug(“### main_loop entered: bootdelay=%d\n\n”, bootdelay);
。。。
s = getenv(“bootcmd”);
。。。
stored_bootdelay = bootdelay;
return s;
}1234567891011121314151617181920212223
其中,bootcmd參數(shù)通過以下方式指定:
先在u-boot-2016.05\include\env_default.h中
#ifdef CONFIG_BOOTCOMMAND
“bootcmd=” CONFIG_BOOTCOMMAND “\0”
#endif123
再在u-boot-2016.05\include\configs\smdk2440.h中指定
#define CONFIG_BOOTCOMMAND “nand read 30000000 kernel;bootm 30000000”1
?、?、然后進入autoboot_command函數(shù),并將bootcmd參數(shù)傳入,繼而進入run_command_list函數(shù),繼續(xù)將bootcmd參數(shù)傳入
void autoboot_command(const char *s)
{
。。。
if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
。。。
run_command_list(s, -1, 0);
。。。
}
。。。
}
123456789101112
5、從autoboot_command函數(shù)進入u-boot-2016.05\common\cli.c:run_command_list函數(shù)后,接著會調用board_run_command函數(shù)去執(zhí)行命令
int run_command_list(const char *cmd, int len, int flag)
{
int need_buff = 1;
char *buff = (char *)cmd; /* cast away const */
int rcode = 0;
if (len == -1) {
len = strlen(cmd);
#ifdef CONFIG_SYS_HUSH_PARSER
。。。
#else
/* the built-in parser will change our string if it sees \n */
need_buff = strchr(cmd, ‘\n’) != NULL;
#endif
}
if (need_buff) {
buff = malloc(len + 1);
if (!buff)
return 1;
memcpy(buff, cmd, len);
buff[len] = ‘\0’;
}
#ifdef CONFIG_SYS_HUSH_PARSER
。。。
#ifdef CONFIG_CMDLINE
。。。
#else
rcode = board_run_command(buff);
#endif
#endif
。。。
}1234567891011121314151617181920212223242526272829303132
那么,board_run_command如何去執(zhí)行命令?
首先,board_run_command函數(shù)通過bootcmd參數(shù)中的bootm命令找到u-boot-2016.05\cmd\bootm.c中的
U_BOOT_CMD(
bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,
“boot application image from memory”, bootm_help_text
);1234
然后,根據(jù)這個信息找到執(zhí)行bootm命令的處理函數(shù)指針do_bootm,并進入do_bootm函數(shù)執(zhí)行相關代碼,而U_BOOT_CMD在u-boot-2016.05\include\command.h中定義:
#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)12
#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, \
_comp) \
_CMD_REMOVE(sub_ ## _name, _cmd)123
#define _CMD_REMOVE(_name, _cmd) \
int __remove_ ## _name(void) \
{ \
if (0) \
_cmd(NULL, 0, 0, NULL); \
return 0; \
}1234567
在此,board_run_command函數(shù)還會將bootm命令中的參數(shù)(內核映像所在地址)30000000賦給bootm_headers_t結構體變量images,則images首地址就是30000000,images在u-boot-2016.05\cmd\bootm.c中定義:
bootm_headers_t images; 1
6、根據(jù)U_BOOT_CMD信息進入u-boot-2016.05\cmd\bootm.c:do_bootm函數(shù)
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
。。。
return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START |
BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER |
BOOTM_STATE_LOADOS |
#if defined(CONFIG_PPC) || defined(CONFIG_MIPS)
BOOTM_STATE_OS_CMDLINE |
#endif
BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
BOOTM_STATE_OS_GO, &images, 1);
}
1234567891011121314
其中BOOTM_STATE_START 、BOOTM_STATE_FINDOS 、BOOTM_STATE_FINDOTHER 、BOOTM_STATE_LOADOS 、BOOTM_STATE_OS_PREP 、BOOTM_STATE_OS_FAKE_GO 這些在u-boot-2016.05\include\image.h中bootm_headers結構體中指定:
#define BOOTM_STATE_START (0x00000001)
#define BOOTM_STATE_FINDOS (0x00000002)
#define BOOTM_STATE_FINDOTHER (0x00000004)
#define BOOTM_STATE_LOADOS (0x00000008)
#define BOOTM_STATE_RAMDISK (0x00000010)
#define BOOTM_STATE_FDT (0x00000020)
#define BOOTM_STATE_OS_CMDLINE (0x00000040)
#define BOOTM_STATE_OS_BD_T (0x00000080)
#define BOOTM_STATE_OS_PREP (0x00000100)
#define BOOTM_STATE_OS_FAKE_GO (0x00000200) /* ‘Almost’ run the OS */
#define BOOTM_STATE_OS_GO (0x00000400)1234567891011
7、從do_bootm進入u-boot-2016.05\common\bootm.c:do_bootm_states函數(shù),Now run the OS!
int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int states, bootm_headers_t *images, int boot_progress)
{
boot_os_fn *boot_fn;
ulong iflag = 0;
int ret = 0, need_boot_fn;
images-》state |= states;
/*
* Work through the states and see how far we get. We stop on
* any error.
*/
if (states & BOOTM_STATE_START)
ret = bootm_start(cmdtp, flag, argc, argv);
if (!ret && (states & BOOTM_STATE_FINDOS))
ret = bootm_find_os(cmdtp, flag, argc, argv);
if (!ret && (states & BOOTM_STATE_FINDOTHER)) {
ret = bootm_find_other(cmdtp, flag, argc, argv);
argc = 0; /* consume the args */
}
/* Load the OS */
if (!ret && (states & BOOTM_STATE_LOADOS)) {
ulong load_end;
iflag = bootm_disable_interrupts();
ret = bootm_load_os(images, &load_end, 0);
if (ret == 0)
lmb_reserve(&images-》lmb, images-》os.load,
?。╨oad_end - images-》os.load));
else if (ret && ret != BOOTM_ERR_OVERLAP)
goto err;
else if (ret == BOOTM_ERR_OVERLAP)
ret = 0;
#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY)
if (images-》os.os == IH_OS_LINUX)
fixup_silent_linux();
#endif
}
/* Relocate the ramdisk */
#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH
if (!ret && (states & BOOTM_STATE_RAMDISK)) {
ulong rd_len = images-》rd_end - images-》rd_start;
ret = boot_ramdisk_high(&images-》lmb, images-》rd_start,
rd_len, &images-》initrd_start, &images-》initrd_end);
if (!ret) {
setenv_hex(“initrd_start”, images-》initrd_start);
setenv_hex(“initrd_end”, images-》initrd_end);
}
}
#endif
#if IMAGE_ENABLE_OF_LIBFDT && defined(CONFIG_LMB)
if (!ret && (states & BOOTM_STATE_FDT)) {
boot_fdt_add_mem_rsv_regions(&images-》lmb, images-》ft_addr);
ret = boot_relocate_fdt(&images-》lmb, &images-》ft_addr,
&images-》ft_len);
}
#endif
/* From now on, we need the OS boot function */
if (ret)
return ret;
boot_fn = bootm_os_get_boot_func(images-》os.os);
need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE |
BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP |
BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO);
if (boot_fn == NULL && need_boot_fn) {
if (iflag)
enable_interrupts();
printf(“ERROR: booting os ‘%s’ (%d) is not supported\n”,
genimg_get_os_name(images-》os.os), images-》os.os);
bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS);
return 1;
}
/* Call various other states that are not generally used */
if (!ret && (states & BOOTM_STATE_OS_CMDLINE))
ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images);
if (!ret && (states & BOOTM_STATE_OS_BD_T))
ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images);
if (!ret && (states & BOOTM_STATE_OS_PREP))
ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images);
#ifdef CONFIG_TRACE
/* Pretend to run the OS, then run a user command */
if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) {
char *cmd_list = getenv(“fakegocmd”);
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO,
images, boot_fn);
if (!ret && cmd_list)
ret = run_command_list(cmd_list, -1, flag);
}
#endif
/* Check for unsupported subcommand. */
if (ret) {
puts(“subcommand not supported\n”);
return ret;
}
/* Now run the OS! We hope this doesn‘t return */
if (!ret && (states & BOOTM_STATE_OS_GO))
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
images, boot_fn);
/* Deal with any fallout */
err:
if (iflag)
enable_interrupts();
if (ret == BOOTM_ERR_UNIMPLEMENTED)
bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL);
else if (ret == BOOTM_ERR_RESET)
do_reset(cmdtp, flag, argc, argv);
return ret;
}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
do_bootm_states函數(shù)總共分8個部分:
?、拧?Work through the states and see how far we get. We stop on any error.
其中主要函數(shù)bootm_find_os實現(xiàn)三個功能:get kernel image header, start address and length,get image parameters。大概過程是:bootm_find_os -》 boot_get_kernel -》 image_get_kernel 。
static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
const void *os_hdr;
bool ep_found = false;
int ret;
/* get kernel image header, start address and length */
os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
&images, &images.os.image_start, &images.os.image_len);
。。。
/* get image parameters */
switch (genimg_get_format(os_hdr)) {
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
case IMAGE_FORMAT_LEGACY: /*舊系統(tǒng)格式的內核映像*/
images.os.type = image_get_type(os_hdr);
images.os.comp = image_get_comp(os_hdr);
images.os.os = image_get_os(os_hdr);
images.os.end = image_get_image_end(os_hdr);
images.os.load = image_get_load(os_hdr);
images.os.arch = image_get_arch(os_hdr);
break;
#endif
#if IMAGE_ENABLE_FIT
case IMAGE_FORMAT_FIT:
。。。
#endif
#ifdef CONFIG_ANDROID_BOOT_IMAGE
case IMAGE_FORMAT_ANDROID:
。。。
#endif
default:
puts(“ERROR: unknown image format type!\n”);
return 1;
}
。。。
if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
images.os.load = images.os.image_start;
images.ep += images.os.load;
}
。。.123456789101112131415161718192021222324252627282930313233343536373839404142434445
關于boot_get_kernel 、image_get_kernel 的說明:
boot_get_kernel - find kernel image(returns:
pointer to image header if valid image was found, plus kernel start address and length, otherwise NULL)
image_get_kernel - verify legacy format kernel image(returns:
pointer to a legacy image header if valid image was found otherwise return NULL)
?、啤oad the OS
?、?、Relocate the ramdisk
⑷、From now on, we need the OS boot function
由boot_fn = bootm_os_get_boot_func(images-》os.os);得到boot處理函數(shù)指針并賦給boot_fn。
?、?、關于參數(shù)images-》os.os,可以由下列定義得知它是系統(tǒng)內核的類型,并在(2)中被賦值,若系統(tǒng)類型為linux,則images-》os.os=5。
typedef struct bootm_headers {
。。。
#ifndef USE_HOSTCC /*USE_HOSTCC 沒有宏定義*/
image_info_t os; /* os image info */
ulong ep; /* entry point of OS */
ulong rd_start, rd_end;/* ramdisk start/end */
char *ft_addr; /* flat dev tree address */
ulong ft_len; /* length of flat device tree */
ulong initrd_start;
ulong initrd_end;
ulong cmdline_start;
ulong cmdline_end;
bd_t *kbd;
#endif
。。。
} bootm_headers_t;1234567891011121314151617181920212223
bootm_headers_t images;1
typedef struct image_info {
ulong start, end; /* start/end of blob */
ulong image_start, image_len; /* start of image within blob, len of image */
ulong load; /* load addr for the image */
uint8_t comp, type, os; /* compression, type of image, os type */
uint8_t arch; /* CPU architecture */
} image_info_t;1234567
得到images.os.os的值:
static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
const void *os_hdr;
。。。
/* get kernel image header, start address and length */
os_hdr = boot_get_kernel(cmdtp, flag, argc, argv,
&images, &images.os.image_start, &images.os.image_len);
。。。
/* get image parameters */
switch (genimg_get_format(os_hdr)) {
#if defined(CONFIG_IMAGE_FORMAT_LEGACY)
case IMAGE_FORMAT_LEGACY: /*舊系統(tǒng)格式的內核映像*/
。。。
images.os.os = image_get_os(os_hdr);
。。。
break;
#endif12345678910111213141516171819202122
?、凇ootm_os_get_boot_func中會用到函數(shù)指針數(shù)組boot_os,該數(shù)組利用傳入的images.os.os=5的值得到boot處理函數(shù)指針do_bootm_linux返回給boot_fn 。
boot_fn = bootm_os_get_boot_func(images-》os.os);1
boot_os_fn *bootm_os_get_boot_func(int os)
{
。。。
return boot_os[os];
}
123456
static boot_os_fn *boot_os[] = {
?。跧H_OS_U_BOOT] = do_bootm_standalone,
#ifdef CONFIG_BOOTM_LINUX
?。跧H_OS_LINUX] = do_bootm_linux,
#endif
#ifdef CONFIG_BOOTM_NETBSD
?。跧H_OS_NETBSD] = do_bootm_netbsd,
#endif
。。。
};12345678910
操作系統(tǒng)代號可在u-boot-2016.05\include\image.h中查看
/*
* Operating System Codes
*/
#define IH_OS_INVALID 0 /* Invalid OS */
#define IH_OS_OPENBSD 1 /* OpenBSD */
#define IH_OS_NETBSD 2 /* NetBSD */
#define IH_OS_FREEBSD 3 /* FreeBSD */
#define IH_OS_4_4BSD 4 /* 4.4BSD */
#define IH_OS_LINUX 5 /* Linux */
。。。
123456789101112
?、伞all various other states that are not generally used
?、省heck for unsupported subcommand
?、恕ow run the OS! We hope this doesn’t return
if (!ret && (states & BOOTM_STATE_OS_GO))
ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO,
images, boot_fn);
1234
從do_bootm_states進入u-boot-2016.05\common\bootm_os.c:boot_selected_os函數(shù),執(zhí)行boot_fn(state, argc, argv, images);
int boot_selected_os(int argc, char * const argv[], int state,
bootm_headers_t *images, boot_os_fn *boot_fn)
{
。。。
boot_fn(state, argc, argv, images);
。。。
}1234567
?、?、Deal with any fallout
8、執(zhí)行boot_fn(state, argc, argv, images),因為boot_fn=do_bootm_linux,所以相當于執(zhí)行do_bootm_linux(state, argc, argv, images),程序跳到u-boot-2016.05\arch\arm\lib\bootm.c:
/* Main Entry point for arm bootm implementation*/
int do_bootm_linux(int flag, int argc, char * const argv[],
bootm_headers_t *images)
{
。。。
boot_jump_linux(images, flag);
。。。
}12345678
do_bootm_linux -》 boot_jump_linux -》 kernel_entry(0, machid, r2);
static void boot_jump_linux(bootm_headers_t *images, int flag)
{
。。。
unsigned long machid = gd-》bd-》bi_arch_number;
char *s;
void (*kernel_entry)(int zero, int arch, uint params);
unsigned long r2;
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
kernel_entry = (void (*)(int, int, uint))images-》ep; /* ep:entry point of OS*/
s = getenv(“machid”);
if (s) {
if (strict_strtoul(s, 16, &machid) 《 0) {
debug(“strict_strtoul failed!\n”);
return;
}
printf(“Using machid 0x%lx from environment\n”, machid);
}
。。。
if (IMAGE_ENABLE_OF_LIBFDT && images-》ft_len)
r2 = (unsigned long)images-》ft_addr;
else
r2 = gd-》bd-》bi_boot_params;
if (!fake) {
。。。
kernel_entry(0, machid, r2);
}
#endif
}12345678910111213141516171819202122232425262728293031323334
run the OS!
說明:
關于kernel_entry = (void (*)(int, int, uint))images-》ep;中的images-》ep在u-boot-2016.05\common\bootm.c:bootm_find_os函數(shù)中被賦值。
static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
。。。
if (images.os.type == IH_TYPE_KERNEL_NOLOAD) {
images.os.load = images.os.image_start;
images.ep += images.os.load;
}
。。。
}
評論
查看更多