diff options
author | Jack Rosenthal <jrosenth@chromium.org> | 2019-03-11 17:37:28 -0600 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-03-13 21:05:08 -0700 |
commit | a898b6cc70e1a32494d474620e40076fa5741125 (patch) | |
tree | e152defbb08fcdb3b138ecabaf160e808feea86e /core | |
parent | 88c5b086b2722b6f959f2608de298b3ba8299888 (diff) | |
download | chrome-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.c | 82 | ||||
-rw-r--r-- | core/minute-ia/panic.c | 121 | ||||
-rw-r--r-- | core/minute-ia/task.c | 2 |
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); |