diff mbox series

[RFC,15/41] KVM: x86/pmu: Manage MSR interception for IA32_PERF_GLOBAL_CTRL

Message ID 20240126085444.324918-16-xiong.y.zhang@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series KVM: x86/pmu: Introduce passthrough vPM | expand

Commit Message

Xiong Zhang Jan. 26, 2024, 8:54 a.m. UTC
From: Xiong Zhang <xiong.y.zhang@intel.com>

In PMU passthrough mode, there are three requirements to manage
IA32_PERF_GLOBAL_CTRL:
 - guest IA32_PERF_GLOBAL_CTRL MSR must be saved at vm exit.
 - IA32_PERF_GLOBAL_CTRL MSR must be cleared at vm exit to avoid any
   counter of running within KVM runloop.
 - guest IA32_PERF_GLOBAL_CTRL MSR must be restored at vm entry.

Introduce vmx_set_perf_global_ctrl() function to auto switching
IA32_PERF_GLOBAL_CTR and invoke it after the VMM finishes setting up the
CPUID bits.

Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.com>
Signed-off-by: Mingwei Zhang <mizhang@google.com>
---
 arch/x86/include/asm/vmx.h |  1 +
 arch/x86/kvm/vmx/vmx.c     | 89 ++++++++++++++++++++++++++++++++------
 arch/x86/kvm/vmx/vmx.h     |  3 +-
 3 files changed, 78 insertions(+), 15 deletions(-)

Comments

Sean Christopherson April 11, 2024, 9:21 p.m. UTC | #1
On Fri, Jan 26, 2024, Xiong Zhang wrote:
> +	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);
> +		else {
> +			i = vmx_find_loadstore_msr_slot(&vmx->msr_autoload.guest,
> +						       MSR_CORE_PERF_GLOBAL_CTRL);
> +			if (i < 0) {
> +				i = vmx->msr_autoload.guest.nr++;
> +				vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT,
> +					     vmx->msr_autoload.guest.nr);
> +			}
> +			vmx->msr_autoload.guest.val[i].index = MSR_CORE_PERF_GLOBAL_CTRL;
> +			vmx->msr_autoload.guest.val[i].value = 0;

Eww, no.   Just make cpu_has_load_perf_global_ctrl() and VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL
hard requirements for enabling passthrough mode.  And then have clear_atomic_switch_msr()
yell if KVM tries to disable loading MSR_CORE_PERF_GLOBAL_CTRL.
Jim Mattson April 11, 2024, 10:30 p.m. UTC | #2
On Thu, Apr 11, 2024 at 2:21 PM Sean Christopherson <seanjc@google.com> wrote:
>
> On Fri, Jan 26, 2024, Xiong Zhang wrote:
> > +     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);
> > +             else {
> > +                     i = vmx_find_loadstore_msr_slot(&vmx->msr_autoload.guest,
> > +                                                    MSR_CORE_PERF_GLOBAL_CTRL);
> > +                     if (i < 0) {
> > +                             i = vmx->msr_autoload.guest.nr++;
> > +                             vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT,
> > +                                          vmx->msr_autoload.guest.nr);
> > +                     }
> > +                     vmx->msr_autoload.guest.val[i].index = MSR_CORE_PERF_GLOBAL_CTRL;
> > +                     vmx->msr_autoload.guest.val[i].value = 0;
>
> Eww, no.   Just make cpu_has_load_perf_global_ctrl() and VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL
> hard requirements for enabling passthrough mode.  And then have clear_atomic_switch_msr()
> yell if KVM tries to disable loading MSR_CORE_PERF_GLOBAL_CTRL.

Weren't you just complaining about the PMU version 4 constraint in
another patch? And here, you are saying, "Don't support anything older
than Sapphire Rapids."

