xref: /kvm-unit-tests/x86/syscall.c (revision 576718d036f52b93dbd8a517e6761c08ada09e2f)
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