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 17/17] KVM: selftest: TDX: Add shared memory test
Date: Tue, 30 Aug 2022 22:20:00 +0000	[thread overview]
Message-ID: <20220830222000.709028-18-sagis@google.com> (raw)
In-Reply-To: <20220830222000.709028-1-sagis@google.com>

From: Ryan Afranji <afranji@google.com>

Adds a test that sets up shared memory between the host and guest.

Signed-off-by: Ryan Afranji <afranji@google.com>
Signed-off-by: Sagi Shahar <sagis@google.com>
---
 tools/testing/selftests/kvm/lib/x86_64/tdx.h  |  38 +++++-
 .../selftests/kvm/lib/x86_64/tdx_lib.c        |  41 +++++-
 .../selftests/kvm/x86_64/tdx_vm_tests.c       | 124 ++++++++++++++++++
 3 files changed, 192 insertions(+), 11 deletions(-)

diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx.h b/tools/testing/selftests/kvm/lib/x86_64/tdx.h
index 7af2d189043f..be8564f4672d 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/tdx.h
+++ b/tools/testing/selftests/kvm/lib/x86_64/tdx.h
@@ -23,10 +23,21 @@
 
 /*
  * Max Page Table Size
- * To map 4GB memory region with 2MB pages, there needs to be 1 page for PML4,
- * 1 Page for PDPT, 4 pages for PD. Reserving 6 pages for PT.
+ * To map 4GB memory regions for each private and shared memory with 2MB pages,
+ * there needs to be 1 page for PML4, 1 Page for PDPT, 8 pages for PD. Reserving
+ * 10 pages for PT.
  */
-#define TDX_GUEST_NR_PT_PAGES (1 + 1 + 4)
+#define TDX_GUEST_NR_PT_PAGES (1 + 1 + 8)
+
+/*
+ * Guest Virtual Address Shared Bit
+ * TDX's shared bit is defined as the highest order bit in the GPA. Since the
+ * highest order bit allowed in the GPA may exceed the GVA's, a 1:1 mapping
+ * cannot be applied for shared memory. This value is a bit within the range
+ * [32 - 38] (0-indexed) that will designate a 4 GB region of GVAs that map the
+ * shared GPAs. This approach does not increase number of PML4 and PDPT pages.
+ */
+#define TDX_GUEST_VIRT_SHARED_BIT 32
 
 /*
  * Predefined GDTR values.
@@ -60,6 +71,7 @@
 #define TDX_VMCALL_INVALID_OPERAND 0x8000000000000000
 
 #define TDX_GET_TD_VM_CALL_INFO 0x10000
+#define TDX_MAP_GPA 0x10001
 #define TDX_REPORT_FATAL_ERROR 0x10003
 #define TDX_INSTRUCTION_CPUID 10
 #define TDX_INSTRUCTION_HLT 12
@@ -101,7 +113,7 @@ struct __packed tdx_gdtr {
 struct page_table {
 	uint64_t  pml4[512];
 	uint64_t  pdpt[512];
-	uint64_t  pd[4][512];
+	uint64_t  pd[8][512];
 };
 
 void add_td_memory(struct kvm_vm *vm, void *source_page,
@@ -411,6 +423,24 @@ static inline uint64_t tdcall_vp_info(uint64_t *rcx, uint64_t *rdx,
 	return regs.rax;
 }
 
+/*
+ * Execute MapGPA instruction.
+ */
+static inline uint64_t tdvmcall_map_gpa(uint64_t address, uint64_t size,
+					uint64_t *data_out)
+{
+	struct kvm_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+	regs.r11 = TDX_MAP_GPA;
+	regs.r12 = address;
+	regs.r13 = size;
+	regs.rcx = 0x3C00;
+	tdcall(&regs);
+	*data_out = regs.r11;
+	return regs.r10;
+}
+
 /*
  * 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.
diff --git a/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c b/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c
index dc9a44ae4064..23893949c3a1 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/tdx_lib.c
@@ -183,29 +183,56 @@ void build_gdtr_table(void *gdtr_target, void *gdt_target)
  * which will be used by the TDX guest when paging is enabled.
  * TODO: use virt_pg_map() functions to dynamically allocate the page tables.
  */
