uboot 流程详解

Uboot整体流程

mstar平台
start.S汇编指令 -> board_init_f -> board_init_r -> main_loop

1.start.S汇编指令
2.board_init_f
3.relocate_code
4.board_init_r
5.main_loop

1 start.S
路径:u-boot-2011.06\arch\arm\cpu\arm7\start.S

1.start.S汇编指令
中断向量表的设置
段的地址做出定义
将CPU设置为SVC模式
board_init_f
relocat
清bss段
board_init_r

主要完成功能:

  1. 中断向量表的设置
  2. 对各个段的地址做出定义
  3. 将CPU设置为SVC模式(管理员权限,获取访问某些寄存器的权限)
  4. 跳转到board_init_f
  5. 重定位relocate_code
  6. 清bss段
  7. 跳转到重定位后在board_init_r的函数实现
1中断向量表的设置
#include <asm-offsets.h>
#include <config.h>
#include <version.h>
#include "arm.inc"

#ifndef CONFIG_MSTAR_STR_MINISIZE
.globl _start                           // .globl定义一个全局符号"_start",表明_start这个符号要被链接器在u-boot.lds中用到
                                        //其中符号保存的地址都在顶层目录/system.map中列出来了
/***************设置异常向量表******start*****/
_start:                                 //_start:系统复位设置,以下共8种不同的异常处理
    b	reset                           //复位异常 0x0
	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

//.word类似于(unsigend long) ,_undefined_instruction是一个标号,指向一个32位地址,该地址用undefined_handler符号变量代替
//相当于c的 _undefined_instruction = &undefined_handler ,相当于将undefined_handler地址存到了pc中

_undefined_instruction: .word undefined_handler 
_software_interrupt:    .word swi_handler
_prefetch_abort:        .word prefetch_handler
_data_abort:            .word abort_handler
_not_used:              .word not_used
_irq:                   .word irq_handler
_fiq:                   .word fiq_handler
_pad:                   .word 0x12345678 /* now 16*4=64 */

.global _end_vect
_end_vect:
/***************设置异常向量表*****end ******/

	.balignl 16,0xdeadbeef              //16字节对齐



2.	对各个段的地址做出定义
/*********************对各个段的地址做出定义*************start****************/
.globl _TEXT_BASE
_TEXT_BASE:
	.word	CONFIG_SYS_TEXT_BASE

.globl _MIU0_BUS_BASE
_MIU0_BUS_BASE:
	.word	CONFIG_MIU0_BUSADDR

/*
 * These are defined in the board-specific linker script.
 */
.globl _bss_start_ofs
_bss_start_ofs:
	.word __bss_start - _start

.globl _bss_end_ofs
_bss_end_ofs:
	.word __bss_end__ - _start

.globl _end_ofs
_end_ofs:
	.word _end - _start

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
	.word	0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
	.word 0x0badc0de
#endif

/* IRQ stack memory (calculated at run-time) + 8 bytes */
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
	.word	0x0badc0de
/*********************对各个段的地址做出定义**************end***************/

3.	将CPU设置为SVC模式(管理员权限,获取访问某些寄存器的权限)
/*********************reset函数实现***********************start***************/
/*
 * the actual reset code
 */

.globl reset
reset:
    ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)		//设置栈地址 

	/*
	 * set the cpu to SVC32 mode
	 */
     //设置CPSR程序程序状态寄存器为管理模式
	mrs	r0, cpsr            //MRS读出CPSR寄存器值到R0
	bic	r0, r0, #0x1f       //将R0低5位清空
	orr	r0, r0, #0xd3       //R0与b'110 10011按位或,禁止IRQ和FIQ中断,10011:复位需要设为管理模式
	msr	cpsr,r0             //MSR写入CPSR寄存器
	
/*********************reset函数实现************************end**************/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
	/*********************cpu初始化*****************************start***********/
	bl	cpu_init_crit
	//bl指令,带分支的跳转指令,除了跳转到cpu_init_crit标号处执行,还将当前pc指针存储到lr寄存器,
	//通过mov pc,lr指令跳回当前指令的下一条指令。
	/*********************cpu初始化*****************************end***********/
#endif

/*  init GIC (Generic Interrupt Controller)*/
    bl __init_dic			//初始化通用中断控制器
    bl __init_interrupts	//初始化 CPU中断接口

