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 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

View file

@ -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

View file

@ -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

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); 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);
}

View file

@ -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

View file

@ -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,

View file

@ -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;

View file

@ -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;
} }

View file

@ -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)

View file

@ -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_ */

View file

@ -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>

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; 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
} }

View file

@ -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 */
/* /*

View file

@ -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