uboot启动过程分析

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启动

待续。。。

  • 3
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值