u-boot 第二阶段的代码就进入了一个C语言的环境。
进入这个阶段你的函数的board_init_r
void board_init_r(gd_t *id, ulong dest_addr)1. board_init_r 函数分析
gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
//此时的gd到底是指向什么位置呢? 在代码中,并没有发现对gd位置的重定向。只能说gd目前还处于sdram 的低端内存区域。而不是高端内存区域
//可以知道的是代码运行到这里,重定位已经完成。
/* Setup chipselects */
board_init(); //板级相关的初始化
/* arch number of SMDK2410-Board */ gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; /* adress of boot parameters */ gd->bd->bi_boot_params = 0x30000100; icache_enable(); dcache_enable();
//在 board_init 中对bi_arch_number和 bi_boot_params 两个重要的参数进行了赋值。这是的board 是2410。
//在移植2440的时候,需要适当的进行修改。 另外一个参数 启动的参数。这两个参数是需要传递给内核的。非常重要
//除此之外,还使能了cache
serial_initialize();
//串口的初始化
/* The Malloc area is immediately below the monitor copy in DRAM */
malloc_start = dest_addr - TOTAL_MALLOC_LEN;
mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
//初始第一阶段的malloc空间
/* arch number of SMDK2410-Board */ gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; /* adress of boot parameters */ gd->bd->bi_boot_params = 0x30000100; icache_enable(); dcache_enable();
#ifdef CONFIG_GENERIC_MMC //如果单板支持mmc。只需要在单板文件中定义 CONFIG_GENERIC_MMC 即可 puts("MMC: "); mmc_initialize(gd->bd); #endif /* initialize environment */ if (should_load_env()) env_relocate();
//初始化环境变量 环境变量有两种。一种是默认的,另一种是flash保存的环境变量(优先执行)
stdio_init(); /* get the devices list going. */ //得到设备清单 /* Initialize the list */ INIT_LIST_HEAD(&(devs.list)); drv_system_init (); serial_stdio_init ();//主要是串口信息的初始化
jumptable_init(); //跳转表的出初始化,暂时不明白干嘛用的 console_init_r(); /* fully init console as a device */ /* set up exceptions */ interrupt_init(); /* enable exceptions */ enable_interrupts();//设置中断和使能中断
/* Initialize from environment */ load_addr = getenv_ulong("loadaddr", 16, load_addr); (原值 0x30800000) eth_initialize(gd->bd)
//网卡的初始化
/* main_loop() can return to retry autoboot, if so just run it again. */ for (;;) { main_loop(); }
//进入一个主循环
2.main_loop 分析
在main_loop中有两种实现方式:一种是使用HUSH的这种主循环的方式,另一种是裸机代码形式的主循环 (参考连接 http://blog.csdn.net/andy_wsj/article/details/8614905)
逻辑代码的形式
char *s; int bootdelay;
//定义两个变量
s = getenv ("bootdelay"); bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; int strict_strtol
功能:将一个字符串转换sigend long型。
//将环境变量的字符串转换为一个数字
s = getenv ("bootcmd");//获得boot命令
if (bootdelay != -1 && s && !abortboot(bootdelay)) { run_command_list(s, -1, 0); }
//在倒计时计数前,没有空格,则执行run_command_list
//此时的s 表示的是bootcmd 是一个自启动命令
//bootcmd nand read.jffs 0x300007fc0 kernel
//bootm 0x300007fc0 //内核启动
/如果输入了空格
for(;;) len = readline (CONFIG_SYS_PROMPT); strcpy (lastcommand, console_buffer); rc = run_command(lastcommand, flag);
3. int run_command(const char *cmd, int flag) 分析
//builtin_run_command can return 0 or 1 for success, so clean up its result.
builtin_run_command(cmd, flag) // readline 大于零的情况 flag = 0; /* assume no special flags for now */ flag |= CMD_FLAG_REPEAT;
char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */ //存储每一个cmd CONFIG_SYS_CBSIZE 256 命令的长度限制在256字节 char *token; /* start of token in cmdbuf */ char *sep; /* end of token (separator) in cmdbuf */ char finaltoken[CONFIG_SYS_CBSIZE]; char *str = cmdbuf; //为后续的while 解析做准备 char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */ int argc, inquotes; int repeatable = 1; //命令的可重复性。在中断输入回车是否执行上一条命令 int rc = 0; clear_ctrlc(); /* forget any previous Control C */ //清楚CTRL+C 中止的命令 if (strlen(cmd) >= CONFIG_SYS_CBSIZE) { puts ("## Command too long!\n"); return -1; }
//限制长度
strcpy (cmdbuf, cmd);
//将形参传入的cmd 拷贝到cmdbuf中
while (*str) { /* * Find separator, or string end * Allow simple escape of ';' by writing "\;" */ for (inquotes = 0, sep = str; *sep; sep++) { if ((*sep=='\'') && (*(sep-1) != '\\')) inquotes=!inquotes; if (!inquotes && (*sep == ';') && /* separator */ ( sep != str) && /* past string start */ (*(sep-1) != '\\')) /* and NOT escaped */ break; }
//解析命令, 一个个提取出来。 命令的分割是以 \;作为标识的
token = str; /* find macros in this token and replace them */ process_macros (token, finaltoken);
//解析宏
/* Extract arguments */ if ((argc = parse_line (finaltoken, argv)) == 0) { rc = -1; /* no command at all */ continue; }
//提取参数
int parse_line (char *line, char *argv[])
例如 md.w 0
==> argv[0] = md.w //命令
argv[1] = 0 //参数
返回值 argc = 2
if (cmd_process(flag, argc, argv, &repeatable))
//执行命令
4. (cmd_process(flag, argc, argv, &repeatable)) 的执行过程
enum command_ret_t rc = CMD_RET_SUCCESS; //一个枚举变量。执行运行状态 enum command_ret_t { CMD_RET_SUCCESS, /* 0 = Success */ CMD_RET_FAILURE, /* 1 = Failure */ CMD_RET_USAGE = -1, /* Failure, please report 'usage' error */ };cmd_tbl_t *cmdtp;
//一个命令的结构体 这个结构体非常的重要-->命令的回调函数就是在这个结构体cmd_tbl_t 的函数指针中
typedef struct cmd_tbl_s cmd_tbl_t;
struct cmd_tbl_s { char *name; /* Command Name */ // 命令的查找 find_name 中有(strncmp (cmd, cmdtp->name, len) == 0) int maxargs; /* maximum number of arguments */ int repeatable; /* autorepeat allowed? */ //命令的可重复性 /* Implementation function */ int (*cmd)(struct cmd_tbl_s *, int, int, char * const []); //函数指针。命令的具体执行 cmd_call 中 result = (cmdtp->cmd)(cmdtp, flag, argc, argv); char *usage; /* Usage message (short) */ //命令的短 帮助信息 例如:输入help 在命令后边提示的 char *help; /* Help message (long) */ //命令的长帮助信息 例如 bootcmd -help }
/* Look up command in command table */
cmdtp = find_cmd(argv[0]);
//在命令表中 查找命令 。
//命令表具体又在哪里呢?在u-boot.lds链接脚本中有关于段的分配。其中就有u-boot cmd 段
//同时。每一个u-boot 的命令。都使用U_BOOT_CMD 进行修饰。这个宏就是将这些cmd 分配到对应的段中
. = ALIGN(4); .u_boot_list : { _u_boot_list__start = .; _u_boot_list_cmd__start = .; *(SORT(.u_boot_list.cmd.*)); _u_boot_list_cmd__end = .; _u_boot_list_env_clbk__start = .; *(SORT(.u_boot_list.env_clbk.*)); _u_boot_list_env_clbk__end = .; *(SORT(.u_boot_list.*)); _u_boot_list__end = .; }
#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \
U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL) Command.h (\include)
..... //省略一些
#define ll_entry_declare(_type, _name, _section_u, _section_d) \ _type _u_boot_list_##_section_u##_##_name __attribute__(( \ unused, aligned(4), \ section(".u_boot_list."#_section_d"."#_name)))//find_cmd 函数的具体分析。后续在分析
if (cmdtp == NULL) { printf("Unknown command '%s' - try 'help'\n", argv[0]); return 1; }//如果没有相应的命令则打印提示 Unknown command '%s' - try 'help'\n
if (argc > cmdtp->maxargs)
rc = CMD_RET_USAGE;
//判断参数的格式。是否大于参数的最大值 //这个maxargs 应当是从find_cmd 中查找到的参数,返回而得到的
//如果大于。则标记为 CMD_RET_USAGE
/* If OK so far, then do the command */ if (!rc) { rc = cmd_call(cmdtp, flag, argc, argv); *repeatable &= cmdtp->repeatable; }//如果rc 等于 CMD_RET_SUCCESS 。则执行cmd对应的函数
if (rc == CMD_RET_USAGE )
rc = cmd_usage(cmdtp);
return rc;
//如果rc == CMD_RET_USAGE ,则打印usage 信息
5.cmd_call(cmdtp, flag, argc, argv); 函数分析
Call a command function.
static int cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
result = (cmdtp->cmd)(cmdtp, flag, argc, argv);//执行回调函数
int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);//cmd 函数的原型
下边以bootm为例分析
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
//bootm 的函数原型
6.bootm 分析
6.1 命令模块的框架
文件的命名cmd_xxx.c
框架:
#include <common.h> #include <command.h> int do_xxx (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { .... return 0; } U_BOOT_CMD( xxx, 1, 0, do_xxx, "short usage message", " long usage message" );
6.2 bootm 实现的分析
文件 cmd_bootm.c
6.2.1 分析U_BOOT_CMD这个宏
# define _CMD_HELP(x) x, //首先这里的宏定义 # 后边有个空格,这样的语法,还需要了解 # define _CMD_COMPLETE(x) #define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \ _usage, _help, _comp) \ { #_name, _maxargs, _rep, _cmd, _usage, \ _CMD_HELP(_help) _CMD_COMPLETE(_comp) } ==> #define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \ { #_name, _maxargs, _rep, _cmd, _usage, _help,} #define ll_entry_declare(_type, _name, _section_u, _section_d) \ _type _u_boot_list_##_section_u##_##_name __attribute__(( \ unused, aligned(4), \ section(".u_boot_list."#_section_d"."#_name))) ==>整理一下形式 #define ll_entry_declare(_type, _name, _section_u, _section_d) \ _type _u_boot_list_##_section_u##_##_name __attribute__(( unused, aligned(4),section(".u_boot_list."#_section_d"."#_name))) #define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \ ll_entry_declare(cmd_tbl_t, _name, cmd, cmd) = \ U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \ _usage, _help, _comp); ==》 #define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \ cmd_tbl_t _u_boot_list_##cmd##_##cmd_tbl_t __attribute__(( unused, aligned(4),section(".u_boot_list."#cmd"."#_name))) \ { #_name, _maxargs, _rep, _cmd, _usage, _help,} #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \ U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL) ==》 #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \ cmd_tbl_t _u_boot_list_##cmd##_##cmd_tbl_t __attribute__(( unused, aligned(4),section(".u_boot_list."cmd"."_name))) \ { #_name, _maxargs, _rep, _cmd, _usage, _help,} U_BOOT_CMD( bootm, CONFIG_SYS_MAXARGS, 1, do_bootm, "boot application image from memory", bootm_help_text ); ==>_name:bootm _maxargs: CONFIG_SYS_MAXARGS(16) _rep: 1 _cmd:do_bootm _usage: "boot application image from memory" //字符串 _help : bootm_help_text //字符串 ==>字符数组的首地址 bootm_help_text: static char bootm_help_text[] = "[addr [arg ...]]\n - boot application image stored in memory\n" "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" "\t'arg' can be the address of an initrd image\n" "\nSub-commands to do part of the bootm sequence. The sub-commands " "must be\n" "issued in the order below (it's ok to not issue all sub-commands):\n" "\tstart [addr [arg ...]]\n" "\tloados - load OS image\n" "\tcmdline - OS specific command line processing/setup\n" "\tbdt - OS specific bd_t processing\n" "\tprep - OS specific prep before relocation or go\n" "\tgo - start OS"; } cmd_tbl_t _u_boot_list_do_bootm_cmd_tbl_t __attribute__(( unused, aligned(4),section(".u_boot_list."do_bootm"."bootm))) \ { bootm, 16, 1, do_bootm, "boot application image from memory", "[addr [arg ...]]\n - boot application image stored in memory\n" "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n" "\t'arg' can be the address of an initrd image\n" "\nSub-commands to do part of the bootm sequence. The sub-commands " "must be\n" "issued in the order below (it's ok to not issue all sub-commands):\n" "\tstart [addr [arg ...]]\n" "\tloados - load OS image\n" "\tcmdline - OS specific command line processing/setup\n" "\tbdt - OS specific bd_t processing\n" "\tprep - OS specific prep before relocation or go\n" "\tgo - start OS";,} ;//观察这个存储在u_boot_list段中的这个 _u_boot_list_do_bootm_cmd_tbl_t可以知道。这是在定义一个 cmd_tbl_t类型的变量,同时对它进行初始化操作
c语言中的#号和##号的作用 http://blog.chinaunix.net/uid-27666459-id-3772549.html