@@ -262,6 +262,21 @@ static void sev_decommission(unsigned int handle)
262262 sev_guest_decommission (& decommission , NULL );
263263}
264264
265+ /*
266+ * Transition a page to hypervisor-owned/shared state in the RMP table. This
267+ * should not fail under normal conditions, but leak the page should that
268+ * happen since it will no longer be usable by the host due to RMP protections.
269+ */
270+ static int kvm_rmp_make_shared (struct kvm * kvm , u64 pfn , enum pg_level level )
271+ {
272+ if (KVM_BUG_ON (rmp_make_shared (pfn , level ), kvm )) {
273+ snp_leak_pages (pfn , page_level_size (level ) >> PAGE_SHIFT );
274+ return - EIO ;
275+ }
276+
277+ return 0 ;
278+ }
279+
265280/*
266281 * Certain page-states, such as Pre-Guest and Firmware pages (as documented
267282 * in Chapter 5 of the SEV-SNP Firmware ABI under "Page States") cannot be
@@ -271,32 +286,25 @@ static void sev_decommission(unsigned int handle)
271286 * Until they are reclaimed and subsequently transitioned via RMPUPDATE, they
272287 * might not be usable by the host due to being set as immutable or still
273288 * being associated with a guest ASID.
289+ *
290+ * Bug the VM and leak the page if reclaim fails, or if the RMP entry can't be
291+ * converted back to shared, as the page is no longer usable due to RMP
292+ * protections, and it's infeasible for the guest to continue on.
274293 */
275- static int snp_page_reclaim (u64 pfn )
294+ static int snp_page_reclaim (struct kvm * kvm , u64 pfn )
276295{
277296 struct sev_data_snp_page_reclaim data = {0 };
278- int err , rc ;
297+ int fw_err , rc ;
279298
280299 data .paddr = __sme_set (pfn << PAGE_SHIFT );
281- rc = sev_do_cmd (SEV_CMD_SNP_PAGE_RECLAIM , & data , & err );
282- if (WARN_ONCE (rc , "Failed to reclaim PFN %llx" , pfn ))
300+ rc = sev_do_cmd (SEV_CMD_SNP_PAGE_RECLAIM , & data , & fw_err );
301+ if (KVM_BUG (rc , kvm , "Failed to reclaim PFN %llx, rc %d fw_err %d " , pfn , rc , fw_err )) {
283302 snp_leak_pages (pfn , 1 );
303+ return - EIO ;
304+ }
284305
285- return rc ;
286- }
287-
288- /*
289- * Transition a page to hypervisor-owned/shared state in the RMP table. This
290- * should not fail under normal conditions, but leak the page should that
291- * happen since it will no longer be usable by the host due to RMP protections.
292- */
293- static int host_rmp_make_shared (u64 pfn , enum pg_level level )
294- {
295- int rc ;
296-
297- rc = rmp_make_shared (pfn , level );
298- if (WARN_ON_ONCE (rc ))
299- snp_leak_pages (pfn , page_level_size (level ) >> PAGE_SHIFT );
306+ if (kvm_rmp_make_shared (kvm , pfn , PG_LEVEL_4K ))
307+ return - EIO ;
300308
301309 return rc ;
302310}
@@ -2244,7 +2252,7 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pf
22442252 * information to provide information on which CPUID leaves/fields
22452253 * failed CPUID validation.
22462254 */
2247- if (!snp_page_reclaim (pfn + i ) && ! host_rmp_make_shared ( pfn + i , PG_LEVEL_4K ) &&
2255+ if (!snp_page_reclaim (kvm , pfn + i ) &&
22482256 sev_populate_args -> type == KVM_SEV_SNP_PAGE_TYPE_CPUID &&
22492257 sev_populate_args -> fw_error == SEV_RET_INVALID_PARAM ) {
22502258 void * vaddr = kmap_local_pfn (pfn + i );
@@ -2262,7 +2270,7 @@ static int sev_gmem_post_populate(struct kvm *kvm, gfn_t gfn_start, kvm_pfn_t pf
22622270 pr_debug ("%s: exiting with error ret %d (fw_error %d), restoring %d gmem PFNs to shared.\n" ,
22632271 __func__ , ret , sev_populate_args -> fw_error , n_private );
22642272 for (i = 0 ; i < n_private ; i ++ )
2265- host_rmp_make_shared ( pfn + i , PG_LEVEL_4K );
2273+ kvm_rmp_make_shared ( kvm , pfn + i , PG_LEVEL_4K );
22662274
22672275 return ret ;
22682276}
@@ -2380,8 +2388,7 @@ static int snp_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
23802388 ret = __sev_issue_cmd (argp -> sev_fd , SEV_CMD_SNP_LAUNCH_UPDATE ,
23812389 & data , & argp -> error );
23822390 if (ret ) {
2383- if (!snp_page_reclaim (pfn ))
2384- host_rmp_make_shared (pfn , PG_LEVEL_4K );
2391+ snp_page_reclaim (kvm , pfn );
23852392
23862393 return ret ;
23872394 }
@@ -3069,7 +3076,7 @@ void sev_free_vcpu(struct kvm_vcpu *vcpu)
30693076 if (sev_snp_guest (vcpu -> kvm )) {
30703077 u64 pfn = __pa (svm -> sev_es .vmsa ) >> PAGE_SHIFT ;
30713078
3072- if (host_rmp_make_shared ( pfn , PG_LEVEL_4K ))
3079+ if (kvm_rmp_make_shared ( vcpu -> kvm , pfn , PG_LEVEL_4K ))
30733080 goto skip_vmsa_free ;
30743081 }
30753082
0 commit comments