All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sagi Shahar <sagis@google.com>
To: linux-kselftest@vger.kernel.org
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	Sean Christopherson <seanjc@google.com>,
	Isaku Yamahata <isaku.yamahata@intel.com>,
	Sagi Shahar <sagis@google.com>,
	Erdem Aktas <erdemaktas@google.com>,
	Ryan Afranji <afranji@google.com>,
	Roger Wang <runanwang@google.com>, Shuah Khan <shuah@kernel.org>,
	Andrew Jones <drjones@redhat.com>, Marc Zyngier <maz@kernel.org>,
	Ben Gardon <bgardon@google.com>,
	Jim Mattson <jmattson@google.com>,
	David Matlack <dmatlack@google.com>, Peter Xu <peterx@redhat.com>,
	Oliver Upton <oupton@google.com>,
	Ricardo Koller <ricarkol@google.com>,
	Yang Zhong <yang.zhong@intel.com>,
	Wei Wang <wei.w.wang@intel.com>,
	Xiaoyao Li <xiaoyao.li@intel.com>,
	Peter Gonda <pgonda@google.com>, Marc Orr <marcorr@google.com>,
	Emanuele Giuseppe Esposito <eesposit@redhat.com>,
	Christian Borntraeger <borntraeger@de.ibm.com>,
	Eric Auger <eric.auger@redhat.com>,
	Yanan Wang <wangyanan55@huawei.com>,
	Aaron Lewis <aaronlewis@google.com>,
	Vitaly Kuznetsov <vkuznets@redhat.com>,
	Peter Shier <pshier@google.com>,
	Axel Rasmussen <axelrasmussen@google.com>,
	Zhenzhong Duan <zhenzhong.duan@intel.com>,
	"Maciej S . Szmigiero" <maciej.szmigiero@oracle.com>,
	Like Xu <like.xu@linux.intel.com>,
	linux-kernel@vger.kernel.org, kvm@vger.kernel.org
Subject: [RFC PATCH v2 03/17] KVM: selftest: Adding TDX life cycle test.
Date: Tue, 30 Aug 2022 22:19:46 +0000	[thread overview]
Message-ID: <20220830222000.709028-4-sagis@google.com> (raw)
In-Reply-To: <20220830222000.709028-1-sagis@google.com>

From: Erdem Aktas <erdemaktas@google.com>

Adding a test to verify TDX lifecycle by creating a TD and running a
dummy TDVMCALL<INSTRUCTION.IO> inside it.

Signed-off-by: Erdem Aktas <erdemaktas@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
Signed-off-by: Ryan Afranji <afranji@google.com>
---
 tools/testing/selftests/kvm/Makefile          |   1 +
 tools/testing/selftests/kvm/lib/x86_64/tdx.h  | 149 ++++++++++++++++++
 .../selftests/kvm/x86_64/tdx_vm_tests.c       | 104 ++++++++++++
 3 files changed, 254 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c

diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index ad4d60dadc06..208e0cc30048 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -140,6 +140,7 @@ TEST_GEN_PROGS_x86_64 += set_memory_region_test
 TEST_GEN_PROGS_x86_64 += steal_time
 TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test
 TEST_GEN_PROGS_x86_64 += system_counter_offset_test
+TEST_GEN_PROGS_x86_64 += x86_64/tdx_vm_tests
 
 # Compiled outputs used by test targets
 TEST_GEN_PROGS_EXTENDED_x86_64 += x86_64/nx_huge_pages_test
diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/selftests/kvm/lib/x86_64/tdx.h
index 61b997dfc420..d5de52657112 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h
+++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h
@@ -51,6 +51,12 @@
 #define _PAGE_RW            (1UL<<1)       /* writeable */
 #define _PAGE_PS            (1UL<<7)       /* page size bit*/
 
