自己写bootloader(5)——命令的实现

来源:互联网 发布:软件,程序,文件 编辑:程序博客网 时间:2024/05/21 09:28

我们先来看看运行命令的函数

/**************************************************************************** * returns: *1  - command executed, repeatable *0  - command executed but not repeatable, interrupted commands are *     always considered not repeatable *-1 - not executed (unrecognized, bootd recursion or too many args) *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is *           considered unrecognized) * * WARNING: * * We must create a temporary copy of the command since the command we get * may be the result from getenv(), which returns a pointer directly to * the environment data, which may change magicly when the command we run * creates or modifies environment variables (like "bootp" does). */ /**************************************************************************** * returns: *1  - command executed, repeatable *0  - command executed but not repeatable, interrupted commands are *     always considered not repeatable *-1 - not executed (unrecognized, bootd recursion or too many args) *           (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is *           considered unrecognized) * * WARNING: * * We must create a temporary copy of the command since the command we get * may be the result from getenv(), which returns a pointer directly to * the environment data, which may change magicly when the command we run * creates or modifies environment variables (like "bootp" does). */int run_command (const char *cmd, int flag){cmd_tbl_t *cmdtp;char cmdbuf[CFG_CBSIZE];/* working copy of cmd*/char *token;/* start of token in cmdbuf*/char *sep;/* end of token (separator) in cmdbuf */char *str = cmdbuf;char *argv[16 + 1];/* NULL terminated*/int argc, inquotes;int repeatable = 1;int rc = 0;if (!cmd || !*cmd) {return -1;/* empty command */}if (strlen(cmd) >= CFG_CBSIZE) {puts ("## Command too long!\n");return -1;}strcpy (cmdbuf, cmd);/* Process separators and check for invalid * repeatable commands */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;}/* * Limit the token to data between separators */token = str;if (*sep) {str = sep + 1;/* start of command for next pass */*sep = '\0';}elsestr = sep;/* no more commands for next pass *//* find macros in this token and replace them *///process_macros (token, finaltoken);/* Extract arguments */if ((argc = parse_line (cmdbuf, argv)) == 0) {rc = -1;/* no command at all */continue;}//printc("The argv[0] is %c !\n\r",argv[0]);/* Look up command in command table */if ((cmdtp = find_cmd(argv[0])) == NULL) {printf ("Unknown command '%s' - try 'help'\n", argv[0]);rc = -1;/* give up after bad command */continue;}/* found - check max args */if (argc > cmdtp->maxargs) {printf ("Usage:\n%s\n", cmdtp->usage);rc = -1;continue;}/* OK - call function to do the command */if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {rc = -1;}repeatable &= cmdtp->repeatable;/* Did the user stop this? */}return rc ? rc : repeatable;}

parse_line (cmdbuf, argv)                            解析命令,将命令和参数分别装入数组argv[0]、argv[1]......

find_cmd(argv[0])                                         查找命令

(cmdtp->cmd) (cmdtp, flag, argc, argv)       运行命令


那么是如何来查找的呢?

cmd_tbl_t *find_cmd (char *cmd){cmd_tbl_t *cmdtp;cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;/*Init value *///char *p;int len =0;int n_found = 0;/* * Some commands allow length modifiers (like "cp.b"); * compare command name only until first dot. *///len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);len = strlen (cmd);for (cmdtp = &__u_boot_cmd_start;     cmdtp != &__u_boot_cmd_end;     cmdtp++) { if (strncmp (cmd, cmdtp->name, len) == 0) {if (len == strlen (cmdtp->name))return cmdtp;/* full match */cmdtp_temp = cmdtp;/* abbreviated command ? */n_found++;}}if (n_found == 1) {/* exactly one match */return cmdtp_temp;}return NULL;/* not found or ambiguous command */}

find_cmd的实现的主要功能是在地址__u_boot_cmd_start和__u_boot_cmd_end之间查找是否有cmdtp结构体的名字与cmd相等,如果匹配成功则返回cmdtp结构


那么如何新增一个命令到地址__u_boot_cmd_start和__u_boot_cmd_end之间呢?

u-boot中有一个宏能实现这个功能

#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

定义了一个类型为cmd_tbl_t的结构体

结构体名字为__u_boot_cmd_##name,##为连词符号

这个结构体的段属性设为.u_boot_cmd


例如我们要添加一个hello命令

U_BOOT_CMD( hello,16,1,do_hello, "hello   - jest for a test\n\r", "hello,  long   help......\n\r" );

gcc预编译的时候会定义这个结构体,链接时会链接到.u_boot_cmd段,我们执行hello命令的时候会调用这个cmd_tbl_t结构体中的do_hello函数


最后来看一下连接脚本

SECTIONS {    . = 0x33f80000;    .text : { *(.text) }    . = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.got : { *(.got) }. = .;__u_boot_cmd_start = .;.u_boot_cmd : { *(.u_boot_cmd) }__u_boot_cmd_end = .;. = ALIGN(4);__bss_start = .;.bss : { *(.bss) }_end = .;}

可以看出.u_boot_cmd段是在文件的最后,因为.bss段是不在文件内的


0 0