/* Set stackpointer in internal RAM to call board_init_f */
//调用board_init_f函数前,在内部RAM中设置栈指针

4.	跳转到board_init_f
call_board_init_f:
	bic	sp, sp, #7 			/* 8-byte alignment for ABI compliance */
	ldr	r0,=0x00000000
	bl	board_init_f
	
5.	代码重定位,内存的初始化
/**************************代码重映射******************start******************/
/*
 * void relocate_code (addr_sp, gd, addr_moni)
 *
 * This "function" does not return, instead it continues in RAM
 * after relocating the monitor code.
 *
 */
	.globl	relocate_code
relocate_code:
	mov	r4, r0					/* save addr_sp */				// addr_sp栈顶值
	mov	r5, r1					/* save addr of gd */			// id值
	mov	r6, r2					/* save addr of destination */	//addr值:uboot重定位地址

	/* Set up the stack						    */
stack_setup:
	mov	sp, r4		//设置栈addr_sp
	adr	r0, _start	//在顶层目录下system.map符号文件中找到_start =0,所以r0=0
	
#ifndef CONFIG_PRELOADER
 /*
        * fix .rel.dyn relocations
        */
       ldr   r0, _TEXT_BASE             /* r0 <- Text base */  //r0=text段基地址=0
       sub  r9, r6, r0         /* r9 <- relocation offset */   //r9= 重定位后的偏移值=33F41000
       ldr   r10, _dynsym_start_ofs  /* r10 <- sym table ofs */ 
                                     //_dynsym_start_ofs =__dynsym_start - _start=0x73608
                                     //所以r10=动态符号表的起始偏移值=0x73608

       add r10, r10, r0            	 /* r10 <- sym table in FLASH */
                                     //r10=flash上的动态符号表基地址=0x73608

       ldr   r2, _rel_dyn_start_ofs     /* r2 <- rel dyn start ofs */
                                        //r2=__rel_dyn_start - _start=0x6b568
                                        //所以r2=相对动态信息的起始偏移值=0x6b568

       add r2, r2, r0         			/* r2 <- rel dyn start in FLASH */
                                      	//r2=flash上的相对动态信息基地址=0x6b568

       ldr   r3, _rel_dyn_end_ofs      /* r3 <- rel dyn end ofs */
                                       // _rel_dyn_end_ofs=__rel_dyn_end - _start=00073608
                                       //所以r3=相对动态信息的结束偏移值=00073608

       add r3, r3, r0         		/* r3 <- rel dyn end in FLASH */
                                    //r3=flash上的相对动态信息结束地址=0x6b568

