Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59da1cbf authored by Marc Zyngier's avatar Marc Zyngier
Browse files

KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at EL2



In order to start handling guest access to GICv3 system registers,
let's add a hook that will get called when we trap a system register
access. This is gated by a new static key (vgic_v3_cpuif_trap).

Tested-by: default avatarAlexander Graf <agraf@suse.de>
Acked-by: default avatarDavid Daney <david.daney@cavium.com>
Reviewed-by: default avatarEric Auger <eric.auger@redhat.com>
Reviewed-by: default avatarChristoffer Dall <cdall@linaro.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarChristoffer Dall <cdall@linaro.org>
parent 021234ef
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -127,6 +127,7 @@ int __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);
int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);

void __timer_save_state(struct kvm_vcpu *vcpu);
void __timer_restore_state(struct kvm_vcpu *vcpu);
+14 −0
Original line number Diff line number Diff line
@@ -350,6 +350,20 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
		}
	}

	if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
	    exit_code == ARM_EXCEPTION_TRAP &&
	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 ||
	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_CP15_32)) {
		int ret = __vgic_v3_perform_cpuif_access(vcpu);

		if (ret == 1) {
			__skip_instr(vcpu);
			goto again;
		}

		/* 0 falls through to be handled out of EL2 */
	}

	fp_enabled = __fpsimd_enabled();

	__sysreg_save_guest_state(guest_ctxt);
+1 −0
Original line number Diff line number Diff line
@@ -292,6 +292,7 @@ struct vgic_cpu {
};

extern struct static_key_false vgic_v2_cpuif_trap;
extern struct static_key_false vgic_v3_cpuif_trap;

int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
void kvm_vgic_early_init(struct kvm *kvm);
+38 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/kvm_host.h>

#include <asm/kvm_emulate.h>
#include <asm/kvm_hyp.h>

#define vtr_to_max_lr_idx(v)		((v) & 0xf)
@@ -371,3 +372,40 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
{
	write_gicreg(vmcr, ICH_VMCR_EL2);
}

#ifdef CONFIG_ARM64

int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
{
	int rt;
	u32 esr;
	u32 vmcr;
	void (*fn)(struct kvm_vcpu *, u32, int);
	bool is_read;
	u32 sysreg;

	esr = kvm_vcpu_get_hsr(vcpu);
	if (vcpu_mode_is_32bit(vcpu)) {
		if (!kvm_condition_valid(vcpu))
			return 1;

		sysreg = esr_cp15_to_sysreg(esr);
	} else {
		sysreg = esr_sys64_to_sysreg(esr);
	}

	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;

	switch (sysreg) {
	default:
		return 0;
	}

	vmcr = __vgic_v3_read_vmcr();
	rt = kvm_vcpu_sys_get_rt(vcpu);
	fn(vcpu, vmcr, rt);

	return 1;
}

#endif
+2 −0
Original line number Diff line number Diff line
@@ -429,6 +429,8 @@ int vgic_v3_map_resources(struct kvm *kvm)
	return ret;
}

DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);

/**
 * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
 * @node:	pointer to the DT node