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@xxxxxxx> --- x86/amd_sev.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) 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); } -- 2.34.1