1728e71eeSPaolo Bonzini 2728e71eeSPaolo Bonzini #include "libcflat.h" 3728e71eeSPaolo Bonzini #include "desc.h" 4728e71eeSPaolo Bonzini #include "processor.h" 5728e71eeSPaolo Bonzini 6728e71eeSPaolo Bonzini 7728e71eeSPaolo Bonzini /* GP handler to skip over faulting instructions */ 8728e71eeSPaolo Bonzini 9728e71eeSPaolo Bonzini static unsigned long expected_rip; 10728e71eeSPaolo Bonzini static int skip_count; 11728e71eeSPaolo Bonzini static volatile int gp_count; 12728e71eeSPaolo Bonzini 13b29804b8SThomas Huth static void gp_handler(struct ex_regs *regs) 14728e71eeSPaolo Bonzini { 15728e71eeSPaolo Bonzini if (regs->rip == expected_rip) { 16728e71eeSPaolo Bonzini gp_count++; 17728e71eeSPaolo Bonzini regs->rip += skip_count; 18728e71eeSPaolo Bonzini } else { 19728e71eeSPaolo Bonzini unhandled_exception(regs, false); 20728e71eeSPaolo Bonzini } 21728e71eeSPaolo Bonzini } 22728e71eeSPaolo Bonzini 23728e71eeSPaolo Bonzini 24728e71eeSPaolo Bonzini #define GP_ASM(stmt, in, clobber) \ 2549efa0e0SThomas Huth asm volatile ( \ 2649efa0e0SThomas Huth "mov" W " $1f, %[expected_rip]\n\t" \ 27728e71eeSPaolo Bonzini "movl $2f-1f, %[skip_count]\n\t" \ 28728e71eeSPaolo Bonzini "1: " stmt "\n\t" \ 29728e71eeSPaolo Bonzini "2: " \ 30728e71eeSPaolo Bonzini : [expected_rip] "=m" (expected_rip), \ 31728e71eeSPaolo Bonzini [skip_count] "=m" (skip_count) \ 32728e71eeSPaolo Bonzini : in : clobber) 33728e71eeSPaolo Bonzini 34728e71eeSPaolo Bonzini static void do_smsw(void) 35728e71eeSPaolo Bonzini { 36728e71eeSPaolo Bonzini gp_count = 0; 37728e71eeSPaolo Bonzini GP_ASM("smsw %%ax", , "eax"); 38728e71eeSPaolo Bonzini } 39728e71eeSPaolo Bonzini 40728e71eeSPaolo Bonzini static void do_sldt(void) 41728e71eeSPaolo Bonzini { 42728e71eeSPaolo Bonzini gp_count = 0; 43728e71eeSPaolo Bonzini GP_ASM("sldt %%ax", , "eax"); 44728e71eeSPaolo Bonzini } 45728e71eeSPaolo Bonzini 46728e71eeSPaolo Bonzini static void do_str(void) 47728e71eeSPaolo Bonzini { 48728e71eeSPaolo Bonzini gp_count = 0; 49728e71eeSPaolo Bonzini GP_ASM("str %%ax", , "eax"); 50728e71eeSPaolo Bonzini } 51728e71eeSPaolo Bonzini 52728e71eeSPaolo Bonzini static void do_sgdt(void) 53728e71eeSPaolo Bonzini { 54728e71eeSPaolo Bonzini struct descriptor_table_ptr dt; 55728e71eeSPaolo Bonzini gp_count = 0; 56728e71eeSPaolo Bonzini GP_ASM("sgdt %[dt]", [dt]"m"(dt), ); 57728e71eeSPaolo Bonzini } 58728e71eeSPaolo Bonzini 59728e71eeSPaolo Bonzini static void do_sidt(void) 60728e71eeSPaolo Bonzini { 61728e71eeSPaolo Bonzini struct descriptor_table_ptr dt; 62728e71eeSPaolo Bonzini gp_count = 0; 63728e71eeSPaolo Bonzini GP_ASM("sidt %[dt]", [dt]"m"(dt), ); 64728e71eeSPaolo Bonzini } 65728e71eeSPaolo Bonzini 66728e71eeSPaolo Bonzini static void do_movcr(void) 67728e71eeSPaolo Bonzini { 68728e71eeSPaolo Bonzini gp_count = 0; 69728e71eeSPaolo Bonzini GP_ASM("mov %%cr0, %%" R "ax", , "eax"); 70728e71eeSPaolo Bonzini } 71728e71eeSPaolo Bonzini 7249024be1SPeter Xu static void test_umip_nogp(const char *msg) 73728e71eeSPaolo Bonzini { 74728e71eeSPaolo Bonzini puts(msg); 75728e71eeSPaolo Bonzini 76728e71eeSPaolo Bonzini do_smsw(); 77a299895bSThomas Huth report(gp_count == 0, "no exception from smsw"); 78728e71eeSPaolo Bonzini do_sgdt(); 79a299895bSThomas Huth report(gp_count == 0, "no exception from sgdt"); 80728e71eeSPaolo Bonzini do_sidt(); 81a299895bSThomas Huth report(gp_count == 0, "no exception from sidt"); 82728e71eeSPaolo Bonzini do_sldt(); 83a299895bSThomas Huth report(gp_count == 0, "no exception from sldt"); 84728e71eeSPaolo Bonzini do_str(); 85a299895bSThomas Huth report(gp_count == 0, "no exception from str"); 86728e71eeSPaolo Bonzini if (read_cs() & 3) { 87728e71eeSPaolo Bonzini do_movcr(); 88a299895bSThomas Huth report(gp_count == 1, "exception from mov %%cr0, %%eax"); 89728e71eeSPaolo Bonzini } 90728e71eeSPaolo Bonzini } 91728e71eeSPaolo Bonzini 9249024be1SPeter Xu static void test_umip_gp(const char *msg) 93728e71eeSPaolo Bonzini { 94728e71eeSPaolo Bonzini puts(msg); 95728e71eeSPaolo Bonzini 96d5d04459SPaolo Bonzini #if 0 97d5d04459SPaolo Bonzini /* Skip this, because it cannot be emulated correctly. */ 98728e71eeSPaolo Bonzini do_smsw(); 99a299895bSThomas Huth report(gp_count == 1, "exception from smsw"); 100d5d04459SPaolo Bonzini #endif 101728e71eeSPaolo Bonzini do_sgdt(); 102a299895bSThomas Huth report(gp_count == 1, "exception from sgdt"); 103728e71eeSPaolo Bonzini do_sidt(); 104a299895bSThomas Huth report(gp_count == 1, "exception from sidt"); 105728e71eeSPaolo Bonzini do_sldt(); 106a299895bSThomas Huth report(gp_count == 1, "exception from sldt"); 107728e71eeSPaolo Bonzini do_str(); 108a299895bSThomas Huth report(gp_count == 1, "exception from str"); 109728e71eeSPaolo Bonzini if (read_cs() & 3) { 110728e71eeSPaolo Bonzini do_movcr(); 111a299895bSThomas Huth report(gp_count == 1, "exception from mov %%cr0, %%eax"); 112728e71eeSPaolo Bonzini } 113728e71eeSPaolo Bonzini } 114728e71eeSPaolo Bonzini 115728e71eeSPaolo Bonzini /* The ugly mode switching code */ 116728e71eeSPaolo Bonzini 117*abe6fda7SBill Wendling static noinline int do_ring3(void (*fn)(const char *), const char *arg) 118728e71eeSPaolo Bonzini { 119728e71eeSPaolo Bonzini static unsigned char user_stack[4096]; 120728e71eeSPaolo Bonzini int ret; 121728e71eeSPaolo Bonzini 122728e71eeSPaolo Bonzini asm volatile ("mov %[user_ds], %%" R "dx\n\t" 123728e71eeSPaolo Bonzini "mov %%dx, %%ds\n\t" 124728e71eeSPaolo Bonzini "mov %%dx, %%es\n\t" 125728e71eeSPaolo Bonzini "mov %%dx, %%fs\n\t" 126728e71eeSPaolo Bonzini "mov %%dx, %%gs\n\t" 127728e71eeSPaolo Bonzini "mov %%" R "sp, %%" R "cx\n\t" 128728e71eeSPaolo Bonzini "push" W " %%" R "dx \n\t" 129728e71eeSPaolo Bonzini "lea %[user_stack_top], %%" R "dx \n\t" 130728e71eeSPaolo Bonzini "push" W " %%" R "dx \n\t" 131728e71eeSPaolo Bonzini "pushf" W "\n\t" 132728e71eeSPaolo Bonzini "push" W " %[user_cs] \n\t" 133728e71eeSPaolo Bonzini "push" W " $1f \n\t" 134728e71eeSPaolo Bonzini "iret" W "\n" 135728e71eeSPaolo Bonzini "1: \n\t" 136728e71eeSPaolo Bonzini "push %%" R "cx\n\t" /* save kernel SP */ 137728e71eeSPaolo Bonzini 138728e71eeSPaolo Bonzini #ifndef __x86_64__ 139728e71eeSPaolo Bonzini "push %[arg]\n\t" 140728e71eeSPaolo Bonzini #endif 141728e71eeSPaolo Bonzini "call *%[fn]\n\t" 142728e71eeSPaolo Bonzini #ifndef __x86_64__ 143728e71eeSPaolo Bonzini "pop %%ecx\n\t" 144728e71eeSPaolo Bonzini #endif 145728e71eeSPaolo Bonzini 146728e71eeSPaolo Bonzini "pop %%" R "cx\n\t" 147728e71eeSPaolo Bonzini "mov $1f, %%" R "dx\n\t" 148728e71eeSPaolo Bonzini "int %[kernel_entry_vector]\n\t" 149728e71eeSPaolo Bonzini ".section .text.entry \n\t" 150728e71eeSPaolo Bonzini "kernel_entry: \n\t" 151728e71eeSPaolo Bonzini "mov %%" R "cx, %%" R "sp \n\t" 152728e71eeSPaolo Bonzini "mov %[kernel_ds], %%cx\n\t" 153728e71eeSPaolo Bonzini "mov %%cx, %%ds\n\t" 154728e71eeSPaolo Bonzini "mov %%cx, %%es\n\t" 155728e71eeSPaolo Bonzini "mov %%cx, %%fs\n\t" 156728e71eeSPaolo Bonzini "mov %%cx, %%gs\n\t" 157728e71eeSPaolo Bonzini "jmp *%%" R "dx \n\t" 158728e71eeSPaolo Bonzini ".section .text\n\t" 159728e71eeSPaolo Bonzini "1:\n\t" 160728e71eeSPaolo Bonzini : [ret] "=&a" (ret) 161728e71eeSPaolo Bonzini : [user_ds] "i" (USER_DS), 162728e71eeSPaolo Bonzini [user_cs] "i" (USER_CS), 16349efa0e0SThomas Huth [user_stack_top]"m"(user_stack[sizeof(user_stack) - 16449efa0e0SThomas Huth sizeof(long)]), 165728e71eeSPaolo Bonzini [fn]"r"(fn), 166728e71eeSPaolo Bonzini [arg]"D"(arg), 167728e71eeSPaolo Bonzini [kernel_ds]"i"(KERNEL_DS), 168728e71eeSPaolo Bonzini [kernel_entry_vector]"i"(0x20) 169728e71eeSPaolo Bonzini : "rcx", "rdx"); 170728e71eeSPaolo Bonzini return ret; 171728e71eeSPaolo Bonzini } 172728e71eeSPaolo Bonzini 173b29804b8SThomas Huth int main(void) 174728e71eeSPaolo Bonzini { 175728e71eeSPaolo Bonzini extern unsigned char kernel_entry; 176728e71eeSPaolo Bonzini 177728e71eeSPaolo Bonzini set_idt_entry(0x20, &kernel_entry, 3); 178728e71eeSPaolo Bonzini handle_exception(13, gp_handler); 179728e71eeSPaolo Bonzini set_iopl(3); 180728e71eeSPaolo Bonzini 181728e71eeSPaolo Bonzini test_umip_nogp("UMIP=0, CPL=0\n"); 182728e71eeSPaolo Bonzini do_ring3(test_umip_nogp, "UMIP=0, CPL=3\n"); 183728e71eeSPaolo Bonzini 184badc98caSKrish Sadhukhan if (!this_cpu_has(X86_FEATURE_UMIP)) { 185728e71eeSPaolo Bonzini printf("UMIP not available\n"); 186728e71eeSPaolo Bonzini return report_summary(); 187728e71eeSPaolo Bonzini } 188728e71eeSPaolo Bonzini write_cr4(read_cr4() | X86_CR4_UMIP); 189728e71eeSPaolo Bonzini 190b15e79efSLiran Alon test_umip_nogp("UMIP=1, CPL=0\n"); 191b15e79efSLiran Alon do_ring3(test_umip_gp, "UMIP=1, CPL=3\n"); 192728e71eeSPaolo Bonzini 193728e71eeSPaolo Bonzini return report_summary(); 194728e71eeSPaolo Bonzini } 195