syscall.c 3.3 KB

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