linux-kernel.vger.kernel.org archive mirror
 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 06/17] KVM: selftest: TDX: Add basic TDX CPUID test
Date: Tue, 30 Aug 2022 22:19:49 +0000	[thread overview]
Message-ID: <20220830222000.709028-7-sagis@google.com> (raw)
In-Reply-To: <20220830222000.709028-1-sagis@google.com>

The test reads CPUID values from inside a TD VM and compare them
to expected values.

The test targets CPUID values which are virtualized as "As Configured",
"As Configured (if Native)", "Calculated", "Fixed" and "Native"
according to the TDX spec.

Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/lib/x86_64/tdx.h  |  13 ++
 .../selftests/kvm/x86_64/tdx_vm_tests.c       | 132 ++++++++++++++++++
 2 files changed, 145 insertions(+)

diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/selftests/kvm/lib/x86_64/tdx.h
index c78dba1af14f..a28d15417d3e 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h
+++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h
@@ -56,6 +56,7 @@
 
 #define TDX_SUCCESS_PORT 0x30
 #define TDX_TEST_PORT 0x31
+#define TDX_DATA_REPORT_PORT 0x32
 #define TDX_IO_READ 0
 #define TDX_IO_WRITE 1
 
@@ -231,6 +232,18 @@ static inline void tdvmcall_fatal(uint64_t error_code)
 	tdcall(&regs);
 }
 
+/*
+ * Reports a 32 bit value from the guest to user space using a TDVM IO call.
+ * Data is reported on port TDX_DATA_REPORT_PORT.
+ */
+static inline uint64_t tdvm_report_to_user_space(uint32_t data)
+{
+	// Need to upcast data to match tdvmcall_io signature.
+	uint64_t data_64 = data;
+
+	return tdvmcall_io(TDX_DATA_REPORT_PORT, /*size=*/4, TDX_IO_WRITE, &data_64);
+}
+
 #define TDX_FUNCTION_SIZE(name) ((uint64_t)&__stop_sec_ ## name -\
 			   (uint64_t)&__start_sec_ ## name) \
 
diff --git a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
index a93629cfd13f..3f51f936ea5a 100644
--- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
+++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
@@ -77,6 +77,27 @@ bool is_tdx_enabled(void)
 	return !!(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_TDX_VM));
 }
 