fixloop:
       ldr   r0, [r2]           /* r0 <- location to fix up, IN FLASH! */
                                //以0x20为例,r0=0x6b568地址处的内容= 0x20

       add r0, r0, r9           /* r0 <- location to fix up in RAM */
                                //r0=33F41000+0x20=33F41020

       ldr   r1, [r2, #4]       //r1= 33F41024地址处的内容=0x17
       and  r7, r1, #0xff       
       cmp r7, #23              /* relative fixup? */  //0x17=23,所以相等
       beq fixrel               //跳到:fixerl

       cmp r7, #2               /* absolute fixup? */
       beq fixabs
       /* ignore unknown type of fixup */
       b     fixnext

fixabs:
       /* absolute fix: set location to (offset) symbol value */
       mov r1, r1, LSR #4         	/* r1 <- symbol index in .dynsym */
       add r1, r10, r1              /* r1 <- address of symbol in table */
       ldr   r1, [r1, #4]           /* r1 <- symbol value */
       add r1, r1, r9         		/* r1 <- relocated sym addr */
       b     fixnext	

fixrel:
       /* relative fix: increase location by offset */
       ldr   r1, [r0]                //r1=33F41020地址处的内容=0x1e0
       add r1, r1, r9                //r1=0x1e0+33F41000= 33F411e0

fixnext:
       str   r1, [r0]             	//改变链接地址里的内容, 33F41020=33F411e0  (之前为0x1e0)   
       add r2, r2, #8             	//r2等于下一个相对动态信息(0x24)的地址
       cmp r2, r3                	//若没到尾部__rel_dyn_end,便继续执行: fixloop
       blo  fixloop
       
/*清楚bss段*/
clear_bss:
	ldr   r0, _bss_start_ofs                        	//获取flash上的bss段起始位置
       ldr   r1, _bss_end_ofs                          	//获取flash上的bss段结束位置
       mov r4, r6                    /* reloc addr */   //获取r6(SDRAM上的uboot基地址)
       add r0, r0, r4                                  	//加上重定位偏移值,得到SDRAM上的bss段起始位置
       add r1, r1, r4                                   //得到SDRAM上的bss段结束位置
       mov r2, #0x00000000           /* clear*/

clbss_l:str	r2, [r0]		/* clear loop...		    */
	add	r0, r0, #4
	cmp	r0, r1
	bne	clbss_l
#endif	/* #ifndef CONFIG_PRELOADER */
/**************************代码重映射******************end******************/

/**************************跳转到重定位处执行board_init_r()函数********************************/
/*
 * We are done. Do not return, instead branch to second part of board
 * initialization, now running from RAM.
 */
jump_2_ram:
	ldr	r0, _board_init_r_ofs	//r0=flash上的board_init_r()函数地址偏移值
	adr	r1, _start				//0
	add	lr, r0, r1				//返回地址lr=flash上的board_init_r()函数
	add	lr, lr, r9				//加上重定位偏移值(r9)后,lr=SDRAM上的board_init_r()函数

	/* 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()函数

_board_init_r_ofs:
	.word board_init_r - _start		//获取在flash上的board_init_r()函数地址偏移值


_rel_dyn_start_ofs:
	.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
	.word __rel_dyn_end - _start
_dynsym_start_ofs:
	.word __dynsym_start - _start


2 board_init_f

2.board_init_f
gd初始化

board_init_f主要完成的工作:

  1. 为gd全局变量分配地址
  2. 对gd全局变量进行初始化操作
  3. 执行初始化函数(通过init_sequence数组中的函数指针来实现)
  4. 跳转到board_init_r
    gd_t结构体,gd_t(global data缩写),其中包括了bd变量,可以说gd_t结构体包括了u-boot中所有重要全局变量, (gd是用来传递给内核的参数)。
变量说明取值
bd(board date)开发板子相关参数1.bi_baudrate: 波特率115200 2.bi_ip_addr :p地址 3.bi_arch_number:开发板ID 该变量标识每一种开发板相关的ID,该值将传递给内核,如果这个参数与内核配置的不相同,那么内核启动解压缩完成后将出现“Error:a”错误,开发板ID可以在内核arch/arm/tools/mach-types中查看 4.bi_boot_params:u-boot传递给内核的参数的保存地址 5.start:RAM起始地址 6.size:RAM大小
flags指示标志,如设备已经初始化标志等进入board_init_f函数时flags为0,其后被设置
baudrate串口波特率115200
have_console串口初始化标志在console_init_f中设置
env_addr环境变量参数地址通过函数env_init设置,查uboot.map地址位于.data段,与log打印一致
env_valid环境变量参数crc校验有效标志通过函数env_init设置
fb_base重fb起始地址干啥用的?似乎没有用到
relocaddr Uboot重定位之后的地址0x26E00000
ram_size物理ram的size120MB
mon_lenUboot的总长度0x9D1980,网上资料解释为uboot总长度大小,但个人理解应当为uboot总长度+bss段的大小以某次编译结果为例:.text段起始地址为0x2570 0000.bss结束地址为0x260d 1980mon_len为0x9d1980说明该长度中包含.bss段,而uboot在emmc中存储的时候,是不包含.bss的
irq_sp中断栈指针地址0x265DDF70
start_addr_sp栈起始地址0x265DDF60
tlb_addrtlb空间的地址0x277FC000,tlb空间是干啥的?
reloc_off新旧uboot的偏移0x17000000,也就是重定位偏移,就是实际定向的与链接时指定的位置之差
**jt跳转表用来函数调用地址登记
env_buf[32]环境变量buffer
void board_init_f(ulong bootflag) 
{
       bd_t *bd;
       init_fnc_t **init_fnc_ptr;         //函数指针
       gd_t *id;
       ulong addr, addr_sp;

       /* Pointer is writable since we allocated a register for it */
       gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
       
		__asm__ __volatile__("": : :"memory");          //memory:让cpu重新读取内存的数据

      	memset((void *)gd, 0, sizeof(gd_t));        	//将gd_t结构体清0

      gd->mon_len = _bss_end_ofs;  	// _bss_end_ofs =__bss_end__ - _start,在反汇编找到等于0xae4e0,所以mon_len等于uboot的数据长度
		
		//调用init_sequence[]数组里的各个函数,主要有
        //timer_init():初始化定时器
		//env_init():初始化环境变量,设置gd的成员变量
		//init_baudrate():设置波特率
		//serial_init():串口初始化
		//console_init_f():第一阶段控制台初始化
		//dram_init():设置gd->ram_size= 120*0x100000(120MB)
		for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
      {
       	if ((*init_fnc_ptr)() != 0)     //执行函数,若函数执行出错,则进入hang()
        {               
        	hang ();   //打印错误信息,然后一直while
        }
      }
      
      addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;  // addr=0x20000000 + 120*0x100000 =0x27800000
													// CONFIG_SYS_SDRAM_BASE:  SDRAM基地址,为0X20000000
													// gd->ram_size:          等于120*0x100000 
													
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
       /* reserve TLB table */
       addr -= (4096 * 4);       
       /*round down to next 64 kB limit*/ 
       addr &= ~(0x10000 - 1);  
       gd->tlb_addr = addr;     //将64kB分配给TLB    
#endif
/* round down to next 4 kB limit */
       addr &= ~(4096 - 1);                    //4kb对齐
       debug("Top of RAM usable for U-Boot at: %08lx\n", addr);

       /*
        * reserve memory for U-Boot code, data & bss
        * round down to next 4 kB limit
        */
       addr -= gd->mon_len; 

       addr &= ~(4096 - 1);  //4kb对齐,
                             
       debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);

#ifndef CONFIG_SPL_BUILD
       addr_sp = addr - TOTAL_MALLOC_LEN; //分配一段8M malloc空间给addr_sp
                       //TOTAL_MALLOC_LEN=1024*1024*8,

       addr_sp -= sizeof (bd_t);            //分配一段bd_t结构体大的空间
    bd = (bd_t *) addr_sp;               //bd指向刚刚分配出来的bd_t结构体
    gd->bd = bd;                         // gd变量的成员bd等于bd_t基地址

    addr_sp -= sizeof (gd_t);              //分配一个gd_t结构体大的空间
    id = (gd_t *) addr_sp;                 //id指向刚刚分配的gd_t结构体
    gd->irq_sp = addr_sp;                 //gd变量的成员irq_sp等于gd_t基地址

    addr_sp -= 12;
    addr_sp &= ~0x07;
    ... ...

    relocate_code(addr_sp, id, addr);  //进入relocate_code()函数,重定位代码,以及各个符号
    // addr_sp: 栈顶,该栈顶向上的位置用来存放gd->irq_sp、id 、gd->bd、malloc、uboot、TLB(64kb),
    //id:       存放 gd_t结构体的首地址
    // addr:    等于存放uboot重定位地址
}	

