On 7/31/2024 9:58 PM, Mingwei Zhang wrote: > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c > index 339742350b7a..34a420fa98c5 100644 > --- a/arch/x86/kvm/vmx/vmx.c > +++ b/arch/x86/kvm/vmx/vmx.c > @@ -4394,6 +4394,97 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx) > return pin_based_exec_ctrl; > } > > +static void vmx_set_perf_global_ctrl(struct vcpu_vmx *vmx) > +{ > + u32 vmentry_ctrl = vm_entry_controls_get(vmx); > + u32 vmexit_ctrl = vm_exit_controls_get(vmx); > + struct vmx_msrs *m; > + int i; > + > + if (cpu_has_perf_global_ctrl_bug() || > + !is_passthrough_pmu_enabled(&vmx->vcpu)) { > + vmentry_ctrl &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; > + vmexit_ctrl &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; > + vmexit_ctrl &= ~VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL; > + } > + > + if (is_passthrough_pmu_enabled(&vmx->vcpu)) { > + /* > + * Setup auto restore guest PERF_GLOBAL_CTRL MSR at vm entry. > + */ > + if (vmentry_ctrl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) { > + vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, 0); To save and restore Global Ctrl MSR at VMX transitions, I'm wondering if there are particular reasons why we prefer VMCS exec control over VMX-transition MSR areas? If no, I'd suggest to use the MSR area approach only for two reasons: 1. Simpler code. In this patch set, in total it takes ~100 LOC to handle the switch of this MSR. 2. With exec ctr approach, it needs one expensive VMCS read instruction to save guest Global Ctrl on every VM exit and one VMCS write in VM entry. (covered in patch 37) > + } else { > + m = &vmx->msr_autoload.guest; > + i = vmx_find_loadstore_msr_slot(m, MSR_CORE_PERF_GLOBAL_CTRL); > + if (i < 0) { > + i = m->nr++; > + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr); > + } > + m->val[i].index = MSR_CORE_PERF_GLOBAL_CTRL; > + m->val[i].value = 0; > + } > + /* > + * Setup auto clear host PERF_GLOBAL_CTRL msr at vm exit. > + */ > + if (vmexit_ctrl & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) { > + vmcs_write64(HOST_IA32_PERF_GLOBAL_CTRL, 0); ditto. > + } else { > + m = &vmx->msr_autoload.host; > + i = vmx_find_loadstore_msr_slot(m, MSR_CORE_PERF_GLOBAL_CTRL); > + if (i < 0) { > + i = m->nr++; > + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr); > + } > + m->val[i].index = MSR_CORE_PERF_GLOBAL_CTRL; > + m->val[i].value = 0; > + } > + /* > + * Setup auto save guest PERF_GLOBAL_CTRL msr at vm exit > + */ > + if (!(vmexit_ctrl & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL)) { > + m = &vmx->msr_autostore.guest; > + i = vmx_find_loadstore_msr_slot(m, MSR_CORE_PERF_GLOBAL_CTRL); > + if (i < 0) { > + i = m->nr++; > + vmcs_write32(VM_EXIT_MSR_STORE_COUNT, m->nr); > + } > + m->val[i].index = MSR_CORE_PERF_GLOBAL_CTRL; > + } > + } else { > + if (!(vmentry_ctrl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)) { > + m = &vmx->msr_autoload.guest; > + i = vmx_find_loadstore_msr_slot(m, MSR_CORE_PERF_GLOBAL_CTRL); > + if (i >= 0) { > + m->nr--; > + m->val[i] = m->val[m->nr]; > + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr); > + } > + } > + if (!(vmexit_ctrl & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL)) { > + m = &vmx->msr_autoload.host; > + i = vmx_find_loadstore_msr_slot(m, MSR_CORE_PERF_GLOBAL_CTRL); > + if (i >= 0) { > + m->nr--; > + m->val[i] = m->val[m->nr]; > + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr); > + } > + } > + if (!(vmexit_ctrl & VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL)) { > + m = &vmx->msr_autostore.guest; > + i = vmx_find_loadstore_msr_slot(m, MSR_CORE_PERF_GLOBAL_CTRL); > + if (i >= 0) { > + m->nr--; > + m->val[i] = m->val[m->nr]; > + vmcs_write32(VM_EXIT_MSR_STORE_COUNT, m->nr); > + } > + } > + } > + > + vm_entry_controls_set(vmx, vmentry_ctrl); > + vm_exit_controls_set(vmx, vmexit_ctrl); > +} > + > static u32 vmx_vmentry_ctrl(void) > { > u32 vmentry_ctrl = vmcs_config.vmentry_ctrl;