+#define TDX_INSTRUCTION_IO 30
+
+#define TDX_SUCCESS_PORT 0x30
+#define TDX_IO_READ 0
+#define TDX_IO_WRITE 1
+
 #define GDT_ENTRY(flags, base, limit)				\
 		((((base)  & 0xff000000ULL) << (56-24)) |	\
 		 (((flags) & 0x0000f0ffULL) << 40) |		\
@@ -83,4 +89,147 @@ void prepare_source_image(struct kvm_vm *vm, void *guest_code,
 			  size_t guest_code_size,
 			  uint64_t guest_code_signature);
 
+/*
+ * Generic TDCALL function that can be used to communicate with TDX module or
+ * VMM.
+ * Input operands: rax, rbx, rcx, rdx, r8-r15, rbp, rsi, rdi
+ * Output operands: rax, r8-r15, rbx, rdx, rdi, rsi
+ * rcx is actually a bitmap to tell TDX module which register values will be
+ * exposed to the VMM.
+ * XMM0-XMM15 registers can be used as input operands but the current
+ * implementation does not support it yet.
+ */
+static inline void tdcall(struct kvm_regs *regs)
+{
+	asm volatile (
+			"mov %13, %%rax;\n\t"
+			"mov %14, %%rbx;\n\t"
+			"mov %15, %%rcx;\n\t"
+			"mov %16, %%rdx;\n\t"
+			"mov %17, %%r8;\n\t"
+			"mov %18, %%r9;\n\t"
+			"mov %19, %%r10;\n\t"
+			"mov %20, %%r11;\n\t"
+			"mov %21, %%r12;\n\t"
+			"mov %22, %%r13;\n\t"
+			"mov %23, %%r14;\n\t"
+			"mov %24, %%r15;\n\t"
+			"mov %25, %%rbp;\n\t"
+			"mov %26, %%rsi;\n\t"
+			"mov %27, %%rdi;\n\t"
+			".byte 0x66, 0x0F, 0x01, 0xCC;\n\t"
+			"mov %%rax, %0;\n\t"
+			"mov %%rbx, %1;\n\t"
+			"mov %%rdx, %2;\n\t"
+			"mov %%r8, %3;\n\t"
+			"mov %%r9, %4;\n\t"
+			"mov %%r10, %5;\n\t"
+			"mov %%r11, %6;\n\t"
+			"mov %%r12, %7;\n\t"
+			"mov %%r13, %8;\n\t"
+			"mov %%r14, %9;\n\t"
+			"mov %%r15, %10;\n\t"
+			"mov %%rsi, %11;\n\t"
+			"mov %%rdi, %12;\n\t"
+			: "=m" (regs->rax), "=m" (regs->rbx), "=m" (regs->rdx),
+			"=m" (regs->r8), "=m" (regs->r9), "=m" (regs->r10),
+			"=m" (regs->r11), "=m" (regs->r12), "=m" (regs->r13),
+			"=m" (regs->r14), "=m" (regs->r15), "=m" (regs->rsi),
+			"=m" (regs->rdi)
+			: "m" (regs->rax), "m" (regs->rbx), "m" (regs->rcx),
+			"m" (regs->rdx), "m" (regs->r8), "m" (regs->r9),
+			"m" (regs->r10), "m" (regs->r11), "m" (regs->r12),
+			"m" (regs->r13), "m" (regs->r14), "m" (regs->r15),
+			"m" (regs->rbp), "m" (regs->rsi), "m" (regs->rdi)
+			: "rax", "rbx", "rcx", "rdx", "r8", "r9", "r10", "r11",
+			"r12", "r13", "r14", "r15", "rbp", "rsi", "rdi");
+}
+
+
+/*
+ * Do a TDVMCALL IO request
+ *
+ * Input Args:
+ *  port - IO port to do read/write
+ *  size - Number of bytes to read/write. 1=1byte, 2=2bytes, 4=4bytes.
+ *  write - 1=IO write 0=IO read
+ *  data - pointer for the data to write
+ *
+ * Output Args:
+ *  data - pointer for data to be read
+ *
+ * Return:
+ *   On success, return 0. For Invalid-IO-Port error, returns -1.
+ *
+ * Does an IO operation using the following tdvmcall interface.
+ *
+ * TDG.VP.VMCALL<Instruction.IO>-Input Operands
+ * R11 30 for IO
+ *
+ * R12 Size of access. 1=1byte, 2=2bytes, 4=4bytes.
+ * R13 Direction. 0=Read, 1=Write.
+ * R14 Port number
+ * R15 Data to write, if R13 is 1.
+ *
+ * TDG.VP.VMCALL<Instruction.IO>-Output Operands
+ * R10 TDG.VP.VMCALL-return code.
+ * R11 Data to read, if R13 is 0.
+ *
+ * TDG.VP.VMCALL<Instruction.IO>-Status Codes
+ * Error Code Value Description
+ * TDG.VP.VMCALL_SUCCESS 0x0 TDG.VP.VMCALL is successful
+ * TDG.VP.VMCALL_INVALID_OPERAND 0x80000000 00000000 Invalid-IO-Port access
+ */
+static inline uint64_t tdvmcall_io(uint64_t port, uint64_t size,
+				   uint64_t write, uint64_t *data)
+{
+	struct kvm_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+	regs.r11 = TDX_INSTRUCTION_IO;
+	regs.r12 = size;
+	regs.r13 = write;
+	regs.r14 = port;
+	if (write) {
+		regs.r15 = *data;
+		regs.rcx = 0xFC00;
+	} else {
+		regs.rcx = 0x7C00;
+	}
+	tdcall(&regs);
+	if (!write)
+		*data = regs.r11;
+	return regs.r10;
+}
+
+/*
+ * Report test success to user space.
+ */
+static inline void tdvmcall_success(void)
+{
+	uint64_t code = 0;
+
+	tdvmcall_io(TDX_SUCCESS_PORT, /*size=*/4, TDX_IO_WRITE, &code);
+}
+
+
+#define TDX_FUNCTION_SIZE(name) ((uint64_t)&__stop_sec_ ## name -\
+			   (uint64_t)&__start_sec_ ## name) \
+
+#define TDX_GUEST_FUNCTION__(name, section_name) \
+extern char *__start_sec_ ## name ; \
+extern char *__stop_sec_ ## name ; \
+static void \
+__attribute__((__flatten__, section(section_name))) name(void *arg)
+
+
+#define STRINGIFY2(x) #x
+#define STRINGIFY(x) STRINGIFY2(x)
+#define CONCAT2(a, b) a##b
+#define CONCAT(a, b) CONCAT2(a, b)
+
+
+#define TDX_GUEST_FUNCTION(name) \
+TDX_GUEST_FUNCTION__(name, STRINGIFY(CONCAT(sec_, name)))
+
 #endif  // KVM_LIB_TDX_H_
diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
new file mode 100644
index 000000000000..590e45aa7570
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <fcntl.h>
+#include <limits.h>
+#include <kvm_util.h>
+#include "../lib/x86_64/tdx.h"
+#include <linux/kvm.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <test_util.h>
+#include <unistd.h>
+#include <processor.h>
+#include <time.h>
+#include <sys/mman.h>
+#include<sys/wait.h>
+
+#define CHECK_GUEST_COMPLETION(VCPU)								\
+	(TEST_ASSERT(										\
+		((VCPU)->run->exit_reason == KVM_EXIT_IO) &&					\
+		((VCPU)->run->io.port == TDX_SUCCESS_PORT) &&					\
+		((VCPU)->run->io.size == 4) &&							\
+		((VCPU)->run->io.direction == TDX_IO_WRITE),					\
+		"Unexpected exit values while waiting for test complition: %u (%s) %d %d %d\n",	\
+		(VCPU)->run->exit_reason, exit_reason_str((VCPU)->run->exit_reason),		\
+		(VCPU)->run->io.port, (VCPU)->run->io.size, (VCPU)->run->io.direction))
+
+/*
+ * There might be multiple tests we are running and if one test fails, it will
+ * prevent the subsequent tests to run due to how tests are failing with
+ * TEST_ASSERT function. The run_in_new_process function will run a test in a
+ * new process context and wait for it to finish or fail to prevent TEST_ASSERT
+ * to kill the main testing process.
+ */
+void run_in_new_process(void (*func)(void))
+{
+	if (fork() == 0) {
+		func();
+		exit(0);
+	}
+	wait(NULL);
+}
+
+/*
+ * Verify that the TDX  is supported by the KVM.
+ */
+bool is_tdx_enabled(void)
+{
+	return !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_TDX_VM));
+}
+
+/*
+ * Do a dummy io exit to verify that the TD has been initialized correctly and
+ * guest can run some code inside.
+ */
+TDX_GUEST_FUNCTION(guest_dummy_exit)
+{
+	tdvmcall_success();
+}
+
+/*
+ * TD lifecycle test will create a TD which runs a dumy IO exit to verify that
+ * the guest TD has been created correctly.
+ */
+void verify_td_lifecycle(void)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+
+	printf("Verifying TD lifecycle:\n");
+	/* Create a TD VM with no memory.*/
+	vm = vm_create_tdx();
+
+	/* Allocate TD guest memory and initialize the TD.*/
+	initialize_td(vm);
+
+	/* Initialize the TD vcpu and copy the test code to the guest memory.*/
+	vcpu = vm_vcpu_add_tdx(vm, 0);
+
+	/* Setup and initialize VM memory */
+	prepare_source_image(vm, guest_dummy_exit,
+			     TDX_FUNCTION_SIZE(guest_dummy_exit), 0);
+	finalize_td_memory(vm);
+
+	vcpu_run(vcpu);
+	CHECK_GUEST_COMPLETION(vcpu);
+
+	kvm_vm_free(vm);
+	printf("\t ... PASSED\n");
+}
+
+int main(int argc, char **argv)
+{
+	if (!is_tdx_enabled()) {
+		print_skip("TDX is not supported by the KVM");
+		exit(KSFT_SKIP);
+	}
+
+	run_in_new_process(&verify_td_lifecycle);
+
+	return 0;
+}
-- 
2.37.2.789.g6183377224-goog


  parent reply	other threads:[~2022-08-30 22:20 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-30 22:19 [RFC PATCH v2 00/17] TDX KVM selftests Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 01/17] KVM: selftests: Add support for creating non-default type VMs Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 02/17] KVM: selftest: Add helper functions to create TDX VMs Sagi Shahar
2022-09-01  1:20   ` Isaku Yamahata
2022-09-01  1:22   ` Isaku Yamahata
2022-08-30 22:19 ` Sagi Shahar [this message]
2022-09-01  0:46   ` [RFC PATCH v2 03/17] KVM: selftest: Adding TDX life cycle test Isaku Yamahata
2022-09-01 14:37     ` Sean Christopherson
2022-08-30 22:19 ` [RFC PATCH v2 04/17] KVM: selftest: TDX: Add report_fatal_error test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 05/17] KVM: selftest: Adding test case for TDX port IO Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 06/17] KVM: selftest: TDX: Add basic TDX CPUID test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 07/17] KVM: selftest: TDX: Add basic get_td_vmcall_info test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 08/17] KVM: selftest: TDX: Add TDX IO writes test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 09/17] KVM: selftest: TDX: Add TDX IO reads test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 10/17] KVM: selftest: TDX: Add TDX MSR read/write tests Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 11/17] KVM: selftest: TDX: Add TDX HLT exit test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 12/17] KVM: selftest: TDX: Add TDX MMIO reads test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 13/17] KVM: selftest: TDX: Add TDX MMIO writes test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 14/17] KVM: selftest: TDX: Add TDX CPUID TDVMCALL test Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 15/17] KVM: selftest: TDX: Verify the behavior when host consumes a TD private memory Sagi Shahar
2022-08-30 22:19 ` [RFC PATCH v2 16/17] KVM: selftest: TDX: Add TDG.VP.INFO test Sagi Shahar
2022-08-30 22:20 ` [RFC PATCH v2 17/17] KVM: selftest: TDX: Add shared memory test Sagi Shahar
2022-09-01  1:28 ` [RFC PATCH v2 00/17] TDX KVM selftests Isaku Yamahata

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220830222000.709028-4-sagis@google.com \
    --to=sagis@google.com \
    --cc=aaronlewis@google.com \
    --cc=afranji@google.com \
    --cc=axelrasmussen@google.com \
    --cc=bgardon@google.com \
    --cc=borntraeger@de.ibm.com \
    --cc=dmatlack@google.com \
    --cc=drjones@redhat.com \
    --cc=eesposit@redhat.com \
    --cc=erdemaktas@google.com \
    --cc=eric.auger@redhat.com \
    --cc=isaku.yamahata@intel.com \
    --cc=jmattson@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=like.xu@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=maciej.szmigiero@oracle.com \
    --cc=marcorr@google.com \
    --cc=maz@kernel.org \
    --cc=oupton@google.com \
    --cc=pbonzini@redhat.com \
    --cc=peterx@redhat.com \
    --cc=pgonda@google.com \
    --cc=pshier@google.com \
    --cc=ricarkol@google.com \
    --cc=runanwang@google.com \
    --cc=seanjc@google.com \
    --cc=shuah@kernel.org \
    --cc=vkuznets@redhat.com \
    --cc=wangyanan55@huawei.com \
    --cc=wei.w.wang@intel.com \
    --cc=xiaoyao.li@intel.com \
    --cc=yang.zhong@intel.com \
    --cc=zhenzhong.duan@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.