Message ID | 20240126085444.324918-29-xiong.y.zhang@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM: x86/pmu: Introduce passthrough vPM | expand |
On Fri, Jan 26, 2024, Xiong Zhang wrote: > +static void save_perf_global_ctrl_in_passthrough_pmu(struct vcpu_vmx *vmx) > +{ > + struct kvm_pmu *pmu = vcpu_to_pmu(&vmx->vcpu); > + int i; > + > + if (vm_exit_controls_get(vmx) & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL) { > + pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL); > + } else { > + i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore.guest, > + MSR_CORE_PERF_GLOBAL_CTRL); > + if (i < 0) > + return; > + pmu->global_ctrl = vmx->msr_autostore.guest.val[i].value; As before, NAK to using the MSR load/store lists unless there's a *really* good reason I'm missing. And we should consider adding VCPU_EXREG_GLOBAL_CTRL so that we can defer the VMREAD until KVM actually tries to access the guest value.
On Thu, Apr 11, 2024 at 2:54 PM Sean Christopherson <seanjc@google.com> wrote: > > On Fri, Jan 26, 2024, Xiong Zhang wrote: > > +static void save_perf_global_ctrl_in_passthrough_pmu(struct vcpu_vmx *vmx) > > +{ > > + struct kvm_pmu *pmu = vcpu_to_pmu(&vmx->vcpu); > > + int i; > > + > > + if (vm_exit_controls_get(vmx) & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL) { > > + pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL); > > + } else { > > + i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore.guest, > > + MSR_CORE_PERF_GLOBAL_CTRL); > > + if (i < 0) > > + return; > > + pmu->global_ctrl = vmx->msr_autostore.guest.val[i].value; > > As before, NAK to using the MSR load/store lists unless there's a *really* good > reason I'm missing. The VM-exit control, "save IA32_PERF_GLOBAL_CTL," first appears in Sapphire Rapids. I think that's a compelling reason. > And we should consider adding VCPU_EXREG_GLOBAL_CTRL so that we can defer the > VMREAD until KVM actually tries to access the guest value.
On Thu, Apr 11, 2024, Jim Mattson wrote: > On Thu, Apr 11, 2024 at 2:54 PM Sean Christopherson <seanjc@google.com> wrote: > > > > On Fri, Jan 26, 2024, Xiong Zhang wrote: > > > +static void save_perf_global_ctrl_in_passthrough_pmu(struct vcpu_vmx *vmx) > > > +{ > > > + struct kvm_pmu *pmu = vcpu_to_pmu(&vmx->vcpu); > > > + int i; > > > + > > > + if (vm_exit_controls_get(vmx) & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL) { > > > + pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL); > > > + } else { > > > + i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore.guest, > > > + MSR_CORE_PERF_GLOBAL_CTRL); > > > + if (i < 0) > > > + return; > > > + pmu->global_ctrl = vmx->msr_autostore.guest.val[i].value; > > > > As before, NAK to using the MSR load/store lists unless there's a *really* good > > reason I'm missing. > > The VM-exit control, "save IA32_PERF_GLOBAL_CTL," first appears in > Sapphire Rapids. I think that's a compelling reason. Well that's annoying. When was PMU v4 introduced? E.g. if it came in ICX, I'd be sorely tempted to make VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL a hard requirement. And has someone confirmed that the CPU saves into the MSR store list before processing VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL? Assuming we don't make VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL a hard requirement, this code should be cleaned up and simplified. It should be impossible to get to this point with a passthrough PMU and no slot for saving guest GLOBAL_CTRL. E.g. this could simply be: if (cpu_has_save_perf_global_ctrl()) pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL); else pmu->global_ctrl = *pmu->__global_ctrl; where vmx_set_perf_global_ctrl() sets __global_ctrl to: pmu->__global_ctrl = &vmx->msr_autostore.guest.val[i].value; KVM could store 'i', i.e. the slot, but in the end it's 4 bytes per vCPU (assuming 64-bit kernel, and an int to store the slot). Oh, by the by, vmx_set_perf_global_ctrl() is buggy, as it neglects to *remove* PERF_GLOBAL_CTRL from the lists if userspace sets CPUID multiple times.
On Thu, Apr 11, 2024 at 3:54 PM Sean Christopherson <seanjc@google.com> wrote: > > On Thu, Apr 11, 2024, Jim Mattson wrote: > > On Thu, Apr 11, 2024 at 2:54 PM Sean Christopherson <seanjc@google.com> wrote: > > > > > > On Fri, Jan 26, 2024, Xiong Zhang wrote: > > > > +static void save_perf_global_ctrl_in_passthrough_pmu(struct vcpu_vmx *vmx) > > > > +{ > > > > + struct kvm_pmu *pmu = vcpu_to_pmu(&vmx->vcpu); > > > > + int i; > > > > + > > > > + if (vm_exit_controls_get(vmx) & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL) { > > > > + pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL); > > > > + } else { > > > > + i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore.guest, > > > > + MSR_CORE_PERF_GLOBAL_CTRL); > > > > + if (i < 0) > > > > + return; > > > > + pmu->global_ctrl = vmx->msr_autostore.guest.val[i].value; > > > > > > As before, NAK to using the MSR load/store lists unless there's a *really* good > > > reason I'm missing. > > > > The VM-exit control, "save IA32_PERF_GLOBAL_CTL," first appears in > > Sapphire Rapids. I think that's a compelling reason. > > Well that's annoying. When was PMU v4 introduced? E.g. if it came in ICX, I'd > be sorely tempted to make VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL a hard requirement. Broadwell was v3. Skylake was v4. > And has someone confirmed that the CPU saves into the MSR store list before > processing VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL? It's at the top of chapter 28 in volume 3 of the SDM. MSRs may be saved in the VM-exit MSR-store area before processor state is loaded based in part on the host-state area and some VM-exit controls. Anything else would be stupid. (Yes, I know that this is CPU design we're talking about!)
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 50100954cd92..a9623351eafe 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7193,7 +7193,7 @@ static void vmx_cancel_injection(struct kvm_vcpu *vcpu) vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); } -static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) +static void __atomic_switch_perf_msrs(struct vcpu_vmx *vmx) { int i, nr_msrs; struct perf_guest_switch_msr *msrs; @@ -7216,6 +7216,52 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) msrs[i].host, false); } +static void save_perf_global_ctrl_in_passthrough_pmu(struct vcpu_vmx *vmx) +{ + struct kvm_pmu *pmu = vcpu_to_pmu(&vmx->vcpu); + int i; + + if (vm_exit_controls_get(vmx) & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL) { + pmu->global_ctrl = vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL); + } else { + i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore.guest, + MSR_CORE_PERF_GLOBAL_CTRL); + if (i < 0) + return; + pmu->global_ctrl = vmx->msr_autostore.guest.val[i].value; + } +} + +static void load_perf_global_ctrl_in_passthrough_pmu(struct vcpu_vmx *vmx) +{ + u64 global_ctrl = vcpu_to_pmu(&vmx->vcpu)->global_ctrl; + int i; + + if (vm_entry_controls_get(vmx) & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) { + vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, global_ctrl); + } else { + i = vmx_find_loadstore_msr_slot(&vmx->msr_autoload.guest, + MSR_CORE_PERF_GLOBAL_CTRL); + if (i < 0) + return; + + vmx->msr_autoload.guest.val[i].value = global_ctrl; + } +} + +static void __atomic_switch_perf_msrs_in_passthrough_pmu(struct vcpu_vmx *vmx) +{ + load_perf_global_ctrl_in_passthrough_pmu(vmx); +} + +static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) +{ + if (is_passthrough_pmu_enabled(&vmx->vcpu)) + __atomic_switch_perf_msrs_in_passthrough_pmu(vmx); + else + __atomic_switch_perf_msrs(vmx); +} + static void vmx_update_hv_timer(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -7314,6 +7360,9 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu, vcpu->arch.cr2 = native_read_cr2(); vcpu->arch.regs_avail &= ~VMX_REGS_LAZY_LOAD_SET; + if (is_passthrough_pmu_enabled(vcpu)) + save_perf_global_ctrl_in_passthrough_pmu(vmx); + vmx->idt_vectoring_info = 0; vmx_enable_fb_clear(vmx);