x86: improve exception debugging

We now dump more information for less common cases,
and this is now centralized code for 32-bit/64-bit.
All of this code is now correctly wrapped around
CONFIG_EXCEPTION_DEBUG. Some cruft and unused defines
removed.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2019-11-18 12:07:58 -08:00 committed by Andrew Boie
commit 2b67ca8ac9
6 changed files with 125 additions and 68 deletions

View file

@ -11,12 +11,6 @@
#include <logging/log.h> #include <logging/log.h>
LOG_MODULE_DECLARE(os); LOG_MODULE_DECLARE(os);
#ifdef CONFIG_X86_64
#define PR_UPTR "0x%016lx"
#else
#define PR_UPTR "0x%08lx"
#endif
static inline uintptr_t esf_get_sp(const z_arch_esf_t *esf) static inline uintptr_t esf_get_sp(const z_arch_esf_t *esf)
{ {
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
@ -62,6 +56,7 @@ bool z_x86_check_stack_bounds(uintptr_t addr, size_t size, u16_t cs)
} }
#endif #endif
#ifdef CONFIG_EXCEPTION_DEBUG
#if defined(CONFIG_EXCEPTION_STACK_TRACE) #if defined(CONFIG_EXCEPTION_STACK_TRACE)
struct stack_frame { struct stack_frame {
uintptr_t next; uintptr_t next;
@ -160,31 +155,75 @@ static void dump_regs(const z_arch_esf_t *esf)
} }
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */
FUNC_NORETURN void z_x86_fatal_error(unsigned int reason, static void log_exception(uintptr_t vector, uintptr_t code)
const z_arch_esf_t *esf)
{ {
if (esf != NULL) { switch (vector) {
dump_regs(esf); case IV_DIVIDE_ERROR:
LOG_ERR("Divide by zero");
break;
case IV_DEBUG:
LOG_ERR("Debug");
break;
case IV_NON_MASKABLE_INTERRUPT:
LOG_ERR("Non-maskable interrupt");
break;
case IV_BREAKPOINT:
LOG_ERR("Breakpoint");
break;
case IV_OVERFLOW:
LOG_ERR("Overflow");
break;
case IV_BOUND_RANGE:
LOG_ERR("Bound range exceeded");
break;
case IV_INVALID_OPCODE:
LOG_ERR("Invalid opcode");
break;
case IV_DEVICE_NOT_AVAILABLE:
LOG_ERR("Floating point unit device not available");
break;
case IV_DOUBLE_FAULT:
LOG_ERR("Double fault (code 0x%lx)", code);
break;
case IV_COPROC_SEGMENT_OVERRUN:
LOG_ERR("Co-processor segment overrun");
break;
case IV_INVALID_TSS:
LOG_ERR("Invalid TSS (code 0x%lx)", code);
break;
case IV_SEGMENT_NOT_PRESENT:
LOG_ERR("Segment not present (code 0x%lx)", code);
break;
case IV_STACK_FAULT:
LOG_ERR("Stack segment fault");
break;
case IV_GENERAL_PROTECTION:
LOG_ERR("General protection fault (code 0x%lx)", code);
break;
/* IV_PAGE_FAULT skipped, we have a dedicated handler */
case IV_X87_FPU_FP_ERROR:
LOG_ERR("x87 floating point exception");
break;
case IV_ALIGNMENT_CHECK:
LOG_ERR("Alignment check (code 0x%lx)", code);
break;
case IV_MACHINE_CHECK:
LOG_ERR("Machine check");
break;
case IV_SIMD_FP:
LOG_ERR("SIMD floating point exception");
break;
case IV_VIRT_EXCEPTION:
LOG_ERR("Virtualization exception");
break;
case IV_SECURITY_EXCEPTION:
LOG_ERR("Security exception");
break;
default:
break;
} }
z_fatal_error(reason, esf);
CODE_UNREACHABLE;
} }
/*
* PAGE FAULT HANDLING
*/
#ifdef CONFIG_EXCEPTION_DEBUG
/* 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)
#ifdef CONFIG_X86_MMU #ifdef CONFIG_X86_MMU
static bool dump_entry_flags(const char *name, u64_t flags) static bool dump_entry_flags(const char *name, u64_t flags)
{ {
@ -240,6 +279,15 @@ static void dump_mmu_flags(struct x86_page_tables *ptables, uintptr_t addr)
} }
#endif /* CONFIG_X86_MMU */ #endif /* CONFIG_X86_MMU */
/* 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)
static void dump_page_fault(z_arch_esf_t *esf) static void dump_page_fault(z_arch_esf_t *esf)
{ {
uintptr_t err, cr2; uintptr_t err, cr2;
@ -248,13 +296,24 @@ static void dump_page_fault(z_arch_esf_t *esf)
__asm__ ("mov %%cr2, %0" : "=r" (cr2)); __asm__ ("mov %%cr2, %0" : "=r" (cr2));
err = esf_get_code(esf); err = esf_get_code(esf);
LOG_ERR("***** CPU Page Fault (error code " PR_UPTR ")", err); LOG_ERR("Page fault at address 0x%lx (error code 0x%lx)", cr2, err);
LOG_ERR("%s thread %s address " PR_UPTR, if ((err & RSVD) != 0) {
(err & US) != 0U ? "User" : "Supervisor", LOG_ERR("Reserved bits set in page tables");
(err & ID) != 0U ? "executed" : ((err & WR) != 0U ? } else if ((err & PRESENT) == 0) {
"wrote" : LOG_ERR("Linear address not present in page tables");
"read"), cr2); } else {
LOG_ERR("Access violation: %s thread not allowed to %s",
(err & US) != 0U ? "user" : "supervisor",
(err & ID) != 0U ? "execute" : ((err & WR) != 0U ?
"write" :
"read"));
if ((err & PK) != 0) {
LOG_ERR("Protection key disallowed");
} else if ((err & SGX) != 0) {
LOG_ERR("SGX access control violation");
}
}
#ifdef CONFIG_X86_MMU #ifdef CONFIG_X86_MMU
#ifdef CONFIG_USERSPACE #ifdef CONFIG_USERSPACE
@ -269,6 +328,29 @@ static void dump_page_fault(z_arch_esf_t *esf)
} }
#endif /* CONFIG_EXCEPTION_DEBUG */ #endif /* CONFIG_EXCEPTION_DEBUG */
FUNC_NORETURN void z_x86_fatal_error(unsigned int reason,
const z_arch_esf_t *esf)
{
#ifdef CONFIG_EXCEPTION_DEBUG
if (esf != NULL) {
dump_regs(esf);
}
#endif
z_fatal_error(reason, esf);
CODE_UNREACHABLE;
}
FUNC_NORETURN void z_x86_unhandled_cpu_exception(uintptr_t vector,
const z_arch_esf_t *esf)
{
#ifdef CONFIG_EXCEPTION_DEBUG
log_exception(vector, esf_get_code(esf));
#else
ARG_UNUSED(vector);
#endif
z_x86_fatal_error(K_ERR_CPU_EXCEPTION, esf);
}
#ifdef CONFIG_USERSPACE #ifdef CONFIG_USERSPACE
Z_EXC_DECLARE(z_x86_user_string_nlen); Z_EXC_DECLARE(z_x86_user_string_nlen);

View file

@ -93,21 +93,7 @@ NANO_CPU_INT_REGISTER(_kernel_oops_handler, NANO_SOFT_IRQ,
FUNC_NORETURN static void generic_exc_handle(unsigned int vector, FUNC_NORETURN static void generic_exc_handle(unsigned int vector,
const z_arch_esf_t *pEsf) const z_arch_esf_t *pEsf)
{ {
switch (vector) { z_x86_unhandled_cpu_exception(vector, pEsf);
case IV_GENERAL_PROTECTION:
LOG_ERR("General Protection Fault");
break;
case IV_DEVICE_NOT_AVAILABLE:
LOG_ERR("Floating point unit not enabled");
break;
default:
LOG_ERR("CPU exception %d", vector);
break;
}
if ((BIT(vector) & _EXC_ERROR_CODE_FAULTS) != 0) {
LOG_ERR("Exception code: 0x%x", pEsf->errorCode);
}
z_x86_fatal_error(K_ERR_CPU_EXCEPTION, pEsf);
} }
#define _EXC_FUNC(vector) \ #define _EXC_FUNC(vector) \

View file

@ -17,9 +17,7 @@ void z_x86_exception(z_arch_esf_t *esf)
z_x86_page_fault_handler(esf); z_x86_page_fault_handler(esf);
break; break;
default: default:
LOG_ERR("** CPU Exception %ld (code %ld/0x%lx) **", z_x86_unhandled_cpu_exception(esf->vector, esf);
esf->vector, esf->code, esf->code);
z_x86_fatal_error(K_ERR_CPU_EXCEPTION, esf);
CODE_UNREACHABLE; CODE_UNREACHABLE;
} }
} }

View file

@ -31,6 +31,8 @@
#define IV_ALIGNMENT_CHECK 17 #define IV_ALIGNMENT_CHECK 17
#define IV_MACHINE_CHECK 18 #define IV_MACHINE_CHECK 18
#define IV_SIMD_FP 19 #define IV_SIMD_FP 19
#define IV_VIRT_EXCEPTION 20
#define IV_SECURITY_EXCEPTION 30
#define IV_IRQS 32 /* start of vectors available for IRQs */ #define IV_IRQS 32 /* start of vectors available for IRQs */
#define IV_NR_VECTORS 256 /* total number of vectors */ #define IV_NR_VECTORS 256 /* total number of vectors */

View file

@ -47,6 +47,12 @@ void z_x86_early_serial_init(void);
void z_x86_paging_init(void); void z_x86_paging_init(void);
#endif /* CONFIG_X86_MMU */ #endif /* CONFIG_X86_MMU */
/* Called upon CPU exception that is unhandled and hence fatal; dump
* interesting info and call z_x86_fatal_error()
*/
FUNC_NORETURN void z_x86_unhandled_cpu_exception(uintptr_t vector,
const z_arch_esf_t *esf);
/* Called upon unrecoverable error; dump registers and transfer control to /* Called upon unrecoverable error; dump registers and transfer control to
* kernel via z_fatal_error() * kernel via z_fatal_error()
*/ */

View file

@ -18,23 +18,6 @@
extern "C" { extern "C" {
#endif #endif
/*
* Bitmask used to determine which exceptions result in an error code being
* pushed onto the stack. The following exception vectors push an error code:
*
* Vector Mnemonic Description
* ------ ------- ----------------------
* 8 #DF Double Fault
* 10 #TS Invalid TSS
* 11 #NP Segment Not Present
* 12 #SS Stack Segment Fault
* 13 #GP General Protection Fault
* 14 #PF Page Fault
* 17 #AC Alignment Check
*/
#define _EXC_ERROR_CODE_FAULTS 0x27d00U
/* NOTE: We currently do not have definitions for 16-bit segment, currently /* NOTE: We currently do not have definitions for 16-bit segment, currently
* assume everything we are working with is 32-bit * assume everything we are working with is 32-bit
*/ */