@@ -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);
}
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(-)