uboot的最终目的是引导内核,在此之前uboot需要完成一系列初始化操作,包括设置时钟、初始化DDR、Flash、串口、网卡等等,这时uboot有两条路走(1)通过按键,触发uboot进入命令行模式,等待处理命令。(2)引导内核。具体选择走哪个路,怎么走。main_loop将告诉我们。
我们知道,uboot经过初始化后最终进入main_loop函数,并陷入死循环,不再返回。对于uboot2016,03,其代码如下。
void main_loop(void)
{
const char *s;
//bootstage_mark_name函数调用了show_boot_progress,记录执行到哪一步了。
bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
#ifndef CONFIG_SYS_GENERIC_BOARD
puts("Warning: Your board does not use generic board. Please read\n");
puts("doc/README.generic-board and take action. Boards not\n");
puts("upgraded by the late 2014 may break or be removed.\n");
#endif
#ifdef CONFIG_VERSION_VARIABLE
//setenv设置环境变量ver为version_string.
//const char __weak version_string[] = U_BOOT_VERSION_STRING;(Version.c)
//#define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \
U_BOOT_TIME " " U_BOOT_TZ ")" CONFIG_IDENT_STRING
//其中U_BOOT_VERSION ,U_BOOT_DATE,U_BOOT_TIME,U_BOOT_TZ均由u-boot构建系统自动产生,它们分别代表u-boot版本号,编译日期和时间,以及时间区。
setenv("ver", version_string); /* set version variable */
#endif /* CONFIG_VERSION_VARIABLE */
//如果定义了CONFIG_SYS_HUSH_PARSER,那么配置u-boot使用hush shell来作为执行器。hush shell是一种轻量型的shell。cli_init用来初始化hush shell使用的一些变量。hush shell的实现机制比较复杂,这里不做过多解释。
cli_init();
//run_preboot_environment_command函数从环境变量中获取"preboot"的定义,该变量包含了一些预启动命令,一般环境变量中不包含该项配置。
run_preboot_environment_command();
#if defined(CONFIG_UPDATE_TFTP)
update_tftp(0UL, NULL, NULL);
#endif /* CONFIG_UPDATE_TFTP */
//bootdelay_process从环境变量中取出"bootdelay"和"bootcmd"的配置值,将取出的"bootdelay"配置值转换成整数,赋值给全局变量stored_bootdelay,最后返回"bootcmd"的配置值。bootdelay为u-boot的启动延时计数值,计数期间内如无用户按键输入干预,那么将执行"bootcmd"配置中的命令。
s = bootdelay_process();
if (cli_process_fdt(&s))
cli_secure_boot_cmd(s);
//在执行的时间stored_bootdelay(秒)内,如无用户按键输入干预,那么abortboot_normal函数将返回0,否则返回1。 当无用户按键干预时,接下来将调用run_command_list执行上述从环境变量中读取的"bootcmd"配置值。注意该函数的参数s。run_command_list中调用了hush shell的命令解释器(parse_stream_outer函数),解释bootcmd中的启动命令。环境变量bootcmd中的启动命令,用来设置linux必要的启动环境,然后加载和启动linux内核。u-boot启动linux内核后,将控制权交给linux内核,至此不再返回。
autoboot_command(s);
//若启动内核,则不会执行到cli_loop,若按键,则进入cli_loop函数,循环等待执行命令。
cli_loop();
}
uboot打印信息:
U-Boot 2016.03-mys-6ulx+g4ade113 (Sep 16 2017 - 23:49:21 +0800)
CPU: Freescale i.MX6UL rev1.1 528 MHz (running at 396 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 36C
Reset cause: POR
Board: MX6UL 14x14 EVK
I2C: ready
DRAM: 256 MiB
NAND: 256 MiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1
*** Warning - bad CRC, using default environment
Display: TFT43AB (480x272)
Video: 480x272x24
In: serial
Out: serial
Err: serial
Net: FEC0
Error: FEC0 address not set.
Normal Boot
Hit any key to stop autoboot: 0
NAND read: device 0 offset 0x500000, size 0xa00000
10485760 bytes read: OK
NAND read: device 0 offset 0xf00000, size 0x100000
1048576 bytes read: OK
Kernel image @ 0x80800000 [ 0x000000 - 0x686000 ]
## Flattened Device Tree blob at 83000000
Booting using the fdt blob at 0x83000000
Using Device Tree in place at 83000000, end 8300c171
Modify /soc/aips-bus@02000000/bee@02044000:status disabled
ft_system_setup for mx6
Starting kernel ...
Booting Linux on physical CPU 0x0
Linux version 4.1.15-1.2.0+g422cbfb (blackrose@brix4770-debian) (gcc version 5.3.0 (GCC) ) #1 SMP PREEMPT Wed Sep 13 15:38:23 CST 2017
CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c53c7d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine model: Freescale i.MX6 UltraLite 14x14 EVK Board
Reserved memory: failed to allocate memory for node 'linux,cma'
Memory policy: Data cache writealloc
PERCPU: Embedded 12 pages/cpu @8fdd2000 s16908 r8192 d24052 u49152
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 65024
Kernel command line: console=ttymxc0,115200 ubi.mtd=3 root=ubi0:rootfs rootfstype=ubifs mtdparts=gpmi-nand:5m(boot),10m(kernel),1m(dtb),-(rootfs)
PID hash table entries: 1024 (order: 0, 4096 bytes)
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 246672K/262144K available (8626K kernel code, 440K rwdata, 3028K rodata, 432K init, 450K bss, 15472K reserved, 0K cma-reserved, 0K highmem)
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
vmalloc : 0x90800000 - 0xff000000 (1768 MB)
lowmem : 0x80000000 - 0x90000000 ( 256 MB)
pkmap : 0x7fe00000 - 0x80000000 ( 2 MB)
modules : 0x7f000000 - 0x7fe00000 ( 14 MB)
.text : 0x80008000 - 0x80b69af0 (11655 kB)
.init : 0x80b6a000 - 0x80bd6000 ( 432 kB)
.data : 0x80bd6000 - 0x80c440a0 ( 441 kB)
.bss : 0x80c47000 - 0x80cb7b40 ( 451 kB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Preemptible hierarchical RCU implementation.
Additional per-CPU info printed with stalls.
RCU restricting CPUs from NR_CPUS=4 to nr_cpu_ids=1.
RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
NR_IRQS:16 nr_irqs:16 16
ENTRY(_main)-》board_init_f-》init_sequence_f:
第一句打印:
display_options:
printf ("\n\n%s\n\n", version_string);//第一句打印:打印uboot版本、编译时间等信息。
const char __weak version_string[] = U_BOOT_VERSION_STRING;
#define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \
U_BOOT_TIME " " U_BOOT_TZ ")" CONFIG_IDENT_STRING
第二句打印:
print_cpuinfo: //第二句打印:打印CPU信息
printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n",
get_imx_type((cpurev& 0xFF000) >> 12),
(cpurev& 0x000F0) >> 4,
(cpurev& 0x0000F) >> 0,
mxc_get_clock(MXC_ARM_CLK)/ 1000000);
没有按键启动内核:
main_loop->autoboot_command->run_command_list->cli_simple_run_command_list->cli_simple_run_command->cmd_process->find_cmd(argv[0])
U_BOOT_CMD(
nand, CONFIG_SYS_MAXARGS, 1, do_nand,
"NAND sub-system", nand_help_text
);
->do_nand->if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0)
启动内核命令:
U_BOOT_CMD->do_bootz->bootz_start->bootz_setup
到此我们可以看出uboot通过U_BOOT_CMD来定义一个命令。后面我们会分析uboot的命令。