3 board_init_r
board_init_r主功能为外设的初始化,以及STAGE_MSINIT阶段的命令的注册,以及执行,
主要实现函数为:

  1. MstarSysInit():主要完成板级外设的初始化工作:
    1> os初始化
    2> cache初始化
    3> 中断初始化
    4> 定时器初始化
    5> MMIO(内存映射I/O)初始化
    6> IR(红外?)初始化
    7> SPI初始化
    8> 看门狗初始化
    9> MIU初始化
    10> GPIO初始化
    11> DMA初始化
    12> USB初始化
  2. MstarDrvInit()
    1> 内核链表的初始化
    Talbe_Init();
    2> 将STAGE_MSINIT阶段的指令,挂载到内核链表
    Core_Register_MsInit()
    3> 取出指令
    4> 执行指令
    run_command
3.board_init_r
外设初始化
MstarSysInit
MstarDrvInit
main_loop
STAGE_MSINIT阶段命令挂载
STAGE_MSINIT阶段命执行



4 main_loop
main_loop函数做的都是与具体平台无关的工作(但mstar在uboot中客制化和很多东西,放在MstarProcess和MstarToKernel两函数中),主要完成以下功能:
(1)初始化启动次数限制机制
(2)Modem功能
(3)设置软件版本号
(4)启动延迟
(5)STAGE_PROCESS以及STAGE_TOKERNEL阶段的命令挂载以及执行
(6)读取命令,解析命令
(7)检查bootdel检查bootdelay时间内是否有按键按下,根据按键检查的结果进入控制台或者引导kernal

