The embedded linux Development uboot transplant ( 5、 ... and )——uboot Command system

     This article will be based on SMDKV210 Samsung's official development board uboot Source code analysis uboot The command system of . Content Include uboot The implementation mechanism of the command system of ,uboot How commands are executed , And how to uboot Add a custom command to .

One 、uboot An introduction to the command system

        uboot The command system code is placed in uboot/common in , Include cmd_xxx.c、command.c 、main.c The source code file .uboot The way to implement the command system is every uboot The command corresponds to a function , And shell The implementation of is consistent .

    uboot The command system doesn't use arrays 、 Linked list , It's one for each command cmd_tbl_t Command type structure , Through to cmd_tbl_t Section property setting of command type structure , The command set is stored in the custom section of the program .u_boot_cmd in , The program allocates the command set to a custom segment in the program during the link phase . The link script command set custom section is as follows :

__u_boot_cmd_start = .;// The starting address of the command set segment

.u_boot_cmd : { *(.u_boot_cmd) }// The commands in the command set

__u_boot_cmd_end = .;// The end address of the command set segment

cmd_tbl_t The segment properties of the command type structure are set as follows :

#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))#ifdef  CFG_LONGHELP#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}#else/* no long help info */#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}#endif/* CFG_LONGHELP */

    U_BOOT_CMD The macro actually defines a cmd_tbl_t Type command structure ,U_BOOT_CMD The six parameters of a macro are cmd_tbl_t The six members of the type command structure .

Examples are as follows :

U_BOOT_CMD(hello, 0, 0, do_hello, "hello world help info");

The macro expands to :

cmd_tbl_t __u_boot_cmd_hello __attribute___((unused, section(".u_boot_cmd"))) = {"hello", 0, 0, do_hello, "hello world help info"}

     By adding the cmd_tbl_t The segment property of the command type structure is set to .u_boot_cmd, To ensure that uboot All commands in the command set will be linked and assigned to .u_boot_cmd Custom segment , Of course, the order is here .u_boot_cmd Custom segments are sorted randomly .

    uboot Each command in the command set corresponds to a cmd_tbl_t Type variable , When a user enters a command ,uboot The command system will look up the input command in the command set , If you find it, do it , If the command is not found, it will prompt that the information is not found .

struct cmd_tbl_s {char *name;// Command name /* Command Name*/int maxargs;// Maximum number of parameters /* maximum number of arguments*/int repeatable;// Auto repeat /* autorepeat allowed?*//* Implementation function*/int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);// The function pointer of the corresponding function of the command char *usage;// Easy to use /* Usage message(short)*/#ifdef CFG_LONGHELPchar *help;// Detailed help information /* 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[]);// Command auto-complete #endif};typedef struct cmd_tbl_scmd_tbl_t;

Two 、uboot Command parsing

    uboot After starting, enter BL2 After the phase, the final execution is main_loop function , If the character key is not pressed during the automatic countdown ,uboot Will start automatically kernel; If you press the character key ,uboot It will enter the main loop of human-computer interaction command line , Perform read 、 analysis 、 Carry out orders .

