Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 1 | |
| 2 | #include "libcflat.h" |
| 3 | #include "desc.h" |
| 4 | #include "processor.h" |
| 5 | |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 6 | |
| 7 | /* GP handler to skip over faulting instructions */ |
| 8 | |
| 9 | static unsigned long expected_rip; |
| 10 | static int skip_count; |
| 11 | static volatile int gp_count; |
| 12 | |
Thomas Huth | b29804b | 2018-09-28 10:32:59 +0200 | [diff] [blame] | 13 | static void gp_handler(struct ex_regs *regs) |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 14 | { |
| 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 Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 23 | #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 Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 33 | |
| 34 | #define GP_ASM(stmt, in, clobber) \ |
Thomas Huth | 49efa0e | 2020-05-12 11:44:38 +0200 | [diff] [blame] | 35 | asm volatile ( \ |
Zixuan Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 36 | GP_ASM_MOVE_TO_RIP \ |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 37 | "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 | |
| 44 | static void do_smsw(void) |
| 45 | { |
| 46 | gp_count = 0; |
| 47 | GP_ASM("smsw %%ax", , "eax"); |
| 48 | } |
| 49 | |
| 50 | static void do_sldt(void) |
| 51 | { |
| 52 | gp_count = 0; |
| 53 | GP_ASM("sldt %%ax", , "eax"); |
| 54 | } |
| 55 | |
| 56 | static void do_str(void) |
| 57 | { |
| 58 | gp_count = 0; |
| 59 | GP_ASM("str %%ax", , "eax"); |
| 60 | } |
| 61 | |
| 62 | static 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 | |
| 69 | static 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 | |
| 76 | static void do_movcr(void) |
| 77 | { |
| 78 | gp_count = 0; |
| 79 | GP_ASM("mov %%cr0, %%" R "ax", , "eax"); |
| 80 | } |
| 81 | |
Peter Xu | 49024be | 2018-07-17 15:12:26 +0800 | [diff] [blame] | 82 | static void test_umip_nogp(const char *msg) |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 83 | { |
| 84 | puts(msg); |
| 85 | |
| 86 | do_smsw(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 87 | report(gp_count == 0, "no exception from smsw"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 88 | do_sgdt(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 89 | report(gp_count == 0, "no exception from sgdt"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 90 | do_sidt(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 91 | report(gp_count == 0, "no exception from sidt"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 92 | do_sldt(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 93 | report(gp_count == 0, "no exception from sldt"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 94 | do_str(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 95 | report(gp_count == 0, "no exception from str"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 96 | if (read_cs() & 3) { |
| 97 | do_movcr(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 98 | report(gp_count == 1, "exception from mov %%cr0, %%eax"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 99 | } |
| 100 | } |
| 101 | |
Peter Xu | 49024be | 2018-07-17 15:12:26 +0800 | [diff] [blame] | 102 | static void test_umip_gp(const char *msg) |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 103 | { |
| 104 | puts(msg); |
| 105 | |
Paolo Bonzini | d5d0445 | 2018-09-11 16:57:54 +0200 | [diff] [blame] | 106 | #if 0 |
| 107 | /* Skip this, because it cannot be emulated correctly. */ |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 108 | do_smsw(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 109 | report(gp_count == 1, "exception from smsw"); |
Paolo Bonzini | d5d0445 | 2018-09-11 16:57:54 +0200 | [diff] [blame] | 110 | #endif |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 111 | do_sgdt(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 112 | report(gp_count == 1, "exception from sgdt"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 113 | do_sidt(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 114 | report(gp_count == 1, "exception from sidt"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 115 | do_sldt(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 116 | report(gp_count == 1, "exception from sldt"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 117 | do_str(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 118 | report(gp_count == 1, "exception from str"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 119 | if (read_cs() & 3) { |
| 120 | do_movcr(); |
Thomas Huth | a299895 | 2019-12-06 12:31:02 +0100 | [diff] [blame] | 121 | report(gp_count == 1, "exception from mov %%cr0, %%eax"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 122 | } |
| 123 | } |
| 124 | |
| 125 | /* The ugly mode switching code */ |
| 126 | |
Bill Wendling | abe6fda | 2021-09-09 11:32:06 -0700 | [diff] [blame] | 127 | static noinline int do_ring3(void (*fn)(const char *), const char *arg) |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 128 | { |
| 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 Bonzini | 8cd8653 | 2021-10-21 07:15:14 -0400 | [diff] [blame] | 137 | "mov %%" R "sp, %[sp0]\n\t" /* kernel sp for exception handlers */ |
Zixuan Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 138 | "mov %[sp0], %%" R "bx\n\t" /* ebx/rbx is preserved before and after 'call' instruction */ |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 139 | "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 Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 144 | #ifndef __x86_64__ |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 145 | "push" W " $1f \n\t" |
Zixuan Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 146 | #else |
| 147 | "lea 1f(%%rip), %%rdx \n\t" |
| 148 | "pushq %%rdx \n\t" |
| 149 | #endif |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 150 | "iret" W "\n" |
| 151 | "1: \n\t" |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 152 | #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 Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 159 | #ifndef __x86_64__ |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 160 | "mov $1f, %%" R "dx\n\t" |
Zixuan Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 161 | #else |
| 162 | "lea 1f(%%" R "ip), %%" R "dx\n\t" |
| 163 | #endif |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 164 | "int %[kernel_entry_vector]\n\t" |
| 165 | ".section .text.entry \n\t" |
| 166 | "kernel_entry: \n\t" |
Paolo Bonzini | 8cd8653 | 2021-10-21 07:15:14 -0400 | [diff] [blame] | 167 | #ifdef __x86_64__ |
Zixuan Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 168 | "mov %%rbx, %%rsp\n\t" |
Paolo Bonzini | 8cd8653 | 2021-10-21 07:15:14 -0400 | [diff] [blame] | 169 | #else |
| 170 | "add $(5 * " S "), %%esp\n\t" |
| 171 | #endif |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 172 | "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 Bonzini | 8cd8653 | 2021-10-21 07:15:14 -0400 | [diff] [blame] | 180 | : [ret] "=&a" (ret), |
| 181 | #ifdef __x86_64__ |
Zixuan Wang | dbd3800 | 2021-10-21 07:31:28 -0400 | [diff] [blame] | 182 | [sp0] "=m" (tss[0].rsp0) |
Paolo Bonzini | 8cd8653 | 2021-10-21 07:15:14 -0400 | [diff] [blame] | 183 | #else |
Paolo Bonzini | 7e33895 | 2021-10-21 05:14:51 -0400 | [diff] [blame] | 184 | [sp0] "=m" (tss[0].esp0) |
Paolo Bonzini | 8cd8653 | 2021-10-21 07:15:14 -0400 | [diff] [blame] | 185 | #endif |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 186 | : [user_ds] "i" (USER_DS), |
| 187 | [user_cs] "i" (USER_CS), |
Thomas Huth | 49efa0e | 2020-05-12 11:44:38 +0200 | [diff] [blame] | 188 | [user_stack_top]"m"(user_stack[sizeof(user_stack) - |
| 189 | sizeof(long)]), |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 190 | [fn]"r"(fn), |
| 191 | [arg]"D"(arg), |
| 192 | [kernel_ds]"i"(KERNEL_DS), |
| 193 | [kernel_entry_vector]"i"(0x20) |
Zixuan Wang | 7bf8144 | 2021-10-30 22:56:30 -0700 | [diff] [blame] | 194 | : "rcx", "rdx", "rbx"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 195 | return ret; |
| 196 | } |
| 197 | |
Thomas Huth | b29804b | 2018-09-28 10:32:59 +0200 | [diff] [blame] | 198 | int main(void) |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 199 | { |
| 200 | extern unsigned char kernel_entry; |
| 201 | |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 202 | 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 Sadhukhan | badc98c | 2019-07-30 17:52:56 -0400 | [diff] [blame] | 209 | if (!this_cpu_has(X86_FEATURE_UMIP)) { |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 210 | printf("UMIP not available\n"); |
| 211 | return report_summary(); |
| 212 | } |
| 213 | write_cr4(read_cr4() | X86_CR4_UMIP); |
| 214 | |
Liran Alon | b15e79e | 2018-09-06 02:28:00 +0300 | [diff] [blame] | 215 | test_umip_nogp("UMIP=1, CPL=0\n"); |
| 216 | do_ring3(test_umip_gp, "UMIP=1, CPL=3\n"); |
Paolo Bonzini | 728e71e | 2018-03-23 18:38:57 +0100 | [diff] [blame] | 217 | |
| 218 | return report_summary(); |
| 219 | } |