uboot启动linux内核小结(boot,bootd,boom,bootcmd,bootargs)

uboot在进行系统启动和内核加载的时候被分为俩个阶段,

第一阶段主要是写汇编代码,我没有仔细研究,只是看了看移植好的针对mini2440的tekkman的uboot代码。

第二个阶段为由C写成,易于研究和学习。掌握了基本的流程。

(1)第一阶段的功能

? 硬件设备初始化

? 加载U-Boot第二阶段代码到RAM空间

? 设置好栈

? 跳转到第二阶段代码入口

(2)第二阶段的功能

? 初始化本阶段使用的硬件设备

? 检测系统内存映射

? 将内核从Flash读取到RAM中

? 为内核设置启动参数

? 调用内核

第二阶段的C出口函数为:

由于在cpu/arm920t/start.S的最后阶段有如下代码:

ldr pc, _start_armboot

_start_armboot: .word start_armboot 此时pc指针将会跳转到lib_arm/board.c中定义的函数start_armboot().因此start_armboot().函数是c代码的入口代码,分析就从这里起航。

而在函数start_armboot()中有个死循环,

/* main_loop() can return to retry autoboot, if so just run it again. */for (;;)

{main_loop ();接受用户在uboot命令行输入的命令。}

在uboot启动的时候,如果在#define CONFIG_BOOTDELAY 1超时之前用户没有输入,uboot就会自动加载linux内核,

其加载时将使用变量“bootcmd”和 “bootargs”在uboot代码所定义的变量值进行启动代码。

变量“bootcmd”和 “bootargs”的值可以在在加载linux内核前,uboot的命令行中进行修改。

我这俩个参数的值如下:

bootcmd=nfs 0x30008000 192.168.1.149:/opt/FriendlyARM/uImage;bootm —— 需要注意的是再bootcmd变量的最后添加了bootm命令。bootargs=noinitrd root=/dev/nfs proto=tcp,nolock,nfsvers=3, rw nfsroot=192.168.1.149:/mini2440/rootfs ip=192.168.1.144:192.168.1.149::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M

首先看看启动内核是俩种比较简单明白的方式,boot,bootd命令的实现。

现实代码如下:

/*******************************************************************//* bootd – boot default image *//*******************************************************************/#if defined(CONFIG_CMD_BOOTD)int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){int rcode = 0;

#ifndef CONFIG_SYS_HUSH_PARSERif (run_command (getenv ("bootcmd"), flag) < 0)rcode = 1;#elseif (parse_string_outer (getenv ("bootcmd"),FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)rcode = 1;#endifreturn rcode;}

U_BOOT_CMD(boot,1,1,do_bootd,"boot default, i.e., run ‘bootcmd’","");

/* keep old command name "bootd" for backward compatibility */U_BOOT_CMD(bootd, 1,1,do_bootd,"boot default, i.e., run ‘bootcmd’","");

#endif

从上面的对命令boot,bootd命令实现可以知道,其命令的最终执行的是“bootcmd”命令行参数所定义的值

即"nfs 0x30008000 192.168.1.149:/opt/FriendlyARM/uImage;bootm ":

在上面的函数main_loop ()中又如下代码片段

s = getenv ("bootcmd");

debug ("### main_loop: bootcmd=\&;%s\&;\n", s ? s : "<UNDEFINED>");

if (bootdelay >= 0 && s && !abortboot (bootdelay)){# ifdef CONFIG_AUTOBOOT_KEYEDint prev = disable_ctrlc(1);/* disable Control C checking */# endif

# ifndef CONFIG_SYS_HUSH_PARSERrun_command (s, 0);# elseparse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);# endif

# ifdef CONFIG_AUTOBOOT_KEYEDdisable_ctrlc(prev);/* restore Control C checking */# endif}

# ifdef CONFIG_MENUKEYif (menukey == CONFIG_MENUKEY) { s = getenv("menucmd"); if (s) {# ifndef CONFIG_SYS_HUSH_PARSERrun_command (s, 0);# elseparse_string_outer(s, FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);# endif }}#endif /* CONFIG_MENUKEY */#endif/* CONFIG_BOOTDELAY */

上的代码中在函数abortboot (bootdelay))

执行的过程中已经超时,则自动的执行"bootcmd" 所定义的命令。

现在看看命令"bootm"命令式如何实现的?

"boot application image from memory",这句话很重要,表明bootm执行是必须确保uImage已经在内从中,

在"bootm addr"中当addr省略的时候bootm加载宏#define CONFIG_SYS_LOAD_ADDR 0x30008000 /* default load address */定义处的内核image。

"bootm"命令的实现函数为do_bootm(),在do_bootm()中完成对linux内核的加载启动。

其加载函数为:do_bootm_linux()函数中获取了"bootargs"环境变量的值。最终将此值传递给linux内核,用来加载文件系统时候使用。

对do_bootm()和do_bootm_linux()函数的分析可以找到看其他朋友的分析。

总结

在uboot中每一个命令都对应一个其实现的函数,在启动linux内核过程中,主要是执行环境变量bootcmd和bootargs所定义的命令。因此,对这俩个变量的定义很重要,如果定义不对就不能正确的加载内核和文件系统。尤其是必须确保文件系统所在分区。

我就想是一只草原中被牧童遗忘的羊,

uboot启动linux内核小结(boot,bootd,boom,bootcmd,bootargs)

相关文章:

你感兴趣的文章:

标签云: