Experimental Environment
- Hardware: Forlinx OK-T527 Development Board
- Software: Allwinner Longan SDK (U-Boot version 2018)
U-Boot Initialization Flow
To understand how to inject a custom menu, we must first examine the entry point for U-Boot's main logic. The core execution loop is defined in /common/main.c, specifically within the main_loop() function. This function is called after hardware initialization is complete and the system is ready to process commands.
/* <u-boot>/common/main.c */
void main_loop(void)
{
const char *boot_cmd;
bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
#ifdef CONFIG_VERSION_VARIABLE
env_set("ver", version_string);
#endif
cli_init();
/* Execute commands defined in the preboot environment variable */
run_preboot_environment_command();
#if defined(CONFIG_UPDATE_TFTP)
update_tftp(0UL, NULL, NULL);
#endif
/*
* Retrieve 'bootdelay' and 'bootcmd' environment variables.
* This determines how long to wait and what to boot.
*/
boot_cmd = bootdelay_process();
if (cli_process_fdt(&boot_cmd))
cli_secure_boot_cmd(boot_cmd);
/*
* Start the countdown timer.
* This function monitors serial input for user interruption.
*/
autoboot_command(boot_cmd);
/*
* If the boot is interrupted or fails, enter the CLI loop.
* This is the standard U-Boot command line.
*/
cli_loop();
panic("No CLI available");
}
The Auto-Boot Mechanism
The transition from countdown to either booting the OS or entering the shell is controlled by autoboot_command(). This function is implemented in /common/autoboot.c. It checks whether the countdown has expired or if a key press was detected.
/* <u-boot>/common/autoboot.c */
void autoboot_command(const char *cmd_str)
{
debug("### main_loop: bootcmd=\"%s\"\n", cmd_str ? cmd_str : "<undefined>");
/*
* Check if the boot delay is valid and if the boot process was
* not aborted by the user (abortboot checks for key presses).
*/
if (stored_bootdelay != -1 && cmd_str && !abortboot(stored_bootdelay)) {
/* Run the boot command if no key was pressed */
run_command_list(cmd_str, -1, 0);
}
/*
* If a key was pressed (abortboot returns non-zero),
* this function returns, allowing main_loop to proceed to cli_loop().
* This is where a custom menu hook can be inserted.
*/
}
</undefined>
By default, if abortboot() detects a key press, autoboot_command() returns without executing the boot command. Consequently, main_loop() proceeds to call cli_loop(), launching the stanadrd shell. To implement a custom menu, developers can modify the code path following the key press detection to call a custom menu function instead of the standard CLI loop.