1 2 #include "libcflat.h" 3 #include "desc.h" 4 #include "processor.h" 5 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 13 static void gp_handler(struct ex_regs *regs) 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 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 33 34 #define GP_ASM(stmt, in, clobber) \ 35 asm volatile ( \ 36 GP_ASM_MOVE_TO_RIP \ 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 82 static void test_umip_nogp(const char *msg) 83 { 84 puts(msg); 85 86 do_smsw(); 87 report(gp_count == 0, "no exception from smsw"); 88 do_sgdt(); 89 report(gp_count == 0, "no exception from sgdt"); 90 do_sidt(); 91 report(gp_count == 0, "no exception from sidt"); 92 do_sldt(); 93 report(gp_count == 0, "no exception from sldt"); 94 do_str(); 95 report(gp_count == 0, "no exception from str"); 96 if (read_cs() & 3) { 97 do_movcr(); 98 report(gp_count == 1, "exception from mov %%cr0, %%eax"); 99 } 100 } 101 102 static void test_umip_gp(const char *msg) 103 { 104 puts(msg); 105 106 #if 0 107 /* Skip this, because it cannot be emulated correctly. */ 108 do_smsw(); 109 report(gp_count == 1, "exception from smsw"); 110 #endif 111 do_sgdt(); 112 report(gp_count == 1, "exception from sgdt"); 113 do_sidt(); 114 report(gp_count == 1, "exception from sidt"); 115 do_sldt(); 116 report(gp_count == 1, "exception from sldt"); 117 do_str(); 118 report(gp_count == 1, "exception from str"); 119 if (read_cs() & 3) { 120 do_movcr(); 121 report(gp_count == 1, "exception from mov %%cr0, %%eax"); 122 } 123 } 124 125 /* The ugly mode switching code */ 126 127 static noinline int do_ring3(void (*fn)(const char *), const char *arg) 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" 137 "mov %%" R "sp, %[sp0]\n\t" /* kernel sp for exception handlers */ 138 "mov %[sp0], %%" R "bx\n\t" /* ebx/rbx is preserved before and after 'call' instruction */ 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" 144 #ifndef __x86_64__ 145 "push" W " $1f \n\t" 146 #else 147 "lea 1f(%%rip), %%rdx \n\t" 148 "pushq %%rdx \n\t" 149 #endif 150 "iret" W "\n" 151 "1: \n\t" 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 159 #ifndef __x86_64__ 160 "mov $1f, %%" R "dx\n\t" 161 #else 162 "lea 1f(%%" R "ip), %%" R "dx\n\t" 163 #endif 164 "int %[kernel_entry_vector]\n\t" 165 ".section .text.entry \n\t" 166 "kernel_entry: \n\t" 167 #ifdef __x86_64__ 168 "mov %%rbx, %%rsp\n\t" 169 #else 170 "add $(5 * " S "), %%esp\n\t" 171 #endif 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" 180 : [ret] "=&a" (ret), 181 #ifdef __x86_64__ 182 [sp0] "=m" (tss[0].rsp0) 183 #else 184 [sp0] "=m" (tss[0].esp0) 185 #endif 186 : [user_ds] "i" (USER_DS), 187 [user_cs] "i" (USER_CS), 188 [user_stack_top]"m"(user_stack[sizeof(user_stack) - 189 sizeof(long)]), 190 [fn]"r"(fn), 191 [arg]"D"(arg), 192 [kernel_ds]"i"(KERNEL_DS), 193 [kernel_entry_vector]"i"(0x20) 194 : "rcx", "rdx", "rbx"); 195 return ret; 196 } 197 198 int main(void) 199 { 200 extern unsigned char kernel_entry; 201 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 209 if (!this_cpu_has(X86_FEATURE_UMIP)) { 210 printf("UMIP not available\n"); 211 return report_summary(); 212 } 213 write_cr4(read_cr4() | X86_CR4_UMIP); 214 215 test_umip_nogp("UMIP=1, CPL=0\n"); 216 do_ring3(test_umip_gp, "UMIP=1, CPL=3\n"); 217 218 return report_summary(); 219 } 220