Skip to content

Commit f4e7403

Browse files
Fuad Tabbabonzini
authored andcommitted
KVM: arm64: nv: Handle VNCR_EL2-triggered faults backed by guest_memfd
Handle faults for memslots backed by guest_memfd in arm64 nested virtualization triggered by VNCR_EL2. * Introduce is_gmem output parameter to kvm_translate_vncr(), indicating whether the faulted memory slot is backed by guest_memfd. * Dispatch faults backed by guest_memfd to kvm_gmem_get_pfn(). * Update kvm_handle_vncr_abort() to handle potential guest_memfd errors. Some of the guest_memfd errors need to be handled by userspace instead of attempting to (implicitly) retry by returning to the guest. Suggested-by: Marc Zyngier <[email protected]> Reviewed-by: Marc Zyngier <[email protected]> Signed-off-by: Fuad Tabba <[email protected]> Signed-off-by: Sean Christopherson <[email protected]> Message-ID: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent a7b57e0 commit f4e7403

1 file changed

Lines changed: 35 additions & 6 deletions

File tree

arch/arm64/kvm/nested.c

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,8 +1172,9 @@ static u64 read_vncr_el2(struct kvm_vcpu *vcpu)
11721172
return (u64)sign_extend64(__vcpu_sys_reg(vcpu, VNCR_EL2), 48);
11731173
}
11741174

1175-
static int kvm_translate_vncr(struct kvm_vcpu *vcpu)
1175+
static int kvm_translate_vncr(struct kvm_vcpu *vcpu, bool *is_gmem)
11761176
{
1177+
struct kvm_memory_slot *memslot;
11771178
bool write_fault, writable;
11781179
unsigned long mmu_seq;
11791180
struct vncr_tlb *vt;
@@ -1216,10 +1217,25 @@ static int kvm_translate_vncr(struct kvm_vcpu *vcpu)
12161217
smp_rmb();
12171218

12181219
gfn = vt->wr.pa >> PAGE_SHIFT;
1219-
pfn = kvm_faultin_pfn(vcpu, gfn, write_fault, &writable, &page);
1220-
if (is_error_noslot_pfn(pfn) || (write_fault && !writable))
1220+
memslot = gfn_to_memslot(vcpu->kvm, gfn);
1221+
if (!memslot)
12211222
return -EFAULT;
12221223

1224+
*is_gmem = kvm_slot_has_gmem(memslot);
1225+
if (!*is_gmem) {
1226+
pfn = __kvm_faultin_pfn(memslot, gfn, write_fault ? FOLL_WRITE : 0,
1227+
&writable, &page);
1228+
if (is_error_noslot_pfn(pfn) || (write_fault && !writable))
1229+
return -EFAULT;
1230+
} else {
1231+
ret = kvm_gmem_get_pfn(vcpu->kvm, memslot, gfn, &pfn, &page, NULL);
1232+
if (ret) {
1233+
kvm_prepare_memory_fault_exit(vcpu, vt->wr.pa, PAGE_SIZE,
1234+
write_fault, false, false);
1235+
return ret;
1236+
}
1237+
}
1238+
12231239
scoped_guard(write_lock, &vcpu->kvm->mmu_lock) {
12241240
if (mmu_invalidate_retry(vcpu->kvm, mmu_seq))
12251241
return -EAGAIN;
@@ -1292,23 +1308,36 @@ int kvm_handle_vncr_abort(struct kvm_vcpu *vcpu)
12921308
if (esr_fsc_is_permission_fault(esr)) {
12931309
inject_vncr_perm(vcpu);
12941310
} else if (esr_fsc_is_translation_fault(esr)) {
1295-
bool valid;
1311+
bool valid, is_gmem = false;
12961312
int ret;
12971313

12981314
scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
12991315
valid = kvm_vncr_tlb_lookup(vcpu);
13001316

13011317
if (!valid)
1302-
ret = kvm_translate_vncr(vcpu);
1318+
ret = kvm_translate_vncr(vcpu, &is_gmem);
13031319
else
13041320
ret = -EPERM;
13051321

13061322
switch (ret) {
13071323
case -EAGAIN:
1308-
case -ENOMEM:
13091324
/* Let's try again... */
13101325
break;
1326+
case -ENOMEM:
1327+
/*
1328+
* For guest_memfd, this indicates that it failed to
1329+
* create a folio to back the memory. Inform userspace.
1330+
*/
1331+
if (is_gmem)
1332+
return 0;
1333+
/* Otherwise, let's try again... */
1334+
break;
13111335
case -EFAULT:
1336+
case -EIO:
1337+
case -EHWPOISON:
1338+
if (is_gmem)
1339+
return 0;
1340+
fallthrough;
13121341
case -EINVAL:
13131342
case -ENOENT:
13141343
case -EACCES:

0 commit comments

Comments
 (0)