diff options
author | Richard Braun <rbraun@sceen.net> | 2017-05-23 20:32:30 +0200 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2017-05-23 20:37:53 +0200 |
commit | a323e51f75ee54c9177c1173a3834dfdc7f63dda (patch) | |
tree | 38ec7524b58c3e65af5e8bb40e978fca254a9d78 /arch/x86/machine/trap.c | |
parent | e4324d5165d9fd57ae1419d33d9a7680b7cc74a4 (diff) |
x86/trap: rework to allow registering trap handlers
Diffstat (limited to 'arch/x86/machine/trap.c')
-rw-r--r-- | arch/x86/machine/trap.c | 145 |
1 files changed, 64 insertions, 81 deletions
diff --git a/arch/x86/machine/trap.c b/arch/x86/machine/trap.c index aa045a9..3de4fd2 100644 --- a/arch/x86/machine/trap.c +++ b/arch/x86/machine/trap.c @@ -19,12 +19,15 @@ * additional configuration and resources to be properly handled. */ +#include <stdint.h> #include <stdio.h> #include <kern/assert.h> +#include <kern/atomic.h> #include <kern/init.h> #include <kern/macros.h> #include <kern/param.h> +#include <kern/spinlock.h> #include <kern/thread.h> #include <machine/cpu.h> #include <machine/lapic.h> @@ -43,7 +46,6 @@ static struct trap_cpu_data trap_cpu_data __percpu; * Type for interrupt service routines and trap handler functions. */ typedef void (*trap_isr_fn_t)(void); -typedef void (*trap_handler_fn_t)(struct trap_frame *); /* * Trap handler flags. @@ -59,42 +61,24 @@ struct trap_handler { }; /* - * Low level interrupt service routines. + * Table of ISR addresses. */ -void trap_isr_default(void); -void trap_isr_divide_error(void); -void trap_isr_debug(void); -void trap_isr_nmi(void); -void trap_isr_breakpoint(void); -void trap_isr_overflow(void); -void trap_isr_bound_range(void); -void trap_isr_invalid_opcode(void); -void trap_isr_device_not_available(void); -void trap_isr_double_fault(void); -void trap_isr_invalid_tss(void); -void trap_isr_segment_not_present(void); -void trap_isr_stack_segment_fault(void); -void trap_isr_general_protection(void); -void trap_isr_page_fault(void); -void trap_isr_math_fault(void); -void trap_isr_alignment_check(void); -void trap_isr_machine_check(void); -void trap_isr_simd_fp_exception(void); -void trap_isr_pic_int7(void); -void trap_isr_pic_int15(void); -void trap_isr_xcall(void); -void trap_isr_thread_schedule(void); -void trap_isr_cpu_halt(void); -void trap_isr_lapic_timer(void); -void trap_isr_lapic_error(void); -void trap_isr_lapic_spurious(void); +extern trap_isr_fn_t trap_isr_table[CPU_IDT_SIZE]; /* * Array of trap handlers. + */ +static struct trap_handler trap_handlers[CPU_IDT_SIZE] __read_mostly; + +/* + * Global trap lock. + * + * This lock is currently only used to serialize concurrent trap handler + * updates. * - * The additional entry is the default entry used for unhandled traps. + * Interrupts must be disabled when holding this lock. */ -static struct trap_handler trap_handlers[CPU_IDT_SIZE + 1] __read_mostly; +static struct spinlock trap_lock; static struct trap_handler * trap_handler_get(unsigned int vector) @@ -107,17 +91,14 @@ static void __init trap_handler_init(struct trap_handler *handler, int flags, trap_handler_fn_t fn) { handler->flags = flags; - handler->fn = fn; + atomic_store(&handler->fn, fn, ATOMIC_RELAXED); } static void __init -trap_install(unsigned int vector, int flags, trap_isr_fn_t isr, - trap_handler_fn_t fn) +trap_install(unsigned int vector, int flags, trap_handler_fn_t fn) { - assert(vector < CPU_IDT_SIZE); - + assert(vector < ARRAY_SIZE(trap_handlers)); trap_handler_init(trap_handler_get(vector), flags, fn); - cpu_idt_set_gate(vector, isr); } static void @@ -175,9 +156,8 @@ trap_double_fault(struct trap_frame *frame) static void __init trap_install_double_fault(void) { - trap_handler_init(trap_handler_get(TRAP_DF), - TRAP_HF_INTR, trap_double_fault); - cpu_idt_set_double_fault(trap_isr_double_fault); + trap_install(TRAP_DF, TRAP_HF_INTR, trap_double_fault); + cpu_idt_set_double_fault(trap_isr_table[TRAP_DF]); } static void @@ -196,58 +176,50 @@ trap_setup(void) { size_t i; - for (i = 0; i < CPU_IDT_SIZE; i++) { - trap_install(i, TRAP_HF_INTR, trap_isr_default, trap_default); + spinlock_init(&trap_lock); + + for (i = 0; i < ARRAY_SIZE(trap_isr_table); i++) { + cpu_idt_set_gate(i, trap_isr_table[i]); + } + + for (i = 0; i < ARRAY_SIZE(trap_handlers); i++) { + trap_install(i, TRAP_HF_INTR, trap_default); } /* Architecture defined traps */ - trap_install(TRAP_DE, 0, trap_isr_divide_error, trap_default); - trap_install(TRAP_DB, 0, trap_isr_debug, trap_default); - trap_install(TRAP_NMI, TRAP_HF_INTR, trap_isr_nmi, trap_default); - trap_install(TRAP_BP, 0, trap_isr_breakpoint, trap_default); - trap_install(TRAP_OF, 0, trap_isr_overflow, trap_default); - trap_install(TRAP_BR, 0, trap_isr_bound_range, trap_default); - trap_install(TRAP_UD, 0, trap_isr_invalid_opcode, trap_default); - trap_install(TRAP_NM, 0, trap_isr_device_not_available, trap_default); + trap_install(TRAP_DE, 0, trap_default); + trap_install(TRAP_DB, 0, trap_default); + trap_install(TRAP_NMI, TRAP_HF_INTR, trap_default); + trap_install(TRAP_BP, 0, trap_default); + trap_install(TRAP_OF, 0, trap_default); + trap_install(TRAP_BR, 0, trap_default); + trap_install(TRAP_UD, 0, trap_default); + trap_install(TRAP_NM, 0, trap_default); trap_install_double_fault(); - trap_install(TRAP_TS, 0, trap_isr_invalid_tss, trap_default); - trap_install(TRAP_NP, 0, trap_isr_segment_not_present, trap_default); - trap_install(TRAP_SS, 0, trap_isr_stack_segment_fault, trap_default); - trap_install(TRAP_GP, 0, trap_isr_general_protection, trap_default); - trap_install(TRAP_PF, 0, trap_isr_page_fault, trap_default); - trap_install(TRAP_MF, 0, trap_isr_math_fault, trap_default); - trap_install(TRAP_AC, 0, trap_isr_alignment_check, trap_default); - trap_install(TRAP_MC, TRAP_HF_INTR, trap_isr_machine_check, trap_default); - trap_install(TRAP_XM, 0, trap_isr_simd_fp_exception, trap_default); - - /* Basic PIC support */ - trap_install(TRAP_PIC_BASE + 7, TRAP_HF_INTR, - trap_isr_pic_int7, pic_spurious_intr); - trap_install(TRAP_PIC_BASE + 15, TRAP_HF_INTR, - trap_isr_pic_int15, pic_spurious_intr); + trap_install(TRAP_TS, 0, trap_default); + trap_install(TRAP_NP, 0, trap_default); + trap_install(TRAP_SS, 0, trap_default); + trap_install(TRAP_GP, 0, trap_default); + trap_install(TRAP_PF, 0, trap_default); + trap_install(TRAP_MF, 0, trap_default); + trap_install(TRAP_AC, 0, trap_default); + trap_install(TRAP_MC, TRAP_HF_INTR, trap_default); + trap_install(TRAP_XM, 0, trap_default); /* System defined traps */ - trap_install(TRAP_XCALL, TRAP_HF_INTR, - trap_isr_xcall, cpu_xcall_intr); - trap_install(TRAP_THREAD_SCHEDULE, TRAP_HF_INTR, - trap_isr_thread_schedule, cpu_thread_schedule_intr); - trap_install(TRAP_CPU_HALT, TRAP_HF_INTR, - trap_isr_cpu_halt, cpu_halt_intr); - trap_install(TRAP_LAPIC_TIMER, TRAP_HF_INTR, - trap_isr_lapic_timer, lapic_timer_intr); - trap_install(TRAP_LAPIC_ERROR, TRAP_HF_INTR, - trap_isr_lapic_error, lapic_error_intr); - trap_install(TRAP_LAPIC_SPURIOUS, TRAP_HF_INTR, - trap_isr_lapic_spurious, lapic_spurious_intr); - - trap_handler_init(trap_handler_get(TRAP_DEFAULT), - TRAP_HF_INTR, trap_default); + trap_install(TRAP_XCALL, TRAP_HF_INTR, cpu_xcall_intr); + trap_install(TRAP_THREAD_SCHEDULE, TRAP_HF_INTR, cpu_thread_schedule_intr); + trap_install(TRAP_CPU_HALT, TRAP_HF_INTR, cpu_halt_intr); + trap_install(TRAP_LAPIC_TIMER, TRAP_HF_INTR, lapic_timer_intr); + trap_install(TRAP_LAPIC_ERROR, TRAP_HF_INTR, lapic_error_intr); + trap_install(TRAP_LAPIC_SPURIOUS, TRAP_HF_INTR, lapic_spurious_intr); } void trap_main(struct trap_frame *frame) { struct trap_handler *handler; + trap_handler_fn_t fn; assert(!cpu_intr_enabled()); @@ -257,7 +229,8 @@ trap_main(struct trap_frame *frame) thread_intr_enter(); } - handler->fn(frame); + fn = atomic_load(&handler->fn, ATOMIC_RELAXED); + fn(frame); if (handler->flags & TRAP_HF_INTR) { thread_intr_leave(); @@ -266,6 +239,16 @@ trap_main(struct trap_frame *frame) assert(!cpu_intr_enabled()); } +void +trap_register(unsigned int vector, trap_handler_fn_t handler_fn) +{ + unsigned long flags; + + spinlock_lock_intr_save(&trap_lock, &flags); + trap_install(vector, TRAP_HF_INTR, handler_fn); + spinlock_unlock_intr_restore(&trap_lock, flags); +} + #ifdef __LP64__ void |