diff options
author | Rob Barnes <robbarnes@google.com> | 2022-11-15 01:46:49 +0000 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2022-12-06 07:11:49 +0000 |
commit | e6c5dc42187847f5b728d865d9c750555b9b33b8 (patch) | |
tree | 0eae5b11bf0f674635ce21d15b8bbfde1536cdbb /core/cortex-m | |
parent | 4df4ed38aff2fcfc5b469d168ac87c1ebedeec56 (diff) | |
download | chrome-ec-e6c5dc42187847f5b728d865d9c750555b9b33b8.tar.gz |
system: Implement system safe mode
Basic implementation of system safe mode recovery.
System safe mode is a recovery mode that may be started after
a fault/panic. It allows the AP to collect info about the fault
and system state before the system resets
This CL includes support for Zephyr EC and legacy CrOS EC
BUG=b:249128225
BRANCH=None
TEST=./twister -s
external/platform/ec/zephyr/test/rw_safe_mode/rw_safe_mode.default
Manually tested on skyrim
Change-Id: I15139bb082011485b54e4ca7813839940bf5401a
Signed-off-by: Rob Barnes <robbarnes@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4029604
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Diffstat (limited to 'core/cortex-m')
-rw-r--r-- | core/cortex-m/cpu.c | 38 | ||||
-rw-r--r-- | core/cortex-m/cpu.h | 5 | ||||
-rw-r--r-- | core/cortex-m/panic.c | 31 |
3 files changed, 74 insertions, 0 deletions
diff --git a/core/cortex-m/cpu.c b/core/cortex-m/cpu.c index ffb6b7780c..5a882bb532 100644 --- a/core/cortex-m/cpu.c +++ b/core/cortex-m/cpu.c @@ -9,6 +9,10 @@ #include "cpu.h" #include "hooks.h" +#define STACK_IDX_REG_LR 5 +#define STACK_IDX_REG_PC 6 +#define STACK_IDX_REG_PSR 7 + void cpu_init(void) { /* Catch divide by 0 and unaligned access */ @@ -20,6 +24,40 @@ void cpu_init(void) CPU_NVIC_SHCSR_USGFAULTENA; } +void cpu_return_from_exception_msp(void (*func)(void)) +{ + uint32_t *msp; + + __asm__ volatile("mrs %0, msp" : "=r"(msp)); + + msp[STACK_IDX_REG_LR] = 0; /* Will never return */ + msp[STACK_IDX_REG_PC] = (uint32_t)func; /* Return to this function */ + msp[STACK_IDX_REG_PSR] = (1 << 24); /* Just set thumb mode */ + + /* Return from exception using main stack */ + __asm__ volatile("bx %0" : : "r"(0xFFFFFFF9)); + + /* should not reach here */ + __builtin_unreachable(); +} + +void cpu_return_from_exception_psp(void (*func)(void)) +{ + uint32_t *psp; + + __asm__ volatile("mrs %0, psp" : "=r"(psp)); + + psp[STACK_IDX_REG_LR] = 0; /* Will never return */ + psp[STACK_IDX_REG_PC] = (uint32_t)func; /* Return to this function */ + psp[STACK_IDX_REG_PSR] = (1 << 24); /* Just set thumb mode */ + + /* Return from exception using main stack */ + __asm__ volatile("bx %0" : : "r"(0xFFFFFFFD)); + + /* should not reach here */ + __builtin_unreachable(); +} + #ifdef CONFIG_ARMV7M_CACHE static void cpu_invalidate_icache(void) { diff --git a/core/cortex-m/cpu.h b/core/cortex-m/cpu.h index 4a36d63dda..d3144006f6 100644 --- a/core/cortex-m/cpu.h +++ b/core/cortex-m/cpu.h @@ -127,6 +127,11 @@ void cpu_invalidate_dcache_range(uintptr_t base, unsigned int length); /* Clean and Invalidate a single range of the D-cache */ void cpu_clean_invalidate_dcache_range(uintptr_t base, unsigned int length); +/* Return to specified function from exception handler using main stack. */ +void cpu_return_from_exception_msp(void (*func)(void)); +/* Return to specified function from exception handler using process stack. */ +void cpu_return_from_exception_psp(void (*func)(void)); + /* Set the priority of the given IRQ in the NVIC (0 is highest). */ static inline void cpu_set_interrupt_priority(uint8_t irq, uint8_t priority) { diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 1de8376cfb..eefe068931 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -11,6 +11,7 @@ #include "panic.h" #include "printf.h" #include "system.h" +#include "system_safe_mode.h" #include "task.h" #include "timer.h" #include "uart.h" @@ -287,6 +288,16 @@ void panic_data_print(const struct panic_data *pdata) #endif } +/* This is just a placeholder function for returning from exception. + * It's not expected to actually be executed. + */ +static void exception_return_placeholder(void) +{ + panic_printf("Unexpected return from exception\n"); + panic_reboot(); + __builtin_unreachable(); +} + void __keep report_panic(void) { /* @@ -353,6 +364,26 @@ void __keep report_panic(void) if (IS_ENABLED(CONFIG_ARMV7M_CACHE)) cpu_clean_invalidate_dcache(); + /* Start safe mode if possible */ + if (IS_ENABLED(CONFIG_SYSTEM_SAFE_MODE)) { + /* TODO: check for nested exceptions */ + if (start_system_safe_mode() == EC_SUCCESS) { + /* Return from exception on process stack. + * We should not actually land in + * exception_return_placeholder function. Instead the + * scheduler should interrupt and schedule + * a different task since the current task has + * been disabled. + */ + pdata->flags |= PANIC_DATA_FLAG_SAFE_MODE_STARTED; + cpu_return_from_exception_psp( + exception_return_placeholder); + + __builtin_unreachable(); + } + pdata->flags |= PANIC_DATA_FLAG_SAFE_MODE_FAIL_PRECONDITIONS; + } + panic_reboot(); } |