@@ -118,10 +118,8 @@ static inline void __deactivate_traps_common(struct kvm_vcpu *vcpu)
}
}
-static inline void ___activate_traps(struct kvm_vcpu *vcpu)
+static inline void ___activate_traps(struct kvm_vcpu *vcpu, u64 hcr)
{
- u64 hcr = vcpu->arch.hcr_el2;
-
if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM))
hcr |= HCR_TVM;
@@ -40,7 +40,7 @@ static void __activate_traps(struct kvm_vcpu *vcpu)
{
u64 val;
- ___activate_traps(vcpu);
+ ___activate_traps(vcpu, vcpu->arch.hcr_el2);
__activate_traps_common(vcpu);
val = vcpu->arch.cptr_el2;
@@ -35,9 +35,14 @@ DEFINE_PER_CPU(unsigned long, kvm_hyp_vector);
static void __activate_traps(struct kvm_vcpu *vcpu)
{
+ u64 hcr = vcpu->arch.hcr_el2;
u64 val;
- ___activate_traps(vcpu);
+ /* Trap VM sysreg accesses if an EL2 guest is not using VHE. */
+ if (vcpu_is_el2(vcpu) && !vcpu_el2_e2h_is_set(vcpu))
+ hcr |= HCR_TVM | HCR_TRVM;
+
+ ___activate_traps(vcpu, hcr);
val = read_sysreg(cpacr_el1);
val |= CPACR_ELx_TTA;
@@ -318,8 +318,15 @@ static void get_access_mask(const struct sys_reg_desc *r, u64 *mask, u64 *shift)
/*
* 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
- * sys_regs and leave it in complete control of the caches.
+ * is set.
+ *
+ * This is set in two cases: either (1) we're running at vEL2, or (2)
+ * we're running at EL1 and the guest has its MMU off.
+ *
+ * (1) TVM/TRVM is set, as we need to virtualise some of the VM
+ * registers for the guest hypervisor
+ * (2) Once the guest enables the MMU, we stop trapping the VM sys_regs
+ * and leave it in complete control of the caches.
*/
static bool access_vm_reg(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
@@ -328,7 +335,13 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
bool was_enabled = vcpu_has_cache_enabled(vcpu);
u64 val, mask, shift;
- BUG_ON(!p->is_write);
+ /* We don't expect TRVM on the host */
+ BUG_ON(!vcpu_is_el2(vcpu) && !p->is_write);
+
+ if (!p->is_write) {
+ p->regval = vcpu_read_sys_reg(vcpu, r->reg);
+ return true;
+ }
get_access_mask(r, &mask, &shift);