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:
parent
94140b6816
commit
2b67ca8ac9
6 changed files with 125 additions and 68 deletions
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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) \
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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()
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue