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:
Andrew Boie 2019-12-18 14:12:54 -08:00 committed by Anas Nashif
commit 077b587447
14 changed files with 63 additions and 50 deletions

View file

@ -58,7 +58,7 @@ config MAX_IRQ_LINES
config IRQ_OFFLOAD_VECTOR
int "IDT vector to use for IRQ offload"
default 32
default 33
range 32 255
depends on IRQ_OFFLOAD

View file

@ -197,22 +197,6 @@ config CACHE_FLUSHING
cache must be selected as well. By default, that mechanism is discovered at
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
int "Number of dynamic interrupt stubs"
depends on DYNAMIC_INTERRUPTS

View file

@ -42,7 +42,7 @@ config X86_EXCEPTION_STACK_TRACE
config SCHED_IPI_VECTOR
int "IDT vector to use for scheduler IPI"
default 33
default 34
range 33 255
depends on SMP

View file

@ -342,3 +342,28 @@ void z_x86_page_fault_handler(z_arch_esf_t *esf)
z_x86_fatal_error(K_ERR_CPU_EXCEPTION, esf);
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);
}

View file

@ -25,7 +25,7 @@
GTEXT(_kernel_oops_handler)
/* 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 */
KPTI_IRET
#if CONFIG_X86_KERNEL_OOPS
SECTION_FUNC(TEXT, _kernel_oops_handler)
push $0 /* dummy error code */
push $z_do_kernel_oops
push $z_x86_do_kernel_oops
jmp _exception_enter
#endif

View file

@ -50,30 +50,9 @@ void arch_syscall_oops(void *ssf_ptr)
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);
NANO_CPU_INT_REGISTER(_kernel_oops_handler, NANO_SOFT_IRQ,
CONFIG_X86_KERNEL_OOPS_VECTOR / 16,
CONFIG_X86_KERNEL_OOPS_VECTOR, 3);
#endif
Z_X86_OOPS_VECTOR / 16, Z_X86_OOPS_VECTOR, 3);
#if CONFIG_EXCEPTION_DEBUG
FUNC_NORETURN static void generic_exc_handle(unsigned int vector,

View file

@ -13,6 +13,9 @@ LOG_MODULE_DECLARE(os);
void z_x86_exception(z_arch_esf_t *esf)
{
switch (esf->vector) {
case Z_X86_OOPS_VECTOR:
z_x86_do_kernel_oops(esf);
break;
case IV_PAGE_FAULT:
z_x86_page_fault_handler(esf);
break;

View file

@ -52,6 +52,9 @@ static int allocate_vector(unsigned int priority)
continue;
}
#endif
if (vector == Z_X86_OOPS_VECTOR) {
continue;
}
if (x86_irq_funcs[vector - IV_IRQS] == NULL) {
return vector;
}

View file

@ -334,6 +334,11 @@ EXCEPT (20); EXCEPT (21); EXCEPT (22); EXCEPT (23)
EXCEPT (24); EXCEPT (25); EXCEPT (26); EXCEPT (27)
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,
* 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
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( 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)
@ -504,6 +509,7 @@ IRQ(248); IRQ(249); IRQ(250); IRQ(251); IRQ(252); IRQ(253); IRQ(254); IRQ(255)
#define TRAP 0x8f
#define INTR 0x8e
#define USER_INTR 0xee
#define IDT(nr, type, ist) \
.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( 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( 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)

View file

@ -108,6 +108,8 @@ void z_x86_apply_mem_domain(struct x86_page_tables *ptables,
#endif /* CONFIG_USERSPACE */
void z_x86_do_kernel_oops(const z_arch_esf_t *esf);
#endif /* !_ASMLANGUAGE */
#endif /* ZEPHYR_ARCH_X86_INCLUDE_KERNEL_ARCH_FUNC_H_ */

View file

@ -8,6 +8,11 @@
#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)
#include <sys/sys_io.h>

View file

@ -410,17 +410,15 @@ extern void k_float_enable(struct k_thread *thread, unsigned int options);
extern struct task_state_segment _main_tss;
#endif
#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), \
: [vector] "i" (Z_X86_OOPS_VECTOR), \
[reason] "i" (reason_p)); \
CODE_UNREACHABLE; \
} while (false)
#endif
#ifdef __cplusplus
}

View file

@ -59,6 +59,15 @@ struct x86_esf {
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 */
/*

View file

@ -10,5 +10,4 @@ CONFIG_PWM=y
CONFIG_SERIAL=y
CONFIG_SPI=y
CONFIG_WATCHDOG=y
CONFIG_X86_KERNEL_OOPS=n
CONFIG_TEST_USERSPACE=y