[RFC PATCH v2 33/38] KVM: arm64: Emulate appropriate VM control system registers

Jintack Lim jintack.lim at linaro.org
Tue Jul 18 09:58:59 PDT 2017


Now that the virtual EL2 can access EL2 register states via EL1
registers, we need to consider it when selecting the register to
emulate.

Signed-off-by: Jintack Lim <jintack.lim at linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 79980be..910b50d 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -110,6 +110,31 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+struct el1_el2_map {
+	int	el1;
+	int	el2;
+};
+
+static const struct el1_el2_map vm_map[] = {
+	{SCTLR_EL1, SCTLR_EL2},
+	{TTBR0_EL1, TTBR0_EL2},
+	{TTBR1_EL1, TTBR1_EL2},
+	{TCR_EL1, TCR_EL2},
+	{ESR_EL1, ESR_EL2},
+	{FAR_EL1, FAR_EL2},
+	{AFSR0_EL1, AFSR0_EL2},
+	{AFSR1_EL1, AFSR1_EL2},
+	{MAIR_EL1, MAIR_EL2},
+	{AMAIR_EL1, AMAIR_EL2},
+	{CONTEXTIDR_EL1, CONTEXTIDR_EL2},
+};
+
+static inline bool el12_reg(struct sys_reg_params *p)
+{
+	/* All *_EL12 registers have Op1=5. */
+	return (p->Op1 == 5);
+}
+
 /*
  * Generic accessor for VM registers. Only called as long as HCR_TVM
  * is set. If the guest enables the MMU, we stop trapping the VM
@@ -120,16 +145,33 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
 			  const struct sys_reg_desc *r)
 {
 	bool was_enabled = vcpu_has_cache_enabled(vcpu);
+	u64 *sysreg = &vcpu_sys_reg(vcpu, r->reg);
+	int i;
+	const struct el1_el2_map *map;
+
+	/*
+	 * Redirect EL1 register accesses to the corresponding EL2 registers if
+	 * they are meant to access EL2 registers.
+	 */
+	if (vcpu_el2_e2h_is_set(vcpu) && !el12_reg(p)) {
+		for (i = 0; i < ARRAY_SIZE(vm_map); i++) {
+			map = &vm_map[i];
+			if (map->el1 == r->reg) {
+				sysreg = &vcpu_sys_reg(vcpu, map->el2);
+				break;
+			}
+		}
+	}
 
 	BUG_ON(!vcpu_mode_el2(vcpu) && !p->is_write);
 
 	if (!p->is_write) {
-		p->regval = vcpu_sys_reg(vcpu, r->reg);
+		p->regval = *sysreg;
 		return true;
 	}
 
 	if (!p->is_aarch32) {
-		vcpu_sys_reg(vcpu, r->reg) = p->regval;
+		*sysreg = p->regval;
 	} else {
 		if (!p->is_32bit)
 			vcpu_cp15_64_high(vcpu, r->reg) = upper_32_bits(p->regval);
-- 
1.9.1




More information about the linux-arm-kernel mailing list