Add snp_unaccept_memory() and wire it up to arch_unaccept_memory() and
arch_has_unaccept_memory() on AMD SEV-SNP guests.

When memory ranges are dynamically unaccepted (such as during
virtio-balloon inflation or free page reporting), snp_unaccept_memory()
invokes set_pages_state(..., SNP_PAGE_STATE_SHARED). This call rescinds
guest RMP validation via PVALIDATE(..., validate=false), handling 2MB
PMD pages with automatic fallback to 4KB pages on RMP size mismatch.
snp_unaccept_memory() -> set_pages_state() also issues a GHCB Page State
Change request so the hypervisor transitions the range from private to
shared symmetrically with snp_accept_memory().

Signed-off-by: Kevin Loughlin <[email protected]>
---
 arch/x86/coco/sev/core.c                 | 13 +++++++++++++
 arch/x86/include/asm/sev.h               |  2 ++
 arch/x86/include/asm/unaccepted_memory.h | 14 ++++++++++++++
 3 files changed, 29 insertions(+)

diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index eb2e853e950a..3f8809bae14a 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -432,6 +432,19 @@ void snp_accept_memory(phys_addr_t start, phys_addr_t end)
        set_pages_state(vaddr, npages, SNP_PAGE_STATE_PRIVATE);
 }
 
+void snp_unaccept_memory(phys_addr_t start, phys_addr_t end)
+{
+       unsigned long vaddr, npages;
+
+       if (!cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+               return;
+
+       vaddr = (unsigned long)__va(start);
+       npages = (end - start) >> PAGE_SHIFT;
+
+       set_pages_state(vaddr, npages, SNP_PAGE_STATE_SHARED);
+}
+
 static int vmgexit_ap_control(u64 event, struct sev_es_save_area *vmsa, u32 
apic_id)
 {
        bool create = event != SVM_VMGEXIT_AP_DESTROY;
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index c7ea9845351e..464a721f8889 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h
@@ -514,6 +514,7 @@ bool snp_init(struct boot_params *bp);
 void snp_dmi_setup(void);
 int snp_issue_svsm_attest_req(u64 call_id, struct svsm_call *call, struct 
svsm_attest_call *input);
 void snp_accept_memory(phys_addr_t start, phys_addr_t end);
+void snp_unaccept_memory(phys_addr_t start, phys_addr_t end);
 u64 snp_get_unsupported_features(u64 status);
 u64 sev_get_status(void);
 void sev_show_status(void);
@@ -624,6 +625,7 @@ static inline int snp_issue_svsm_attest_req(u64 call_id, 
struct svsm_call *call,
        return -ENOTTY;
 }
 static inline void snp_accept_memory(phys_addr_t start, phys_addr_t end) { }
+static inline void snp_unaccept_memory(phys_addr_t start, phys_addr_t end) { }
 static inline u64 snp_get_unsupported_features(u64 status) { return 0; }
 static inline u64 sev_get_status(void) { return 0; }
 static inline void sev_show_status(void) { }
diff --git a/arch/x86/include/asm/unaccepted_memory.h 
b/arch/x86/include/asm/unaccepted_memory.h
index f5937e9866ac..931d1388973e 100644
--- a/arch/x86/include/asm/unaccepted_memory.h
+++ b/arch/x86/include/asm/unaccepted_memory.h
@@ -18,6 +18,20 @@ static inline void arch_accept_memory(phys_addr_t start, 
phys_addr_t end)
        }
 }
 
+static inline bool arch_has_unaccept_memory(void)
+{
+       return cc_platform_has(CC_ATTR_GUEST_SEV_SNP);
+}
+
+static inline void arch_unaccept_memory(phys_addr_t start, phys_addr_t end)
+{
+       /* Platform-specific memory-unacceptance call goes here */
+       if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP))
+               snp_unaccept_memory(start, end);
+       else
+               WARN_ONCE(1, "Cannot unaccept memory: unsupported platform\n");
+}
+
 static inline struct efi_unaccepted_memory *efi_get_unaccepted_table(void)
 {
        if (efi.unaccepted == EFI_INVALID_TABLE_ADDR)
-- 
2.56.0.307.g5fe7bd680c-goog


Reply via email to