The test performs the following actions: 1. Allocates a 2M private page (512 4K entries) and performs 2M private to shared conversion. 2. Performs a write operation on these un-encrypted pages. 3. Performs partial page state changes (shared->private) on first 256 sub-pages and conducts a re-validation ('pvalidate') check on one of these entries to ensure its state has been changed to private. 4. Performs write test on the other set of sub-pages whose state is shared. 5. Performs PSC from 2M intermixed state to private, backed up with a re-validation check on the 2M range to ensure successfull conversion. 6. Performs PSC from 2M private to 2M shared followed by a write operation to ensure the 2M page is successfully changed to shared. The main goal of this test is to ensure 2MB page state changes are handled properly even if the 2MB range is a mix of private/shared pages. Suggested-by: Michael Roth <michael.roth@xxxxxxx> Signed-off-by: Pavan Kumar Paluri <papaluri@xxxxxxx> --- x86/amd_sev.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/x86/amd_sev.c b/x86/amd_sev.c index 7b53ef9c44d0..94944fb80a70 100644 --- a/x86/amd_sev.c +++ b/x86/amd_sev.c @@ -657,6 +657,32 @@ static void __test_sev_psc_private(unsigned long vaddr, struct ghcb *ghcb, "Expected 2M page state: Private"); } +static void __test_sev_psc_shared(unsigned long vaddr, struct ghcb *ghcb, + bool large_page, pteval_t *pte) +{ + allow_noupdate = true; + + set_pte_encrypted((unsigned long)vaddr, 1 << INTERMIX_PSC_ORDER); + + /* Convert the intermixed 2M range to 2M private */ + sev_set_pages_state(vaddr, 512, SNP_PAGE_STATE_PRIVATE, ghcb, + large_page); + + allow_noupdate = false; + + report(is_validated_private_page(vaddr, large_page, 1), + "Expected 2M page state: Private"); + + /* 2M private->shared conversion */ + sev_set_pages_state(vaddr, 512, SNP_PAGE_STATE_SHARED, ghcb, + large_page); + + set_pte_decrypted((unsigned long)vaddr, 1 << INTERMIX_PSC_ORDER); + + report(!test_write((unsigned long)vaddr, 512), + "Write to a 2M un-encrypted range"); +} + static void test_sev_psc_intermix(bool is_private) { unsigned long *vm_page; @@ -714,6 +740,9 @@ static void test_sev_psc_intermix(bool is_private) if (is_private) __test_sev_psc_private((unsigned long)vm_page, ghcb, large_page, pte); + else + __test_sev_psc_shared((unsigned long)vm_page, ghcb, + large_page, pte); /* Cleanup */ free_pages_by_order(vm_page, INTERMIX_PSC_ORDER); @@ -724,6 +753,11 @@ static void test_sev_psc_intermix_to_private(void) test_sev_psc_intermix(true); } +static void test_sev_psc_intermix_to_shared(void) +{ + test_sev_psc_intermix(false); +} + int main(void) { int rtn; @@ -738,6 +772,7 @@ int main(void) test_sev_psc_ghcb_msr(); test_sev_psc_ghcb_nae(); test_sev_psc_intermix_to_private(); + test_sev_psc_intermix_to_shared(); } return report_summary(); -- 2.34.1