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
