Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

x86/sev: Share implementation of MSR-based page state change

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

authored by

Ard Biesheuvel and committed by
Borislav Petkov (AMD)
d5949ea5 a5f03880

+39 -65
+3 -37
arch/x86/boot/compressed/sev.c
··· 60 60 return sev_status & MSR_AMD64_SEV_SNP_ENABLED; 61 61 } 62 62 63 - static void __page_state_change(unsigned long paddr, enum psc_op op) 64 - { 65 - u64 val, msr; 66 - 67 - /* 68 - * If private -> shared then invalidate the page before requesting the 69 - * state change in the RMP table. 70 - */ 71 - if (op == SNP_PAGE_STATE_SHARED) 72 - pvalidate_4k_page(paddr, paddr, false); 73 - 74 - /* Save the current GHCB MSR value */ 75 - msr = sev_es_rd_ghcb_msr(); 76 - 77 - /* Issue VMGEXIT to change the page state in RMP table. */ 78 - sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op)); 79 - VMGEXIT(); 80 - 81 - /* Read the response of the VMGEXIT. */ 82 - val = sev_es_rd_ghcb_msr(); 83 - if ((GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP) || GHCB_MSR_PSC_RESP_VAL(val)) 84 - sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC); 85 - 86 - /* Restore the GHCB MSR value */ 87 - sev_es_wr_ghcb_msr(msr); 88 - 89 - /* 90 - * Now that page state is changed in the RMP table, validate it so that it is 91 - * consistent with the RMP entry. 92 - */ 93 - if (op == SNP_PAGE_STATE_PRIVATE) 94 - pvalidate_4k_page(paddr, paddr, true); 95 - } 96 - 97 63 void snp_set_page_private(unsigned long paddr) 98 64 { 99 65 if (!sev_snp_enabled()) 100 66 return; 101 67 102 - __page_state_change(paddr, SNP_PAGE_STATE_PRIVATE); 68 + __page_state_change(paddr, paddr, SNP_PAGE_STATE_PRIVATE); 103 69 } 104 70 105 71 void snp_set_page_shared(unsigned long paddr) ··· 73 107 if (!sev_snp_enabled()) 74 108 return; 75 109 76 - __page_state_change(paddr, SNP_PAGE_STATE_SHARED); 110 + __page_state_change(paddr, paddr, SNP_PAGE_STATE_SHARED); 77 111 } 78 112 79 113 bool early_setup_ghcb(void) ··· 99 133 void snp_accept_memory(phys_addr_t start, phys_addr_t end) 100 134 { 101 135 for (phys_addr_t pa = start; pa < end; pa += PAGE_SIZE) 102 - __page_state_change(pa, SNP_PAGE_STATE_PRIVATE); 136 + __page_state_change(pa, pa, SNP_PAGE_STATE_PRIVATE); 103 137 } 104 138 105 139 void sev_es_shutdown_ghcb(void)
+35
arch/x86/boot/startup/sev-shared.c
··· 664 664 sev_evict_cache((void *)vaddr, 1); 665 665 } 666 666 667 + static void __head __page_state_change(unsigned long vaddr, unsigned long paddr, 668 + enum psc_op op) 669 + { 670 + u64 val, msr; 671 + 672 + /* 673 + * If private -> shared then invalidate the page before requesting the 674 + * state change in the RMP table. 675 + */ 676 + if (op == SNP_PAGE_STATE_SHARED) 677 + pvalidate_4k_page(vaddr, paddr, false); 678 + 679 + /* Save the current GHCB MSR value */ 680 + msr = sev_es_rd_ghcb_msr(); 681 + 682 + /* Issue VMGEXIT to change the page state in RMP table. */ 683 + sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op)); 684 + VMGEXIT(); 685 + 686 + /* Read the response of the VMGEXIT. */ 687 + val = sev_es_rd_ghcb_msr(); 688 + if ((GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP) || GHCB_MSR_PSC_RESP_VAL(val)) 689 + sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC); 690 + 691 + /* Restore the GHCB MSR value */ 692 + sev_es_wr_ghcb_msr(msr); 693 + 694 + /* 695 + * Now that page state is changed in the RMP table, validate it so that it is 696 + * consistent with the RMP entry. 697 + */ 698 + if (op == SNP_PAGE_STATE_PRIVATE) 699 + pvalidate_4k_page(vaddr, paddr, true); 700 + } 701 + 667 702 /* 668 703 * Maintain the GPA of the SVSM Calling Area (CA) in order to utilize the SVSM 669 704 * services needed when not running in VMPL0.
+1 -28
arch/x86/boot/startup/sev-startup.c
··· 135 135 unsigned long npages, enum psc_op op) 136 136 { 137 137 unsigned long paddr_end; 138 - u64 val; 139 138 140 139 vaddr = vaddr & PAGE_MASK; 141 140 ··· 142 143 paddr_end = paddr + (npages << PAGE_SHIFT); 143 144 144 145 while (paddr < paddr_end) { 145 - /* Page validation must be rescinded before changing to shared */ 146 - if (op == SNP_PAGE_STATE_SHARED) 147 - pvalidate_4k_page(vaddr, paddr, false); 148 - 149 - /* 150 - * Use the MSR protocol because this function can be called before 151 - * the GHCB is established. 152 - */ 153 - sev_es_wr_ghcb_msr(GHCB_MSR_PSC_REQ_GFN(paddr >> PAGE_SHIFT, op)); 154 - VMGEXIT(); 155 - 156 - val = sev_es_rd_ghcb_msr(); 157 - 158 - if (GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP) 159 - goto e_term; 160 - 161 - if (GHCB_MSR_PSC_RESP_VAL(val)) 162 - goto e_term; 163 - 164 - /* Page validation must be performed after changing to private */ 165 - if (op == SNP_PAGE_STATE_PRIVATE) 166 - pvalidate_4k_page(vaddr, paddr, true); 146 + __page_state_change(vaddr, paddr, op); 167 147 168 148 vaddr += PAGE_SIZE; 169 149 paddr += PAGE_SIZE; 170 150 } 171 - 172 - return; 173 - 174 - e_term: 175 - sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PSC); 176 151 } 177 152 178 153 void __head early_snp_set_memory_private(unsigned long vaddr, unsigned long paddr,