]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: Load VPIDR_EL2 with the VM's MIDR_EL1 value
authorOliver Upton <oliver.upton@linux.dev>
Tue, 25 Feb 2025 00:53:59 +0000 (16:53 -0800)
committerOliver Upton <oliver.upton@linux.dev>
Wed, 26 Feb 2025 09:32:05 +0000 (01:32 -0800)
Userspace will soon be able to change the value of MIDR_EL1. Prepare by
loading VPIDR_EL2 with the guest value for non-nested VMs.

Since VPIDR_EL2 is set for any VM, get rid of the NV-specific cleanup of
reloading the hardware value on vcpu_put(). And for nVHE, load the
hardware value before switching to the host.

Link: https://lore.kernel.org/r/20250225005401.679536-4-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h
arch/arm64/kvm/hyp/nvhe/sysreg-sr.c
arch/arm64/kvm/hyp/vhe/sysreg-sr.c

index 76ff095c6b6ebf336aab3018ec1f384a5f19949e..6e6d135803771c276ffdd9c2d1ceabcf79e36b67 100644 (file)
@@ -43,6 +43,11 @@ static inline u64 *ctxt_mdscr_el1(struct kvm_cpu_context *ctxt)
        return &ctxt_sys_reg(ctxt, MDSCR_EL1);
 }
 
+static inline u64 ctxt_midr_el1(struct kvm_cpu_context *ctxt)
+{
+       return read_cpuid_id();
+}
+
 static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
 {
        *ctxt_mdscr_el1(ctxt)   = read_sysreg(mdscr_el1);
@@ -168,8 +173,9 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
 }
 
 static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt,
-                                             u64 mpidr)
+                                             u64 midr, u64 mpidr)
 {
+       write_sysreg(midr,                              vpidr_el2);
        write_sysreg(mpidr,                             vmpidr_el2);
 
        if (has_vhe() ||
index dba101565de36718ff63a03503e3941b4430c2be..3cc613cce5f52aa079e78d174913aaac36285527 100644 (file)
@@ -28,7 +28,9 @@ void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt)
 
 void __sysreg_restore_state_nvhe(struct kvm_cpu_context *ctxt)
 {
-       __sysreg_restore_el1_state(ctxt, ctxt_sys_reg(ctxt, MPIDR_EL1));
+       u64 midr = ctxt_midr_el1(ctxt);
+
+       __sysreg_restore_el1_state(ctxt, midr, ctxt_sys_reg(ctxt, MPIDR_EL1));
        __sysreg_restore_common_state(ctxt);
        __sysreg_restore_user_state(ctxt);
        __sysreg_restore_el2_return_state(ctxt);
index 90b018e06f2cbb0398fda58949574475871b33bd..3814b0b2c937f5214edcc7c6d37ecf04b96b2688 100644 (file)
@@ -87,11 +87,12 @@ static void __sysreg_restore_vel2_state(struct kvm_vcpu *vcpu)
        write_sysreg(__vcpu_sys_reg(vcpu, PAR_EL1),     par_el1);
        write_sysreg(__vcpu_sys_reg(vcpu, TPIDR_EL1),   tpidr_el1);
 
-       write_sysreg(__vcpu_sys_reg(vcpu, MPIDR_EL1),           vmpidr_el2);
-       write_sysreg_el1(__vcpu_sys_reg(vcpu, MAIR_EL2),        SYS_MAIR);
-       write_sysreg_el1(__vcpu_sys_reg(vcpu, VBAR_EL2),        SYS_VBAR);
-       write_sysreg_el1(__vcpu_sys_reg(vcpu, CONTEXTIDR_EL2),  SYS_CONTEXTIDR);
-       write_sysreg_el1(__vcpu_sys_reg(vcpu, AMAIR_EL2),       SYS_AMAIR);
+       write_sysreg(ctxt_midr_el1(&vcpu->arch.ctxt),                   vpidr_el2);
+       write_sysreg(__vcpu_sys_reg(vcpu, MPIDR_EL1),                   vmpidr_el2);
+       write_sysreg_el1(__vcpu_sys_reg(vcpu, MAIR_EL2),                SYS_MAIR);
+       write_sysreg_el1(__vcpu_sys_reg(vcpu, VBAR_EL2),                SYS_VBAR);
+       write_sysreg_el1(__vcpu_sys_reg(vcpu, CONTEXTIDR_EL2),          SYS_CONTEXTIDR);
+       write_sysreg_el1(__vcpu_sys_reg(vcpu, AMAIR_EL2),               SYS_AMAIR);
 
        if (vcpu_el2_e2h_is_set(vcpu)) {
                /*
@@ -191,7 +192,7 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt;
        struct kvm_cpu_context *host_ctxt;
-       u64 mpidr;
+       u64 midr, mpidr;
 
        host_ctxt = host_data_ptr(host_ctxt);
        __sysreg_save_user_state(host_ctxt);
@@ -220,23 +221,18 @@ void __vcpu_load_switch_sysregs(struct kvm_vcpu *vcpu)
                __sysreg_restore_vel2_state(vcpu);
        } else {
                if (vcpu_has_nv(vcpu)) {
-                       /*
-                        * Use the guest hypervisor's VPIDR_EL2 when in a
-                        * nested state. The hardware value of MIDR_EL1 gets
-                        * restored on put.
-                        */
-                       write_sysreg(ctxt_sys_reg(guest_ctxt, VPIDR_EL2), vpidr_el2);
-
                        /*
                         * As we're restoring a nested guest, set the value
                         * provided by the guest hypervisor.
                         */
+                       midr = ctxt_sys_reg(guest_ctxt, VPIDR_EL2);
                        mpidr = ctxt_sys_reg(guest_ctxt, VMPIDR_EL2);
                } else {
+                       midr = ctxt_midr_el1(guest_ctxt);
                        mpidr = ctxt_sys_reg(guest_ctxt, MPIDR_EL1);
                }
 
-               __sysreg_restore_el1_state(guest_ctxt, mpidr);
+               __sysreg_restore_el1_state(guest_ctxt, midr, mpidr);
        }
 
        vcpu_set_flag(vcpu, SYSREGS_ON_CPU);
@@ -271,9 +267,5 @@ void __vcpu_put_switch_sysregs(struct kvm_vcpu *vcpu)
        /* Restore host user state */
        __sysreg_restore_user_state(host_ctxt);
 
-       /* If leaving a nesting guest, restore MIDR_EL1 default view */
-       if (vcpu_has_nv(vcpu))
-               write_sysreg(read_cpuid_id(),   vpidr_el2);
-
        vcpu_clear_flag(vcpu, SYSREGS_ON_CPU);
 }