Commit 9369bc5c authored by Oliver Upton's avatar Oliver Upton Committed by Marc Zyngier
Browse files

KVM: arm64: Plumb cp10 ID traps through the AArch64 sysreg handler



In order to enable HCR_EL2.TID3 for AArch32 guests KVM needs to handle
traps where ESR_EL2.EC=0x8, which corresponds to an attempted VMRS
access from an ID group register. Specifically, the MVFR{0-2} registers
are accessed this way from AArch32. Conveniently, these registers are
architecturally mapped to MVFR{0-2}_EL1 in AArch64. Furthermore, KVM
already handles reads to these aliases in AArch64.

Plumb VMRS read traps through to the general AArch64 system register
handler.

Signed-off-by: default avatarOliver Upton <oupton@google.com>
Reviewed-by: default avatarReiji Watanabe <reijiw@google.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220503060205.2823727-5-oupton@google.com
parent e6519766
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -683,6 +683,7 @@ int kvm_handle_cp14_64(struct kvm_vcpu *vcpu);
int kvm_handle_cp15_32(struct kvm_vcpu *vcpu);
int kvm_handle_cp15_64(struct kvm_vcpu *vcpu);
int kvm_handle_sys_reg(struct kvm_vcpu *vcpu);
int kvm_handle_cp10_id(struct kvm_vcpu *vcpu);

void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);

+1 −0
Original line number Diff line number Diff line
@@ -167,6 +167,7 @@ static exit_handle_fn arm_exit_handlers[] = {
	[ESR_ELx_EC_CP15_64]	= kvm_handle_cp15_64,
	[ESR_ELx_EC_CP14_MR]	= kvm_handle_cp14_32,
	[ESR_ELx_EC_CP14_LS]	= kvm_handle_cp14_load_store,
	[ESR_ELx_EC_CP10_ID]	= kvm_handle_cp10_id,
	[ESR_ELx_EC_CP14_64]	= kvm_handle_cp14_64,
	[ESR_ELx_EC_HVC32]	= handle_hvc,
	[ESR_ELx_EC_SMC32]	= handle_smc,
+71 −0
Original line number Diff line number Diff line
@@ -2346,6 +2346,77 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,

static bool emulate_sys_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *params);

/*
 * The CP10 ID registers are architecturally mapped to AArch64 feature
 * registers. Abuse that fact so we can rely on the AArch64 handler for accesses
 * from AArch32.
 */
static bool kvm_esr_cp10_id_to_sys64(u32 esr, struct sys_reg_params *params)
{
	u8 reg_id = (esr >> 10) & 0xf;
	bool valid;

	params->is_write = ((esr & 1) == 0);
	params->Op0 = 3;
	params->Op1 = 0;
	params->CRn = 0;
	params->CRm = 3;

	/* CP10 ID registers are read-only */
	valid = !params->is_write;

	switch (reg_id) {
	/* MVFR0 */
	case 0b0111:
		params->Op2 = 0;
		break;
	/* MVFR1 */
	case 0b0110:
		params->Op2 = 1;
		break;
	/* MVFR2 */
	case 0b0101:
		params->Op2 = 2;
		break;
	default:
		valid = false;
	}

	if (valid)
		return true;

	kvm_pr_unimpl("Unhandled cp10 register %s: %u\n",
		      params->is_write ? "write" : "read", reg_id);
	return false;
}

/**
 * kvm_handle_cp10_id() - Handles a VMRS trap on guest access to a 'Media and
 *			  VFP Register' from AArch32.
 * @vcpu: The vCPU pointer
 *
 * MVFR{0-2} are architecturally mapped to the AArch64 MVFR{0-2}_EL1 registers.
 * Work out the correct AArch64 system register encoding and reroute to the
 * AArch64 system register emulation.
 */
int kvm_handle_cp10_id(struct kvm_vcpu *vcpu)
{
	int Rt = kvm_vcpu_sys_get_rt(vcpu);
	u32 esr = kvm_vcpu_get_esr(vcpu);
	struct sys_reg_params params;

	/* UNDEF on any unhandled register access */
	if (!kvm_esr_cp10_id_to_sys64(esr, &params)) {
		kvm_inject_undefined(vcpu);
		return 1;
	}

	if (emulate_sys_reg(vcpu, &params))
		vcpu_set_reg(vcpu, Rt, params.regval);

	return 1;
}

/**
 * kvm_emulate_cp15_id_reg() - Handles an MRC trap on a guest CP15 access where
 *			       CRn=0, which corresponds to the AArch32 feature