xref: /kvm-unit-tests/x86/umip.c (revision 92a6c9b95ab10eba66bff3ff44476ab0c015b276)
1728e71eeSPaolo Bonzini 
2728e71eeSPaolo Bonzini #include "libcflat.h"
3728e71eeSPaolo Bonzini #include "desc.h"
4728e71eeSPaolo Bonzini #include "processor.h"
5728e71eeSPaolo Bonzini 
6728e71eeSPaolo Bonzini 
7728e71eeSPaolo Bonzini /* GP handler to skip over faulting instructions */
8728e71eeSPaolo Bonzini 
9728e71eeSPaolo Bonzini static unsigned long expected_rip;
10728e71eeSPaolo Bonzini static int skip_count;
11728e71eeSPaolo Bonzini static volatile int gp_count;
12728e71eeSPaolo Bonzini 
gp_handler(struct ex_regs * regs)13b29804b8SThomas Huth static void gp_handler(struct ex_regs *regs)
14728e71eeSPaolo Bonzini {
15728e71eeSPaolo Bonzini     if (regs->rip == expected_rip) {
16728e71eeSPaolo Bonzini         gp_count++;
17728e71eeSPaolo Bonzini         regs->rip += skip_count;
18728e71eeSPaolo Bonzini     } else {
19728e71eeSPaolo Bonzini         unhandled_exception(regs, false);
20728e71eeSPaolo Bonzini     }
21728e71eeSPaolo Bonzini }
22728e71eeSPaolo Bonzini 
23*7bf8144eSZixuan Wang #ifndef __x86_64__
24*7bf8144eSZixuan Wang #define GP_ASM_MOVE_TO_RIP                  \
25*7bf8144eSZixuan Wang 	"mov" W " $1f, %[expected_rip]\n\t"
26*7bf8144eSZixuan Wang #else
27*7bf8144eSZixuan Wang #define GP_ASM_MOVE_TO_RIP                  \
28*7bf8144eSZixuan Wang 	"pushq %%rax\n\t"                   \
29*7bf8144eSZixuan Wang 	"lea 1f(%%rip), %%rax\n\t"          \
30*7bf8144eSZixuan Wang 	"mov %%rax, %[expected_rip]\n\t"    \
31*7bf8144eSZixuan Wang 	"popq %%rax\n\t"
32*7bf8144eSZixuan Wang #endif
33728e71eeSPaolo Bonzini 
34728e71eeSPaolo Bonzini #define GP_ASM(stmt, in, clobber)                  \
3549efa0e0SThomas Huth     asm volatile (                                 \
36*7bf8144eSZixuan Wang 	  GP_ASM_MOVE_TO_RIP                       \
37728e71eeSPaolo Bonzini           "movl $2f-1f, %[skip_count]\n\t"         \
38728e71eeSPaolo Bonzini           "1: " stmt "\n\t"                        \
39728e71eeSPaolo Bonzini           "2: "                                    \
40728e71eeSPaolo Bonzini           : [expected_rip] "=m" (expected_rip),    \
41728e71eeSPaolo Bonzini             [skip_count] "=m" (skip_count)         \
42728e71eeSPaolo Bonzini           : in : clobber)
43728e71eeSPaolo Bonzini 
do_smsw(void)44728e71eeSPaolo Bonzini static void do_smsw(void)
45728e71eeSPaolo Bonzini {
46728e71eeSPaolo Bonzini     gp_count = 0;
47728e71eeSPaolo Bonzini     GP_ASM("smsw %%ax", , "eax");
48728e71eeSPaolo Bonzini }
49728e71eeSPaolo Bonzini 
do_sldt(void)50728e71eeSPaolo Bonzini static void do_sldt(void)
51728e71eeSPaolo Bonzini {
52728e71eeSPaolo Bonzini     gp_count = 0;
53728e71eeSPaolo Bonzini     GP_ASM("sldt %%ax", , "eax");
54728e71eeSPaolo Bonzini }
55728e71eeSPaolo Bonzini 
do_str(void)56728e71eeSPaolo Bonzini static void do_str(void)
57728e71eeSPaolo Bonzini {
58728e71eeSPaolo Bonzini     gp_count = 0;
59728e71eeSPaolo Bonzini     GP_ASM("str %%ax", , "eax");
60728e71eeSPaolo Bonzini }
61728e71eeSPaolo Bonzini 
do_sgdt(void)62728e71eeSPaolo Bonzini static void do_sgdt(void)
63728e71eeSPaolo Bonzini {
64728e71eeSPaolo Bonzini     struct descriptor_table_ptr dt;
65728e71eeSPaolo Bonzini     gp_count = 0;
66728e71eeSPaolo Bonzini     GP_ASM("sgdt %[dt]", [dt]"m"(dt), );
67728e71eeSPaolo Bonzini }
68728e71eeSPaolo Bonzini 
do_sidt(void)69728e71eeSPaolo Bonzini static void do_sidt(void)
70728e71eeSPaolo Bonzini {
71728e71eeSPaolo Bonzini     struct descriptor_table_ptr dt;
72728e71eeSPaolo Bonzini     gp_count = 0;
73728e71eeSPaolo Bonzini     GP_ASM("sidt %[dt]", [dt]"m"(dt), );
74728e71eeSPaolo Bonzini }
75728e71eeSPaolo Bonzini 
do_movcr(void)76728e71eeSPaolo Bonzini static void do_movcr(void)
77728e71eeSPaolo Bonzini {
78728e71eeSPaolo Bonzini     gp_count = 0;
79728e71eeSPaolo Bonzini     GP_ASM("mov %%cr0, %%" R "ax", , "eax");
80728e71eeSPaolo Bonzini }
81728e71eeSPaolo Bonzini 
test_umip_nogp(const char * msg)8249024be1SPeter Xu static void test_umip_nogp(const char *msg)
83728e71eeSPaolo Bonzini {
84728e71eeSPaolo Bonzini     puts(msg);
85728e71eeSPaolo Bonzini 
86728e71eeSPaolo Bonzini     do_smsw();
87a299895bSThomas Huth     report(gp_count == 0, "no exception from smsw");
88728e71eeSPaolo Bonzini     do_sgdt();
89a299895bSThomas Huth     report(gp_count == 0, "no exception from sgdt");
90728e71eeSPaolo Bonzini     do_sidt();
91a299895bSThomas Huth     report(gp_count == 0, "no exception from sidt");
92728e71eeSPaolo Bonzini     do_sldt();
93a299895bSThomas Huth     report(gp_count == 0, "no exception from sldt");
94728e71eeSPaolo Bonzini     do_str();
95a299895bSThomas Huth     report(gp_count == 0, "no exception from str");
96728e71eeSPaolo Bonzini     if (read_cs() & 3) {
97728e71eeSPaolo Bonzini         do_movcr();
98a299895bSThomas Huth         report(gp_count == 1, "exception from mov %%cr0, %%eax");
99728e71eeSPaolo Bonzini     }
100728e71eeSPaolo Bonzini }
101728e71eeSPaolo Bonzini 
test_umip_gp(const char * msg)10249024be1SPeter Xu static void test_umip_gp(const char *msg)
103728e71eeSPaolo Bonzini {
104728e71eeSPaolo Bonzini     puts(msg);
105728e71eeSPaolo Bonzini 
106d5d04459SPaolo Bonzini #if 0
107d5d04459SPaolo Bonzini     /* Skip this, because it cannot be emulated correctly.  */
108728e71eeSPaolo Bonzini     do_smsw();
109a299895bSThomas Huth     report(gp_count == 1, "exception from smsw");
110d5d04459SPaolo Bonzini #endif
111728e71eeSPaolo Bonzini     do_sgdt();
112a299895bSThomas Huth     report(gp_count == 1, "exception from sgdt");
113728e71eeSPaolo Bonzini     do_sidt();
114a299895bSThomas Huth     report(gp_count == 1, "exception from sidt");
115728e71eeSPaolo Bonzini     do_sldt();
116a299895bSThomas Huth     report(gp_count == 1, "exception from sldt");
117728e71eeSPaolo Bonzini     do_str();
118a299895bSThomas Huth     report(gp_count == 1, "exception from str");
119728e71eeSPaolo Bonzini     if (read_cs() & 3) {
120728e71eeSPaolo Bonzini         do_movcr();
121a299895bSThomas Huth         report(gp_count == 1, "exception from mov %%cr0, %%eax");
122728e71eeSPaolo Bonzini     }
123728e71eeSPaolo Bonzini }
124728e71eeSPaolo Bonzini 
125728e71eeSPaolo Bonzini /* The ugly mode switching code */
126728e71eeSPaolo Bonzini 
do_ring3(void (* fn)(const char *),const char * arg)127abe6fda7SBill Wendling static noinline int do_ring3(void (*fn)(const char *), const char *arg)
128728e71eeSPaolo Bonzini {
129728e71eeSPaolo Bonzini     static unsigned char user_stack[4096];
130728e71eeSPaolo Bonzini     int ret;
131728e71eeSPaolo Bonzini 
132728e71eeSPaolo Bonzini     asm volatile ("mov %[user_ds], %%" R "dx\n\t"
133728e71eeSPaolo Bonzini 		  "mov %%dx, %%ds\n\t"
134728e71eeSPaolo Bonzini 		  "mov %%dx, %%es\n\t"
135728e71eeSPaolo Bonzini 		  "mov %%dx, %%fs\n\t"
136728e71eeSPaolo Bonzini 		  "mov %%dx, %%gs\n\t"
1378cd86535SPaolo Bonzini 		  "mov %%" R "sp, %[sp0]\n\t" /* kernel sp for exception handlers */
138*7bf8144eSZixuan Wang 		  "mov %[sp0], %%" R "bx\n\t" /* ebx/rbx is preserved before and after 'call' instruction */
139728e71eeSPaolo Bonzini 		  "push" W " %%" R "dx \n\t"
140728e71eeSPaolo Bonzini 		  "lea %[user_stack_top], %%" R "dx \n\t"
141728e71eeSPaolo Bonzini 		  "push" W " %%" R "dx \n\t"
142728e71eeSPaolo Bonzini 		  "pushf" W "\n\t"
143728e71eeSPaolo Bonzini 		  "push" W " %[user_cs] \n\t"
144*7bf8144eSZixuan Wang #ifndef __x86_64__
145728e71eeSPaolo Bonzini 		  "push" W " $1f \n\t"
146*7bf8144eSZixuan Wang #else
147*7bf8144eSZixuan Wang 		  "lea 1f(%%rip), %%rdx \n\t"
148*7bf8144eSZixuan Wang 		  "pushq %%rdx \n\t"
149*7bf8144eSZixuan Wang #endif
150728e71eeSPaolo Bonzini 		  "iret" W "\n"
151728e71eeSPaolo Bonzini 		  "1: \n\t"
152728e71eeSPaolo Bonzini #ifndef __x86_64__
153728e71eeSPaolo Bonzini 		  "push %[arg]\n\t"
154728e71eeSPaolo Bonzini #endif
155728e71eeSPaolo Bonzini 		  "call *%[fn]\n\t"
156728e71eeSPaolo Bonzini #ifndef __x86_64__
157728e71eeSPaolo Bonzini 		  "pop %%ecx\n\t"
158728e71eeSPaolo Bonzini #endif
159*7bf8144eSZixuan Wang #ifndef __x86_64__
160728e71eeSPaolo Bonzini 		  "mov $1f, %%" R "dx\n\t"
161*7bf8144eSZixuan Wang #else
162*7bf8144eSZixuan Wang 		  "lea 1f(%%" R "ip), %%" R "dx\n\t"
163*7bf8144eSZixuan Wang #endif
164728e71eeSPaolo Bonzini 		  "int %[kernel_entry_vector]\n\t"
165728e71eeSPaolo Bonzini 		  ".section .text.entry \n\t"
166728e71eeSPaolo Bonzini 		  "kernel_entry: \n\t"
1678cd86535SPaolo Bonzini #ifdef __x86_64__
168*7bf8144eSZixuan Wang 		  "mov %%rbx, %%rsp\n\t"
1698cd86535SPaolo Bonzini #else
1708cd86535SPaolo Bonzini 		  "add $(5 * " S "), %%esp\n\t"
1718cd86535SPaolo Bonzini #endif
172728e71eeSPaolo Bonzini 		  "mov %[kernel_ds], %%cx\n\t"
173728e71eeSPaolo Bonzini 		  "mov %%cx, %%ds\n\t"
174728e71eeSPaolo Bonzini 		  "mov %%cx, %%es\n\t"
175728e71eeSPaolo Bonzini 		  "mov %%cx, %%fs\n\t"
176728e71eeSPaolo Bonzini 		  "mov %%cx, %%gs\n\t"
177728e71eeSPaolo Bonzini 		  "jmp *%%" R "dx \n\t"
178728e71eeSPaolo Bonzini 		  ".section .text\n\t"
179728e71eeSPaolo Bonzini 		  "1:\n\t"
1808cd86535SPaolo Bonzini 		  : [ret] "=&a" (ret),
1818cd86535SPaolo Bonzini #ifdef __x86_64__
182dbd38004SZixuan Wang 		    [sp0] "=m" (tss[0].rsp0)
1838cd86535SPaolo Bonzini #else
1847e33895dSPaolo Bonzini 		    [sp0] "=m" (tss[0].esp0)
1858cd86535SPaolo Bonzini #endif
186728e71eeSPaolo Bonzini 		  : [user_ds] "i" (USER_DS),
187728e71eeSPaolo Bonzini 		    [user_cs] "i" (USER_CS),
18849efa0e0SThomas Huth 		    [user_stack_top]"m"(user_stack[sizeof(user_stack) -
18949efa0e0SThomas Huth 						   sizeof(long)]),
190728e71eeSPaolo Bonzini 		    [fn]"r"(fn),
191728e71eeSPaolo Bonzini 		    [arg]"D"(arg),
192728e71eeSPaolo Bonzini 		    [kernel_ds]"i"(KERNEL_DS),
193728e71eeSPaolo Bonzini 		    [kernel_entry_vector]"i"(0x20)
194*7bf8144eSZixuan Wang 		  : "rcx", "rdx", "rbx");
195728e71eeSPaolo Bonzini     return ret;
196728e71eeSPaolo Bonzini }
197728e71eeSPaolo Bonzini 
main(void)198b29804b8SThomas Huth int main(void)
199728e71eeSPaolo Bonzini {
200728e71eeSPaolo Bonzini     extern unsigned char kernel_entry;
201728e71eeSPaolo Bonzini 
202728e71eeSPaolo Bonzini     set_idt_entry(0x20, &kernel_entry, 3);
203728e71eeSPaolo Bonzini     handle_exception(13, gp_handler);
204728e71eeSPaolo Bonzini     set_iopl(3);
205728e71eeSPaolo Bonzini 
206728e71eeSPaolo Bonzini     test_umip_nogp("UMIP=0, CPL=0\n");
207728e71eeSPaolo Bonzini     do_ring3(test_umip_nogp, "UMIP=0, CPL=3\n");
208728e71eeSPaolo Bonzini 
209badc98caSKrish Sadhukhan     if (!this_cpu_has(X86_FEATURE_UMIP)) {
210728e71eeSPaolo Bonzini         printf("UMIP not available\n");
211728e71eeSPaolo Bonzini         return report_summary();
212728e71eeSPaolo Bonzini     }
213728e71eeSPaolo Bonzini     write_cr4(read_cr4() | X86_CR4_UMIP);
214728e71eeSPaolo Bonzini 
215b15e79efSLiran Alon     test_umip_nogp("UMIP=1, CPL=0\n");
216b15e79efSLiran Alon     do_ring3(test_umip_gp, "UMIP=1, CPL=3\n");
217728e71eeSPaolo Bonzini 
218728e71eeSPaolo Bonzini     return report_summary();
219728e71eeSPaolo Bonzini }
220