Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | /* * Copyright (c) 2013-2014 Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Kernel fatal error handler * * This module provides the _NanoFatalErrorHandler() routine. */ #include <toolchain.h> #include <sections.h> #include <kernel.h> #include <kernel_structs.h> #include <misc/printk.h> #include <arch/x86/irq_controller.h> #include <arch/x86/segmentation.h> #include <exception.h> #include <inttypes.h> __weak void _debug_fatal_hook(const NANO_ESF *esf) { ARG_UNUSED(esf); } /** * * @brief Kernel fatal error handler * * This routine is called when a fatal error condition is detected by either * hardware or software. * * The caller is expected to always provide a usable ESF. In the event that the * fatal error does not have a hardware generated ESF, the caller should either * create its own or use a pointer to the global default ESF <_default_esf>. * * @param reason the reason that the handler was called * @param pEsf pointer to the exception stack frame * * @return This function does not return. */ FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason, const NANO_ESF *pEsf) { _debug_fatal_hook(pEsf); #ifdef CONFIG_PRINTK /* Display diagnostic information about the error */ switch (reason) { case _NANO_ERR_CPU_EXCEPTION: break; case _NANO_ERR_SPURIOUS_INT: { int vector = _irq_controller_isr_vector_get(); printk("***** Unhandled interrupt vector "); if (vector >= 0) { printk("%d ", vector); } printk("*****\n"); break; } case _NANO_ERR_INVALID_TASK_EXIT: printk("***** Invalid Exit Software Error! *****\n"); break; #if defined(CONFIG_STACK_CANARIES) || defined(CONFIG_STACK_SENTINEL) case _NANO_ERR_STACK_CHK_FAIL: printk("***** Stack Check Fail! *****\n"); break; #endif /* CONFIG_STACK_CANARIES */ case _NANO_ERR_KERNEL_OOPS: printk("***** Kernel OOPS! *****\n"); break; case _NANO_ERR_KERNEL_PANIC: printk("***** Kernel Panic! *****\n"); break; case _NANO_ERR_ALLOCATION_FAIL: printk("**** Kernel Allocation Failure! ****\n"); break; default: printk("**** Unknown Fatal Error %d! ****\n", reason); break; } printk("Current thread ID = %p\n" "Faulting segment:address = 0x%04x:0x%08x\n" "eax: 0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x\n" "esi: 0x%08x, edi: 0x%08x, ebp: 0x%08x, esp: 0x%08x\n" "eflags: 0x%x\n", k_current_get(), pEsf->cs & 0xFFFF, pEsf->eip, pEsf->eax, pEsf->ebx, pEsf->ecx, pEsf->edx, pEsf->esi, pEsf->edi, pEsf->ebp, pEsf->esp, pEsf->eflags); #endif /* CONFIG_PRINTK */ /* * Error was fatal to a kernel task or a fiber; invoke the system * fatal error handling policy defined for the platform. */ _SysFatalErrorHandler(reason, pEsf); } #ifdef CONFIG_X86_KERNEL_OOPS /* The reason code gets pushed onto the stack right before the exception is * triggered, so it would be after the nano_esf data */ struct oops_esf { NANO_ESF nano_esf; unsigned int reason; }; FUNC_NORETURN void _do_kernel_oops(const struct oops_esf *esf) { _NanoFatalErrorHandler(esf->reason, &esf->nano_esf); } extern void (*_kernel_oops_handler)(void); NANO_CPU_INT_REGISTER(_kernel_oops_handler, NANO_SOFT_IRQ, CONFIG_X86_KERNEL_OOPS_VECTOR / 16, CONFIG_X86_KERNEL_OOPS_VECTOR, 0); #else /* * Define a default ESF for use with _NanoFatalErrorHandler() in the event * the caller does not have a NANO_ESF to pass */ const NANO_ESF _default_esf = { 0xdeaddead, /* ESP */ 0xdeaddead, /* EBP */ 0xdeaddead, /* EBX */ 0xdeaddead, /* ESI */ 0xdeaddead, /* EDI */ 0xdeaddead, /* EDX */ 0xdeaddead, /* ECX */ 0xdeaddead, /* EAX */ 0xdeaddead, /* error code */ 0xdeaddead, /* EIP */ 0xdeaddead, /* CS */ 0xdeaddead, /* EFLAGS */ }; #endif /* CONFIG_X86_KERNEL_OOPS */ #if CONFIG_EXCEPTION_DEBUG static FUNC_NORETURN void generic_exc_handle(unsigned int vector, const NANO_ESF *pEsf) { printk("***** CPU exception %d\n", vector); if ((1 << vector) & _EXC_ERROR_CODE_FAULTS) { printk("***** Exception code: 0x%x\n", pEsf->errorCode); } _NanoFatalErrorHandler(_NANO_ERR_CPU_EXCEPTION, pEsf); } #define _EXC_FUNC(vector) \ FUNC_NORETURN void handle_exc_##vector(const NANO_ESF *pEsf) \ { \ generic_exc_handle(vector, pEsf); \ } #define _EXC_FUNC_CODE(vector) \ _EXC_FUNC(vector) \ _EXCEPTION_CONNECT_CODE(handle_exc_##vector, vector) #define _EXC_FUNC_NOCODE(vector) \ _EXC_FUNC(vector) \ _EXCEPTION_CONNECT_NOCODE(handle_exc_##vector, vector) /* Necessary indirection to ensure 'vector' is expanded before we expand * the handle_exc_##vector */ #define EXC_FUNC_NOCODE(vector) \ _EXC_FUNC_NOCODE(vector) #define EXC_FUNC_CODE(vector) \ _EXC_FUNC_CODE(vector) EXC_FUNC_NOCODE(IV_DIVIDE_ERROR); EXC_FUNC_NOCODE(IV_NON_MASKABLE_INTERRUPT); EXC_FUNC_NOCODE(IV_OVERFLOW); EXC_FUNC_NOCODE(IV_BOUND_RANGE); EXC_FUNC_NOCODE(IV_INVALID_OPCODE); EXC_FUNC_NOCODE(IV_DEVICE_NOT_AVAILABLE); EXC_FUNC_CODE(IV_DOUBLE_FAULT); EXC_FUNC_CODE(IV_INVALID_TSS); EXC_FUNC_CODE(IV_SEGMENT_NOT_PRESENT); EXC_FUNC_CODE(IV_STACK_FAULT); EXC_FUNC_CODE(IV_GENERAL_PROTECTION); EXC_FUNC_NOCODE(IV_X87_FPU_FP_ERROR); EXC_FUNC_CODE(IV_ALIGNMENT_CHECK); EXC_FUNC_NOCODE(IV_MACHINE_CHECK); /* Page fault error code flags */ #define PRESENT BIT(0) #define WR BIT(1) #define US BIT(2) #define RSVD BIT(3) #define ID BIT(4) #define PK BIT(5) #define SGX BIT(15) FUNC_NORETURN void page_fault_handler(const NANO_ESF *pEsf) { u32_t err, cr2; /* See Section 6.15 of the IA32 Software Developer's Manual vol 3 */ __asm__ ("mov %%cr2, %0" : "=r" (cr2)); err = pEsf->errorCode; printk("***** CPU Page Fault (error code 0x%08x)\n", err); printk("%s thread %s address 0x%08x\n", err & US ? "User" : "Supervisor", err & ID ? "executed" : (err & WR ? "wrote" : "read"), cr2); _NanoFatalErrorHandler(_NANO_ERR_CPU_EXCEPTION, pEsf); } _EXCEPTION_CONNECT_CODE(page_fault_handler, IV_PAGE_FAULT); #endif /* CONFIG_EXCEPTION_DEBUG */ |