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 } 30 31 uint64_t run_in_user(usermode_func func, unsigned int fault_vector, 32 uint64_t arg1, uint64_t arg2, uint64_t arg3, 33 uint64_t arg4, bool *raised_vector) 34 { 35 extern char ret_to_kernel; 36 uint64_t rax = 0; 37 static unsigned char user_stack[USERMODE_STACK_SIZE]; 38 39 *raised_vector = 0; 40 set_idt_entry(RET_TO_KERNEL_IRQ, &ret_to_kernel, 3); 41 handle_exception(fault_vector, 42 restore_exec_to_jmpbuf_exception_handler); 43 44 if (setjmp(jmpbuf) != 0) { 45 *raised_vector = 1; 46 return 0; 47 } 48 49 asm volatile ( 50 /* Prepare kernel SP for exception handlers */ 51 "mov %%rsp, %[rsp0]\n\t" 52 /* Load user_ds to DS and ES */ 53 "mov %[user_ds], %%ax\n\t" 54 "mov %%ax, %%ds\n\t" 55 "mov %%ax, %%es\n\t" 56 /* IRET into user mode */ 57 "pushq %[user_ds]\n\t" 58 "pushq %[user_stack_top]\n\t" 59 "pushfq\n\t" 60 "pushq %[user_cs]\n\t" 61 "lea user_mode(%%rip), %%rdx\n\t" 62 "pushq %%rdx\n\t" 63 "iretq\n" 64 65 "user_mode:\n\t" 66 /* Back up registers before invoking func */ 67 "push %%rbx\n\t" 68 "push %%rcx\n\t" 69 "push %%rdx\n\t" 70 "push %%r8\n\t" 71 "push %%r9\n\t" 72 "push %%r10\n\t" 73 "push %%r11\n\t" 74 "push %%rdi\n\t" 75 "push %%rsi\n\t" 76 /* Call user mode function */ 77 "mov %[arg1], %%rdi\n\t" 78 "mov %[arg2], %%rsi\n\t" 79 "mov %[arg3], %%rdx\n\t" 80 "mov %[arg4], %%rcx\n\t" 81 "call *%[func]\n\t" 82 /* Restore registers */ 83 "pop %%rsi\n\t" 84 "pop %%rdi\n\t" 85 "pop %%r11\n\t" 86 "pop %%r10\n\t" 87 "pop %%r9\n\t" 88 "pop %%r8\n\t" 89 "pop %%rdx\n\t" 90 "pop %%rcx\n\t" 91 "pop %%rbx\n\t" 92 /* Return to kernel via system call */ 93 "int %[kernel_entry_vector]\n\t" 94 /* Kernel Mode */ 95 "ret_to_kernel:\n\t" 96 "mov %[rsp0], %%rsp\n\t" 97 : 98 "+a"(rax), 99 [rsp0]"=m"(tss[0].rsp0) 100 : 101 [arg1]"m"(arg1), 102 [arg2]"m"(arg2), 103 [arg3]"m"(arg3), 104 [arg4]"m"(arg4), 105 [func]"m"(func), 106 [user_ds]"i"(USER_DS), 107 [user_cs]"i"(USER_CS), 108 [user_stack_top]"r"(user_stack + 109 sizeof(user_stack)), 110 [kernel_entry_vector]"i"(RET_TO_KERNEL_IRQ) 111 : 112 "rsi", "rdi", "rcx", "rdx"); 113 114 return rax; 115 } 116