uboot在启动过程中是分为两个阶段启动的
1. 汇编阶段(初始化运行环境)
- 设置异常向量表
- 设置cpu工作模式
- 禁止中断使能
- 关看门狗
- 设置时钟
- 关闭cache和MMU
- 代码重定向(拷贝代码到SDRAM)
- 设置栈
- 清除BSS段
- 跳转C语言阶段
2. C语言阶段(外设进行初始化)
- 外围设备初始化
- 引导内核启动
A. 什么是异常向量表
异常向量表就是对程序运行过程中的异常进行处理的中断服务程序的跳转指令,每个中断向量在向量表中只占位一个字节存储,只能放一条指令
B. 那么多模式,为什么要设置成SVC
ARM—cpu共有7种模式,svc简称为特权模式,在uboot启动阶段cpu需要访问更多的硬件资源需要的权限,其他模式无法满足需求
具体可以看看这个:https://blog.csdn.net/u014183377/article/details/45285651
C. 为什么要禁中断
uboot只是完成硬件初始化,环境参数设置,代码搬运等工作,而这段时间还没有搬移代码,所以编译地址上面没有这个代码,如果进行跳转就会跳转到空指针上面
D. 什么是看门狗,看门狗作用是什么
在嵌入式系统长期运行时,难免出现系统岩机等,这时候就需要重启设备来恢复系统工作状态,看门狗就担任这样的一个角色,watchdog一般就是一个带计时器功能的硬件模块,watchdog启动后用户必须在计时结束前置位,然后再重新计时,就像到点了要给狗喂食,不喂狗就除去霍霍别人,在uboot启动阶段是不需要用到这个功能的,否则在U-Boot启动过程中,CPU将不断重启。
E. 设置时钟
相对CPU来说时钟是不会影响启动的,频率的设置是要让外围的设备能承受所设置的频率,如果频率过高则会导致cpu操作外围设备失败,设置时钟就是为了cpu能操作外围设备
F. 关闭CACHE和MMU
cache:俗称缓存,是一种容量小但存储速度快的存储器,它介于处理器和存储器之间,存储的是一些数据和指令,
没有使用cache时,处理器是直接访问存储器的。其中存储器的速度较慢,处理器速度较快,这种速度的不一致导致了处理器访问存储器用时较长。为了解决这个问题,引进了cache,见下图
mmu的作用:完成虚拟地址到物理地址的映射
MMU和Cache的控制都是通过协处理器CP15来实现的。刚上电的时候,CPU还不能管理他们,不关闭cache否则可能导致刚开始的代码里面,去取数据的时候,从cache里面取,而这时候RAM中数据还没有cache过来,导致数据预取异常,
mmu 先要把实地址转换成虚地址,然后再做设置,但对uboot而言就是起到一个简单的初始化的作用和引导操作系统,如果开启MMU的话,很麻烦,所以关闭MMU
G. 代码重定向
在某些情况下,uboot是在某些只读存储器上运行,比如ROM、nor flash等。需要将这部分代码拷贝到DDR上才能完整运行uboot。见下图:
H. 设置栈
让sp寄存器指向一段没有使用的内存即可,保存现场/上下文,传递参数,保存临时变量
I. 清BSS段
BSS 段通常是指用来存放程序中未初始化的或者初始化为0的全局变量和静态变量的一块内存区域
全局变量,静态变量的初始化
确定开始文件start.S
我的开发板: make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- da850_omapl138_evm_config
2718 da850_omapl138_evm_config : unconfig
2719 @mkdir -p $(obj)include
2720 echo "#define CONFIG_DA850_EVM" >> $(obj)include/config.h
2721 $(XECHO) "... configured for DA850/OMAP-L138 boot"
2722 @$(MKCONFIG) -a da850_evm arm arm926ejs da8xx-evm da8xx da8xx
有些开发板可能在根目录下生成.config 文件,可以根据这个文件确定开发板的厂商,soc,型号架构等信息
然后在开发板的/board/da8xx/da8xx-evm下找到了链接文件 u-boot.lds
24 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
25 OUTPUT_ARCH(arm)
26 ENTRY(_start)
27 SECTIONS
28 {
29 . = 0x00000000;
30 . = ALIGN(4);
31 .text :
32 {
33 cpu/arm926ejs/start.o (.text)
34 *(.text)
35 }
36 . = ALIGN(4);
通过这个文件确定了start.S文件位于 cpu/arm926ejs/start.S
在start.S下的另一个文件我们也需要注意下 .config.mk
29 #Provide at least 16MB spacing between us and the Linux Kernel image
30 TEXT_BASE = 0xC1080000
uboot引导的起始地址在TEXT_BASE
.globl _start //声明一个_start全局符号(Symbol), 这个_start这个符号要被lds链接脚本用到
_start:
b reset //复位异常0x0 ,是无条件直接跳转到reset标号出执行程序
ldr pc, _undefined_instruction //未定义的指令异常 0x4
ldr pc, _software_interrupt // 软件中断异常 0x8
ldr pc, _prefetch_abort //内存操作异常 0xc
ldr pc, _data_abort //数据异常 0x10
ldr pc, _not_used //未使用 0x14
ldr pc, _irq //中断IRQ异常 0x18
ldr pc, _fiq //快速中断FIQ异常 0x1c
_undefined_instruction: //0x20
.word undefined_instruction
_software_interrupt:
.word software_interrupt //0x24
_prefetch_abort:
.word prefetch_abort // 0x28
_data_abort:
.word data_abort //0x2c
_not_used:
.word not_used //0x30
_irq:
.word irq //0x34
_fiq:
.word fiq //0x38
.balignl 16,0xdeadbeef // 0x3c,当前地址开始,在地址为16的倍数的指令位置的上一个指令填入为0xdeadbeef
ARM异常向量表
地址 | 异常 | 进入模式 | 描述 |
0x00000000 | 复位 | 管理模式 | 复位电平有效时,产生复位异常,程序跳转到复位处理程序处执行 |
0x00000004 | 未定义指令 | 未定义模式 | 遇到不能处理的指令时,产生未定义指令异常 |
0x00000008 | 软件中断 | 管理模式 | 执行SWI指令产生,用于用户模式下的程序调用特权操作指令 |
0x0000000c | 预存指令 | 中止模式 | 处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常 |
0x00000010 | 数据操作 | 中止模式 | 处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常 |
0x00000014 | 未使用 | 未使用 | 未使用 |
0x00000018 | IRQ | IRQ | 外部中断请求有效,且CPSR中的I位为0时,产生IRQ异常 |
0x0000001c | FIQ | FIQ | 快速中断请求引脚有效,且CPSR中的F位为0时,产生FIQ异常 |
.globl reset
reset:
/*
* set the cpu to SVC32 mode
*/
// CPU的工作模式位设置为管理模式,并将中断禁止位和快中断禁止置位,屏蔽IRQ和FIQ中断
mrs r0,cpsr
bic r0,r0,#0x1f //工作模式位清零
orr r0,r0,#0xd3 //工作模式位设置为"10011"(管理模式),并将中断禁止位和快中断禁止位置1
msr cpsr,r0
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit //关闭MMU,cache
#endif
cpu_init_crit 只会在重启的时候运行,当 u-boot 在 ram 中的时候不会运行
/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
*/
//使数据cache与指令cache无效
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
/*
* disable MMU stuff and caches
*/
//关闭MMU
mrc p15, 0, r0, c1, c0, 0 // 读出控制寄存器到r0中
bic r0, r0, #0x00002300 /* clear bits 13, 9:8 (--V- --RS) */
bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */
orr r0, r0, #0x00000002 /* set bit 2 (A) Align */
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
/*
* Go setup Memory and board specific bits prior to relocation.
*/
mov ip, lr /* perserve link reg across call */
bl lowlevel_init /* go setup pll,mux,memory */
mov lr, ip /* restore link */
mov pc, lr /* back to my caller */
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
清除指令与数据缓存,禁用MMU与数据指令缓存,最后调用lowlevel_init函数设置SDRAM控制器,该函数的实现与具体的目标板有关的。
bl lowlevel_init /* go setup pll,mux,memory */
bl lowlevel_init下来初始化各个bank // cpu/arm926ejs/davinci/lowlevel_init.S
代码重定位判断
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
获取_start实际当前位于的地方,_TEXT_BASE 为 0xC1080000,这里判断的是代码是否直接运行在 sdram 里了,如果是就不需要重定位了。
拷贝范围:_start 至 _bss_start 前,拷贝到 0xC1080000处
设置栈:
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
清 BSS 段:
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
点亮核心板上指示灯:(与硬件相关的)
bl coloured_LED_init
bl red_LED_on
使用的芯片默认上电watchdog关闭,所以不用做关闭看门狗动作(这个可以查datasheet知道)
跳转C语言阶段:
ldr pc, _start_armboot
_start_armboot:
.word start_armboot
跳转到二阶段 lib_arm/board.c
start_armboot
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
gd->flags |= GD_FLG_RELOC;
monitor_flash_len = _bss_start - _armboot_start;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN);
#ifndef CONFIG_SYS_NO_FLASH
/* configure available FLASH banks */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
#ifdef CONFIG_VFD
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
/* board init may have inited fb_base */
if (!gd->fb_base) {
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
lcd_setmem (addr);
gd->fb_base = addr;
}
#endif /* CONFIG_LCD */
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
#ifdef CONFIG_GENERIC_MMC
puts ("MMC: ");
mmc_initialize (gd->bd);
#endif
/* initialize environment */
env_relocate ();
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
#if defined CONFIG_SPLASH_SCREEN && defined CONFIG_VIDEO_MX5
setup_splash_image();
#endif
stdio_init (); /* get the devices list going. */
jumptable_init ();
#if defined(CONFIG_API)
/* Initialize API */
api_init ();
#endif
console_init_r (); /* fully init console as a device */
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
/* enable exceptions */
enable_interrupts ();
#ifdef CONFIG_MD5
extern void generate_mac_by_uuid(void);
if(!getenv ("ethaddr") || !getenv ("fec_mac"))
generate_mac_by_uuid();
#endif
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
/* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
#endif
#ifdef CONFIG_DRIVER_CS8900
/* XXX: this needs to be moved to board init */
cs8900_get_enetaddr ();
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
/* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
#if defined(CONFIG_ENC28J60_ETH) && !defined(CONFIG_ETHADDR)
extern void enc_set_mac_addr (void);
enc_set_mac_addr ();
#endif /* CONFIG_ENC28J60_ETH && !CONFIG_ETHADDR*/
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#ifdef CONFIG_ANDROID_RECOVERY
check_recovery_mode();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
#ifdef CONFIG_FASTBOOT
check_fastboot_mode();
#endif
if(strcmp(getenv("wdtenable"), "enable") == 0 ) {
set_watchdog_enable();
puts ("WatchDog is enabled\n");
} else
puts ("WatchDog is disabled\n");
clear_watchdog_pde();
#ifdef CONFIG_VIDEO_MX5
extern void enable_backlight(void);
enable_backlight();
#endif
/* 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 */
}
定义二重指针 init_fnc_ptr 指向 init_sequence指针数组,调用init_sequence函数指针数组里的初始化函数、nand初始化、环境变量初始化、USB初始化
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {//初始化各个函数
if ((*init_fnc_ptr)() != 0) {//函数的返回值不为0,认为出错,打印出错信息
hang ();//打印出错信息
}
}
init_sequence指针数组进行初始化
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup *///CPU的一些堆栈大小设置
board_init, /* basic board dependent setup *///设置芯片代码、设置与内核交互的地址
interrupt_init, /* set up exceptions *///10ms时钟定时器设置
env_init, /* initialize environment *///初始化环境变量,采用默认环境变量
init_baudrate, /* initialze baudrate settings *///初始化串口波特率为115200
serial_init, /* serial communications setup *///初始化串口
console_init_f, /* stage 1 init of console *///设置控制台初始化标志
display_banner, /* say that we are here *///打印UBOOT版本信息
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
nand初始化
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
读取nand中的环境变量
/* initialize environment */
env_relocate ();
调用stdio_init,初始化标准输入、标准输出、标准错误输出等 IO
stdio_init (); /* get the devices list going. */
jumptable_init()初始化gd中的jump table中的函数
jumptable_init ();
start_armboot函数继续往下执行,控制台初始化,主要为设置输入输出与错误设备都为串口
console_init_r (); /* fully init console as a device */
main_loop()死循环解析指令
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
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 */
#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
ulong bmp = 0; /* default bitmap */
extern int trab_vfd (ulong bitmap);
#ifdef CONFIG_MODEM_SUPPORT
if (do_mdm_init)
bmp = 1; /* alternate bitmap */
#endif
trab_vfd (bmp);
#endif /* CONFIG_VFD && VFD_TEST_LOGO */
#if defined(CONFIG_UPDATE_TFTP)
update_tftp ();
#endif /* CONFIG_UPDATE_TFTP */
#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
{
extern char version_string[];
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_AUTO_COMPLETE
install_auto_complete();
#endif
#ifdef CONFIG_PREBOOT
if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
# endif
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (p, 0);
# else
parse_string_outer(p, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
# endif
}
#endif /* CONFIG_PREBOOT */
s = getenv ("bootargs_android");
if(s)
run_command (s, 0);
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
# ifdef CONFIG_BOOT_RETRY_TIME
init_cmd_timeout ();
# endif /* CONFIG_BOOT_RETRY_TIME */
#ifdef CONFIG_POST
if (gd->flags & GD_FLG_POSTFAIL) {
s = getenv("failbootcmd");
}
else
#endif /* CONFIG_POST */
#ifdef CONFIG_BOOTCOUNT_LIMIT
if (bootlimit && (bootcount > bootlimit)) {
printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
(unsigned)bootlimit);
s = getenv ("altbootcmd");
}
else
#endif /* CONFIG_BOOTCOUNT_LIMIT */
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 // 关闭Ctrl+C组合键
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, 0); // 运行启动命令行
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
# endif // 打开Ctrl+C组合键
}
# ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) { // 检查是否支持菜单键
s = getenv("menucmd");
if (s) {
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, 0);
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
}
}
#endif /* CONFIG_MENUKEY */
#endif /* CONFIG_BOOTDELAY */
#ifdef CONFIG_AMIGAONEG3SE
{
extern void video_banner(void);
video_banner(); // 打印启动图标
}
#endif
/*run into scr configure menu first*/
//debug ("### main_loop: begin to menu \n");
if(getenv("system"))
{
debug ("### main_loop: system=\"android\"\n");
}
run_command("scr_android", 0);
/*
* 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
len = readline (CONFIG_SYS_PROMPT); // 读取命令
flag = 0; /* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
else if (len == -2) {
/* -2 means timed out, retry autoboot
*/
puts ("\nTimed out waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
/* Reinit board to run initialization code again */
do_reset (NULL, 0, 0, NULL);
# else
return; /* retry autoboot */
# endif
}
#endif
if (len == -1)
puts ("<INTERRUPT>\n");
else
rc = run_command (lastcommand, flag);
if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
}
}
#endif /*CONFIG_SYS_HUSH_PARSER*/
}
在main_loop()中主要是对命令解析,如果这个在延时时间内按任意键会进入uboot模式,在uboot模式下通过输入相关指令来进行参数设置common/cmd_xxx.c ,如果没有进uboot模式则会解析 /include/configs/xxx.h 里的默认参数引导kernel启动
待续。。。