diff options
-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 | ||||
-rw-r--r-- | include/panic.h | 21 |
4 files changed, 205 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); diff --git a/include/panic.h b/include/panic.h index 1984081dd7..aeaa8f8024 100644 --- a/include/panic.h +++ b/include/panic.h @@ -41,6 +41,25 @@ struct nds32_n8_panic_data { uint32_t ipsw; }; +/* x86 registers saved on panic */ +struct x86_panic_data { + uint32_t vector; /* Exception vector number */ + + /* Data pushed when exception handler called */ + uint32_t error_code; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + + /* General purpose registers */ + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; +}; + /* Data saved across reboots */ struct panic_data { uint8_t arch; /* Architecture (PANIC_ARCH_*) */ @@ -52,6 +71,7 @@ struct panic_data { union { struct cortex_panic_data cm; /* Cortex-Mx registers */ struct nds32_n8_panic_data nds_n8; /* NDS32 N8 registers */ + struct x86_panic_data x86; /* Intel x86 */ }; /* @@ -66,6 +86,7 @@ struct panic_data { enum panic_arch { PANIC_ARCH_CORTEX_M = 1, /* Cortex-M architecture */ PANIC_ARCH_NDS32_N8 = 2, /* NDS32 N8 architecture */ + PANIC_ARCH_X86 = 3, /* Intel x86 */ }; /* |