aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/exceptions.c40
-rw-r--r--core/fast-reboot.c1
-rw-r--r--core/init.c29
-rw-r--r--core/platform.c6
-rw-r--r--core/utils.c26
-rw-r--r--include/processor.h3
-rw-r--r--include/skiboot.h1
-rw-r--r--libc/include/assert.h45
-rw-r--r--libc/include/stdlib.h7
-rw-r--r--skiboot.lds.S7
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*))