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 24 #define GP_ASM(stmt, in, clobber) \ 25 asm volatile ( \ 26 "mov" W " $1f, %[expected_rip]\n\t" \ 27 "movl $2f-1f, %[skip_count]\n\t" \ 28 "1: " stmt "\n\t" \ 29 "2: " \ 30 : [expected_rip] "=m" (expected_rip), \ 31 [skip_count] "=m" (skip_count) \ 32 : in : clobber) 33 34 static void do_smsw(void) 35 { 36 gp_count = 0; 37 GP_ASM("smsw %%ax", , "eax"); 38 } 39 40 static void do_sldt(void) 41 { 42 gp_count = 0; 43 GP_ASM("sldt %%ax", , "eax"); 44 } 45 46 static void do_str(void) 47 { 48 gp_count = 0; 49 GP_ASM("str %%ax", , "eax"); 50 } 51 52 static void do_sgdt(void) 53 { 54 struct descriptor_table_ptr dt; 55 gp_count = 0; 56 GP_ASM("sgdt %[dt]", [dt]"m"(dt), ); 57 } 58 59 static void do_sidt(void) 60 { 61 struct descriptor_table_ptr dt; 62 gp_count = 0; 63 GP_ASM("sidt %[dt]", [dt]"m"(dt), ); 64 } 65 66 static void do_movcr(void) 67 { 68 gp_count = 0; 69 GP_ASM("mov %%cr0, %%" R "ax", , "eax"); 70 } 71 72 static void test_umip_nogp(const char *msg) 73 { 74 puts(msg); 75 76 do_smsw(); 77 report(gp_count == 0, "no exception from smsw"); 78 do_sgdt(); 79 report(gp_count == 0, "no exception from sgdt"); 80 do_sidt(); 81 report(gp_count == 0, "no exception from sidt"); 82 do_sldt(); 83 report(gp_count == 0, "no exception from sldt"); 84 do_str(); 85 report(gp_count == 0, "no exception from str"); 86 if (read_cs() & 3) { 87 do_movcr(); 88 report(gp_count == 1, "exception from mov %%cr0, %%eax"); 89 } 90 } 91 92 static void test_umip_gp(const char *msg) 93 { 94 puts(msg); 95 96 #if 0 97 /* Skip this, because it cannot be emulated correctly. */ 98 do_smsw(); 99 report(gp_count == 1, "exception from smsw"); 100 #endif 101 do_sgdt(); 102 report(gp_count == 1, "exception from sgdt"); 103 do_sidt(); 104 report(gp_count == 1, "exception from sidt"); 105 do_sldt(); 106 report(gp_count == 1, "exception from sldt"); 107 do_str(); 108 report(gp_count == 1, "exception from str"); 109 if (read_cs() & 3) { 110 do_movcr(); 111 report(gp_count == 1, "exception from mov %%cr0, %%eax"); 112 } 113 } 114 115 /* The ugly mode switching code */ 116 117 static noinline int do_ring3(void (*fn)(const char *), const char *arg) 118 { 119 static unsigned char user_stack[4096]; 120 int ret; 121 122 asm volatile ("mov %[user_ds], %%" R "dx\n\t" 123 "mov %%dx, %%ds\n\t" 124 "mov %%dx, %%es\n\t" 125 "mov %%dx, %%fs\n\t" 126 "mov %%dx, %%gs\n\t" 127 "mov %%" R "sp, %[sp0]\n\t" /* kernel sp for exception handlers */ 128 "push" W " %%" R "dx \n\t" 129 "lea %[user_stack_top], %%" R "dx \n\t" 130 "push" W " %%" R "dx \n\t" 131 "pushf" W "\n\t" 132 "push" W " %[user_cs] \n\t" 133 "push" W " $1f \n\t" 134 "iret" W "\n" 135 "1: \n\t" 136 #ifndef __x86_64__ 137 "push %[arg]\n\t" 138 #endif 139 "call *%[fn]\n\t" 140 #ifndef __x86_64__ 141 "pop %%ecx\n\t" 142 #endif 143 "mov $1f, %%" R "dx\n\t" 144 "int %[kernel_entry_vector]\n\t" 145 ".section .text.entry \n\t" 146 "kernel_entry: \n\t" 147 #ifdef __x86_64__ 148 "mov %[sp0], %%" R "sp\n\t" 149 #else 150 "add $(5 * " S "), %%esp\n\t" 151 #endif 152 "mov %[kernel_ds], %%cx\n\t" 153 "mov %%cx, %%ds\n\t" 154 "mov %%cx, %%es\n\t" 155 "mov %%cx, %%fs\n\t" 156 "mov %%cx, %%gs\n\t" 157 "jmp *%%" R "dx \n\t" 158 ".section .text\n\t" 159 "1:\n\t" 160 : [ret] "=&a" (ret), 161 #ifdef __x86_64__ 162 [sp0] "=m" (tss[0].rsp0) 163 #else 164 [sp0] "=m" (tss.esp0) 165 #endif 166 : [user_ds] "i" (USER_DS), 167 [user_cs] "i" (USER_CS), 168 [user_stack_top]"m"(user_stack[sizeof(user_stack) - 169 sizeof(long)]), 170 [fn]"r"(fn), 171 [arg]"D"(arg), 172 [kernel_ds]"i"(KERNEL_DS), 173 [kernel_entry_vector]"i"(0x20) 174 : "rcx", "rdx"); 175 return ret; 176 } 177 178 int main(void) 179 { 180 extern unsigned char kernel_entry; 181 182 set_idt_entry(0x20, &kernel_entry, 3); 183 handle_exception(13, gp_handler); 184 set_iopl(3); 185 186 test_umip_nogp("UMIP=0, CPL=0\n"); 187 do_ring3(test_umip_nogp, "UMIP=0, CPL=3\n"); 188 189 if (!this_cpu_has(X86_FEATURE_UMIP)) { 190 printf("UMIP not available\n"); 191 return report_summary(); 192 } 193 write_cr4(read_cr4() | X86_CR4_UMIP); 194 195 test_umip_nogp("UMIP=1, CPL=0\n"); 196 do_ring3(test_umip_gp, "UMIP=1, CPL=3\n"); 197 198 return report_summary(); 199 } 200