From e03d4196a3492063d24dccc8da58c5c185b4c4ec Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Fri, 9 Aug 2024 19:30:20 -0700 Subject: [PATCH] [platform][halt] refactor the default halt/reboot/shutdown logic Move common logic into a default routine in platform/power that other platforms can reuse to implement the general default shutdown logic. Add helper routines to print the cause. Refactor the platforms that had substantial halt logic to reuse the default implementation. --- platform/debug.c | 4 +- platform/include/platform.h | 32 +++++++--- platform/init.c | 3 +- platform/jh7110/platform.c | 44 ++++---------- platform/pc/debug.c | 9 --- platform/power.c | 93 +++++++++++++++++++++++++---- platform/qemu-virt-arm/debug.c | 4 +- platform/qemu-virt-arm/platform.c | 14 +---- platform/qemu-virt-m68k/platform.c | 33 ---------- platform/qemu-virt-riscv/platform.c | 48 +++++---------- platform/spacemit-k1/platform.c | 44 +++++--------- 11 files changed, 154 insertions(+), 174 deletions(-) diff --git a/platform/debug.c b/platform/debug.c index cd41b26d..7d2d1000 100644 --- a/platform/debug.c +++ b/platform/debug.c @@ -6,9 +6,9 @@ * https://opensource.org/licenses/MIT */ +#include + #include -#include -#include /* Default implementation of panic time getc/putc. * Just calls through to the underlying dputc/dgetc implementation diff --git a/platform/include/platform.h b/platform/include/platform.h index 598a43b1..78353e44 100644 --- a/platform/include/platform.h +++ b/platform/include/platform.h @@ -21,6 +21,8 @@ typedef enum { HALT_ACTION_SHUTDOWN, // Shutdown and power off. } platform_halt_action; +const char *platform_halt_action_string(platform_halt_action action); + typedef enum { HALT_REASON_UNKNOWN = 0, HALT_REASON_POR, // Cold-boot @@ -35,14 +37,7 @@ typedef enum { HALT_REASON_SW_UPDATE, // SW triggered reboot in order to begin firmware update } platform_halt_reason; -/* super early platform initialization, before almost everything */ -void platform_early_init(void); - -/* later init, after the kernel has come up */ -void platform_init(void); - -/* called by the arch init code to get the platform to set up any mmu mappings it may need */ -void platform_init_mmu_mappings(void); +const char *platform_halt_reason_string(platform_halt_reason reason); /* if the platform has knowledge of what caused the latest reboot, it can report * it to applications with this function. */ @@ -62,11 +57,30 @@ platform_halt_reason platform_get_reboot_reason(void); * reason, and then halt execution by turning off interrupts and spinning * forever. */ -void platform_halt(platform_halt_action suggested_action, +__WEAK void platform_halt(platform_halt_action suggested_action, platform_halt_reason reason) __NO_RETURN; +/* Default implementation of the above routine, which platforms can call with + * appropriate hooks to implement platform specific reboot and shutdown behavior. + */ +typedef void (*platform_reboot_hook)(void); +typedef void (*platform_shutdown_hook)(void); +void platform_halt_default(platform_halt_action suggested_action, + platform_halt_reason reason, + platform_reboot_hook prh, + platform_shutdown_hook psh) __NO_RETURN; + /* called during chain loading to make sure drivers and platform is put into a stopped state */ void platform_quiesce(void); +/* super early platform initialization, before almost everything */ +void platform_early_init(void); + +/* later init, after the kernel has come up */ +void platform_init(void); + +/* called by the arch init code to get the platform to set up any mmu mappings it may need */ +void platform_init_mmu_mappings(void); + __END_CDECLS diff --git a/platform/init.c b/platform/init.c index b3d1b65e..9f36a3b0 100644 --- a/platform/init.c +++ b/platform/init.c @@ -5,9 +5,10 @@ * license that can be found in the LICENSE file or at * https://opensource.org/licenses/MIT */ +#include + #include #include -#include /* * default implementations of these routines, if the platform code diff --git a/platform/jh7110/platform.c b/platform/jh7110/platform.c index e72342f6..b48ae46f 100644 --- a/platform/jh7110/platform.c +++ b/platform/jh7110/platform.c @@ -24,9 +24,6 @@ #include #endif #include -#if WITH_LIB_CONSOLE -#include -#endif #include "platform_p.h" @@ -82,35 +79,20 @@ void platform_init(void) { } -void platform_halt(platform_halt_action suggested_action, - platform_halt_reason reason) { - switch (suggested_action) { - case HALT_ACTION_SHUTDOWN: - dprintf(ALWAYS, "Shutting down... (reason = %d)\n", reason); - // try to use SBI as a cleaner way to stop - sbi_system_reset(SBI_RESET_TYPE_SHUTDOWN, SBI_RESET_REASON_NONE); - *power_reset_reg = 0x5555; - break; - case HALT_ACTION_REBOOT: - dprintf(ALWAYS, "Rebooting... (reason = %d)\n", reason); - sbi_system_reset(SBI_RESET_TYPE_WARM_REBOOT, SBI_RESET_REASON_NONE); - *power_reset_reg = 0x7777; - break; - case HALT_ACTION_HALT: -#if ENABLE_PANIC_SHELL - if (reason == HALT_REASON_SW_PANIC) { - dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason); - arch_disable_ints(); - panic_shell_start(); - } -#endif // ENABLE_PANIC_SHELL - dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason); - break; - } +static void reboot_(void) { + sbi_system_reset(SBI_RESET_TYPE_COLD_REBOOT, SBI_RESET_REASON_NONE); + *power_reset_reg = 0x7777; +} - arch_disable_ints(); - for (;;) - arch_idle(); +static void shutdown_(void) { + // try to use sbi as a cleaner way to stop + sbi_system_reset(SBI_RESET_TYPE_SHUTDOWN, SBI_RESET_REASON_NONE); + *power_reset_reg = 0x5555; +} + +void platform_halt(platform_halt_action suggested_action, platform_halt_reason reason) { + // Use the default halt implementation using sbi as the reset and shutdown implementation. + platform_halt_default(suggested_action, reason, &reboot_, &shutdown_); } status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) { diff --git a/platform/pc/debug.c b/platform/pc/debug.c index 648cdc63..61e09fe3 100644 --- a/platform/pc/debug.c +++ b/platform/pc/debug.c @@ -94,12 +94,3 @@ void platform_dputc(char c) { int platform_dgetc(char *c, bool wait) { return cbuf_read_char(&console_input_buf, c, wait); } - -void platform_halt(platform_halt_action suggested_action, - platform_halt_reason reason) { - for (;;) { - x86_cli(); - x86_hlt(); - } -} - diff --git a/platform/power.c b/platform/power.c index 24c7ed77..de8a48b2 100644 --- a/platform/power.c +++ b/platform/power.c @@ -12,32 +12,99 @@ #include #include #include -#include #if WITH_LIB_CONSOLE #include #endif -/* - * default implementations of these routines, if the platform code - * chooses not to implement. - */ -__WEAK void platform_halt(platform_halt_action suggested_action, - platform_halt_reason reason) { +// Default implementation of the system halt and reset function. Platforms may use +// this as a helper to implement the logic by passing in a few hooks to do the +// actual shutdown or reboot. +void platform_halt_default(platform_halt_action suggested_action, + platform_halt_reason reason, + platform_reboot_hook prh, + platform_shutdown_hook psh) { + const char *reason_string = platform_halt_reason_string(reason); + switch (suggested_action) { + case HALT_ACTION_SHUTDOWN: + if (psh) { + dprintf(ALWAYS, "Shutting down, reason '%s'\n", reason_string); + psh(); + } + break; + case HALT_ACTION_REBOOT: + if (prh) { + dprintf(ALWAYS, "Rebooting, reason '%s'\n", reason_string); + prh(); + } + break; + case HALT_ACTION_HALT: #if ENABLE_PANIC_SHELL - if (reason == HALT_REASON_SW_PANIC && suggested_action == HALT_ACTION_HALT) { - dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason); - arch_disable_ints(); - panic_shell_start(); - } + if (reason == HALT_REASON_SW_PANIC) { + dprintf(ALWAYS, "CRASH: starting debug shell, reason '%s'\n", reason_string); + arch_disable_ints(); + panic_shell_start(); + } #endif // ENABLE_PANIC_SHELL + break; + } - dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason); + dprintf(ALWAYS, "HALT: spinning forever, reason '%s'\n", reason_string); arch_disable_ints(); for (;;) arch_idle(); } +// Default implementation of platform halt, which simply start the debug shell or spins forever. +__WEAK void platform_halt(platform_halt_action suggested_action, + platform_halt_reason reason) { + platform_halt_default(suggested_action, reason, NULL, NULL); +} + +__WEAK platform_halt_reason platform_get_reboot_reason(void) { + return HALT_REASON_UNKNOWN; +} + +const char *platform_halt_action_string(platform_halt_action action) { + switch(action) { + case HALT_ACTION_HALT: + return "halt"; + case HALT_ACTION_REBOOT: + return "reboot"; + case HALT_ACTION_SHUTDOWN: + return "shutdown"; + } + return "unknown"; +} + +const char *platform_halt_reason_string(platform_halt_reason reason) { + switch(reason) { + case HALT_REASON_UNKNOWN: + return "unknown"; + case HALT_REASON_POR: + return "power on reset"; + case HALT_REASON_HW_WATCHDOG: + return "hardware watchdog"; + case HALT_REASON_LOWVOLTAGE: + return "low voltage"; + case HALT_REASON_HIGHVOLTAGE: + return "high voltage"; + case HALT_REASON_THERMAL: + return "thermal"; + case HALT_REASON_OTHER_HW: + return "other hardware"; + case HALT_REASON_SW_RESET: + return "software reset"; + case HALT_REASON_SW_WATCHDOG: + return "software watchdog"; + case HALT_REASON_SW_PANIC: + return "software panic"; + case HALT_REASON_SW_UPDATE: + return "software update"; + } + return "unknown"; +} + static int cmd_reboot(int argc, const console_cmd_args *argv) { platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET); return 0; diff --git a/platform/qemu-virt-arm/debug.c b/platform/qemu-virt-arm/debug.c index 99679816..f8be333c 100644 --- a/platform/qemu-virt-arm/debug.c +++ b/platform/qemu-virt-arm/debug.c @@ -30,8 +30,8 @@ void platform_dputc(char c) { int platform_dgetc(char *c, bool wait) { int ret = uart_getc(DEBUG_UART, wait); - if (ret == -1) - return -1; + if (ret < 0) + return ret; *c = ret; return 0; } diff --git a/platform/qemu-virt-arm/platform.c b/platform/qemu-virt-arm/platform.c index c492c675..1af6082c 100644 --- a/platform/qemu-virt-arm/platform.c +++ b/platform/qemu-virt-arm/platform.c @@ -194,16 +194,6 @@ status_t platform_compute_msi_values(unsigned int vector, unsigned int cpu, bool } void platform_halt(platform_halt_action suggested_action, platform_halt_reason reason) { - switch (suggested_action) { - case HALT_ACTION_SHUTDOWN: - case HALT_ACTION_HALT: - psci_system_off(); - break; - case HALT_ACTION_REBOOT: - psci_system_reset(); - break; - } - dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason); - arch_disable_ints(); - for (;;); + // Use the default halt implementation using psci as the reset and shutdown implementation. + platform_halt_default(suggested_action, reason, &psci_system_reset, &psci_system_off); } diff --git a/platform/qemu-virt-m68k/platform.c b/platform/qemu-virt-m68k/platform.c index 7f4d9107..bc1a78b2 100644 --- a/platform/qemu-virt-m68k/platform.c +++ b/platform/qemu-virt-m68k/platform.c @@ -24,9 +24,6 @@ #else #include #endif -#if WITH_LIB_CONSOLE -#include -#endif #include "platform_p.h" @@ -119,33 +116,3 @@ void platform_init(void) { } #endif } - -#if 0 -void platform_halt(platform_halt_action suggested_action, - platform_halt_reason reason) { - switch (suggested_action) { - case HALT_ACTION_SHUTDOWN: - dprintf(ALWAYS, "Shutting down... (reason = %d)\n", reason); - *power_reset_reg = 0x5555; - break; - case HALT_ACTION_REBOOT: - dprintf(ALWAYS, "Rebooting... (reason = %d)\n", reason); - *power_reset_reg = 0x7777; - break; - case HALT_ACTION_HALT: -#if ENABLE_PANIC_SHELL - if (reason == HALT_REASON_SW_PANIC) { - dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason); - arch_disable_ints(); - panic_shell_start(); - } -#endif // ENABLE_PANIC_SHELL - dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason); - break; - } - - arch_disable_ints(); - for (;;) - arch_idle(); -} -#endif diff --git a/platform/qemu-virt-riscv/platform.c b/platform/qemu-virt-riscv/platform.c index 459f0e5b..2372fba7 100644 --- a/platform/qemu-virt-riscv/platform.c +++ b/platform/qemu-virt-riscv/platform.c @@ -31,9 +31,6 @@ #else #include #endif -#if WITH_LIB_CONSOLE -#include -#endif #include "platform_p.h" @@ -123,39 +120,24 @@ void platform_init(void) { #endif } -void platform_halt(platform_halt_action suggested_action, - platform_halt_reason reason) { - switch (suggested_action) { - case HALT_ACTION_SHUTDOWN: - dprintf(ALWAYS, "Shutting down... (reason = %d)\n", reason); +static void reboot_(void) { #if RISCV_S_MODE - // try to use SBI as a cleaner way to stop - sbi_system_reset(SBI_RESET_TYPE_SHUTDOWN, SBI_RESET_REASON_NONE); + sbi_system_reset(SBI_RESET_TYPE_COLD_REBOOT, SBI_RESET_REASON_NONE); #endif - *power_reset_reg = 0x5555; - break; - case HALT_ACTION_REBOOT: - dprintf(ALWAYS, "Rebooting... (reason = %d)\n", reason); -#if RISCV_S_MODE - sbi_system_reset(SBI_RESET_TYPE_COLD_REBOOT, SBI_RESET_REASON_NONE); -#endif - *power_reset_reg = 0x7777; - break; - case HALT_ACTION_HALT: -#if ENABLE_PANIC_SHELL - if (reason == HALT_REASON_SW_PANIC) { - dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason); - arch_disable_ints(); - panic_shell_start(); - } -#endif // ENABLE_PANIC_SHELL - dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason); - break; - } + *power_reset_reg = 0x7777; +} - arch_disable_ints(); - for (;;) - arch_idle(); +static void shutdown_(void) { +#if RISCV_S_MODE + // try to use sbi as a cleaner way to stop + sbi_system_reset(SBI_RESET_TYPE_SHUTDOWN, SBI_RESET_REASON_NONE); +#endif + *power_reset_reg = 0x5555; +} + +void platform_halt(platform_halt_action suggested_action, platform_halt_reason reason) { + // Use the default halt implementation using sbi as the reset and shutdown implementation. + platform_halt_default(suggested_action, reason, &reboot_, &shutdown_); } status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) { diff --git a/platform/spacemit-k1/platform.c b/platform/spacemit-k1/platform.c index 49b3c9a6..ca587273 100644 --- a/platform/spacemit-k1/platform.c +++ b/platform/spacemit-k1/platform.c @@ -24,9 +24,6 @@ #include #endif #include -#if WITH_LIB_CONSOLE -#include -#endif #include "platform_p.h" @@ -68,33 +65,22 @@ void platform_init(void) { uart_init(); } -void platform_halt(platform_halt_action suggested_action, - platform_halt_reason reason) { - switch (suggested_action) { - case HALT_ACTION_SHUTDOWN: - dprintf(ALWAYS, "Shutting down... (reason = %d)\n", reason); - // try to use SBI as a cleaner way to stop - sbi_system_reset(SBI_RESET_TYPE_SHUTDOWN, SBI_RESET_REASON_NONE); - break; - case HALT_ACTION_REBOOT: - dprintf(ALWAYS, "Rebooting... (reason = %d)\n", reason); - sbi_system_reset(SBI_RESET_TYPE_WARM_REBOOT, SBI_RESET_REASON_NONE); - break; - case HALT_ACTION_HALT: -#if ENABLE_PANIC_SHELL - if (reason == HALT_REASON_SW_PANIC) { - dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason); - arch_disable_ints(); - panic_shell_start(); - } -#endif // ENABLE_PANIC_SHELL - dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason); - break; - } +static void reboot_(void) { +#if RISCV_S_MODE + sbi_system_reset(SBI_RESET_TYPE_COLD_REBOOT, SBI_RESET_REASON_NONE); +#endif +} - arch_disable_ints(); - for (;;) - arch_idle(); +static void shutdown_(void) { +#if RISCV_S_MODE + // try to use sbi as a cleaner way to stop + sbi_system_reset(SBI_RESET_TYPE_SHUTDOWN, SBI_RESET_REASON_NONE); +#endif +} + +void platform_halt(platform_halt_action suggested_action, platform_halt_reason reason) { + // Use the default halt implementation using sbi as the reset and shutdown implementation. + platform_halt_default(suggested_action, reason, &reboot_, &shutdown_); } status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) {