11c93387eSArbel Moshe #include "x86/msr.h" 21c93387eSArbel Moshe #include "x86/processor.h" 31c93387eSArbel Moshe #include "x86/apic-defs.h" 41c93387eSArbel Moshe #include "x86/apic.h" 51c93387eSArbel Moshe #include "x86/desc.h" 61c93387eSArbel Moshe #include "x86/isr.h" 71c93387eSArbel Moshe #include "alloc.h" 81c93387eSArbel Moshe #include "setjmp.h" 91c93387eSArbel Moshe #include "usermode.h" 101c93387eSArbel Moshe 111c93387eSArbel Moshe #include "libcflat.h" 121c93387eSArbel Moshe #include <stdint.h> 131c93387eSArbel Moshe 141c93387eSArbel Moshe #define USERMODE_STACK_SIZE 0x2000 151c93387eSArbel Moshe #define RET_TO_KERNEL_IRQ 0x20 161c93387eSArbel Moshe 17e743729cSVitaly Kuznetsov static jmp_buf jmpbuf; 181c93387eSArbel Moshe 191c93387eSArbel Moshe static void restore_exec_to_jmpbuf(void) 201c93387eSArbel Moshe { 211c93387eSArbel Moshe longjmp(jmpbuf, 1); 221c93387eSArbel Moshe } 231c93387eSArbel Moshe 241c93387eSArbel Moshe static void restore_exec_to_jmpbuf_exception_handler(struct ex_regs *regs) 251c93387eSArbel Moshe { 261c93387eSArbel Moshe /* longjmp must happen after iret, so do not do it now. */ 271c93387eSArbel Moshe regs->rip = (unsigned long)&restore_exec_to_jmpbuf; 281c93387eSArbel Moshe regs->cs = KERNEL_CS; 29*663f9e44SAaron Lewis #ifdef __x86_64__ 30*663f9e44SAaron Lewis regs->ss = KERNEL_DS; 31*663f9e44SAaron Lewis #endif 321c93387eSArbel Moshe } 331c93387eSArbel Moshe 341c93387eSArbel Moshe uint64_t run_in_user(usermode_func func, unsigned int fault_vector, 351c93387eSArbel Moshe uint64_t arg1, uint64_t arg2, uint64_t arg3, 361c93387eSArbel Moshe uint64_t arg4, bool *raised_vector) 371c93387eSArbel Moshe { 381c93387eSArbel Moshe extern char ret_to_kernel; 391c93387eSArbel Moshe uint64_t rax = 0; 401c93387eSArbel Moshe static unsigned char user_stack[USERMODE_STACK_SIZE]; 411c93387eSArbel Moshe 421c93387eSArbel Moshe *raised_vector = 0; 431c93387eSArbel Moshe set_idt_entry(RET_TO_KERNEL_IRQ, &ret_to_kernel, 3); 441c93387eSArbel Moshe handle_exception(fault_vector, 451c93387eSArbel Moshe restore_exec_to_jmpbuf_exception_handler); 461c93387eSArbel Moshe 471c93387eSArbel Moshe if (setjmp(jmpbuf) != 0) { 481c93387eSArbel Moshe *raised_vector = 1; 491c93387eSArbel Moshe return 0; 501c93387eSArbel Moshe } 511c93387eSArbel Moshe 521c93387eSArbel Moshe asm volatile ( 538cd86535SPaolo Bonzini /* Prepare kernel SP for exception handlers */ 548cd86535SPaolo Bonzini "mov %%rsp, %[rsp0]\n\t" 551c93387eSArbel Moshe /* Load user_ds to DS and ES */ 561c93387eSArbel Moshe "mov %[user_ds], %%ax\n\t" 571c93387eSArbel Moshe "mov %%ax, %%ds\n\t" 581c93387eSArbel Moshe "mov %%ax, %%es\n\t" 591c93387eSArbel Moshe /* IRET into user mode */ 601c93387eSArbel Moshe "pushq %[user_ds]\n\t" 611c93387eSArbel Moshe "pushq %[user_stack_top]\n\t" 621c93387eSArbel Moshe "pushfq\n\t" 631c93387eSArbel Moshe "pushq %[user_cs]\n\t" 641c93387eSArbel Moshe "pushq $user_mode\n\t" 651c93387eSArbel Moshe "iretq\n" 661c93387eSArbel Moshe 671c93387eSArbel Moshe "user_mode:\n\t" 681c93387eSArbel Moshe /* Back up registers before invoking func */ 691c93387eSArbel Moshe "push %%rbx\n\t" 701c93387eSArbel Moshe "push %%rcx\n\t" 711c93387eSArbel Moshe "push %%rdx\n\t" 721c93387eSArbel Moshe "push %%r8\n\t" 731c93387eSArbel Moshe "push %%r9\n\t" 741c93387eSArbel Moshe "push %%r10\n\t" 751c93387eSArbel Moshe "push %%r11\n\t" 761c93387eSArbel Moshe "push %%rdi\n\t" 771c93387eSArbel Moshe "push %%rsi\n\t" 781c93387eSArbel Moshe /* Call user mode function */ 791c93387eSArbel Moshe "mov %[arg1], %%rdi\n\t" 801c93387eSArbel Moshe "mov %[arg2], %%rsi\n\t" 811c93387eSArbel Moshe "mov %[arg3], %%rdx\n\t" 821c93387eSArbel Moshe "mov %[arg4], %%rcx\n\t" 83ebc1b903SPaolo Bonzini "call *%[func]\n\t" 841c93387eSArbel Moshe /* Restore registers */ 851c93387eSArbel Moshe "pop %%rsi\n\t" 861c93387eSArbel Moshe "pop %%rdi\n\t" 871c93387eSArbel Moshe "pop %%r11\n\t" 881c93387eSArbel Moshe "pop %%r10\n\t" 891c93387eSArbel Moshe "pop %%r9\n\t" 901c93387eSArbel Moshe "pop %%r8\n\t" 911c93387eSArbel Moshe "pop %%rdx\n\t" 921c93387eSArbel Moshe "pop %%rcx\n\t" 931c93387eSArbel Moshe "pop %%rbx\n\t" 941c93387eSArbel Moshe /* Return to kernel via system call */ 951c93387eSArbel Moshe "int %[kernel_entry_vector]\n\t" 961c93387eSArbel Moshe /* Kernel Mode */ 971c93387eSArbel Moshe "ret_to_kernel:\n\t" 988cd86535SPaolo Bonzini "mov %[rsp0], %%rsp\n\t" 991c93387eSArbel Moshe : 1008cd86535SPaolo Bonzini "+a"(rax), 101dbd38004SZixuan Wang [rsp0]"=m"(tss[0].rsp0) 1021c93387eSArbel Moshe : 1031c93387eSArbel Moshe [arg1]"m"(arg1), 1041c93387eSArbel Moshe [arg2]"m"(arg2), 1051c93387eSArbel Moshe [arg3]"m"(arg3), 1061c93387eSArbel Moshe [arg4]"m"(arg4), 1071c93387eSArbel Moshe [func]"m"(func), 1081c93387eSArbel Moshe [user_ds]"i"(USER_DS), 1091c93387eSArbel Moshe [user_cs]"i"(USER_CS), 1101c93387eSArbel Moshe [user_stack_top]"r"(user_stack + 1111c93387eSArbel Moshe sizeof(user_stack)), 1121c93387eSArbel Moshe [kernel_entry_vector]"i"(RET_TO_KERNEL_IRQ) 1131c93387eSArbel Moshe : 1141c93387eSArbel Moshe "rsi", "rdi", "rcx", "rdx"); 1151c93387eSArbel Moshe 1161c93387eSArbel Moshe return rax; 1171c93387eSArbel Moshe } 118