]> www.infradead.org Git - users/hch/misc.git/commitdiff
x86/sev: Share implementation of MSR-based page state change
authorArd Biesheuvel <ardb@kernel.org>
Thu, 28 Aug 2025 10:22:10 +0000 (12:22 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Wed, 3 Sep 2025 15:58:19 +0000 (17:58 +0200)
Both the decompressor and the SEV startup code implement the exact same
sequence for invoking the MSR based communication protocol to effectuate
a page state change.

Before tweaking the internal APIs used in both versions, merge them and
share them so those tweaks are only needed in a single place.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/20250828102202.1849035-31-ardb+git@google.com
arch/x86/boot/compressed/sev.c
arch/x86/boot/startup/sev-shared.c
arch/x86/boot/startup/sev-startup.c

index f2b8dfbd453ccca35de8aff0d5ab5b4c29fb681b..6b62c75ea9117e80c22a3f017537e700e45c48a9 100644 (file)
@@ -60,46 +60,12 @@ static bool sev_snp_enabled(void)
        return sev_status & MSR_AMD64_SEV_SNP_ENABLED;
 }
 
-static void __page_state_change(unsigned long paddr, enum psc_op op)
-{
-       u64 val, msr;
-
-       /*
-        * If private -> shared then invalidate the page before requesting the
-        * state change in the RMP table.
-        */
-       if (op == SNP_PAGE_STATE_SHARED)
-               pvalidate_4k_page(paddr, paddr, false);
-
-       /* Save the current GHCB MSR value */
-       msr = sev_es_rd_ghcb_msr();
-
-       /* Issue VMGEXIT to change the page state in RMP table. */
-       sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op));
-       VMGEXIT();
-
-       /* Read the response of the VMGEXIT. */
-       val = sev_es_rd_ghcb_msr();
-       if ((GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP) || GHCB_MSR_PSC_RESP_VAL(val))
-               sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
-
-       /* Restore the GHCB MSR value */
-       sev_es_wr_ghcb_msr(msr);
-
-       /*
-        * Now that page state is changed in the RMP table, validate it so that it is
-        * consistent with the RMP entry.
-        */
-       if (op == SNP_PAGE_STATE_PRIVATE)
-               pvalidate_4k_page(paddr, paddr, true);
-}
-
 void snp_set_page_private(unsigned long paddr)
 {
        if (!sev_snp_enabled())
                return;
 
-       __page_state_change(paddr, SNP_PAGE_STATE_PRIVATE);
+       __page_state_change(paddr, paddr, SNP_PAGE_STATE_PRIVATE);
 }
 
 void snp_set_page_shared(unsigned long paddr)
@@ -107,7 +73,7 @@ void snp_set_page_shared(unsigned long paddr)
        if (!sev_snp_enabled())
                return;
 
-       __page_state_change(paddr, SNP_PAGE_STATE_SHARED);
+       __page_state_change(paddr, paddr, SNP_PAGE_STATE_SHARED);
 }
 
 bool early_setup_ghcb(void)
@@ -133,7 +99,7 @@ bool early_setup_ghcb(void)
 void snp_accept_memory(phys_addr_t start, phys_addr_t end)
 {
        for (phys_addr_t pa = start; pa < end; pa += PAGE_SIZE)
-               __page_state_change(pa, SNP_PAGE_STATE_PRIVATE);
+               __page_state_change(pa, pa, SNP_PAGE_STATE_PRIVATE);
 }
 
 void sev_es_shutdown_ghcb(void)
index 80d4fdada33a8224c1febf1464764138a5cd2089..00220d7b981b0bf1351104d134bf700e239934a9 100644 (file)
@@ -664,6 +664,41 @@ static void __head pvalidate_4k_page(unsigned long vaddr, unsigned long paddr,
                sev_evict_cache((void *)vaddr, 1);
 }
 
+static void __head __page_state_change(unsigned long vaddr, unsigned long paddr,
+                                      enum psc_op op)
+{
+       u64 val, msr;
+
+       /*
+        * If private -> shared then invalidate the page before requesting the
+        * state change in the RMP table.
+        */
+       if (op == SNP_PAGE_STATE_SHARED)
+               pvalidate_4k_page(vaddr, paddr, false);
+
+       /* Save the current GHCB MSR value */
+       msr = sev_es_rd_ghcb_msr();
+
+       /* Issue VMGEXIT to change the page state in RMP table. */
+       sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op));
+       VMGEXIT();
+
+       /* Read the response of the VMGEXIT. */
+       val = sev_es_rd_ghcb_msr();
+       if ((GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP) || GHCB_MSR_PSC_RESP_VAL(val))
+               sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
+
+       /* Restore the GHCB MSR value */
+       sev_es_wr_ghcb_msr(msr);
+
+       /*
+        * Now that page state is changed in the RMP table, validate it so that it is
+        * consistent with the RMP entry.
+        */
+       if (op == SNP_PAGE_STATE_PRIVATE)
+               pvalidate_4k_page(vaddr, paddr, true);
+}
+
 /*
  * Maintain the GPA of the SVSM Calling Area (CA) in order to utilize the SVSM
  * services needed when not running in VMPL0.
index 8a06f6026101321c0c46840977ee629d09221b61..5eb7d939ebd3456ad970fc24381dbb65e29fb688 100644 (file)
@@ -135,7 +135,6 @@ early_set_pages_state(unsigned long vaddr, unsigned long paddr,
                      unsigned long npages, enum psc_op op)
 {
        unsigned long paddr_end;
-       u64 val;
 
        vaddr = vaddr & PAGE_MASK;
 
@@ -143,37 +142,11 @@ early_set_pages_state(unsigned long vaddr, unsigned long paddr,
        paddr_end = paddr + (npages << PAGE_SHIFT);
 
        while (paddr < paddr_end) {
-               /* Page validation must be rescinded before changing to shared */
-               if (op == SNP_PAGE_STATE_SHARED)
-                       pvalidate_4k_page(vaddr, paddr, false);
-
-               /*
-                * Use the MSR protocol because this function can be called before
-                * the GHCB is established.
-                */
-               sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op));
-               VMGEXIT();
-
-               val = sev_es_rd_ghcb_msr();
-
-               if (GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP)
-                       goto e_term;
-
-               if (GHCB_MSR_PSC_RESP_VAL(val))
-                       goto e_term;
-
-               /* Page validation must be performed after changing to private */
-               if (op == SNP_PAGE_STATE_PRIVATE)
-                       pvalidate_4k_page(vaddr, paddr, true);
+               __page_state_change(vaddr, paddr, op);
 
                vaddr += PAGE_SIZE;
                paddr += PAGE_SIZE;
        }
-
-       return;
-
-e_term:
-       sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC);
 }
 
 void __head early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,