blob: fccdedce59e760406c844c03c16995bc5b968736 [file] [log] [blame]
Paolo Bonzini728e71e2018-03-23 18:38:57 +01001
2#include "libcflat.h"
3#include "desc.h"
4#include "processor.h"
5
Paolo Bonzini728e71e2018-03-23 18:38:57 +01006
7/* GP handler to skip over faulting instructions */
8
9static unsigned long expected_rip;
10static int skip_count;
11static volatile int gp_count;
12
Thomas Huthb29804b2018-09-28 10:32:59 +020013static void gp_handler(struct ex_regs *regs)
Paolo Bonzini728e71e2018-03-23 18:38:57 +010014{
15 if (regs->rip == expected_rip) {
16 gp_count++;
17 regs->rip += skip_count;
18 } else {
19 unhandled_exception(regs, false);
20 }
21}
22
Zixuan Wang7bf81442021-10-30 22:56:30 -070023#ifndef __x86_64__
24#define GP_ASM_MOVE_TO_RIP \
25 "mov" W " $1f, %[expected_rip]\n\t"
26#else
27#define GP_ASM_MOVE_TO_RIP \
28 "pushq %%rax\n\t" \
29 "lea 1f(%%rip), %%rax\n\t" \
30 "mov %%rax, %[expected_rip]\n\t" \
31 "popq %%rax\n\t"
32#endif
Paolo Bonzini728e71e2018-03-23 18:38:57 +010033
34#define GP_ASM(stmt, in, clobber) \
Thomas Huth49efa0e2020-05-12 11:44:38 +020035 asm volatile ( \
Zixuan Wang7bf81442021-10-30 22:56:30 -070036 GP_ASM_MOVE_TO_RIP \
Paolo Bonzini728e71e2018-03-23 18:38:57 +010037 "movl $2f-1f, %[skip_count]\n\t" \
38 "1: " stmt "\n\t" \
39 "2: " \
40 : [expected_rip] "=m" (expected_rip), \
41 [skip_count] "=m" (skip_count) \
42 : in : clobber)
43
44static void do_smsw(void)
45{
46 gp_count = 0;
47 GP_ASM("smsw %%ax", , "eax");
48}
49
50static void do_sldt(void)
51{
52 gp_count = 0;
53 GP_ASM("sldt %%ax", , "eax");
54}
55
56static void do_str(void)
57{
58 gp_count = 0;
59 GP_ASM("str %%ax", , "eax");
60}
61
62static void do_sgdt(void)
63{
64 struct descriptor_table_ptr dt;
65 gp_count = 0;
66 GP_ASM("sgdt %[dt]", [dt]"m"(dt), );
67}
68
69static void do_sidt(void)
70{
71 struct descriptor_table_ptr dt;
72 gp_count = 0;
73 GP_ASM("sidt %[dt]", [dt]"m"(dt), );
74}
75
76static void do_movcr(void)
77{
78 gp_count = 0;
79 GP_ASM("mov %%cr0, %%" R "ax", , "eax");
80}
81
Peter Xu49024be2018-07-17 15:12:26 +080082static void test_umip_nogp(const char *msg)
Paolo Bonzini728e71e2018-03-23 18:38:57 +010083{
84 puts(msg);
85
86 do_smsw();
Thomas Hutha2998952019-12-06 12:31:02 +010087 report(gp_count == 0, "no exception from smsw");
Paolo Bonzini728e71e2018-03-23 18:38:57 +010088 do_sgdt();
Thomas Hutha2998952019-12-06 12:31:02 +010089 report(gp_count == 0, "no exception from sgdt");
Paolo Bonzini728e71e2018-03-23 18:38:57 +010090 do_sidt();
Thomas Hutha2998952019-12-06 12:31:02 +010091 report(gp_count == 0, "no exception from sidt");
Paolo Bonzini728e71e2018-03-23 18:38:57 +010092 do_sldt();
Thomas Hutha2998952019-12-06 12:31:02 +010093 report(gp_count == 0, "no exception from sldt");
Paolo Bonzini728e71e2018-03-23 18:38:57 +010094 do_str();
Thomas Hutha2998952019-12-06 12:31:02 +010095 report(gp_count == 0, "no exception from str");
Paolo Bonzini728e71e2018-03-23 18:38:57 +010096 if (read_cs() & 3) {
97 do_movcr();
Thomas Hutha2998952019-12-06 12:31:02 +010098 report(gp_count == 1, "exception from mov %%cr0, %%eax");
Paolo Bonzini728e71e2018-03-23 18:38:57 +010099 }
100}
101
Peter Xu49024be2018-07-17 15:12:26 +0800102static void test_umip_gp(const char *msg)
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100103{
104 puts(msg);
105
Paolo Bonzinid5d04452018-09-11 16:57:54 +0200106#if 0
107 /* Skip this, because it cannot be emulated correctly. */
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100108 do_smsw();
Thomas Hutha2998952019-12-06 12:31:02 +0100109 report(gp_count == 1, "exception from smsw");
Paolo Bonzinid5d04452018-09-11 16:57:54 +0200110#endif
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100111 do_sgdt();
Thomas Hutha2998952019-12-06 12:31:02 +0100112 report(gp_count == 1, "exception from sgdt");
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100113 do_sidt();
Thomas Hutha2998952019-12-06 12:31:02 +0100114 report(gp_count == 1, "exception from sidt");
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100115 do_sldt();
Thomas Hutha2998952019-12-06 12:31:02 +0100116 report(gp_count == 1, "exception from sldt");
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100117 do_str();
Thomas Hutha2998952019-12-06 12:31:02 +0100118 report(gp_count == 1, "exception from str");
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100119 if (read_cs() & 3) {
120 do_movcr();
Thomas Hutha2998952019-12-06 12:31:02 +0100121 report(gp_count == 1, "exception from mov %%cr0, %%eax");
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100122 }
123}
124
125/* The ugly mode switching code */
126
Bill Wendlingabe6fda2021-09-09 11:32:06 -0700127static noinline int do_ring3(void (*fn)(const char *), const char *arg)
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100128{
129 static unsigned char user_stack[4096];
130 int ret;
131
132 asm volatile ("mov %[user_ds], %%" R "dx\n\t"
133 "mov %%dx, %%ds\n\t"
134 "mov %%dx, %%es\n\t"
135 "mov %%dx, %%fs\n\t"
136 "mov %%dx, %%gs\n\t"
Paolo Bonzini8cd86532021-10-21 07:15:14 -0400137 "mov %%" R "sp, %[sp0]\n\t" /* kernel sp for exception handlers */
Zixuan Wang7bf81442021-10-30 22:56:30 -0700138 "mov %[sp0], %%" R "bx\n\t" /* ebx/rbx is preserved before and after 'call' instruction */
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100139 "push" W " %%" R "dx \n\t"
140 "lea %[user_stack_top], %%" R "dx \n\t"
141 "push" W " %%" R "dx \n\t"
142 "pushf" W "\n\t"
143 "push" W " %[user_cs] \n\t"
Zixuan Wang7bf81442021-10-30 22:56:30 -0700144#ifndef __x86_64__
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100145 "push" W " $1f \n\t"
Zixuan Wang7bf81442021-10-30 22:56:30 -0700146#else
147 "lea 1f(%%rip), %%rdx \n\t"
148 "pushq %%rdx \n\t"
149#endif
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100150 "iret" W "\n"
151 "1: \n\t"
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100152#ifndef __x86_64__
153 "push %[arg]\n\t"
154#endif
155 "call *%[fn]\n\t"
156#ifndef __x86_64__
157 "pop %%ecx\n\t"
158#endif
Zixuan Wang7bf81442021-10-30 22:56:30 -0700159#ifndef __x86_64__
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100160 "mov $1f, %%" R "dx\n\t"
Zixuan Wang7bf81442021-10-30 22:56:30 -0700161#else
162 "lea 1f(%%" R "ip), %%" R "dx\n\t"
163#endif
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100164 "int %[kernel_entry_vector]\n\t"
165 ".section .text.entry \n\t"
166 "kernel_entry: \n\t"
Paolo Bonzini8cd86532021-10-21 07:15:14 -0400167#ifdef __x86_64__
Zixuan Wang7bf81442021-10-30 22:56:30 -0700168 "mov %%rbx, %%rsp\n\t"
Paolo Bonzini8cd86532021-10-21 07:15:14 -0400169#else
170 "add $(5 * " S "), %%esp\n\t"
171#endif
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100172 "mov %[kernel_ds], %%cx\n\t"
173 "mov %%cx, %%ds\n\t"
174 "mov %%cx, %%es\n\t"
175 "mov %%cx, %%fs\n\t"
176 "mov %%cx, %%gs\n\t"
177 "jmp *%%" R "dx \n\t"
178 ".section .text\n\t"
179 "1:\n\t"
Paolo Bonzini8cd86532021-10-21 07:15:14 -0400180 : [ret] "=&a" (ret),
181#ifdef __x86_64__
Zixuan Wangdbd38002021-10-21 07:31:28 -0400182 [sp0] "=m" (tss[0].rsp0)
Paolo Bonzini8cd86532021-10-21 07:15:14 -0400183#else
Paolo Bonzini7e338952021-10-21 05:14:51 -0400184 [sp0] "=m" (tss[0].esp0)
Paolo Bonzini8cd86532021-10-21 07:15:14 -0400185#endif
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100186 : [user_ds] "i" (USER_DS),
187 [user_cs] "i" (USER_CS),
Thomas Huth49efa0e2020-05-12 11:44:38 +0200188 [user_stack_top]"m"(user_stack[sizeof(user_stack) -
189 sizeof(long)]),
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100190 [fn]"r"(fn),
191 [arg]"D"(arg),
192 [kernel_ds]"i"(KERNEL_DS),
193 [kernel_entry_vector]"i"(0x20)
Zixuan Wang7bf81442021-10-30 22:56:30 -0700194 : "rcx", "rdx", "rbx");
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100195 return ret;
196}
197
Thomas Huthb29804b2018-09-28 10:32:59 +0200198int main(void)
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100199{
200 extern unsigned char kernel_entry;
201
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100202 set_idt_entry(0x20, &kernel_entry, 3);
203 handle_exception(13, gp_handler);
204 set_iopl(3);
205
206 test_umip_nogp("UMIP=0, CPL=0\n");
207 do_ring3(test_umip_nogp, "UMIP=0, CPL=3\n");
208
Krish Sadhukhanbadc98c2019-07-30 17:52:56 -0400209 if (!this_cpu_has(X86_FEATURE_UMIP)) {
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100210 printf("UMIP not available\n");
211 return report_summary();
212 }
213 write_cr4(read_cr4() | X86_CR4_UMIP);
214
Liran Alonb15e79e2018-09-06 02:28:00 +0300215 test_umip_nogp("UMIP=1, CPL=0\n");
216 do_ring3(test_umip_gp, "UMIP=1, CPL=3\n");
Paolo Bonzini728e71e2018-03-23 18:38:57 +0100217
218 return report_summary();
219}