Sapphire Rapids has PMU version 4, so if we require
VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL, PMU version 4 is irrelevant.
Sean Christopherson April 11, 2024, 11:27 p.m. UTC | #3
On Thu, Apr 11, 2024, Jim Mattson wrote:
> On Thu, Apr 11, 2024 at 2:21 PM Sean Christopherson <seanjc@google.com> wrote:
> >
> > On Fri, Jan 26, 2024, Xiong Zhang wrote:
> > > +     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);
> > > +             else {
> > > +                     i = vmx_find_loadstore_msr_slot(&vmx->msr_autoload.guest,
> > > +                                                    MSR_CORE_PERF_GLOBAL_CTRL);
> > > +                     if (i < 0) {
> > > +                             i = vmx->msr_autoload.guest.nr++;
> > > +                             vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT,
> > > +                                          vmx->msr_autoload.guest.nr);
> > > +                     }
> > > +                     vmx->msr_autoload.guest.val[i].index = MSR_CORE_PERF_GLOBAL_CTRL;
> > > +                     vmx->msr_autoload.guest.val[i].value = 0;
> >
> > Eww, no.   Just make cpu_has_load_perf_global_ctrl() and VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL
> > hard requirements for enabling passthrough mode.  And then have clear_atomic_switch_msr()
> > yell if KVM tries to disable loading MSR_CORE_PERF_GLOBAL_CTRL.
> 
> Weren't you just complaining about the PMU version 4 constraint in
> another patch? And here, you are saying, "Don't support anything older
> than Sapphire Rapids."

Heh, I didn't realize VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL was SPR+ when I wrote
this, I thought it existed alongside the "load" controls.

> Sapphire Rapids has PMU version 4, so if we require
> VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL, PMU version 4 is irrelevant.
Mi, Dapeng April 13, 2024, 2:10 a.m. UTC | #4
On 4/12/2024 6:30 AM, Jim Mattson wrote:
> On Thu, Apr 11, 2024 at 2:21 PM Sean Christopherson <seanjc@google.com> wrote:
>> On Fri, Jan 26, 2024, Xiong Zhang wrote:
>>> +     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);
>>> +             else {
>>> +                     i = vmx_find_loadstore_msr_slot(&vmx->msr_autoload.guest,
>>> +                                                    MSR_CORE_PERF_GLOBAL_CTRL);
>>> +                     if (i < 0) {
>>> +                             i = vmx->msr_autoload.guest.nr++;
>>> +                             vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT,
>>> +                                          vmx->msr_autoload.guest.nr);
>>> +                     }
>>> +                     vmx->msr_autoload.guest.val[i].index = MSR_CORE_PERF_GLOBAL_CTRL;
>>> +                     vmx->msr_autoload.guest.val[i].value = 0;
>> Eww, no.   Just make cpu_has_load_perf_global_ctrl() and VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL
>> hard requirements for enabling passthrough mode.  And then have clear_atomic_switch_msr()
>> yell if KVM tries to disable loading MSR_CORE_PERF_GLOBAL_CTRL.
> Weren't you just complaining about the PMU version 4 constraint in
> another patch? And here, you are saying, "Don't support anything older
> than Sapphire Rapids."
>
> Sapphire Rapids has PMU version 4, so if we require
> VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL, PMU version 4 is irrelevant.

Just clarify Sapphire Rapids has PMU version 5 :).

[    2.687826] Performance Events: XSAVE Architectural LBR, PEBS 
fmt4+-baseline,  AnyThread deprecated, *Sapphire Rapids events*, 32-deep 
LBR, full-width counters, Intel PMU driver.
[    2.687925] ... version:                   5
[    2.687928] ... bit width:                 48
[    2.687929] ... generic counters:          8

>
diff mbox series

Patch

diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 0e73616b82f3..f574e7b429a3 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -104,6 +104,7 @@ 
 #define VM_EXIT_CLEAR_BNDCFGS                   0x00800000
 #define VM_EXIT_PT_CONCEAL_PIP			0x01000000
 #define VM_EXIT_CLEAR_IA32_RTIT_CTL		0x02000000
