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