1aa2efa4dSPaolo Bonzini /* msr tests */ 2aa2efa4dSPaolo Bonzini 3aa2efa4dSPaolo Bonzini #include "libcflat.h" 4aa2efa4dSPaolo Bonzini #include "processor.h" 5aa2efa4dSPaolo Bonzini #include "msr.h" 6aa2efa4dSPaolo Bonzini #include "desc.h" 7aa2efa4dSPaolo Bonzini 8aa2efa4dSPaolo Bonzini static void test_syscall_lazy_load(void) 9aa2efa4dSPaolo Bonzini { 107db17e21SThomas Huth extern void syscall_target(void); 11aa2efa4dSPaolo Bonzini u16 cs = read_cs(), ss = read_ss(); 12aa2efa4dSPaolo Bonzini ulong tmp; 13aa2efa4dSPaolo Bonzini 14aa2efa4dSPaolo Bonzini wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SCE); 15aa2efa4dSPaolo Bonzini wrmsr(MSR_LSTAR, (ulong)syscall_target); 16aa2efa4dSPaolo Bonzini wrmsr(MSR_STAR, (uint64_t)cs << 32); 17aa2efa4dSPaolo Bonzini asm volatile("pushf; syscall; syscall_target: popf" : "=c"(tmp) : : "r11"); 18aa2efa4dSPaolo Bonzini write_ss(ss); 19aa2efa4dSPaolo Bonzini // will crash horribly if broken 20a299895bSThomas Huth report(true, "MSR_*STAR eager loading"); 21aa2efa4dSPaolo Bonzini } 22aa2efa4dSPaolo Bonzini 23a1e63d03SPaolo Bonzini /* 24a1e63d03SPaolo Bonzini * test handling of TF in syscall/sysret: #DB is raised if TF 25a1e63d03SPaolo Bonzini * is 1 at the *end* of syscall/sysret. 26a1e63d03SPaolo Bonzini * 27a1e63d03SPaolo Bonzini * This uses 32-bit syscall/sysret because KVM emulates it on Intel processors. 28a1e63d03SPaolo Bonzini * However, the same bug happens with 64-bit syscall/sysret if two vCPUs 29a1e63d03SPaolo Bonzini * "race" to force the emulation of syscall/sysret. 30a1e63d03SPaolo Bonzini */ 31a1e63d03SPaolo Bonzini 32a1e63d03SPaolo Bonzini static uint16_t code_segment_upon_db; 33a1e63d03SPaolo Bonzini static void handle_db(struct ex_regs *regs) 34a1e63d03SPaolo Bonzini { 35a1e63d03SPaolo Bonzini code_segment_upon_db = regs->cs; 36a1e63d03SPaolo Bonzini regs->rflags &= ~(1 << 8); 37a1e63d03SPaolo Bonzini } 38a1e63d03SPaolo Bonzini 39a1e63d03SPaolo Bonzini /* expects desired ring 3 flags in rax */ 40a1e63d03SPaolo Bonzini asm("syscall32_target:\n" 41*576718d0SBill Wendling " cmpl $0, code_segment_upon_db(%rip)\n" 42a1e63d03SPaolo Bonzini " jne back_to_test\n" 43a1e63d03SPaolo Bonzini " mov %eax,%r11d\n" 44a1e63d03SPaolo Bonzini " sysretl\n"); 45a1e63d03SPaolo Bonzini 46a1e63d03SPaolo Bonzini /* 32-bit, ring-3 part of test_syscall_tf */ 47a1e63d03SPaolo Bonzini asm(" .code32\n" 48a1e63d03SPaolo Bonzini "syscall_tf_user32:\n" 49a1e63d03SPaolo Bonzini " pushf\n" 50a1e63d03SPaolo Bonzini " pop %eax\n" 51a1e63d03SPaolo Bonzini " or $(1<<8),%eax\n" 52a1e63d03SPaolo Bonzini " push %eax\n" 53a1e63d03SPaolo Bonzini " popf\n" 54a1e63d03SPaolo Bonzini " syscall\n" /* singlestep trap taken after syscall */ 55a1e63d03SPaolo Bonzini " syscall\n" /* jumps back to test_syscall_tf's body */ 56a1e63d03SPaolo Bonzini " .code64\n"); 57a1e63d03SPaolo Bonzini 58a1e63d03SPaolo Bonzini static void test_syscall_tf(void) 59a1e63d03SPaolo Bonzini { 607db17e21SThomas Huth extern void syscall32_target(void); 617db17e21SThomas Huth extern void syscall_tf_user32(void); 62a1e63d03SPaolo Bonzini ulong rcx; 63a1e63d03SPaolo Bonzini 64a1e63d03SPaolo Bonzini wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SCE); 65a1e63d03SPaolo Bonzini wrmsr(MSR_CSTAR, (ulong)syscall32_target); 66a1e63d03SPaolo Bonzini wrmsr(MSR_STAR, ((uint64_t)USER_CS32 << 48) | ((uint64_t)KERNEL_CS64 << 32)); 67a1e63d03SPaolo Bonzini wrmsr(MSR_SYSCALL_MASK, X86_EFLAGS_TF|X86_EFLAGS_DF|X86_EFLAGS_IF|X86_EFLAGS_NT); 68a1e63d03SPaolo Bonzini handle_exception(DB_VECTOR, handle_db); 69a1e63d03SPaolo Bonzini 70a1e63d03SPaolo Bonzini /* good: 71a1e63d03SPaolo Bonzini * sysret to syscall_tf_user32 72a1e63d03SPaolo Bonzini * popf sets TF (singlestep starts on the next instruction) 73a1e63d03SPaolo Bonzini * syscall to syscall32_target -> TF cleared and no singlestep 74a1e63d03SPaolo Bonzini * sysretl sets TF 75a1e63d03SPaolo Bonzini * handle_db sets code_segment_upon_db to USER_CS32 and clears TF 76a1e63d03SPaolo Bonzini * syscall to syscall32_target 77a1e63d03SPaolo Bonzini * syscall32_target jumps to back_to_test 78a1e63d03SPaolo Bonzini * 79a1e63d03SPaolo Bonzini * bad: 80a1e63d03SPaolo Bonzini * sysret to syscall_tf_user32 81a1e63d03SPaolo Bonzini * popf sets TF (singlestep starts on the next instruction) 82a1e63d03SPaolo Bonzini * syscall to syscall32_target, TF cleared and wrong singlestep exception 83a1e63d03SPaolo Bonzini * handle_db sets code_segment_upon_db to KERNEL_CS64 84a1e63d03SPaolo Bonzini * syscall32_target jumps to back_to_test 85a1e63d03SPaolo Bonzini */ 86a1e63d03SPaolo Bonzini rcx = (ulong)syscall_tf_user32; 87a1e63d03SPaolo Bonzini asm volatile(" push %%rbp\n" 88a1e63d03SPaolo Bonzini " pushf; pop %%rax\n" // expected by syscall32_target 89a1e63d03SPaolo Bonzini " sysret\n" 90a1e63d03SPaolo Bonzini "back_to_test:\n" 91a1e63d03SPaolo Bonzini " pop %%rbp" 92a1e63d03SPaolo Bonzini : "+c"(rcx) : 93a1e63d03SPaolo Bonzini : "rax", "rbx", "rdx", "rsi", "rdi", "r8", "r9", "r10", "r11", 94a1e63d03SPaolo Bonzini "r12", "r13", "r14", "r15"); 95a1e63d03SPaolo Bonzini if (code_segment_upon_db != USER_CS32) { 96a1e63d03SPaolo Bonzini printf("wrong CS (%#04x)!\n", code_segment_upon_db); 97a1e63d03SPaolo Bonzini } 98a299895bSThomas Huth report(code_segment_upon_db == USER_CS32, "syscall TF handling"); 99a1e63d03SPaolo Bonzini } 100a1e63d03SPaolo Bonzini 101aa2efa4dSPaolo Bonzini int main(int ac, char **av) 102aa2efa4dSPaolo Bonzini { 103a1e63d03SPaolo Bonzini setup_idt(); 104aa2efa4dSPaolo Bonzini test_syscall_lazy_load(); 105a1e63d03SPaolo Bonzini test_syscall_tf(); 106aa2efa4dSPaolo Bonzini 107aa2efa4dSPaolo Bonzini return report_summary(); 108aa2efa4dSPaolo Bonzini } 109