-void build_page_tables(void *pt_target, uint64_t  pml4_base_address)
+void build_page_tables(void *pt_target, uint64_t  pml4_base_address,
+		       uint64_t gpa_shared_bit)
 {
 	uint64_t i;
+	uint64_t shared_pdpt_index;
+	uint64_t gpa_shared_mask;
+	uint64_t *pde;
 	struct page_table *pt;
 
 	pt = malloc(sizeof(struct page_table));
 	TEST_ASSERT(pt != NULL, "Could not allocate memory for page tables!\n");
 	memset((void *) &(pt->pml4[0]), 0, sizeof(pt->pml4));
 	memset((void *) &(pt->pdpt[0]), 0, sizeof(pt->pdpt));
-	for (i = 0; i < 4; i++)
+	for (i = 0; i < 8; i++)
 		memset((void *) &(pt->pd[i][0]), 0, sizeof(pt->pd[i]));
 
+	/* Populate pml4 entry. */
 	pt->pml4[0] = (pml4_base_address + PAGE_SIZE) |
 		      _PAGE_PRESENT | _PAGE_RW;
+
+	/* Populate pdpt entries for private memory region. */
 	for (i = 0; i < 4; i++)
 		pt->pdpt[i] = (pml4_base_address + (i + 2) * PAGE_SIZE) |
-				_PAGE_PRESENT | _PAGE_RW;
+			      _PAGE_PRESENT | _PAGE_RW;
+
+	/* Index used in pdpt #0 to map to pd with guest virt shared bit set. */
+	static_assert(TDX_GUEST_VIRT_SHARED_BIT >= 32 &&
+		      TDX_GUEST_VIRT_SHARED_BIT <= 38,
+		      "Guest virtual shared bit must be in the range [32 - 38].\n");
+	shared_pdpt_index = 1 << (TDX_GUEST_VIRT_SHARED_BIT - 30);
 
-	uint64_t *pde = &(pt->pd[0][0]);
+	/* Populate pdpt entries for shared memory region. */
+	for (i = 0; i < 4; i++)
+		pt->pdpt[shared_pdpt_index + i] = (pml4_base_address + (i + 6) *
+						  PAGE_SIZE) | _PAGE_PRESENT |
+						  _PAGE_RW;
 
-	for (i = 0; i < sizeof(pt->pd) / sizeof(pt->pd[0][0]); i++, pde++)
+	/* Populate pd entries for private memory region. */
+	pde = &(pt->pd[0][0]);
+	for (i = 0; i < (sizeof(pt->pd) / sizeof(pt->pd[0][0])) / 2; i++, pde++)
 		*pde = (i << 21) | _PAGE_PRESENT | _PAGE_RW | _PAGE_PS;
-	memcpy(pt_target, pt, 6 * PAGE_SIZE);
+
+	/* Populate pd entries for shared memory region; set shared bit. */
+	pde = &(pt->pd[4][0]);
+	gpa_shared_mask = BIT_ULL(gpa_shared_bit);
+	for (i = 0; i < (sizeof(pt->pd) / sizeof(pt->pd[0][0])) / 2; i++, pde++)
+		*pde = gpa_shared_mask | (i << 21) | _PAGE_PRESENT | _PAGE_RW |
+		       _PAGE_PS;
+
+	memcpy(pt_target, pt, 10 * PAGE_SIZE);
 }
 
 static void
