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