diff --git a/arch/x86/entry.S b/arch/x86/entry.S index 7e7636a7..d2593d45 100644 --- a/arch/x86/entry.S +++ b/arch/x86/entry.S @@ -92,6 +92,23 @@ ENTRY(asm_interrupt_handler_\sym) END_FUNC(asm_interrupt_handler_\sym) .endm +ENTRY(handle_exception) + cld + SAVE_ALL_REGS + + mov %_ASM_SP, %_ASM_DI + call do_exception + + RESTORE_ALL_REGS + + add $8, %_ASM_SP + + enter_to_usermode + IRET +END_FUNC(handle_exception) + +.align PAGE_SIZE +GLOBAL(exception_handlers) exception_handler DE X86_EX_DE 0 exception_handler DB X86_EX_DB 0 exception_handler NMI X86_EX_NMI 0 @@ -114,29 +131,40 @@ exception_handler MC X86_EX_MC 0 exception_handler XM X86_EX_XM 0 exception_handler VE X86_EX_VE 0 exception_handler SE X86_EX_SE 1 +GLOBAL(end_exception_handlers) -ENTRY(handle_exception) - cld - SAVE_ALL_REGS - - mov %_ASM_SP, %_ASM_DI - call do_exception - - RESTORE_ALL_REGS - - add $8, %_ASM_SP - - enter_to_usermode - IRET -END_FUNC(handle_exception) - +GLOBAL(interrupt_handlers) interrupt_handler timer timer_interrupt_handler interrupt_handler uart uart_interrupt_handler interrupt_handler keyboard keyboard_interrupt_handler #ifdef KTF_ACPICA interrupt_handler acpi acpi_interrupt_handler #endif +GLOBAL(end_interrupt_handlers) + +.align PAGE_SIZE +ENTRY(syscall_exit) + POPF + + /* Save exit code to return value register (AX) */ + mov %_ASM_SI, cpu_regs_ax(%_ASM_SP) + RESTORE_ALL_REGS + ret +END_FUNC(syscall_exit) + +ENTRY(terminate_user_task) + SWITCH_STACK + POPF + + movl $-EFAULT, cpu_regs_ax(%_ASM_SP) + RESTORE_ALL_REGS + + ret +END_FUNC(terminate_user_task) + +.align PAGE_SIZE +GLOBAL(usermode_helpers) ENTRY(enter_usermode) /* FIXME: Add 32-bit support */ @@ -145,10 +173,9 @@ ENTRY(enter_usermode) PUSHF /* Save stack pointer onto per-cpu */ - mov %_ASM_SP, %gs:usermode_private + mov %_ASM_DX, %gs:(usermode_private) - /* Move to user stack */ - mov %_ASM_DX, %_ASM_SP + syscall_to_usermode /* SS + SP */ push $__USER_DS @@ -162,32 +189,9 @@ ENTRY(enter_usermode) /* CS + IP */ push $__USER_CS push $usermode_stub - - enter_to_usermode IRET END_FUNC(enter_usermode) -ENTRY(syscall_exit) - POPF - - /* Save exit code to return value register (AX) */ - mov %_ASM_SI, cpu_regs_ax(%_ASM_SP) - RESTORE_ALL_REGS - - ret -END_FUNC(syscall_exit) - -ENTRY(terminate_user_task) - SWITCH_STACK - POPF - - movl $-EFAULT, cpu_regs_ax(%_ASM_SP) - RESTORE_ALL_REGS - - ret -END_FUNC(terminate_user_task) - -.align PAGE_SIZE ENTRY(syscall_handler_entry) SAVE_CALLEE_SAVED_REGS syscall_from_usermode @@ -209,6 +213,7 @@ ENTRY(syscall_handler_entry) RESTORE_CALLEE_SAVED_REGS SYSRET END_FUNC(syscall_handler_entry) +GLOBAL(end_usermode_helpers) SECTION(.text.user, "ax", 16) ENTRY(usermode_stub) diff --git a/arch/x86/pagetables.c b/arch/x86/pagetables.c index fe03ec60..289a907f 100644 --- a/arch/x86/pagetables.c +++ b/arch/x86/pagetables.c @@ -30,7 +30,7 @@ #include #include -cr3_t cr3; +cr3_t __aligned(PAGE_SIZE) cr3; cr3_t user_cr3; static inline const char *dump_pte_flags(char *buf, size_t size, pte_t pte) { diff --git a/common/usermode.c b/common/usermode.c index a214d64a..7c97937b 100644 --- a/common/usermode.c +++ b/common/usermode.c @@ -28,6 +28,10 @@ #include #include +extern char exception_handlers[], end_exception_handlers[]; +extern char interrupt_handlers[], end_interrupt_handlers[]; +extern char usermode_helpers[], end_usermode_helpers[]; + long syscall_handler(long syscall_nr, long arg1, long arg2, long arg3, long arg4, long arg5) { switch (syscall_nr) { @@ -89,8 +93,17 @@ static void init_syscall(void) { void init_usermode(percpu_t *percpu) { vmap_user_4k(&cr3, virt_to_mfn(&cr3), L1_PROT); - vmap_user_4k(&enter_usermode, virt_to_mfn(&enter_usermode), L1_PROT); - vmap_user_4k(&syscall_handler_entry, virt_to_mfn(&syscall_handler_entry), L1_PROT); + vmap_user_4k(&user_cr3, virt_to_mfn(&user_cr3), L1_PROT); + + BUG_ON(end_exception_handlers - exception_handlers > (long) PAGE_SIZE); + vmap_user_4k(exception_handlers, virt_to_mfn(exception_handlers), L1_PROT); + + BUG_ON(end_interrupt_handlers - interrupt_handlers > (long) PAGE_SIZE); + vmap_user_4k(interrupt_handlers, virt_to_mfn(interrupt_handlers), L1_PROT); + + BUG_ON(end_usermode_helpers - usermode_helpers > (long) PAGE_SIZE); + vmap_user_4k(usermode_helpers, virt_to_mfn(usermode_helpers), L1_PROT); + init_syscall(); }