+/*
+ * Find a specific CPUID entry.
+ */
+static struct kvm_cpuid_entry2 *
+find_cpuid_entry(struct tdx_cpuid_data cpuid_data, uint32_t function,
+		 uint32_t index)
+{
+	struct kvm_cpuid_entry2 *e;
+	int i;
+
+	for (i = 0; i < cpuid_data.cpuid.nent; i++) {
+		e = &cpuid_data.entries[i];
+
+		if (e->function == function &&
+		    (e->index == index ||
+		     !(e->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX)))
+			return e;
+	}
+	return NULL;
+}
+
 /*
  * Do a dummy io exit to verify that the TD has been initialized correctly and
  * guest can run some code inside.
@@ -251,6 +272,116 @@ void verify_td_ioexit(void)
 	printf("\t ... PASSED\n");
 }
 
+/*
+ * Verifies CPUID functionality by reading CPUID values in guest. The guest
+ * will then send the values to userspace using an IO write to be checked
+ * against the expected values.
+ */
+TDX_GUEST_FUNCTION(guest_code_cpuid)
+{
+	uint64_t err;
+	uint32_t eax, ebx, edx, ecx;
+
+	// Read CPUID leaf 0x1.
+	cpuid(1, &eax, &ebx, &ecx, &edx);
+
+	err = tdvm_report_to_user_space(ebx);
+	if (err)
+		tdvmcall_fatal(err);
+
+	err = tdvm_report_to_user_space(ecx);
+	if (err)
+		tdvmcall_fatal(err);
+
+	tdvmcall_success();
+}
+
+void verify_td_cpuid(void)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	uint32_t ebx, ecx;
+	struct kvm_cpuid_entry2 *cpuid_entry;
+	struct tdx_cpuid_data cpuid_data;
+	uint32_t guest_clflush_line_size;
+	uint32_t guest_max_addressable_ids, host_max_addressable_ids;
+	uint32_t guest_sse3_enabled;
+	uint32_t guest_fma_enabled;
+	uint32_t guest_initial_apic_id;
+	int ret;
+
+	printf("Verifying TD CPUID:\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_code_cpuid,
+			     TDX_FUNCTION_SIZE(guest_code_cpuid), 0);
+	finalize_td_memory(vm);
+
+	/* Wait for guest to report ebx value */
+	vcpu_run(vcpu);
+	CHECK_GUEST_FAILURE(vcpu);
+	CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE);
+	ebx = *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset);
+
+	/* Wait for guest to report either ecx value or error */
+	vcpu_run(vcpu);
+	CHECK_GUEST_FAILURE(vcpu);
+	CHECK_IO(vcpu, TDX_DATA_REPORT_PORT, 4, TDX_IO_WRITE);
+	ecx = *(uint32_t *)((void *)vcpu->run + vcpu->run->io.data_offset);
+
+	/* Wait for guest to complete execution */
+	vcpu_run(vcpu);
+	CHECK_GUEST_FAILURE(vcpu);
+	CHECK_GUEST_COMPLETION(vcpu);
+
+	/* Verify the CPUID values we got from the guest. */
+	printf("\t ... Verifying CPUID values from guest\n");
+
+	/* Get KVM CPUIDs for reference */
+	memset(&cpuid_data, 0, sizeof(cpuid_data));
+	cpuid_data.cpuid.nent = KVM_MAX_CPUID_ENTRIES;
+	ret = ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_CPUID, &cpuid_data);
+	TEST_ASSERT(!ret, "KVM_GET_SUPPORTED_CPUID failed\n");
+	cpuid_entry = find_cpuid_entry(cpuid_data, 1, 0);
+	TEST_ASSERT(cpuid_entry, "CPUID entry missing\n");
+
+	host_max_addressable_ids = (cpuid_entry->ebx >> 16) & 0xFF;
+
+	guest_sse3_enabled = ecx & 0x1;  // Native
+	guest_clflush_line_size = (ebx >> 8) & 0xFF;  // Fixed
+	guest_max_addressable_ids = (ebx >> 16) & 0xFF;  // As Configured
+	guest_fma_enabled = (ecx >> 12) & 0x1;  // As Configured (if Native)
+	guest_initial_apic_id = (ebx >> 24) & 0xFF;  // Calculated
+
+	ASSERT_EQ(guest_sse3_enabled, 1);
+	ASSERT_EQ(guest_clflush_line_size, 8);
+	ASSERT_EQ(guest_max_addressable_ids, host_max_addressable_ids);
+
+	/* TODO: This only tests the native value. To properly test
+	 * "As Configured (if Native)" we need to override this value
+	 * in the TD params
+	 */
+	ASSERT_EQ(guest_fma_enabled, 1);
+
+	/* TODO: guest_initial_apic_id is calculated based on the number of
+	 * VCPUs in the TD. From the spec: "Virtual CPU index, starting from 0
+	 * and allocated sequentially on each successful TDH.VP.INIT"
+	 * To test non-trivial values we either need a TD with multiple VCPUs
+	 * or to pick a different calculated value.
+	 */
+	ASSERT_EQ(guest_initial_apic_id, 0);
+
+	kvm_vm_free(vm);
+	printf("\t ... PASSED\n");
+}
 
 int main(int argc, char **argv)
 {
@@ -262,6 +393,7 @@ int main(int argc, char **argv)
 	run_in_new_process(&verify_td_lifecycle);
 	run_in_new_process(&verify_report_fatal_error);
 	run_in_new_process(&verify_td_ioexit);
+	run_in_new_process(&verify_td_cpuid);
 
 	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 ` [RFC PATCH v2 03/17] KVM: selftest: Adding TDX life cycle test Sagi Shahar
2022-09-01  0:46   ` 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 ` Sagi Shahar [this message]
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-7-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).