4.main_loop
启动hash命令解析器
MstarProcess
按键是否按下
控制台
MstarToKenel
STAGE_PROCESS阶段命令挂载
STAGE_TOKERNEL阶段命令挂载
STAGE_PROCESS阶段命令执行
his_projecid
STAGE_TOKERNEL阶段命令执行
引导内核
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
/*(1)初始化启动次数限制机制
*启动次数限制功能,启动次数限制可以被用户设置一个启动次数,然后保存在Flash存储器的特定位置,当到达启动次数后,
*U-Boot无法启动。该功能适合一些商业产品,通过配置不同的License限制用户重新启动系统。
*/
#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);	//设置环境变量bootcount
	bcs = getenv ("bootlimit");	//获得启动次数的上限
	bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */

#ifdef CONFIG_MODEM_SUPPORT
	if (do_mdm_init)
		bmp = 1;	/* alternate bitmap */
#endif

/*
* (2)Modem功能。如果系统中有Modem,打开该功能可以接受其他用户通过电话网络的拨号请求。Modem功能通常供一些远程控制的系统使用。
*/
#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 */

/*
*(3)设置U-Boot的版本号,初始化命令自动完成功能等。动态版本号功能支持代码,version_string变量是在其他文件定义的一个字符串变量,
*当用户改变U-Boot版本的时候会更新该变量。打开动态版本支持功能后,U-Boot在启动的时候会显示最新的版本号。
*/
#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

/*
*设置命令行自动完成功能,该功能与Linux的shell类似,当用户输入一部分命令后,可以通过按下键盘上的Tab键   //补全命令的剩余部分。
*main_loop()函数不同的功能使用宏开关控制不仅能提高代码模块化,更主要的是针对嵌入  //式系统Flash存储器大小设计的。在嵌入式系统
*上,不同的系统Flash存储空间不同。对于一些Flash空间比较紧张  //的设备来说,通过宏开关关闭一些不是特别必要的功能如命令行自动完
*成,可以减小U-Boot编译后的文件大小。
*/

#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 */

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

/*
*(4)启动延迟功能,需要等待用户从串口或者网络接口输入。如果用户按下任意键打断,启动流程,会向终端打印出一个启动菜单。
*/
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	s = getenv ("bootdelay");
	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;  //这段代码是获取环境变量bootdelay的值,bootdelay就是uboot启动之后倒计时的时间

	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>");

	timer_list_init();
	if(FALSE==MstarProcess())		//(5)STAGE_PROCESS阶段命令注册及执行
	{
		printf("Error:MstarProcess() \n");
	}

/*
 *	在启动命令非0(有启动命令)的情况下,如果在启动延时时间到之前按下键终止了,abortboot返回1,否则如果一 //直没有
 *	键按下,直到启动延时时间到,那么函数返回0。所以,如果按下键了,就可以跳过启动操作系统;如果没	//按就直接启动操作系统了。
 */
	if (bootdelay >= 0 && s && !abortboot (bootdelay)) {	/*在启动延迟期间是否有按钮按下,按下则跳过启动linux代码*/
	
	if(FALSE==MstarToKernel())		//(5)STAGE_TOKERNEL阶段命令注册及执行
	{
		printf("MstarToKernel() \n");
	}
	
	s = getenv("bootcmd");
	
# ifdef CONFIG_AUTOBOOT_KEYED
		int prev = disable_ctrlc(1);	/* disable Control C checking *///关闭control+c组合键
# endif

# 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 *///恢复control+c组合键功能
# endif
	}

# 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 */

/*
*(6)读取命令,解析命令。这是一个for死循环,该循环不断使用readline()函数(第463行)从控制台(一般是串口)读取用户的输入,
*然后解析。有关如何解析命令请参考U-Boot代码中run_command()函数的定义。
*/
	/*
	 * 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);		// 读取命令,读取到的命令存储在全局变量console_buffer 中

		flag = 0;	/* assume no special flags for now */
		if (len > 0)	//命令长度大于0
			strcpy (lastcommand, console_buffer);	//将读取到的命令copy到lastcommand中
		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*/
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值