@@ -17,6 +17,76 @@
#include <linux/kvm_host.h>
#include <asm/kvm_emulate.h>
+#include <asm/esr.h>
+
+struct el1_el2_map {
+ enum vcpu_sysreg el1;
+ enum el2_regs el2;
+};
+
+/*
+ * List of EL2 registers which can be directly applied to EL1 registers to
+ * emulate running EL2 in EL1. The EL1 registers here must either be trapped
+ * or paravirtualized in EL1.
+ */
+static const struct el1_el2_map el1_el2_map[] = {
+ { AMAIR_EL1, AMAIR_EL2 },
+ { MAIR_EL1, MAIR_EL2 },
+ { TTBR0_EL1, TTBR0_EL2 },
+ { ACTLR_EL1, ACTLR_EL2 },
+ { AFSR0_EL1, AFSR0_EL2 },
+ { AFSR1_EL1, AFSR1_EL2 },
+ { SCTLR_EL1, SCTLR_EL2 },
+ { VBAR_EL1, VBAR_EL2 },
+};
+
+static inline u64 tcr_el2_ips_to_tcr_el1_ps(u64 tcr_el2)
+{
+ return ((tcr_el2 & TCR_EL2_PS_MASK) >> TCR_EL2_PS_SHIFT)
+ << TCR_IPS_SHIFT;
+}
+
+static inline u64 cptr_el2_to_cpacr_el1(u64 cptr_el2)
+{
+ u64 cpacr_el1 = 0;
+
+ if (!(cptr_el2 & CPTR_EL2_TFP))
+ cpacr_el1 |= CPACR_EL1_FPEN;
+ if (cptr_el2 & CPTR_EL2_TTA)
+ cpacr_el1 |= CPACR_EL1_TTA;
+
+ return cpacr_el1;
+}
+
+static void create_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
+{
+ u64 *s_sys_regs = vcpu->arch.ctxt.shadow_sys_regs;
+ u64 *el2_regs = vcpu->arch.ctxt.el2_regs;
+ u64 tcr_el2;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(el1_el2_map); i++) {
+ const struct el1_el2_map *map = &el1_el2_map[i];
+
+ s_sys_regs[map->el1] = el2_regs[map->el2];
+ }
+
+ tcr_el2 = el2_regs[TCR_EL2];
+ s_sys_regs[TCR_EL1] =
+ TCR_EPD1 | /* disable TTBR1_EL1 */
+ ((tcr_el2 & TCR_EL2_TBI) ? TCR_TBI0 : 0) |
+ tcr_el2_ips_to_tcr_el1_ps(tcr_el2) |
+ (tcr_el2 & TCR_EL2_TG0_MASK) |
+ (tcr_el2 & TCR_EL2_ORGN0_MASK) |
+ (tcr_el2 & TCR_EL2_IRGN0_MASK) |
+ (tcr_el2 & TCR_EL2_T0SZ_MASK);
+
+ /* Rely on separate VMID for VA context, always use ASID 0 */
+ s_sys_regs[TTBR0_EL1] &= ~GENMASK_ULL(63, 48);
+ s_sys_regs[TTBR1_EL1] = 0;
+
+ s_sys_regs[CPACR_EL1] = cptr_el2_to_cpacr_el1(el2_regs[CPTR_EL2]);
+}
/**
* kvm_arm_setup_shadow_state -- prepare shadow state based on emulated mode
@@ -37,6 +107,7 @@ void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
else
ctxt->hw_pstate |= PSR_MODE_EL1t;
+ create_shadow_el1_sysregs(vcpu);
ctxt->hw_sys_regs = ctxt->shadow_sys_regs;
ctxt->hw_sp_el1 = ctxt->el2_regs[SP_EL2];
} else {