Skip to content

Commit fb5ee36

Browse files
Marc Zyngierchazy
authored andcommitted
arm64: KVM: vgic-v2: Add the GICV emulation infrastructure
In order to efficiently perform the GICV access on behalf of the guest, we need to be able to avoid going back all the way to the host kernel. For this, we introduce a new hook in the world switch code, conveniently placed just after populating the fault info. At that point, we only have saved/restored the GP registers, and we can quickly perform all the required checks (data abort, translation fault, valid faulting syndrome, not an external abort, not a PTW). Coming back from the emulation code, we need to skip the emulated instruction. This involves an additional bit of save/restore in order to be able to access the guest's PC (and possibly CPSR if this is a 32bit guest). At this stage, no emulation code is provided. Signed-off-by: Marc Zyngier <[email protected]> Reviewed-by: Christoffer Dall <[email protected]> Signed-off-by: Christoffer Dall <[email protected]>
1 parent 8cebe75 commit fb5ee36

File tree

5 files changed

+45
-0
lines changed

5 files changed

+45
-0
lines changed

arch/arm64/include/asm/kvm_hyp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ typeof(orig) * __hyp_text fname(void) \
123123

124124
void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
125125
void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
126+
bool __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
126127

127128
void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
128129
void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);

arch/arm64/kvm/hyp/switch.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include <linux/types.h>
1919
#include <asm/kvm_asm.h>
20+
#include <asm/kvm_emulate.h>
2021
#include <asm/kvm_hyp.h>
2122

2223
static bool __hyp_text __fpsimd_enabled_nvhe(void)
@@ -232,6 +233,21 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
232233
return true;
233234
}
234235

236+
static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu)
237+
{
238+
*vcpu_pc(vcpu) = read_sysreg_el2(elr);
239+
240+
if (vcpu_mode_is_32bit(vcpu)) {
241+
vcpu->arch.ctxt.gp_regs.regs.pstate = read_sysreg_el2(spsr);
242+
kvm_skip_instr32(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
243+
write_sysreg_el2(vcpu->arch.ctxt.gp_regs.regs.pstate, spsr);
244+
} else {
245+
*vcpu_pc(vcpu) += 4;
246+
}
247+
248+
write_sysreg_el2(*vcpu_pc(vcpu), elr);
249+
}
250+
235251
int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
236252
{
237253
struct kvm_cpu_context *host_ctxt;
@@ -270,6 +286,22 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
270286
if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
271287
goto again;
272288

289+
if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
290+
exit_code == ARM_EXCEPTION_TRAP) {
291+
bool valid;
292+
293+
valid = kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_DABT_LOW &&
294+
kvm_vcpu_trap_get_fault_type(vcpu) == FSC_FAULT &&
295+
kvm_vcpu_dabt_isvalid(vcpu) &&
296+
!kvm_vcpu_dabt_isextabt(vcpu) &&
297+
!kvm_vcpu_dabt_iss1tw(vcpu);
298+
299+
if (valid && __vgic_v2_perform_cpuif_access(vcpu)) {
300+
__skip_instr(vcpu);
301+
goto again;
302+
}
303+
}
304+
273305
fp_enabled = __fpsimd_enabled();
274306

275307
__sysreg_save_guest_state(guest_ctxt);

include/kvm/arm_vgic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/kvm.h>
2121
#include <linux/irqreturn.h>
2222
#include <linux/spinlock.h>
23+
#include <linux/static_key.h>
2324
#include <linux/types.h>
2425
#include <kvm/iodev.h>
2526
#include <linux/list.h>
@@ -265,6 +266,8 @@ struct vgic_cpu {
265266
bool lpis_enabled;
266267
};
267268

269+
extern struct static_key_false vgic_v2_cpuif_trap;
270+
268271
int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
269272
void kvm_vgic_early_init(struct kvm *kvm);
270273
int kvm_vgic_create(struct kvm *kvm, u32 type);

virt/kvm/arm/hyp/vgic-v2-sr.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,10 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
167167
writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
168168
vcpu->arch.vgic_cpu.live_lrs = live_lrs;
169169
}
170+
171+
#ifdef CONFIG_ARM64
172+
bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
173+
{
174+
return false;
175+
}
176+
#endif

virt/kvm/arm/vgic/vgic-v2.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ int vgic_v2_map_resources(struct kvm *kvm)
294294
return ret;
295295
}
296296

297+
DEFINE_STATIC_KEY_FALSE(vgic_v2_cpuif_trap);
298+
297299
/**
298300
* vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
299301
* @node: pointer to the DT node

0 commit comments

Comments
 (0)