x86: implement hw-based oops for both variants
We use a fixed value of 32 as the way interrupts/exceptions are setup in x86_64's locore.S do not lend themselves to Kconfig configuration of the vector to use. HW-based kernel oops is now permanently on, there's no reason to make it optional that I can see. Default vectors for IPI and irq offload adjusted to not collide. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
708d5f7922
commit
077b587447
14 changed files with 63 additions and 50 deletions
|
@ -58,7 +58,7 @@ config MAX_IRQ_LINES
|
||||||
|
|
||||||
config IRQ_OFFLOAD_VECTOR
|
config IRQ_OFFLOAD_VECTOR
|
||||||
int "IDT vector to use for IRQ offload"
|
int "IDT vector to use for IRQ offload"
|
||||||
default 32
|
default 33
|
||||||
range 32 255
|
range 32 255
|
||||||
depends on IRQ_OFFLOAD
|
depends on IRQ_OFFLOAD
|
||||||
|
|
||||||
|
|
|
@ -197,22 +197,6 @@ config CACHE_FLUSHING
|
||||||
cache must be selected as well. By default, that mechanism is discovered at
|
cache must be selected as well. By default, that mechanism is discovered at
|
||||||
runtime.
|
runtime.
|
||||||
|
|
||||||
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 33
|
|
||||||
range 32 255
|
|
||||||
depends on X86_KERNEL_OOPS
|
|
||||||
help
|
|
||||||
Specify the IDT vector to use for the kernel oops exception handler.
|
|
||||||
|
|
||||||
config X86_DYNAMIC_IRQ_STUBS
|
config X86_DYNAMIC_IRQ_STUBS
|
||||||
int "Number of dynamic interrupt stubs"
|
int "Number of dynamic interrupt stubs"
|
||||||
depends on DYNAMIC_INTERRUPTS
|
depends on DYNAMIC_INTERRUPTS
|
||||||
|
|
|
@ -42,7 +42,7 @@ config X86_EXCEPTION_STACK_TRACE
|
||||||
|
|
||||||
config SCHED_IPI_VECTOR
|
config SCHED_IPI_VECTOR
|
||||||
int "IDT vector to use for scheduler IPI"
|
int "IDT vector to use for scheduler IPI"
|
||||||
default 33
|
default 34
|
||||||
range 33 255
|
range 33 255
|
||||||
depends on SMP
|
depends on SMP
|
||||||
|
|
||||||
|
|
|
@ -342,3 +342,28 @@ void z_x86_page_fault_handler(z_arch_esf_t *esf)
|
||||||
z_x86_fatal_error(K_ERR_CPU_EXCEPTION, esf);
|
z_x86_fatal_error(K_ERR_CPU_EXCEPTION, esf);
|
||||||
CODE_UNREACHABLE;
|
CODE_UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void z_x86_do_kernel_oops(const z_arch_esf_t *esf)
|
||||||
|
{
|
||||||
|
uintptr_t reason;
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
reason = esf->rax;
|
||||||
|
#else
|
||||||
|
uintptr_t *stack_ptr = (uintptr_t *)esf->esp;
|
||||||
|
|
||||||
|
reason = *stack_ptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_USERSPACE
|
||||||
|
/* User mode is only allowed to induce oopses and stack check
|
||||||
|
* failures via this software interrupt
|
||||||
|
*/
|
||||||
|
if ((esf->cs & 0x3) != 0 && !(reason == K_ERR_KERNEL_OOPS ||
|
||||||
|
reason == K_ERR_STACK_CHK_FAIL)) {
|
||||||
|
reason = K_ERR_KERNEL_OOPS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
z_x86_fatal_error(reason, esf);
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
GTEXT(_kernel_oops_handler)
|
GTEXT(_kernel_oops_handler)
|
||||||
|
|
||||||
/* externs (internal APIs) */
|
/* externs (internal APIs) */
|
||||||
GTEXT(z_do_kernel_oops)
|
GTEXT(z_x86_do_kernel_oops)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -219,9 +219,7 @@ nestedException:
|
||||||
/* Pop of EFLAGS will re-enable interrupts and restore direction flag */
|
/* Pop of EFLAGS will re-enable interrupts and restore direction flag */
|
||||||
KPTI_IRET
|
KPTI_IRET
|
||||||
|
|
||||||
#if CONFIG_X86_KERNEL_OOPS
|
|
||||||
SECTION_FUNC(TEXT, _kernel_oops_handler)
|
SECTION_FUNC(TEXT, _kernel_oops_handler)
|
||||||
push $0 /* dummy error code */
|
push $0 /* dummy error code */
|
||||||
push $z_do_kernel_oops
|
push $z_x86_do_kernel_oops
|
||||||
jmp _exception_enter
|
jmp _exception_enter
|
||||||
#endif
|
|
||||||
|
|
|
@ -50,30 +50,9 @@ void arch_syscall_oops(void *ssf_ptr)
|
||||||
z_x86_fatal_error(K_ERR_KERNEL_OOPS, &oops);
|
z_x86_fatal_error(K_ERR_KERNEL_OOPS, &oops);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_KERNEL_OOPS
|
|
||||||
void z_do_kernel_oops(const z_arch_esf_t *esf)
|
|
||||||
{
|
|
||||||
u32_t *stack_ptr = (u32_t *)esf->esp;
|
|
||||||
u32_t reason = *stack_ptr;
|
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
|
||||||
/* User mode is only allowed to induce oopses and stack check
|
|
||||||
* failures via this software interrupt
|
|
||||||
*/
|
|
||||||
if (esf->cs == USER_CODE_SEG && !(reason == K_ERR_KERNEL_OOPS ||
|
|
||||||
reason == K_ERR_STACK_CHK_FAIL)) {
|
|
||||||
reason = K_ERR_KERNEL_OOPS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
z_x86_fatal_error(reason, esf);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void (*_kernel_oops_handler)(void);
|
extern void (*_kernel_oops_handler)(void);
|
||||||
NANO_CPU_INT_REGISTER(_kernel_oops_handler, NANO_SOFT_IRQ,
|
NANO_CPU_INT_REGISTER(_kernel_oops_handler, NANO_SOFT_IRQ,
|
||||||
CONFIG_X86_KERNEL_OOPS_VECTOR / 16,
|
Z_X86_OOPS_VECTOR / 16, Z_X86_OOPS_VECTOR, 3);
|
||||||
CONFIG_X86_KERNEL_OOPS_VECTOR, 3);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CONFIG_EXCEPTION_DEBUG
|
#if CONFIG_EXCEPTION_DEBUG
|
||||||
FUNC_NORETURN static void generic_exc_handle(unsigned int vector,
|
FUNC_NORETURN static void generic_exc_handle(unsigned int vector,
|
||||||
|
|
|
@ -13,6 +13,9 @@ LOG_MODULE_DECLARE(os);
|
||||||
void z_x86_exception(z_arch_esf_t *esf)
|
void z_x86_exception(z_arch_esf_t *esf)
|
||||||
{
|
{
|
||||||
switch (esf->vector) {
|
switch (esf->vector) {
|
||||||
|
case Z_X86_OOPS_VECTOR:
|
||||||
|
z_x86_do_kernel_oops(esf);
|
||||||
|
break;
|
||||||
case IV_PAGE_FAULT:
|
case IV_PAGE_FAULT:
|
||||||
z_x86_page_fault_handler(esf);
|
z_x86_page_fault_handler(esf);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -52,6 +52,9 @@ static int allocate_vector(unsigned int priority)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (vector == Z_X86_OOPS_VECTOR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (x86_irq_funcs[vector - IV_IRQS] == NULL) {
|
if (x86_irq_funcs[vector - IV_IRQS] == NULL) {
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,6 +334,11 @@ EXCEPT (20); EXCEPT (21); EXCEPT (22); EXCEPT (23)
|
||||||
EXCEPT (24); EXCEPT (25); EXCEPT (26); EXCEPT (27)
|
EXCEPT (24); EXCEPT (25); EXCEPT (26); EXCEPT (27)
|
||||||
EXCEPT (28); EXCEPT (29); EXCEPT (30); EXCEPT (31)
|
EXCEPT (28); EXCEPT (29); EXCEPT (30); EXCEPT (31)
|
||||||
|
|
||||||
|
/* Vector reserved for handling a kernel oops; treat as an exception
|
||||||
|
* and not an interrupt
|
||||||
|
*/
|
||||||
|
EXCEPT(Z_X86_OOPS_VECTOR);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When we arrive at 'irq' from one of the IRQ(X) stubs,
|
* When we arrive at 'irq' from one of the IRQ(X) stubs,
|
||||||
* we're on the "freshest" IRQ stack and it contains:
|
* we're on the "freshest" IRQ stack and it contains:
|
||||||
|
@ -467,7 +472,7 @@ irq_exit_nested:
|
||||||
|
|
||||||
#define IRQ(nr) vector_ ## nr: pushq $(nr - IV_IRQS); jmp irq
|
#define IRQ(nr) vector_ ## nr: pushq $(nr - IV_IRQS); jmp irq
|
||||||
|
|
||||||
IRQ( 32); IRQ( 33); IRQ( 34); IRQ( 35); IRQ( 36); IRQ( 37); IRQ( 38); IRQ( 39)
|
IRQ( 33); IRQ( 34); IRQ( 35); IRQ( 36); IRQ( 37); IRQ( 38); IRQ( 39)
|
||||||
IRQ( 40); IRQ( 41); IRQ( 42); IRQ( 43); IRQ( 44); IRQ( 45); IRQ( 46); IRQ( 47)
|
IRQ( 40); IRQ( 41); IRQ( 42); IRQ( 43); IRQ( 44); IRQ( 45); IRQ( 46); IRQ( 47)
|
||||||
IRQ( 48); IRQ( 49); IRQ( 50); IRQ( 51); IRQ( 52); IRQ( 53); IRQ( 54); IRQ( 55)
|
IRQ( 48); IRQ( 49); IRQ( 50); IRQ( 51); IRQ( 52); IRQ( 53); IRQ( 54); IRQ( 55)
|
||||||
IRQ( 56); IRQ( 57); IRQ( 58); IRQ( 59); IRQ( 60); IRQ( 61); IRQ( 62); IRQ( 63)
|
IRQ( 56); IRQ( 57); IRQ( 58); IRQ( 59); IRQ( 60); IRQ( 61); IRQ( 62); IRQ( 63)
|
||||||
|
@ -504,6 +509,7 @@ IRQ(248); IRQ(249); IRQ(250); IRQ(251); IRQ(252); IRQ(253); IRQ(254); IRQ(255)
|
||||||
|
|
||||||
#define TRAP 0x8f
|
#define TRAP 0x8f
|
||||||
#define INTR 0x8e
|
#define INTR 0x8e
|
||||||
|
#define USER_INTR 0xee
|
||||||
|
|
||||||
#define IDT(nr, type, ist) \
|
#define IDT(nr, type, ist) \
|
||||||
.word vector_ ## nr, X86_KERNEL_CS; \
|
.word vector_ ## nr, X86_KERNEL_CS; \
|
||||||
|
@ -521,7 +527,9 @@ idt:
|
||||||
IDT( 24, TRAP, 7); IDT( 25, TRAP, 7); IDT( 26, TRAP, 7); IDT( 27, TRAP, 7)
|
IDT( 24, TRAP, 7); IDT( 25, TRAP, 7); IDT( 26, TRAP, 7); IDT( 27, TRAP, 7)
|
||||||
IDT( 28, TRAP, 7); IDT( 29, TRAP, 7); IDT( 30, TRAP, 7); IDT( 31, TRAP, 7)
|
IDT( 28, TRAP, 7); IDT( 29, TRAP, 7); IDT( 30, TRAP, 7); IDT( 31, TRAP, 7)
|
||||||
|
|
||||||
IDT( 32, INTR, 1); IDT( 33, INTR, 1); IDT( 34, INTR, 1); IDT( 35, INTR, 1)
|
/* Oops vector can be invoked from Ring 3 and runs on exception stack */
|
||||||
|
IDT(Z_X86_OOPS_VECTOR, USER_INTR, 7);
|
||||||
|
IDT( 33, INTR, 1); IDT( 34, INTR, 1); IDT( 35, INTR, 1)
|
||||||
IDT( 36, INTR, 1); IDT( 37, INTR, 1); IDT( 38, INTR, 1); IDT( 39, INTR, 1)
|
IDT( 36, INTR, 1); IDT( 37, INTR, 1); IDT( 38, INTR, 1); IDT( 39, INTR, 1)
|
||||||
IDT( 40, INTR, 1); IDT( 41, INTR, 1); IDT( 42, INTR, 1); IDT( 43, INTR, 1)
|
IDT( 40, INTR, 1); IDT( 41, INTR, 1); IDT( 42, INTR, 1); IDT( 43, INTR, 1)
|
||||||
IDT( 44, INTR, 1); IDT( 45, INTR, 1); IDT( 46, INTR, 1); IDT( 47, INTR, 1)
|
IDT( 44, INTR, 1); IDT( 45, INTR, 1); IDT( 46, INTR, 1); IDT( 47, INTR, 1)
|
||||||
|
|
|
@ -108,6 +108,8 @@ void z_x86_apply_mem_domain(struct x86_page_tables *ptables,
|
||||||
|
|
||||||
#endif /* CONFIG_USERSPACE */
|
#endif /* CONFIG_USERSPACE */
|
||||||
|
|
||||||
|
void z_x86_do_kernel_oops(const z_arch_esf_t *esf);
|
||||||
|
|
||||||
#endif /* !_ASMLANGUAGE */
|
#endif /* !_ASMLANGUAGE */
|
||||||
|
|
||||||
#endif /* ZEPHYR_ARCH_X86_INCLUDE_KERNEL_ARCH_FUNC_H_ */
|
#endif /* ZEPHYR_ARCH_X86_INCLUDE_KERNEL_ARCH_FUNC_H_ */
|
||||||
|
|
|
@ -8,6 +8,11 @@
|
||||||
|
|
||||||
#include <generated_dts_board.h>
|
#include <generated_dts_board.h>
|
||||||
|
|
||||||
|
/* Changing this value will require manual changes to exception and IDT setup
|
||||||
|
* in locore.S for intel64
|
||||||
|
*/
|
||||||
|
#define Z_X86_OOPS_VECTOR 32
|
||||||
|
|
||||||
#if !defined(_ASMLANGUAGE)
|
#if !defined(_ASMLANGUAGE)
|
||||||
|
|
||||||
#include <sys/sys_io.h>
|
#include <sys/sys_io.h>
|
||||||
|
|
|
@ -410,17 +410,15 @@ extern void k_float_enable(struct k_thread *thread, unsigned int options);
|
||||||
extern struct task_state_segment _main_tss;
|
extern struct task_state_segment _main_tss;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_X86_KERNEL_OOPS
|
|
||||||
#define ARCH_EXCEPT(reason_p) do { \
|
#define ARCH_EXCEPT(reason_p) do { \
|
||||||
__asm__ volatile( \
|
__asm__ volatile( \
|
||||||
"push %[reason]\n\t" \
|
"push %[reason]\n\t" \
|
||||||
"int %[vector]\n\t" \
|
"int %[vector]\n\t" \
|
||||||
: \
|
: \
|
||||||
: [vector] "i" (CONFIG_X86_KERNEL_OOPS_VECTOR), \
|
: [vector] "i" (Z_X86_OOPS_VECTOR), \
|
||||||
[reason] "i" (reason_p)); \
|
[reason] "i" (reason_p)); \
|
||||||
CODE_UNREACHABLE; \
|
CODE_UNREACHABLE; \
|
||||||
} while (false)
|
} while (false)
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,15 @@ struct x86_esf {
|
||||||
|
|
||||||
typedef struct x86_esf z_arch_esf_t;
|
typedef struct x86_esf z_arch_esf_t;
|
||||||
|
|
||||||
|
#define ARCH_EXCEPT(reason_p) do { \
|
||||||
|
__asm__ volatile( \
|
||||||
|
"movq %[reason], %%rax\n\t" \
|
||||||
|
"int $32\n\t" \
|
||||||
|
: \
|
||||||
|
: [reason] "i" (reason_p)); \
|
||||||
|
CODE_UNREACHABLE; \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
#endif /* _ASMLANGUAGE */
|
#endif /* _ASMLANGUAGE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -10,5 +10,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
|
|
||||||
CONFIG_TEST_USERSPACE=y
|
CONFIG_TEST_USERSPACE=y
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue