sub-test1: Test APIC self IPI with vector < 16 trigger #VE. sub-test2: Test single step on simulation instructions work well with single step emulation in #VE handler, we choose cpuid(0xb) and wrmsr(0x1a0) to test. Please note not all cpuid trigger #VE, e.x. cpuid(0) will not. Signed-off-by: Zhenzhong Duan <zhenzhong.duan@xxxxxxxxx> Reviewed-by: Yu Zhang <yu.c.zhang@xxxxxxxxx> --- x86/Makefile.x86_64 | 1 + x86/intel_tdx.c | 94 +++++++++++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 4 ++ 3 files changed, 99 insertions(+) create mode 100644 x86/intel_tdx.c diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64 index a3cb75ae5868..de79212951a3 100644 --- a/x86/Makefile.x86_64 +++ b/x86/Makefile.x86_64 @@ -31,6 +31,7 @@ tests += $(TEST_DIR)/vmware_backdoors.$(exe) tests += $(TEST_DIR)/rdpru.$(exe) tests += $(TEST_DIR)/pks.$(exe) tests += $(TEST_DIR)/pmu_lbr.$(exe) +tests += $(TEST_DIR)/intel_tdx.$(exe) ifeq ($(TARGET_EFI),y) tests += $(TEST_DIR)/amd_sev.$(exe) diff --git a/x86/intel_tdx.c b/x86/intel_tdx.c new file mode 100644 index 000000000000..e7e65fb32b89 --- /dev/null +++ b/x86/intel_tdx.c @@ -0,0 +1,94 @@ +#include "libcflat.h" +#include "x86/processor.h" +#include "x86/apic-defs.h" +#include "x86/tdx.h" +#include "msr.h" + +static volatile unsigned long db_addr[10], dr6[10]; +static volatile unsigned int n; + +static void test_selfipi_msr(void) +{ + unsigned char vector; + u64 i; + + printf("start APIC_SELF_IPI MSR write test.\n"); + + for (i = 0; i < 16; i++) { + vector = wrmsr_checking(APIC_SELF_IPI, i); + report(vector == VE_VECTOR, + "Expected #VE on WRSMR(%s, 0x%lx), got vector %d", + "APIC_SELF_IPI", i, vector); + } + + printf("end APIC_SELF_IPI MSR write test.\n"); +} + +static void handle_db(struct ex_regs *regs) +{ + db_addr[n] = regs->rip; + dr6[n] = read_dr6(); + + if (dr6[n] & 0x1) + regs->rflags |= (1 << 16); + + if (++n >= 10) { + regs->rflags &= ~(1 << 8); + write_dr7(0x00000400); + } +} + +static void test_single_step(void) +{ + unsigned long start; + + handle_exception(DB_VECTOR, handle_db); + + /* + * cpuid(0xb) and wrmsr(0x1a0) trigger #VE and are then emulated. + * Test #DB on these instructions as there is single step + * simulation in #VE handler. This is complement to x86/debug.c + * which test cpuid(0) and in(0x3fd) instruction. In fact, + * cpuid(0) is emulated by seam module. + */ + n = 0; + write_dr6(0); + asm volatile( + "pushf\n\t" + "pop %%rax\n\t" + "or $(1<<8),%%rax\n\t" + "push %%rax\n\t" + "lea (%%rip),%0\n\t" + "popf\n\t" + "and $~(1<<8),%%rax\n\t" + "push %%rax\n\t" + "mov $0xb,%%rax\n\t" + "cpuid\n\t" + "movl $0x1a0,%%ecx\n\t" + "rdmsr\n\t" + "wrmsr\n\t" + "popf\n\t" + : "=r" (start) : : "rax", "ebx", "ecx", "edx"); + report(n == 8 && + db_addr[0] == start + 1 + 6 && dr6[0] == 0xffff4ff0 && + db_addr[1] == start + 1 + 6 + 1 && dr6[1] == 0xffff4ff0 && + db_addr[2] == start + 1 + 6 + 1 + 7 && dr6[2] == 0xffff4ff0 && + db_addr[3] == start + 1 + 6 + 1 + 7 + 2 && dr6[3] == 0xffff4ff0 && + db_addr[4] == start + 1 + 6 + 1 + 7 + 2 + 5 && dr6[4] == 0xffff4ff0 && + db_addr[5] == start + 1 + 6 + 1 + 7 + 2 + 5 + 2 && dr6[5] == 0xffff4ff0 && + db_addr[6] == start + 1 + 6 + 1 + 7 + 2 + 5 + 2 + 2 && dr6[6] == 0xffff4ff0 && + db_addr[7] == start + 1 + 6 + 1 + 7 + 2 + 5 + 2 + 2 + 1 && dr6[6] == 0xffff4ff0, + "single step emulated instructions"); +} + +int main(void) +{ + if (!is_tdx_guest()) { + printf("Not TDX environment!\n"); + return report_summary(); + } + + test_selfipi_msr(); + test_single_step(); + return report_summary(); +} diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 9a70ba3b4f2e..840e2054d54d 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -437,3 +437,7 @@ file = cet.flat arch = x86_64 smp = 2 extra_params = -enable-kvm -m 2048 -cpu host + +[intel_tdx] +file = intel_tdx.flat +arch = x86_64 -- 2.25.1