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.
Previous article:How to implement partition in u-boot
Next article:Analysis of start_armboot function of u-boot
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Sandia Labs develops battery failure early warning technology to detect battery failures faster
- Infineon BFP540FESD internal diagram
- 【DFRobot Motor Driver】+ Trial Review
- [Mill MYB-YT507 development board trial experience] Replace Ubuntu 18 firmware
- [Fourth Batch of Shortlist] GigaDevice GD32L233 Review Activity
- ISM330DHCX iNEMO Inertial SiP Module Related Resources
- Xunwei 3399 development board Linux firmware compilation-Debian system compilation and burning
- About the problem of using DMAX's SPI slave mode for transmission
- Making friends through dismantling, review of dismantling articles
- AVR MCU I2C bus program
- Good luck in resuming work!!!