关于BOOTCMD

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_PARSER
 if (run_command (getenv ("bootcmd"), flag) < 0)
  rcode = 1;
#else
 if (parse_string_outer (getenv ("bootcmd"),
   FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
  rcode = 1;
#endif
 return 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_KEYED
  int prev = disable_ctrlc(1); /* disable Control C checking */
# 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 */
# 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 */

 

上的代码中在函数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所定义的命令。因此,对这俩个变量的定义很重要,如果定义不对就不能正确的加载内核和文件系统。尤其是必须确保文件系统所在分区

你可能感兴趣的:(关于BOOTCMD)