    main_loop Function is executed first getenv ("bootcmd"), If bootcmd The environment variable is set to start kenel The order of , After the auto countdown, if there is no character input , be uboot Automatically bootcmd The order of , Start by default kernel. If there is a character input before the end of the auto countdown , Then enter the command prompt state and wait for the user to enter the command .readline Function to read user input commands , And then pass run_command Function analysis 、 Run the command .run_command Function will receive the command with parse_line Function analysis , It is mainly to receive the command string according to the space 、 The semicolon is divided into several parts , utilize find_cmd Function traversal to find the command set , see uboot Is there a command entered in , If there is no command entered , Print prompt . If there is a command currently entered , Call the function pointer member of the command structure of the current input command cmd Execute the function corresponding to the command .

run_command The source of the function is as follows :

int run_command (const char *cmd, int flag){.......................while (*str) {// Simply split the command string 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 */#ifdef DEBUG_PARSERprintf ("token: \"%s\"\n", token);#endif/* find macros in this token and replace them */process_macros (token, finaltoken);// Parsing command strings if ((argc = parse_line (finaltoken, argv)) == 0) {rc = -1;/* no command at all */continue;}// Traverse the command set to find if there is a current input command 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 defined(CONFIG_CMD_BOOTD)/* avoid "bootd" recursion */if (cmdtp->cmd == do_bootd) {#ifdef DEBUG_PARSERprintf ("[%s]\n", finaltoken);#endifif (flag & CMD_FLAG_BOOTD) {puts ("'bootd' recursion detected\n");rc = -1;continue;} else {flag |= CMD_FLAG_BOOTD;}}#endif // Call the member function pointer of the command structure cmd The corresponding command function if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {rc = -1;}repeatable &= cmdtp->repeatable;/* Did the user stop this? */if (had_ctrlc ())return -1;/* if stopped then not repeatable */}return rc ? rc : repeatable;}

Command traversal search :

uboot The command set is actually allocated in the custom segment .u_boot_cmd Medium , By means of uboot The program declares the reference to the custom segment .u_boot_cmd Start address of __u_boot_cmd_start And end address __u_boot_cmd_end,find_cmd Functions can access commands in the command set through pointers .

cmd_tbl_t *find_cmd (const char *cmd){cmd_tbl_t *cmdtp;cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;// The first address of the command set const char *p;int len;int n_found = 0;len = ((p = strchr(cmd, '.')) == NULL) ? strlen (cmd) : (p - cmd);// Calculate the length of the main command for (cmdtp = &__u_boot_cmd_start;// The starting address of the command set      cmdtp != &__u_boot_cmd_end;// The end address of the command set      cmdtp++) {if (strncmp (cmd, cmdtp->name, len) == 0) {// Search the current command through the command set if (len == strlen (cmdtp->name))// If the length of the current command is the same as the length of the found command , The instructions are the same return cmdtp;/* full match */// If the length of the current command is not the same as that of the found command , The main command is the same , The subcommand continues to find cmdtp_temp = cmdtp;/* abbreviated command ? */n_found++;}}if (n_found == 1) {/* exactly one match */return cmdtp_temp;}return NULL;/* not found or ambiguous command */}


 

3、 ... and 、uboot Execution of command

run_command Function 、 After traversing the search command , If you find a member that will call the command structure cmd Function pointer calls the command function corresponding to the current command do_xxxx.uboot An example of a definition template for a command is as follows :

#if defined(CONFIG_CMD_ECHO)int do_echo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){int i, putnl = 1;for (i = 1; i < argc; i++) {    char *p = argv[i], c;    if (i > 1)    putc(' ');    while ((c = *p++) != '\0')     {        if (c == '\\' && *p == 'c')         {        putnl = 0;        p++;        }         else         {        putc(c);         }           }}if (putnl)putc('\n');return 0;}U_BOOT_CMD(echo,CFG_MAXARGS,1,do_echo,"echo    - echo args to console\n","[args..]\n""    - echo args to console; \\c suppresses newline\n");#endif

CONFIG_CMD_ECHO Macro can determine whether the defined command is compiled into the current uboot in , Generally, it needs to be defined in the development board header file . Command definition must include the definition of command structure and command function .U_BOOT_CMD Macros define the command structure ,do_echo Function is the specific execution function of the command .

 

Four 、uboot Command add programming practice

    uboot You can add a command in common/commmand.c Add , You can also add another cmd_xxxx.c File to add .

1、command.c Add command to file

int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){printf ("\n%s\n", "hello world");return 0;}U_BOOT_CMD(hello,1,1,do_hello,"hello - print hello world help info\n",NULL);

stay command.c Adding commands to a file can lead to a confusing set of commands , Therefore, it is not recommended .

2、 add to cmd_xxxx.c File add command

A、 establish cmd_xxxx.c file

B、 Add header file

#include <common.h>

#include <command.h>

C、 add to do_xxx() Functions and U_BOOT_CMD macro

int do_hello (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){printf ("\n%s\n", "hello world");return 0;}U_BOOT_CMD(hello,1,1,do_hello,"hello - print hello world help info\n",NULL);

D、 stay common/Makefile Add cmd_xxxx.o Target file

COBJS-y+=cmd_xxxx.o

E、 Compiler Engineering , test hello command

stay common Add under directory cmd_xxx.c Command file is a relatively standard operation , Easy uboot Normalization of command sets , Recommend ways .

 

    uboot The command system itself is more complex , But developers are uboot It's very easy to add commands to , Just add cmd_xxx.c file , Modify the corresponding Makefile Just file .