mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-05-04 20:26:13 +02:00
Merge patch series "bootm: Clean up arch-specific, pre-OS clean-up"
Simon Glass <sjg@chromium.org> says: Each arch does something slightly different before booting the OS. Some archs even do different things depending on the CPU type. It is quite hard to know what actually happens in the final milliseconds before the OS boot. This series attempts to start cleaning up U-Boot in this area. The basic intent is to create a new bootm_final() function which can be called by all archs. It provides some flags for a couple of necessary variations but otherwise it is generic. All architectures are converted over to use this new function. board_quiesce_devices() is moved into bootm_final() so that all archs benefit from it. This series fixes a bug in device_remove() is fixed where removing a parent with specialised flags (e.g. DM_REMOVE_ACTIVE_ALL) could leave children activated, since they do not match the flags. This fixes is needed to avoid bootm_final() causing test failures on sandbox. Future work could take this a little further: - Convert EFI loader to use the same function - Improve comments for cleanup_before_linux() across architectures - Support fake-run tracing on all archs Link: https://lore.kernel.org/r/20260306023638.2678886-1-sjg@chromium.org
This commit is contained in:
commit
eb00c71050
@ -50,17 +50,13 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
{
|
||||
ulong kernel_entry;
|
||||
unsigned int r0, r2;
|
||||
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
|
||||
|
||||
kernel_entry = images->ep;
|
||||
|
||||
debug("## Transferring control to Linux (at address %08lx)...\n",
|
||||
kernel_entry);
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
|
||||
printf("\nStarting kernel ...%s\n\n", fake ?
|
||||
"(fake run for tracing)" : "");
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
bootm_final(flag);
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len) {
|
||||
r0 = 2;
|
||||
@ -72,7 +68,7 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
|
||||
cleanup_before_linux();
|
||||
|
||||
if (!fake)
|
||||
if (!(flag & BOOTM_STATE_OS_FAKE_GO))
|
||||
board_jump_and_run(kernel_entry, r0, 0, r2);
|
||||
}
|
||||
|
||||
|
||||
@ -42,42 +42,6 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct tag *params;
|
||||
|
||||
__weak void board_quiesce_devices(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* announce_and_cleanup() - Print message and prepare for kernel boot
|
||||
*
|
||||
* @fake: non-zero to do everything except actually boot
|
||||
*/
|
||||
static void announce_and_cleanup(int fake)
|
||||
{
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
#ifdef CONFIG_BOOTSTAGE_FDT
|
||||
bootstage_fdt_add_report();
|
||||
#endif
|
||||
bootstage_stash_default();
|
||||
#ifdef CONFIG_BOOTSTAGE_REPORT
|
||||
bootstage_report();
|
||||
#endif
|
||||
|
||||
board_quiesce_devices();
|
||||
|
||||
printf("\nStarting kernel ...%s\n\n", fake ?
|
||||
"(fake run for tracing)" : "");
|
||||
/*
|
||||
* Call remove function of all devices with a removal flag set.
|
||||
* This may be useful for last-stage operations, like cancelling
|
||||
* of DMA operation or releasing device internal buffers.
|
||||
* dm_remove_devices_active() ensures that vital devices are removed in
|
||||
* a second round.
|
||||
*/
|
||||
dm_remove_devices_active();
|
||||
|
||||
cleanup_before_linux();
|
||||
}
|
||||
|
||||
static void setup_start_tag (struct bd_info *bd)
|
||||
{
|
||||
params = (struct tag *)bd->bi_boot_params;
|
||||
@ -294,8 +258,6 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
{
|
||||
void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
|
||||
void *res2);
|
||||
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
|
||||
|
||||
kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
|
||||
void *res2))images->ep;
|
||||
|
||||
@ -303,9 +265,10 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
(ulong) kernel_entry);
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
|
||||
announce_and_cleanup(fake);
|
||||
bootm_final(flag);
|
||||
cleanup_before_linux();
|
||||
|
||||
if (!fake) {
|
||||
if (!(flag & BOOTM_STATE_OS_FAKE_GO)) {
|
||||
#ifdef CONFIG_ARMV8_PSCI
|
||||
armv8_setup_psci();
|
||||
#endif
|
||||
@ -340,8 +303,6 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
char *s;
|
||||
void (*kernel_entry)(int zero, int arch, uint params);
|
||||
unsigned long r2;
|
||||
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
|
||||
|
||||
kernel_entry = (void (*)(int, int, uint))images->ep;
|
||||
#ifdef CONFIG_CPU_V7M
|
||||
ulong addr = (ulong)kernel_entry | 1;
|
||||
@ -366,14 +327,15 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
debug("## Transferring control to Linux (at address %08lx)" \
|
||||
"...\n", (ulong) kernel_entry);
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
announce_and_cleanup(fake);
|
||||
bootm_final(flag);
|
||||
cleanup_before_linux();
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len)
|
||||
r2 = (unsigned long)images->ft_addr;
|
||||
else
|
||||
r2 = gd->bd->bi_boot_params;
|
||||
|
||||
if (fake)
|
||||
if (flag & BOOTM_STATE_OS_FAKE_GO)
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_ARMV7_NONSEC
|
||||
|
||||
@ -62,6 +62,8 @@ int do_bootm_linux(int flag, struct bootm_info *bmi)
|
||||
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
|
||||
bootm_final(0);
|
||||
|
||||
/*
|
||||
* Linux Kernel Parameters (passing board info data):
|
||||
* sp+00: Ignore, side effect of using jsr to jump to kernel
|
||||
|
||||
@ -26,8 +26,6 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
ulong dt = (ulong)images->ft_addr;
|
||||
ulong rd_start = images->initrd_start;
|
||||
ulong cmdline = images->cmdline_start;
|
||||
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
|
||||
|
||||
thekernel = (void (*)(char *, ulong, ulong))images->ep;
|
||||
|
||||
debug("## Transferring control to Linux (at address 0x%08lx) ",
|
||||
@ -36,13 +34,11 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
cmdline, rd_start, dt);
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
|
||||
printf("\nStarting kernel ...%s\n\n", fake ?
|
||||
"(fake run for tracing)" : "");
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
bootm_final(flag);
|
||||
|
||||
flush_cache_all();
|
||||
|
||||
if (!fake) {
|
||||
if (!(flag & BOOTM_STATE_OS_FAKE_GO)) {
|
||||
/*
|
||||
* Linux Kernel Parameters (passing device tree):
|
||||
* r5: pointer to command line
|
||||
|
||||
@ -268,12 +268,7 @@ static void boot_jump_linux(struct bootm_headers *images)
|
||||
if (CONFIG_IS_ENABLED(MALTA))
|
||||
linux_extra = gd->ram_size;
|
||||
|
||||
#if IS_ENABLED(CONFIG_BOOTSTAGE_FDT)
|
||||
bootstage_fdt_add_report();
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_BOOTSTAGE_REPORT)
|
||||
bootstage_report();
|
||||
#endif
|
||||
bootm_final(0);
|
||||
|
||||
if (CONFIG_IS_ENABLED(RESTORE_EXCEPTION_VECTOR_BASE))
|
||||
trap_restore();
|
||||
|
||||
@ -41,6 +41,8 @@ int do_bootm_linux(int flag, struct bootm_info *bmi)
|
||||
if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
|
||||
return 1;
|
||||
|
||||
bootm_final(0);
|
||||
|
||||
/* flushes data and instruction caches before calling the kernel */
|
||||
disable_interrupts();
|
||||
flush_dcache_all();
|
||||
|
||||
@ -54,12 +54,7 @@ static void boot_jump_linux(struct bootm_headers *images)
|
||||
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
|
||||
#ifdef CONFIG_BOOTSTAGE_FDT
|
||||
bootstage_fdt_add_report();
|
||||
#endif
|
||||
#ifdef CONFIG_BOOTSTAGE_REPORT
|
||||
bootstage_report();
|
||||
#endif
|
||||
bootm_final(0);
|
||||
|
||||
#if defined(CONFIG_SYS_INIT_RAM_LOCK) && !defined(CONFIG_E500)
|
||||
unlock_ram_in_cache();
|
||||
|
||||
@ -16,7 +16,6 @@ int cleanup_before_linux(void);
|
||||
|
||||
/* board/.../... */
|
||||
int board_init(void);
|
||||
void board_quiesce_devices(void);
|
||||
int riscv_board_reserved_mem_fixup(void *fdt);
|
||||
int riscv_fdt_copy_resv_mem_node(const void *src_fdt, void *dest_fdt);
|
||||
|
||||
|
||||
@ -25,39 +25,6 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
__weak void board_quiesce_devices(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* announce_and_cleanup() - Print message and prepare for kernel boot
|
||||
*
|
||||
* @fake: non-zero to do everything except actually boot
|
||||
*/
|
||||
static void announce_and_cleanup(int fake)
|
||||
{
|
||||
printf("\nStarting kernel ...%s\n\n", fake ?
|
||||
"(fake run for tracing)" : "");
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
#ifdef CONFIG_BOOTSTAGE_FDT
|
||||
bootstage_fdt_add_report();
|
||||
#endif
|
||||
#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT)
|
||||
bootstage_report();
|
||||
#endif
|
||||
|
||||
board_quiesce_devices();
|
||||
|
||||
/*
|
||||
* Call remove function of all devices with a removal flag set.
|
||||
* This may be useful for last-stage operations, like cancelling
|
||||
* of DMA operation or releasing device internal buffers.
|
||||
*/
|
||||
dm_remove_devices_active();
|
||||
|
||||
cleanup_before_linux();
|
||||
}
|
||||
|
||||
static void boot_prep_linux(struct bootm_headers *images)
|
||||
{
|
||||
if (CONFIG_IS_ENABLED(OF_LIBFDT) && IS_ENABLED(CONFIG_LMB) && images->ft_len) {
|
||||
@ -75,7 +42,6 @@ static void boot_prep_linux(struct bootm_headers *images)
|
||||
static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
{
|
||||
void (*kernel)(ulong hart, void *dtb);
|
||||
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
|
||||
#ifdef CONFIG_SMP
|
||||
int ret;
|
||||
#endif
|
||||
@ -87,9 +53,10 @@ static void boot_jump_linux(struct bootm_headers *images, int flag)
|
||||
debug("## Transferring control to kernel (at address %08lx) ...\n",
|
||||
(ulong)kernel);
|
||||
|
||||
announce_and_cleanup(fake);
|
||||
bootm_final(flag);
|
||||
cleanup_before_linux();
|
||||
|
||||
if (!fake) {
|
||||
if (!(flag & BOOTM_STATE_OS_FAKE_GO)) {
|
||||
if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len) {
|
||||
#ifdef CONFIG_SMP
|
||||
ret = smp_call_function(images->ep,
|
||||
|
||||
@ -73,6 +73,7 @@ int do_bootm_linux(int flag, struct bootm_info *bmi)
|
||||
|
||||
if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
|
||||
bootstage_mark(BOOTSTAGE_ID_RUN_OS);
|
||||
bootm_final(flag);
|
||||
printf("## Transferring control to Linux (at address %08lx)...\n",
|
||||
images->ep);
|
||||
printf("sandbox: continuing, as we cannot run Linux\n");
|
||||
|
||||
@ -92,6 +92,8 @@ int do_bootm_linux(int flag, struct bootm_info *bmi)
|
||||
images->rd_end - images->rd_start);
|
||||
}
|
||||
|
||||
bootm_final(0);
|
||||
|
||||
/* Boot kernel */
|
||||
kernel();
|
||||
|
||||
|
||||
@ -34,22 +34,10 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
void bootm_announce_and_cleanup(void)
|
||||
{
|
||||
printf("\nStarting kernel ...\n\n");
|
||||
|
||||
#ifdef CONFIG_SYS_COREBOOT
|
||||
timestamp_add_now(TS_START_KERNEL);
|
||||
#endif
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
#if IS_ENABLED(CONFIG_BOOTSTAGE_REPORT)
|
||||
bootstage_report();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Call remove function of all devices with a removal flag set.
|
||||
* This may be useful for last-stage operations, like cancelling
|
||||
* of DMA operation or releasing device internal buffers.
|
||||
*/
|
||||
dm_remove_devices_active();
|
||||
bootm_final(0);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
|
||||
|
||||
@ -178,6 +178,8 @@ int do_bootm_linux(int flag, struct bootm_info *bmi)
|
||||
printf("Transferring Control to Linux @0x%08lx ...\n\n",
|
||||
(ulong)images->ep);
|
||||
|
||||
bootm_final(flag);
|
||||
|
||||
flush_dcache_range((unsigned long)params_start, (unsigned long)params);
|
||||
|
||||
if (flag & BOOTM_STATE_OS_FAKE_GO)
|
||||
|
||||
25
boot/bootm.c
25
boot/bootm.c
@ -7,6 +7,7 @@
|
||||
#ifndef USE_HOSTCC
|
||||
#include <bootm.h>
|
||||
#include <bootstage.h>
|
||||
#include <dm/root.h>
|
||||
#include <cli.h>
|
||||
#include <command.h>
|
||||
#include <cpu_func.h>
|
||||
@ -1194,6 +1195,30 @@ void __weak switch_to_non_secure_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
void bootm_final(int flag)
|
||||
{
|
||||
printf("\nStarting kernel ...%s\n\n",
|
||||
(flag & BOOTM_STATE_OS_FAKE_GO) ?
|
||||
" (fake run for tracing)" : "");
|
||||
|
||||
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
|
||||
|
||||
if (IS_ENABLED(CONFIG_BOOTSTAGE_FDT) && IS_ENABLED(CONFIG_CMD_FDT))
|
||||
bootstage_fdt_add_report();
|
||||
bootstage_stash_default();
|
||||
if (IS_ENABLED(CONFIG_BOOTSTAGE_REPORT))
|
||||
bootstage_report();
|
||||
|
||||
board_quiesce_devices();
|
||||
|
||||
/*
|
||||
* Call remove function of all devices with a removal flag set.
|
||||
* This may be useful for last-stage operations, like cancelling
|
||||
* of DMA operation or releasing device internal buffers.
|
||||
*/
|
||||
dm_remove_devices_active();
|
||||
}
|
||||
|
||||
#else /* USE_HOSTCC */
|
||||
|
||||
#if defined(CONFIG_FIT_SIGNATURE)
|
||||
|
||||
@ -198,7 +198,7 @@ static int flags_remove(uint flags, uint drv_flags)
|
||||
int device_remove(struct udevice *dev, uint flags)
|
||||
{
|
||||
const struct driver *drv;
|
||||
int ret;
|
||||
int ret, cret;
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
@ -210,25 +210,35 @@ int device_remove(struct udevice *dev, uint flags)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If the child returns EKEYREJECTED, continue. It just means that it
|
||||
* didn't match the flags.
|
||||
*/
|
||||
ret = device_chld_remove(dev, NULL, flags);
|
||||
if (ret && ret != -EKEYREJECTED)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Remove the device if called with the "normal" remove flag set,
|
||||
* or if the remove flag matches any of the drivers remove flags
|
||||
*/
|
||||
drv = dev->driver;
|
||||
assert(drv);
|
||||
ret = flags_remove(flags, drv->flags);
|
||||
if (ret) {
|
||||
log_debug("%s: When removing: flags=%x, drv->flags=%x, err=%d\n",
|
||||
dev->name, flags, drv->flags, ret);
|
||||
cret = flags_remove(flags, drv->flags);
|
||||
|
||||
/*
|
||||
* Remove all children. If this device is being removed due to
|
||||
* active-DMA or OS-prepare flags, drop the active-flag requirement
|
||||
* for children so they are removed even without matching active
|
||||
* flags, since a deactivated device must not have activated
|
||||
* children. Preserve other flags (e.g. DM_REMOVE_NON_VITAL) so
|
||||
* that vital children are still protected.
|
||||
*
|
||||
* If the child returns EKEYREJECTED, continue. It just means that it
|
||||
* didn't match the flags.
|
||||
*/
|
||||
ret = device_chld_remove(dev, NULL,
|
||||
cret ? flags :
|
||||
(flags & ~DM_REMOVE_ACTIVE_ALL));
|
||||
if (ret && ret != -EKEYREJECTED)
|
||||
return ret;
|
||||
|
||||
if (cret) {
|
||||
log_debug("%s: When removing: flags=%x, drv->flags=%x, err=%d\n",
|
||||
dev->name, flags, drv->flags, cret);
|
||||
return cret;
|
||||
}
|
||||
|
||||
ret = uclass_pre_remove_device(dev);
|
||||
|
||||
@ -321,4 +321,14 @@ void zimage_dump(struct boot_params *base_ptr, bool show_cmdline);
|
||||
*/
|
||||
int bootm_boot_start(ulong addr, const char *cmdline);
|
||||
|
||||
/**
|
||||
* bootm_final() - Announce and do cleanup before boot
|
||||
*
|
||||
* This performs the common pre-boot steps: printing the "Starting kernel"
|
||||
* message, recording bootstage data, and removing active devices.
|
||||
*
|
||||
* @flag: Boot state flags (BOOTM_STATE_OS_FAKE_GO prints a fake-run message)
|
||||
*/
|
||||
void bootm_final(int flag);
|
||||
|
||||
#endif
|
||||
|
||||
@ -435,6 +435,14 @@ static inline uint32_t bootstage_accum(enum bootstage_id id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void bootstage_report(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void bootstage_fdt_add_report(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int bootstage_stash(void *base, int size)
|
||||
{
|
||||
return 0; /* Pretend to succeed */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user