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) \ 25728e71eeSPaolo Bonzini asm ("mov" W " $1f, %[expected_rip]\n\t" \ 26728e71eeSPaolo Bonzini "movl $2f-1f, %[skip_count]\n\t" \ 27728e71eeSPaolo Bonzini "1: " stmt "\n\t" \ 28728e71eeSPaolo Bonzini "2: " \ 29728e71eeSPaolo Bonzini : [expected_rip] "=m" (expected_rip), \ 30728e71eeSPaolo Bonzini [skip_count] "=m" (skip_count) \ 31728e71eeSPaolo Bonzini : in : clobber) 32728e71eeSPaolo Bonzini 33728e71eeSPaolo Bonzini static void do_smsw(void) 34728e71eeSPaolo Bonzini { 35728e71eeSPaolo Bonzini gp_count = 0; 36728e71eeSPaolo Bonzini GP_ASM("smsw %%ax", , "eax"); 37728e71eeSPaolo Bonzini } 38728e71eeSPaolo Bonzini 39728e71eeSPaolo Bonzini static void do_sldt(void) 40728e71eeSPaolo Bonzini { 41728e71eeSPaolo Bonzini gp_count = 0; 42728e71eeSPaolo Bonzini GP_ASM("sldt %%ax", , "eax"); 43728e71eeSPaolo Bonzini } 44728e71eeSPaolo Bonzini 45728e71eeSPaolo Bonzini static void do_str(void) 46728e71eeSPaolo Bonzini { 47728e71eeSPaolo Bonzini gp_count = 0; 48728e71eeSPaolo Bonzini GP_ASM("str %%ax", , "eax"); 49728e71eeSPaolo Bonzini } 50728e71eeSPaolo Bonzini 51728e71eeSPaolo Bonzini static void do_sgdt(void) 52728e71eeSPaolo Bonzini { 53728e71eeSPaolo Bonzini struct descriptor_table_ptr dt; 54728e71eeSPaolo Bonzini gp_count = 0; 55728e71eeSPaolo Bonzini GP_ASM("sgdt %[dt]", [dt]"m"(dt), ); 56728e71eeSPaolo Bonzini } 57728e71eeSPaolo Bonzini 58728e71eeSPaolo Bonzini static void do_sidt(void) 59728e71eeSPaolo Bonzini { 60728e71eeSPaolo Bonzini struct descriptor_table_ptr dt; 61728e71eeSPaolo Bonzini gp_count = 0; 62728e71eeSPaolo Bonzini GP_ASM("sidt %[dt]", [dt]"m"(dt), ); 63728e71eeSPaolo Bonzini } 64728e71eeSPaolo Bonzini 65728e71eeSPaolo Bonzini static void do_movcr(void) 66728e71eeSPaolo Bonzini { 67728e71eeSPaolo Bonzini gp_count = 0; 68728e71eeSPaolo Bonzini GP_ASM("mov %%cr0, %%" R "ax", , "eax"); 69728e71eeSPaolo Bonzini } 70728e71eeSPaolo Bonzini 7149024be1SPeter Xu static void test_umip_nogp(const char *msg) 72728e71eeSPaolo Bonzini { 73728e71eeSPaolo Bonzini puts(msg); 74728e71eeSPaolo Bonzini 75728e71eeSPaolo Bonzini do_smsw(); 76*a299895bSThomas Huth report(gp_count == 0, "no exception from smsw"); 77728e71eeSPaolo Bonzini do_sgdt(); 78*a299895bSThomas Huth report(gp_count == 0, "no exception from sgdt"); 79728e71eeSPaolo Bonzini do_sidt(); 80*a299895bSThomas Huth report(gp_count == 0, "no exception from sidt"); 81728e71eeSPaolo Bonzini do_sldt(); 82*a299895bSThomas Huth report(gp_count == 0, "no exception from sldt"); 83728e71eeSPaolo Bonzini do_str(); 84*a299895bSThomas Huth report(gp_count == 0, "no exception from str"); 85728e71eeSPaolo Bonzini if (read_cs() & 3) { 86728e71eeSPaolo Bonzini do_movcr(); 87*a299895bSThomas Huth report(gp_count == 1, "exception from mov %%cr0, %%eax"); 88728e71eeSPaolo Bonzini } 89728e71eeSPaolo Bonzini } 90728e71eeSPaolo Bonzini 9149024be1SPeter Xu static void test_umip_gp(const char *msg) 92728e71eeSPaolo Bonzini { 93728e71eeSPaolo Bonzini puts(msg); 94728e71eeSPaolo Bonzini 95d5d04459SPaolo Bonzini #if 0 96d5d04459SPaolo Bonzini /* Skip this, because it cannot be emulated correctly. */ 97728e71eeSPaolo Bonzini do_smsw(); 98*a299895bSThomas Huth report(gp_count == 1, "exception from smsw"); 99d5d04459SPaolo Bonzini #endif 100728e71eeSPaolo Bonzini do_sgdt(); 101*a299895bSThomas Huth report(gp_count == 1, "exception from sgdt"); 102728e71eeSPaolo Bonzini do_sidt(); 103*a299895bSThomas Huth report(gp_count == 1, "exception from sidt"); 104728e71eeSPaolo Bonzini do_sldt(); 105*a299895bSThomas Huth report(gp_count == 1, "exception from sldt"); 106728e71eeSPaolo Bonzini do_str(); 107*a299895bSThomas Huth report(gp_count == 1, "exception from str"); 108728e71eeSPaolo Bonzini if (read_cs() & 3) { 109728e71eeSPaolo Bonzini do_movcr(); 110*a299895bSThomas Huth report(gp_count == 1, "exception from mov %%cr0, %%eax"); 111728e71eeSPaolo Bonzini } 112728e71eeSPaolo Bonzini } 113728e71eeSPaolo Bonzini 114728e71eeSPaolo Bonzini /* The ugly mode switching code */ 115728e71eeSPaolo Bonzini 116b29804b8SThomas Huth static int do_ring3(void (*fn)(const char *), const char *arg) 117728e71eeSPaolo Bonzini { 118728e71eeSPaolo Bonzini static unsigned char user_stack[4096]; 119728e71eeSPaolo Bonzini int ret; 120728e71eeSPaolo Bonzini 121728e71eeSPaolo Bonzini asm volatile ("mov %[user_ds], %%" R "dx\n\t" 122728e71eeSPaolo Bonzini "mov %%dx, %%ds\n\t" 123728e71eeSPaolo Bonzini "mov %%dx, %%es\n\t" 124728e71eeSPaolo Bonzini "mov %%dx, %%fs\n\t" 125728e71eeSPaolo Bonzini "mov %%dx, %%gs\n\t" 126728e71eeSPaolo Bonzini "mov %%" R "sp, %%" R "cx\n\t" 127728e71eeSPaolo Bonzini "push" W " %%" R "dx \n\t" 128728e71eeSPaolo Bonzini "lea %[user_stack_top], %%" R "dx \n\t" 129728e71eeSPaolo Bonzini "push" W " %%" R "dx \n\t" 130728e71eeSPaolo Bonzini "pushf" W "\n\t" 131728e71eeSPaolo Bonzini "push" W " %[user_cs] \n\t" 132728e71eeSPaolo Bonzini "push" W " $1f \n\t" 133728e71eeSPaolo Bonzini "iret" W "\n" 134728e71eeSPaolo Bonzini "1: \n\t" 135728e71eeSPaolo Bonzini "push %%" R "cx\n\t" /* save kernel SP */ 136728e71eeSPaolo Bonzini 137728e71eeSPaolo Bonzini #ifndef __x86_64__ 138728e71eeSPaolo Bonzini "push %[arg]\n\t" 139728e71eeSPaolo Bonzini #endif 140728e71eeSPaolo Bonzini "call *%[fn]\n\t" 141728e71eeSPaolo Bonzini #ifndef __x86_64__ 142728e71eeSPaolo Bonzini "pop %%ecx\n\t" 143728e71eeSPaolo Bonzini #endif 144728e71eeSPaolo Bonzini 145728e71eeSPaolo Bonzini "pop %%" R "cx\n\t" 146728e71eeSPaolo Bonzini "mov $1f, %%" R "dx\n\t" 147728e71eeSPaolo Bonzini "int %[kernel_entry_vector]\n\t" 148728e71eeSPaolo Bonzini ".section .text.entry \n\t" 149728e71eeSPaolo Bonzini "kernel_entry: \n\t" 150728e71eeSPaolo Bonzini "mov %%" R "cx, %%" R "sp \n\t" 151728e71eeSPaolo Bonzini "mov %[kernel_ds], %%cx\n\t" 152728e71eeSPaolo Bonzini "mov %%cx, %%ds\n\t" 153728e71eeSPaolo Bonzini "mov %%cx, %%es\n\t" 154728e71eeSPaolo Bonzini "mov %%cx, %%fs\n\t" 155728e71eeSPaolo Bonzini "mov %%cx, %%gs\n\t" 156728e71eeSPaolo Bonzini "jmp *%%" R "dx \n\t" 157728e71eeSPaolo Bonzini ".section .text\n\t" 158728e71eeSPaolo Bonzini "1:\n\t" 159728e71eeSPaolo Bonzini : [ret] "=&a" (ret) 160728e71eeSPaolo Bonzini : [user_ds] "i" (USER_DS), 161728e71eeSPaolo Bonzini [user_cs] "i" (USER_CS), 162728e71eeSPaolo Bonzini [user_stack_top]"m"(user_stack[sizeof user_stack]), 163728e71eeSPaolo Bonzini [fn]"r"(fn), 164728e71eeSPaolo Bonzini [arg]"D"(arg), 165728e71eeSPaolo Bonzini [kernel_ds]"i"(KERNEL_DS), 166728e71eeSPaolo Bonzini [kernel_entry_vector]"i"(0x20) 167728e71eeSPaolo Bonzini : "rcx", "rdx"); 168728e71eeSPaolo Bonzini return ret; 169728e71eeSPaolo Bonzini } 170728e71eeSPaolo Bonzini 171b29804b8SThomas Huth int main(void) 172728e71eeSPaolo Bonzini { 173728e71eeSPaolo Bonzini extern unsigned char kernel_entry; 174728e71eeSPaolo Bonzini 175728e71eeSPaolo Bonzini setup_idt(); 176728e71eeSPaolo Bonzini set_idt_entry(0x20, &kernel_entry, 3); 177728e71eeSPaolo Bonzini handle_exception(13, gp_handler); 178728e71eeSPaolo Bonzini set_iopl(3); 179728e71eeSPaolo Bonzini 180728e71eeSPaolo Bonzini test_umip_nogp("UMIP=0, CPL=0\n"); 181728e71eeSPaolo Bonzini do_ring3(test_umip_nogp, "UMIP=0, CPL=3\n"); 182728e71eeSPaolo Bonzini 183badc98caSKrish Sadhukhan if (!this_cpu_has(X86_FEATURE_UMIP)) { 184728e71eeSPaolo Bonzini printf("UMIP not available\n"); 185728e71eeSPaolo Bonzini return report_summary(); 186728e71eeSPaolo Bonzini } 187728e71eeSPaolo Bonzini write_cr4(read_cr4() | X86_CR4_UMIP); 188728e71eeSPaolo Bonzini 189b15e79efSLiran Alon test_umip_nogp("UMIP=1, CPL=0\n"); 190b15e79efSLiran Alon do_ring3(test_umip_gp, "UMIP=1, CPL=3\n"); 191728e71eeSPaolo Bonzini 192728e71eeSPaolo Bonzini return report_summary(); 193728e71eeSPaolo Bonzini } 194