KVM: arm64: nv: Add basic emulation of AT S1E2{R,W}
authorMarc Zyngier <maz@kernel.org>
Wed, 19 Jun 2024 07:43:35 +0000 (08:43 +0100)
committerMarc Zyngier <maz@kernel.org>
Fri, 30 Aug 2024 11:04:20 +0000 (12:04 +0100)
Similar to our AT S1E{0,1} emulation, we implement the AT S1E2
handling.

This emulation of course suffers from the same problems, but is
somehow simpler due to the lack of PAN2 and the fact that we are
guaranteed to execute it from the correct context.

Co-developed-by: Jintack Lim <jintack.lim@linaro.org>
Signed-off-by: Jintack Lim <jintack.lim@linaro.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_asm.h
arch/arm64/kvm/at.c

index 9b6c9f4f4d88596d3502d02f1000da5abe119039..6ec06229697667489a317a2e67864a2cb5c1dc18 100644 (file)
@@ -237,6 +237,7 @@ extern int __kvm_tlbi_s1e2(struct kvm_s2_mmu *mmu, u64 va, u64 sys_encoding);
 
 extern void __kvm_timer_set_cntvoff(u64 cntvoff);
 extern void __kvm_at_s1e01(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
+extern void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
index 92df948350e1896a1a15858ab093675253c79491..34736c1fe39871a2ef7e3c52950337d99f80be17 100644 (file)
@@ -164,3 +164,54 @@ void __kvm_at_s1e01(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
 
        vcpu_write_sys_reg(vcpu, par, PAR_EL1);
 }
+
+void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
+{
+       u64 par;
+
+       /*
+        * We've trapped, so everything is live on the CPU. As we will be
+        * switching context behind everybody's back, disable interrupts...
+        */
+       scoped_guard(write_lock_irqsave, &vcpu->kvm->mmu_lock) {
+               struct kvm_s2_mmu *mmu;
+               u64 val, hcr;
+               bool fail;
+
+               mmu = &vcpu->kvm->arch.mmu;
+
+               val = hcr = read_sysreg(hcr_el2);
+               val &= ~HCR_TGE;
+               val |= HCR_VM;
+
+               if (!vcpu_el2_e2h_is_set(vcpu))
+                       val |= HCR_NV | HCR_NV1;
+
+               write_sysreg(val, hcr_el2);
+               isb();
+
+               par = SYS_PAR_EL1_F;
+
+               switch (op) {
+               case OP_AT_S1E2R:
+                       fail = __kvm_at(OP_AT_S1E1R, vaddr);
+                       break;
+               case OP_AT_S1E2W:
+                       fail = __kvm_at(OP_AT_S1E1W, vaddr);
+                       break;
+               default:
+                       WARN_ON_ONCE(1);
+                       fail = true;
+               }
+
+               isb();
+
+               if (!fail)
+                       par = read_sysreg_par();
+
+               write_sysreg(hcr, hcr_el2);
+               isb();
+       }
+
+       vcpu_write_sys_reg(vcpu, par, PAR_EL1);
+}