@@ -151,9 +151,39 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM))
hcr |= HCR_TVM;
- /* Trap VM sysreg accesses if an EL2 guest is not using VHE. */
- if (vcpu_mode_el2(vcpu) && !vcpu_el2_e2h_is_set(vcpu))
- hcr |= HCR_TVM | HCR_TRVM;
+ if (is_hyp_ctxt(vcpu)) {
+ hcr |= HCR_NV;
+
+ if (!vcpu_el2_e2h_is_set(vcpu)) {
+ /*
+ * For a guest hypervisor on v8.0, trap and emulate
+ * the EL1 virtual memory control register accesses.
+ */
+ hcr |= HCR_TVM | HCR_TRVM | HCR_NV1;
+ } else {
+ /*
+ * For a guest hypervisor on v8.1 (VHE), allow to
+ * access the EL1 virtual memory control registers
+ * natively. These accesses are to access EL2 register
+ * states.
+ * Note that we still need to respect the virtual
+ * HCR_EL2 state.
+ */
+ u64 vhcr_el2 = __vcpu_sys_reg(vcpu, HCR_EL2);
+
+ /*
+ * We already set TVM to handle set/way cache maint
+ * ops traps, this somewhat collides with the nested
+ * virt trapping for nVHE. So turn this off for now
+ * here, in the hope that VHE guests won't ever do this.
+ * TODO: find out whether it's worth to support both
+ * cases at the same time.
+ */
+ hcr &= ~HCR_TVM;
+
+ hcr |= vhcr_el2 & (HCR_TVM | HCR_TRVM);
+ }
+ }
write_sysreg(hcr, hcr_el2);