天天看点

05-uboot分析之uboot命令实现

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];    

    ...

    strcpy (cmdbuf, cmd);

    while (*str) {

        process_macros (token, finaltoken);

        if ((argc = parse_line (finaltoken, argv)) == 0) {

            rc = -1;    

            continue;

        }

        if ((cmdtp = find_cmd(argv[0])) == NULL) {

            printf ("Unknown command '%s' - try 'help'\n", argv[0]);

            rc = -1;    

            continue;

        }

        if (argc > cmdtp->maxargs) {

            printf ("Usage:\n%s\n", cmdtp->usage);

            rc = -1;

            continue;

        }

#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)

        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    

        if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {

            rc = -1;

        }

        repeatable &= cmdtp->repeatable;

        if (had_ctrlc ())

            return 0;    

    }

}

命令结构:

struct cmd_tbl_s {

    char        *name;        

    int        maxargs;    

    int        repeatable;    

    int        (*cmd)(struct cmd_tbl_s *, int, int, char *[]);

    char        *usage;        

#ifdef    CFG_LONGHELP

    char        *help;        

#endif

#ifdef CONFIG_AUTO_COMPLETE

    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;    

    const char *p;

    int len;

    int n_found = 0;

    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;    

            cmdtp_temp = cmdtp;    

            n_found++;

        }

    }

    if (n_found == 1) {            

        return cmdtp_temp;

    }

    return NULL;    

}

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命令了