summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2019-03-11 17:37:28 -0600
committerchrome-bot <chrome-bot@chromium.org>2019-03-13 21:05:08 -0700
commita898b6cc70e1a32494d474620e40076fa5741125 (patch)
treee152defbb08fcdb3b138ecabaf160e808feea86e /core
parent88c5b086b2722b6f959f2608de298b3ba8299888 (diff)
downloadchrome-ec-a898b6cc70e1a32494d474620e40076fa5741125.tar.gz
minute-ia: Print panic info on processor exception
This adds appropriate x86 exception handlers to print helpful panic info when a processor exception occurs. An example is shown below: > rw 0xFFFFFFFF 0xDEADBEEF write 0xffffffff = 0xdeadbeef ========== PANIC ========== General Protection Fault Error Code = 0xFF010000 EIP = 0xFF006363 CS = 0x00000008 EFLAGS = 0x00010202 EAX = 0x00000060 EBX = 0xDEADBEEF ECX = 0xFF01519F EDX = 0x00103085 ESI = 0xFF015280 EDI = 0xFFFFFFFF Resetting system... =========================== In addition, this fixes a bug with get_current_vector_number, causing it to return 0x100 when ISR=0. BUG=b:126691187,b:128444630 BRANCH=none TEST=loaded onto arcada using ISH shim loader, used memory access and divide by zero instructions to trigger a processor exception Change-Id: Ibd58e6cb3a28b4d9cf3aa7bfb0f13d4f6fdbb77e Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1515949 Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'core')
-rw-r--r--core/minute-ia/interrupts.c82
-rw-r--r--core/minute-ia/panic.c121
-rw-r--r--core/minute-ia/task.c2
3 files changed, 184 insertions, 21 deletions
diff --git a/core/minute-ia/interrupts.c b/core/minute-ia/interrupts.c
index 336182064f..96e5626d47 100644
--- a/core/minute-ia/interrupts.c
+++ b/core/minute-ia/interrupts.c
@@ -100,6 +100,50 @@ static const irq_desc_t system_irqs[] = {
LEVEL_INTR(ISH_RESET_PREP_IRQ, ISH_RESET_PREP_VEC),
};
+/**
+ * The macro below is used to define 20 exeption handler routines, each
+ * of which will push their corresponding interrupt vector number to
+ * the stack, and then call exception_panic. The remaining arguments to
+ * exception_panic were pushed by the hardware when the exception was
+ * called.
+ *
+ * This is done since the ISR appears to be zero when exceptions are
+ * handled (b:128444630). A more ideal solution would be to use
+ * get_current_interrupt_vector from exception_panic. A fix for this
+ * *might* involve a closer investigation of the flags passed to
+ * set_interrupt_gate.
+ */
+#define DEFINE_EXN_HANDLER(vector) \
+ void __keep exception_panic_##vector(void); \
+ __attribute__ ((noreturn)) void exception_panic_##vector(void) \
+ { \
+ __asm__ ( \
+ "push $" #vector "\n" \
+ "call exception_panic\n"); \
+ while (1) \
+ continue; \
+ }
+
+DEFINE_EXN_HANDLER(0);
+DEFINE_EXN_HANDLER(1);
+DEFINE_EXN_HANDLER(2);
+DEFINE_EXN_HANDLER(3);
+DEFINE_EXN_HANDLER(4);
+DEFINE_EXN_HANDLER(5);
+DEFINE_EXN_HANDLER(6);
+DEFINE_EXN_HANDLER(7);
+DEFINE_EXN_HANDLER(8);
+DEFINE_EXN_HANDLER(9);
+DEFINE_EXN_HANDLER(10);
+DEFINE_EXN_HANDLER(11);
+DEFINE_EXN_HANDLER(12);
+DEFINE_EXN_HANDLER(13);
+DEFINE_EXN_HANDLER(14);
+DEFINE_EXN_HANDLER(16);
+DEFINE_EXN_HANDLER(17);
+DEFINE_EXN_HANDLER(18);
+DEFINE_EXN_HANDLER(19);
+DEFINE_EXN_HANDLER(20);
void set_interrupt_gate(uint8_t num, isr_handler_t func, uint8_t flags)
{
@@ -116,10 +160,19 @@ void set_interrupt_gate(uint8_t num, isr_handler_t func, uint8_t flags)
__idt[num].flags = flags;
}
-/* This should only be called from an interrupt context */
+/**
+ * This procedure gets the current interrupt vector number, and should
+ * only be called from an interrupt vector context. Note that it may
+ * fail under some cases (see b:128444630).
+ *
+ * Returns an integer in range 0-255 upon success, or 256 (0x100)
+ * upon failure.
+ */
uint32_t get_current_interrupt_vector(void)
{
- uint32_t vec, i;
+ int i;
+ uint32_t vec;
+
/* In service register */
uint32_t *ioapic_icr_last = (uint32_t *)LAPIC_ISR_REG;
@@ -131,8 +184,7 @@ uint32_t get_current_interrupt_vector(void)
}
}
- CPRINTS("Cannot get vector, not in ISR!");
- return 0;
+ return 0x100;
}
static uint32_t lapic_lvt_error_count;
@@ -281,6 +333,28 @@ void init_interrupts(void)
set_interrupt_gate(ISH_TS_VECTOR, __switchto, IDT_FLAGS);
+ /* Bind exception handlers to print panic message */
+ set_interrupt_gate(0, exception_panic_0, IDT_FLAGS);
+ set_interrupt_gate(1, exception_panic_1, IDT_FLAGS);
+ set_interrupt_gate(2, exception_panic_2, IDT_FLAGS);
+ set_interrupt_gate(3, exception_panic_3, IDT_FLAGS);
+ set_interrupt_gate(4, exception_panic_4, IDT_FLAGS);
+ set_interrupt_gate(5, exception_panic_5, IDT_FLAGS);
+ set_interrupt_gate(6, exception_panic_6, IDT_FLAGS);
+ set_interrupt_gate(7, exception_panic_7, IDT_FLAGS);
+ set_interrupt_gate(8, exception_panic_8, IDT_FLAGS);
+ set_interrupt_gate(9, exception_panic_9, IDT_FLAGS);
+ set_interrupt_gate(10, exception_panic_10, IDT_FLAGS);
+ set_interrupt_gate(11, exception_panic_11, IDT_FLAGS);
+ set_interrupt_gate(12, exception_panic_12, IDT_FLAGS);
+ set_interrupt_gate(13, exception_panic_13, IDT_FLAGS);
+ set_interrupt_gate(14, exception_panic_14, IDT_FLAGS);
+ set_interrupt_gate(16, exception_panic_16, IDT_FLAGS);
+ set_interrupt_gate(17, exception_panic_17, IDT_FLAGS);
+ set_interrupt_gate(18, exception_panic_18, IDT_FLAGS);
+ set_interrupt_gate(19, exception_panic_19, IDT_FLAGS);
+ set_interrupt_gate(20, exception_panic_20, IDT_FLAGS);
+
/* Note: At reset, ID field is already set to 0 in APIC ID register */
/* Enable the APIC, mapping the spurious interrupt at the same time. */
diff --git a/core/minute-ia/panic.c b/core/minute-ia/panic.c
index 38c9852cca..aec6c4016a 100644
--- a/core/minute-ia/panic.c
+++ b/core/minute-ia/panic.c
@@ -15,14 +15,60 @@
#include "util.h"
#include "watchdog.h"
-/* Whether bus fault is ignored */
-static int bus_fault_ignored;
+/*
+ * This array maps an interrupt vector number to the corresponding
+ * exception name. See see "Intel 64 and IA-32 Architectures Software
+ * Developer's Manual", Volume 3A, Section 6.15.
+ */
+const static char *PANIC_REASON[] = {
+ "Divide By Zero",
+ "Debug Exception",
+ "NMI Interrupt",
+ "Breakpoint Exception",
+ "Overflow Exception",
+ "BOUND Range Exceeded Exception",
+ "Invalid Opcode Exception",
+ "Device Not Available Exception",
+ "Double Fault Exception",
+ "Coprocessor Segment Overrun",
+ "Invalid TSS Exception",
+ "Segment Not Present",
+ "Stack Fault Exception",
+ "General Protection Fault",
+ "Page Fault",
+ "Reserved",
+ "Math Fault",
+ "Alignment Check Exception",
+ "Machine Check Exception",
+ "SIMD Floating Point Exception",
+ "Virtualization Exception",
+};
/*
* Print panic data
*/
void panic_data_print(const struct panic_data *pdata)
{
+ panic_printf("\n========== PANIC ==========\n");
+ if (pdata->x86.vector <= 20)
+ panic_printf("%s\n", PANIC_REASON[pdata->x86.vector]);
+ else
+ panic_printf("Interrupt vector number: 0x%08X (unknown)\n",
+ pdata->x86.vector);
+ panic_printf("\n");
+ panic_printf("Error Code = 0x%08X\n", pdata->x86.error_code);
+ panic_printf("EIP = 0x%08X\n", pdata->x86.eip);
+ panic_printf("CS = 0x%08X\n", pdata->x86.cs);
+ panic_printf("EFLAGS = 0x%08X\n", pdata->x86.eflags);
+ panic_printf("EAX = 0x%08X\n", pdata->x86.eax);
+ panic_printf("EBX = 0x%08X\n", pdata->x86.ebx);
+ panic_printf("ECX = 0x%08X\n", pdata->x86.ecx);
+ panic_printf("EDX = 0x%08X\n", pdata->x86.edx);
+ panic_printf("ESI = 0x%08X\n", pdata->x86.esi);
+ panic_printf("EDI = 0x%08X\n", pdata->x86.edi);
+ panic_printf("\n");
+ panic_printf("Resetting system...\n");
+ panic_printf("===========================\n");
}
void __keep report_panic(void)
@@ -32,19 +78,71 @@ void __keep report_panic(void)
/**
* Default exception handler, which reports a panic.
*
- * Declare this as a naked call so we can extract raw LR and IPSR values.
+ * The first parameter should be pushed by a software routine aware of
+ * the interrupt vector number (see DEFINE_EXN_HANDLER macro in
+ * interrupts.c).
+ *
+ * The remaining parameters (error_code, eip, cs, eflags) are in the
+ * order pushed to the stack by hardware: see "Intel 64 and IA-32
+ * Architectures Software Developer's Manual", Volume 3A, Figure 6-4.
*/
-void __keep exception_panic(void);
-void exception_panic(void)
+__attribute__ ((noreturn)) void __keep exception_panic(
+ uint32_t vector,
+ uint32_t error_code,
+ uint32_t eip,
+ uint32_t cs,
+ uint32_t eflags)
+{
+ register uint32_t eax asm("eax");
+ register uint32_t ebx asm("ebx");
+ register uint32_t ecx asm("ecx");
+ register uint32_t edx asm("edx");
+ register uint32_t esi asm("esi");
+ register uint32_t edi asm("edi");
+
+ /* Save registers to global panic structure */
+ PANIC_DATA_PTR->x86.eax = eax;
+ PANIC_DATA_PTR->x86.ebx = ebx;
+ PANIC_DATA_PTR->x86.ecx = ecx;
+ PANIC_DATA_PTR->x86.edx = edx;
+ PANIC_DATA_PTR->x86.esi = esi;
+ PANIC_DATA_PTR->x86.edi = edi;
+
+ /* Save stack data to global panic structure */
+ PANIC_DATA_PTR->x86.vector = vector;
+ PANIC_DATA_PTR->x86.error_code = error_code;
+ PANIC_DATA_PTR->x86.eip = eip;
+ PANIC_DATA_PTR->x86.cs = cs;
+ PANIC_DATA_PTR->x86.eflags = eflags;
+
+ /* Initialize panic data */
+ PANIC_DATA_PTR->arch = PANIC_ARCH_X86;
+ PANIC_DATA_PTR->struct_version = 2;
+ PANIC_DATA_PTR->magic = PANIC_DATA_MAGIC;
+
+ /* Display the panic and reset */
+ panic_data_print(PANIC_DATA_PTR);
+ system_reset(SYSTEM_RESET_HARD);
+ while (1)
+ continue;
+}
+
+static int command_divzero(int argc, char **argv)
{
+ volatile int x = 0;
+
+ x = 1 / x;
+ return EC_SUCCESS;
}
+DECLARE_CONSOLE_COMMAND(divzero, command_divzero, NULL,
+ "Divide by zero to trigger a processor exception");
#ifdef CONFIG_SOFTWARE_PANIC
void software_panic(uint32_t reason, uint32_t info)
{
/* TODO: store panic log */
while (1)
- ;
+ continue;
}
void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception)
@@ -55,14 +153,3 @@ void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception)
{
}
#endif
-
-void bus_fault_handler(void)
-{
- if (!bus_fault_ignored)
- exception_panic();
-}
-
-void ignore_bus_fault(int ignored)
-{
- bus_fault_ignored = ignored;
-}
diff --git a/core/minute-ia/task.c b/core/minute-ia/task.c
index 9975cc62d7..62481d96f0 100644
--- a/core/minute-ia/task.c
+++ b/core/minute-ia/task.c
@@ -269,6 +269,8 @@ void __keep task_start_irq_handler(void *unused)
* pre-empted.
*/
uint32_t t = get_time().le.lo;
+
+ /* ISR is occasionally zero, see b:128444630 */
uint32_t vector = get_current_interrupt_vector();
int irq = VEC_TO_IRQ(vector);