Because of the above, KVM programs hardware VPIDR_EL2 with the hardware MPIDR_EL1 value, instead of the L1 hypervisor virtual VPIDR_EL2 value. I feel that this deserves a comment because it's not immediately obvious what is happening, perhaps along the lines "Reading MIDR_EL1 from virtual EL2 returns the hardware MIDR_EL1 value, not the value that the guest programmed in virtual VPIDR_EL2". > + write_sysreg(ctxt_sys_reg(ctxt, MPIDR_EL1), vmpidr_el2); But here, the guest will always read the value that KVM computed for the VM in reset_mpidr(), that's why KVM is writing the shadow MPIDR value. > + write_sysreg_el1(ctxt_sys_reg(ctxt, MAIR_EL2), SYS_MAIR); > + write_sysreg_el1(ctxt_sys_reg(ctxt, VBAR_EL2), SYS_VBAR); > + write_sysreg_el1(ctxt_sys_reg(ctxt, CONTEXTIDR_EL2),SYS_CONTEXTIDR); > + write_sysreg_el1(ctxt_sys_reg(ctxt, AMAIR_EL2), SYS_AMAIR); > + > + if (__vcpu_el2_e2h_is_set(ctxt)) { > + /* > + * In VHE mode those registers are compatible between > + * EL1 and EL2. > + */ > + write_sysreg_el1(ctxt_sys_reg(ctxt, SCTLR_EL2), SYS_SCTLR); > + write_sysreg_el1(ctxt_sys_reg(ctxt, CPTR_EL2), SYS_CPACR); > + write_sysreg_el1(ctxt_sys_reg(ctxt, TTBR0_EL2), SYS_TTBR0); > + write_sysreg_el1(ctxt_sys_reg(ctxt, TTBR1_EL2), SYS_TTBR1); > + write_sysreg_el1(ctxt_sys_reg(ctxt, TCR_EL2), SYS_TCR); > + write_sysreg_el1(ctxt_sys_reg(ctxt, CNTHCTL_EL2), SYS_CNTKCTL); > + } else { > + val = translate_sctlr_el2_to_sctlr_el1(ctxt_sys_reg(ctxt, SCTLR_EL2)); > + write_sysreg_el1(val, SYS_SCTLR); > + val = translate_cptr_el2_to_cpacr_el1(ctxt_sys_reg(ctxt, CPTR_EL2)); > + write_sysreg_el1(val, SYS_CPACR); > + val = translate_ttbr0_el2_to_ttbr0_el1(ctxt_sys_reg(ctxt, TTBR0_EL2)); > + write_sysreg_el1(val, SYS_TTBR0); > + val = translate_tcr_el2_to_tcr_el1(ctxt_sys_reg(ctxt, TCR_EL2)); > + write_sysreg_el1(val, SYS_TCR); > + val = translate_cnthctl_el2_to_cntkctl_el1(ctxt_sys_reg(ctxt, CNTHCTL_EL2)); > + write_sysreg_el1(val, SYS_CNTKCTL); > + } > + > + write_sysreg_el1(ctxt_sys_reg(ctxt, ESR_EL2), SYS_ESR); > + write_sysreg_el1(ctxt_sys_reg(ctxt, AFSR0_EL2), SYS_AFSR0); > + write_sysreg_el1(ctxt_sys_reg(ctxt, AFSR1_EL2), SYS_AFSR1); > + write_sysreg_el1(ctxt_sys_reg(ctxt, FAR_EL2), SYS_FAR); > + write_sysreg(ctxt_sys_reg(ctxt, SP_EL2), sp_el1); > + write_sysreg_el1(ctxt_sys_reg(ctxt, ELR_EL2), SYS_ELR); > + > + val = __fixup_spsr_el2_write(ctxt, ctxt_sys_reg(ctxt, SPSR_EL2)); > + write_sysreg_el1(val, SYS_SPSR); > +} > > /* > * VHE: Host and guest must save mdscr_el1 and sp_el0 (and the PC and > @@ -65,6 +155,7 @@ void kvm_vcpu_load_sysregs_vhe(struct kvm_vcpu *vcpu) > { > struct kvm_cpu_context *guest_ctxt = &vcpu->arch.ctxt; > struct kvm_cpu_context *host_ctxt; > + u64 mpidr; > > host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; > __sysreg_save_user_state(host_ctxt); > @@ -77,7 +168,29 @@ void kvm_vcpu_load_sysregs_vhe(struct kvm_vcpu *vcpu) > */ > __sysreg32_restore_state(vcpu); > __sysreg_restore_user_state(guest_ctxt); > - __sysreg_restore_el1_state(guest_ctxt); > + > + if (unlikely(__is_hyp_ctxt(guest_ctxt))) { > + __sysreg_restore_vel2_state(guest_ctxt); > + } else { > + if (vcpu_has_nv(vcpu)) { > + /* > + * Only set VPIDR_EL2 for nested VMs, as this is the > + * only time it changes. We'll restore the MIDR_EL1 > + * view 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. > + */ > + mpidr = ctxt_sys_reg(guest_ctxt, VMPIDR_EL2); > + } else { > + mpidr = ctxt_sys_reg(guest_ctxt, MPIDR_EL1); > + } > + > + __sysreg_restore_el1_state(guest_ctxt, mpidr); > + } > > vcpu->arch.sysregs_loaded_on_cpu = true; > > @@ -103,12 +216,20 @@ void kvm_vcpu_put_sysregs_vhe(struct kvm_vcpu *vcpu) > host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; > deactivate_traps_vhe_put(vcpu); > > - __sysreg_save_el1_state(guest_ctxt); > + if (unlikely(__is_hyp_ctxt(guest_ctxt))) > + __sysreg_save_vel2_state(guest_ctxt); > + else > + __sysreg_save_el1_state(guest_ctxt); > + > __sysreg_save_user_state(guest_ctxt); > __sysreg32_save_state(vcpu); > > /* Restore host user state */ > __sysreg_restore_user_state(host_ctxt); > > + /* If leaving a nesting guest, restore MPIDR_EL1 default view */ > + if (vcpu_has_nv(vcpu)) > + write_sysreg(read_cpuid_id(), vpidr_el2); > + > vcpu->arch.sysregs_loaded_on_cpu = false; Compared __sysreg_{save,restore}_vel2_state() with __sysreg_{save,restore}_el1_state(), they access the same registers. Also checked in the Arm ARM that the registers for which KVM doesn't differentiate between E2H set and cleared in virtual EL2 have the same encoding regardless of the value of HCR_EL2.E2H: Reviewed-by: Alexandru Elisei <alexandru.elisei@xxxxxxx> Thanks, Alex > } > -- > 2.30.2 > _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm