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