How is the u-boot kernel started?

Publisher:RadiantBreezeLatest update time:2024-08-29 Source: cnblogsKeywords:u-boot Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The entire program framework has been analyzed in the analysis of the start_armboot function of u-boot, but it only talks about when to run the kernel, and does not specifically explain how to execute the kernel. The kernel startup is described in the following steps:


1. Boot parameter bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0 Description


2. How does the run_command function execute commands?


3. Description of parameters passed by u-boot to the kernel


4. Kernel startup process


1. Boot parameter bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0 Description


This parameter is divided into two uboot commands. First, copy the kernel of the corresponding size from the kernel area to the memory 0x30007FC0; then execute the bootm 0x30007FC0 command. The process of this command will be explained in detail later. After executing this command, the kernel can be started from 0x30007FC0. It needs to be explained here that the real kernel is located at 0x30008000, because the first 64 bytes are some kernel information, which is specifically defined as follows:


typedef struct image_header {

uint32_t ih_magic; /* Image Header Magic Number *///Core number

uint32_t ih_hcrc; /* Image Header CRC Checksum */ //CRC checksum of kernel header data

uint32_t ih_time; /* Image Creation Timestamp */ //Timestamp created by the kernel

uint32_t ih_size; /* Image Data Size */ //Kernel size

uint32_t ih_load; /* Data Load Address */ //Kernel loading address

uint32_t ih_ep; /* Entry Point Address */ //Kernel entry point address

uint32_t ih_dcrc; /* Image Data CRC Checksum */ //CRC checksum of kernel data

uint8_t ih_os; /* Operating System *///What is the operating system of the kernel

uint8_t ih_arch; /* CPU architecture */ //Core CPU architecture

uint8_t ih_type; /* Image Type */ //Kernel image file type

uint8_t ih_comp; /* Compression Type *///Compression type

uint8_t ih_name[IH_NMLEN]; /* Image Name *///Kernel image file name

} image_header_t;


2. How does the run_command function execute commands?


The run_command function is in Main.c (common). This function is the core function of the entire U-BOOT command. There is a .u_boot_cmd segment in the uboot link file. The content of this segment is to store all the UBOOT commands.


This section is defined in command.h (include) as follows:


#define Struct_Section __attribute__ ((unused,section (".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}

//Decomposed into =>U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) cmd_tbl_t __u_boot_cmd_name __attribute__ ((unused,section (".u_boot_cmd"))) = {name, maxargs, rep, cmd, usage, help}

//name is the name of the command

//maxargs is the maximum number of commands

//rep is whether the command can be repeated, indicating whether pressing Enter can run the last command

//cmd indicates the execution function pointer of a specific command. This function is not in the .u_boot_cmd segment, but the function pointer is stored in the .u_boot_cmd segment

//usage indicates a brief usage description

//help indicates a long description

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

};


For example, take the bootm command as an example. After the bootm command is entered in the u-boot console, the u-boot code will execute the run_command(bootm, 0); function and then call the do_bootm function.


U_BOOT_CMD(

bootm, CFG_MAXARGS, 1, do_bootm,

"bootm - boot application image from memoryn",

"[addr [arg ...]]n - boot application image stored in memoryn"

"tpassing arguments 'arg ...'; when booting a Linux kernel,n"

"t'arg' can be the address of an initrd imagen"

#ifdef CONFIG_OF_FLAT_TREE

"tWhen booting a Linux kernel which requires a flat device-tree"

"ta third argument is required which is the address of the then"

"tdevice-tree blob. To boot that kernel without an initrd image,n"

"tuse a '-' for the second argument. If you do not pass a thirdn"

"ta bd_info struct will be passed insteadn"

#endif

);


Continue to execute the bootm command. The run_command (bootm, 0) function first performs some parameter checks.


clear_ctrlc(); /* forget any previous Control C *///Clear the previous command


if (!cmd || !*cmd) {//Check if cmd command exists

return -1; /* empty command */

}


if (strlen(cmd) >= CFG_CBSIZE) {//Check whether the number of parameters exceeds the maximum limit

puts ("## Command too long!n");

return -1;

}


strcpy (cmdbuf, cmd); //Copy all cmd to cmdbuf


run_command (bootm, 0) continues to run, looping to find the command in str. str has been assigned to cmdbuf during initialization. Here is a brief description of the program flow:


a. First, there are several query commands


b. Expand the command to call the environment variable


c. Get the number of parameters


d. Search for commands and find the matching commands from the .u_boot_cmd section


e. Run function to execute commands


while (*str) {//Extract valid commands from the input characters by andy


/*

* Find separator, or string end

* Allow simple escape of ';' by writing ";"

*/

for (inquotes = 0, sep = str; *sep; sep++) {//Search until the last byte is the terminator

if ((*sep==''') && //Find connections that match

(*(sep-1) != '\'))

inquotes=!inquotes; //If it is a connector


if (!inquotes &&

(*sep == ';') && /* separator *///Indicates multiple consecutive commands

( sep != str) && /* past string start */

(*(sep-1) != '\')) /* and NOT escaped */

break;

}


/*

* Limit the token to data between separators

*/

token = str;

if (*sep) {//If there is more than one command by andy

str = sep + 1; /* start of command for next pass */// points to the beginning of the next command, the current seq points to;

*sep = '';

}

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); //Expand environment variables by andy, use $() or ${} to get variables and finally get finaltoken


/* Extract arguments */

if ((argc = parse_line (finaltoken, argv)) == 0) {//Get the number of variables and their values ​​​​and store them in argv. The number of variables includes commands, so it should be greater than 0 by andy

rc = -1; /* no command at all */

continue;

}


/* Look up command in command table */

if ((cmdtp = find_cmd(argv[0])) == NULL) { //Search for the command and return a pointer to the cmd_tbl_t structure after finding it by andy

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) {//Verify whether the number of parameters exceeds the limit by andy

printf ("Usage:n%sn", 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 detectedn");

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) {//Call command function to execute by andy

rc = -1;

}


repeatable &= cmdtp->repeatable;


/* Did the user stop this? */

if (had_ctrlc ()) // Is the crtl+c key pressed? If so, the next command will be processed. by andy

return 0; /* if stopped then not repeatable */

}


Comment the code that finds the corresponding command from the .u_boot_cmd section


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); //Get the command length, excluding the characters after . by andy


for (cmdtp = &__u_boot_cmd_start; //__u_boot_cmd_start is defined in the link file by andy

cmdtp != &__u_boot_cmd_end; //__u_boot_cmd_end is defined in the link file by andy

cmdtp++) {

if (strncmp (cmd, cmdtp->name, len) == 0) {//Compare whether there is the same command name in the searched segment by andy

if (len == strlen (cmdtp->name))

return cmdtp; /* full match *///Fully matched by andy


cmdtp_temp = cmdtp; /* abbreviated command? */

n_found++;

}

}

if (n_found == 1) { /* exactly one match *///Command found by andy

return cmdtp_temp;

}


return NULL; /* not found or ambiguous command */

}


3. Description of parameters passed by u-boot to the kernel


The interaction between the bootloader and the kernel is one-way. The kernel and u-boot agree to put the parameters in a certain location, and the kernel can get them. The address specified here is 0x30000100. The specific meaning has been introduced in the first point above. Here you only need to know that 0x30000100 is the first address of the data exchanged between the kernel and u-boot.

[1] [2] [3]
Keywords:u-boot Reference address:How is the u-boot kernel started?

Previous article:How to implement partition in u-boot
Next article:Analysis of start_armboot function of u-boot

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号