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