xref: /kvm-unit-tests/lib/x86/usermode.c (revision f1dcfd54130ca2b1851d46dffd7ffadbe5eb4a3b)
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