diff mbox series

[kvm-unit-tests,RFC,09/13] x86 AMD SEV-SNP: Test Shared->Private Page State Changes using GHCB MSR

Message ID 20240419125759.242870-10-papaluri@amd.com (mailing list archive)
State New, archived
Headers show
Series Introduce SEV-SNP Support | expand

Commit Message

Paluri, PavanKumar April 19, 2024, 12:57 p.m. UTC
The SEV-SNP guest VM issues page state change requests to hypervisor to
convert hypervisor-owned 4K shared pages back to private (guest-owned)
using GHCB MSR protocol. Guest then issues a 'pvalidate' instruction to
validate the pages after the conversions.

The purpose of this test is to determine whether the hypervisor changes
the page state to shared. After the conversion test, issue a re-validation
('pvalidate' with validated bit set) on one of the converted 4K pages to
ensure the page state is actually private.

It is important to note that the re-validation test cannot be performed
on a shared page ('pvalidate' with validated bit unset) as pvalidate
instruction will raise an undefined #PF exception as the page's C-bit
will be 0 during the guest page table walk, as mentioned in APM Vol-3,
PVALIDATE. Therefore, perform writes to the shared pages (with C-bit unset)
to ensure state of the pages are shared.

Signed-off-by: Pavan Kumar Paluri <papaluri@amd.com>
---
 x86/amd_sev.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 47 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/x86/amd_sev.c b/x86/amd_sev.c
index 71d1ee1cef91..31d15b49fc7a 100644
--- a/x86/amd_sev.c
+++ b/x86/amd_sev.c
@@ -206,8 +206,28 @@  static void set_pte_decrypted(unsigned long vaddr, int npages)
 	flush_tlb();
 }
 
-static efi_status_t sev_set_pages_state_msr_proto(unsigned long vaddr, int npages,
-						  int operation)
+static void set_pte_encrypted(unsigned long vaddr, int npages)
+{
+	pteval_t *pte;
+	unsigned long vaddr_end = vaddr + (npages * PAGE_SIZE);
+
+	while (vaddr < vaddr_end) {
+		pte = get_pte((pgd_t *)read_cr3(), (void *)vaddr);
+
+		if (!pte)
+			assert_msg(pte, "No pte found for vaddr 0x%lx", vaddr);
+
+		/* Set C-bit */
+		*pte |= get_amd_sev_c_bit_mask();
+
+		vaddr += PAGE_SIZE;
+	}
+
+	flush_tlb();
+}
+
+static efi_status_t sev_set_pages_state_msr_proto(unsigned long vaddr,
+						  int npages, int operation)
 {
 	efi_status_t status;
 
@@ -226,6 +246,16 @@  static efi_status_t sev_set_pages_state_msr_proto(unsigned long vaddr, int npage
 		}
 
 		set_pte_decrypted(vaddr, npages);
+
+	} else {
+		set_pte_encrypted(vaddr, npages);
+
+		status = __sev_set_pages_state_msr_proto(vaddr, npages,
+							 operation);
+		if (status != ES_OK) {
+			printf("Page state change (Shared->Private failure.\n");
+			return status;
+		}
 	}
 
 	return ES_OK;
@@ -358,6 +388,21 @@  static void test_sev_psc_ghcb_msr(void)
 		       1 << SNP_PSC_ALLOC_ORDER);
 	}
 
+	report_info("Shared->Private conversion test using GHCB MSR");
+	status = sev_set_pages_state_msr_proto((unsigned long)vaddr,
+					       1 << SNP_PSC_ALLOC_ORDER,
+					       SNP_PAGE_STATE_PRIVATE);
+
+	report(status == ES_OK, "Shared->Private Page State Change");
+
+	/*
+	 * After performing shared->private test, ensure the page is in
+	 * private state by issuing a pvalidate on a 4K page.
+	 */
+	report(is_validated_private_page((unsigned long)vaddr,
+					 RMP_PG_SIZE_4K, true),
+	       "Expected page state: Private");
+
 	/* Cleanup */
 	free_pages_by_order(vaddr, SNP_PSC_ALLOC_ORDER);
 }