u-boot分析之u-boot命令实现

本文详细介绍了U-Boot中命令的实现原理,包括命令输入、解析及执行过程,并通过实例展示了如何自定义命令。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当我们在串口的控制台上输入一个命令,要么提示不能识别的命令,要么就会打印某些东西(执行)。这些命令是怎么实现的?

使用命令的步骤:
1,输入字符串,对应某些命令名。
2,执行。

显然,在程序里面是根据这些命令,找到对应的函数,然后执行相应的函数;在在u-boot不会只有一个结构体,这些命令肯定会有一个结构体,结构体中包括:名字、函数;根据输入的命令到这个结构体链中一一比较,然后执行;

先看一下run_command的实现,它的代码如下:







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 finaltoken[CFG_CBSIZE];
    char *str = cmdbuf;
    char *argv[CFG_MAXARGS + 1];    /* NULL terminated  */
    int argc, inquotes;
    int repeatable = 1;
    int rc = 0;

#ifdef DEBUG_PARSER
    printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
    puts (cmd ? cmd : "NULL");  /* use puts - string may be loooong */
    puts ("\"\n");
#endif

    clear_ctrlc();      /* forget any previous Control C */

    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
     */

#ifdef DEBUG_PARSER
    printf ("[PROCESS_SEPARATORS] %s\n", cmd);
#endif
    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';
        }
        else
            str = sep;  /* no more commands for next pass */
#ifdef DEBUG_PARSER
        printf ("token: \"%s\"\n", token);
#endif

        /* 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;
        }

        /* 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;
        }

#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
        /* avoid "bootd" recursion */
        if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSER
            printf ("[%s]\n", finaltoken);
#endif
            if (flag & CMD_FLAG_BOOTD) {
                puts ("'bootd' recursion detected\n");
                rc = -1;
                continue;
            } else {
                flag |= CMD_FLAG_BOOTD;
            }
        }
#endif  /* CFG_CMD_BOOTD */

        /* 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? */
        if (had_ctrlc ())
            return 0;   /* if stopped then not repeatable */
    }

    return rc ? rc : repeatable;
}













这段代码中调用了find_cmd函数查找命令对应的函数,find_cmd函数如下:


/***************************************************************************
 * find command table entry for a command
 */
cmd_tbl_t *find_cmd (const char *cmd)
{
    cmd_tbl_t *cmdtp;
    cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;    /*Init value */
    const char *p;
    int len;
    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);

    /*
    *  __u_boot_cmd_start,__u_boot_cmd_end这两个变量是在链接脚本里面
    * 
    **/
    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 */
}

命令对应的结构体代码如下:

struct cmd_tbl_s {
    char        *name;      /* Command Name         */
    int     maxargs;    /* maximum number of arguments  */
    int     repeatable; /* autorepeat allowed?      */
                    /* Implementation function  */
    int     (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
    char        *usage;     /* Usage message    (short) */
#ifdef  CFG_LONGHELP
    char        *help;      /* Help  message    (long)  */
#endif
#ifdef CONFIG_AUTO_COMPLETE
    /* do auto completion on the arguments */
    int     (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};

这个命令结构体包含了命令名、帮助信息、执行函数,其中cmd就是一个函数指针;

实践操作

如何在u-boot里面自定义一个hello命令?
1,首先我们在u-boot的common目录下增加一个cmd_hello.c文件 。
参照其他命令的书写方式,代码如下 :

#include <image.h>
#include <malloc.h>
#include <u-boot/zlib.h>
#include <bzlib.h>
#include <environment.h>
#include <lmb.h>
#include <linux/ctype.h>
#include <asm/byteorder.h>

int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    int i = 0;
    printf("hello,Lover!!!\nthe argcs are \n");
    for(i = 0 ; i<argc ; i++)
        printf("argv[%d]: %s\n",i,argv[i]);
    return 0;
}



U_BOOT_CMD(
    hello,    CONFIG_SYS_MAXARGS,    1,    do_hello,
    "This is a user defined command hello,Lover!!!",
    "hello,long help ......\n"

    ); 

2, 修改common下面的makefile文件,告诉U-Boot编译我们自定义的C文件
参考Makefile中其他文件的定义,加入一句

COBJS-y += cmd_hello.o

3,重新make编译 u-boot

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值