Skip to content

Commit

Permalink
arm64: KVM: vgic-v2: Add the GICV emulation infrastructure
Browse files Browse the repository at this point in the history
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 <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
  • Loading branch information
Marc Zyngier authored and Christoffer Dall committed Sep 8, 2016
1 parent 8cebe75 commit fb5ee36
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/arm64/include/asm/kvm_hyp.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ typeof(orig) * __hyp_text fname(void) \

void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
bool __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);

void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
Expand Down
32 changes: 32 additions & 0 deletions arch/arm64/kvm/hyp/switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <linux/types.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_hyp.h>

static bool __hyp_text __fpsimd_enabled_nvhe(void)
Expand Down Expand Up @@ -232,6 +233,21 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
return true;
}

static void __hyp_text __skip_instr(struct kvm_vcpu *vcpu)
{
*vcpu_pc(vcpu) = read_sysreg_el2(elr);

if (vcpu_mode_is_32bit(vcpu)) {
vcpu->arch.ctxt.gp_regs.regs.pstate = read_sysreg_el2(spsr);
kvm_skip_instr32(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
write_sysreg_el2(vcpu->arch.ctxt.gp_regs.regs.pstate, spsr);
} else {
*vcpu_pc(vcpu) += 4;
}

write_sysreg_el2(*vcpu_pc(vcpu), elr);
}

int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
{
struct kvm_cpu_context *host_ctxt;
Expand Down Expand Up @@ -270,6 +286,22 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
goto again;

if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
exit_code == ARM_EXCEPTION_TRAP) {
bool valid;

valid = kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_DABT_LOW &&
kvm_vcpu_trap_get_fault_type(vcpu) == FSC_FAULT &&
kvm_vcpu_dabt_isvalid(vcpu) &&
!kvm_vcpu_dabt_isextabt(vcpu) &&
!kvm_vcpu_dabt_iss1tw(vcpu);

if (valid && __vgic_v2_perform_cpuif_access(vcpu)) {
__skip_instr(vcpu);
goto again;
}
}

fp_enabled = __fpsimd_enabled();

__sysreg_save_guest_state(guest_ctxt);
Expand Down
3 changes: 3 additions & 0 deletions include/kvm/arm_vgic.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/kvm.h>
#include <linux/irqreturn.h>
#include <linux/spinlock.h>
#include <linux/static_key.h>
#include <linux/types.h>
#include <kvm/iodev.h>
#include <linux/list.h>
Expand Down Expand Up @@ -265,6 +266,8 @@ struct vgic_cpu {
bool lpis_enabled;
};

extern struct static_key_false vgic_v2_cpuif_trap;

int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
void kvm_vgic_early_init(struct kvm *kvm);
int kvm_vgic_create(struct kvm *kvm, u32 type);
Expand Down
7 changes: 7 additions & 0 deletions virt/kvm/arm/hyp/vgic-v2-sr.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,10 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
vcpu->arch.vgic_cpu.live_lrs = live_lrs;
}

#ifdef CONFIG_ARM64
bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
{
return false;
}
#endif
2 changes: 2 additions & 0 deletions virt/kvm/arm/vgic/vgic-v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ int vgic_v2_map_resources(struct kvm *kvm)
return ret;
}

DEFINE_STATIC_KEY_FALSE(vgic_v2_cpuif_trap);

/**
* vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
* @node: pointer to the DT node
Expand Down

0 comments on commit fb5ee36

Please sign in to comment.