diff options
-rw-r--r-- | core/exceptions.c | 40 | ||||
-rw-r--r-- | core/fast-reboot.c | 1 | ||||
-rw-r--r-- | core/init.c | 29 | ||||
-rw-r--r-- | core/platform.c | 6 | ||||
-rw-r--r-- | core/utils.c | 26 | ||||
-rw-r--r-- | include/processor.h | 3 | ||||
-rw-r--r-- | include/skiboot.h | 1 | ||||
-rw-r--r-- | libc/include/assert.h | 45 | ||||
-rw-r--r-- | libc/include/stdlib.h | 7 | ||||
-rw-r--r-- | skiboot.lds.S | 7 |
10 files changed, 130 insertions, 35 deletions
diff --git a/core/exceptions.c b/core/exceptions.c index f853278..c50db82 100644 --- a/core/exceptions.c +++ b/core/exceptions.c @@ -89,6 +89,35 @@ void exception_entry(struct stack_frame *stack) "Fatal MCE at "REG" ", nip); break; + case 0x700: { + struct trap_table_entry *tte; + + fatal = true; + prerror("***********************************************\n"); + for (tte = __trap_table_start; tte < __trap_table_end; tte++) { + if (tte->address == nip) { + prerror("< %s >\n", tte->message); + prerror(" .\n"); + prerror(" .\n"); + prerror(" .\n"); + prerror(" OO__)\n"); + prerror(" <\"__/\n"); + prerror(" ^ ^\n"); + break; + } + } + l += snprintf(buf + l, EXCEPTION_MAX_STR - l, + "Fatal TRAP at "REG" ", nip); + l += snprintf_symbol(buf + l, EXCEPTION_MAX_STR - l, nip); + l += snprintf(buf + l, EXCEPTION_MAX_STR - l, " MSR "REG, msr); + prerror("%s\n", buf); + dump_regs(stack); + backtrace(); + if (platform.terminate) + platform.terminate(buf); + for (;;) ; + break; } + default: fatal = true; prerror("***********************************************\n"); @@ -100,11 +129,12 @@ void exception_entry(struct stack_frame *stack) l += snprintf(buf + l, EXCEPTION_MAX_STR - l, " MSR "REG, msr); prerror("%s\n", buf); dump_regs(stack); - - if (fatal) - abort(); - else - backtrace(); + backtrace(); + if (fatal) { + if (platform.terminate) + platform.terminate(buf); + for (;;) ; + } if (hv) { /* Set up for SRR return */ diff --git a/core/fast-reboot.c b/core/fast-reboot.c index 9631eb9..a6c903f 100644 --- a/core/fast-reboot.c +++ b/core/fast-reboot.c @@ -183,6 +183,7 @@ void fast_reboot(void) /* Restore skiboot vectors */ copy_exception_vectors(); + patch_traps(true); /* * Secondaries may still have an issue with machine checks if they have diff --git a/core/init.c b/core/init.c index cd333dc..7dc0611 100644 --- a/core/init.c +++ b/core/init.c @@ -618,6 +618,8 @@ void __noreturn load_and_boot_kernel(bool is_reboot) /* Disable machine checks on all */ cpu_disable_ME_RI_all(); + patch_traps(false); + debug_descriptor.state_flags |= OPAL_BOOT_COMPLETE; cpu_give_self_os(); @@ -758,7 +760,7 @@ static void __nomcount do_ctors(void) #ifndef PPC64_ELF_ABI_v2 static void branch_null(void) { - assert_fail("Branch to NULL !"); + assert(0); } @@ -821,6 +823,28 @@ void copy_exception_vectors(void) sync_icache(); } +/* + * When skiboot owns the exception vectors, patch in 'trap' for assert fails. + * Otherwise use assert_fail() + */ +void patch_traps(bool enable) +{ + struct trap_table_entry *tte; + + for (tte = __trap_table_start; tte < __trap_table_end; tte++) { + uint32_t *insn; + + insn = (uint32_t *)tte->address; + if (enable) { + *insn = PPC_INST_TRAP; + } else { + *insn = PPC_INST_NOP; + } + } + + sync_icache(); +} + static void per_thread_sanity_checks(void) { struct cpu_thread *cpu = this_cpu(); @@ -950,6 +974,9 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) /* Copy all vectors down to 0 */ copy_exception_vectors(); + /* Enable trap based asserts */ + patch_traps(true); + /* * Enable MSR[ME] bit so we can take MCEs. We don't currently * recover, but we print some useful information. diff --git a/core/platform.c b/core/platform.c index 1246f84..9f1873c 100644 --- a/core/platform.c +++ b/core/platform.c @@ -110,7 +110,11 @@ static int64_t opal_cec_reboot2(uint32_t reboot_type, char *diag) case OPAL_REBOOT_MPIPL: prlog(PR_NOTICE, "Reboot: OS reported error. Performing MPIPL\n"); console_complete_flush(); - _abort("Reboot: OS reported error. Performing MPIPL\n"); + if (platform.terminate) + platform.terminate("OS reported error. Performing MPIPL\n"); + else + opal_cec_reboot(); + for (;;); break; default: prlog(PR_NOTICE, "OPAL: Unsupported reboot request %d\n", reboot_type); diff --git a/core/utils.c b/core/utils.c index 728cea4..8fd63fc 100644 --- a/core/utils.c +++ b/core/utils.c @@ -13,28 +13,24 @@ #include <cpu.h> #include <stack.h> -void __noreturn assert_fail(const char *msg) -{ - /** - * @fwts-label FailedAssert - * @fwts-advice OPAL hit an assert(). During normal usage (even - * testing) we should never hit an assert. There are other code - * paths for controlled shutdown/panic in the event of catastrophic - * errors. - */ - prlog(PR_EMERG, "Assert fail: %s\n", msg); - _abort(msg); -} - -void __noreturn _abort(const char *msg) +void __noreturn assert_fail(const char *msg, const char *file, + unsigned int line, const char *function) { static bool in_abort = false; + (void)function; if (in_abort) for (;;) ; in_abort = true; - prlog(PR_EMERG, "Aborting!\n"); + /** + * @fwts-label FailedAssert2 + * @fwts-advice OPAL hit an assert(). During normal usage (even + * testing) we should never hit an assert. There are other code + * paths for controlled shutdown/panic in the event of catastrophic + * errors. + */ + prlog(PR_EMERG, "assert failed at %s:%u: %s\n", file, line, msg); backtrace(); if (platform.terminate) diff --git a/include/processor.h b/include/processor.h index 352fd1e..a0c2864 100644 --- a/include/processor.h +++ b/include/processor.h @@ -206,6 +206,9 @@ #include <stdbool.h> #include <stdint.h> +#define PPC_INST_NOP 0x60000000UL +#define PPC_INST_TRAP 0x7fe00008UL + #define RB(b) (((b) & 0x1f) << 11) #define MSGSND(b) stringify(.long 0x7c00019c | RB(b)) #define MSGCLR(b) stringify(.long 0x7c0001dc | RB(b)) diff --git a/include/skiboot.h b/include/skiboot.h index 96d25b8..686ba9d 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -192,6 +192,7 @@ extern bool start_preload_kernel(void); extern void copy_exception_vectors(void); extern void copy_sreset_vector(void); extern void copy_sreset_vector_fast_reboot(void); +extern void patch_traps(bool enable); /* Various probe routines, to replace with an initcall system */ extern void probe_phb3(void); diff --git a/libc/include/assert.h b/libc/include/assert.h index 2c49fd7..1e511fb 100644 --- a/libc/include/assert.h +++ b/libc/include/assert.h @@ -13,17 +13,48 @@ #ifndef _ASSERT_H #define _ASSERT_H -#define assert(cond) \ - do { if (!(cond)) { \ - assert_fail(__FILE__ \ - ":" stringify(__LINE__) \ - ":" stringify(cond)); } \ - } while(0) +struct trap_table_entry { + unsigned long address; + const char *message; +}; -void __attribute__((noreturn)) assert_fail(const char *msg); +extern struct trap_table_entry __trap_table_start[]; +extern struct trap_table_entry __trap_table_end[]; #define stringify(expr) stringify_1(expr) /* Double-indirection required to stringify expansions */ #define stringify_1(expr) #expr +void __attribute__((noreturn)) assert_fail(const char *msg, + const char *file, + unsigned int line, + const char *function); + +/* + * The 'nop' gets patched to 'trap' after skiboot takes over the exception + * vectors, then patched to 'nop' before booting the OS (see patch_traps). + * This makes assert fall through to assert_fail when we can't use the 0x700 + * interrupt. + */ +#define assert(cond) \ +do { \ + /* evaluate cond exactly once */ \ + const unsigned long __cond = (unsigned long)(cond); \ + asm volatile( \ + " cmpdi %0,0" "\n\t" \ + " bne 2f" "\n\t" \ + "1: nop # assert" "\n\t" \ + "2:" "\n\t" \ + ".section .rodata" "\n\t" \ + "3: .string \"assert failed at " __FILE__ ":" stringify(__LINE__) "\"" "\n\t" \ + ".previous" "\n\t" \ + ".section .trap_table,\"aw\"" "\n\t" \ + ".llong 1b" "\n\t" \ + ".llong 3b" "\n\t" \ + ".previous" "\n\t" \ + : : "r"(__cond) : "cr0"); \ + if (!__cond) \ + assert_fail(stringify(cond), __FILE__, __LINE__, __FUNCTION__); \ +} while (0) + #endif diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h index 234bd11..43d5c24 100644 --- a/libc/include/stdlib.h +++ b/libc/include/stdlib.h @@ -26,11 +26,6 @@ long int strtol(const char *nptr, char **endptr, int base); int rand(void); long int __attribute__((const)) labs(long int n); -void __attribute__((noreturn)) _abort(const char *msg); -#define abort() do { \ - _abort("abort():" __FILE__ \ - ":" stringify(__LINE__)); \ - } while(0) - +#define abort() assert(0) #endif diff --git a/skiboot.lds.S b/skiboot.lds.S index 5b4bb41..8890d69 100644 --- a/skiboot.lds.S +++ b/skiboot.lds.S @@ -109,6 +109,13 @@ SECTIONS } . = ALIGN(0x10); + .trap_table : { + __trap_table_start = .; + KEEP(*(.trap_table)) + __trap_table_end = .; + } + + . = ALIGN(0x10); .init : { __ctors_start = .; KEEP(*(.ctors*)) |