1 #include "x86/msr.h" 2 #include "x86/processor.h" 3 #include "x86/apic-defs.h" 4 #include "x86/apic.h" 5 #include "x86/desc.h" 6 #include "x86/isr.h" 7 #include "alloc.h" 8 #include "setjmp.h" 9 #include "usermode.h" 10 11 #include "libcflat.h" 12 #include <stdint.h> 13 14 #define USERMODE_STACK_SIZE 0x2000 15 #define RET_TO_KERNEL_IRQ 0x20 16 17 static jmp_buf jmpbuf; 18 19 static void restore_exec_to_jmpbuf(void) 20 { 21 longjmp(jmpbuf, 1); 22 } 23 24 static void restore_exec_to_jmpbuf_exception_handler(struct ex_regs *regs) 25 { 26 /* longjmp must happen after iret, so do not do it now. */ 27 regs->rip = (unsigned long)&restore_exec_to_jmpbuf; 28 regs->cs = KERNEL_CS; 29 #ifdef __x86_64__ 30 regs->ss = KERNEL_DS; 31 #endif 32 } 33 34 uint64_t run_in_user(usermode_func func, unsigned int fault_vector, 35 uint64_t arg1, uint64_t arg2, uint64_t arg3, 36 uint64_t arg4, bool *raised_vector) 37 { 38 extern char ret_to_kernel; 39 volatile uint64_t rax = 0; 40 static unsigned char user_stack[USERMODE_STACK_SIZE]; 41 handler old_ex; 42 43 *raised_vector = 0; 44 set_idt_entry(RET_TO_KERNEL_IRQ, &ret_to_kernel, 3); 45 old_ex = handle_exception(fault_vector, 46 restore_exec_to_jmpbuf_exception_handler); 47 48 if (setjmp(jmpbuf) != 0) { 49 handle_exception(fault_vector, old_ex); 50 *raised_vector = 1; 51 return 0; 52 } 53 54 asm volatile ( 55 /* Prepare kernel SP for exception handlers */ 56 "mov %%rsp, %[rsp0]\n\t" 57 /* Load user_ds to DS and ES */ 58 "mov %[user_ds], %%ax\n\t" 59 "mov %%ax, %%ds\n\t" 60 "mov %%ax, %%es\n\t" 61 /* IRET into user mode */ 62 "pushq %[user_ds]\n\t" 63 "pushq %[user_stack_top]\n\t" 64 "pushfq\n\t" 65 "pushq %[user_cs]\n\t" 66 "lea user_mode(%%rip), %%rax\n\t" 67 "pushq %%rax\n\t" 68 "iretq\n" 69 70 "user_mode:\n\t" 71 /* Back up volatile registers before invoking func */ 72 "push %%rcx\n\t" 73 "push %%rdx\n\t" 74 "push %%rdi\n\t" 75 "push %%rsi\n\t" 76 "push %%r8\n\t" 77 "push %%r9\n\t" 78 "push %%r10\n\t" 79 "push %%r11\n\t" 80 /* Call user mode function */ 81 "mov %[arg1], %%rdi\n\t" 82 "mov %[arg2], %%rsi\n\t" 83 "mov %[arg3], %%rdx\n\t" 84 "mov %[arg4], %%rcx\n\t" 85 "call *%[func]\n\t" 86 /* Restore registers */ 87 "pop %%r11\n\t" 88 "pop %%r10\n\t" 89 "pop %%r9\n\t" 90 "pop %%r8\n\t" 91 "pop %%rsi\n\t" 92 "pop %%rdi\n\t" 93 "pop %%rdx\n\t" 94 "pop %%rcx\n\t" 95 /* Return to kernel via system call */ 96 "int %[kernel_entry_vector]\n\t" 97 /* Kernel Mode */ 98 "ret_to_kernel:\n\t" 99 "mov %[rsp0], %%rsp\n\t" 100 #ifdef __x86_64__ 101 /* 102 * Restore SS, as the CPU loads SS with a NULL segment 103 * if handling an interrupt/exception changes the CPL. 104 */ 105 "mov %[kernel_ds], %%ss\n\t" 106 #endif 107 : 108 "+a"(rax), 109 [rsp0]"=m"(tss[0].rsp0) 110 : 111 [arg1]"m"(arg1), 112 [arg2]"m"(arg2), 113 [arg3]"m"(arg3), 114 [arg4]"m"(arg4), 115 [func]"m"(func), 116 [user_ds]"i"(USER_DS), 117 [user_cs]"i"(USER_CS), 118 [kernel_ds]"rm"(KERNEL_DS), 119 [user_stack_top]"r"(user_stack + 120 sizeof(user_stack)), 121 [kernel_entry_vector]"i"(RET_TO_KERNEL_IRQ)); 122 123 handle_exception(fault_vector, old_ex); 124 125 return rax; 126 } 127