+#define VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL      0x40000000
 
 #define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR	0x00036dff
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 33cb69ff0804..8ab266e1e2a7 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -4387,6 +4387,74 @@  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);
+	int i;
+
+       /*
+	* PERF_GLOBAL_CTRL is toggled dynamically in emulated vPMU.
+	*/
+	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);
+		else {
+			i = vmx_find_loadstore_msr_slot(&vmx->msr_autoload.guest,
+						       MSR_CORE_PERF_GLOBAL_CTRL);
+			if (i < 0) {
+				i = vmx->msr_autoload.guest.nr++;
+				vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT,
+					     vmx->msr_autoload.guest.nr);
+			}
+			vmx->msr_autoload.guest.val[i].index = MSR_CORE_PERF_GLOBAL_CTRL;
+			vmx->msr_autoload.guest.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);
+		else {
+			i = vmx_find_loadstore_msr_slot(&vmx->msr_autoload.host,
+							MSR_CORE_PERF_GLOBAL_CTRL);
+			if (i < 0) {
+				i = vmx->msr_autoload.host.nr++;
+				vmcs_write32(VM_EXIT_MSR_LOAD_COUNT,
+					     vmx->msr_autoload.host.nr);
+			}
+			vmx->msr_autoload.host.val[i].index = MSR_CORE_PERF_GLOBAL_CTRL;
+			vmx->msr_autoload.host.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)) {
+			i = vmx_find_loadstore_msr_slot(&vmx->msr_autostore.guest,
+							MSR_CORE_PERF_GLOBAL_CTRL);
+			if (i < 0) {
+				i = vmx->msr_autostore.guest.nr++;
+				vmcs_write32(VM_EXIT_MSR_STORE_COUNT,
+					     vmx->msr_autostore.guest.nr);
+			}
+			vmx->msr_autostore.guest.val[i].index = MSR_CORE_PERF_GLOBAL_CTRL;
+		}
+	}
+
+	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;
@@ -4394,15 +4462,9 @@  static u32 vmx_vmentry_ctrl(void)
 	if (vmx_pt_mode_is_system())
 		vmentry_ctrl &= ~(VM_ENTRY_PT_CONCEAL_PIP |
 				  VM_ENTRY_LOAD_IA32_RTIT_CTL);
-	/*
-	 * IA32e mode, and loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically.
-	 */
-	vmentry_ctrl &= ~(VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL |
-			  VM_ENTRY_LOAD_IA32_EFER |
-			  VM_ENTRY_IA32E_MODE);
 
-	if (cpu_has_perf_global_ctrl_bug())
-		vmentry_ctrl &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL;
+	/* IA32e mode, and loading of EFER is toggled dynamically. */
+	vmentry_ctrl &= ~(VM_ENTRY_LOAD_IA32_EFER | VM_ENTRY_IA32E_MODE);
 
 	return vmentry_ctrl;
 }
@@ -4422,12 +4484,8 @@  static u32 vmx_vmexit_ctrl(void)
 		vmexit_ctrl &= ~(VM_EXIT_PT_CONCEAL_PIP |
 				 VM_EXIT_CLEAR_IA32_RTIT_CTL);
 
-	if (cpu_has_perf_global_ctrl_bug())
-		vmexit_ctrl &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL;
-
-	/* Loading of EFER and PERF_GLOBAL_CTRL are toggled dynamically */
-	return vmexit_ctrl &
-		~(VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | VM_EXIT_LOAD_IA32_EFER);
+       /* Loading of EFER is toggled dynamically */
+       return vmexit_ctrl & ~VM_EXIT_LOAD_IA32_EFER;
 }
 
 static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
@@ -4765,6 +4823,7 @@  static void init_vmcs(struct vcpu_vmx *vmx)
 		vmcs_write64(VM_FUNCTION_CONTROL, 0);
 
 	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
+	vmcs_write64(VM_EXIT_MSR_STORE_ADDR, __pa(vmx->msr_autostore.guest.val));
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
 	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val));
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
@@ -7822,6 +7881,8 @@  static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
 	if (is_passthrough_pmu_enabled(&vmx->vcpu))
 		exec_controls_clearbit(vmx, CPU_BASED_RDPMC_EXITING);
 
+	vmx_set_perf_global_ctrl(vmx);
+
 	/* Refresh #PF interception to account for MAXPHYADDR changes. */
 	vmx_update_exception_bitmap(vcpu);
 }
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index c2130d2c8e24..c89db35e1de8 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -502,7 +502,8 @@  static inline u8 vmx_get_rvi(void)
 	       VM_EXIT_LOAD_IA32_EFER |					\
 	       VM_EXIT_CLEAR_BNDCFGS |					\
 	       VM_EXIT_PT_CONCEAL_PIP |					\
-	       VM_EXIT_CLEAR_IA32_RTIT_CTL)
+	       VM_EXIT_CLEAR_IA32_RTIT_CTL |                            \
+	       VM_EXIT_SAVE_IA32_PERF_GLOBAL_CTRL)
 
 #define KVM_REQUIRED_VMX_PIN_BASED_VM_EXEC_CONTROL			\
 	(PIN_BASED_EXT_INTR_MASK |					\