@@ -318,7 +345,7 @@ void prepare_source_image(struct kvm_vm *vm, void *guest_code,
 	guest_code_base =  gdt_address + (TDX_GUEST_STACK_NR_PAGES *
 					  PAGE_SIZE);
 
-	build_page_tables(pt_address, TDX_GUEST_PT_FIXED_ADDR);
+	build_page_tables(pt_address, TDX_GUEST_PT_FIXED_ADDR, vm->pa_bits - 1);
 	build_gdtr_table(gdtr_address, gdt_address);
 
 	/* reset vector code should end with int3 instructions.
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 8d49099e1ed8..a96abada54b6 100644
--- a/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
+++ b/tools/testing/selftests/kvm/x86_64/tdx_vm_tests.c
@@ -1515,6 +1515,129 @@ void verify_tdcall_vp_info(void)
 	printf("\t ... PASSED\n");
 }
 
+TDX_GUEST_FUNCTION(guest_shared_mem)
+{
+	uint64_t gpa_shared_mask;
+	uint64_t gva_shared_mask;
+	uint64_t shared_gpa;
+	uint64_t shared_gva;
+	uint64_t gpa_width;
+	uint64_t failed_gpa;
+	uint64_t ret;
+	uint64_t err;
+
+	gva_shared_mask = BIT_ULL(TDX_GUEST_VIRT_SHARED_BIT);
+	shared_gpa = 0x80000000;
+	shared_gva = gva_shared_mask | shared_gpa;
+
+	/* Read highest order physical bit to calculate shared mask. */
+	err = tdcall_vp_info(&gpa_width, 0, 0, 0, 0, 0);
+	if (err)
+		tdvmcall_fatal(err);
+
+	/* Map gpa as shared. */
+	gpa_shared_mask = BIT_ULL(gpa_width - 1);
+	ret = tdvmcall_map_gpa(shared_gpa | gpa_shared_mask, PAGE_SIZE,
+			       &failed_gpa);
+	if (ret)
+		tdvmcall_fatal(ret);
+
+	/* Write to shared memory. */
+	*(uint16_t *)shared_gva = 0x1234;
+	tdvmcall_success();
+
+	/* Read from shared memory; report to host. */
+	ret = tdvmcall_io(TDX_TEST_PORT, 2, TDX_IO_WRITE,
+			  (uint64_t *)shared_gva);
+	if (ret)
+		tdvmcall_fatal(ret);
+
+	tdvmcall_success();
+}
+
+void verify_shared_mem(void)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+	struct userspace_mem_region *region;
+	uint16_t guest_read_val;
+	uint64_t shared_gpa;
+	uint64_t shared_hva;
+	uint64_t shared_pages_num;
+	int ctr;
+
+	printf("Verifying shared memory\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);
+
+	/* Allocate shared memory. */
+	shared_gpa = 0x80000000;
+	shared_pages_num = 1;
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+				    shared_gpa, 1,
+				    shared_pages_num, 0);
+
+	/* Setup and initialize VM memory. */
+	prepare_source_image(vm, guest_shared_mem,
+			     TDX_FUNCTION_SIZE(guest_shared_mem), 0);
+	finalize_td_memory(vm);
+
+	/* Begin guest execution; guest writes to shared memory. */
+	printf("\t ... Starting guest execution\n");
+	vcpu_run(vcpu);
+	CHECK_GUEST_FAILURE(vcpu);
+
+	/* Get the host's shared memory address. */
+	shared_hva = 0;
+	hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) {
+		uint64_t region_guest_addr;
+
+		region_guest_addr = (uint64_t)region->region.guest_phys_addr;
+		if (region_guest_addr == (shared_gpa)) {
+			shared_hva = (uint64_t)region->host_mem;
+			break;
+		}
+	}
+	TEST_ASSERT(shared_hva != 0,
+		    "Guest address not found in guest memory regions\n");
+
+	/* Verify guest write -> host read succeeds. */
+	printf("\t ... Guest wrote 0x1234 to shared memory\n");
+	if (*(uint16_t *)shared_hva != 0x1234) {
+		printf("\t ... FAILED: Host read 0x%x instead of 0x1234\n",
+		       *(uint16_t *)shared_hva);
+	}
+	printf("\t ... Host read 0x%x from shared memory\n",
+	       *(uint16_t *)shared_hva);
+
+	/* Verify host write -> guest read succeeds. */
+	*((uint16_t *)shared_hva) = 0xABCD;
+	printf("\t ... Host wrote 0xabcd to shared memory\n");
+	vcpu_run(vcpu);
+	CHECK_GUEST_FAILURE(vcpu);
+	CHECK_IO(vcpu, TDX_TEST_PORT, 2, TDX_IO_WRITE);
+	guest_read_val = *(uint16_t *)((void *)vcpu->run + vcpu->run->io.data_offset);
+
+	if (guest_read_val != 0xABCD) {
+		printf("\t ... FAILED: Guest read 0x%x instead of 0xABCD\n",
+		       guest_read_val);
+		kvm_vm_free(vm);
+		return;
+	}
+	printf("\t ... Guest read 0x%x from shared memory\n",
+	       guest_read_val);
+
+	kvm_vm_free(vm);
+	printf("\t ... PASSED\n");
+}
+
 int main(int argc, char **argv)
 {
 	if (!is_tdx_enabled()) {
@@ -1537,6 +1660,7 @@ int main(int argc, char **argv)
 	run_in_new_process(&verify_mmio_writes);
 	run_in_new_process(&verify_host_reading_private_mem);
 	run_in_new_process(&verify_tdcall_vp_info);
+	run_in_new_process(&verify_shared_mem);
 
 	return 0;
 }
-- 
2.37.2.789.g6183377224-goog


  parent reply	other threads:[~2022-08-30 22:22 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 ` [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 ` Sagi Shahar [this message]
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-18-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.