x86: exception-assisted panic/oops support
We reserve a specific vector in the IDT to trigger when we want to enter a fatal exception state from software. Disabled for drivers/build_all tests as we were up to the ROM limit on Quark D2000. Issue: ZEP-843 Change-Id: I4de7f025fba0691d07bcc3b3f0925973834496a0 Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
cdb94d6425
commit
7827b7bf4a
7 changed files with 89 additions and 23 deletions
|
@ -256,6 +256,26 @@ config IRQ_OFFLOAD_VECTOR
|
||||||
where there is a fixed IRQ-to-vector mapping another value may be
|
where there is a fixed IRQ-to-vector mapping another value may be
|
||||||
needed to avoid collision.
|
needed to avoid collision.
|
||||||
|
|
||||||
|
config X86_KERNEL_OOPS
|
||||||
|
bool "Enable handling of kernel oops as an exception"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Enable handling of k_oops() API as a CPU exception, which will provide
|
||||||
|
extra debugging information such as program counter and register
|
||||||
|
values when the oops is triggered. Requires an entry in the IDT.
|
||||||
|
|
||||||
|
config X86_KERNEL_OOPS_VECTOR
|
||||||
|
int "IDT vector to use for kernel oops"
|
||||||
|
default 62 if MVIC
|
||||||
|
default 33 if !MVIC
|
||||||
|
range 32 255
|
||||||
|
depends on X86_KERNEL_OOPS
|
||||||
|
help
|
||||||
|
Specify the IDT vector to use for the kernel oops exception handler.
|
||||||
|
The default should be fine for most arches, but on systems like MVIC
|
||||||
|
where there is a fixed IRQ-to-vector mapping another value may be
|
||||||
|
needed to avoid collision.
|
||||||
|
|
||||||
config XIP
|
config XIP
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,11 @@
|
||||||
/* exports (internal APIs) */
|
/* exports (internal APIs) */
|
||||||
|
|
||||||
GTEXT(_exception_enter)
|
GTEXT(_exception_enter)
|
||||||
|
GTEXT(_kernel_oops_handler)
|
||||||
|
|
||||||
/* externs (internal APIs) */
|
/* externs (internal APIs) */
|
||||||
|
GTEXT(_do_kernel_oops)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @brief Inform the kernel of an exception
|
* @brief Inform the kernel of an exception
|
||||||
|
@ -226,3 +229,9 @@ nestedException:
|
||||||
/* Pop of EFLAGS will re-enable interrupts and restore direction flag */
|
/* Pop of EFLAGS will re-enable interrupts and restore direction flag */
|
||||||
iret
|
iret
|
||||||
|
|
||||||
|
#if CONFIG_X86_KERNEL_OOPS
|
||||||
|
SECTION_FUNC(TEXT, _kernel_oops_handler)
|
||||||
|
push $0 /* dummy error code */
|
||||||
|
push $_do_kernel_oops
|
||||||
|
jmp _exception_enter
|
||||||
|
#endif
|
||||||
|
|
|
@ -24,24 +24,6 @@
|
||||||
|
|
||||||
__weak void _debug_fatal_hook(const NANO_ESF *esf) { ARG_UNUSED(esf); }
|
__weak void _debug_fatal_hook(const NANO_ESF *esf) { ARG_UNUSED(esf); }
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -110,9 +92,9 @@ FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason,
|
||||||
}
|
}
|
||||||
|
|
||||||
printk("Current thread ID = %p\n"
|
printk("Current thread ID = %p\n"
|
||||||
"Faulting segment:address = 0x%x:0x%x\n"
|
"Faulting segment:address = 0x%04x:0x%08x\n"
|
||||||
"eax: 0x%x, ebx: 0x%x, ecx: 0x%x, edx: 0x%x\n"
|
"eax: 0x%08x, ebx: 0x%08x, ecx: 0x%08x, edx: 0x%08x\n"
|
||||||
"esi: 0x%x, edi: 0x%x, ebp: 0%x, esp: 0x%x\n"
|
"esi: 0x%08x, edi: 0x%08x, ebp: 0x%08x, esp: 0x%08x\n"
|
||||||
"eflags: 0x%x\n",
|
"eflags: 0x%x\n",
|
||||||
k_current_get(),
|
k_current_get(),
|
||||||
pEsf->cs & 0xFFFF, pEsf->eip,
|
pEsf->cs & 0xFFFF, pEsf->eip,
|
||||||
|
@ -130,6 +112,45 @@ FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason,
|
||||||
_SysFatalErrorHandler(reason, pEsf);
|
_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
|
#if CONFIG_EXCEPTION_DEBUG
|
||||||
|
|
||||||
static FUNC_NORETURN void generic_exc_handle(unsigned int vector,
|
static FUNC_NORETURN void generic_exc_handle(unsigned int vector,
|
||||||
|
|
|
@ -498,11 +498,25 @@ extern u32_t _timer_cycle_get_32(void);
|
||||||
/** kernel provided routine to report any detected fatal error. */
|
/** kernel provided routine to report any detected fatal error. */
|
||||||
extern FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason,
|
extern FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason,
|
||||||
const NANO_ESF * pEsf);
|
const NANO_ESF * pEsf);
|
||||||
|
|
||||||
/** User provided routine to handle any detected fatal error post reporting. */
|
/** User provided routine to handle any detected fatal error post reporting. */
|
||||||
extern FUNC_NORETURN void _SysFatalErrorHandler(unsigned int reason,
|
extern FUNC_NORETURN void _SysFatalErrorHandler(unsigned int reason,
|
||||||
const NANO_ESF * pEsf);
|
const NANO_ESF * pEsf);
|
||||||
|
|
||||||
|
#if CONFIG_X86_KERNEL_OOPS
|
||||||
|
#define _ARCH_EXCEPT(reason_p) do { \
|
||||||
|
__asm__ volatile( \
|
||||||
|
"push %[reason]\n\t" \
|
||||||
|
"int %[vector]\n\t" \
|
||||||
|
: \
|
||||||
|
: [vector] "i" (CONFIG_X86_KERNEL_OOPS_VECTOR), \
|
||||||
|
[reason] "i" (reason_p)); \
|
||||||
|
CODE_UNREACHABLE; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
/** Dummy ESF for fatal errors that would otherwise not have an ESF */
|
/** Dummy ESF for fatal errors that would otherwise not have an ESF */
|
||||||
extern const NANO_ESF _default_esf;
|
extern const NANO_ESF _default_esf;
|
||||||
|
#endif /* CONFIG_X86_KERNEL_OOPS */
|
||||||
|
|
||||||
#endif /* !_ASMLANGUAGE */
|
#endif /* !_ASMLANGUAGE */
|
||||||
|
|
||||||
|
|
|
@ -13,3 +13,4 @@ CONFIG_SERIAL=n
|
||||||
CONFIG_IPM=n
|
CONFIG_IPM=n
|
||||||
CONFIG_GPIO=n
|
CONFIG_GPIO=n
|
||||||
CONFIG_ERRNO=n
|
CONFIG_ERRNO=n
|
||||||
|
CONFIG_X86_KERNEL_OOPS=n
|
||||||
|
|
|
@ -8,3 +8,4 @@ CONFIG_PWM=y
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
CONFIG_SPI=y
|
CONFIG_SPI=y
|
||||||
CONFIG_WATCHDOG=y
|
CONFIG_WATCHDOG=y
|
||||||
|
CONFIG_X86_KERNEL_OOPS=n
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* These vectors are somewhat arbitrary. We try and use unused vectors */
|
/* These vectors are somewhat arbitrary. We try and use unused vectors */
|
||||||
#define TEST_SOFT_INT 62
|
#define TEST_SOFT_INT 60
|
||||||
#define TEST_SPUR_INT 63
|
#define TEST_SPUR_INT 61
|
||||||
|
|
||||||
|
|
||||||
#define MY_STACK_SIZE 2048
|
#define MY_STACK_SIZE 2048
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue