Run the test with Intel's vendor ID and in the long mode, to test the emulation of this instruction on AMD. Signed-off-by: Maxim Levitsky <mlevitsk@xxxxxxxxxx> --- x86/Makefile.x86_64 | 3 ++ x86/cstart64.S | 1 + x86/sysenter.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 5 +++ 4 files changed, 100 insertions(+) create mode 100644 x86/sysenter.c diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64 index 8134952..c430bfb 100644 --- a/x86/Makefile.x86_64 +++ b/x86/Makefile.x86_64 @@ -16,6 +16,7 @@ tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \ $(TEST_DIR)/ioapic.flat $(TEST_DIR)/memory.flat \ $(TEST_DIR)/pku.flat $(TEST_DIR)/hyperv_clock.flat tests += $(TEST_DIR)/syscall.flat +tests += $(TEST_DIR)/sysenter.flat tests += $(TEST_DIR)/svm.flat tests += $(TEST_DIR)/vmx.flat tests += $(TEST_DIR)/tscdeadline_latency.flat @@ -35,3 +36,5 @@ $(TEST_DIR)/hyperv_clock.elf: $(TEST_DIR)/hyperv_clock.o $(TEST_DIR)/vmx.elf: $(TEST_DIR)/vmx_tests.o $(TEST_DIR)/svm.elf: $(TEST_DIR)/svm_tests.o + +$(TEST_DIR)/sysenter.o: CFLAGS += -Wa,-mintel64 \ No newline at end of file diff --git a/x86/cstart64.S b/x86/cstart64.S index 5c6ad38..62ace35 100644 --- a/x86/cstart64.S +++ b/x86/cstart64.S @@ -62,6 +62,7 @@ gdt64_desc: .word gdt64_end - gdt64 - 1 .quad gdt64 +.globl gdt64 gdt64: .quad 0 .quad 0x00af9b000000ffff // 64-bit code segment diff --git a/x86/sysenter.c b/x86/sysenter.c new file mode 100644 index 0000000..c1fc9d5 --- /dev/null +++ b/x86/sysenter.c @@ -0,0 +1,91 @@ + +#include "libcflat.h" +#include "processor.h" +#include "msr.h" +#include "desc.h" + +extern uint64_t gdt64[]; + +// undefine this to run the syscall instruction in 64 bit mode. +// this won't work on AMD due to disabled code in the emulator. +#define COMP32 + +int main(int ac, char **av) +{ + extern void sysenter_target(void); + int gdt_index = 0x50 >> 3; + ulong rax = 0xDEAD; + + /* init the sysenter GDT block */ + gdt64[gdt_index+0] = gdt64[KERNEL_CS >> 3]; + gdt64[gdt_index+1] = gdt64[KERNEL_DS >> 3]; + gdt64[gdt_index+2] = gdt64[USER_CS >> 3]; + gdt64[gdt_index+3] = gdt64[USER_DS >> 3]; + + /* init the sysenter msrs*/ + wrmsr(MSR_IA32_SYSENTER_CS, gdt_index << 3); + wrmsr(MSR_IA32_SYSENTER_ESP, 0xAAFFFFFFFF); + wrmsr(MSR_IA32_SYSENTER_EIP, (uint64_t)sysenter_target); + + asm volatile ( +#ifdef COMP32 + "# switch to comp32, mode prior to running the test\n" + "ljmpl *1f\n" + "1:\n" + ".long 1f\n" + ".long " xstr(KERNEL_CS32) "\n" + "1:\n" + ".code32\n" +#endif + "# use sysenter\n" + "mov %%esp, %%ecx #stash rsp value\n" + "mov $1, %%ebx\n" + "sysenter\n" + "ud2\n" + + "# 64 bit cpl=0 code\n" + "sysenter_target:\n" + ".code64\n" + "test %%rbx, %%rbx # check if we are here for second time \n" + "jne 1f\n" + "movq %%rcx, %%rsp # restore stack pointer manually\n" + "jmp test_done\n" + + "1:\n" + "# test that MSR_IA32_SYSENTER_ESP is correct\n" + "movq $0xAAFFFFFFFF, %%rbx\n" + "movq $0xDEAD, %%rax\n" + "cmpq %%rsp, %%rbx \n" + "jne 1f\n" + "movq $0xACED, %%rax\n" + + "# use sysexit to exit back to cpl=3 32 bit code\n" + "1:\n" + "leaq sysexit_target, %%rdx\n" + "sysexit\n" + "ud2\n" + + "# second sysenter to return to CPL=0 and 64 bit\n" + "# the sysenter handler will jump back to here without sysexit due to ebx=0\n" + "sysexit_target:\n" + ".code32\n" + "mov $0, %%ebx\n" + "sysenter\n" + "test_done:\n" + ".code64\n" + + : /*outputs*/ + "=a" (rax) + : /* inputs*/ + : /*clobbers*/ + "rbx", /* action flag for sysenter_target */ + "rcx", /* saved RSP */ + "rdx", /* used for SYSEXIT*/ + "flags" + ); + + report(rax == 0xACED, "MSR_IA32_SYSENTER_ESP has correct value"); + return report_summary(); +} + + diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 60c4b13..5fe39f5 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -205,6 +205,11 @@ file = syscall.flat arch = x86_64 extra_params = -cpu Opteron_G1,vendor=AuthenticAMD +[sysenter] +file = sysenter.flat +arch = x86_64 +extra_params = -cpu host,vendor=GenuineIntel + [tsc] file = tsc.flat extra_params = -cpu kvm64,+rdtscp -- 2.26.2