[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.
This commit is contained in:
Travis Geiselbrecht
2024-08-09 19:30:20 -07:00
parent 6fd2626359
commit e03d4196a3
11 changed files with 154 additions and 174 deletions

View File

@@ -6,9 +6,9 @@
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include <platform/debug.h>
#include <lk/compiler.h> #include <lk/compiler.h>
#include <lk/debug.h>
#include <lk/trace.h>
/* Default implementation of panic time getc/putc. /* Default implementation of panic time getc/putc.
* Just calls through to the underlying dputc/dgetc implementation * Just calls through to the underlying dputc/dgetc implementation

View File

@@ -21,6 +21,8 @@ typedef enum {
HALT_ACTION_SHUTDOWN, // Shutdown and power off. HALT_ACTION_SHUTDOWN, // Shutdown and power off.
} platform_halt_action; } platform_halt_action;
const char *platform_halt_action_string(platform_halt_action action);
typedef enum { typedef enum {
HALT_REASON_UNKNOWN = 0, HALT_REASON_UNKNOWN = 0,
HALT_REASON_POR, // Cold-boot HALT_REASON_POR, // Cold-boot
@@ -35,14 +37,7 @@ typedef enum {
HALT_REASON_SW_UPDATE, // SW triggered reboot in order to begin firmware update HALT_REASON_SW_UPDATE, // SW triggered reboot in order to begin firmware update
} platform_halt_reason; } platform_halt_reason;
/* super early platform initialization, before almost everything */ const char *platform_halt_reason_string(platform_halt_reason reason);
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);
/* if the platform has knowledge of what caused the latest reboot, it can report /* if the platform has knowledge of what caused the latest reboot, it can report
* it to applications with this function. */ * 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 * reason, and then halt execution by turning off interrupts and spinning
* forever. * forever.
*/ */
void platform_halt(platform_halt_action suggested_action, __WEAK void platform_halt(platform_halt_action suggested_action,
platform_halt_reason reason) __NO_RETURN; 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 */ /* called during chain loading to make sure drivers and platform is put into a stopped state */
void platform_quiesce(void); 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 __END_CDECLS

View File

@@ -5,9 +5,10 @@
* license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include <platform.h>
#include <lk/err.h> #include <lk/err.h>
#include <lk/debug.h> #include <lk/debug.h>
#include <platform.h>
/* /*
* default implementations of these routines, if the platform code * default implementations of these routines, if the platform code

View File

@@ -24,9 +24,6 @@
#include <lib/minip.h> #include <lib/minip.h>
#endif #endif
#include <kernel/vm.h> #include <kernel/vm.h>
#if WITH_LIB_CONSOLE
#include <lib/console.h>
#endif
#include "platform_p.h" #include "platform_p.h"
@@ -82,35 +79,20 @@ void platform_init(void) {
} }
void platform_halt(platform_halt_action suggested_action, static void reboot_(void) {
platform_halt_reason reason) { sbi_system_reset(SBI_RESET_TYPE_COLD_REBOOT, SBI_RESET_REASON_NONE);
switch (suggested_action) { *power_reset_reg = 0x7777;
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;
}
arch_disable_ints(); static void shutdown_(void) {
for (;;) // try to use sbi as a cleaner way to stop
arch_idle(); 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) { status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) {

View File

@@ -94,12 +94,3 @@ void platform_dputc(char c) {
int platform_dgetc(char *c, bool wait) { int platform_dgetc(char *c, bool wait) {
return cbuf_read_char(&console_input_buf, c, 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();
}
}

View File

@@ -12,32 +12,99 @@
#include <platform.h> #include <platform.h>
#include <platform/debug.h> #include <platform/debug.h>
#include <kernel/thread.h> #include <kernel/thread.h>
#include <stdio.h>
#if WITH_LIB_CONSOLE #if WITH_LIB_CONSOLE
#include <lib/console.h> #include <lib/console.h>
#endif #endif
/* // Default implementation of the system halt and reset function. Platforms may use
* default implementations of these routines, if the platform code // this as a helper to implement the logic by passing in a few hooks to do the
* chooses not to implement. // actual shutdown or reboot.
*/ void platform_halt_default(platform_halt_action suggested_action,
__WEAK void platform_halt(platform_halt_action suggested_action, platform_halt_reason reason,
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 ENABLE_PANIC_SHELL
if (reason == HALT_REASON_SW_PANIC && suggested_action == HALT_ACTION_HALT) { if (reason == HALT_REASON_SW_PANIC) {
dprintf(ALWAYS, "CRASH: starting debug shell... (reason = %d)\n", reason); dprintf(ALWAYS, "CRASH: starting debug shell, reason '%s'\n", reason_string);
arch_disable_ints(); arch_disable_ints();
panic_shell_start(); panic_shell_start();
} }
#endif // ENABLE_PANIC_SHELL #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(); arch_disable_ints();
for (;;) for (;;)
arch_idle(); 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) { static int cmd_reboot(int argc, const console_cmd_args *argv) {
platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET); platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET);
return 0; return 0;

View File

@@ -30,8 +30,8 @@ void platform_dputc(char c) {
int platform_dgetc(char *c, bool wait) { int platform_dgetc(char *c, bool wait) {
int ret = uart_getc(DEBUG_UART, wait); int ret = uart_getc(DEBUG_UART, wait);
if (ret == -1) if (ret < 0)
return -1; return ret;
*c = ret; *c = ret;
return 0; return 0;
} }

View File

@@ -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) { void platform_halt(platform_halt_action suggested_action, platform_halt_reason reason) {
switch (suggested_action) { // Use the default halt implementation using psci as the reset and shutdown implementation.
case HALT_ACTION_SHUTDOWN: platform_halt_default(suggested_action, reason, &psci_system_reset, &psci_system_off);
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 (;;);
} }

View File

@@ -24,9 +24,6 @@
#else #else
#include <kernel/novm.h> #include <kernel/novm.h>
#endif #endif
#if WITH_LIB_CONSOLE
#include <lib/console.h>
#endif
#include "platform_p.h" #include "platform_p.h"
@@ -119,33 +116,3 @@ void platform_init(void) {
} }
#endif #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

View File

@@ -31,9 +31,6 @@
#else #else
#include <kernel/novm.h> #include <kernel/novm.h>
#endif #endif
#if WITH_LIB_CONSOLE
#include <lib/console.h>
#endif
#include "platform_p.h" #include "platform_p.h"
@@ -123,39 +120,24 @@ void platform_init(void) {
#endif #endif
} }
void platform_halt(platform_halt_action suggested_action, static void reboot_(void) {
platform_halt_reason reason) {
switch (suggested_action) {
case HALT_ACTION_SHUTDOWN:
dprintf(ALWAYS, "Shutting down... (reason = %d)\n", reason);
#if RISCV_S_MODE #if RISCV_S_MODE
// try to use SBI as a cleaner way to stop sbi_system_reset(SBI_RESET_TYPE_COLD_REBOOT, SBI_RESET_REASON_NONE);
sbi_system_reset(SBI_RESET_TYPE_SHUTDOWN, SBI_RESET_REASON_NONE);
#endif #endif
*power_reset_reg = 0x5555; *power_reset_reg = 0x7777;
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;
}
arch_disable_ints(); static void shutdown_(void) {
for (;;) #if RISCV_S_MODE
arch_idle(); // 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) { status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) {

View File

@@ -24,9 +24,6 @@
#include <lib/minip.h> #include <lib/minip.h>
#endif #endif
#include <kernel/vm.h> #include <kernel/vm.h>
#if WITH_LIB_CONSOLE
#include <lib/console.h>
#endif
#include "platform_p.h" #include "platform_p.h"
@@ -68,33 +65,22 @@ void platform_init(void) {
uart_init(); uart_init();
} }
void platform_halt(platform_halt_action suggested_action, static void reboot_(void) {
platform_halt_reason reason) { #if RISCV_S_MODE
switch (suggested_action) { sbi_system_reset(SBI_RESET_TYPE_COLD_REBOOT, SBI_RESET_REASON_NONE);
case HALT_ACTION_SHUTDOWN: #endif
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;
}
arch_disable_ints(); static void shutdown_(void) {
for (;;) #if RISCV_S_MODE
arch_idle(); // 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) { status_t platform_pci_int_to_vector(unsigned int pci_int, unsigned int *vector) {