05-uboot分析之uboot命令实现

本文深入探讨U-Boot命令系统的工作原理,包括命令的解析与执行过程,以及如何自定义并添加新的命令。通过分析源码,详细解释了从串口接收命令到调用相应处理函数的全过程,并以bootm和hello命令为例,展示了如何在U-Boot中实现自定义命令。

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

uboot分析之uboot命令实现

// md.w 0 命令打印0地址的内容
OpenJTAG> md.w 0
00000000: 00ff ea00 f014 e59f f014 e59f f014 e59f    ................
00000010: f014 e59f f014 e59f f014 e59f f014 e59f    ................
00000020: 0160 33f8 01c0 33f8 0220 33f8 0280 33f8    `..3...3 ..3...3
00000030: 02e0 33f8 0400 33f8 0420 33f8 beef dead    ...3...3 ..3....
00000040: 0000 33f8 0000 33f8 06ac 33fb 7904 33fb    ...3...3...3.y.3
00000050: c0de 0bad c0de 0bad 0000 0000 c0de 0bad    ................
00000060: c0de 0bad 0000 e10f 001f e3c0 00d3 e380    ................
00000070: f000 e129 0453 e3a0 1000 e3a0 1000 e580    ..).S...........


u-boot的命令:
    1. 串口输入命令
    2. 处理命令, 输出结果
    
处理的时候肯定是根据命令名字找到对应的处理函数, 然后调用处理函数

看看run_command实现:
int run_command (const char *cmd, int flag)
{
    char cmdbuf[CFG_CBSIZE];    /* working copy of cmd        */
    
    ...
    strcpy (cmdbuf, cmd);
    while (*str) {

        /*
         * Find separator, or string end
         * Allow simple escape of ';' by writing "\;"
         */
        /* 查找是否有;分号隔开两个命令 */

        /* 处理宏 下载文件到内存时会临时生成一些宏 */
        /* find macros in this token and replace them */
        process_macros (token, finaltoken);

        /* 提取参数 argc argv*/
        /* 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 */
    }
}

命令结构:
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)    短的帮助信息 执行help看到的信息 */
#ifdef    CFG_LONGHELP
    char        *help;        /* Help  message    (long)    长的帮助信息 对某个命令执行help看到的信息 */
#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_tbl_t *find_cmd (const char *cmd)
{
    cmd_tbl_t *cmdtp;
    cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;    /*Init value__u_boot_cmd_start从uboot.lds文件中传进来 */
    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);

    for (cmdtp = &__u_boot_cmd_start;      // __u_boot_cmd_start从uboot.lds文件中传进来
         cmdtp != &__u_boot_cmd_end;    // __u_boot_cmd_end从uboot.lds文件中传进来
         cmdtp++) {
        if (strncmp (cmd, cmdtp->name, len) == 0) { //从__u_boot_cmd_start到__u_boot_cmd_end逐个比对命令名
            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 */
}

bootm命令分析:
    我们输入bootm 0x30007FC0命令之后就确定内核, 看看bootm命令是调用哪个函数执行
    
在cmd_bootm.c定义了一个宏:
U_BOOT_CMD(
     bootm,    CFG_MAXARGS,    1,    do_bootm,
     "bootm   - boot application image from memory\n",
     "[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"
#ifdef CONFIG_OF_FLAT_TREE
    "\tWhen booting a Linux kernel which requires a flat device-tree\n"
    "\ta third argument is required which is the address of the of the\n"
    "\tdevice-tree blob. To boot that kernel without an initrd image,\n"
    "\tuse a '-' for the second argument. If you do not pass a third\n"
    "\ta bd_info struct will be passed instead\n"
#endif
);

在command.h中定义了一个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}

name = bootm
maxargs = CFG_MAXARGS
rep = 1
cmd = do_bootm
usage = "bootm   - boot application image from memory\n"
help = "[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"

command.h中定义宏
#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

将以上值代入宏
cmd_tbl_t __u_boot_cmd_bootm __attribute__ ((unused,section (".u_boot_cmd"))) = {
    bootm,
    CFG_MAXARGS,
    1,
    do_bootm,
    "boo...memory\n",
    "[add..image\n"
}

可以看出以上定义了名为__u_boot_cmd_bootm的cmd_tbl_t类型的结构体, 结构体的属性section(段属性)强制设置为.u_boot_cmd
__attribute__ ((unused,section (".u_boot_cmd")))是强制把section段属性设置为.u_boot_cmd

可以看出所有用U_BOOT_CMD定义的东西都会相当定义了一个cmd_tbl_t类型的结构,
这个结构体的特别之处就是它的段属性被强制设置为.u_boot_cmd, 所以所有的命令都被集中在__u_boot_cmd_start到__u_boot_cmd_end之间



实现简单的hello命令
创建cmd_hello.c

#include <common.h>
#include <watchdog.h>
#include <command.h>
#include <image.h>
#include <malloc.h>
#include <zlib.h>
#include <bzlib.h>
#include <environment.h>
#include <asm/byteorder.h>

int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
    int i = 0;

    for (i = 0; i < argc; i++)
        printf("%s\r\n", argv[i]);
    printf("hello world\r\n");

    return 0;
}


U_BOOT_CMD(
     hello,    CFG_MAXARGS,    1,    do_hello,
     "hello   - hello\n",
     "hello - long hello.........\n"
);

存放在common目录, 修改common目录下的Makefile文件, 加入cmd_hello.o
编译, 烧写就可以执行hello命令了
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值