Uboot整体流程
mstar平台
start.S汇编指令 -> board_init_f -> board_init_r -> main_loop
1 start.S
路径:u-boot-2011.06\arch\arm\cpu\arm7\start.S
主要完成功能:
- 中断向量表的设置
- 对各个段的地址做出定义
- 将CPU设置为SVC模式(管理员权限,获取访问某些寄存器的权限)
- 跳转到board_init_f
- 重定位relocate_code
- 清bss段
- 跳转到重定位后在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
board_init_f主要完成的工作:
- 为gd全局变量分配地址
- 对gd全局变量进行初始化操作
- 执行初始化函数(通过init_sequence数组中的函数指针来实现)
- 跳转到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的size | 120MB |
mon_len | Uboot的总长度 | 0x9D1980,网上资料解释为uboot总长度大小,但个人理解应当为uboot总长度+bss段的大小以某次编译结果为例:.text段起始地址为0x2570 0000.bss结束地址为0x260d 1980mon_len为0x9d1980说明该长度中包含.bss段,而uboot在emmc中存储的时候,是不包含.bss的 |
irq_sp | 中断栈指针地址 | 0x265DDF70 |
start_addr_sp | 栈起始地址 | 0x265DDF60 |
tlb_addr | tlb空间的地址 | 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阶段的命令的注册,以及执行,
主要实现函数为:
- MstarSysInit():主要完成板级外设的初始化工作:
1> os初始化
2> cache初始化
3> 中断初始化
4> 定时器初始化
5> MMIO(内存映射I/O)初始化
6> IR(红外?)初始化
7> SPI初始化
8> 看门狗初始化
9> MIU初始化
10> GPIO初始化
11> DMA初始化
12> USB初始化- MstarDrvInit()
1> 内核链表的初始化
Talbe_Init();
2> 将STAGE_MSINIT阶段的指令,挂载到内核链表
Core_Register_MsInit()
3> 取出指令
4> 执行指令
run_command
4 main_loop
main_loop函数做的都是与具体平台无关的工作(但mstar在uboot中客制化和很多东西,放在MstarProcess和MstarToKernel两函数中),主要完成以下功能:
(1)初始化启动次数限制机制
(2)Modem功能
(3)设置软件版本号
(4)启动延迟
(5)STAGE_PROCESS以及STAGE_TOKERNEL阶段的命令挂载以及执行
(6)读取命令,解析命令
(7)检查bootdel检查bootdelay时间内是否有按键按下,根据按键检查的结果进入控制台或者引导kernal
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*/
}