KVM: arm64: Plumb cp10 ID traps through the AArch64 sysreg handler
authorOliver Upton <oupton@google.com>
Tue, 3 May 2022 06:02:02 +0000 (06:02 +0000)
committerMarc Zyngier <maz@kernel.org>
Tue, 3 May 2022 10:14:34 +0000 (11:14 +0100)
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: Oliver Upton <oupton@google.com>
Reviewed-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20220503060205.2823727-5-oupton@google.com
arch/arm64/include/asm/kvm_host.h
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/sys_regs.c

index 94a27a7..05081b9 100644 (file)
@@ -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);
 
index 97fe14a..5088a86 100644 (file)
@@ -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,
index f403ea4..586b292 100644 (file)
@@ -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