天天看點

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