Skip to content

Commit febff04

Browse files
mdrothbonzini
authored andcommitted
KVM: SEV: Automatically switch reclaimed pages to shared
Currently there's a consistent pattern of always calling host_rmp_make_shared() immediately after snp_page_reclaim(), so go ahead and handle it automatically as part of snp_page_reclaim(). Also rename it to kvm_rmp_make_shared() to more easily distinguish it as a KVM-specific variant of the more generic rmp_make_shared() helper. Suggested-by: Sean Christopherson <[email protected]> Signed-off-by: Michael Roth <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 6f627b4 commit febff04

File tree

1 file changed

+31
-24
lines changed

1 file changed

+31
-24
lines changed

arch/x86/kvm/svm/sev.c

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)