diff mbox series

[RFC,13/16] KVM: selftests: add support for creating SEV-SNP guests

Message ID 20211005234459.430873-14-michael.roth@amd.com (mailing list archive)
State New
Headers show
Series KVM: selftests: Add tests for SEV, SEV-ES, and SEV-SNP guests | expand

Commit Message

Michael Roth Oct. 5, 2021, 11:44 p.m. UTC
SEV-SNP uses an entirely different set of KVM_SEV_* ioctls to manage
guests. The needed vm_memcrypt callbacks are different as well. Address
these differences by extending the SEV library with a new set of
interfaces specific to creating/managing SEV-SNP guests.

These guests will still use a struct sev_vm under the covers, so some
existing sev_*() helpers are still applicable.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 .../selftests/kvm/include/x86_64/sev.h        |  8 ++
 tools/testing/selftests/kvm/lib/x86_64/sev.c  | 77 ++++++++++++++++++-
 2 files changed, 82 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/tools/testing/selftests/kvm/include/x86_64/sev.h b/tools/testing/selftests/kvm/include/x86_64/sev.h
index d2f41b131ecc..f3e088c03bdd 100644
--- a/tools/testing/selftests/kvm/include/x86_64/sev.h
+++ b/tools/testing/selftests/kvm/include/x86_64/sev.h
@@ -18,6 +18,10 @@ 
 #define SEV_POLICY_NO_DBG	(1UL << 0)
 #define SEV_POLICY_ES		(1UL << 2)
 
+#define SNP_POLICY_SMT		(1ULL << 16)
+#define SNP_POLICY_RSVD		(1ULL << 17)
+#define SNP_POLICY_DBG		(1ULL << 19)
+
 #define SEV_GUEST_ASSERT(sync, token, _cond) do {	\
 	if (!(_cond))					\
 		sev_guest_abort(sync, token, 0);	\
@@ -59,4 +63,8 @@  void sev_vm_launch(struct sev_vm *sev);
 void sev_vm_measure(struct sev_vm *sev, uint8_t *measurement);
 void sev_vm_launch_finish(struct sev_vm *sev);
 
+struct sev_vm *sev_snp_vm_create(uint64_t policy, uint64_t npages);
+void sev_snp_vm_free(struct sev_vm *sev);
+void sev_snp_vm_launch(struct sev_vm *sev);
+
 #endif /* SELFTEST_KVM_SEV_H */
diff --git a/tools/testing/selftests/kvm/lib/x86_64/sev.c b/tools/testing/selftests/kvm/lib/x86_64/sev.c
index d01b0f637ced..939d7d5dff41 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/sev.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/sev.c
@@ -20,6 +20,7 @@  struct sev_vm {
 	int fd;
 	int enc_bit;
 	uint32_t sev_policy;
+	uint64_t snp_policy;
 };
 
 /* Helpers for coordinating between guests and test harness. */
@@ -119,6 +120,12 @@  void kvm_sev_ioctl(struct sev_vm *sev, int cmd, void *data)
 
 /* Local helpers. */
 
+static bool sev_snp_enabled(struct sev_vm *sev)
+{
+	/* RSVD is always 1 for SNP guests. */
+	return sev->snp_policy & SNP_POLICY_RSVD;
+}
+
 static void
 sev_register_user_range(struct sev_vm *sev, void *hva, uint64_t size)
 {
@@ -147,6 +154,21 @@  sev_encrypt_phy_range(struct sev_vm *sev, vm_paddr_t gpa, uint64_t size)
 	kvm_sev_ioctl(sev, KVM_SEV_LAUNCH_UPDATE_DATA, &ksev_update_data);
 }
 
+static void
+sev_snp_encrypt_phy_range(struct sev_vm *sev, vm_paddr_t gpa, uint64_t size)
+{
+	struct kvm_sev_snp_launch_update update_data = {0};
+
+	pr_debug("encrypt_phy_range: addr: 0x%lx, size: %lu\n", gpa, size);
+
+	update_data.uaddr = (__u64)addr_gpa2hva(sev->vm, gpa);
+	update_data.start_gfn = gpa >> PAGE_SHIFT;
+	update_data.len = size;
+	update_data.page_type = KVM_SEV_SNP_PAGE_TYPE_NORMAL;
+
+	kvm_sev_ioctl(sev, KVM_SEV_SNP_LAUNCH_UPDATE, &update_data);
+}
+
 static void sev_encrypt(struct sev_vm *sev)
 {
 	struct sparsebit *enc_phy_pages;
@@ -171,9 +193,14 @@  static void sev_encrypt(struct sev_vm *sev)
 		if (pg_cnt <= 0)
 			pg_cnt = 1;
 
-		sev_encrypt_phy_range(sev,
-				      gpa_start + pg * vm_get_page_size(vm),
-				      pg_cnt * vm_get_page_size(vm));
+		if (sev_snp_enabled(sev))
+			sev_snp_encrypt_phy_range(sev,
+						  gpa_start + pg * vm_get_page_size(vm),
+						  pg_cnt * vm_get_page_size(vm));
+		else
+			sev_encrypt_phy_range(sev,
+					      gpa_start + pg * vm_get_page_size(vm),
+					      pg_cnt * vm_get_page_size(vm));
 		pg += pg_cnt;
 	}
 
@@ -308,3 +335,47 @@  void sev_vm_launch_finish(struct sev_vm *sev)
 	TEST_ASSERT(ksev_status.state == SEV_GSTATE_RUNNING,
 		    "Unexpected guest state: %d", ksev_status.state);
 }
+
+/* SEV-SNP VM implementation. */
+
+struct sev_vm *sev_snp_vm_create(uint64_t policy, uint64_t npages)
+{
+	struct kvm_snp_init init = {0};
+	struct sev_vm *sev;
+	struct kvm_vm *vm;
+
+	vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR);
+	sev = sev_common_create(vm);
+	if (!sev)
+		return NULL;
+	sev->snp_policy = policy | SNP_POLICY_RSVD;
+
+	kvm_sev_ioctl(sev, KVM_SEV_SNP_INIT, &init);
+	vm_set_memory_encryption(vm, true, true, sev->enc_bit);
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, npages, 0);
+	sev_register_user_range(sev, addr_gpa2hva(vm, 0), npages * vm_get_page_size(vm));
+
+	pr_info("SEV-SNP guest created, policy: 0x%lx, size: %lu KB\n",
+		sev->snp_policy, npages * vm_get_page_size(vm) / 1024);
+
+	return sev;
+}
+
+void sev_snp_vm_free(struct sev_vm *sev)
+{
+	kvm_vm_free(sev->vm);
+	sev_common_free(sev);
+}
+
+void sev_snp_vm_launch(struct sev_vm *sev)
+{
+	struct kvm_sev_snp_launch_start launch_start = {0};
+	struct kvm_sev_snp_launch_update launch_finish = {0};
+
+	launch_start.policy = sev->snp_policy;
+	kvm_sev_ioctl(sev, KVM_SEV_SNP_LAUNCH_START, &launch_start);
+
+	sev_encrypt(sev);
+
+	kvm_sev_ioctl(sev, KVM_SEV_SNP_LAUNCH_FINISH, &launch_finish);
+}