uboot boot kernel

我们以armv7为例
uboot的入口函数在start.s中
_start: 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
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f
先调用board_init_f 其中f表示运行在flash上。
在dram准备好后
ldr r0, _board_init_r_ofs
adr r1, _start
add lr, r0, r1
add lr, lr, r9
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
mov pc, lr


_board_init_r_ofs:
.word board_init_r - _start
调用board_init_r
void board_init_r(gd_t *id, ulong dest_addr)
{
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop();
}


/* NOTREACHED - no way out of command loop except booting */
}
在board_init_r中调用main_loop
void main_loop (void)
{
#ifndef CONFIG_SYS_HUSH_PARSER
static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
int len;
int rc = 1;
int flag;
#endif


#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
char *s;
int bootdelay;
#endif
#ifdef CONFIG_PREBOOT
char *p;
#endif
#ifdef CONFIG_BOOTCOUNT_LIMIT
unsigned long bootcount = 0;
unsigned long bootlimit = 0;
char *bcs;
char bcs_set[16];
#endif /* CONFIG_BOOTCOUNT_LIMIT */


#ifdef CONFIG_BOOTCOUNT_LIMIT
bootcount = bootcount_load();
bootcount++;
bootcount_store (bootcount);
sprintf (bcs_set, "%lu", bootcount);
setenv ("bootcount", bcs_set);
bcs = getenv ("bootlimit");
bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */


#ifdef CONFIG_MODEM_SUPPORT
debug ("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
if (do_mdm_init) {
char *str = strdup(getenv("mdm_cmd"));
setenv ("preboot", str);  /* set or delete definition */
if (str != NULL)
free (str);
mdm_init(); /* wait for modem connection */
}
#endif  /* CONFIG_MODEM_SUPPORT */


#ifdef CONFIG_VERSION_VARIABLE
{
setenv ("ver", version_string);  /* set version variable */
}
#endif /* CONFIG_VERSION_VARIABLE */


#ifdef CONFIG_SYS_HUSH_PARSER
u_boot_hush_start ();
#endif


#if defined(CONFIG_HUSH_INIT_VAR)
hush_init_var ();
#endif


#ifdef CONFIG_PREBOOT
if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# endif


run_command2(p, 0);


# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
# endif
}
#endif /* CONFIG_PREBOOT */


#if defined(CONFIG_UPDATE_TFTP)
update_tftp (0UL);
#endif /* CONFIG_UPDATE_TFTP */


s = getenv ("bootcmd");


debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");


if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# endif


run_command2(s, 0);


# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
# endif
}


# ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) {
s = getenv("menucmd");
if (s)
run_command2(s, 0);
}
#endif /* CONFIG_MENUKEY */
#endif /* CONFIG_BOOTDELAY */


/*
* Main Loop for Monitor Command Processing
*/
#ifdef CONFIG_SYS_HUSH_PARSER
parse_file_outer();
/* This point is never reached */
for (;;);
#else
for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
if (rc >= 0) {
/* Saw enough of a valid command to
* restart the timeout.
*/
reset_cmd_timeout();
}
#
}
#endif /*CONFIG_SYS_HUSH_PARSER*/
}
在main_loop中最要的就是调用 s = getenv ("bootcmd");
得到用户定义的bootcmd,然后调用run_command2(s, 0);来执行这个bootcmd。
下面为例,定义bootcmd
#define CONFIG_BOOTCOMMAND "nboot 0x21000000 0 400000"
因此会执行nboot命令,其回调函数是do_nandboot
U_BOOT_CMD(nboot, 4, 1, do_nandboot,
"boot from NAND device",
"[partition] | [[[loadAddr] dev] offset]"
);
do_nandboot->nand_load_image->bootm_maybe_autostart->do_bootm->do_bootm_states
static 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;

/* From now on, we need the OS boot function */
if (ret)
return ret;
boot_fn = boot_os[images->os.os];
/* 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);


}
由于我们是linux系统因此boot_fn被赋值do_bootm_linux。而boot_os的赋值如下:
static boot_os_fn *boot_os[] = {
#ifdef CONFIG_BOOTM_LINUX
[IH_OS_LINUX] = do_bootm_linux,
#endif
do_bootm_states继续调用boot_selected_os
static int boot_selected_os(int argc, char * const argv[], int state,
bootm_headers_t *images, boot_os_fn *boot_fn)
{
if (images->os.type == IH_TYPE_STANDALONE) {
/* This may return when 'autostart' is 'no' */
bootm_start_standalone(argc, argv);
return 0;
}
arch_preboot_os();
boot_fn(state, argc, argv, images);
if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */
return 0;
bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED);
return BOOTM_ERR_RESET;
}


其实就是直接跑do_bootm_linux
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
bd_t *bd = gd->bd;
char *s;
int machid = bd->bi_arch_number;
void (*kernel_entry)(int zero, int arch, uint params);


#ifdef CONFIG_CMDLINE_TAG
char *commandline = getenv ("bootargs");
#endif


if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
return 1;


s = getenv ("machid");
if (s) {
machid = simple_strtoul (s, NULL, 16);
printf ("Using machid 0x%x from environment\n", machid);
}


show_boot_progress (15);


#ifdef CONFIG_OF_LIBFDT
if (images->ft_len)
return bootm_linux_fdt(machid, images);
#endif
//从uImage的header中得到kernel的地址,一般是0x80000
kernel_entry = (void (*)(int, int, uint))images->ep;


debug ("## Transferring control to Linux (at address %08lx) ...\n",
      (ulong) kernel_entry);
通过atag向kernel传递参数
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
    defined (CONFIG_CMDLINE_TAG) || \
    defined (CONFIG_INITRD_TAG) || \
    defined (CONFIG_SERIAL_TAG) || \
    defined (CONFIG_REVISION_TAG)
setup_start_tag (bd);
#ifdef CONFIG_SERIAL_TAG
setup_serial_tag (&params);
#endif
#ifdef CONFIG_REVISION_TAG
setup_revision_tag (&params);
#endif
#ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdef CONFIG_INITRD_TAG
if (images->rd_start && images->rd_end)
setup_initrd_tag (bd, images->rd_start, images->rd_end);
#endif
setup_end_tag(bd);
#endif
//关闭cache和mmu
announce_and_cleanup();
//跳到kerne_entry执行kernel》
kernel_entry(0, machid, bd->bi_boot_params);
/* does not return */


return 1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值