xref: /kvm-unit-tests/x86/umip.c (revision abe6fda70a7a083f038ef9f579153bba800bb7f4)
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 
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 
23728e71eeSPaolo Bonzini 
24728e71eeSPaolo Bonzini #define GP_ASM(stmt, in, clobber)                  \
2549efa0e0SThomas Huth     asm volatile (                                 \
2649efa0e0SThomas Huth           "mov" W " $1f, %[expected_rip]\n\t"      \
27728e71eeSPaolo Bonzini           "movl $2f-1f, %[skip_count]\n\t"         \
28728e71eeSPaolo Bonzini           "1: " stmt "\n\t"                        \
29728e71eeSPaolo Bonzini           "2: "                                    \
30728e71eeSPaolo Bonzini           : [expected_rip] "=m" (expected_rip),    \
31728e71eeSPaolo Bonzini             [skip_count] "=m" (skip_count)         \
32728e71eeSPaolo Bonzini           : in : clobber)
33728e71eeSPaolo Bonzini 
34728e71eeSPaolo Bonzini static void do_smsw(void)
35728e71eeSPaolo Bonzini {
36728e71eeSPaolo Bonzini     gp_count = 0;
37728e71eeSPaolo Bonzini     GP_ASM("smsw %%ax", , "eax");
38728e71eeSPaolo Bonzini }
39728e71eeSPaolo Bonzini 
40728e71eeSPaolo Bonzini static void do_sldt(void)
41728e71eeSPaolo Bonzini {
42728e71eeSPaolo Bonzini     gp_count = 0;
43728e71eeSPaolo Bonzini     GP_ASM("sldt %%ax", , "eax");
44728e71eeSPaolo Bonzini }
45728e71eeSPaolo Bonzini 
46728e71eeSPaolo Bonzini static void do_str(void)
47728e71eeSPaolo Bonzini {
48728e71eeSPaolo Bonzini     gp_count = 0;
49728e71eeSPaolo Bonzini     GP_ASM("str %%ax", , "eax");
50728e71eeSPaolo Bonzini }
51728e71eeSPaolo Bonzini 
52728e71eeSPaolo Bonzini static void do_sgdt(void)
53728e71eeSPaolo Bonzini {
54728e71eeSPaolo Bonzini     struct descriptor_table_ptr dt;
55728e71eeSPaolo Bonzini     gp_count = 0;
56728e71eeSPaolo Bonzini     GP_ASM("sgdt %[dt]", [dt]"m"(dt), );
57728e71eeSPaolo Bonzini }
58728e71eeSPaolo Bonzini 
59728e71eeSPaolo Bonzini static void do_sidt(void)
60728e71eeSPaolo Bonzini {
61728e71eeSPaolo Bonzini     struct descriptor_table_ptr dt;
62728e71eeSPaolo Bonzini     gp_count = 0;
63728e71eeSPaolo Bonzini     GP_ASM("sidt %[dt]", [dt]"m"(dt), );
64728e71eeSPaolo Bonzini }
65728e71eeSPaolo Bonzini 
66728e71eeSPaolo Bonzini static void do_movcr(void)
67728e71eeSPaolo Bonzini {
68728e71eeSPaolo Bonzini     gp_count = 0;
69728e71eeSPaolo Bonzini     GP_ASM("mov %%cr0, %%" R "ax", , "eax");
70728e71eeSPaolo Bonzini }
71728e71eeSPaolo Bonzini 
7249024be1SPeter Xu static void test_umip_nogp(const char *msg)
73728e71eeSPaolo Bonzini {
74728e71eeSPaolo Bonzini     puts(msg);
75728e71eeSPaolo Bonzini 
76728e71eeSPaolo Bonzini     do_smsw();
77a299895bSThomas Huth     report(gp_count == 0, "no exception from smsw");
78728e71eeSPaolo Bonzini     do_sgdt();
79a299895bSThomas Huth     report(gp_count == 0, "no exception from sgdt");
80728e71eeSPaolo Bonzini     do_sidt();
81a299895bSThomas Huth     report(gp_count == 0, "no exception from sidt");
82728e71eeSPaolo Bonzini     do_sldt();
83a299895bSThomas Huth     report(gp_count == 0, "no exception from sldt");
84728e71eeSPaolo Bonzini     do_str();
85a299895bSThomas Huth     report(gp_count == 0, "no exception from str");
86728e71eeSPaolo Bonzini     if (read_cs() & 3) {
87728e71eeSPaolo Bonzini         do_movcr();
88a299895bSThomas Huth         report(gp_count == 1, "exception from mov %%cr0, %%eax");
89728e71eeSPaolo Bonzini     }
90728e71eeSPaolo Bonzini }
91728e71eeSPaolo Bonzini 
9249024be1SPeter Xu static void test_umip_gp(const char *msg)
93728e71eeSPaolo Bonzini {
94728e71eeSPaolo Bonzini     puts(msg);
95728e71eeSPaolo Bonzini 
96d5d04459SPaolo Bonzini #if 0
97d5d04459SPaolo Bonzini     /* Skip this, because it cannot be emulated correctly.  */
98728e71eeSPaolo Bonzini     do_smsw();
99a299895bSThomas Huth     report(gp_count == 1, "exception from smsw");
100d5d04459SPaolo Bonzini #endif
101728e71eeSPaolo Bonzini     do_sgdt();
102a299895bSThomas Huth     report(gp_count == 1, "exception from sgdt");
103728e71eeSPaolo Bonzini     do_sidt();
104a299895bSThomas Huth     report(gp_count == 1, "exception from sidt");
105728e71eeSPaolo Bonzini     do_sldt();
106a299895bSThomas Huth     report(gp_count == 1, "exception from sldt");
107728e71eeSPaolo Bonzini     do_str();
108a299895bSThomas Huth     report(gp_count == 1, "exception from str");
109728e71eeSPaolo Bonzini     if (read_cs() & 3) {
110728e71eeSPaolo Bonzini         do_movcr();
111a299895bSThomas Huth         report(gp_count == 1, "exception from mov %%cr0, %%eax");
112728e71eeSPaolo Bonzini     }
113728e71eeSPaolo Bonzini }
114728e71eeSPaolo Bonzini 
115728e71eeSPaolo Bonzini /* The ugly mode switching code */
116728e71eeSPaolo Bonzini 
117*abe6fda7SBill Wendling static noinline int do_ring3(void (*fn)(const char *), const char *arg)
118728e71eeSPaolo Bonzini {
119728e71eeSPaolo Bonzini     static unsigned char user_stack[4096];
120728e71eeSPaolo Bonzini     int ret;
121728e71eeSPaolo Bonzini 
122728e71eeSPaolo Bonzini     asm volatile ("mov %[user_ds], %%" R "dx\n\t"
123728e71eeSPaolo Bonzini 		  "mov %%dx, %%ds\n\t"
124728e71eeSPaolo Bonzini 		  "mov %%dx, %%es\n\t"
125728e71eeSPaolo Bonzini 		  "mov %%dx, %%fs\n\t"
126728e71eeSPaolo Bonzini 		  "mov %%dx, %%gs\n\t"
127728e71eeSPaolo Bonzini 		  "mov %%" R "sp, %%" R "cx\n\t"
128728e71eeSPaolo Bonzini 		  "push" W " %%" R "dx \n\t"
129728e71eeSPaolo Bonzini 		  "lea %[user_stack_top], %%" R "dx \n\t"
130728e71eeSPaolo Bonzini 		  "push" W " %%" R "dx \n\t"
131728e71eeSPaolo Bonzini 		  "pushf" W "\n\t"
132728e71eeSPaolo Bonzini 		  "push" W " %[user_cs] \n\t"
133728e71eeSPaolo Bonzini 		  "push" W " $1f \n\t"
134728e71eeSPaolo Bonzini 		  "iret" W "\n"
135728e71eeSPaolo Bonzini 		  "1: \n\t"
136728e71eeSPaolo Bonzini 		  "push %%" R "cx\n\t"   /* save kernel SP */
137728e71eeSPaolo Bonzini 
138728e71eeSPaolo Bonzini #ifndef __x86_64__
139728e71eeSPaolo Bonzini 		  "push %[arg]\n\t"
140728e71eeSPaolo Bonzini #endif
141728e71eeSPaolo Bonzini 		  "call *%[fn]\n\t"
142728e71eeSPaolo Bonzini #ifndef __x86_64__
143728e71eeSPaolo Bonzini 		  "pop %%ecx\n\t"
144728e71eeSPaolo Bonzini #endif
145728e71eeSPaolo Bonzini 
146728e71eeSPaolo Bonzini 		  "pop %%" R "cx\n\t"
147728e71eeSPaolo Bonzini 		  "mov $1f, %%" R "dx\n\t"
148728e71eeSPaolo Bonzini 		  "int %[kernel_entry_vector]\n\t"
149728e71eeSPaolo Bonzini 		  ".section .text.entry \n\t"
150728e71eeSPaolo Bonzini 		  "kernel_entry: \n\t"
151728e71eeSPaolo Bonzini 		  "mov %%" R "cx, %%" R "sp \n\t"
152728e71eeSPaolo Bonzini 		  "mov %[kernel_ds], %%cx\n\t"
153728e71eeSPaolo Bonzini 		  "mov %%cx, %%ds\n\t"
154728e71eeSPaolo Bonzini 		  "mov %%cx, %%es\n\t"
155728e71eeSPaolo Bonzini 		  "mov %%cx, %%fs\n\t"
156728e71eeSPaolo Bonzini 		  "mov %%cx, %%gs\n\t"
157728e71eeSPaolo Bonzini 		  "jmp *%%" R "dx \n\t"
158728e71eeSPaolo Bonzini 		  ".section .text\n\t"
159728e71eeSPaolo Bonzini 		  "1:\n\t"
160728e71eeSPaolo Bonzini 		  : [ret] "=&a" (ret)
161728e71eeSPaolo Bonzini 		  : [user_ds] "i" (USER_DS),
162728e71eeSPaolo Bonzini 		    [user_cs] "i" (USER_CS),
16349efa0e0SThomas Huth 		    [user_stack_top]"m"(user_stack[sizeof(user_stack) -
16449efa0e0SThomas Huth 						   sizeof(long)]),
165728e71eeSPaolo Bonzini 		    [fn]"r"(fn),
166728e71eeSPaolo Bonzini 		    [arg]"D"(arg),
167728e71eeSPaolo Bonzini 		    [kernel_ds]"i"(KERNEL_DS),
168728e71eeSPaolo Bonzini 		    [kernel_entry_vector]"i"(0x20)
169728e71eeSPaolo Bonzini 		  : "rcx", "rdx");
170728e71eeSPaolo Bonzini     return ret;
171728e71eeSPaolo Bonzini }
172728e71eeSPaolo Bonzini 
173b29804b8SThomas Huth int main(void)
174728e71eeSPaolo Bonzini {
175728e71eeSPaolo Bonzini     extern unsigned char kernel_entry;
176728e71eeSPaolo Bonzini 
177728e71eeSPaolo Bonzini     set_idt_entry(0x20, &kernel_entry, 3);
178728e71eeSPaolo Bonzini     handle_exception(13, gp_handler);
179728e71eeSPaolo Bonzini     set_iopl(3);
180728e71eeSPaolo Bonzini 
181728e71eeSPaolo Bonzini     test_umip_nogp("UMIP=0, CPL=0\n");
182728e71eeSPaolo Bonzini     do_ring3(test_umip_nogp, "UMIP=0, CPL=3\n");
183728e71eeSPaolo Bonzini 
184badc98caSKrish Sadhukhan     if (!this_cpu_has(X86_FEATURE_UMIP)) {
185728e71eeSPaolo Bonzini         printf("UMIP not available\n");
186728e71eeSPaolo Bonzini         return report_summary();
187728e71eeSPaolo Bonzini     }
188728e71eeSPaolo Bonzini     write_cr4(read_cr4() | X86_CR4_UMIP);
189728e71eeSPaolo Bonzini 
190b15e79efSLiran Alon     test_umip_nogp("UMIP=1, CPL=0\n");
191b15e79efSLiran Alon     do_ring3(test_umip_gp, "UMIP=1, CPL=3\n");
192728e71eeSPaolo Bonzini 
193728e71eeSPaolo Bonzini     return report_summary();
194728e71eeSPaolo Bonzini }
195