From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 50ACE1F471F; Tue, 3 Feb 2026 18:17:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142654; cv=none; b=knZjDxorMHD4HgMNnqjCysJ9z1GYEKMewuUCMX6W6LV64PKM0evRKVp1xUyTEmeoN7XTAQhUvVRBPWWOGPf25tOStqPXryPLG5H9rLl1rPKWOTjIklWO7Mew286bYEbc5k4FYo/HUsJsl18snHe0TwSZX4jVXLnypKg5V8CwwKY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142654; c=relaxed/simple; bh=slCSGj+JBFhyh3GRqC7AbCQMZ+OirmH4eDMYMwIG5gE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=d7+w9MspyOCyVk1y4jv/GdHiKAXTGcCu77K/J0UaeZdaSBRdTHtSa1dVwgzObOxL7xGwRN4Iw1Y8eBd0dtBjqiM6e4zYZ9eNHYGNRj0zCWB3zdazhtRiS0rNbbMm1FMem4/9wP2Lzdurv6CkR7w3QStZOMEkH63E/9rvFMdZXuM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=ib2zTYL3; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="ib2zTYL3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142652; x=1801678652; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=slCSGj+JBFhyh3GRqC7AbCQMZ+OirmH4eDMYMwIG5gE=; b=ib2zTYL3rx5ji6E7LrSc27E67ek0k2Hb+jbRZGuf29lnI3AXbB/MksvR 1wTZvOehQlKHz+4fgVBT/kMKzpASXYkrTPogYmVco3WVZ1wbBLuRtQMKF 8M4DcVeMf19WAChEULIHQb3ZogvMz1C89odcxoB13EXZWsvCOXL9F6PbS 7bXL7crh/dKX5OklMz2eqgn+eSD2vGJO35HtZ4Ce6Jr63URXN1R2G6YII Or4AG3+ZmZ2CqcSfZ8/iur7fOSB7mqFrDv05MkSzirjDcmuNk8r7NueGI qUnRh0tesT7XAw4hHk8EAAhUpPp06hB3FdY1pOQxeAchCJlivWtEnsJ9D Q==; X-CSE-ConnectionGUID: LHrkkBPXQMu7on2nh2SmYg== X-CSE-MsgGUID: gB/OFl4ST8O78+/EnZPc1w== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433155" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433155" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:31 -0800 X-CSE-ConnectionGUID: 38pKlMxpRXa48bcnsyGnrQ== X-CSE-MsgGUID: /z+fyx4uRkykteJwtIIHqg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727447" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:31 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, Yang Zhong Subject: [PATCH 01/32] KVM: VMX: Detect APIC timer virtualization bit Date: Tue, 3 Feb 2026 10:16:44 -0800 Message-ID: <387a84de1bdf461c895da0a3812ea0cde1434716.1770116050.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yang Zhong Detect the APIC timer virtualization feature by setting the bit (bit 8) in the tertiary processor-based VM-execution controls. Additionally, define the new related VMCS fields necessary for managing this feature. Do not enable the feature bit in the tertiary VM exec control yet until the supporting logic is implemented. Signed-off-by: Yang Zhong Signed-off-by: Isaku Yamahata --- arch/x86/include/asm/vmx.h | 6 ++++++ arch/x86/include/asm/vmxfeatures.h | 1 + arch/x86/kvm/vmx/vmx.c | 10 ++++++++++ arch/x86/kvm/vmx/vmx.h | 1 + 4 files changed, 18 insertions(+) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index c85c50019523..99f853bd8a4c 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -85,6 +85,7 @@ * Definitions of Tertiary Processor-Based VM-Execution Controls. */ #define TERTIARY_EXEC_IPI_VIRT VMCS_CONTROL_BIT(IPI_VIRT) +#define TERTIARY_EXEC_GUEST_APIC_TIMER VMCS_CONTROL_BIT(GUEST_APIC_TIMER) =20 #define PIN_BASED_EXT_INTR_MASK VMCS_CONTROL_BIT(INTR_EXIT= ING) #define PIN_BASED_NMI_EXITING VMCS_CONTROL_BIT(NMI_EXITI= NG) @@ -192,6 +193,7 @@ enum vmcs_field { VIRTUAL_PROCESSOR_ID =3D 0x00000000, POSTED_INTR_NV =3D 0x00000002, LAST_PID_POINTER_INDEX =3D 0x00000008, + GUEST_APIC_TIMER_VECTOR =3D 0x0000000a, GUEST_ES_SELECTOR =3D 0x00000800, GUEST_CS_SELECTOR =3D 0x00000802, GUEST_SS_SELECTOR =3D 0x00000804, @@ -262,6 +264,8 @@ enum vmcs_field { SHARED_EPT_POINTER =3D 0x0000203C, PID_POINTER_TABLE =3D 0x00002042, PID_POINTER_TABLE_HIGH =3D 0x00002043, + GUEST_DEADLINE_VIR =3D 0x0000204e, + GUEST_DEADLINE_VIR_HIGH =3D 0x0000204f, GUEST_PHYSICAL_ADDRESS =3D 0x00002400, GUEST_PHYSICAL_ADDRESS_HIGH =3D 0x00002401, VMCS_LINK_POINTER =3D 0x00002800, @@ -286,6 +290,8 @@ enum vmcs_field { GUEST_BNDCFGS_HIGH =3D 0x00002813, GUEST_IA32_RTIT_CTL =3D 0x00002814, GUEST_IA32_RTIT_CTL_HIGH =3D 0x00002815, + GUEST_DEADLINE_PHY =3D 0x00002830, + GUEST_DEADLINE_PHY_HIGH =3D 0x00002831, HOST_IA32_PAT =3D 0x00002c00, HOST_IA32_PAT_HIGH =3D 0x00002c01, HOST_IA32_EFER =3D 0x00002c02, diff --git a/arch/x86/include/asm/vmxfeatures.h b/arch/x86/include/asm/vmxf= eatures.h index 09b1d7e607c1..f2eb4243bae4 100644 --- a/arch/x86/include/asm/vmxfeatures.h +++ b/arch/x86/include/asm/vmxfeatures.h @@ -90,4 +90,5 @@ =20 /* Tertiary Processor-Based VM-Execution Controls, word 3 */ #define VMX_FEATURE_IPI_VIRT ( 3*32+ 4) /* "ipi_virt" Enable IPI virtual= ization */ +#define VMX_FEATURE_GUEST_APIC_TIMER ( 3*32+ 8) /* Enable virtual APIC ts= c deadline */ #endif /* _ASM_X86_VMXFEATURES_H */ diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 6b96f7aea20b..6d0d2d8ebcff 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2789,6 +2789,9 @@ static int setup_vmcs_config(struct vmcs_config *vmcs= _conf, adjust_vmx_controls64(KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL, MSR_IA32_VMX_PROCBASED_CTLS3); =20 + if (!(_cpu_based_2nd_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)) + _cpu_based_3rd_exec_control &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; + if (adjust_vmx_controls(KVM_REQUIRED_VMX_VM_EXIT_CONTROLS, KVM_OPTIONAL_VMX_VM_EXIT_CONTROLS, MSR_IA32_VMX_EXIT_CTLS, @@ -4616,6 +4619,13 @@ static u64 vmx_tertiary_exec_control(struct vcpu_vmx= *vmx) if (!enable_ipiv || !kvm_vcpu_apicv_active(&vmx->vcpu)) exec_control &=3D ~TERTIARY_EXEC_IPI_VIRT; =20 + /* + * APIC timer virtualization is supported only for TSC deadline mode. + * Disable for one-shot/periodic mode. Dynamically set/clear the bit + * on the guest timer mode change. Disable on reset state. + */ + exec_control &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; + return exec_control; } =20 diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index bc3ed3145d7e..cb32d0fdf3b8 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -584,6 +584,7 @@ static inline u8 vmx_get_rvi(void) SECONDARY_EXEC_EPT_VIOLATION_VE) =20 #define KVM_REQUIRED_VMX_TERTIARY_VM_EXEC_CONTROL 0 +/* Once apic timer virtualization supported, add TERTIARY_EXEC_GUEST_APIC_= TIMER */ #define KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL \ (TERTIARY_EXEC_IPI_VIRT) =20 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8574431B830; Tue, 3 Feb 2026 18:17:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142654; cv=none; b=UX4jnZFcXh4lgR580WwQ2xISPhjbMpdKB7OFXFiGinuefCYoxjFYTR5ENt0YuBJWdNLmoQgv/EBzelIBJAz9SkrSD+7MSKd9KpQk/u0pf4igNrBI8J2AHsdOcst+GfoLyNvF3nQb8rSAwfal33+Te1oQyUz8HMv1LsIv4Hz1V8A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142654; c=relaxed/simple; bh=oWoJrfPihrgDy/XI8mj5RjgXHEmS9GRKCwFpQbmnfUU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dYNSjYZ/qYeuPBWqjnKTL4BHQyMIyIVWIVEz3T4qqKkqtikN02EzfNM6OmJxcRA4VPzM6ImFOt6ghxqUKPWgqa9esKkkGm8fxKyVSDLdzrGSnBOdCRNzJMy/+CPNVn+KDPGlLcA1wEdLaCqHB/Qj/0SnvfcuI1It03qJDMitqaU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=bugbZ6lI; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="bugbZ6lI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142652; x=1801678652; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oWoJrfPihrgDy/XI8mj5RjgXHEmS9GRKCwFpQbmnfUU=; b=bugbZ6lIJb87hLmcH3Z5WMAiK5OxSobT0U62dRZLT6KMR9F/DdxMEA/U ix1NB2g+MEOdQIJhKtiOW02xy/DuAbAxBVCEZfYDA6diEDl7eEY9Ynrn/ va14OeNBX/kqAGGYnGLKrneltPvTHR5RshaBruTkSsY2fi4Xk00PD0pqG FKE1HtkgmiouI18z+4YUW276YbXeLbSo+I1pAqg7WF3U/vNVXL96TgPGi 7BQCFdaY0oCy5t5rjqrFM8ivczKncV/RnPnOoEwPl+pU6uMfArPNlPcaP vdSLtfvRf4hACmdY5I7RYl2wFB/A6KQya68KOedFi5C/TBNXANBcfnoB9 Q==; X-CSE-ConnectionGUID: BRlo66wPS2SvXVC2woIn2g== X-CSE-MsgGUID: uTMcNX8YTmGpCftOaA9W3A== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433161" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433161" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:32 -0800 X-CSE-ConnectionGUID: yuTfLe18TWyPyEnhCDEM/g== X-CSE-MsgGUID: Hn4W1dEqRcGvTsOfRd5k0g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727454" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:32 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, Yang Zhong Subject: [PATCH 02/32] KVM: x86: Implement APIC virt timer helpers with callbacks Date: Tue, 3 Feb 2026 10:16:45 -0800 Message-ID: <995074de8754f559b59c65d76aeb940fac122bd3.1770116050.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yang Zhong Add an additional APIC emulation mode for APIC timer virtualization. When the guest programs the local APIC timer mode, switch to this new emulation mode using the newly added hooks when APIC timer virtualization is available. Add five x86 KVM callbacks for APIC timer virtualization. These callbacks are analogous to those used for the preemption timer and will be invoked by kvm/lapic. These helpers start/stop the timer once the APIC virt timer feature is enabled and the guest sets the MSR_IA32_TSC_DEADLINE. Upon updating the TSC deadline mode in the APIC_LVTT register, KVM's LAPIC will initiate the APIC virt timer instead of the preemption timer. Co-developed-by: Yang Zhong Signed-off-by: Yang Zhong Co-developed-by: Isaku Yamahata Signed-off-by: Isaku Yamahata --- arch/x86/include/asm/kvm-x86-ops.h | 5 ++ arch/x86/include/asm/kvm_host.h | 6 +++ arch/x86/kvm/lapic.c | 81 +++++++++++++++++++++++++++++- arch/x86/kvm/lapic.h | 1 + 4 files changed, 91 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-= x86-ops.h index de709fb5bd76..09f664aa72c1 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -118,6 +118,11 @@ KVM_X86_OP_OPTIONAL_RET0(dy_apicv_has_pending_interrup= t) KVM_X86_OP_OPTIONAL(protected_apic_has_interrupt) KVM_X86_OP_OPTIONAL(set_hv_timer) KVM_X86_OP_OPTIONAL(cancel_hv_timer) +KVM_X86_OP_OPTIONAL(can_use_apic_virt_timer) +KVM_X86_OP_OPTIONAL(set_apic_virt_timer) +KVM_X86_OP_OPTIONAL(cancel_apic_virt_timer) +KVM_X86_OP_OPTIONAL(set_guest_tsc_deadline_virt) +KVM_X86_OP_OPTIONAL(get_guest_tsc_deadline_virt) KVM_X86_OP(setup_mce) #ifdef CONFIG_KVM_SMM KVM_X86_OP(smi_allowed) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index 5a3bfa293e8b..9fabaf532e41 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1896,6 +1896,12 @@ struct kvm_x86_ops { int (*set_hv_timer)(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc, bool *expired); void (*cancel_hv_timer)(struct kvm_vcpu *vcpu); + bool (*can_use_apic_virt_timer)(struct kvm_vcpu *vcpu); + void (*set_apic_virt_timer)(struct kvm_vcpu *vcpu, u16 vector); + void (*cancel_apic_virt_timer)(struct kvm_vcpu *vcpu); + void (*set_guest_tsc_deadline_virt)(struct kvm_vcpu *vcpu, + u64 tscdeadline); + u64 (*get_guest_tsc_deadline_virt)(struct kvm_vcpu *vcpu); =20 void (*setup_mce)(struct kvm_vcpu *vcpu); =20 diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 1597dd0b0cc6..b942210c6a25 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -131,7 +131,8 @@ static inline u32 kvm_x2apic_id(struct kvm_lapic *apic) static bool kvm_can_post_timer_interrupt(struct kvm_vcpu *vcpu) { return pi_inject_timer && kvm_vcpu_apicv_active(vcpu) && - (kvm_mwait_in_guest(vcpu->kvm) || kvm_hlt_in_guest(vcpu->kvm)); + (kvm_mwait_in_guest(vcpu->kvm) || kvm_hlt_in_guest(vcpu->kvm)) && + !vcpu->arch.apic->lapic_timer.apic_virt_timer_in_use; } =20 static bool kvm_can_use_hv_timer(struct kvm_vcpu *vcpu) @@ -1817,17 +1818,81 @@ static void limit_periodic_timer_frequency(struct k= vm_lapic *apic) } =20 static void cancel_hv_timer(struct kvm_lapic *apic); +static void cancel_apic_virt_timer(struct kvm_lapic *apic); =20 -static void cancel_apic_timer(struct kvm_lapic *apic) +static void __cancel_apic_timer(struct kvm_lapic *apic) { hrtimer_cancel(&apic->lapic_timer.timer); preempt_disable(); if (apic->lapic_timer.hv_timer_in_use) cancel_hv_timer(apic); + else if (apic->lapic_timer.apic_virt_timer_in_use) + cancel_apic_virt_timer(apic); preempt_enable(); +} + +static void cancel_apic_timer(struct kvm_lapic *apic) +{ + __cancel_apic_timer(apic); atomic_set(&apic->lapic_timer.pending, 0); } =20 +static void start_apic_timer(struct kvm_lapic *apic); + +static void cancel_apic_virt_timer(struct kvm_lapic *apic) +{ + struct kvm_vcpu *vcpu =3D apic->vcpu; + + apic->lapic_timer.tscdeadline =3D kvm_x86_call(get_guest_tsc_deadline_vir= t)(vcpu); + kvm_x86_call(set_guest_tsc_deadline_virt)(vcpu, 0); + + kvm_x86_call(cancel_apic_virt_timer)(vcpu); + apic->lapic_timer.apic_virt_timer_in_use =3D false; +} + +static void apic_cancel_apic_virt_timer(struct kvm_lapic *apic) +{ + if (!apic->lapic_timer.apic_virt_timer_in_use) + return; + + cancel_apic_virt_timer(apic); + start_apic_timer(apic); +} + +static void apic_set_apic_virt_timer(struct kvm_lapic *apic) +{ + struct kvm_timer *ktimer =3D &apic->lapic_timer; + struct kvm_vcpu *vcpu =3D apic->vcpu; + u8 vector; + u32 reg; + + if (apic->lapic_timer.apic_virt_timer_in_use) + return; + + reg =3D kvm_lapic_get_reg(apic, APIC_LVTT); + vector =3D reg & APIC_VECTOR_MASK; + + __cancel_apic_timer(apic); + kvm_x86_call(set_apic_virt_timer)(vcpu, vector); + kvm_x86_call(set_guest_tsc_deadline_virt)(vcpu, ktimer->tscdeadline); + ktimer->apic_virt_timer_in_use =3D true; +} + +static bool kvm_can_use_apic_virt_timer(struct kvm_vcpu *vcpu) +{ + return kvm_x86_ops.can_use_apic_virt_timer && + apic_lvt_enabled(vcpu->arch.apic, APIC_LVTT) && + kvm_x86_call(can_use_apic_virt_timer)(vcpu); +} + +static void apic_update_apic_virt_timer(struct kvm_lapic *apic) +{ + if (kvm_can_use_apic_virt_timer(apic->vcpu)) + apic_set_apic_virt_timer(apic); + else + apic_cancel_apic_virt_timer(apic); +} + static void apic_update_lvtt(struct kvm_lapic *apic) { u32 timer_mode =3D kvm_lapic_get_reg(apic, APIC_LVTT) & @@ -1840,10 +1905,19 @@ static void apic_update_lvtt(struct kvm_lapic *apic) kvm_lapic_set_reg(apic, APIC_TMICT, 0); apic->lapic_timer.period =3D 0; apic->lapic_timer.tscdeadline =3D 0; + + if (apic->lapic_timer.apic_virt_timer_in_use) + kvm_x86_call(set_guest_tsc_deadline_virt)(apic->vcpu, 0); } apic->lapic_timer.timer_mode =3D timer_mode; limit_periodic_timer_frequency(apic); } + + /* + * Update on not only timer mode change, but also mask change + * for the case of timer_mode =3D TSCDEADLINE, mask =3D 1. + */ + apic_update_apic_virt_timer(apic); } =20 /* @@ -2265,6 +2339,9 @@ static void restart_apic_timer(struct kvm_lapic *apic) if (!apic_lvtt_period(apic) && atomic_read(&apic->lapic_timer.pending)) goto out; =20 + if (apic->lapic_timer.apic_virt_timer_in_use) + goto out; + if (!start_hv_timer(apic)) start_sw_timer(apic); out: diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 282b9b7da98c..42fbb66f1e4e 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -57,6 +57,7 @@ struct kvm_timer { u32 timer_advance_ns; atomic_t pending; /* accumulated triggered timers */ bool hv_timer_in_use; + bool apic_virt_timer_in_use; }; =20 struct kvm_lapic { --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A5C2236681F; Tue, 3 Feb 2026 18:17:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142656; cv=none; b=NYEjBjM3ZgYZtUFMzep0VBmxycY9cDf5rmiE08ALqpf5M9sqMTzYOFb1i9OsGDoCxKrdpCdxPNrYW4qGa8tddnZKgCq168wetxze8J2DpgzxdAxmVPMbXPitbN0yRw2/O+9LhY/i3HfOkr1/UlCAPFxB5LNjnWl73GrRpjFvQ/Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142656; c=relaxed/simple; bh=aCKhLSC9cSpDGKMJzFvx5enOYQp21sjnziHx6Q4aa+4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=irVg8uFyzohOgVTNVx+IYeAFOcCzNqBaB9gGrrdqK86KUfLeKZhfV5cw7JEQxtynCTUl1wPkalrcNsQLjudM6xgSQt05b2Btj5AAWj3ixW4Z935PWWyhL6BDVBYYgC4zXGLPZdl3WX+OuCAdwv/h/FmbYbAj43zG9sco2FraJWo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=aaqWCCJ4; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="aaqWCCJ4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142653; x=1801678653; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=aCKhLSC9cSpDGKMJzFvx5enOYQp21sjnziHx6Q4aa+4=; b=aaqWCCJ4edrB+Yn2kFBFdUFGwxOSVzf7No8GxvmUN9JOAHaNVHoQrRG1 W1PnM92mtk8Kqkcy9yxXt53dSYfmuqKPmBqM2FpjN+NG/CLNSpO18wO8+ WrLfzdhhI5kCovQkG2OnO47EvDBOhXtT2fZqG5CKzRMm86pkTrKIrusM/ VGRHYN0p7l+q76jOjpsVenZ2rZP+vHyci9ABsVWvJhMuTYRWXOAgYNEmC +I0Xjy6Z5QsT8Repdpw8yLr+5+cSPvS+4J7mygmg7G6H5sQZcHj/HW+7E 5bKxlcayzz5jHdvhVUVAFcI+CTCTLKHdkFEg/2mM/5ZuyRJ4bnn9j5Y2U Q==; X-CSE-ConnectionGUID: oGljXx1KQBmZ2vDHcyTaYQ== X-CSE-MsgGUID: XO+94rEHTfangXGpNUeamw== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433166" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433166" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:32 -0800 X-CSE-ConnectionGUID: s2E7sISEREuaqrGICI+fUg== X-CSE-MsgGUID: OT/LvNxWQHmvYHzo0fXkSg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727474" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:33 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, Yang Zhong Subject: [PATCH 03/32] KVM: x86/lapic: Start/stop sw/hv timer on vCPU un/block Date: Tue, 3 Feb 2026 10:16:46 -0800 Message-ID: <0ff98f7888b5ff26d5a2c546587dcb52234aafe9.1770116050.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yang Zhong Switch to use software timer when a vCPU is blocked by instructions such as HLT similar to the hv timer case. The guest deadline shadow field is read to obtain the guest_tsc value, which is then used to program an hrtimer for the duration of the vCPU block. Upon completion of the block, if the LAPIC timer has pending interrupts, the LAPIC timer is transitioned to APIC virt timer mode to continue providing timer services to the guest. Set the guest TSC deadline to 0 when injecting a timer interrupt, as the TSC deadline is cleared to zero when a timer interrupt is injected. Do so when injecting a timer interrupt to the vCPU. Co-developed-by: Yang Zhong Signed-off-by: Yang Zhong Co-developed-by: Isaku Yamahata Signed-off-by: Isaku Yamahata --- arch/x86/kvm/lapic.c | 20 +++++++++++++++++--- arch/x86/kvm/lapic.h | 6 ++++++ arch/x86/kvm/x86.c | 7 +++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index b942210c6a25..ee15d3bf5ef9 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2041,6 +2041,8 @@ static void kvm_apic_inject_pending_timer_irqs(struct= kvm_lapic *apic) kvm_apic_local_deliver(apic, APIC_LVTT); if (apic_lvtt_tscdeadline(apic)) { ktimer->tscdeadline =3D 0; + if (apic->lapic_timer.apic_virt_timer_in_use) + kvm_x86_call(set_guest_tsc_deadline_virt)(apic->vcpu, 0); } else if (apic_lvtt_oneshot(apic)) { ktimer->tscdeadline =3D 0; ktimer->target_expiration =3D 0; @@ -2320,8 +2322,10 @@ static void start_sw_timer(struct kvm_lapic *apic) struct kvm_timer *ktimer =3D &apic->lapic_timer; =20 WARN_ON(preemptible()); - if (apic->lapic_timer.hv_timer_in_use) + if (apic->lapic_timer.hv_timer_in_use) { cancel_hv_timer(apic); + trace_kvm_hv_timer_state(apic->vcpu->vcpu_id, false); + } if (!apic_lvtt_period(apic) && atomic_read(&ktimer->pending)) return; =20 @@ -2329,7 +2333,6 @@ static void start_sw_timer(struct kvm_lapic *apic) start_sw_period(apic); else if (apic_lvtt_tscdeadline(apic)) start_sw_tscdeadline(apic); - trace_kvm_hv_timer_state(apic->vcpu->vcpu_id, false); } =20 static void restart_apic_timer(struct kvm_lapic *apic) @@ -2374,13 +2377,24 @@ void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *= vcpu) restart_apic_timer(vcpu->arch.apic); } =20 +void kvm_lapic_switch_to_apic_virt_timer(struct kvm_vcpu *vcpu) +{ + hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); +} + void kvm_lapic_switch_to_sw_timer(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic =3D vcpu->arch.apic; =20 preempt_disable(); + + if (apic->lapic_timer.apic_virt_timer_in_use) + apic->lapic_timer.tscdeadline =3D + kvm_x86_call(get_guest_tsc_deadline_virt)(vcpu); + /* Possibly the TSC deadline timer is not enabled yet */ - if (apic->lapic_timer.hv_timer_in_use) + if (apic->lapic_timer.hv_timer_in_use || + apic->lapic_timer.apic_virt_timer_in_use) start_sw_timer(apic); preempt_enable(); } diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 42fbb66f1e4e..67172fef1b5b 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -241,10 +241,16 @@ bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct = kvm_lapic_irq *irq, struct kvm_vcpu **dest_vcpu); void kvm_lapic_switch_to_sw_timer(struct kvm_vcpu *vcpu); void kvm_lapic_switch_to_hv_timer(struct kvm_vcpu *vcpu); +void kvm_lapic_switch_to_apic_virt_timer(struct kvm_vcpu *vcpu); void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu); bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu); void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu); =20 +static inline bool kvm_lapic_apic_virt_timer_in_use(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.apic->lapic_timer.apic_virt_timer_in_use; +} + static inline enum lapic_mode kvm_apic_mode(u64 apic_base) { return apic_base & (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 63afdb6bb078..2a72709aeb03 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -11563,7 +11563,7 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) /* Called within kvm->srcu read side. */ static inline int vcpu_block(struct kvm_vcpu *vcpu) { - bool hv_timer; + bool hv_timer, virt_timer; =20 if (!kvm_arch_vcpu_runnable(vcpu)) { /* @@ -11574,7 +11574,8 @@ static inline int vcpu_block(struct kvm_vcpu *vcpu) * timer before blocking. */ hv_timer =3D kvm_lapic_hv_timer_in_use(vcpu); - if (hv_timer) + virt_timer =3D kvm_lapic_apic_virt_timer_in_use(vcpu); + if (hv_timer || virt_timer) kvm_lapic_switch_to_sw_timer(vcpu); =20 kvm_vcpu_srcu_read_unlock(vcpu); @@ -11586,6 +11587,8 @@ static inline int vcpu_block(struct kvm_vcpu *vcpu) =20 if (hv_timer) kvm_lapic_switch_to_hv_timer(vcpu); + else if (virt_timer) + kvm_lapic_switch_to_apic_virt_timer(vcpu); =20 /* * If the vCPU is not runnable, a signal or another host event --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2EBE1366DDB; Tue, 3 Feb 2026 18:17:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142655; cv=none; b=oERWXQqHIgRYElir+GmW2h9XNLaQfluI7SaiZWMVBs4qERlaabniFVgvcp31HIiUmq43gTnF5vFt9yZXvw618T6XUaBrHl1er1sOkIrcqqmQmne5ttJaFO6BBnVLLTbPecp80M1+fux9k8KZl7aqStpsdBTU5xr8bTVZ6nO/4d4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142655; c=relaxed/simple; bh=COE8kPmigj/LgeZHfmEjw88aXbrjj1fBsgrpEydMIZo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=X/vb4lRlJY7R/k+nDwhi8vt9oYXER2kYkMy8eaUCPROBLxM05G02uDidlko2VDEijy++sdb0HbryITjMXcQeMCWd7u7tORuxf8lqzk7KrQh8w42dzoAeHS9L95wQsDY/mxhFKUKuUERUAZs9pVb2fy2D4R3IVuc/basTQ9vb030= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Uwjph0f1; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Uwjph0f1" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142654; x=1801678654; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=COE8kPmigj/LgeZHfmEjw88aXbrjj1fBsgrpEydMIZo=; b=Uwjph0f1VoGPQqepr7MHa/3g/vVWhv+6ycfiufWnP+hJgRZTg2OfYy0X 1+wY3mpzjCOoBVjGDhjum4NXh7t8+U3MDzk/Rbq2XipMqBlQOOO/TaGks WZMHbMSzudPdkGmGBDA/rubo42FeLyeqBec3VAIdRHNrKsn8uCknaJ46/ qnHwuNUasAvPQk4yIUmcc6iGt2GpZFIe4d+u+hlAPmqjpp7H7JcumKUjq p1PoJsUGSYZbUfkbfvmE3oeW4AN+OASVoRyYSVGEhW416kntozU7uQun3 ZFaBJ4UcWobSinjhHjM+PNiWNoKxhxu8kevxC0FLacPwxXJ6E9uxM/nVH w==; X-CSE-ConnectionGUID: Y1L6KhuvRUOQJd5d8ECl4A== X-CSE-MsgGUID: +HpU4BDdQ+CzlMbs1Lxp1g== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433170" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433170" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:33 -0800 X-CSE-ConnectionGUID: MiaA+CieTfC3TibqOcqdeQ== X-CSE-MsgGUID: qbmYqY2MQ42De7w57vsxfA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727481" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:34 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 04/32] KVM: x86/lapic: Wire DEADLINE MSR update to guest virtual TSC deadline Date: Tue, 3 Feb 2026 10:16:47 -0800 Message-ID: <799fefe0c582ac5f9356a9a9a3dbf521b03cf39b.1770116050.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Wire userpace read/write (KVM_GET_MSRS, KVM_SET_MSRS) of TSCDEADLINE MSR to the vendor backend to update the VMCS field of GUEST TSCDEADLINE and GUEST TSCDEADLINE shadow. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/lapic.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index ee15d3bf5ef9..080245f6dac1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2754,6 +2754,10 @@ u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *v= cpu) if (!kvm_apic_present(vcpu) || !apic_lvtt_tscdeadline(apic)) return 0; =20 + if (apic->lapic_timer.apic_virt_timer_in_use) + apic->lapic_timer.tscdeadline =3D + kvm_x86_call(get_guest_tsc_deadline_virt)(vcpu); + return apic->lapic_timer.tscdeadline; } =20 @@ -2766,6 +2770,8 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *v= cpu, u64 data) =20 hrtimer_cancel(&apic->lapic_timer.timer); apic->lapic_timer.tscdeadline =3D data; + if (apic->lapic_timer.apic_virt_timer_in_use) + kvm_x86_call(set_guest_tsc_deadline_virt)(vcpu, data); start_apic_timer(apic); } =20 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E55E369207; Tue, 3 Feb 2026 18:17:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142657; cv=none; b=jK2pYM3P9n5ByvXECw1i7YJ0aft1x7FQH8oAZcuXRBWmoLhbF3mCqx/SekDKQpb7RpM94G610Wugu0QMJD0kSH28HVbswAxpYmBMG36yDUh8xv7sVZ+1RnTZ5b3XRXapHB7rwkeuzXBjzVELIm08wYOxTZ6zbSy9if9MgQhHC3s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142657; c=relaxed/simple; bh=v6JWNFCO9hbIhS9f+Hpe5Tv6VmFe0s0qenV2T/lAeic=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=isYok3R80px6bdUVlg3hFTqpoZ29c4tZIjubTg6y/r9UGQM78xaJuzDLp/ViR0jc2rVbUo/8j/gnMn6bCr/IDRD/SyRpayvNRHKnqVqz4KnPFXkJsnIXZJg/Qr9AsMgm8pEifc/YXVVYWkpSt8CyYfEBd03f/T8PtAdNqkC97Tc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=WsPrWpeg; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="WsPrWpeg" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142654; x=1801678654; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=v6JWNFCO9hbIhS9f+Hpe5Tv6VmFe0s0qenV2T/lAeic=; b=WsPrWpeg/fIHLh1odgBI84Lf6yLtxdipcOc8yufLZ1mefETINpKf2aVe GDy2+JMOnaAqoUwnQszeIPVRwSSZ2HgpEEnE0tOvFnqIb31BHtV3g7kar ZQMTq5UBNcwC96W+sOygDliL9ujs110fbuP1QktPhpmA5rkr9ysLe1OlO JOF9BRJYTYz/OMsFp7nZgPYc9BSdSZNaWBYNlawnzecQtYK4ZMxKhb9EM gGkS7wjP8o/NNy243WOZcGj4ZaklqD0KPh6JjX8fMDdQqsRki21BB9N5z rqp9Dk9x76RyDw8dYWAIugGtOn0WC6+2Q55Y+SgS0WFF6lyzExpueltds w==; X-CSE-ConnectionGUID: hmWxtI3aQ4+IreKqVjtiAw== X-CSE-MsgGUID: YWgcCo5ZSCOQuvUM8dxF6g== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433175" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433175" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:34 -0800 X-CSE-ConnectionGUID: bPAhYS24Sv+GIrYxK4XqwQ== X-CSE-MsgGUID: bErh3sbBRQSHtmvodQMvcA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727487" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:34 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, Yang Zhong Subject: [PATCH 05/32] KVM: x86/lapic: Add a trace point for guest virtual timer Date: Tue, 3 Feb 2026 10:16:48 -0800 Message-ID: <4dfe5a137204456cd984fb0be7c1041898a3a91a.1770116050.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yang Zhong Add a trace point for changing the guest virtual timer, similar to the hv timer case. Co-developed-by: Yang Zhong Signed-off-by: Yang Zhong Co-developed-by: Isaku Yamahata Signed-off-by: Isaku Yamahata --- arch/x86/kvm/lapic.c | 5 +++++ arch/x86/kvm/trace.h | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 080245f6dac1..837f446eea41 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1848,6 +1848,9 @@ static void cancel_apic_virt_timer(struct kvm_lapic *= apic) =20 kvm_x86_call(cancel_apic_virt_timer)(vcpu); apic->lapic_timer.apic_virt_timer_in_use =3D false; + + trace_kvm_apic_virt_timer_state(vcpu->vcpu_id, + apic->lapic_timer.apic_virt_timer_in_use); } =20 static void apic_cancel_apic_virt_timer(struct kvm_lapic *apic) @@ -1876,6 +1879,8 @@ static void apic_set_apic_virt_timer(struct kvm_lapic= *apic) kvm_x86_call(set_apic_virt_timer)(vcpu, vector); kvm_x86_call(set_guest_tsc_deadline_virt)(vcpu, ktimer->tscdeadline); ktimer->apic_virt_timer_in_use =3D true; + + trace_kvm_apic_virt_timer_state(vcpu->vcpu_id, ktimer->apic_virt_timer_in= _use); } =20 static bool kvm_can_use_apic_virt_timer(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index e79bc9cb7162..649d06f87619 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -1649,6 +1649,22 @@ TRACE_EVENT(kvm_hv_timer_state, __entry->hv_timer_in_use) ); =20 +TRACE_EVENT(kvm_apic_virt_timer_state, + TP_PROTO(unsigned int vcpu_id, unsigned int apic_virt_timer_in_use), + TP_ARGS(vcpu_id, apic_virt_timer_in_use), + TP_STRUCT__entry( + __field(unsigned int, vcpu_id) + __field(unsigned int, apic_virt_timer_in_use) + ), + TP_fast_assign( + __entry->vcpu_id =3D vcpu_id; + __entry->apic_virt_timer_in_use =3D apic_virt_timer_in_use; + ), + TP_printk("vcpu_id %x apic_virt_timer %x", + __entry->vcpu_id, + __entry->apic_virt_timer_in_use) +); + /* * Tracepoint for kvm_hv_flush_tlb. */ --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4AD21369986; Tue, 3 Feb 2026 18:17:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142659; cv=none; b=meuIUzPTkVfiK0tVoB0IxbSmfkMBEXuTTKJyznp2KdFMjsOxcylZQq9dGx+Q1Db1Tm4m5jYHYjFaSq5srMLwLUl0D2s96TlXbzDfox1oM/xCthSLN0gliWGU8Lnhk1tLCyyeum1tjSKmWq5GxX7Dkh/b1kSRJAHFYYJMyVf64Ow= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142659; c=relaxed/simple; bh=vbBFzFGGMBaUVVXq5gBrNuL4GVQbi4JRrKzQPeO1JBo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pIPVFtwRmGmHytvmrMDzyNCzT5qus71qUVQ6MnEW1tfGT+Ah1Gu57dmedmlAEoyBk9looDg8VuE1bbIMod/uaYlTlXHGWmLZbVUMyFfwsBCW7hghd7IqL9cAyQvJwB3NvjzB2sD5F90PLyemIHtBRJPK+kNDfJf4n7odyltRfz4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=aoDz/iyE; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="aoDz/iyE" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142656; x=1801678656; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=vbBFzFGGMBaUVVXq5gBrNuL4GVQbi4JRrKzQPeO1JBo=; b=aoDz/iyE8Q0geAkf2QpT9E+3z1+TYEjPtAPJag9N4zIIHtalft86dGKm eLQ/rOgTycwr2G2aUrgHtSe1LBuKBD6ZemJVmx6xL2qdbZL3jE+GWKhZP Xqim0gB8J4JhXSL/9CrkRwTcOCo+rsZhkxiqFJci2H6k2UFd4npBRge7S jZsdr7ErvLHeKccVvAUw6pPGE2YHYpWTtMr+maRIgBR9EzAE2LcJnv2Md Z6ig1tvOGnxIFzMYnCUocKr3I8MgqZ4akEDGaojywFzWJNly5FrtiXeLW Nwj74jUWsTHH54unpM/lmfyV9CFWE6Gv1qKW1c/qvaiAH1zqRW6wQ7KCe w==; X-CSE-ConnectionGUID: 6IAsTQmkRIiGHgOnx7q61w== X-CSE-MsgGUID: UPxaJZllRxCoNP6pR9EqbQ== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433179" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433179" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:35 -0800 X-CSE-ConnectionGUID: MXEsmSjcQQ6venxgoiUfiw== X-CSE-MsgGUID: zuC3c9LhRRKjOfZ1zVlmIg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727492" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:35 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, Yang Zhong Subject: [PATCH 06/32] KVM: VMX: Implement the hooks for VMX guest virtual deadline timer Date: Tue, 3 Feb 2026 10:16:49 -0800 Message-ID: <67503c138899e2f5ebb84d9c4a19c2fd632fb1e7.1770116050.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yang Zhong Implement the hooks for the VMX backend for APIC timer virtualization to access the related VMCS fields. Co-developed-by: Yang Zhong Signed-off-by: Yang Zhong Co-developed-by: Isaku Yamahata Signed-off-by: Isaku Yamahata --- arch/x86/kvm/lapic.h | 5 ++ arch/x86/kvm/vmx/capabilities.h | 6 +++ arch/x86/kvm/vmx/main.c | 5 ++ arch/x86/kvm/vmx/vmx.c | 83 ++++++++++++++++++++++++++++++++- arch/x86/kvm/vmx/x86_ops.h | 5 ++ 5 files changed, 103 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 67172fef1b5b..d3fad67a4e78 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -230,6 +230,11 @@ static inline int kvm_lapic_latched_init(struct kvm_vc= pu *vcpu) return lapic_in_kernel(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic-= >pending_events); } =20 +static inline int kvm_lapic_lvtt_timer_mode(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.apic->lapic_timer.timer_mode; +} + bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector); =20 void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilitie= s.h index 02aadb9d730e..ffc51fe9a455 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -90,6 +90,12 @@ static inline bool cpu_has_vmx_preemption_timer(void) PIN_BASED_VMX_PREEMPTION_TIMER; } =20 +static inline bool cpu_has_vmx_apic_timer_virt(void) +{ + return vmcs_config.cpu_based_3rd_exec_ctrl & + TERTIARY_EXEC_GUEST_APIC_TIMER; +} + static inline bool cpu_has_vmx_posted_intr(void) { return vmcs_config.pin_based_exec_ctrl & PIN_BASED_POSTED_INTR; diff --git a/arch/x86/kvm/vmx/main.c b/arch/x86/kvm/vmx/main.c index a46ccd670785..56387c3412e1 100644 --- a/arch/x86/kvm/vmx/main.c +++ b/arch/x86/kvm/vmx/main.c @@ -989,6 +989,11 @@ struct kvm_x86_ops vt_x86_ops __initdata =3D { #ifdef CONFIG_X86_64 .set_hv_timer =3D vt_op(set_hv_timer), .cancel_hv_timer =3D vt_op(cancel_hv_timer), + .can_use_apic_virt_timer =3D vmx_can_use_apic_virt_timer, + .set_apic_virt_timer =3D vmx_set_apic_virt_timer, + .cancel_apic_virt_timer =3D vmx_cancel_apic_virt_timer, + .set_guest_tsc_deadline_virt =3D vmx_set_guest_tsc_deadline_virt, + .get_guest_tsc_deadline_virt =3D vmx_get_guest_tsc_deadline_virt, #endif =20 .setup_mce =3D vt_op(setup_mce), diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 6d0d2d8ebcff..dcb04fc0b8a7 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2789,7 +2789,8 @@ static int setup_vmcs_config(struct vmcs_config *vmcs= _conf, adjust_vmx_controls64(KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL, MSR_IA32_VMX_PROCBASED_CTLS3); =20 - if (!(_cpu_based_2nd_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)) + if (!IS_ENABLED(CONFIG_X86_64) || + !(_cpu_based_2nd_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)) _cpu_based_3rd_exec_control &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; =20 if (adjust_vmx_controls(KVM_REQUIRED_VMX_VM_EXIT_CONTROLS, @@ -8268,6 +8269,86 @@ void vmx_cancel_hv_timer(struct kvm_vcpu *vcpu) { to_vmx(vcpu)->hv_deadline_tsc =3D -1; } + +bool vmx_can_use_apic_virt_timer(struct kvm_vcpu *vcpu) +{ + if (vcpu->kvm->arch.vm_type !=3D KVM_X86_DEFAULT_VM) + return false; + + return cpu_has_vmx_apic_timer_virt() && + /* VMX guest virtual timer supports only TSC deadline mode. */ + kvm_lapic_lvtt_timer_mode(vcpu) =3D=3D APIC_LVT_TIMER_TSCDEADLINE && + /* Require SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY */ + kvm_vcpu_apicv_active(vcpu) && + /* KVM doesn't use RDTSC existing. Safeguard. */ + !(exec_controls_get(to_vmx(vcpu)) & CPU_BASED_RDTSC_EXITING); +} + +void vmx_set_apic_virt_timer(struct kvm_vcpu *vcpu, u16 vector) +{ + vmcs_write16(GUEST_APIC_TIMER_VECTOR, vector); + vmx_disable_intercept_for_msr(vcpu, MSR_IA32_TSC_DEADLINE, MSR_TYPE_RW); + tertiary_exec_controls_setbit(to_vmx(vcpu), TERTIARY_EXEC_GUEST_APIC_TIME= R); +} + +void vmx_cancel_apic_virt_timer(struct kvm_vcpu *vcpu) +{ + vmx_enable_intercept_for_msr(vcpu, MSR_IA32_TSC_DEADLINE, MSR_TYPE_RW); + tertiary_exec_controls_clearbit(to_vmx(vcpu), TERTIARY_EXEC_GUEST_APIC_TI= MER); +} + +static u64 vmx_calc_deadline_l1_to_host(struct kvm_vcpu *vcpu, u64 l1_tsc) +{ + u64 host_tsc_now =3D rdtsc(); + u64 l1_tsc_now =3D kvm_read_l1_tsc(vcpu, host_tsc_now); + u64 host_tsc; + + /* 0 means that timer is disarmed. */ + if (!l1_tsc) + return 0; + + host_tsc =3D l1_tsc - vcpu->arch.l1_tsc_offset; + if (vcpu->arch.l1_tsc_scaling_ratio !=3D kvm_caps.default_tsc_scaling_rat= io) + if (u64_shl_div_u64(l1_tsc, + kvm_caps.tsc_scaling_ratio_frac_bits, + vcpu->arch.l1_tsc_scaling_ratio, + &host_tsc)) + host_tsc =3D ~0ull; + + /* + * Clamp the result on overflow. + * TSC deadline isn't supposed to overflow in practice. + * ~0ull is considered that the timer is armed, but won't fire in + * practical timer frame. + */ + if (l1_tsc > l1_tsc_now && host_tsc <=3D host_tsc_now) + host_tsc =3D ~0ull; + /* + * Clamp the result on underflow. + * The past value means fire the timer immediately. + * Pick the obvious past value. + */ + if (l1_tsc <=3D l1_tsc_now && host_tsc > host_tsc_now) + host_tsc =3D 1ull; + + if (!host_tsc) + host_tsc =3D 1ull; + + return host_tsc; +} + +void vmx_set_guest_tsc_deadline_virt(struct kvm_vcpu *vcpu, + u64 guest_deadline_virt) +{ + vmcs_write64(GUEST_DEADLINE_VIR, guest_deadline_virt); + vmcs_write64(GUEST_DEADLINE_PHY, + vmx_calc_deadline_l1_to_host(vcpu, guest_deadline_virt)); +} + +u64 vmx_get_guest_tsc_deadline_virt(struct kvm_vcpu *vcpu) +{ + return vmcs_read64(GUEST_DEADLINE_VIR); +} #endif =20 void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx/x86_ops.h b/arch/x86/kvm/vmx/x86_ops.h index d09abeac2b56..364050e0427c 100644 --- a/arch/x86/kvm/vmx/x86_ops.h +++ b/arch/x86/kvm/vmx/x86_ops.h @@ -117,6 +117,11 @@ void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcp= u); int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc, bool *expired); void vmx_cancel_hv_timer(struct kvm_vcpu *vcpu); +bool vmx_can_use_apic_virt_timer(struct kvm_vcpu *vcpu); +void vmx_set_apic_virt_timer(struct kvm_vcpu *vcpu, u16 vector); +void vmx_cancel_apic_virt_timer(struct kvm_vcpu *vcpu); +void vmx_set_guest_tsc_deadline_virt(struct kvm_vcpu *vcpu, u64 guest_dead= line_tsc); +u64 vmx_get_guest_tsc_deadline_virt(struct kvm_vcpu *vcpu); #endif void vmx_setup_mce(struct kvm_vcpu *vcpu); =20 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A761F366833; Tue, 3 Feb 2026 18:17:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142659; cv=none; b=NCnI5kPzgRoopXYfMVXFXRXQuZPZcLXHCjqCSzft2a/2iRG9HjKEX1Vce337NpVKhcTWCQPWbUPMNxWxV32vNQ8cbucsceRWgK9/GkM6c125Bjovuz6Xaqn01PqpmIVTf9mCMFPXWUNhOuEij+1eBtEPOS/AcEgU7BwsfnqE4X8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142659; c=relaxed/simple; bh=6h76HamtuX5WAWZxbtzCPlZnwCKgGwSsmIJkkIJPz8A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VIDHeGUQ0cTrf+GZPvoDgVZPMES2mLs0/IpfN1lI3afJkARUmI0iCfZbpAN+kCocm8MCVjv01GOVPtIoawTBgfz0rJX5ZoPu/0iepd860dtKhP/jXHVlR247WBUZ1HmKsR9uj0/Qlyby2B1ZUHZR2FxrfNuEGcf+rpXFhs7XNvg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=YQfLJV3U; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="YQfLJV3U" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142656; x=1801678656; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=6h76HamtuX5WAWZxbtzCPlZnwCKgGwSsmIJkkIJPz8A=; b=YQfLJV3U4W00bz3RsQwN46plVpbuHaXH36NgjNvtAXt7a+YHWCZlid3m j390G2IPC0mVc6DbzB+Xr2uRwJtwdiTf1reNMOwdNEcTprjGe9J9KBi0h zMnGPxwuJIUDYj8ER9yM3V+jMSAiYN/fcBSHkqTmrTaaAcpce+o9fRRLw AxHfJ6X2hHVol8zJZPz87bJSOv4Y74jB3Su+1KSLUScpoDBvNTU1fcpPQ 7MBGBK3QKgnAaI2e6fmwiieg7gcnYOug41+X+rN/ESS32nbpy43jYqtV+ zwqhWBFmETECCDsrtMWnnU2PxwKUehy6iquLNByJdeqOnYRI1UaGScb3b A==; X-CSE-ConnectionGUID: RcSblYuhRq2wabtdF3UbfQ== X-CSE-MsgGUID: 4ViusSTBSeenuNxiIuGaRQ== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433182" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433182" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:36 -0800 X-CSE-ConnectionGUID: SHh7J4kKSOWnZnd07MoA5g== X-CSE-MsgGUID: jyHEamHNSZOOrGgfhhKNtA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727496" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:36 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 07/32] KVM: VMX: Update APIC timer virtualization on apicv changed Date: Tue, 3 Feb 2026 10:16:50 -0800 Message-ID: <5f8655049106de981021d3d17bedc56574756678.1770116050.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata VMX APIC timer virtualization requires the virtual-interrupt delivery. It's part of KVM apicv, and when apicv state is changed, the refresh_apicv_exec_ctrl() callback is invoked. Export a lapic function to update which timer to use for APIC timer emulation and make the VMX backend call it. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/lapic.c | 6 ++++++ arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/vmx/vmx.c | 2 ++ 3 files changed, 9 insertions(+) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 837f446eea41..a2f714eb78b1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1898,6 +1898,12 @@ static void apic_update_apic_virt_timer(struct kvm_l= apic *apic) apic_cancel_apic_virt_timer(apic); } =20 +void kvm_update_apic_virt_timer(struct kvm_vcpu *vcpu) +{ + apic_update_apic_virt_timer(vcpu->arch.apic); +} +EXPORT_SYMBOL_GPL(kvm_update_apic_virt_timer); + static void apic_update_lvtt(struct kvm_lapic *apic) { u32 timer_mode =3D kvm_lapic_get_reg(apic, APIC_LVTT) & diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index d3fad67a4e78..3c597b670e7e 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -250,6 +250,7 @@ void kvm_lapic_switch_to_apic_virt_timer(struct kvm_vcp= u *vcpu); void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu); bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu); void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu); +void kvm_update_apic_virt_timer(struct kvm_vcpu *vcpu); =20 static inline bool kvm_lapic_apic_virt_timer_in_use(struct kvm_vcpu *vcpu) { diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index dcb04fc0b8a7..82e1a0b2a8d2 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4563,6 +4563,8 @@ void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcp= u) kvm_vcpu_apicv_active(vcpu)); =20 vmx_update_msr_bitmap_x2apic(vcpu); + + kvm_update_apic_virt_timer(vcpu); } =20 static u32 vmx_exec_control(struct vcpu_vmx *vmx) --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3F2973D667F; Tue, 3 Feb 2026 18:17:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142665; cv=none; b=lvw89Ciny99LKxkV1eMvVl7T/wbttgDflFiVzBWeVXYrAZlGEyc7EFv0gFKr1+K58tg4flVQyAa8VNbi41/UUvrUF7Lemulj0OlIs7CuIzgeVQ86M+bcpWz3nPSbn40X5nBqjTNxbMCF6JTZe9j30k0KYFnOnibWKT+CZnSmVeE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142665; c=relaxed/simple; bh=kZmy1PJDzMPDX74OH/nE3q+FpGgrr1mWJ3pQWgdL5PI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SWPjs2DXrPMQwiwp5iucV8EwYk27T0GszGFwnNRZHAugHriiHpoPH+YxFXw39RutfP4Isv7XZuyjUe2yAAlFZd68BaOWKYsIhIsoAULwn1f5N7afenTc29Q00Q73doEia/yPGEjne699yxz9PNcOb9gsfDkf0lw4a5X+i3RTLhE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=fJmQoijE; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="fJmQoijE" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142663; x=1801678663; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kZmy1PJDzMPDX74OH/nE3q+FpGgrr1mWJ3pQWgdL5PI=; b=fJmQoijE2Z+2kbWghnue8mFNeDRoVCuf3iAaj4dpSvA5/+Rp54g67z9o yM9OBzjh5iSfMbVMGFhExleAAFkgkeYhr48QB6sFrOKynSm5v+m3+U96Z Efd523lpE/KgzWNYQW92ME1ar1t0C/3wVanWZZTdUUmXn4Vzkrh4vXrRN IF3cBpAsGaedplQRln0R1QLngIWmp4GBjNDhTP/U99lFgC+EE6YxpeugC j6gL/Y3/qWAr9nohaX+uOkf07qkCYaW66lrq8R5iDDN6/jtxnryen1qcW oXPxBSAnOzNR3L/yxauHDkbq8QPB5o/te4w3x0RoDid9wu/2FRQAmhLep Q==; X-CSE-ConnectionGUID: uqUCfCJsQM26M5mUnHf+BA== X-CSE-MsgGUID: lw3XP9d5RKKEFO/p1xS8JA== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433188" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433188" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:43 -0800 X-CSE-ConnectionGUID: sXOOppfjTUalWMA0ZiH1Uw== X-CSE-MsgGUID: Ungg3JJuSaiyhWJLDLA+Qw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727505" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:37 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 08/32] KVM: nVMX: Disallow/allow guest APIC timer virtualization switch to/from L2 Date: Tue, 3 Feb 2026 10:16:51 -0800 Message-ID: <642d76482132d7b0ebc4c2468bc24e0f65cc48da.1770116050.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Disable guest APIC timer virtualization on nested VMEnter, enable it on nested vmexit. With VMX APIC timer virtualization, the CPU directly injects a guest timer interrupt without VMExit. When the L1 APIC timer fires while running the nested (L2) vCPU, KVM should emulate VMExit from L2 to L1. Switch to the hv timer (preemption timer) or the sw timer when VMEntering from L1 to L2, switch to guest APIC timer virtualization when VM exiting from L2 to L1. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/lapic.c | 29 +++++++++++++++++++++++++++++ arch/x86/kvm/lapic.h | 2 ++ arch/x86/kvm/vmx/nested.c | 13 +++++++++++++ arch/x86/kvm/vmx/vmx.c | 5 +++++ 4 files changed, 49 insertions(+) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index a2f714eb78b1..7c3ec0565a8f 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1862,6 +1862,35 @@ static void apic_cancel_apic_virt_timer(struct kvm_l= apic *apic) start_apic_timer(apic); } =20 +void kvm_sync_apic_virt_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic =3D vcpu->arch.apic; + + WARN_ON_ONCE(is_guest_mode(vcpu)); + + if (!apic->lapic_timer.apic_virt_timer_in_use) + return; + + apic->lapic_timer.tscdeadline =3D kvm_x86_call(get_guest_tsc_deadline_vir= t)(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_sync_apic_virt_timer); + +void kvm_cancel_apic_virt_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic =3D vcpu->arch.apic; + + WARN_ON_ONCE(!is_guest_mode(vcpu)); + + if (!apic->lapic_timer.apic_virt_timer_in_use) + return; + + apic->lapic_timer.apic_virt_timer_in_use =3D false; + trace_kvm_apic_virt_timer_state(vcpu->vcpu_id, false); + + start_apic_timer(apic); +} +EXPORT_SYMBOL_GPL(kvm_cancel_apic_virt_timer); + static void apic_set_apic_virt_timer(struct kvm_lapic *apic) { struct kvm_timer *ktimer =3D &apic->lapic_timer; diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 3c597b670e7e..2ebe294fe0f9 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -251,6 +251,8 @@ void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu); bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu); void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu); void kvm_update_apic_virt_timer(struct kvm_vcpu *vcpu); +void kvm_sync_apic_virt_timer(struct kvm_vcpu *vcpu); +void kvm_cancel_apic_virt_timer(struct kvm_vcpu *vcpu); =20 static inline bool kvm_lapic_apic_virt_timer_in_use(struct kvm_vcpu *vcpu) { diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 6137e5307d0f..77521e37cfc6 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3634,6 +3634,8 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mo= de(struct kvm_vcpu *vcpu, if (!enable_ept) vmcs_writel(GUEST_CR3, vcpu->arch.cr3); =20 + kvm_sync_apic_virt_timer(vcpu); + vmx_switch_vmcs(vcpu, &vmx->nested.vmcs02); =20 prepare_vmcs02_early(vmx, &vmx->vmcs01, vmcs12); @@ -3709,6 +3711,14 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_m= ode(struct kvm_vcpu *vcpu, vmx_start_preemption_timer(vcpu, timer_value); } =20 + /* + * Disable apic virtual timer for L1 to use sw timer (hr timer) or + * hypervisor timer (VMX preemption timer). + * When L1 timer interrupt occurs during running L2, KVM emulates + * VMExit from L2 to L1. Not directly injecting the interrupt into L2. + */ + kvm_cancel_apic_virt_timer(vcpu); + /* * Note no nested_vmx_succeed or nested_vmx_fail here. At this point * we are no longer running L1, and VMLAUNCH/VMRESUME has not yet @@ -5181,6 +5191,9 @@ void __nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 v= m_exit_reason, /* in case we halted in L2 */ kvm_set_mp_state(vcpu, KVM_MP_STATE_RUNNABLE); =20 + /* If apic virtual timer is supported, switch back to it. */ + kvm_update_apic_virt_timer(vcpu); + if (likely(!vmx->fail)) { if (vm_exit_reason !=3D -1) trace_kvm_nested_vmexit_inject(vmcs12->vm_exit_reason, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 82e1a0b2a8d2..c625c46658dc 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8277,6 +8277,9 @@ bool vmx_can_use_apic_virt_timer(struct kvm_vcpu *vcp= u) if (vcpu->kvm->arch.vm_type !=3D KVM_X86_DEFAULT_VM) return false; =20 + if (is_guest_mode(vcpu)) + return false; + return cpu_has_vmx_apic_timer_virt() && /* VMX guest virtual timer supports only TSC deadline mode. */ kvm_lapic_lvtt_timer_mode(vcpu) =3D=3D APIC_LVT_TIMER_TSCDEADLINE && @@ -8288,6 +8291,8 @@ bool vmx_can_use_apic_virt_timer(struct kvm_vcpu *vcp= u) =20 void vmx_set_apic_virt_timer(struct kvm_vcpu *vcpu, u16 vector) { + WARN_ON_ONCE(is_guest_mode(vcpu)); + vmcs_write16(GUEST_APIC_TIMER_VECTOR, vector); vmx_disable_intercept_for_msr(vcpu, MSR_IA32_TSC_DEADLINE, MSR_TYPE_RW); tertiary_exec_controls_setbit(to_vmx(vcpu), TERTIARY_EXEC_GUEST_APIC_TIME= R); --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7EEC83D6687; Tue, 3 Feb 2026 18:17:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142665; cv=none; b=NVwMAjv81J/hrS/w+xBEaiPAsZcEvTebHRs6gXqqki6AiFT99+5Nmt9M7Mh2dBta1iyf9nQhcEGLZ7GAxU/N/CnOgBGuicIIIpfO/kiLdD/Eg428BK4xRRC1fVG3/qSlGZulQ1pr8gRlpJVOuTghT6BZgGm3pGEwDnVqd0A7lDM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142665; c=relaxed/simple; bh=BeDOchtE/6gFBkGg5vQffPr5YjORRd2s8W+KTY2b1Zg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=E3mHy1znEeUhUlD6DrwL2LN2IFtBGL13w7FcPDFORs1NyjF2CIt4/G6QGELRG8Epskt7Uw3wlT5ArtEIqf5Baytcb/1CbbOuhzBJGoKKGWWQRx+k5eSmekDa920bbw9/ZXF07EZdwfXFv1O6sI4o4ATxgealvbbYtjMVV18qamI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=a1kAqIa4; arc=none smtp.client-ip=198.175.65.13 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="a1kAqIa4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142663; x=1801678663; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BeDOchtE/6gFBkGg5vQffPr5YjORRd2s8W+KTY2b1Zg=; b=a1kAqIa4PgKvNsGZWl1zE4tFcwsGs5YHT/FjKuG/5aESLFwr3gcztha5 blv/eipuHU4yeCgpARiutxArFxMpQfmzw9djpbh7J0NcB1udOyaR42I53 h4uQHuOcT8QRAv61YRsfCgUA0aD/AkihW0SNtcMQvQTDPJPAEGa9yyvL9 BRqAVkZUDUx23WeZqxUnHpEsIw9UD+Rj38AtQthyhPzWmDkHmJrVVa4wo O9m38fnsqRBFPax8JvM5y7Bq3YQLaY+3D8Suy4VrOvfN6Gcw4ncITSiKV 3g48wkRRi9IpbVeND2+K5kBMJq+JJknR2IDHVPhZYiInA81aMQqylTbOQ g==; X-CSE-ConnectionGUID: u+x050k5S9KygOBuTFn3IA== X-CSE-MsgGUID: 1g6YhQUpTN2GZc1pmcmFNQ== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="82433193" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="82433193" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:43 -0800 X-CSE-ConnectionGUID: M229sq89QK65pF7tZSFxuA== X-CSE-MsgGUID: bWyK3jdrTmC3d8Lh5SO4kA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209727508" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by orviesa009-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:40 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 09/32] KVM: nVMX: Pass struct msr_data to VMX MSRs emulation Date: Tue, 3 Feb 2026 10:16:52 -0800 Message-ID: <3d79f3816536abb0e81a19aac60bb5a213b67803.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Pass struct msr_data, which has host_initiated member in addition to msr_index and data to vmx_set/get_vmx_msr(). Processor-based tertiary control access depends on which initiated the operation, the host or the guest. For host-initiated access (KVM_GET_MSRS, KVM_SET_MSRS), if the host supports processor-based tertiary controls, allow access. If guest-initiated access (emulation for guest rdmsr/wrmsr), allow/disallow based on guest tertiary controls is advertised to the guest (guest processor-based control high & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS). Prepare to add the check. No functional change intended. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/nested.c | 9 +++++++-- arch/x86/kvm/vmx/nested.h | 4 ++-- arch/x86/kvm/vmx/vmx.c | 18 ++++++++++++++---- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 77521e37cfc6..b1b8f0c88ca5 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -1479,9 +1479,11 @@ static int vmx_restore_fixed0_msr(struct vcpu_vmx *v= mx, u32 msr_index, u64 data) * * Returns 0 on success, non-0 otherwise. */ -int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) +int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { struct vcpu_vmx *vmx =3D to_vmx(vcpu); + u32 msr_index =3D msr_info->index; + u64 data =3D msr_info->data; =20 /* * Don't allow changes to the VMX capability MSRs while the vCPU @@ -1544,8 +1546,11 @@ int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_i= ndex, u64 data) } =20 /* Returns 0 on success, non-0 otherwise. */ -int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdat= a) +int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, struct msr_data *msr_inf= o) { + u32 msr_index =3D msr_info->index; + u64 *pdata =3D &msr_info->data; + switch (msr_index) { case MSR_IA32_VMX_BASIC: *pdata =3D msrs->basic; diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index 983484d42ebf..f51d7cac8a58 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -47,8 +47,8 @@ static inline void nested_vmx_vmexit(struct kvm_vcpu *vcp= u, u32 vm_exit_reason, } =20 void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu); -int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); -int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdat= a); +int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, struct msr_data *msr); +int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, struct msr_data *msr); int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualific= ation, u32 vmx_instruction_info, bool wr, int len, gva_t *ret); void nested_mark_vmcs12_pages_dirty(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index c625c46658dc..dc6b6659a093 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2065,11 +2065,22 @@ static inline bool is_vmx_feature_control_msr_valid= (struct vcpu_vmx *vmx, =20 int vmx_get_feature_msr(u32 msr, u64 *data) { + struct msr_data msr_info; + int r; + switch (msr) { case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: if (!nested) return 1; - return vmx_get_vmx_msr(&vmcs_config.nested, msr, data); + + msr_info =3D (struct msr_data) { + .index =3D msr, + .host_initiated =3D true, + }; + r =3D vmx_get_vmx_msr(&vmcs_config.nested, &msr_info); + if (!r) + *data =3D msr_info.data; + return r; default: return KVM_MSR_RET_UNSUPPORTED; } @@ -2154,8 +2165,7 @@ int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_dat= a *msr_info) case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: if (!guest_cpu_cap_has(vcpu, X86_FEATURE_VMX)) return 1; - if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index, - &msr_info->data)) + if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info)) return 1; #ifdef CONFIG_KVM_HYPERV /* @@ -2482,7 +2492,7 @@ int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_dat= a *msr_info) return 1; /* they are read-only */ if (!guest_cpu_cap_has(vcpu, X86_FEATURE_VMX)) return 1; - return vmx_set_vmx_msr(vcpu, msr_index, data); + return vmx_set_vmx_msr(vcpu, msr_info); case MSR_IA32_RTIT_CTL: if (!vmx_pt_mode_is_host_guest() || vmx_rtit_ctl_check(vcpu, data) || --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 760773D6474; Tue, 3 Feb 2026 18:17:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142663; cv=none; b=a/0ZbrDZYXyCAI5+v53EJLoeETYs9ZSQTa0Q2cNjlGkxESKHLdo6I7EVPB2Kefmd1+PDMJcvwuu+yUK7C0YPpcTAg/ljq4+DRM578RB79rv01JDimhgBNUWhSLGI5F3zhLdg/i7y8jDu6psM8nTqZ/psMmZ2IzcvLT1p9olwiYk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142663; c=relaxed/simple; bh=c9TKvGjIeGGIhjlMGzJs9IJ4jamyM/FgsY22RuZP+Tg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SWnYJgkH7HVspgSlJAwp+sfj+dGGSXVYD+bowDz0nV19SwH9XY0nipV9dl3NgEgCQ7OPZYRz+8I0A6YeNZhHA86cxTw5L4IIwDMlyVurZ2PrC91YbDdWYV1lSS8gg0Hci1K1/cmF1W4CSQIgkQf0vHxMAR6DpJ2uaHCSdd2YA2M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Gcf2mJic; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Gcf2mJic" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142662; x=1801678662; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=c9TKvGjIeGGIhjlMGzJs9IJ4jamyM/FgsY22RuZP+Tg=; b=Gcf2mJicUHeKBWjHlJ5dMJNyZNBLOJNu7TUxvdszgwiKo3nY2M2CGcEO 3wCfyCP+5IIOcqQnYIaEf+VgHGtZSUAyEwfDkQXQYtsd0gzH3vqoQB+nO er3hvcPgFtXRxuFOF1gnjZ/t+g1YO0eBrDzbiI0Y2ZZU+sk/EEnNZbuIM al8AVDzajxWhtTJaZy+FrfciduImiRVinZC0TkXO/Vy+JnOro11j8Lprl R3Xvj8uIREQri4ZdVYeepRm0R4bajJA8xcOvJ4DnX1cOK7HxC7cAqsSds dvAO9jWCLYG19pCqAh7DlJd1r3IVdhLrrS1wihlN4HoANP0bnlBbL9UNv Q==; X-CSE-ConnectionGUID: hqS9oOkxT5KoRYbwAQsvBQ== X-CSE-MsgGUID: vd/2Kw9hQ2mCFpy7qSxp3g== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745794" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745794" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:41 -0800 X-CSE-ConnectionGUID: 6lBy9vnTR72Vz8XFoA+OcQ== X-CSE-MsgGUID: 4ZMv1rGuRGa3vKdWagkSEA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605475" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:40 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 10/32] KVM: nVMX: Supports VMX tertiary controls and GUEST_APIC_TIMER bit Date: Tue, 3 Feb 2026 10:16:53 -0800 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Emulate MSR_IA32_VMX_PROCBASED_CTLS3 to advertise APIC timer virtualization feature to the L2 guest. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/capabilities.h | 1 + arch/x86/kvm/vmx/hyperv.c | 7 ++++++ arch/x86/kvm/vmx/nested.c | 42 +++++++++++++++++++++++++++++++++ arch/x86/kvm/vmx/nested.h | 5 ++++ arch/x86/kvm/x86.h | 2 +- 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilitie= s.h index ffc51fe9a455..f73a50c887ac 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -47,6 +47,7 @@ struct nested_vmx_msrs { u64 cr4_fixed1; u64 vmcs_enum; u64 vmfunc_controls; + u64 tertiary_ctls; }; =20 struct vmcs_config { diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c index fa41d036acd4..2731c2e4b0e5 100644 --- a/arch/x86/kvm/vmx/hyperv.c +++ b/arch/x86/kvm/vmx/hyperv.c @@ -141,6 +141,13 @@ void nested_evmcs_filter_control_msr(struct kvm_vcpu *= vcpu, u32 msr_index, u64 * case MSR_IA32_VMX_PROCBASED_CTLS2: ctl_high &=3D evmcs_get_supported_ctls(EVMCS_2NDEXEC); break; + case MSR_IA32_VMX_PROCBASED_CTLS3: + /* + * tertiary procbased controls are 64-bit. 0 means unsupported, + * 1 supported. + */ + *pdata &=3D evmcs_get_supported_ctls(EVMCS_3RDEXEC); + return; case MSR_IA32_VMX_TRUE_PINBASED_CTLS: case MSR_IA32_VMX_PINBASED_CTLS: ctl_high &=3D evmcs_get_supported_ctls(EVMCS_PINCTRL); diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index b1b8f0c88ca5..8cd56e9f1cf0 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -215,6 +215,11 @@ static inline bool vmx_control_verify(u32 control, u32= low, u32 high) return fixed_bits_valid(control, low, high); } =20 +static inline bool vmx_control64_verify(u64 control, u64 msr) +{ + return !(control & ~msr); +} + static inline u64 vmx_control_msr(u32 low, u32 high) { return low | ((u64)high << 32); @@ -1515,6 +1520,19 @@ int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, struct ms= r_data *msr_info) case MSR_IA32_VMX_TRUE_ENTRY_CTLS: case MSR_IA32_VMX_PROCBASED_CTLS2: return vmx_restore_control_msr(vmx, msr_index, data); + case MSR_IA32_VMX_PROCBASED_CTLS3: + if (!__nested_cpu_supports_tertiary_ctls(&vmcs_config.nested)) + return -EINVAL; + + /* read-only for guest. */ + if (!msr_info->host_initiated) + return -EINVAL; + + if (!vmx_control64_verify(data, + vmcs_config.nested.tertiary_ctls)) + return -EINVAL; + vmx->nested.msrs.tertiary_ctls =3D data; + return 0; case MSR_IA32_VMX_MISC: return vmx_restore_vmx_misc(vmx, data); case MSR_IA32_VMX_CR0_FIXED0: @@ -1612,6 +1630,16 @@ int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, st= ruct msr_data *msr_info) msrs->secondary_ctls_low, msrs->secondary_ctls_high); break; + case MSR_IA32_VMX_PROCBASED_CTLS3: + if (!__nested_cpu_supports_tertiary_ctls(&vmcs_config.nested)) + return KVM_MSR_RET_UNSUPPORTED; + + if (!msr_info->host_initiated && + !__nested_cpu_supports_tertiary_ctls(msrs)) + return -EINVAL; + + *pdata =3D msrs->tertiary_ctls; + break; case MSR_IA32_VMX_EPT_VPID_CAP: *pdata =3D msrs->ept_caps | ((u64)msrs->vpid_caps << 32); @@ -7314,6 +7342,18 @@ static void nested_vmx_setup_secondary_ctls(u32 ept_= caps, msrs->secondary_ctls_high |=3D SECONDARY_EXEC_ENCLS_EXITING; } =20 +static void nested_vmx_setup_tertiary_ctls(struct vmcs_config *vmcs_conf, + struct nested_vmx_msrs *msrs) +{ + msrs->tertiary_ctls =3D vmcs_conf->cpu_based_3rd_exec_ctrl; + + msrs->tertiary_ctls &=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + + if (msrs->tertiary_ctls) + msrs->procbased_ctls_high |=3D + CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; +} + static void nested_vmx_setup_misc_data(struct vmcs_config *vmcs_conf, struct nested_vmx_msrs *msrs) { @@ -7402,6 +7442,8 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *v= mcs_conf, u32 ept_caps) =20 nested_vmx_setup_secondary_ctls(ept_caps, vmcs_conf, msrs); =20 + nested_vmx_setup_tertiary_ctls(vmcs_conf, msrs); + nested_vmx_setup_misc_data(vmcs_conf, msrs); =20 nested_vmx_setup_basic(msrs); diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index f51d7cac8a58..d6d89ae1daec 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -153,6 +153,11 @@ static inline bool nested_cpu_has_vmx_shadow_vmcs(stru= ct kvm_vcpu *vcpu) SECONDARY_EXEC_SHADOW_VMCS; } =20 +static inline bool __nested_cpu_supports_tertiary_ctls(struct nested_vmx_m= srs *msrs) +{ + return msrs->procbased_ctls_high & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; +} + static inline bool nested_cpu_has(struct vmcs12 *vmcs12, u32 bit) { return vmcs12->cpu_based_vm_exec_control & bit; diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index fdab0ad49098..7ba7abf02bbd 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -92,7 +92,7 @@ do { \ * associated feature that KVM supports for nested virtualization. */ #define KVM_FIRST_EMULATED_VMX_MSR MSR_IA32_VMX_BASIC -#define KVM_LAST_EMULATED_VMX_MSR MSR_IA32_VMX_VMFUNC +#define KVM_LAST_EMULATED_VMX_MSR MSR_IA32_VMX_PROCBASED_CTLS3 =20 #define KVM_DEFAULT_PLE_GAP 128 #define KVM_VMX_DEFAULT_PLE_WINDOW 4096 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9761E36A00D; Tue, 3 Feb 2026 18:17:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142664; cv=none; b=C60F6geASvTlMXeh0EJFIS2B/NjMMnsBRjbheVXnkzTptITyRqg6RXVa91qxl4fUWC/8DX3pfZcjRyreIpEI2Rm3j8KDr4awrBi9bAVzSUYP/D1ga/PoTj0fESpdhfujrqWeyw/f7gkiAJ2dzgf9QGX4EKSdvKe5wPQPP8kDk+M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142664; c=relaxed/simple; bh=vtqwmnv6BUztDTb7SL0PpDFYYt8itAFaXzecMcCYsr4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SxU8bnITnGz+yktY6LGWsOoDU/qNVZQ7GkkXNL2vlo/l+raL/IYp+YObVD+JSPAj6VvWNjFiFfDYEBwvfzkDzXt6cbI3J6rJNKDyrj+0BfFhGeVUgUDuNBpSgDvSTFZ0Q2krls9kcfyWAz5oKwxQIuTgUmrHMMP6qUNdHEK1xOw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=GZal9T58; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="GZal9T58" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142663; x=1801678663; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=vtqwmnv6BUztDTb7SL0PpDFYYt8itAFaXzecMcCYsr4=; b=GZal9T58aRpWR2Cnb3u8i4grqRfJNKZvR0GwRcyVWuDFGAK2XEv5JvQI EuAAho7eYmcWRFwYEx1UvT9CCf84SSemEwxwoF1N1FLE2utMTTf1ToUwg Nxvgk9gKkB2NB6vGaNZgMIr2bJvrbL7MRtAa/rwFASJ0ETbvn0PvMJXZt CveC6DPNYf/aLOL3WhSGQxlxjHTUFgWRBrVauwHIcQRYY5TEHbrTG6fK4 wu8jFCDgsuRrFQbLedsbK+wc8dlcHgfIuhyLUsdrQr+QgZijCZJy09PLj mpCXMlJXFwAoAAMHSiZP7OESPPVqmY+1jo/BbVJTfGVGnO78Jxe3dInCI g==; X-CSE-ConnectionGUID: sf9gSDeERuKIddwHXALkKg== X-CSE-MsgGUID: E10XV0H6R9Oj1g0Sq85Beg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745797" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745797" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:41 -0800 X-CSE-ConnectionGUID: G3ZU3MZiRXqYk1HIocWDrg== X-CSE-MsgGUID: sS8uGskaSfKOvHAVm5XCBQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605479" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:40 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 11/32] KVM: nVMX: Add tertiary VM-execution control VMCS support Date: Tue, 3 Feb 2026 10:16:54 -0800 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Support tertiary processor-based VM-execution control VMCS field. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/hyperv.c | 10 ++++++++++ arch/x86/kvm/vmx/nested.c | 17 +++++++++++++++++ arch/x86/kvm/vmx/nested.h | 7 +++++++ arch/x86/kvm/vmx/vmcs12.c | 1 + arch/x86/kvm/vmx/vmcs12.h | 3 ++- 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c index 2731c2e4b0e5..70e210472681 100644 --- a/arch/x86/kvm/vmx/hyperv.c +++ b/arch/x86/kvm/vmx/hyperv.c @@ -166,6 +166,12 @@ static bool nested_evmcs_is_valid_controls(enum evmcs_= ctrl_type ctrl_type, return !(val & ~evmcs_get_supported_ctls(ctrl_type)); } =20 +static bool nested_evmcs_is_valid_controls64(enum evmcs_ctrl_type ctrl_typ= e, + u64 val) +{ + return !(val & ~evmcs_get_supported_ctls(ctrl_type)); +} + int nested_evmcs_check_controls(struct vmcs12 *vmcs12) { if (CC(!nested_evmcs_is_valid_controls(EVMCS_PINCTRL, @@ -188,6 +194,10 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) vmcs12->vm_entry_controls))) return -EINVAL; =20 + if (CC(!nested_evmcs_is_valid_controls64(EVMCS_3RDEXEC, + vmcs12->tertiary_vm_exec_control))) + return -EINVAL; + /* * VM-Func controls are 64-bit, but KVM currently doesn't support any * controls in bits 63:32, i.e. dropping those bits on the consistency diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 8cd56e9f1cf0..3e02dee38e9c 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -1813,6 +1813,7 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vm= x *vmx, u32 hv_clean_fields vmcs12->vm_exit_controls =3D evmcs->vm_exit_controls; vmcs12->secondary_vm_exec_control =3D evmcs->secondary_vm_exec_control; + vmcs12->tertiary_vm_exec_control =3D 0; } =20 if (unlikely(!(hv_clean_fields & @@ -2510,6 +2511,17 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vm= x, struct loaded_vmcs *vmcs0 secondary_exec_controls_set(vmx, exec_control); } =20 + /* + * TERTIARY EXEC CONTROLS + */ + if (cpu_has_tertiary_exec_ctrls()) { + u64 ctls =3D 0; + + /* guest apic timer virtualization will come */ + + tertiary_exec_controls_set(vmx, ctls); + } + /* * ENTRY CONTROLS * @@ -2955,6 +2967,11 @@ static int nested_check_vm_execution_controls(struct= kvm_vcpu *vcpu, vmx->nested.msrs.secondary_ctls_high))) return -EINVAL; =20 + if (nested_cpu_has(vmcs12, CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) && + CC(!vmx_control64_verify(vmcs12->tertiary_vm_exec_control, + vmx->nested.msrs.tertiary_ctls))) + return -EINVAL; + if (CC(vmcs12->cr3_target_count > nested_cpu_vmx_misc_cr3_count(vcpu)) || nested_vmx_check_io_bitmap_controls(vcpu, vmcs12) || nested_vmx_check_msr_bitmap_controls(vcpu, vmcs12) || diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index d6d89ae1daec..2a3768a194fe 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -170,6 +170,13 @@ static inline bool nested_cpu_has2(struct vmcs12 *vmcs= 12, u32 bit) (vmcs12->secondary_vm_exec_control & bit); } =20 +static inline bool nested_cpu_has3(struct vmcs12 *vmcs12, u64 bit) +{ + return (vmcs12->cpu_based_vm_exec_control & + CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) && + (vmcs12->tertiary_vm_exec_control & bit); +} + static inline bool nested_cpu_has_preemption_timer(struct vmcs12 *vmcs12) { return vmcs12->pin_based_vm_exec_control & diff --git a/arch/x86/kvm/vmx/vmcs12.c b/arch/x86/kvm/vmx/vmcs12.c index 4233b5ca9461..2a21864a020a 100644 --- a/arch/x86/kvm/vmx/vmcs12.c +++ b/arch/x86/kvm/vmx/vmcs12.c @@ -38,6 +38,7 @@ const unsigned short vmcs12_field_offsets[] =3D { FIELD64(PML_ADDRESS, pml_address), FIELD64(TSC_OFFSET, tsc_offset), FIELD64(TSC_MULTIPLIER, tsc_multiplier), + FIELD64(TERTIARY_VM_EXEC_CONTROL, tertiary_vm_exec_control), FIELD64(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr), FIELD64(APIC_ACCESS_ADDR, apic_access_addr), FIELD64(POSTED_INTR_DESC_ADDR, posted_intr_desc_addr), diff --git a/arch/x86/kvm/vmx/vmcs12.h b/arch/x86/kvm/vmx/vmcs12.h index 4ad6b16525b9..db1f86a48343 100644 --- a/arch/x86/kvm/vmx/vmcs12.h +++ b/arch/x86/kvm/vmx/vmcs12.h @@ -71,7 +71,7 @@ struct __packed vmcs12 { u64 pml_address; u64 encls_exiting_bitmap; u64 tsc_multiplier; - u64 padding64[1]; /* room for future expansion */ + u64 tertiary_vm_exec_control; /* * To allow migration of L1 (complete with its L2 guests) between * machines of different natural widths (32 or 64 bit), we cannot have @@ -261,6 +261,7 @@ static inline void vmx_check_vmcs12_offsets(void) CHECK_OFFSET(pml_address, 312); CHECK_OFFSET(encls_exiting_bitmap, 320); CHECK_OFFSET(tsc_multiplier, 328); + CHECK_OFFSET(tertiary_vm_exec_control, 336); CHECK_OFFSET(cr0_guest_host_mask, 344); CHECK_OFFSET(cr4_guest_host_mask, 352); CHECK_OFFSET(cr0_read_shadow, 360); --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 108C73D6678; Tue, 3 Feb 2026 18:17:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142664; cv=none; b=D84r/ipnTVxwJqCS/6hBezqAPVauYG8cso6q27tRrWW7KFbr7T+9xjdI03GrM7ew0MB85obak60yF3dwM1T8i17V7+EcZvvPY0Uyl6Scx2QTA5LY57yoSfutxp9bgs+YMSPjd9KikvYKq8rvDWzUcUdl/OMddGDy0WCo+R/FOMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142664; c=relaxed/simple; bh=ygxoguN3hTv5ACLQU4KD3m9xKTSxYHGGA0so5e174bw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uXiQA46LdolOyxiK7U+705f4iQ1pQhIfdSzh/HJlir5tUV7m9QNOmh2x092JAkTBxmStuyJP3pNiWsYww9MELMWK5vuUErKS/7F8O4kCLOjOJ0Z02rsTdSdZ7DTis9MdA8Te0DfD78BVrPdic1h0/V9AKQx0qdS4Atws8NHSJ9o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=UptHThwQ; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="UptHThwQ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142663; x=1801678663; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ygxoguN3hTv5ACLQU4KD3m9xKTSxYHGGA0so5e174bw=; b=UptHThwQ+eGNMzqlufjIzVX56l4FSEIJ6O0/bASzM2UtWqqDTpArD2Dr 5M33t6liGDcn5pXXrCe28oJJrU7WP0rFtMHj1wh3FWrYOevmpwRACD9sC MyL756nIXhPb2wLtzOn2drRMrRVS5B789jwL8ctbLiOaJI+2bfYSRPol9 lB22z2kFG9S8Ei0dbJlGJw4X56jYVo4R7miBZ0/9lsgskA7rEKD/ppPfy 4uNH0+J+m2iJwXSt+94Ob135u8Pk+ZXtLOYvoUGyaNiCwGZiQ1usCxOHT wYb0K0ZIMIHylJZPUS+Q1WCJ36a+iWjBKzv4Acs80efx9NEiR/UqvVppC g==; X-CSE-ConnectionGUID: nC+cDCJ5Sh+0p6S/aL2qbw== X-CSE-MsgGUID: zx0m2uofRm2O04qsBQYuwg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745801" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745801" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:42 -0800 X-CSE-ConnectionGUID: qNJiH//jR5O/W/PFqnJftQ== X-CSE-MsgGUID: 06dt9Ib7QDCwwpBYqfKZ2A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605482" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:41 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 12/32] KVM: nVMX: Update intercept on TSC deadline MSR Date: Tue, 3 Feb 2026 10:16:55 -0800 Message-ID: <6f8a75e4848e03b84370a57520cc2a7fad799ed2.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata When APIC timer virtualization is enabled, the hardware handles the access to the guest TSC deadline MSR, not by the VMM. Disable/enable MSR intercept on TSC DEADLINE MSR based on the APIC timer virtualization bit of tertiary processor-based execution control. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/nested.c | 22 ++++++++++++++++++++++ arch/x86/kvm/vmx/nested.h | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 3e02dee38e9c..191317479d5e 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -595,6 +595,26 @@ static inline void enable_x2apic_msr_intercepts(unsign= ed long *msr_bitmap) } } =20 +static inline void prepare_tsc_deadline_msr_intercepts(struct vmcs12 *vmcs= 12, + unsigned long *msr_bitmap_l1, + unsigned long *msr_bitmap_l0) +{ + if (nested_cpu_has_guest_apic_timer(vmcs12)) { + if (vmx_test_msr_bitmap_read(msr_bitmap_l1, MSR_IA32_TSC_DEADLINE)) + vmx_set_msr_bitmap_read(msr_bitmap_l0, MSR_IA32_TSC_DEADLINE); + else + vmx_clear_msr_bitmap_read(msr_bitmap_l0, MSR_IA32_TSC_DEADLINE); + + if (vmx_test_msr_bitmap_write(msr_bitmap_l1, MSR_IA32_TSC_DEADLINE)) + vmx_set_msr_bitmap_write(msr_bitmap_l0, MSR_IA32_TSC_DEADLINE); + else + vmx_clear_msr_bitmap_write(msr_bitmap_l0, MSR_IA32_TSC_DEADLINE); + } else { + vmx_set_msr_bitmap_read(msr_bitmap_l0, MSR_IA32_TSC_DEADLINE); + vmx_set_msr_bitmap_write(msr_bitmap_l0, MSR_IA32_TSC_DEADLINE); + } +} + #define BUILD_NVMX_MSR_INTERCEPT_HELPER(rw) \ static inline \ void nested_vmx_set_msr_##rw##_intercept(struct vcpu_vmx *vmx, \ @@ -701,6 +721,8 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct= kvm_vcpu *vcpu, } } =20 + prepare_tsc_deadline_msr_intercepts(vmcs12, msr_bitmap_l1, msr_bitmap_l0); + /* * Always check vmcs01's bitmap to honor userspace MSR filters and any * other runtime changes to vmcs01's bitmap, e.g. dynamic pass-through. diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index 2a3768a194fe..9ca1df72e228 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -281,6 +281,11 @@ static inline bool nested_cpu_has_encls_exit(struct vm= cs12 *vmcs12) return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENCLS_EXITING); } =20 +static inline bool nested_cpu_has_guest_apic_timer(struct vmcs12 *vmcs12) +{ + return nested_cpu_has3(vmcs12, TERTIARY_EXEC_GUEST_APIC_TIMER); +} + /* * if fixed0[i] =3D=3D 1: val[i] must be 1 * if fixed1[i] =3D=3D 0: val[i] must be 0 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CE41E3D6692; Tue, 3 Feb 2026 18:17:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142665; cv=none; b=ebNimNrn0bth8F0DqSLgkaikER1JtKbxFsRSiRe+3TViq7PC5KVtBcWP/KjfanQOToN5V85F1nyshWUm3CIv1fzxibNRqoou4Ay9Y3LmjudTutPl3yMd+to2AcWVEIwvY+qWn8fhq+IsHEEIQwwfkNp2Nx/vcFPRrcVPwTgNKr4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142665; c=relaxed/simple; bh=lay6C04NpMEaRDmWEt9cg+qeeEi4r9NeoST7W3hXgnE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=n4ygADAGpLEiI2L3Cb+DABN80O2m0KGzFjNEDgIJW0hKcIJmCn+kr/mkWtJG2n89ERv0gORaiZwoPHIRU2NKwaWL/2ZjVGPTy1kLuOEbgP/qJpb5lLzIRGN5jlGYhQ20RIaRdALQQkOt5iZKROfsxiz3stEIujmRPM2rwos6/bY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=TrPz3Tic; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="TrPz3Tic" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142664; x=1801678664; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=lay6C04NpMEaRDmWEt9cg+qeeEi4r9NeoST7W3hXgnE=; b=TrPz3TiczwWeG8zn6azTTn9jypRcJZIuepq0AgTI2IuKYyGfDEfEP4VR Zc9kbDTYiMMpKa1Jwkq3sPNnm6cQHrOyD4L7pK0H7yr5+JyqqBmPa11+X T64Hh8MUSFtCzQXpzPYOT6JjFZ3Q0RHyLAkNBShnKr+dEBt8WXBWyhLN8 /fLh0szNii26hkLRaPKXO6uVN69R/1Qu6mq3VsA7WoZjITGVQ/4KfwSEh Tx20nbnUz7LBt77v0lCZlkqkIxxaMcIvnavra5GCqVZr7Gu84achFViyi BP6MehpdqPKuK9yOBRXJL34HuWBJHXz+71AwAlKWPVWPKlUnQf0+Cx3mD A==; X-CSE-ConnectionGUID: nakI1TOtSbq7vvrPweHNuA== X-CSE-MsgGUID: v7Yp3wshSZOTKDGdNMzVxQ== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745806" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745806" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:42 -0800 X-CSE-ConnectionGUID: YWZoxF6LTBW36s5Sr2mW/w== X-CSE-MsgGUID: EJd6BUxASYuNw1Bxptu99w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605485" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:41 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 13/32] KVM: nVMX: Handle virtual timer vector VMCS field Date: Tue, 3 Feb 2026 10:16:56 -0800 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Support virtual timer vector VMCS field. Opportunistically add a size check of struct vmcs12. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/nested.c | 15 ++++++++++++++- arch/x86/kvm/vmx/vmcs12.c | 3 +++ arch/x86/kvm/vmx/vmcs12.h | 2 ++ arch/x86/kvm/vmx/vmcs_shadow_fields.h | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 191317479d5e..5829562145a7 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -86,6 +86,15 @@ static void init_vmcs_shadow_fields(void) pr_err("Missing field from shadow_read_only_field %x\n", field + 1); =20 + switch (field) { + case GUEST_APIC_TIMER_VECTOR: + if (!cpu_has_vmx_apic_timer_virt()) + continue; + break; + default: + break; + } + clear_bit(field, vmx_vmread_bitmap); if (field & 1) #ifdef CONFIG_X86_64 @@ -2539,7 +2548,8 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx= , struct loaded_vmcs *vmcs0 if (cpu_has_tertiary_exec_ctrls()) { u64 ctls =3D 0; =20 - /* guest apic timer virtualization will come */ + if (nested_cpu_has_guest_apic_timer(vmcs12)) + ctls |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; =20 tertiary_exec_controls_set(vmx, ctls); } @@ -2733,6 +2743,9 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx,= struct vmcs12 *vmcs12) vmcs_write64(EOI_EXIT_BITMAP3, vmcs12->eoi_exit_bitmap3); } =20 + if (nested_cpu_has_guest_apic_timer(vmcs12)) + vmcs_write16(GUEST_APIC_TIMER_VECTOR, vmcs12->virtual_timer_vector); + /* * Make sure the msr_autostore list is up to date before we set the * count in the vmcs02. diff --git a/arch/x86/kvm/vmx/vmcs12.c b/arch/x86/kvm/vmx/vmcs12.c index 2a21864a020a..3842ee1ddabf 100644 --- a/arch/x86/kvm/vmx/vmcs12.c +++ b/arch/x86/kvm/vmx/vmcs12.c @@ -3,6 +3,8 @@ =20 #include "vmcs12.h" =20 +static_assert(sizeof(struct vmcs12) <=3D VMCS12_SIZE); + #define VMCS12_OFFSET(x) offsetof(struct vmcs12, x) #define FIELD(number, name) [ROL16(number, 6)] =3D VMCS12_OFFSET(name) #define FIELD64(number, name) \ @@ -22,6 +24,7 @@ const unsigned short vmcs12_field_offsets[] =3D { FIELD(GUEST_TR_SELECTOR, guest_tr_selector), FIELD(GUEST_INTR_STATUS, guest_intr_status), FIELD(GUEST_PML_INDEX, guest_pml_index), + FIELD(GUEST_APIC_TIMER_VECTOR, virtual_timer_vector), FIELD(HOST_ES_SELECTOR, host_es_selector), FIELD(HOST_CS_SELECTOR, host_cs_selector), FIELD(HOST_SS_SELECTOR, host_ss_selector), diff --git a/arch/x86/kvm/vmx/vmcs12.h b/arch/x86/kvm/vmx/vmcs12.h index db1f86a48343..d8e09de44f2a 100644 --- a/arch/x86/kvm/vmx/vmcs12.h +++ b/arch/x86/kvm/vmx/vmcs12.h @@ -191,6 +191,7 @@ struct __packed vmcs12 { u16 host_gs_selector; u16 host_tr_selector; u16 guest_pml_index; + u16 virtual_timer_vector; }; =20 /* @@ -373,6 +374,7 @@ static inline void vmx_check_vmcs12_offsets(void) CHECK_OFFSET(host_gs_selector, 992); CHECK_OFFSET(host_tr_selector, 994); CHECK_OFFSET(guest_pml_index, 996); + CHECK_OFFSET(virtual_timer_vector, 998); } =20 extern const unsigned short vmcs12_field_offsets[]; diff --git a/arch/x86/kvm/vmx/vmcs_shadow_fields.h b/arch/x86/kvm/vmx/vmcs_= shadow_fields.h index cad128d1657b..db1558d11c4c 100644 --- a/arch/x86/kvm/vmx/vmcs_shadow_fields.h +++ b/arch/x86/kvm/vmx/vmcs_shadow_fields.h @@ -34,6 +34,7 @@ BUILD_BUG_ON(1) /* 16-bits */ SHADOW_FIELD_RW(GUEST_INTR_STATUS, guest_intr_status) SHADOW_FIELD_RW(GUEST_PML_INDEX, guest_pml_index) +SHADOW_FIELD_RO(GUEST_APIC_TIMER_VECTOR, virtual_timer_vector) SHADOW_FIELD_RW(HOST_FS_SELECTOR, host_fs_selector) SHADOW_FIELD_RW(HOST_GS_SELECTOR, host_gs_selector) =20 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 62FE33D7D63; Tue, 3 Feb 2026 18:17:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142665; cv=none; b=XzZn+pdfIL4DDRFtxtbgVhMr0BQYIWHIOTvlTM0L57n8qytMolTs/8qRSMcLALhdNSZ6VVrqmOU/629CCLfExXtSiH7TKWjsc56z0LgtoQKeDkyvs62Yk+gTbxw/bzuirzCLwMUKgbTW3sPENvMWc3gnot7IhzWGI5r6J4ldqQg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142665; c=relaxed/simple; bh=9XI7vB+0OJRjYggT6bE/btEJW/0e/kC1khjIdnkgrRc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZO/6bjEA1aBgiXBPdiwHZLCGTSNLWOLDTJBmXG2thowNkwlvUE1//mEdMIKZzdiE1bzO6kqCVj4/9mDu8fie0utQ0mkOnPJE3ysaTpmCVshBilXkyDojJAa2qub2chJcKyH7Ky/YWBjpug66sGOLiGmIH7eK7g8DjoyOy3Qm72M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=MBvL2Ua9; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="MBvL2Ua9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142665; x=1801678665; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9XI7vB+0OJRjYggT6bE/btEJW/0e/kC1khjIdnkgrRc=; b=MBvL2Ua9Yk1BInlgt+YWY26OnQNg3N1CplfcNCPJg+ElNpCE9vhCsx8e a/ufl1Rg2LSacMEJMDYHgimP5+j8Yk9hccjII61e+gNCm+31BzFJm8OmJ ZURCaPlfZqbyoivSrhDwLaevXGKyrlbscr2JxcS7Zs7r4hjOG3FZi9OW/ NYWhgMnAMpbALowUaCEeyX1Yebgu2oOx7vieZlFWhC1uBnrp/jwYAuH60 x+9Mm6hz+2/Iz3eqJSGUWquAvDZMSioY3PceduOuEHtVfi0Wa/mYYB1en YOFO/83f0LxWvHNWYpvCgj6Ty967C4eBCj6Mpnx950PWfVSx8t/oaexxH Q==; X-CSE-ConnectionGUID: DfXAEdEpSKi77E2yxDA7pA== X-CSE-MsgGUID: YFDwxr65RfC2TXAo90dwfg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745810" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745810" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:42 -0800 X-CSE-ConnectionGUID: Zfh5TzQVTgK6R48jzLbj6A== X-CSE-MsgGUID: 4zEi82FJSUOUGp+5STScvw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605488" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:42 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 14/32] KVM: VMX: Make vmx_calc_deadline_l1_to_host() non-static Date: Tue, 3 Feb 2026 10:16:57 -0800 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Remove static from vmx_calc_deadline_l1_to_host() and declare in vmx.h. As nVMX APIC timer virtualization will use vmx_calc_deadline_l1_to_host(), make it available to nested.c. Make u64_shl_div_u64() usable for X86_32 that vmx_calc_deadline_l1_to_host() uses for both X86_32 and X86_64. Without this change, ARCH=3Di386 fails to compile. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/vmx.c | 41 ++++++++++++++++++++++++----------------- arch/x86/kvm/vmx/vmx.h | 2 ++ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index dc6b6659a093..41c94f5194f6 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8218,25 +8218,32 @@ int vmx_check_intercept(struct kvm_vcpu *vcpu, return X86EMUL_INTERCEPTED; } =20 -#ifdef CONFIG_X86_64 /* (a << shift) / divisor, return 1 if overflow otherwise 0 */ static inline int u64_shl_div_u64(u64 a, unsigned int shift, u64 divisor, u64 *result) { - u64 low =3D a << shift, high =3D a >> (64 - shift); + u64 high =3D a >> (64 - shift); +#ifdef CONFIG_X86_64 + u64 low =3D a << shift; +#endif =20 /* To avoid the overflow on divq */ if (high >=3D divisor) return 1; =20 +#ifdef CONFIG_X86_64 /* Low hold the result, high hold rem which is discarded */ asm("divq %2\n\t" : "=3Da" (low), "=3Dd" (high) : "rm" (divisor), "0" (low), "1" (high)); *result =3D low; +#else + *result =3D mul_u64_u64_div_u64(a, 1ULL << shift, divisor); +#endif =20 return 0; } =20 +#ifdef CONFIG_X86_64 int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc, bool *expired) { @@ -8314,7 +8321,21 @@ void vmx_cancel_apic_virt_timer(struct kvm_vcpu *vcp= u) tertiary_exec_controls_clearbit(to_vmx(vcpu), TERTIARY_EXEC_GUEST_APIC_TI= MER); } =20 -static u64 vmx_calc_deadline_l1_to_host(struct kvm_vcpu *vcpu, u64 l1_tsc) +void vmx_set_guest_tsc_deadline_virt(struct kvm_vcpu *vcpu, + u64 guest_deadline_virt) +{ + vmcs_write64(GUEST_DEADLINE_VIR, guest_deadline_virt); + vmcs_write64(GUEST_DEADLINE_PHY, + vmx_calc_deadline_l1_to_host(vcpu, guest_deadline_virt)); +} + +u64 vmx_get_guest_tsc_deadline_virt(struct kvm_vcpu *vcpu) +{ + return vmcs_read64(GUEST_DEADLINE_VIR); +} +#endif + +u64 vmx_calc_deadline_l1_to_host(struct kvm_vcpu *vcpu, u64 l1_tsc) { u64 host_tsc_now =3D rdtsc(); u64 l1_tsc_now =3D kvm_read_l1_tsc(vcpu, host_tsc_now); @@ -8354,20 +8375,6 @@ static u64 vmx_calc_deadline_l1_to_host(struct kvm_v= cpu *vcpu, u64 l1_tsc) return host_tsc; } =20 -void vmx_set_guest_tsc_deadline_virt(struct kvm_vcpu *vcpu, - u64 guest_deadline_virt) -{ - vmcs_write64(GUEST_DEADLINE_VIR, guest_deadline_virt); - vmcs_write64(GUEST_DEADLINE_PHY, - vmx_calc_deadline_l1_to_host(vcpu, guest_deadline_virt)); -} - -u64 vmx_get_guest_tsc_deadline_virt(struct kvm_vcpu *vcpu) -{ - return vmcs_read64(GUEST_DEADLINE_VIR); -} -#endif - void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx =3D to_vmx(vcpu); diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index cb32d0fdf3b8..28625a2d17bd 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -405,6 +405,8 @@ static inline void vmx_enable_intercept_for_msr(struct = kvm_vcpu *vcpu, u64 vmx_get_l2_tsc_offset(struct kvm_vcpu *vcpu); u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu); =20 +u64 vmx_calc_deadline_l1_to_host(struct kvm_vcpu *vcpu, u64 l1_tsc); + gva_t vmx_get_untagged_addr(struct kvm_vcpu *vcpu, gva_t gva, unsigned int= flags); =20 void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu); --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D64363D7D70; Tue, 3 Feb 2026 18:17:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142666; cv=none; b=lWz6h6RsRXcIScw7lawnzxd7m+qBD4CoEh8BFeDcG5xphpGYmYPRW/qNzBWbu3GQHhKyqmJ/hFAs3USTH395Fo85j74eRhIJjPMOEx6c6nGC4OR0gRQxppP9ZuWELy7CE8ZrYogJTelHleJSYaGw1UMjrVlEhRiqpa59z7XatMk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142666; c=relaxed/simple; bh=MtffooadCDO7564JErY6ne+USupfnVx4VISpnugLIYQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bprsDwVWNa3JRV1U5Sk9Ik73xq0lP8HZVRFsFLH+lvrD5TjGk7cnk2R7ub9HNuxv30QhUlOemgXDG/adQ+BHs95m75kwBEGrMix9RA0dr30Sry6k98BGI6DUyqM/4QsqcJYPl67vqHan5YyG7ZhgNhErzkD3Y0tqHEkYBDYhslw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Jzx0wYqa; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Jzx0wYqa" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142665; x=1801678665; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=MtffooadCDO7564JErY6ne+USupfnVx4VISpnugLIYQ=; b=Jzx0wYqaOuzs940xbCBDLpJydaEzvEOuxPR0ZJchNjjbb0samts3DEC0 F8YBMUhS50bvuj93+u2PS1wedTNkrADwFuGRtf9vZ4H32IWXm181V1DSQ NfczawqUZPsugcBIBQyvT+AkHjzICg9NAP/fIWDTttLlChZK/LJ8dBnTv yl1zIdCVPuWeqOu9rxrV1yUPVu78v2PaifhM+gnqnVr2o1au7n3uX9uYA 26isgINp5EcfenfZF0fMRSMYgI9d5IgwC/Xzz4kmAaDsB306RlsP6ubtd V10if45Emq7Z7kKoY/XuVJlfQuCmwWB3+WjPvqH3vyJa9Hzz/KBtVaisV w==; X-CSE-ConnectionGUID: 4iI74/tETzy+PUNlXxQjDw== X-CSE-MsgGUID: Pi1DVcYETEWCtg4jHoEF9w== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745814" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745814" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:43 -0800 X-CSE-ConnectionGUID: qyzcQAUgTv2Y3wgSirMolg== X-CSE-MsgGUID: Nl/bJ16GSwidw17TFMn5TA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605492" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:42 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 15/32] KVM: nVMX: Enable guest deadline and its shadow VMCS field Date: Tue, 3 Feb 2026 10:16:58 -0800 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Support the guest deadline and the guest deadline shadow VMCS field. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/nested.c | 48 +++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/vmx/vmcs12.c | 2 ++ arch/x86/kvm/vmx/vmcs12.h | 6 +++++ arch/x86/kvm/vmx/vmx.h | 2 ++ 4 files changed, 58 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 5829562145a7..66adc1821671 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -2763,6 +2763,22 @@ static void prepare_vmcs02_rare(struct vcpu_vmx *vmx= , struct vmcs12 *vmcs12) set_cr4_guest_host_mask(vmx); } =20 +static void nested_guest_apic_timer(struct kvm_vcpu *vcpu, struct vmcs12 *= vmcs12) +{ + u64 guest_deadline_shadow =3D vmcs12->guest_deadline_shadow; + u64 guest_deadline =3D vmcs12->guest_deadline; + struct vcpu_vmx *vmx =3D to_vmx(vcpu); + + if (!vmx->nested.guest_deadline_dirty) + return; + + guest_deadline =3D vmx_calc_deadline_l1_to_host(vcpu, guest_deadline); + + vmcs_write64(GUEST_DEADLINE_PHY, guest_deadline); + vmcs_write64(GUEST_DEADLINE_VIR, guest_deadline_shadow); + vmx->nested.guest_deadline_dirty =3D false; +} + /* * prepare_vmcs02 is called when the L1 guest hypervisor runs its nested * L2 guest. L1 has a vmcs for L2 (vmcs12), and this function "merges" it @@ -2840,6 +2856,9 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, stru= ct vmcs12 *vmcs12, if (kvm_caps.has_tsc_control) vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio); =20 + if (nested_cpu_has_guest_apic_timer(vmcs12)) + nested_guest_apic_timer(vcpu, vmcs12); + nested_vmx_transition_tlb_flush(vcpu, vmcs12, true); =20 if (nested_cpu_has_ept(vmcs12)) @@ -4637,6 +4656,8 @@ static bool is_vmcs12_ext_field(unsigned long field) case GUEST_IDTR_BASE: case GUEST_PENDING_DBG_EXCEPTIONS: case GUEST_BNDCFGS: + case GUEST_DEADLINE_PHY: + case GUEST_DEADLINE_VIR: return true; default: break; @@ -4687,6 +4708,24 @@ static void sync_vmcs02_to_vmcs12_rare(struct kvm_vc= pu *vcpu, vmcs12->guest_pending_dbg_exceptions =3D vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS); =20 + if (nested_cpu_has_guest_apic_timer(vmcs12)) { + u64 guest_deadline_shadow =3D vmcs_read64(GUEST_DEADLINE_VIR); + u64 guest_deadline =3D vmcs_read64(GUEST_DEADLINE_PHY); + + if (guest_deadline) { + guest_deadline =3D kvm_read_l1_tsc(vcpu, guest_deadline); + if (!guest_deadline) + guest_deadline =3D 1; + } + + vmcs12->guest_deadline =3D guest_deadline; + vmcs12->guest_deadline_shadow =3D guest_deadline_shadow; + } else if (vmx->nested.msrs.tertiary_ctls & TERTIARY_EXEC_GUEST_APIC_TIME= R) { + vmcs12->guest_deadline =3D 0; + vmcs12->guest_deadline_shadow =3D 0; + } + vmx->nested.guest_deadline_dirty =3D false; + vmx->nested.need_sync_vmcs02_to_vmcs12_rare =3D false; } =20 @@ -5959,6 +5998,13 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) vmx->nested.dirty_vmcs12 =3D true; } =20 + if (!is_guest_mode(vcpu) && + (field =3D=3D GUEST_DEADLINE_PHY || + field =3D=3D GUEST_DEADLINE_PHY_HIGH || + field =3D=3D GUEST_DEADLINE_VIR || + field =3D=3D GUEST_DEADLINE_VIR_HIGH)) + vmx->nested.guest_deadline_dirty =3D true; + return nested_vmx_succeed(vcpu); } =20 @@ -5973,6 +6019,7 @@ static void set_current_vmptr(struct vcpu_vmx *vmx, g= pa_t vmptr) } vmx->nested.dirty_vmcs12 =3D true; vmx->nested.force_msr_bitmap_recalc =3D true; + vmx->nested.guest_deadline_dirty =3D true; } =20 /* Emulate the VMPTRLD instruction */ @@ -7150,6 +7197,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, =20 vmx->nested.dirty_vmcs12 =3D true; vmx->nested.force_msr_bitmap_recalc =3D true; + vmx->nested.guest_deadline_dirty =3D true; ret =3D nested_vmx_enter_non_root_mode(vcpu, false); if (ret) goto error_guest_mode; diff --git a/arch/x86/kvm/vmx/vmcs12.c b/arch/x86/kvm/vmx/vmcs12.c index 3842ee1ddabf..6849790a0af1 100644 --- a/arch/x86/kvm/vmx/vmcs12.c +++ b/arch/x86/kvm/vmx/vmcs12.c @@ -70,6 +70,8 @@ const unsigned short vmcs12_field_offsets[] =3D { FIELD64(HOST_IA32_PAT, host_ia32_pat), FIELD64(HOST_IA32_EFER, host_ia32_efer), FIELD64(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl), + FIELD64(GUEST_DEADLINE_PHY, guest_deadline), + FIELD64(GUEST_DEADLINE_VIR, guest_deadline_shadow), FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control), FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control), FIELD(EXCEPTION_BITMAP, exception_bitmap), diff --git a/arch/x86/kvm/vmx/vmcs12.h b/arch/x86/kvm/vmx/vmcs12.h index d8e09de44f2a..c0d5981475b3 100644 --- a/arch/x86/kvm/vmx/vmcs12.h +++ b/arch/x86/kvm/vmx/vmcs12.h @@ -192,6 +192,10 @@ struct __packed vmcs12 { u16 host_tr_selector; u16 guest_pml_index; u16 virtual_timer_vector; + + /* offset 0x3e8 */ + u64 guest_deadline; + u64 guest_deadline_shadow; }; =20 /* @@ -375,6 +379,8 @@ static inline void vmx_check_vmcs12_offsets(void) CHECK_OFFSET(host_tr_selector, 994); CHECK_OFFSET(guest_pml_index, 996); CHECK_OFFSET(virtual_timer_vector, 998); + CHECK_OFFSET(guest_deadline, 1000); + CHECK_OFFSET(guest_deadline_shadow, 1008); } =20 extern const unsigned short vmcs12_field_offsets[]; diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 28625a2d17bd..bdeef2e12640 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -169,6 +169,8 @@ struct nested_vmx { bool has_preemption_timer_deadline; bool preemption_timer_expired; =20 + bool guest_deadline_dirty; + /* * Used to snapshot MSRs that are conditionally loaded on VM-Enter in * order to propagate the guest's pre-VM-Enter value into vmcs02. For --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A69F136CDF7; Tue, 3 Feb 2026 18:17:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142667; cv=none; b=VJGxvwp1hUn+RYN4+GNtFCaEdrEaToH5xW/b6czX5atcG2MXvXFcFNi/joREET4U6kJS0mcJn7g5V+u/x6JOlMUjyKmxi3lzgNlD8wMpzzLEpRGLvpodyA2ybY8FfidjKysbqEHMzxYPJfXfCHjCcegiOcvS/m201EQ9HO7AXbE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142667; c=relaxed/simple; bh=voz3+s1ChUumlWHWsfQ5GQcF6eeXX1XtQLaRACWTxXg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cCp5+vooDdRnGfpPpfgnkhtzCsnjMxS52ys5+F4z4dzJGoeXDg2qG7J3DDy0uvV1km07kei8rUiPbF/xKaCeB4O+GU7qS2DQd9CeGSh8yjlFUMvzSjqt+qs41UdJOIf2yA3LUeYn/a6zReIHMm7ItTFho0WiJzmYGYfPWuRPyCY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=VrsuOCqt; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="VrsuOCqt" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142666; x=1801678666; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=voz3+s1ChUumlWHWsfQ5GQcF6eeXX1XtQLaRACWTxXg=; b=VrsuOCqtZEoc0mIgsuZ8QrMSc8Hlxt4XCveOY7Xba/jA6HhAwTPBbNff AmWbw7MeXxNCX3G7Rxi5zvcXRbnotWt9w/s44L6mlJaLk6NwQZybiY4SN fZLfCnd/U/vkzpigsVyPfFIY4WjqIwutvNYxJgau2rGealm4H+4f5EFXE LgkklYNiFjHPsrdjjmrLi9+BhXsnZuqIx1N8AbyPC1Tg4OhQapxZ+G5VI S9TF/4bq0SGs53tH7K2ac20cqpMyBpQ03mVezNzjF/s6igdgrkV2EDuyJ ZcGnzcFVeGxSq/0ByQf/zQQjonYO3le2XJnMSyDvKS9UQrLOuiXhiEZvU w==; X-CSE-ConnectionGUID: iVqjwV3zR1WzCjSPAJlJ5A== X-CSE-MsgGUID: ZX6AP1/lSGKgR9RoHpHjeg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745818" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745818" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:43 -0800 X-CSE-ConnectionGUID: RoSHYyc2RLyxazbLlGPhIQ== X-CSE-MsgGUID: 9/K4KgYyQQKQIPcO2LwDiQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605495" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:42 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 16/32] KVM: nVMX: Add VM entry checks related to APIC timer virtualization Date: Tue, 3 Feb 2026 10:16:59 -0800 Message-ID: <7d0817ab09b55e055c344418008083d7049ab39b.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Add checks of VMX controls for APIC timer virtualization on VM entries. The spec adds some checks on VMX controls related to the APIC timer virtualization on VM entry. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/nested.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 66adc1821671..c8b42c880300 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3064,6 +3064,12 @@ static int nested_check_vm_execution_controls(struct= kvm_vcpu *vcpu, CC(!vmcs12->tsc_multiplier)) return -EINVAL; =20 + if (nested_cpu_has_guest_apic_timer(vmcs12) && + (CC(!nested_cpu_has_vid(vmcs12)) || + CC(nested_cpu_has(vmcs12, CPU_BASED_RDTSC_EXITING)) || + CC(vmcs12->virtual_timer_vector > 255))) + return -EINVAL; + return 0; } =20 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 07D4B3D9029; Tue, 3 Feb 2026 18:17:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142667; cv=none; b=EldO/zI4K0kbSWeRyYCDq2vgaZY8EAhz2WO1Tn0KpmkDbcoYtXERxD0YjgBBQujE9dylEShl5XEg/1PUv1F3/+ZWcD5AbQCr6C1jYMYDYI3/tpV7JZQ1i8JCd502tltkCD25RDyqKhuqpitZB0ONwpu/drrd9LJCPjmdtxLF37Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142667; c=relaxed/simple; bh=px+gf9CycIrN2SRb7cWFwlLMe1ewXZI2g90WSPrwj7s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g9FJ+HlFv7kfIZouoYYPj9u+ZG14hIrAaEJNydaVn3nZmJtArf1saFa/EpUThMeR231SZ3BWl2MCulS9rQ5oZqXaxpQRP2v3DgE5PQH/EAQlIVbivDfWZv/8VFytHtCEMDlh/wUqcdtObdV+sQUaz/FVtNxz+6JLvBbrnvD5MNk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=VAqHUdBc; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="VAqHUdBc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142666; x=1801678666; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=px+gf9CycIrN2SRb7cWFwlLMe1ewXZI2g90WSPrwj7s=; b=VAqHUdBcKcI/kvaS/5JqpHdPUmv8yHloPbrOsROMNRQVwcOs0gCZfP0F utm4peSxcBhCExhhY8CdMhJZuvuuHvrN6/dKLVuZEuJKaGyZUwvyWmNeq gQQcZahhmq7oYPXV9+vSHmKbGKXxAeP2cMFNbd3Vdmxhjc0TfdOPtpSk5 lwRVCeh7Ax9+dZb+A9VZEfPyfs20vSlefsoZ8vQK8VFEx7cp5Xn/ImDo1 WFYPx8TDMqnu7bj5znU4EJNt49An7GFwCWizZ+9BBr0KrZwjd0HRaS/G5 Z8begdY8o9XGzl7eRR+TvVwGik1cuVS5GyVT53qFRFfpTjUvSY87xGW5G g==; X-CSE-ConnectionGUID: MHTgx4+oRTiWNVQvnIpTAg== X-CSE-MsgGUID: Sl5GRDBURpiui6vLfgpUvQ== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745823" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745823" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:44 -0800 X-CSE-ConnectionGUID: W7yY16fLS7qbPpRzmzGmuw== X-CSE-MsgGUID: FtFY+x9hT1OXLV/050JKtQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605498" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:43 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, kernel test robot Subject: [PATCH 17/32] KVM: nVMX: Add check vmread/vmwrite on tertiary control Date: Tue, 3 Feb 2026 10:17:00 -0800 Message-ID: <610a83212de7a5e598e45a4d80d3409ac693ffb6.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Make the access to the tertiary processor-based VM control an error if the guest VMX true processor-based controls don't report it. Without this patch, the KVM unit test_vmread_vmwrite() fails because vmread()/vmwrite() can succeeds with the index beyond MSR_IA32_VMX_VMCS_ENUM when the tertiary processor-based VM-executing controls aren't advertised to the guest. Reported-by: kernel test robot Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/nested.c | 20 ++++++++++++++++++++ arch/x86/kvm/vmx/nested.h | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index c8b42c880300..d6ae62e70560 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -5794,6 +5794,16 @@ static int handle_vmresume(struct kvm_vcpu *vcpu) return nested_vmx_run(vcpu, false); } =20 +static bool is_vmcs_field_valid(struct kvm_vcpu *vcpu, unsigned long field) +{ + if (!nested_cpu_supports_tertiary_ctls(vcpu) && + (field =3D=3D TERTIARY_VM_EXEC_CONTROL || + field =3D=3D TERTIARY_VM_EXEC_CONTROL_HIGH)) + return false; + + return true; +} + static int handle_vmread(struct kvm_vcpu *vcpu) { struct vmcs12 *vmcs12 =3D is_guest_mode(vcpu) ? get_shadow_vmcs12(vcpu) @@ -5824,6 +5834,9 @@ static int handle_vmread(struct kvm_vcpu *vcpu) get_vmcs12(vcpu)->vmcs_link_pointer =3D=3D INVALID_GPA)) return nested_vmx_failInvalid(vcpu); =20 + if (!is_vmcs_field_valid(vcpu, field)) + return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); + offset =3D get_vmcs12_field_offset(field); if (offset < 0) return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); @@ -5948,6 +5961,9 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) =20 field =3D kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf)); =20 + if (!is_vmcs_field_valid(vcpu, field)) + return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); + offset =3D get_vmcs12_field_offset(field); if (offset < 0) return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); @@ -7196,6 +7212,10 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcp= u, kvm_state->hdr.vmx.preemption_timer_deadline; } =20 + if (!nested_cpu_supports_tertiary_ctls(vcpu) && + vmcs12->tertiary_vm_exec_control) + goto error_guest_mode; + if (nested_vmx_check_controls(vcpu, vmcs12) || nested_vmx_check_host_state(vcpu, vmcs12) || nested_vmx_check_guest_state(vcpu, vmcs12, &ignored)) diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index 9ca1df72e228..07c0f112e37e 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -158,6 +158,11 @@ static inline bool __nested_cpu_supports_tertiary_ctls= (struct nested_vmx_msrs *m return msrs->procbased_ctls_high & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; } =20 +static inline bool nested_cpu_supports_tertiary_ctls(struct kvm_vcpu *vcpu) +{ + return __nested_cpu_supports_tertiary_ctls(&to_vmx(vcpu)->nested.msrs); +} + static inline bool nested_cpu_has(struct vmcs12 *vmcs12, u32 bit) { return vmcs12->cpu_based_vm_exec_control & bit; --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B6F9A36E473; Tue, 3 Feb 2026 18:17:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142668; cv=none; b=mYrdFtZRq6c9SSrUaK6R/DgR0H9H2sQ19UNll4CMmqj1IqpGhLCt4QZM0a7+eHgzmI38Pp/v6TQCT0xC0g2ckoY+oDauG4FL8bMP8wS4aBLE1cLkenxMQkT0w4sM9CjQFOcYzjP/hNbK8qElJlTc9QDKGEhx1Ptn3j/jxSOhhyQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142668; c=relaxed/simple; bh=16MA10iAEBEjY/zIcYesOhSOwM/Zu2zd4qCPUxxxgCo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=djxi2aTWJJDc5MHVj3mKbLWj/WKe1CLtLd9lnqS3fIIKpeSwsBvciAMUkTN2aTKxjFIfFM7lyQ1DV2g81RWR1Nx90m90cF9Rqgi2uJ+5eapOhpFhS6+yHnsF6wtXbaaXv9GAJ+3sH8mlnBbTF/GrhYhBZlFVrBQS1USgHM/AYy4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=Ea2/arQb; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="Ea2/arQb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142667; x=1801678667; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=16MA10iAEBEjY/zIcYesOhSOwM/Zu2zd4qCPUxxxgCo=; b=Ea2/arQbLtRjA3175wG3qo1n6rrr2oSzRGRqix21dwwR9YKpb/6LJmLa G8n3+ymCag7nF/W4YZGSsuKkAAViHvpLc81S6aFeMJBKssn78caugmWLY y0LMdYYFjl9zRIble+0mpYsGmwas8OC2zjVuWPiVmINb9GV9Z18zJ5i8P skkqehfd+ivJ99TKlZeclMBEDpwKP9oFC8igtwb5UMwpEn9htOpZ+5831 b9KyNOwtA9N1Cj0BRJUvb0ITM5ZnQzZeJE09slIzKktvEy1fcajXdjItI DCN5t/huBC6+v8Ur/QFByj+n4qPz4QwMKJcJxOEkBhDsqd10DiF0dI4m7 w==; X-CSE-ConnectionGUID: s+qQy+OVT1+jg6o+k+CCPg== X-CSE-MsgGUID: VPN1EBFuQ2uE0RRa5FVGQg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745828" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745828" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:44 -0800 X-CSE-ConnectionGUID: OpeYDVIUSSi+eX7pc5IQOA== X-CSE-MsgGUID: 9hRHuqUdQ4WDgeUKpiB/bQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605505" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:43 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, kernel test robot Subject: [PATCH 18/32] KVM: nVMX: Add check VMCS index for guest timer virtualization Date: Tue, 3 Feb 2026 10:17:01 -0800 Message-ID: <01a8714db6af834214a3811c4d4b727371264964.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Make vmread/vmwrite to the VMCS fields an error if the guest MSR_IA32_VMX_PROCBASED_CTLS3 doesn't advertise APIC timer virtualization. Without this check, test_vmwrite_vmread of the KVM unit test fails. Reported-by: kernel test robot Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/nested.c | 14 ++++++++++++++ arch/x86/kvm/vmx/nested.h | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index d6ae62e70560..a940f1d9ee83 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -5801,6 +5801,14 @@ static bool is_vmcs_field_valid(struct kvm_vcpu *vcp= u, unsigned long field) field =3D=3D TERTIARY_VM_EXEC_CONTROL_HIGH)) return false; =20 + if (!nested_cpu_supports_guest_apic_timer(vcpu) && + (field =3D=3D GUEST_APIC_TIMER_VECTOR || + field =3D=3D GUEST_DEADLINE_VIR || + field =3D=3D GUEST_DEADLINE_VIR_HIGH || + field =3D=3D GUEST_DEADLINE_PHY || + field =3D=3D GUEST_DEADLINE_PHY_HIGH)) + return false; + return true; } =20 @@ -7216,6 +7224,12 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcp= u, vmcs12->tertiary_vm_exec_control) goto error_guest_mode; =20 + if (!nested_cpu_supports_guest_apic_timer(vcpu) && + (vmcs12->virtual_timer_vector || + vmcs12->guest_deadline || + vmcs12->guest_deadline_shadow)) + goto error_guest_mode; + if (nested_vmx_check_controls(vcpu, vmcs12) || nested_vmx_check_host_state(vcpu, vmcs12) || nested_vmx_check_guest_state(vcpu, vmcs12, &ignored)) diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index 07c0f112e37e..d84ed234a8d6 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -286,6 +286,13 @@ static inline bool nested_cpu_has_encls_exit(struct vm= cs12 *vmcs12) return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENCLS_EXITING); } =20 +static inline bool nested_cpu_supports_guest_apic_timer(struct kvm_vcpu *v= cpu) +{ + return nested_cpu_supports_tertiary_ctls(vcpu) && + to_vmx(vcpu)->nested.msrs.tertiary_ctls & + TERTIARY_EXEC_GUEST_APIC_TIMER; +} + static inline bool nested_cpu_has_guest_apic_timer(struct vmcs12 *vmcs12) { return nested_cpu_has3(vmcs12, TERTIARY_EXEC_GUEST_APIC_TIMER); --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DAEDA3DA7FB; Tue, 3 Feb 2026 18:17:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142669; cv=none; b=K+rsFZmOZip6fq+sB3TSEslYfbn7TXMq0ejRl2JQoi5UJitG7hmBuUPVtkPX1M+XOnY8BH2h7SIHUOrWIPZXyE7NB3bGqgzoIxQYUlJ3ciuyXImCYIcusp/psJnZi0NTuCAnlJZmQoxLAE7BNCRzo6Nz9+uzzKm4IIYFevg/ksE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142669; c=relaxed/simple; bh=VjG2YAysFSwDRuY/3SPr+aLhDFhOkSIB0MlGU+9VGuk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uYcB+MoNs+z5qw2ZDkW6JBzmQiO/iLK5jj6WR5ceOOV9n4FXUWcZfgihQzVwpieuepkhADngWMdQNa5Zp861cp+AhpUpvBoZkAhtnaKv1zc98EPSNpqB4FhB7LE6WnWv4wgUsgnDNMj7o5RWUQPnNkq/SrdFOdDbFLdVILnz0VE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=EQl/B27c; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="EQl/B27c" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142668; x=1801678668; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=VjG2YAysFSwDRuY/3SPr+aLhDFhOkSIB0MlGU+9VGuk=; b=EQl/B27cNx57edW79EPEEjTGwRqqJWS0XHRaWOeR9YeuWVqzefKZcpCy EwjAHKkx9fbXzUcL2pnE0bLbv3h8YIRGIAynwVviS06E/Fh3vemYqNOVE IXEggR8TGPbZyuMynrdTha5lO2KHG9ir3iCLU+t7DNxsklRqGBzhZZSB4 wTIKhFW7/Ug00+TSW6VVXX833ztOsqV+xIcv7YdD4o0+oH7K+JougyNZh wxGiTa/zckADmhtwh/CXmPOi5YreJKv/FzcXOd+NNdewRgUdn0Ejoq8sW s0oy4zft5aKfypNG9TOnf+uk3MmpIa1KXznvFWtJmEIa4YNbRghiR2Oel g==; X-CSE-ConnectionGUID: 2DyFIYnqTAKOvVUl3JFsoA== X-CSE-MsgGUID: ZiZZb6CIQ7iZFQCdfJBsDw== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745833" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745833" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:44 -0800 X-CSE-ConnectionGUID: 5NCJ0TZTS2uP92aNJwa1OQ== X-CSE-MsgGUID: ioY4IeAvR42f3y2+Vc8hrw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605510" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:44 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 19/32] KVM: VMX: Advertise tertiary controls to the user space Date: Tue, 3 Feb 2026 10:17:02 -0800 Message-ID: <2e7175eeceb0c38bad5322e20db4acc6ab38cc83.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Make KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST, KVM_GET_MSRS to advertise MSR_IA32_VMX_PROCBASED_CTLS3 to the user space VMM like QEMU. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/vmx.c | 3 +++ arch/x86/kvm/x86.c | 1 + 2 files changed, 4 insertions(+) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 41c94f5194f6..50d4390d41f0 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7146,6 +7146,9 @@ bool vmx_has_emulated_msr(struct kvm *kvm, u32 index) */ return enable_unrestricted_guest || emulate_invalid_guest_state; case KVM_FIRST_EMULATED_VMX_MSR ... KVM_LAST_EMULATED_VMX_MSR: + if (index =3D=3D MSR_IA32_VMX_PROCBASED_CTLS3 && + !__nested_cpu_supports_tertiary_ctls(&vmcs_config.nested)) + return false; return nested; case MSR_AMD64_VIRT_SPEC_CTRL: case MSR_AMD64_TSC_RATIO: diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2a72709aeb03..beeee88e3878 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -446,6 +446,7 @@ static const u32 emulated_msrs_all[] =3D { MSR_IA32_VMX_PROCBASED_CTLS2, MSR_IA32_VMX_EPT_VPID_CAP, MSR_IA32_VMX_VMFUNC, + MSR_IA32_VMX_PROCBASED_CTLS3, =20 MSR_K7_HWCR, MSR_KVM_POLL_CONTROL, --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 622163E8C5C; Tue, 3 Feb 2026 18:17:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142670; cv=none; b=fK3aIDAXgqlIM5CysKO7gvD97RapcO55WwopvvDjMy29pWvFriW+rP9LtLJNtGieqtEbBoA2KrsKkSzlhghNnnWhb6mnq2sZsVDpYg2gtOmi7KecF2od7mSAfKJ6JesuqYySG5e9zvpStu5vC2W7klYN3djeoBhplZzZVMT7poI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142670; c=relaxed/simple; bh=5Jz0V9XuxzAVJr8QmZ5HTOdNpc3K/kmgi9wZva0kZe4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XxFwgAQbyH+UtnCGBjHCvQjn7tPyzGm0yB3YEiwJcazgo1si31Dl3lQdO6ie9EnSRuz9FnLJM6lvf0a2mzsTcpw31Ry/lErQfanNa5nY5mhEqvkWfRnp4K4Bpn1y0nTfngVNVOo9+Ru0LTnnye0nH9pvpFRJ91xd389Io0nZtgk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=mQYTp+56; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="mQYTp+56" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142669; x=1801678669; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=5Jz0V9XuxzAVJr8QmZ5HTOdNpc3K/kmgi9wZva0kZe4=; b=mQYTp+56MDzz3W4orT6dRf/7mtcUdWu7LyIpFdF1GOY7TornIdWT6rAy zPQfsWbUMHJjGYi6RyTT8M5IKw3hiJIZrw4eGE8HlR9AfkrO3ipVWBLAP i+4JBLh+45hjX5v1neg9KMkwt7P5IarCT9YXjuDuFJsMfcDcOJ3aUWkf1 P6HBNykAlgqN+Z0nDfOJiBlVcM16v33PU9Pj1OyikU1jQI1eBND4CT3r8 QItWg7OtOA95dS6DFOcC0zqsto7/vC3mrNI0KLTRqh1oXy8E+2KWodOym W+pdI/+Yz1630uXBgvL31jZ6DrVQPB2qImVEFWhh56ysdTcLDrHg/GGVJ g==; X-CSE-ConnectionGUID: 5oLu+ue+TUadAhwWMZhlvg== X-CSE-MsgGUID: nk6vnGdmQhmkhT1lFfxrDA== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745839" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745839" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:45 -0800 X-CSE-ConnectionGUID: EVGNVp7lRHSpUqhg0kbH8g== X-CSE-MsgGUID: FcFELbLaQ0eWLljrTbjUzg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605513" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:44 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, Yang Zhong Subject: [PATCH 20/32] KVM: VMX: dump_vmcs() support the guest virt timer Date: Tue, 3 Feb 2026 10:17:03 -0800 Message-ID: <2ae528c16a244e8c138835217c2a190e350dcde8.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yang Zhong Add three VMCS fields from the guest virt timer into dump_vmcs(). Signed-off-by: Yang Zhong Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/vmx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 50d4390d41f0..5496f4230424 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6522,6 +6522,12 @@ void dump_vmcs(struct kvm_vcpu *vcpu) vmx_dump_msrs("guest autoload", &vmx->msr_autoload.guest); if (vmcs_read32(VM_EXIT_MSR_STORE_COUNT) > 0) vmx_dump_msrs("guest autostore", &vmx->msr_autostore.guest); + if (tertiary_exec_control & TERTIARY_EXEC_GUEST_APIC_TIMER) { + pr_err("DeadlinePhy =3D 0x%016llx\n", vmcs_read64(GUEST_DEADLINE_PHY)); + pr_err("DeadlineVir =3D 0x%016llx\n", vmcs_read64(GUEST_DEADLINE_VIR)); + pr_err("GuestApicTimerVector =3D 0x%04x\n", + vmcs_read16(GUEST_APIC_TIMER_VECTOR)); + } =20 if (vmentry_ctl & VM_ENTRY_LOAD_CET_STATE) pr_err("S_CET =3D 0x%016lx, SSP =3D 0x%016lx, SSP TABLE =3D 0x%016lx\n", --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8C77B36A00D; Tue, 3 Feb 2026 18:17:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142670; cv=none; b=bwhMrAZtQmpZXstzZAh4bRo8tawDwAbDXXqYWi2cEBnefEDFNzCIjFKtEZPpJdZ1Jol9t1c53R2oqkMPN0Kv5M02h1kkp79Y9yAHpf1T2fWHc9QhnxITQE5EuE/fDeZG18WGrORE+sBnTF8cF+X/xBo6nTCRV4oFN2DTKRAb6WA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142670; c=relaxed/simple; bh=CMv7tamvHKs001xtNyhXn3dY0Dc+tq4bZp/NdM6KFdQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VzugmGvsTBj2DsKvbOjd2EqV0u7aYAaXikGGKAzDJNTGkVSh3K2B/TjL+RW4Y6kGHYnuVooHOJ9gWPRx316ndZRDtDgKfTQJG9YbTpxR1fCJn4DMGmsL9QGqoOumf3rR7p5GiU15TNyphi38mnMU0mYDAdNR9eRlLU3ydMSc9ao= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=bIuy1MvK; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="bIuy1MvK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142669; x=1801678669; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CMv7tamvHKs001xtNyhXn3dY0Dc+tq4bZp/NdM6KFdQ=; b=bIuy1MvKDgLhvMpX0XKDl4Ww2xKUaIcLAzxHvGRFohk/omFlgx96DH3m /lOY6SLFegJm19tWAWvPP3EBc8RPXaifNXoB8Ys1KeqCaoBNscuVusx7o c9c+Gn3SyQiF9S4wjKZYH6ntFrXe3Ic433PtOssvsnWzJ/nP4ziBdhNl+ 6huP916VBokmYq1eleuJ4eBxdALxzeoMfIUdAcaruu1DE37qvvOOWpP7O DKihLIUQKIezQ61RSWLS7+SYV/j4kjtCMJudw9Go94macp+h3M1EgMovK S8VciDjYjhU1mmLtHHjncUNBGiwb+7ndkElPZgZqeqYMwgND8wGV65ONy w==; X-CSE-ConnectionGUID: syeyx4WTQySx/hkQpY8Dgw== X-CSE-MsgGUID: Lx/SNogMQomu4npPaza80g== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745842" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745842" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:45 -0800 X-CSE-ConnectionGUID: 4gT/6bgkT56cf/dUK+m0gw== X-CSE-MsgGUID: Zb0qc95XQ3CdKHh5EiMPeA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605516" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:44 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 21/32] KVM: VMX: Enable APIC timer virtualization Date: Tue, 3 Feb 2026 10:17:04 -0800 Message-ID: <0107fa9de9ad238a7b1c8d8207e93f8d2e61615d.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Add TERTIARY_EXEC_GUEST_APIC_TIMER bit to KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL as optional feature as the supporting logic is implemented. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/vmx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index bdeef2e12640..b296950d855e 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -588,9 +588,9 @@ static inline u8 vmx_get_rvi(void) SECONDARY_EXEC_EPT_VIOLATION_VE) =20 #define KVM_REQUIRED_VMX_TERTIARY_VM_EXEC_CONTROL 0 -/* Once apic timer virtualization supported, add TERTIARY_EXEC_GUEST_APIC_= TIMER */ #define KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL \ - (TERTIARY_EXEC_IPI_VIRT) + (TERTIARY_EXEC_IPI_VIRT | \ + TERTIARY_EXEC_GUEST_APIC_TIMER) =20 #define BUILD_CONTROLS_SHADOW(lname, uname, bits) \ static inline void lname##_controls_set(struct vcpu_vmx *vmx, u##bits val)= \ --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7C4883E95A4; Tue, 3 Feb 2026 18:17:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142670; cv=none; b=iUSeLq5wh4GLSJwIhX8TinnBWTZ+DJDB8SiboL4BahtgVfBdLsbll6eTR1vr5wDHZ1qMacnGEQ/8Mr+vCTZGcW+ammuIafyrz+cDBydqRiIhEuylcl4U8Qu6yejU9+tfsRksIu8eSXouNczURvBqkB/d8ZoNXTQmS5fAhMWwMHY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142670; c=relaxed/simple; bh=GagopKe8p6DQVgcXl32pCqybRoXB7F0rArot8lPxFz4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F8ALv0QPbKNs0zROMtWdZFQ5EI9ed/WrzL33h6J2oatf45NixZNTFGXHgyEUfZnPrblKkb0zwviJ2XX5z3HIsmaiNEnVZBb1Gr+Nt8Eu0qklwsKFOrUVhMo14DgMH0Qmm8bNLvmUC5ksBNG93QB9o4fSBmkinDUjvA6gvCClVAQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=FEiw8wzS; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="FEiw8wzS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142670; x=1801678670; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=GagopKe8p6DQVgcXl32pCqybRoXB7F0rArot8lPxFz4=; b=FEiw8wzSkLv0V1pJon/Dt5rvDNj8iZm9OYcwaFF85AtbRBe6yQYKMjgh HTUHskdAacTub3emFptHouV2lyOwyRaO2JI0umnA/+4ML+n6424m0TXcn TCgJSRZKoKOcaCVSLsbQv/80QYKj2YhwO2XPIOMOHUcwHc+bRhiuToSdj BIAkF9DL3oGu+MMVeMlCO6DWPfk/JsN4RTdwYtDbxsk6m3rMfwIGUGF81 lxzoNk75BLrkr3t3Aq8B/zO5QXUQF8YqVlDz4Jwwm+uxfaos9vZHC4rwD WRR7HQwiTAlD7ADbAAnxk8KaAQ4jAIk4SWyJlbXRtGjZOaiMgXzMf8QAz g==; X-CSE-ConnectionGUID: YJ8s4vh1TIyv+3D0dE6w1w== X-CSE-MsgGUID: X+fLN5jsTIK1mjdk6um7Ag== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745847" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745847" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:46 -0800 X-CSE-ConnectionGUID: edytMeF7SVmamA8GNScu6Q== X-CSE-MsgGUID: U2dz4GLdTjO6xLeTDDe8zA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605519" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:45 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org, Yang Zhong Subject: [PATCH 22/32] KVM: VMX: Introduce module parameter for APIC virt timer support Date: Tue, 3 Feb 2026 10:17:05 -0800 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Yang Zhong Introduce a new module parameter, apic_timer_virt, to control the virtualization of the APIC timer in KVM. The primary improvement offered by APIC timer virtualization over the preemption timer is the passthrough of MSR_IA32_TSC_DEADLINE to the VM. This passthrough capability reduces the number of VM exits triggered by MSR write operations, thereby enhancing the performance of the virtual machine. The apic_timer_virt parameter is set to true by default on processor platforms that support APIC timer virtualization. On platforms that do not support this feature, the parameter will indicate that APIC timer virtualization is not available. Signed-off-by: Yang Zhong Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/vmx.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 5496f4230424..76725f8dd228 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -118,6 +118,9 @@ module_param(enable_ipiv, bool, 0444); =20 module_param(enable_device_posted_irqs, bool, 0444); =20 +static bool __read_mostly enable_apic_timer_virt =3D true; +module_param_named(apic_timer_virt, enable_apic_timer_virt, bool, 0444); + /* * If nested=3D1, nested virtualization is supported, i.e., guests may use * VMX and be a hypervisor for its own guests. If nested=3D0, guests may n= ot @@ -2799,7 +2802,7 @@ static int setup_vmcs_config(struct vmcs_config *vmcs= _conf, adjust_vmx_controls64(KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL, MSR_IA32_VMX_PROCBASED_CTLS3); =20 - if (!IS_ENABLED(CONFIG_X86_64) || + if (!IS_ENABLED(CONFIG_X86_64) || !enable_apic_timer_virt || !(_cpu_based_2nd_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)) _cpu_based_3rd_exec_control &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; =20 @@ -8748,6 +8751,9 @@ __init int vmx_hardware_setup(void) if (!cpu_has_vmx_preemption_timer()) enable_preemption_timer =3D false; =20 + if (!cpu_has_vmx_apic_timer_virt()) + enable_apic_timer_virt =3D false; + if (enable_preemption_timer) { u64 use_timer_freq =3D 5000ULL * 1000 * 1000; =20 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1A1073E9F65; Tue, 3 Feb 2026 18:17:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142672; cv=none; b=GnQGwU1xivm+2J5jCdlS8TtczoJKi47yvGdgZZ8pDhlp05hwRIeK+PDvUmX1LsTLBDVSrreQgt/YXUj8a3NOYiF8grNWxiIpjCLuynvvX0PNbaI7B1DhnkXOBZk79eBRU5PY9mKhALrfg2IN9zu+JtDVa7V15HIr2272OPsIK8w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142672; c=relaxed/simple; bh=JRZl22MrKBXrmWeEoctb6XWd0blFgFAn0h4yl+0mCos=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TjAAUaaMUlFIQXnOXi/owefz4xkVY8oOChxKjYPVO5KLY3sBmGlkiYdPzXCKZLfQZcnebU62pXl7uIc2iKqZq50dCpVUjmw4Khl6skxZJWGG2dY/dQcjPFlmNzqfezqUfnA8PCGeMWaTr4Q3ZIdiO6tQrNfXU4NJTqxmqM0Pdg0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=nE4cmgeC; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="nE4cmgeC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142670; x=1801678670; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=JRZl22MrKBXrmWeEoctb6XWd0blFgFAn0h4yl+0mCos=; b=nE4cmgeCMTHidTWemDVK3WsqmNSpXRUROprEsPU59DLvkKkCEX6W6RlG VAszC9mogLiHjBb1dOLqflvZG4j153DejjMXNcnxj06lVKsTaaENcmU2o fQkhGpJlTxldqSyQJsqS3WMwJt62Bv9E9+gaD8JsmhsYW+ED/z3NlIMrH +/Ftl0CJm2flkfHWoUEWhwrleITF1u5Ze4CdkU7m/T8spkDVdJnGIAr3j A5Cc6pfvXULxvsUxzZplc8ZDBvgC8Js4Ber2JcQJNu+I+7TEzl3ONAdZK xaIFS1Yzmye0zFGHjwjr1ODhBTb+nD5trHazlHxZpWRN8/5h9HRhyH1d5 g==; X-CSE-ConnectionGUID: nDN4rU6wToGysktyUG1Psg== X-CSE-MsgGUID: joht6PABS1mmOhNCs5/SqQ== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745850" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745850" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:46 -0800 X-CSE-ConnectionGUID: d8TgeHvSQMqYv8fs6+dphw== X-CSE-MsgGUID: PH0EyS4yT++7ioUQZhPpEA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605523" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:45 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 23/32] KVM: nVMX: Introduce module parameter for nested APIC timer virtualization Date: Tue, 3 Feb 2026 10:17:06 -0800 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Introduce a new module parameter, nested_apic_timer_virt, to control the nested virtualization of the APIC timer in KVM. The nested_apic_timer_virt parameter is set to true by default on processor platforms that support APIC timer virtualization. On platforms that do not support this feature, the parameter will indicate that APIC timer virtualization is not available. Signed-off-by: Isaku Yamahata --- arch/x86/kvm/vmx/capabilities.h | 1 + arch/x86/kvm/vmx/nested.c | 13 ++++++++++++- arch/x86/kvm/vmx/vmx.c | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilitie= s.h index f73a50c887ac..8d8beae4839a 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -15,6 +15,7 @@ extern bool __read_mostly enable_ept; extern bool __read_mostly enable_unrestricted_guest; extern bool __read_mostly enable_ept_ad_bits; extern bool __read_mostly enable_pml; +extern bool __read_mostly enable_apic_timer_virt; extern int __read_mostly pt_mode; =20 #define PT_MODE_SYSTEM 0 diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index a940f1d9ee83..fd2c3b11aabe 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -27,6 +27,10 @@ module_param_named(enable_shadow_vmcs, enable_shadow_vmc= s, bool, S_IRUGO); static bool __ro_after_init warn_on_missed_cc; module_param(warn_on_missed_cc, bool, 0444); =20 +static bool __read_mostly enable_nested_apic_timer_virt =3D true; +module_param_named(nested_apic_timer_virt, enable_nested_apic_timer_virt, = bool, + S_IRUGO); + #define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK =20 /* @@ -7485,13 +7489,20 @@ static void nested_vmx_setup_secondary_ctls(u32 ept= _caps, static void nested_vmx_setup_tertiary_ctls(struct vmcs_config *vmcs_conf, struct nested_vmx_msrs *msrs) { - msrs->tertiary_ctls =3D vmcs_conf->cpu_based_3rd_exec_ctrl; + enable_nested_apic_timer_virt &=3D enable_apic_timer_virt; =20 + msrs->tertiary_ctls =3D vmcs_conf->cpu_based_3rd_exec_ctrl; msrs->tertiary_ctls &=3D TERTIARY_EXEC_GUEST_APIC_TIMER; =20 + if (!enable_nested_apic_timer_virt) + msrs->tertiary_ctls &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; + if (msrs->tertiary_ctls) msrs->procbased_ctls_high |=3D CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + + if (!(msrs->tertiary_ctls & TERTIARY_EXEC_GUEST_APIC_TIMER)) + enable_nested_apic_timer_virt =3D false; } =20 static void nested_vmx_setup_misc_data(struct vmcs_config *vmcs_conf, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 76725f8dd228..bc4611629879 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -118,7 +118,7 @@ module_param(enable_ipiv, bool, 0444); =20 module_param(enable_device_posted_irqs, bool, 0444); =20 -static bool __read_mostly enable_apic_timer_virt =3D true; +bool __read_mostly enable_apic_timer_virt =3D true; module_param_named(apic_timer_virt, enable_apic_timer_virt, bool, 0444); =20 /* --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 492173E9F73; Tue, 3 Feb 2026 18:17:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142672; cv=none; b=NqGggX17t5/Ukpngtgmpyezuc1tPua+ys1QQ0tnfCngtwSKgBk5yZfimjWyCqGt1yn0c2rHwmgnF2IgfCYyb+sClPtjshrtrUQZMroXI27rx9tcRroyC+HZR5+tPe3aa6d1Hk8L4NXWnAv6Y5bI/QxE98qplZVQP1M9GnMeW/Gw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142672; c=relaxed/simple; bh=we2sIhVXtUPvYa/AJ3J/k7gvy9fThDWbSAlpUUdRmQU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Oh1gEm4L546k7posyQ2ugMjdXUJ42jUu2z9d6BzQIHVBfKGR5JVk6+898v5eGgEtr9Jx+lx5kidZc5PWugFo8wWu3DvKenB68sx2B/CZqIk3balMWD41fsvvvT7U20tUhWKvGc/0cvLK4IfVAq3kEsMyil/As2OPOcCYVwldU0s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=A0n0Rmrt; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="A0n0Rmrt" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142671; x=1801678671; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=we2sIhVXtUPvYa/AJ3J/k7gvy9fThDWbSAlpUUdRmQU=; b=A0n0RmrtYYMvDa79VjkJ9W2K1GS7pSKA5L7F5wADoc95OKXrygqjWv0O wElFe36jWAZ7uDyjqFux5lScy1FqXTj+oDDD7IFwfq6WsqRvuwvWfzexQ +UoTOt28IJBHyihybmzFRqzWT2C8N9v2Ne6deMvI6GXodHjIg7NUKaaD6 fPyaNZJ/QaTNkwxbP7EDZ4bDfoEf26ioa9MM7xZ2HLvs8pDUvyAELpHjI aF6Oqh49mIy4OWGuN3zel+Y3VoNpy2qXO0jNQ4ul1GgRoN1zW5e+eP9Ke T9Il+9ciZE8Bwi0mqenPr7isTlu/aecPDMnC+6lWofnDXFILpP7CsiyWa g==; X-CSE-ConnectionGUID: TspSFukVQCmEK43RGW/CcA== X-CSE-MsgGUID: ocALFzGHQOm5riRco0qvLg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745854" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745854" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:46 -0800 X-CSE-ConnectionGUID: vJG9b3OWQS+m3Zm8ZdATFg== X-CSE-MsgGUID: Z80vKbtXR52HG+27ZVLhGg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605526" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:46 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 24/32] KVM: selftests: Add a test to measure local timer latency Date: Tue, 3 Feb 2026 10:17:07 -0800 Message-ID: <7e6fa29d20d36e1191c5c64d612ec43f5375adac.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata A test case to measure local timer latency and to confirm that VMExit doesn't happen on TSC DEADLINE MSR on the platform that supports VMX APIC timer virtualization. Or VMExit happens on the platform without the feature. This is inspired by kvm-unit-test x86/tscdeadline_latency.c. The original test records all latency, but this records only the max/min/avg of the latency for simplicity. It sets the local APIC timer (APIC oneshot or TSC deadline) and the timer interrupt handler records the delay from the timer value. Signed-off-by: Isaku Yamahata --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../testing/selftests/kvm/x86/timer_latency.c | 574 ++++++++++++++++++ 2 files changed, 575 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/timer_latency.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index ba5c2b643efa..695d19c73199 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -139,6 +139,7 @@ TEST_GEN_PROGS_x86 +=3D x86/max_vcpuid_cap_test TEST_GEN_PROGS_x86 +=3D x86/triple_fault_event_test TEST_GEN_PROGS_x86 +=3D x86/recalc_apic_map_test TEST_GEN_PROGS_x86 +=3D x86/aperfmperf_test +TEST_GEN_PROGS_x86 +=3D x86/timer_latency TEST_GEN_PROGS_x86 +=3D access_tracking_perf_test TEST_GEN_PROGS_x86 +=3D coalesced_io_test TEST_GEN_PROGS_x86 +=3D dirty_log_perf_test diff --git a/tools/testing/selftests/kvm/x86/timer_latency.c b/tools/testin= g/selftests/kvm/x86/timer_latency.c new file mode 100644 index 000000000000..a87a744330c8 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/timer_latency.c @@ -0,0 +1,574 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025, Intel Corporation. + * + * Measure timer interrupt latency between time set to the local timer and + * interrupt arrival time. Optionally print out max/min/avg of the latenc= y. + */ + +#include +#include +#include +#include +#include + +#include "kvm_util.h" +#include "processor.h" +#include "apic.h" + +#define LOCAL_TIMER_VECTOR 0xec + +#define TEST_DURATION_DEFAULT_IN_SEC 10 + +/* Random number in ns, appropriate for timer interrupt */ +#define DEFAULT_TIMER_INC_NS 10000 + +/* Twice 100Hz scheduler tick for nested virtualization. */ +#define DEFAULT_ALLOWED_TIMER_LATENCY_NS (20 * 1000 * 1000) + +struct options { + bool use_oneshot_timer; + bool use_x2apic; + bool use_poll; + + uint64_t timer_inc_ns; + uint64_t allowed_timer_latency_ns; + + bool print_result; +}; + +static struct options options =3D { + .use_x2apic =3D true, + .timer_inc_ns =3D DEFAULT_TIMER_INC_NS, + .allowed_timer_latency_ns =3D DEFAULT_ALLOWED_TIMER_LATENCY_NS, +}; + +enum event_type { + EVENT_TIMER_HANDLER, + EVENT_HLT_WAKEUP, + EVENT_MAX, +}; + +struct test_sample { + uint64_t time_stamp; + enum event_type etype; + uint32_t latency; +}; + +struct test_latency_stat { + uint64_t sum; + uint64_t count; + uint32_t min; + uint32_t max; +}; + +struct test_shared_data { + atomic_bool stop_test; + atomic_bool terminated; + uint64_t tsc_khz; + uint64_t apic_bus_cycle_ns; + uint64_t allowed_timer_latency_tsc; + + uint64_t timer_inc; + + uint64_t hlt_count; + uint64_t timer_interrupt_set; + uint64_t timer_interrupt_received; + + struct test_latency_stat latency_stat[EVENT_MAX]; +}; + +#define GUEST_ASSERT_LATENCY(latency_tsc) \ + __GUEST_ASSERT((latency_tsc) <=3D data->allowed_timer_latency_tsc, \ + "too large timer latency %ld ns " \ + "(requires %ld ns) %ld khz tsc", \ + tsc_to_ns(data, latency_tsc), \ + options.allowed_timer_latency_ns, \ + data->tsc_khz) + +static struct test_shared_data shared_data; + +static u64 tsc_to_ns(struct test_shared_data *data, u64 tsc_delta) +{ + return tsc_delta * NSEC_PER_SEC / (data->tsc_khz * 1000); +} + +static u64 ns_to_tsc(struct test_shared_data *data, u64 ns) +{ + return ns * (data->tsc_khz * 1000) / NSEC_PER_SEC; +} + +static void latency_init(struct test_latency_stat *stat) +{ + stat->sum =3D 0; + stat->count =3D 0; + stat->min =3D -1; + stat->max =3D 0; +} + +static void shared_data_init(struct test_shared_data *data) +{ + int i; + + memset(data, 0, sizeof(*data)); + + for (i =3D 0; i < ARRAY_SIZE(data->latency_stat); i++) + latency_init(data->latency_stat + i); +} + +static void stop_test(struct kvm_vm *vm, struct test_shared_data *data) +{ + atomic_store(&data->stop_test, true); + sync_global_to_guest(vm, data->stop_test); +} + +static void guest_apic_enable(void) +{ + if (options.use_x2apic) + x2apic_enable(); + else + xapic_enable(); +} + +static void guest_apic_write_reg(unsigned int reg, uint64_t val) +{ + if (options.use_x2apic) + x2apic_write_reg(reg, val); + else + xapic_write_reg(reg, val); +} + +static void record_sample(struct test_shared_data *data, enum event_type e= type, + uint64_t ts, uint64_t latency) +{ + struct test_latency_stat *stat; + + stat =3D &data->latency_stat[etype]; + + stat->count++; + stat->sum +=3D latency; + + if (stat->min > latency) + stat->min =3D latency; + if (stat->max < latency) + stat->max =3D latency; + + if (etype =3D=3D EVENT_TIMER_HANDLER && + latency > data->allowed_timer_latency_tsc) { + if (options.use_poll) { + GUEST_PRINTF("latency is too high %ld ns (> %ld ns)\n", + tsc_to_ns(data, latency), + options.allowed_timer_latency_ns); + } else + GUEST_ASSERT_LATENCY(latency); + } +} + +static atomic_bool timer_interrupted; +static atomic_uint_fast64_t timer_tsc; + +static inline bool tsc_before(u64 a, u64 b) +{ + return (s64)(a - b) < 0; +} + +static void guest_timer_interrupt_handler(struct ex_regs *regs) +{ + uint64_t now =3D rdtsc(); + uint64_t timer_tsc__ =3D atomic_load(&timer_tsc); + + __GUEST_ASSERT(!atomic_load(&timer_interrupted), + "timer handler is called multiple times per timer"); + __GUEST_ASSERT(tsc_before(timer_tsc__, now), + "timer is fired before armed time timer_tsc 0x%lx now 0x%lx", + timer_tsc__, now); + + record_sample(&shared_data, EVENT_TIMER_HANDLER, now, now - timer_tsc__); + + shared_data.timer_interrupt_received++; + atomic_store(&timer_interrupted, true); + guest_apic_write_reg(APIC_EOI, 0); +} + +static void __set_timer(struct test_shared_data *data, + uint64_t next_tsc, uint64_t apic_inc) +{ + if (options.use_oneshot_timer) + guest_apic_write_reg(APIC_TMICT, apic_inc); + else + wrmsr(MSR_IA32_TSC_DEADLINE, next_tsc); +} + +static void set_timer(struct test_shared_data *data, + uint64_t next_tsc, uint64_t apic_inc) +{ + atomic_store(&timer_tsc, next_tsc); + data->timer_interrupt_set++; + __set_timer(data, next_tsc, apic_inc); +} + +static u64 to_apic_bus_cycle(struct test_shared_data *data, u64 tsc_delta) +{ + u64 ret; + + if (!tsc_delta) + return 0; + + ret =3D tsc_to_ns(data, tsc_delta) / data->apic_bus_cycle_ns; + if (!ret) + ret++; + + return ret; +} + +static void hlt_loop(struct test_shared_data *data) +{ + uint64_t inc, now, prev_tsc, next_tsc; + + asm volatile("cli"); + guest_apic_enable(); + + inc =3D data->timer_inc; + + /* DIVISOR =3D 1 for oneshot timer case */ + guest_apic_write_reg(APIC_TDCR, 0xb); + guest_apic_write_reg(APIC_LVTT, + (options.use_oneshot_timer ? + APIC_LVT_TIMER_ONESHOT : + APIC_LVT_TIMER_TSCDEADLINE) | + LOCAL_TIMER_VECTOR); + + next_tsc =3D rdtsc() + inc; + if (!next_tsc) + next_tsc++; + atomic_store(&timer_interrupted, false); + set_timer(data, next_tsc, to_apic_bus_cycle(data, inc)); + + while (!atomic_load(&data->stop_test)) { + prev_tsc =3D rdtsc(); + + if (options.use_poll) { + asm volatile("sti"); + while (!atomic_load(&timer_interrupted) && + rdtsc() < next_tsc + data->allowed_timer_latency_tsc) + cpu_relax(); + asm volatile("cli"); + } else + asm volatile("sti; hlt; cli"); + + now =3D rdtsc(); + + record_sample(data, EVENT_HLT_WAKEUP, now, now - prev_tsc); + data->hlt_count++; + + if (atomic_load(&timer_interrupted)) { + while (next_tsc <=3D now) + next_tsc +=3D inc; + if (!next_tsc) + next_tsc++; + + atomic_store(&timer_interrupted, false); + set_timer(data, next_tsc, + to_apic_bus_cycle(data, next_tsc - now)); + } else { + uint64_t latency =3D now - next_tsc; + + GUEST_ASSERT_LATENCY(latency); + } + } + + /* Wait for the interrupt to arrive. */ + now =3D rdtsc(); + next_tsc =3D now + inc * 2; + asm volatile ("sti"); + while (now < next_tsc || !atomic_load(&timer_interrupted)) { + cpu_relax(); + now =3D rdtsc(); + } + asm volatile ("cli"); + + /* Stop timer explicitly just in case. */ + __set_timer(data, 0, 0); +} + +static void guest_code(void) +{ + struct test_shared_data *data =3D &shared_data; + + hlt_loop(data); + + __GUEST_ASSERT(data->timer_interrupt_set =3D=3D data->timer_interrupt_rec= eived, + "timer interrupt lost set %ld received %ld", + data->timer_interrupt_set, data->timer_interrupt_received); + + GUEST_DONE(); +} + +static void __run_vcpu(struct kvm_vcpu *vcpu) +{ + struct ucall uc; + + for (;;) { + vcpu_run(vcpu); + + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_DONE: + pr_info("vcpu id %d passed\n", vcpu->id); + return; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + return; + case UCALL_PRINTF: + pr_info("%s", uc.buffer); + continue; + default: + TEST_FAIL("Unexpected ucall cmd: %ld", uc.cmd); + return; + } + + return; + } +} + +static void *run_vcpu(void *args) +{ + struct kvm_vcpu *vcpu =3D args; + + __run_vcpu(vcpu); + + return NULL; +} + +static void print_result_type(struct test_shared_data *data, + enum event_type etype, const char *event_name) +{ + struct test_latency_stat *stat =3D &data->latency_stat[etype]; + uint64_t avg =3D 0; + + if (stat->count) + avg =3D stat->sum / stat->count; + + pr_info("%s latency (%ld samples)\tmin %ld avg %ld max %ld ns\n", + event_name, stat->count, + tsc_to_ns(data, stat->min), tsc_to_ns(data, avg), + tsc_to_ns(data, stat->max)); +} + +static void print_result(struct test_shared_data *data) +{ + pr_info("guest timer: %s timer period %ld ns\n", + options.use_oneshot_timer ? + "APIC oneshot timer" : "tsc deadline", + options.timer_inc_ns); + + pr_info("tsc_khz %ld apic_bus_cycle_ns %ld\n", + data->tsc_khz, data->apic_bus_cycle_ns); + + pr_info("hlt %ld timer set %ld received %ld\n", + data->hlt_count, + data->timer_interrupt_set, data->timer_interrupt_received); + + print_result_type(data, EVENT_TIMER_HANDLER, "timer interrupt"); + print_result_type(data, EVENT_HLT_WAKEUP, "halt wakeup"); +} + +static void print_exit_stats(struct kvm_vcpu *vcpu) +{ + char* stat_name[] =3D { + "exits", + "halt_exits", + "irq_exits", + "inject_tscdeadline" + }; + uint64_t data; + int i; + + for (i =3D 0; i < ARRAY_SIZE(stat_name); i++) { + kvm_get_stat(&vcpu->stats, stat_name[i], &data, 1); + pr_info("%s: %ld ", stat_name[i], data); + } + pr_info("\n"); +} + +static void setup_timer_freq(struct kvm_vm *vm, + struct test_shared_data *data) +{ + data->tsc_khz =3D __vm_ioctl(vm, KVM_GET_TSC_KHZ, NULL); + TEST_ASSERT(data->tsc_khz > 0, "KVM_GET_TSC_KHZ failed.."); + + data->apic_bus_cycle_ns =3D kvm_check_cap(KVM_CAP_X86_APIC_BUS_CYCLES_NS); + if (options.use_oneshot_timer) + data->timer_inc =3D options.timer_inc_ns * data->apic_bus_cycle_ns; + else + data->timer_inc =3D ns_to_tsc(data, options.timer_inc_ns); + + data->allowed_timer_latency_tsc =3D + ns_to_tsc(data, options.allowed_timer_latency_ns); +} + +static void setup(struct kvm_vm **vm__, struct kvm_vcpu **vcpu__) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + vm_install_exception_handler(vm, LOCAL_TIMER_VECTOR, + guest_timer_interrupt_handler); + setup_timer_freq(vm, &shared_data); + + if (!options.use_oneshot_timer) + vcpu_set_cpuid_feature(vcpu, X86_FEATURE_TSC_DEADLINE_TIMER); + + sync_global_to_guest(vm, options); + sync_global_to_guest(vm, shared_data); + + *vm__ =3D vm; + *vcpu__ =3D vcpu; +} + +static void print_stats(struct kvm_vm *vm, struct kvm_vcpu *vcpu) +{ + if (options.print_result) { + sync_global_from_guest(vm, *&shared_data); + print_result(&shared_data); + print_exit_stats(vcpu); + } +} + +static void sigterm_handler(int signum, siginfo_t *info, void *arg_) +{ + atomic_store(&shared_data.terminated, true); +} + +static int run_test(unsigned int duration) +{ + struct kvm_vcpu *vcpu; + struct sigaction sa; + struct kvm_vm *vm; + pthread_t thread; + int r; + + shared_data_init(&shared_data); + + setup(&vm, &vcpu); + + sa =3D (struct sigaction) { + .sa_sigaction =3D sigterm_handler, + }; + sigemptyset(&sa.sa_mask); + r =3D sigaction(SIGTERM, &sa, NULL); + TEST_ASSERT(!r, "sigaction"); + + r =3D pthread_create(&thread, NULL, run_vcpu, vcpu); + TEST_ASSERT(!r, "pthread_create"); + + while (duration > 0 && !atomic_load(&shared_data.terminated)) { + duration =3D sleep(duration); + TEST_ASSERT(duration >=3D 0, "sleep"); + } + + if (atomic_load(&shared_data.terminated)) { + pr_info("terminated\n"); + print_stats(vm, vcpu); + return -EINTR; + } + + stop_test(vm, &shared_data); + + r =3D pthread_join(thread, NULL); + TEST_ASSERT(!r, "pthread_join"); + + print_stats(vm, vcpu); + + kvm_vm_free(vm); + return 0; +} + +static void help(const char *name) +{ + puts(""); + printf("usage: %s [-h] [-l] [-d duration_in_sec] [-a allowed_timer_latenc= y] [-p period_in_ns] [-o] [-O] [-x] [-X]\n", + name); + puts(""); + printf("-h: Display this help message."); + printf("-l: use idle loop instead of hlt\n"); + printf("-d: specify test to run in second (default %d sec)\n", + TEST_DURATION_DEFAULT_IN_SEC); + printf("-p: timer period in ns (default %d nsec)\n", + DEFAULT_TIMER_INC_NS); + printf("-a: allowed timer latency in ns (default %d nsec)\n", + DEFAULT_ALLOWED_TIMER_LATENCY_NS); + printf("-o: use APIC oneshot timer instead of TSC deadline timer\n"); + printf("-t: use TSC deadline timer instead of APIC oneshot timer (default= )\n"); + printf("-P: print result stat\n"); + printf("-x: use xAPIC mode\n"); + printf("-X: use x2APIC mode (default)\n"); + puts(""); + + exit(EXIT_SUCCESS); +} + +int main(int argc, char **argv) +{ + int opt; + unsigned int duration =3D TEST_DURATION_DEFAULT_IN_SEC; + + while ((opt =3D getopt(argc, argv, "hld:p:a:otxXP")) !=3D -1) { + switch (opt) { + case 'l': + options.use_poll =3D true; + break; + + case 'd': + duration =3D atoi_non_negative("test duration in sec", optarg); + break; + case 'p': + options.timer_inc_ns =3D + atoi_non_negative("timer period in nsec", optarg); + break; + case 'a': + options.allowed_timer_latency_ns =3D + atoi_non_negative("allowed timer latency in nsec", + optarg); + break; + + + case 'x': + options.use_x2apic =3D false; + break; + case 'X': + options.use_x2apic =3D true; + break; + + case 'o': + options.use_oneshot_timer =3D true; + break; + case 't': + options.use_oneshot_timer =3D false; + break; + + case 'P': + options.print_result =3D true; + break; + + case 'h': + default: + help(argv[0]); + break; + } + } + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_GET_TSC_KHZ)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_TSC_CONTROL)); + if (!options.use_oneshot_timer) + TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_DEADLINE_TIMER)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_APIC_BUS_CYCLES_NS)); + if (options.use_x2apic) + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_X2APIC)); + + run_test(duration); + + return 0; +} --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3892F3ECBD7; Tue, 3 Feb 2026 18:17:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142673; cv=none; b=PYPdhuirZqj8SYHU0chCZJ3pR4F5HN6r/ydQHWgcjba7r7kg6DVWlzB8xdUpRAW8x5s1Hw92FKV6u+Y/Z5JsU2TRpQc/l5zU8/jaSx697XFZdi9jjzC2uTqEjeftbva4xRgBgGDBYk+8oDsOQEsxsql2WtPdSFcYqUYe79ZCv7U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142673; c=relaxed/simple; bh=hDRCEcsCvNNOTbuhPMcR+uWFWLbjO9Z+jIj4RLnNVC8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=h2fwHkkwMUSLwbC1UnnMKdC3ySg0+l5heHyLE9RPFWd5qdjexQCjqMaxZg1j8sfSzavg6gptj4gpIi2DhPc3rLrYZRjZfyG97mh2tczwjgWvzmiO+AZXY6HANMuTi8rZAKms8BZ9S1/fbQbLDave/J/2S6jKSCLrNpe8wh1ojaQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=gG6GKDB0; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="gG6GKDB0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142672; x=1801678672; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=hDRCEcsCvNNOTbuhPMcR+uWFWLbjO9Z+jIj4RLnNVC8=; b=gG6GKDB0UP9FZhu/HL5yD5vRSHwgaNsYbM8MIbOED0hVkYYOZA7K+FiU rEbmD5ZRTSF2PgFWSH902FcJIgn5reTfyb+WmMVYoPcXm2zJhzFh2x9uX wnrHlQamj9wi2V9qRuv1BnHW4Y5nmJ77+ME1As3RzGIouuo5O0bJE5Wgw 0/YmKXuCBJVhM4pqKEFyVQeRZEJ1orpw92OYopDtlm0MFYinodWFci5rP lErArthF6vDVtUk+zrjWI3gh5b5cgVyCtBwO7S2LA9JAofY+vKFpus3RQ DsaC1CfRPiJIPz5nDZZRYCelh+/gFRmuKiLaoube3rcagHIy9wPRhf/I4 g==; X-CSE-ConnectionGUID: A0BQXIWGRDueiQmfaQDhiA== X-CSE-MsgGUID: 6Sw1t81QTmyKhT2LA6QEWw== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745858" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745858" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:47 -0800 X-CSE-ConnectionGUID: VxUYhekMSdCohXPUz3ur9g== X-CSE-MsgGUID: ARJin5auT3efKdbSxjPAig== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605530" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:46 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 25/32] KVM: selftests: Add nVMX support to timer_latency test case Date: Tue, 3 Feb 2026 10:17:08 -0800 Message-ID: <18f54797d5a705719a8fb8dfce74fc4cfb5d1e18.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Support nVMX for the timer_latency test case to exercise the nVMX APIC timer virtualization. Signed-off-by: Isaku Yamahata --- tools/testing/selftests/kvm/include/x86/vmx.h | 10 ++ .../testing/selftests/kvm/x86/timer_latency.c | 132 +++++++++++++++++- 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/= selftests/kvm/include/x86/vmx.h index 96e2b4c630a9..304892500089 100644 --- a/tools/testing/selftests/kvm/include/x86/vmx.h +++ b/tools/testing/selftests/kvm/include/x86/vmx.h @@ -24,6 +24,7 @@ #define CPU_BASED_RDTSC_EXITING 0x00001000 #define CPU_BASED_CR3_LOAD_EXITING 0x00008000 #define CPU_BASED_CR3_STORE_EXITING 0x00010000 +#define CPU_BASED_ACTIVATE_TERTIARY_CONTROLS 0x00020000 #define CPU_BASED_CR8_LOAD_EXITING 0x00080000 #define CPU_BASED_CR8_STORE_EXITING 0x00100000 #define CPU_BASED_TPR_SHADOW 0x00200000 @@ -63,6 +64,12 @@ #define SECONDARY_ENABLE_XSAV_RESTORE 0x00100000 #define SECONDARY_EXEC_TSC_SCALING 0x02000000 =20 +/* + * Definitions of Tertiary Processor-Based VM-Execution Controls. + * It's 64 bit unlike primary/secondary processor based vm-execution contr= ols. + */ +#define TERTIARY_EXEC_GUEST_APIC_TIMER 0x0000000000000100ULL + #define PIN_BASED_EXT_INTR_MASK 0x00000001 #define PIN_BASED_NMI_EXITING 0x00000008 #define PIN_BASED_VIRTUAL_NMIS 0x00000020 @@ -104,6 +111,7 @@ enum vmcs_field { VIRTUAL_PROCESSOR_ID =3D 0x00000000, POSTED_INTR_NV =3D 0x00000002, + GUEST_APIC_TIMER_VECTOR =3D 0x0000000a, GUEST_ES_SELECTOR =3D 0x00000800, GUEST_CS_SELECTOR =3D 0x00000802, GUEST_SS_SELECTOR =3D 0x00000804, @@ -163,6 +171,8 @@ enum vmcs_field { ENCLS_EXITING_BITMAP_HIGH =3D 0x0000202F, TSC_MULTIPLIER =3D 0x00002032, TSC_MULTIPLIER_HIGH =3D 0x00002033, + TERTIARY_VM_EXEC_CONTROL =3D 0x00002034, + TERTIARY_VM_EXEC_CONTROL_HIGH =3D 0x00002035, GUEST_PHYSICAL_ADDRESS =3D 0x00002400, GUEST_PHYSICAL_ADDRESS_HIGH =3D 0x00002401, VMCS_LINK_POINTER =3D 0x00002800, diff --git a/tools/testing/selftests/kvm/x86/timer_latency.c b/tools/testin= g/selftests/kvm/x86/timer_latency.c index a87a744330c8..9d96b7d18dd5 100644 --- a/tools/testing/selftests/kvm/x86/timer_latency.c +++ b/tools/testing/selftests/kvm/x86/timer_latency.c @@ -15,6 +15,10 @@ #include "kvm_util.h" #include "processor.h" #include "apic.h" +#include "vmx.h" + +#define L2_GUEST_STACK_SIZE 256 +static unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; =20 #define LOCAL_TIMER_VECTOR 0xec =20 @@ -30,6 +34,7 @@ struct options { bool use_oneshot_timer; bool use_x2apic; bool use_poll; + bool nested; =20 uint64_t timer_inc_ns; uint64_t allowed_timer_latency_ns; @@ -304,6 +309,65 @@ static void guest_code(void) GUEST_DONE(); } =20 +static void l1_guest_code(struct vmx_pages *vmx_pages) +{ + union vmx_ctrl_msr ctls_msr, ctls2_msr; + uint64_t pin, ctls, ctls2, ctls3; + + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_vmcs(vmx_pages, guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + /* Check prerequisites */ + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS, &ctls_msr.val)); + GUEST_ASSERT(ctls_msr.clr & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS); + GUEST_ASSERT(ctls_msr.clr & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS); + + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS2, &ctls2_msr.val)); + GUEST_ASSERT(ctls2_msr.clr & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); + + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS3, &ctls3)); + GUEST_ASSERT(ctls3 & TERTIARY_EXEC_GUEST_APIC_TIMER); + + /* + * SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY requires + * PIN_BASED_EXT_INTR_MASK + */ + pin =3D vmreadz(PIN_BASED_VM_EXEC_CONTROL); + pin |=3D PIN_BASED_EXT_INTR_MASK; + GUEST_ASSERT(!vmwrite(PIN_BASED_VM_EXEC_CONTROL, pin)); + + ctls =3D vmreadz(CPU_BASED_VM_EXEC_CONTROL); + ctls |=3D CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_TPR_SHADOW | + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS | + CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + GUEST_ASSERT(!vmwrite(CPU_BASED_VM_EXEC_CONTROL, ctls)); + + /* guest apic timer requires virtual interrutp delivery */ + ctls2 =3D vmreadz(SECONDARY_VM_EXEC_CONTROL); + ctls2 |=3D SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; + vmwrite(SECONDARY_VM_EXEC_CONTROL, ctls2); + + ctls3 =3D vmreadz(TERTIARY_VM_EXEC_CONTROL); + ctls3 |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + GUEST_ASSERT(!vmwrite(TERTIARY_VM_EXEC_CONTROL, ctls3)); + + /* + * We don't emulate apic registers(including APIC_LVTT) for simplicity. + * Directly set vector for timer interrupt instead. + */ + GUEST_ASSERT(!vmwrite(GUEST_APIC_TIMER_VECTOR, LOCAL_TIMER_VECTOR)); + + /* launch L2 */ + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) =3D=3D EXIT_REASON_VMCALL); + + GUEST_DONE(); +} + static void __run_vcpu(struct kvm_vcpu *vcpu) { struct ucall uc; @@ -408,12 +472,40 @@ static void setup_timer_freq(struct kvm_vm *vm, ns_to_tsc(data, options.allowed_timer_latency_ns); } =20 +static void clear_msr_bitmap(struct vmx_pages *vmx, int msr) +{ + clear_bit(msr, vmx->msr_hva); + clear_bit(msr, vmx->msr_hva + 2048); +} + static void setup(struct kvm_vm **vm__, struct kvm_vcpu **vcpu__) { struct kvm_vcpu *vcpu; struct kvm_vm *vm; =20 - vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + if (options.nested) { + vm_vaddr_t vmx_pages_gva =3D 0; + struct vmx_pages *vmx; + + vm =3D vm_create_with_one_vcpu(&vcpu, l1_guest_code); + + vmx =3D vcpu_alloc_vmx(vm, &vmx_pages_gva); + memset(vmx->msr_hva, 0xff, 4096); + + /* Allow nested apic timer virtualization. */ + clear_msr_bitmap(vmx, MSR_IA32_TSC_DEADLINE); + + /* Rely on x2apic virtualization. */ + clear_msr_bitmap(vmx, MSR_IA32_APICBASE); + clear_msr_bitmap(vmx, APIC_BASE_MSR + (APIC_TDCR >> 4)); + clear_msr_bitmap(vmx, APIC_BASE_MSR + (APIC_LVTT >> 4)); + clear_msr_bitmap(vmx, APIC_BASE_MSR + (APIC_SPIV >> 4)); + clear_msr_bitmap(vmx, APIC_BASE_MSR + (APIC_EOI >> 4)); + + vcpu_args_set(vcpu, 1, vmx_pages_gva); + } else + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + vm_install_exception_handler(vm, LOCAL_TIMER_VECTOR, guest_timer_interrupt_handler); setup_timer_freq(vm, &shared_data); @@ -505,6 +597,8 @@ static void help(const char *name) printf("-P: print result stat\n"); printf("-x: use xAPIC mode\n"); printf("-X: use x2APIC mode (default)\n"); + printf("-n: Only measure nested VM (L2)\n"); + printf("-N: Don't measure nested VM (L2)\n"); puts(""); =20 exit(EXIT_SUCCESS); @@ -514,8 +608,10 @@ int main(int argc, char **argv) { int opt; unsigned int duration =3D TEST_DURATION_DEFAULT_IN_SEC; + bool nested_only =3D false; + bool no_nest =3D false; =20 - while ((opt =3D getopt(argc, argv, "hld:p:a:otxXP")) !=3D -1) { + while ((opt =3D getopt(argc, argv, "hld:p:a:otxXPnN")) !=3D -1) { switch (opt) { case 'l': options.use_poll =3D true; @@ -553,6 +649,15 @@ int main(int argc, char **argv) options.print_result =3D true; break; =20 + case 'n': + nested_only =3D true; + no_nest =3D false; + break; + case 'N': + nested_only =3D false; + no_nest =3D true; + break; + case 'h': default: help(argv[0]); @@ -568,7 +673,28 @@ int main(int argc, char **argv) if (options.use_x2apic) TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_X2APIC)); =20 - run_test(duration); + if (!nested_only) { + options.nested =3D false; + run_test(duration); + } + + if (!no_nest) { + union vmx_ctrl_msr ctls; + uint64_t ctls3; + + ctls.val =3D kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + TEST_REQUIRE(ctls.clr & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS); + + ctls3 =3D kvm_get_feature_msr(MSR_IA32_VMX_PROCBASED_CTLS3); + TEST_REQUIRE(ctls3 & TERTIARY_EXEC_GUEST_APIC_TIMER); + + /* L1 doesn't emulate HLT and memory-mapped APIC. */ + options.use_poll =3D true; + options.use_oneshot_timer =3D false; + + options.nested =3D true; + run_test(duration); + } =20 return 0; } --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 571133ED112; Tue, 3 Feb 2026 18:17:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142674; cv=none; b=B3ZjHTVX9AlaFaoG/vvcrtcpRV1/OWdPFO1aryizbIYHfFRR00+sABu+SflfieHliNwIYZ8fbYB/hg1aa1atnM1iI1qFKWJN9MoTXkQ+SWAlMS/nA+OtAuULASm/1g+wq01065KhwGgh/TQKTiJJrh7dNeBk+XyIsm6zyBoJ9Nw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142674; c=relaxed/simple; bh=Xp9vVVC9VmSIjmyuA7qa6qei/ZbOzg/Sj/hvegc3Ao8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rykYQVQoiMsooAjuDwPmuw3scsb+aELCEsrjnzPPbOwJlmoKGVaX2U+z+NrWrCBzK06weSJEnf5E9W9PU6uxksSWwp+f81hRv+u7xU2XyECGVRtvbtk907yGptn7LMSHqSWO4Cdl5KvLqZZNWTYJOG5ChZDiHX1805itgEMwFVQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=KInTC9tL; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="KInTC9tL" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142673; x=1801678673; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Xp9vVVC9VmSIjmyuA7qa6qei/ZbOzg/Sj/hvegc3Ao8=; b=KInTC9tLxmVvYOWTDECmRGwEAHHqO+xArMduOeED7oMG8Uhc3ZG1QZXS pkeAk9jeyu/ZEXYEPioXVP3BXngayRRez+aL6e/5nfn/Uf9qex7da7KIF kRdE0qRhc/zBK9WXDh099WH/8avEQlM7GAICRxN82uUtq3D+YNi0hAjZL yJRPN2Xd5tywfUctD1ELqj5aLdWZVjBXQdSIlk7Ev7XVyajiSOM6izEhK NXu4w5QFRxPQsCfAXpwT+rsXdIe8iEu7cq+MWny5Ny9v0a5omPCHTMvA8 zaGLB0sQQo7EPzDvPh6TnOiKe/WOyytB/rYpv8v0Q10P49dLerY9crsAz g==; X-CSE-ConnectionGUID: opTjxPAWQLazoquhQM81vg== X-CSE-MsgGUID: ZnmHevydTYeuNd8cAeuarg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745862" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745862" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:47 -0800 X-CSE-ConnectionGUID: JpN5z5EzR5G1EXujeqLJwQ== X-CSE-MsgGUID: Xa68/UmEQlSxZfzIe+d7HA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605533" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:46 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 26/32] KVM: selftests: Add test for nVMX MSR_IA32_VMX_PROCBASED_CTLS3 Date: Tue, 3 Feb 2026 10:17:09 -0800 Message-ID: <94e3f8de4021620758a213721d05e65437cdf4da.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Add test case for nVMX MSR_IA32_VMX_PROCBASED_CTLS3 emulation. Test if the access to MSR_IA32_VMX_PROCBASED_CTLS3 to succeed or fail, depending on whether the vCPU supports it or not. Signed-off-by: Isaku Yamahata --- .../testing/selftests/kvm/x86/vmx_msrs_test.c | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tools/testing/selftests/kvm/x86/vmx_msrs_test.c b/tools/testin= g/selftests/kvm/x86/vmx_msrs_test.c index 90720b6205f4..3ec5b73b4f2f 100644 --- a/tools/testing/selftests/kvm/x86/vmx_msrs_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_msrs_test.c @@ -48,6 +48,11 @@ static void vmx_fixed0and1_msr_test(struct kvm_vcpu *vcp= u, uint32_t msr_index) =20 static void vmx_save_restore_msrs_test(struct kvm_vcpu *vcpu) { + union vmx_ctrl_msr ctls; + const struct kvm_msr_list *feature_list; + bool ctl3_found =3D false; + int i; + vcpu_set_msr(vcpu, MSR_IA32_VMX_VMCS_ENUM, 0); vcpu_set_msr(vcpu, MSR_IA32_VMX_VMCS_ENUM, -1ull); =20 @@ -65,6 +70,54 @@ static void vmx_save_restore_msrs_test(struct kvm_vcpu *= vcpu) vmx_fixed0and1_msr_test(vcpu, MSR_IA32_VMX_TRUE_EXIT_CTLS); vmx_fixed0and1_msr_test(vcpu, MSR_IA32_VMX_TRUE_ENTRY_CTLS); vmx_fixed1_msr_test(vcpu, MSR_IA32_VMX_VMFUNC, -1ull); + + ctls.val =3D kvm_get_feature_msr(MSR_IA32_VMX_PROCBASED_CTLS); + TEST_ASSERT(!(ctls.set & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS), + "CPU_BASED_ACTIVATE_TERTIARY_CONTROLS should be cleared."); + + feature_list =3D kvm_get_feature_msr_index_list(); + for (i =3D 0; i < feature_list->nmsrs; i++) { + if (feature_list->indices[i] =3D=3D MSR_IA32_VMX_PROCBASED_CTLS3) { + ctl3_found =3D true; + break; + } + } + + if (ctls.clr & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) { + uint64_t kvm_ctls3, ctls3; + + TEST_ASSERT(ctl3_found, + "MSR_IA32_VMX_PROCBASED_CTLS3 was not in feature msr index list."); + + kvm_ctls3 =3D kvm_get_feature_msr(MSR_IA32_VMX_PROCBASED_CTLS3); + ctls3 =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3); + TEST_ASSERT(kvm_ctls3 =3D=3D ctls3, + "msr values for kvm and vcpu must match."); + + vcpu_set_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, 0); + vcpu_set_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, ctls3); + vmx_fixed1_msr_test(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, ctls3); + + /* + * The kvm host should be able to get/set + * MSR_IA32_VMX_PROCBASED_CTLS3 irrespective to the bit + * CPU_BASED_ACTIVATE_TERTIARY_CONTROLS of + * MSR_IA32_VMX_TRUE_PROCBASED_CTLS. + */ + ctls.val =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + vcpu_set_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, + ctls.set & ~CPU_BASED_ACTIVATE_TERTIARY_CONTROLS); + vcpu_set_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, 0); + vcpu_set_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, ctls3); + vmx_fixed1_msr_test(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, ctls3); + vcpu_set_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, ctls.val); + } else { + TEST_ASSERT(!ctl3_found, + "MSR_IA32_VMX_PROCBASED_CTLS3 was in feature msr index list."); + + TEST_ASSERT(!_vcpu_set_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, 0), + "setting MSR_IA32_VMX_PROCBASED_CTLS3 didn't fail."); + } } =20 static void __ia32_feature_control_msr_test(struct kvm_vcpu *vcpu, --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 84E5D3ED120; Tue, 3 Feb 2026 18:17:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142674; cv=none; b=tg9O+b7RyXS52CI6T29LStOizM2s2HFyIn3cQCsgKTvFxpNKZyVzlGu7zjMdfs20JbdFxt4qwozMdivxYW9Mj4LMxiHdNZOkPC/wPdZAtwVr91RK/5OkK8k6Fu1qH/6QXgBDObTNeFB3gpL5AJ4i9pJ2mTaOH2+p/rZnGm72jiw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142674; c=relaxed/simple; bh=MTUlsvIH1AkRzwWJPF1ATD3Q1XzZXcMIgmLGy8/GHBA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=oS1bkC7aMt2Q9sVW8E+kFTRWxk/vZ00aAeUXgE0UGOUFCQPAWLKGOaBaJmsT1L0ePzBCIc1RQePBXe65+HLszvoyv+DCKegCuAzcIPQyInLTWNI3UFS8T0krth/DJwdBHMbwEvgLQ41gFeqJWxFLaiTvI8rZqJ9CF/s+S0pKZEQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=hxX8nFLR; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="hxX8nFLR" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142673; x=1801678673; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=MTUlsvIH1AkRzwWJPF1ATD3Q1XzZXcMIgmLGy8/GHBA=; b=hxX8nFLR//vXwEsUtnXx9l7jP4tlB1RaE3gSgxF6//A2Ig8vE/8mdZfp ivKTQikX8Zpc3ozYn4OpRG1Ad7hXUP/K7IPOk7+y0VWtf4up1JCcz8PO/ JDR5A+c8swsejJO+BSoy7kNdNpm/yn0dMnF81zKMnCoo0mRG2UxmY7ZtN t8ekvSwCoZWkYOtdN7H3FDAY/ZN2aQRK65808oa9D+kbe9aARlua0gKmZ LKFW8+vvKQTc9CYBm0+lD7IYKLsngPZdVD847UKQ0jhwT3+JLPcfllpnL 4QfM+lmqZ6IxdoqEnJwHbzpVQD8QBSyNHsQS417ARZm9peNWnWXopwanm w==; X-CSE-ConnectionGUID: xJ1nz92OTH6u7isXBCqrfA== X-CSE-MsgGUID: VXDfuw4HSheLehZQw7znpA== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745867" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745867" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:48 -0800 X-CSE-ConnectionGUID: Rm0jqLTXTgq1ii+5qBwmHA== X-CSE-MsgGUID: mIfTUGxNT/SWtA3Sj0DQ2w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605538" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:47 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 27/32] KVM: selftests: Add test vmx_set_nested_state_test with EVMCS disabled Date: Tue, 3 Feb 2026 10:17:10 -0800 Message-ID: <8935e63039b4cfc9a343a2ed7dc7bc25b392fa33.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Hyper-V EVMCS capability, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, is optional. To increase test coverage, when Hyper-V EVMCS is supported, additionally run tests with EVMCS disabled. Signed-off-by: Isaku Yamahata --- .../selftests/kvm/x86/vmx_set_nested_state_test.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c b/= tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c index 67a62a5a8895..cbf6a8ff626e 100644 --- a/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c @@ -298,6 +298,18 @@ int main(int argc, char *argv[]) test_nested_state_expect_einval(vcpu, &state); =20 test_vmx_nested_state(vcpu); + if (have_evmcs) { + /* + * KVM_CAP_HYPERV_ENLIGHTENED_VMCS can be only enabled. + * Because There is no way to disable it, re-create vm and vcpu. + */ + have_evmcs =3D false; + kvm_vm_free(vm); + vm =3D vm_create_with_one_vcpu(&vcpu, NULL); + vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_VMX); + + test_vmx_nested_state(vcpu); + } =20 kvm_vm_free(vm); return 0; --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5550E3C1995; Tue, 3 Feb 2026 18:17:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142675; cv=none; b=ebZVKaITlQGTCRLPWpxLRpYrziqRPRkK8hl5Z2T+KElEj0l3TeFAjUdbrQXVRdTI+KS96qV23ioeURdaNklOlIsZvAu4/aJhCwzv8B6kFxgsHlxjZQEmrvE16QCF7B/aolyaVsy+CFNOLOryjQNOCMgxzsH5bM+96amQqWu7sFc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142675; c=relaxed/simple; bh=zn2LCIv7iXyBsSK01o7/GmoZjwISSXR6b33kXBbRNZ8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=R+P9yS4YNhRaEayzSGvEpE6zFk9/ZrdMr4gYp+OtV2PDD5QhqFrnqoqVcHEJ2Jx0aqizORfUsbgZFhNXiK6RlzYD/vhX82HTo8XQHlRpZZUCVCHFP8cwFHK1c+mBqcuX9r7Gk5AVCQLoW6qxP69fg0CJINVijrrtXhpGrekrXY4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=YymRuExU; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="YymRuExU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142674; x=1801678674; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zn2LCIv7iXyBsSK01o7/GmoZjwISSXR6b33kXBbRNZ8=; b=YymRuExUcgZH8bIo9VXZP+NwR+a9Bn1EnoFkNkRionQtkWJf78FH0fFh NbEnmmTpw5UZzckl+Pn5rvTWqBKIh2+RaNO7b+VvgWYDZunInKFOBmbZ1 M3fvHASEys2jNEFPaipaBItaRKZy8LfJ0J/KXKaBVybEsTaZPpMST6r9o Cpas2SEz6yCRAWiOa5HRX2sRzPq3ZK8SCyGXykvmJTFcIDIp7AQtZOtCa MItKrTrDnCMda4RSP8cxMyFx2553s5Dc4n2jn/JRprIDjEm64GJY2/v+I X6M5aNOYvj8Vqs4LpxGzIcY9wWfEkvWmIBJMavjzh9roXVhA+jmVF0tqz g==; X-CSE-ConnectionGUID: X0OPC3S5SJau5Y9H4v5ZIA== X-CSE-MsgGUID: SlICvL42QOOoDoJSUws34A== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745872" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745872" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:48 -0800 X-CSE-ConnectionGUID: 1P8CqZaCQFejvo0ij7GrGg== X-CSE-MsgGUID: nZrZKHDqSEKk5EfMMg255w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605544" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:47 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 28/32] KVM: selftests: Add tests nested state of APIC timer virtualization Date: Tue, 3 Feb 2026 10:17:11 -0800 Message-ID: <1cd17fc2aedaa11b2d104dc28ec7e0884267edd6.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Test vmread/vmwrite for the following VMCS fields related to apic timer virtualization in vmx_set_nested_state_test. - TERTIARY_EXEC_GUEST_APIC_TIMER bit in TERTIARY_VM_EXEC_CONTROL - VIRTUAL_TIMER_VECTOR_OFFSET - GUEST_DEADLINE_OFFSET - GUEST_DEADLINE_SHADOW_OFFSET Signed-off-by: Isaku Yamahata --- tools/testing/selftests/kvm/include/x86/vmx.h | 4 + .../kvm/x86/vmx_set_nested_state_test.c | 237 ++++++++++++++++++ 2 files changed, 241 insertions(+) diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/= selftests/kvm/include/x86/vmx.h index 304892500089..a46346ce92cb 100644 --- a/tools/testing/selftests/kvm/include/x86/vmx.h +++ b/tools/testing/selftests/kvm/include/x86/vmx.h @@ -173,6 +173,8 @@ enum vmcs_field { TSC_MULTIPLIER_HIGH =3D 0x00002033, TERTIARY_VM_EXEC_CONTROL =3D 0x00002034, TERTIARY_VM_EXEC_CONTROL_HIGH =3D 0x00002035, + GUEST_DEADLINE_VIR =3D 0x0000204e, + GUEST_DEADLINE_VIR_HIGH =3D 0x0000204f, GUEST_PHYSICAL_ADDRESS =3D 0x00002400, GUEST_PHYSICAL_ADDRESS_HIGH =3D 0x00002401, VMCS_LINK_POINTER =3D 0x00002800, @@ -195,6 +197,8 @@ enum vmcs_field { GUEST_PDPTR3_HIGH =3D 0x00002811, GUEST_BNDCFGS =3D 0x00002812, GUEST_BNDCFGS_HIGH =3D 0x00002813, + GUEST_DEADLINE_PHY =3D 0x00002830, + GUEST_DEADLINE_PHY_HIGH =3D 0x00002831, HOST_IA32_PAT =3D 0x00002c00, HOST_IA32_PAT_HIGH =3D 0x00002c01, HOST_IA32_EFER =3D 0x00002c02, diff --git a/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c b/= tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c index cbf6a8ff626e..e4c0e6c49e55 100644 --- a/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_set_nested_state_test.c @@ -25,6 +25,8 @@ #define VMCS12_REVISION 0x11e57ed0 =20 bool have_evmcs; +bool have_procbased_tertiary_ctls; +bool have_apic_timer_virtualization; =20 void test_nested_state(struct kvm_vcpu *vcpu, struct kvm_nested_state *sta= te) { @@ -85,6 +87,233 @@ void set_default_vmx_state(struct kvm_nested_state *sta= te, int size) set_revision_id_for_vmcs12(state, VMCS12_REVISION); } =20 +/* Those values are taken from arch/x86/kvm/vmx/vmcs12.h */ +#define VMCS_LINK_POINTER_OFFSET 176 +#define TERTIARY_VM_EXEC_CONTROL_OFFSET 336 +#define GUEST_CR0_OFFSET 424 +#define GUEST_CR4_OFFSET 440 +#define HOST_CR0_OFFSET 584 +#define HOST_CR4_OFFSET 600 +#define PIN_BASED_VM_EXEC_CONTROL_OFFSET 744 +#define CPU_BASED_VM_EXEC_CONTROL_OFFSET 748 +#define VM_EXIT_CONTROLS_OFFSET 768 +#define VM_ENTRY_CONTROLS_OFFSET 780 +#define SECONDARY_VM_EXEC_CONTROL_OFFSET 804 +#define HOST_CS_SELECTOR_OFFSET 984 +#define HOST_SS_SELECTOR_OFFSET 986 +#define HOST_TR_SELECTOR_OFFSET 994 +#define VIRTUAL_TIMER_VECTOR_OFFSET 998 +#define GUEST_DEADLINE_OFFSET 1000 +#define GUEST_DEADLINE_SHADOW_OFFSET 1008 + +#define KERNEL_CS 0x8 +#define KERNEL_DS 0x10 +#define KERNEL_TSS 0x18 + +/* vcpu with vmxon=3Dfalse is needed to be able to set VMX MSRs. */ +static void nested_vmxoff(struct kvm_vcpu *vcpu, struct kvm_nested_state *= state, + int state_sz) +{ + set_default_vmx_state(state, state_sz); + state->flags =3D 0; + state->hdr.vmx.vmxon_pa =3D -1ull; + state->hdr.vmx.vmcs12_pa =3D -1ull; + test_nested_state(vcpu, state); +} + +static void get_control(struct kvm_vcpu *vcpu, uint32_t msr_index, + uint32_t *fixed0, uint32_t *fixed1) +{ + uint64_t ctls; + + ctls =3D vcpu_get_msr(vcpu, msr_index); + + *fixed0 =3D ctls & 0xffffffff; + *fixed1 =3D ctls >> 32; +} + +static uint32_t *init_control(struct kvm_vcpu *vcpu, + struct kvm_nested_state *state, + uint32_t msr_index, size_t offset) +{ + uint32_t fixed0, fixed1, *vmcs32; + + get_control(vcpu, msr_index, &fixed0, &fixed1); + vmcs32 =3D (uint32_t *)&state->data.vmx->vmcs12[offset]; + + *vmcs32 =3D fixed0; + *vmcs32 &=3D fixed1; + + return vmcs32; +} + +void set_guest_vmx_state(struct kvm_vcpu *vcpu, struct kvm_nested_state *s= tate, + int size) +{ + unsigned long cr0, cr4; + uint32_t *vmcs32; + uint64_t *vmcs64; + + set_default_vmx_state(state, size); + state->flags |=3D KVM_STATE_NESTED_GUEST_MODE; + + /* control */ + init_control(vcpu, state, MSR_IA32_VMX_TRUE_PINBASED_CTLS, + PIN_BASED_VM_EXEC_CONTROL_OFFSET); + + vmcs32 =3D init_control(vcpu, state, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, + CPU_BASED_VM_EXEC_CONTROL_OFFSET); + *vmcs32 |=3D CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; + *vmcs32 &=3D ~CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + + init_control(vcpu, state, MSR_IA32_VMX_PROCBASED_CTLS2, + SECONDARY_VM_EXEC_CONTROL_OFFSET); + + vmcs32 =3D init_control(vcpu, state, MSR_IA32_VMX_TRUE_EXIT_CTLS, + VM_EXIT_CONTROLS_OFFSET); + *vmcs32 |=3D VM_EXIT_HOST_ADDR_SPACE_SIZE; + + init_control(vcpu, state, MSR_IA32_VMX_TRUE_ENTRY_CTLS, + VM_ENTRY_CONTROLS_OFFSET); + + vmcs64 =3D (uint64_t *)&state->data.vmx->vmcs12[VMCS_LINK_POINTER_OFFSET]; + *vmcs64 =3D -1ull; + + /* host state */ + cr0 =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_CR0_FIXED0); + cr0 &=3D vcpu_get_msr(vcpu, MSR_IA32_VMX_CR0_FIXED1); + cr0 |=3D X86_CR0_PG; + *(unsigned long*)&state->data.vmx->vmcs12[HOST_CR0_OFFSET] =3D cr0; + + cr4 =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_CR4_FIXED0); + cr4 &=3D vcpu_get_msr(vcpu, MSR_IA32_VMX_CR4_FIXED1); + cr4 |=3DX86_CR4_PAE | X86_CR4_VMXE; + *(unsigned long *)&state->data.vmx->vmcs12[HOST_CR4_OFFSET] =3D cr4; + + *(unsigned long *)&state->data.vmx->vmcs12[HOST_CS_SELECTOR_OFFSET] =3D K= ERNEL_CS; + *(unsigned long *)&state->data.vmx->vmcs12[HOST_TR_SELECTOR_OFFSET] =3D K= ERNEL_TSS; + *(unsigned long *)&state->data.vmx->vmcs12[HOST_SS_SELECTOR_OFFSET] =3D K= ERNEL_DS; + + /* guest state */ + cr0 =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_CR0_FIXED0); + cr0 &=3D vcpu_get_msr(vcpu, MSR_IA32_VMX_CR0_FIXED1); + *(unsigned long*)&state->data.vmx->vmcs12[GUEST_CR0_OFFSET] =3D cr0; + + cr4 =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_CR4_FIXED0); + cr4 &=3D vcpu_get_msr(vcpu, MSR_IA32_VMX_CR4_FIXED1); + *(unsigned long *)&state->data.vmx->vmcs12[GUEST_CR4_OFFSET] =3D cr4; + +} + +static void test_tertiary_ctls(struct kvm_vcpu *vcpu, + struct kvm_nested_state *state, + int state_sz) +{ + union vmx_ctrl_msr msr; + uint16_t *vmcs16; + uint32_t *vmcs32; + uint64_t *vmcs64; + uint64_t ctls; + + nested_vmxoff(vcpu, state, state_sz); + + msr.val =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + msr.clr |=3D CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; + msr.clr |=3D CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + vcpu_set_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, msr.val); + + ctls =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3); + ctls |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + vcpu_set_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, ctls); + + set_default_vmx_state(state, state_sz); + test_nested_state(vcpu, state); + + vmcs32 =3D (uint32_t *)&state->data.vmx->vmcs12[PIN_BASED_VM_EXEC_CONTROL= _OFFSET]; + *vmcs32 |=3D PIN_BASED_EXT_INTR_MASK; + + vmcs32 =3D (uint32_t *)&state->data.vmx->vmcs12[CPU_BASED_VM_EXEC_CONTROL= _OFFSET]; + *vmcs32 |=3D CPU_BASED_TPR_SHADOW | CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + + vmcs32 =3D (uint32_t *)&state->data.vmx->vmcs12[SECONDARY_VM_EXEC_CONTROL= _OFFSET]; + *vmcs32 |=3D SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; + + vmcs64 =3D (uint64_t *)&state->data.vmx->vmcs12[TERTIARY_VM_EXEC_CONTROL_= OFFSET]; + *vmcs64 |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + + vmcs16 =3D (uint16_t *)&state->data.vmx->vmcs12[VIRTUAL_TIMER_VECTOR_OFFS= ET]; + *vmcs16 =3D 128; + + vmcs64 =3D (uint64_t *)&state->data.vmx->vmcs12[GUEST_DEADLINE_OFFSET]; + /* random non-zero value */ + *vmcs64 =3D 0xffff; + + vmcs64 =3D (uint64_t *)&state->data.vmx->vmcs12[GUEST_DEADLINE_SHADOW_OFF= SET]; + *vmcs64 =3D 0xffff; + + test_nested_state(vcpu, state); +} + +static void test_tertiary_ctls_disabled(struct kvm_vcpu *vcpu, + struct kvm_nested_state *state, + int state_sz) +{ + union vmx_ctrl_msr msr; + uint16_t *vmcs16; + uint32_t *vmcs32; + uint64_t *vmcs64; + + nested_vmxoff(vcpu, state, state_sz); + + msr.val =3D kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + if (msr.clr & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) { + msr.val =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + msr.clr &=3D ~CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + vcpu_set_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, msr.val); + vcpu_set_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, 0); + } + + set_guest_vmx_state(vcpu, state, state_sz); + test_nested_state(vcpu, state); + + set_guest_vmx_state(vcpu, state, state_sz); + vmcs32 =3D (uint32_t *)&state->data.vmx->vmcs12[CPU_BASED_VM_EXEC_CONTROL= _OFFSET]; + *vmcs32 |=3D CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + test_nested_state_expect_einval(vcpu, state); + + set_guest_vmx_state(vcpu, state, state_sz); + vmcs64 =3D (uint64_t *)&state->data.vmx->vmcs12[TERTIARY_VM_EXEC_CONTROL_= OFFSET]; + *vmcs64 |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + test_nested_state_expect_einval(vcpu, state); + + set_guest_vmx_state(vcpu, state, state_sz); + vmcs16 =3D (uint16_t *)&state->data.vmx->vmcs12[VIRTUAL_TIMER_VECTOR_OFFS= ET]; + *vmcs16 =3D 128; + test_nested_state_expect_einval(vcpu, state); + + set_guest_vmx_state(vcpu, state, state_sz); + vmcs64 =3D (uint64_t *)&state->data.vmx->vmcs12[GUEST_DEADLINE_OFFSET]; + *vmcs64 =3D 0xffff; + test_nested_state_expect_einval(vcpu, state); + + set_guest_vmx_state(vcpu, state, state_sz); + vmcs64 =3D (uint64_t *)&state->data.vmx->vmcs12[GUEST_DEADLINE_SHADOW_OFF= SET]; + *vmcs64 =3D 0xffff; + test_nested_state_expect_einval(vcpu, state); +} + +static void test_vmx_tertiary_ctls(struct kvm_vcpu *vcpu, + struct kvm_nested_state *state, + int state_sz) +{ + vcpu_set_cpuid_feature(vcpu, X86_FEATURE_VMX); + + if (have_procbased_tertiary_ctls) + test_tertiary_ctls(vcpu, state, state_sz); + + test_tertiary_ctls_disabled(vcpu, state, state_sz); +} + void test_vmx_nested_state(struct kvm_vcpu *vcpu) { /* Add a page for VMCS12. */ @@ -244,6 +473,8 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) TEST_ASSERT(state->hdr.vmx.vmxon_pa =3D=3D -1ull, "vmxon_pa must be -1ull= ."); TEST_ASSERT(state->hdr.vmx.vmcs12_pa =3D=3D -1ull, "vmcs_pa must be -1ull= ."); =20 + test_vmx_tertiary_ctls(vcpu, state, state_sz); + free(state); } =20 @@ -254,6 +485,12 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; =20 have_evmcs =3D kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS); + have_procbased_tertiary_ctls =3D + (kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS) >> 32) & + CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + have_apic_timer_virtualization =3D have_procbased_tertiary_ctls && + (kvm_get_feature_msr(MSR_IA32_VMX_PROCBASED_CTLS3) & + TERTIARY_EXEC_GUEST_APIC_TIMER); =20 TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE)); =20 --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 533D83EDACD; Tue, 3 Feb 2026 18:17:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142676; cv=none; b=F14ph7h5et/cIqNch+dNvywLfsKDna0s2Wv0dMoyas8tvXM1SChLVrAL2Mk0rvoy2Qew55M8wpYWz4UC+cCGIod13EQBEUVMSiBKoipZ+HypMR8dINePx9al68EnNbaFyYmJo2BP/MYrFgHHGKzHtfpF1hZdnevel5ldzoKi/JA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142676; c=relaxed/simple; bh=JZrMxrBb2wo07lVIP4c3rcKRcWlXtoNkxyQ1gbY6FJ4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sU7ddyEnaEZ8oR2HViHUZVuOHu4P+jc/yeUe5x2fvnl6wIw9w+wQv0u0PUQGOtAR1/3xFIJPw6DZPNvHW6d82pj5aKao4mrD0XJGbJCWz1j0CohIivoMsSSa6V5tE/A8uO4Lsa4CzOZNE7hlyBk629Qo445zBlDWnkfO4pxSWr8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=S92K43cM; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="S92K43cM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142675; x=1801678675; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=JZrMxrBb2wo07lVIP4c3rcKRcWlXtoNkxyQ1gbY6FJ4=; b=S92K43cMtutAAs3H2IHtTdKWY5JXJwdwB7D4eNSy8QGPO3/qyQvDCz8P X1yQSzpaN872hMQhyiVhyKGy2iY6RynUKchRcU+t7/2FNq+EEwhkvJ2y8 aS/33/1gKifOoMQFrfRf1OAhzcPG0OZ3aBFXvqzss08CPRz4kZ5lHrL8b JAOh+tJJlN54i4F9L9EzQU65FDmociE4DQFXxtWcWIAkkuZBJ769yqN6f WHkJnnKHLR8bOeQKJA8OXUf0DR4WpOhSJND/pApF2movZYUKBXzgSsvjY 5CSBxlPV5juyKrHYVw9t0d5wgXMvGb6UH8moZG2wzyHYn/onujAxg/371 Q==; X-CSE-ConnectionGUID: bQ6PKNbTSC2C4evpEfgAoA== X-CSE-MsgGUID: jA4gdw4uRduGIWD9ziVZTQ== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745876" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745876" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:49 -0800 X-CSE-ConnectionGUID: SPPCojEeT/SEvtLvPGnFrw== X-CSE-MsgGUID: VlQnlb06TsqAJd0n7cvN0A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605550" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:47 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 29/32] KVM: selftests: Add VMCS access test to APIC timer virtualization Date: Tue, 3 Feb 2026 10:17:12 -0800 Message-ID: <37a0f982a211cdfbb7214b213744346fddd4bfb6.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Add test case for VMCS access of nVMX APIC timer virtualization. It tests nVMX emulation of a tertiary processor-based VM executing controls MSR, tertiary processor-base VM execution controls, and related VMCS fields by L1 vCPU and L2 vCPU. Signed-off-by: Isaku Yamahata --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../testing/selftests/kvm/include/x86/apic.h | 2 + .../kvm/x86/vmx_apic_timer_virt_vmcs_test.c | 461 ++++++++++++++++++ 3 files changed, 464 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_vmc= s_test.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 695d19c73199..df126774f028 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -140,6 +140,7 @@ TEST_GEN_PROGS_x86 +=3D x86/triple_fault_event_test TEST_GEN_PROGS_x86 +=3D x86/recalc_apic_map_test TEST_GEN_PROGS_x86 +=3D x86/aperfmperf_test TEST_GEN_PROGS_x86 +=3D x86/timer_latency +TEST_GEN_PROGS_x86 +=3D x86/vmx_apic_timer_virt_vmcs_test TEST_GEN_PROGS_x86 +=3D access_tracking_perf_test TEST_GEN_PROGS_x86 +=3D coalesced_io_test TEST_GEN_PROGS_x86 +=3D dirty_log_perf_test diff --git a/tools/testing/selftests/kvm/include/x86/apic.h b/tools/testing= /selftests/kvm/include/x86/apic.h index 80fe9f69b38d..270b2a914725 100644 --- a/tools/testing/selftests/kvm/include/x86/apic.h +++ b/tools/testing/selftests/kvm/include/x86/apic.h @@ -32,6 +32,8 @@ #define APIC_SPIV 0xF0 #define APIC_SPIV_FOCUS_DISABLED (1 << 9) #define APIC_SPIV_APIC_ENABLED (1 << 8) +#define APIC_ISR 0x100 +#define APIC_ISR_NR 0x8 #define APIC_IRR 0x200 #define APIC_ICR 0x300 #define APIC_LVTCMCI 0x2f0 diff --git a/tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_vmcs_test.= c b/tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_vmcs_test.c new file mode 100644 index 000000000000..4b1cec257c60 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_vmcs_test.c @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025, Intel Corporation. + * + * Tested vmread()/vmwrite() related to APIC timer virtualization in L1 + * emulated by KVM. + */ + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "vmx.h" + +#include +#include +#include + +bool have_procbased_tertiary_ctls; +bool have_apic_timer_virtualization; + +#define L2_GUEST_STACK_SIZE 256 +static unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + +/* Any value [32, 255] for timer vector is okay. */ +#define TIMER_VECTOR 0xec + +static bool update_l2_tsc_deadline; +static uint64_t l2_tsc_deadline; + +static void guest_timer_interrupt_handler(struct ex_regs *regs) +{ + x2apic_write_reg(APIC_EOI, 0); +} + +static void l2_guest_code(void) +{ + cli(); + x2apic_enable(); + wrmsr(MSR_IA32_TSC_DEADLINE, 0); + x2apic_write_reg(APIC_LVTT, APIC_LVT_TIMER_TSCDEADLINE | TIMER_VECTOR); + + vmcall(); + + while (true) { + /* reap pending timer interrupt. */ + sti_nop_cli(); + + if (update_l2_tsc_deadline) + GUEST_ASSERT(!wrmsr_safe(MSR_IA32_TSC_DEADLINE, l2_tsc_deadline)); + + vmcall(); + } + + GUEST_FAIL("should not reached."); +} + +static void setup_l2(struct vmx_pages *vmx_pages) +{ + uint64_t ctls, msr_val; + int r; + + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_VMX_TRUE_PROCBASED_CTLS, + &msr_val)); + GUEST_ASSERT(have_procbased_tertiary_ctls =3D=3D + !!((msr_val >> 32) & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS)); + + r =3D rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS3, &msr_val); + GUEST_ASSERT(have_procbased_tertiary_ctls =3D=3D !r); + if (r) + msr_val =3D 0; + GUEST_ASSERT(have_apic_timer_virtualization =3D=3D + !!(msr_val & TERTIARY_EXEC_GUEST_APIC_TIMER)); + + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_vmcs(vmx_pages, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + GUEST_ASSERT(!vmread(PIN_BASED_VM_EXEC_CONTROL, &ctls)); + ctls |=3D PIN_BASED_EXT_INTR_MASK; + GUEST_ASSERT(!vmwrite(PIN_BASED_VM_EXEC_CONTROL, ctls)); + + GUEST_ASSERT(!vmread(CPU_BASED_VM_EXEC_CONTROL, &ctls)); + ctls |=3D CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_TPR_SHADOW | + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; + if (have_procbased_tertiary_ctls) + ctls |=3D CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + GUEST_ASSERT(!vmwrite(CPU_BASED_VM_EXEC_CONTROL, ctls)); + + GUEST_ASSERT(!vmread(SECONDARY_VM_EXEC_CONTROL, &ctls)); + ctls |=3D SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; + GUEST_ASSERT(!vmwrite(SECONDARY_VM_EXEC_CONTROL, ctls)); + + if (have_procbased_tertiary_ctls) { + GUEST_ASSERT(!vmread(TERTIARY_VM_EXEC_CONTROL, &ctls)); + + ctls &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; + GUEST_ASSERT(!vmwrite(TERTIARY_VM_EXEC_CONTROL, ctls)); + } else { + GUEST_ASSERT(vmread(TERTIARY_VM_EXEC_CONTROL, &ctls)); + ctls =3D 0; + } + + ctls |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + GUEST_ASSERT(have_procbased_tertiary_ctls =3D=3D + !vmwrite(TERTIARY_VM_EXEC_CONTROL, ctls)); + if (have_procbased_tertiary_ctls && !have_apic_timer_virtualization) { + ctls &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; + GUEST_ASSERT(!vmwrite(TERTIARY_VM_EXEC_CONTROL, ctls)); + } + + GUEST_ASSERT(have_apic_timer_virtualization =3D=3D + !vmwrite(GUEST_APIC_TIMER_VECTOR, TIMER_VECTOR)); +} + +static void skip_guest_instruction(void) +{ + uint64_t guest_rip, length; + + GUEST_ASSERT(!vmread(GUEST_RIP, &guest_rip)); + GUEST_ASSERT(!vmread(VM_EXIT_INSTRUCTION_LEN, &length)); + + GUEST_ASSERT(!vmwrite(GUEST_RIP, guest_rip + length)); + GUEST_ASSERT(!vmwrite(VM_EXIT_INSTRUCTION_LEN, 0)); +} + +static void l2_load_vmlaunch(struct vmx_pages *vmx_pages) +{ + GUEST_ASSERT(load_vmcs(vmx_pages)); + skip_guest_instruction(); + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) =3D=3D EXIT_REASON_VMCALL); +} + +struct vmcs_guest_deadline { + uint64_t vir; + uint64_t phy; +}; + +struct deadline_test { + struct vmcs_guest_deadline set; + struct vmcs_guest_deadline result; +}; + +static void test_vmclear_vmptrld(struct vmx_pages *vmx_pages) +{ + struct deadline_test tests[] =3D { + { + .set =3D { + .vir =3D ~0ull, + .phy =3D ~0ull, + }, + .result =3D { + .vir =3D ~0ull, + .phy =3D ~0ull, + } + }, + { + .set =3D { + .vir =3D ~0ull, + .phy =3D 0, + }, + .result =3D { + .vir =3D ~0ull, + .phy =3D 0, + } + }, + { + .set =3D { + .vir =3D ~0ull, + .phy =3D 1, + }, + .result =3D { + .vir =3D 0, + .phy =3D 0, + } + }, + { + .set =3D { + .vir =3D 0, + .phy =3D ~0ull, + }, + .result =3D { + .vir =3D 0, + .phy =3D ~0ull, + } + }, + { + .set =3D { + .vir =3D 1, + .phy =3D ~0ull, + }, + .result =3D { + .vir =3D 1, + .phy =3D ~0ull, + } + }, + { + .set =3D { + .vir =3D 1, + .phy =3D 1, + }, + .result =3D { + .vir =3D 0, + .phy =3D 0, + } + }, + { + .set =3D { + .vir =3D 1, + .phy =3D 0, + }, + .result =3D { + .vir =3D 1, + .phy =3D 0, + } + }, + { + .set =3D { + .vir =3D 0, + .phy =3D 1, + }, + .result =3D { + .vir =3D 0, + .phy =3D 0, + } + }, + }; + int i; + + if (!have_apic_timer_virtualization) + return; + + update_l2_tsc_deadline =3D false; + + /* + * Test if KVM properly store/load TIMER_VECTOR, guest deadline of + * vmcs area to/from memory. + * Enforce KVM to store nested vmcs to memory and load it again. + * load_vmcs() issues vmclear(), and then vmptrld() + */ + l2_load_vmlaunch(vmx_pages); + GUEST_ASSERT(vmreadz(GUEST_APIC_TIMER_VECTOR) =3D=3D TIMER_VECTOR); + + for (i =3D 0; i < ARRAY_SIZE(tests); i++) { + struct deadline_test *test =3D &tests[i]; + uint64_t vir, phy, val; + + GUEST_ASSERT(!vmwrite(GUEST_DEADLINE_VIR, test->set.vir)); + GUEST_ASSERT(!vmread(GUEST_DEADLINE_VIR, &val)); + GUEST_ASSERT(test->set.vir =3D=3D val); + + GUEST_ASSERT(!vmwrite(GUEST_DEADLINE_PHY, test->set.phy)); + GUEST_ASSERT(!vmread(GUEST_DEADLINE_PHY, &val)); + GUEST_ASSERT(test->set.phy =3D=3D val); + + l2_load_vmlaunch(vmx_pages); + + GUEST_ASSERT(!vmread(GUEST_DEADLINE_VIR, &vir)); + GUEST_ASSERT(!vmread(GUEST_DEADLINE_PHY, &phy)); + + GUEST_ASSERT(vir =3D=3D test->result.vir); + GUEST_ASSERT(!!phy =3D=3D !!test->result.phy); + } +} + +static void test_ctls(void) +{ + uint64_t ctls; + + update_l2_tsc_deadline =3D false; + + GUEST_ASSERT(!vmwrite(GUEST_APIC_TIMER_VECTOR, TIMER_VECTOR) =3D=3D have_= apic_timer_virtualization); + GUEST_ASSERT(!vmwrite(GUEST_DEADLINE_VIR, 0) =3D=3D have_apic_timer_virtu= alization); + GUEST_ASSERT(!vmwrite(GUEST_DEADLINE_PHY, 0) =3D=3D have_apic_timer_virtu= alization); + + if (!have_procbased_tertiary_ctls) { + GUEST_ASSERT(!vmread(CPU_BASED_VM_EXEC_CONTROL, &ctls)); + ctls |=3D CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + GUEST_ASSERT(!vmwrite(CPU_BASED_VM_EXEC_CONTROL, ctls)); + + skip_guest_instruction(); + GUEST_ASSERT(vmresume()); + + ctls &=3D ~CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + GUEST_ASSERT(!vmwrite(CPU_BASED_VM_EXEC_CONTROL, ctls)); + } + + if (have_procbased_tertiary_ctls && !have_apic_timer_virtualization) { + GUEST_ASSERT(!vmread(TERTIARY_VM_EXEC_CONTROL, &ctls)); + ctls |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + GUEST_ASSERT(!vmwrite(TERTIARY_VM_EXEC_CONTROL, ctls)); + + skip_guest_instruction(); + GUEST_ASSERT(vmresume()); + + ctls &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; + GUEST_ASSERT(!vmwrite(TERTIARY_VM_EXEC_CONTROL, ctls)); + } +} + +static void test_l2_set_deadline(void) +{ + uint64_t deadlines[] =3D { + 0, + 1, + 2, + + rdtsc() / 2, + rdtsc(), + rdtsc() * 2, + + ~0ull / 2 - 1, + ~0ull / 2, + ~0ull / 2 + 1, + + ~0ull - 1, + ~0ull - 2, + ~0ull, + }; + int i; + + update_l2_tsc_deadline =3D true; + + for (i =3D 0; i < ARRAY_SIZE(deadlines); i++) { + uint64_t phy, vir; + + l2_tsc_deadline =3D deadlines[i]; + + skip_guest_instruction(); + GUEST_ASSERT(!vmresume()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) =3D=3D EXIT_REASON_VMCALL); + + GUEST_ASSERT(!vmread(GUEST_DEADLINE_VIR, &vir)); + GUEST_ASSERT(!vmread(GUEST_DEADLINE_PHY, &phy)); + + GUEST_ASSERT(!vir || vir =3D=3D l2_tsc_deadline); + } +} + +static void l1_guest_code(struct vmx_pages *vmx_pages) +{ + setup_l2(vmx_pages); + + GUEST_ASSERT(have_apic_timer_virtualization =3D=3D + !vmwrite(GUEST_DEADLINE_VIR, ~0ull)); + GUEST_ASSERT(have_apic_timer_virtualization =3D=3D + !vmwrite(GUEST_DEADLINE_PHY, ~0ull)); + + test_vmclear_vmptrld(vmx_pages); + + update_l2_tsc_deadline =3D false; + l2_load_vmlaunch(vmx_pages); + test_ctls(); + + if (have_apic_timer_virtualization) { + update_l2_tsc_deadline =3D false; + l2_load_vmlaunch(vmx_pages); + + test_l2_set_deadline(); + } + + GUEST_DONE(); +} + +static void run_vcpu(struct kvm_vcpu *vcpu) +{ + bool done =3D false; + + while (!done) { + struct ucall uc; + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + /* NOT REACHED */ + case UCALL_PRINTF: + pr_info("%s", uc.buffer); + break; + case UCALL_DONE: + done =3D true; + break; + default: + TEST_ASSERT(false, "Unknown ucall %lu", uc.cmd); + } + } +} + +static void test_apic_virtualization_vmcs(void) +{ + vm_vaddr_t vmx_pages_gva; + + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + uint64_t ctls, ctls3; + + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + + vm =3D vm_create_with_one_vcpu(&vcpu, l1_guest_code); + vcpu_alloc_vmx(vm, &vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); + + vcpu_set_cpuid_feature(vcpu, X86_FEATURE_TSC_DEADLINE_TIMER); + + ctls =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + if (have_procbased_tertiary_ctls) { + ctls |=3D (uint64_t)CPU_BASED_ACTIVATE_TERTIARY_CONTROLS << 32; + vcpu_set_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, ctls); + + ctls3 =3D vcpu_get_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3); + if (have_apic_timer_virtualization) + ctls3 |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + else + ctls3 &=3D ~TERTIARY_EXEC_GUEST_APIC_TIMER; + vcpu_set_msr(vcpu, MSR_IA32_VMX_PROCBASED_CTLS3, ctls3); + } else { + ctls &=3D ~((uint64_t)CPU_BASED_ACTIVATE_TERTIARY_CONTROLS << 32); + vcpu_set_msr(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS, ctls); + } + + /* For L2. */ + vm_install_exception_handler(vm, TIMER_VECTOR, + guest_timer_interrupt_handler); + + sync_global_to_guest(vm, have_procbased_tertiary_ctls); + sync_global_to_guest(vm, have_apic_timer_virtualization); + run_vcpu(vcpu); + + kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + have_procbased_tertiary_ctls =3D + (kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS) >> 32) & + CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + have_apic_timer_virtualization =3D have_procbased_tertiary_ctls && + (kvm_get_feature_msr(MSR_IA32_VMX_PROCBASED_CTLS3) & + TERTIARY_EXEC_GUEST_APIC_TIMER); + + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + + test_apic_virtualization_vmcs(); + + if (have_apic_timer_virtualization) { + have_apic_timer_virtualization =3D false; + test_apic_virtualization_vmcs(); + } + + if (have_procbased_tertiary_ctls) { + have_procbased_tertiary_ctls =3D false; + test_apic_virtualization_vmcs(); + } + + return 0; +} --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C0B713EDAD6; Tue, 3 Feb 2026 18:17:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142676; cv=none; b=pQXMqyWijEKDgMRbnG+RjfKOz4ZGN77PioSYUbpIiojo7gX915AQQoFGqaC+WQkUqnDq0srw5iwdE3yed62OC0Mjicxghkj2VWCzhLTLTlWMEa6e3S0a02shPfEXxTtToxdQAhNtduZ726adKHWcP+HOJek2HEFC7hmEjmWKJiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142676; c=relaxed/simple; bh=RLyF8Vlox6NJKFpvnb58liGFm595VlLftIT9aGmUkY0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gi4OHtvpUBLIAIJc9OHiOS+43acKJGTkqzJPOyZA9ZeoK3Nys0mYISmCEAl88Q+1hy9YjmDPmytptyZt/YZC/rgZrcjfeEfS0V9Lyj/nY4Q5lwGMwhzuliZefC0gy1q62pjUru69nAO2yeVBALL34aJ6dmG36W8wG/YFP3NRyno= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=YeaYW1OD; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="YeaYW1OD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142675; x=1801678675; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=RLyF8Vlox6NJKFpvnb58liGFm595VlLftIT9aGmUkY0=; b=YeaYW1ODlIpwcw+r8aAfp8IfvlMFET02TWgNCeOP5FaT0iuQrHB3Zdu1 SjIi5kG6+exzWsALDR71EUwyRshvozqfXrH1fz8bdg+weMLJRfM1kb+Yl 5Bcu+ZqoMMgCB2bRckeO97jDMwcVkHRmb2SOS7Qmwklgi8gTie0RC5r0j lojGcC6yPPSlAslrgE6a9hUQnxRwsyfTv6/6UssefyZTiOBQdUUlW8sXc o1cUOb5i1bra7Kgl8pxuJA99katgD1cSEHoQxKZ8aQcBHz+aSRw6378Ts zDDEhXSZbeNQg4RT9BvHqZVhdoTckNvk9PhEgIGBIx6OzSH8ONhoM8wFB w==; X-CSE-ConnectionGUID: ePzrL22WRbeHRyihP3anUQ== X-CSE-MsgGUID: SoRaf16YQH2eU5mYkQSlMw== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745882" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745882" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:49 -0800 X-CSE-ConnectionGUID: 6Jbr6sP5TQ2RZ7JcbIonSw== X-CSE-MsgGUID: 8wMkKnPDTfupzzfAzZCQ1Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605555" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:48 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 30/32] KVM: selftests: Test cases for L1 APIC timer virtualization Date: Tue, 3 Feb 2026 10:17:13 -0800 Message-ID: <23a90397b5ece88a8297d4010d5f53acd17335ff.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Test nVMX APIC timer virtualization for L1 to see how KVM in L0 works. It exercises KVM TSC deadline conversion between L0 and L1. Signed-off-by: Isaku Yamahata --- tools/testing/selftests/kvm/Makefile.kvm | 1 + .../selftests/kvm/include/x86/processor.h | 6 + .../kvm/x86/vmx_apic_timer_virt_test.c | 317 ++++++++++++++++++ 3 files changed, 324 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_tes= t.c diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index df126774f028..aec47a608b87 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -140,6 +140,7 @@ TEST_GEN_PROGS_x86 +=3D x86/triple_fault_event_test TEST_GEN_PROGS_x86 +=3D x86/recalc_apic_map_test TEST_GEN_PROGS_x86 +=3D x86/aperfmperf_test TEST_GEN_PROGS_x86 +=3D x86/timer_latency +TEST_GEN_PROGS_x86 +=3D x86/vmx_apic_timer_virt_test TEST_GEN_PROGS_x86 +=3D x86/vmx_apic_timer_virt_vmcs_test TEST_GEN_PROGS_x86 +=3D access_tracking_perf_test TEST_GEN_PROGS_x86 +=3D coalesced_io_test diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/te= sting/selftests/kvm/include/x86/processor.h index 57d62a425109..b6c33bc34ed6 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -1430,6 +1430,12 @@ static inline void cli(void) asm volatile ("cli"); } =20 +static inline void serialize(void) +{ + /* serialize instruction. binuutils >=3D 2.35 */ + kvm_asm_safe(".byte 0x0f, 0x01, 0xe8"); +} + void __vm_xsave_require_permission(uint64_t xfeature, const char *name); =20 #define vm_xsave_require_permission(xfeature) \ diff --git a/tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_test.c b/t= ools/testing/selftests/kvm/x86/vmx_apic_timer_virt_test.c new file mode 100644 index 000000000000..ea465e9825d8 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_test.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025, Intel Corporation. + * + * Test timer expiration conversion and exercise various LVTT mode. + */ + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "vmx.h" + +#include +#include +#include + +#include + +static uint64_t host_tsc_khz; +static uint64_t max_guest_tsc_khz; + +/* Any value [32, 255] for timer vector is okay. */ +#define TIMER_VECTOR 0xec + +static atomic_int timer_interrupted; + +static void guest_timer_interrupt_handler(struct ex_regs *regs) +{ + atomic_fetch_add(&timer_interrupted, 1); + x2apic_write_reg(APIC_EOI, 0); +} + +static void reap_interrupt(void) +{ + GUEST_ASSERT(!wrmsr_safe(MSR_IA32_TSC_DEADLINE, 0)); + sti_nop_cli(); +} + +static void deadline_write_test(bool do_interrupt, bool mask, + uint64_t deadlines[], size_t nr_deadlines) +{ + int i; + + for (i =3D 0; i < nr_deadlines; i++) { + uint64_t deadline =3D deadlines[i]; + uint64_t val; + + reap_interrupt(); + + atomic_store(&timer_interrupted, 0); + sti(); + GUEST_ASSERT(!wrmsr_safe(MSR_IA32_TSC_DEADLINE, deadline)); + /* serialize to wait for timer interrupt to fire. */ + serialize(); + cli(); + + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_TSC_DEADLINE, &val)); + + if (do_interrupt) { + GUEST_ASSERT(val =3D=3D 0); + if (mask || deadline =3D=3D 0) + GUEST_ASSERT(!atomic_load(&timer_interrupted)); + else + GUEST_ASSERT(atomic_load(&timer_interrupted) =3D=3D 1); + } else { + GUEST_ASSERT(val =3D=3D deadline); + GUEST_ASSERT(!atomic_load(&timer_interrupted)); + } + } +} + +static void deadline_write_hlt_test(uint64_t deadlines[], size_t nr_deadli= nes) +{ + int i; + + for (i =3D 0; i < nr_deadlines; i++) { + uint64_t deadline =3D deadlines[i]; + uint64_t val; + + reap_interrupt(); + + GUEST_ASSERT(deadline); + + atomic_store(&timer_interrupted, 0); + GUEST_ASSERT(!wrmsr_safe(MSR_IA32_TSC_DEADLINE, deadline)); + + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_TSC_DEADLINE, &val)); + GUEST_ASSERT(val =3D=3D deadline || val =3D=3D 0); + GUEST_ASSERT(!atomic_load(&timer_interrupted)); + + asm volatile ("sti; hlt; nop; cli" + /* L1 exit handler doesn't preserve GP registers. */ + : : : "cc", "memory", + "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", + "r15"); + + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_TSC_DEADLINE, &val)); + GUEST_ASSERT(val =3D=3D 0); + GUEST_ASSERT(atomic_load(&timer_interrupted) =3D=3D 1); + } +} + +static void deadline_no_int_test(void) +{ + uint64_t tsc =3D rdtsc(); + uint64_t deadlines[] =3D { + 0ull, + /* big values > tsc. */ + max(~0ull - tsc, ~0ull / 2 + tsc / 2), + ~0ull - 1, + ~0ull - 2, + ~0ull, + }; + + deadline_write_test(false, false, deadlines, ARRAY_SIZE(deadlines)); +} + +static void __deadline_int_test(bool do_interrupt, bool mask) +{ + uint64_t tsc =3D rdtsc(); + uint64_t deadlines[] =3D { + 0ull, + 1ull, + 2ull, + /* 1 msec past. tsc /2 is to avoid underflow. */ + min(tsc - guest_tsc_khz, tsc / 2 + 1), + tsc, + }; + + deadline_write_test(do_interrupt, mask, deadlines, ARRAY_SIZE(deadlines)); +} + +static void deadline_int_test(void) +{ + __deadline_int_test(true, false); +} + +static void deadline_int_mask_test(void) +{ + __deadline_int_test(true, true); +} + +static void deadline_hlt_test(void) +{ + uint64_t tsc =3D rdtsc(); + /* 1 msec future. */ + uint64_t future =3D tsc + guest_tsc_khz; + uint64_t deadlines[] =3D { + 1ull, + 2ull, + /* pick a positive value between [0, tsc]. */ + tsc > guest_tsc_khz ? tsc - guest_tsc_khz : tsc / 2 + 1, + tsc, + /* If overflow, pick near future value > tsc. */ + future > tsc ? future : ~0ull / 2 + tsc / 2, + }; + + deadline_write_hlt_test(deadlines, ARRAY_SIZE(deadlines)); +} + +static void guest_code(void) +{ + x2apic_enable(); + + x2apic_write_reg(APIC_LVTT, APIC_LVT_TIMER_TSCDEADLINE | TIMER_VECTOR); + deadline_no_int_test(); + deadline_int_test(); + deadline_hlt_test(); + + x2apic_write_reg(APIC_LVTT, APIC_LVT_TIMER_TSCDEADLINE | + APIC_LVT_MASKED | TIMER_VECTOR); + deadline_no_int_test(); + deadline_int_mask_test(); + + GUEST_DONE(); +} + +static void run_vcpu(struct kvm_vcpu *vcpu) +{ + bool done =3D false; + + while (!done) { + struct ucall uc; + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + /* NOT REACHED */ + case UCALL_SYNC: + break; + case UCALL_PRINTF: + pr_info("%s", uc.buffer); + break; + case UCALL_DONE: + done =3D true; + break; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + } + } +} + +static int test_tsc_deadline(bool tsc_offset, uint64_t guest_tsc_khz__) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + + if (guest_tsc_khz__) { + int ret; + + ret =3D __vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)guest_tsc_khz__); + if (ret) { + kvm_vm_free(vm); + return ret; + } + + guest_tsc_khz =3D guest_tsc_khz__; + } + + if (tsc_offset) { + uint64_t offset; + + __TEST_REQUIRE(!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET), + "KVM_VCPU_TSC_OFFSET not supported; skipping test"); + + /* + * Make the conversion guest deadline virt(L1) =3D> phy (l0) + * can overflow/underflow. + */ + offset =3D -rdtsc(); + vcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET, &offset); + } + + vcpu_set_cpuid_feature(vcpu, X86_FEATURE_TSC_DEADLINE_TIMER); + vm_install_exception_handler(vm, TIMER_VECTOR, + guest_timer_interrupt_handler); + + sync_global_to_guest(vm, host_tsc_khz); + sync_global_to_guest(vm, guest_tsc_khz); + run_vcpu(vcpu); + + kvm_vm_free(vm); + + return 0; +} + +static void test(void) +{ + uint64_t guest_tsc_khz__; + int r; + + test_tsc_deadline(false, 0); + test_tsc_deadline(true, 0); + + for (guest_tsc_khz__ =3D host_tsc_khz; guest_tsc_khz__ > 0; + guest_tsc_khz__ >>=3D 1) { + r =3D test_tsc_deadline(false, guest_tsc_khz__); + if (r) + break; + + test_tsc_deadline(true, guest_tsc_khz__); + } + + for (guest_tsc_khz__ =3D host_tsc_khz; guest_tsc_khz__ < max_guest_tsc_kh= z; + guest_tsc_khz__ <<=3D 1) { + r =3D test_tsc_deadline(false, guest_tsc_khz__); + if (r) + break; + + test_tsc_deadline(true, guest_tsc_khz__); + } + + test_tsc_deadline(false, max_guest_tsc_khz); + test_tsc_deadline(true, max_guest_tsc_khz); +} + +int main(int argc, char *argv[]) +{ + uint32_t eax_denominator, ebx_numerator, ecx_hz, edx; + union vmx_ctrl_msr ctls; + uint64_t ctls3; + + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_X2APIC)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); + + cpuid(0x15, &eax_denominator, &ebx_numerator, &ecx_hz, &edx); + TEST_REQUIRE(ebx_numerator > 0); + TEST_REQUIRE(eax_denominator > 0); + + if (ecx_hz > 0) + host_tsc_khz =3D ecx_hz * ebx_numerator / eax_denominator / 1000; + else { + uint32_t eax_base_mhz, ebx, ecx; + + cpuid(0x16, &eax_base_mhz, &ebx, &ecx, &edx); + host_tsc_khz =3D eax_base_mhz * 1000 * ebx_numerator / + eax_denominator; + } + TEST_REQUIRE(host_tsc_khz > 0); + + /* See arch/x86/kvm/{x86.c, vmx/vmx.c}. There is no way for userspace to = retrieve it. */ +#define KVM_VMX_TSC_MULTIPLIER_MAX 0xffffffffffffffffULL + max_guest_tsc_khz =3D min((uint64_t)0x7fffffffULL, + mul_u64_u32_shr(KVM_VMX_TSC_MULTIPLIER_MAX, host_tsc_khz, 48)); + + test(); + + return 0; +} --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C892C3EF0C3; Tue, 3 Feb 2026 18:17:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142677; cv=none; b=Pg/OBHzKloVO/HS1W10UPIV8eS8DwVB7jbXWT7ucBFSsx+K0hUDZVBT8fIrcga8KKtMwREl9u/v+tCZ1CMwpbNWOMsgx4LkV4lVnr84rdEcmwMWU+ilR7sbNqT6pF4Q+L5KWnQw5SI3Y18+rii9aAE649Hcaicj140hFxFLHjpQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142677; c=relaxed/simple; bh=FjSpOUFqM7dbnvpoaEWIFOrNUeXGSOriDiDTxrz25UM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=apN5nFC61elbtqGiyTwmdpbfT4Qr4NahFpIWbSNv35DikgDMDCw2c7LCpwKZ/hSWrpHeO+UJ0+X83j3cqN5JD0Mul5b5+RZoxYlrUTbE56EvIkHmxyONKmrAtHvcAQH1tiSFN99f75/BsQ2SzUs2Yj9oxoXfFe522Ta4Nm8jAG4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=GRHcFM22; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="GRHcFM22" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142676; x=1801678676; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FjSpOUFqM7dbnvpoaEWIFOrNUeXGSOriDiDTxrz25UM=; b=GRHcFM22mkfjeX0l2idVvBbsSoXHFtGKU7yuNhdOoKVVxxF1cwJEnCUo NXdhT8wDI7JO3I8QJ3kdRqhJGfyf7E9Tbx9xJXQUAQUiHw3bi46F4w2Ob lIxVqpLtJ3Y3fYeAS8kxkSpZescl/T3jmQiduWUuHSowNzbG0m+f/Jcdu yFIltpgSD7hM2TnsJ5h6WFKQD7vLjj+zxUCPv4N+DzfviF9RIRWefyzah uR6rWMIUFcvJ6vI3CVhDTduLlFCyelnmm0sLu8H2xUWCwWEGC4vXBA0Og 8zW7r+1ViAL2AcY49/9zMuQv42fuBrYAIrPhcnacjAtzA/o4XMuclhkbX w==; X-CSE-ConnectionGUID: 1CcTnZfGQZa1eBKoHB6IJg== X-CSE-MsgGUID: KiDKSLBBSBSsfsbVDcaL2A== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745886" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745886" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:49 -0800 X-CSE-ConnectionGUID: bCxIVc83SBCHctIYb2RyiA== X-CSE-MsgGUID: yn/xD6ADSXiVLhiUniyKGA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605562" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:48 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 31/32] KVM: selftests: Add tests for nVMX to vmx_apic_timer_virt Date: Tue, 3 Feb 2026 10:17:14 -0800 Message-ID: <122f9c32d232ca6a6e569ef164161feb64c1f624.1770116051.git.isaku.yamahata@intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Support nVMX for vmx_apic_timer_virt. Signed-off-by: Isaku Yamahata --- .../kvm/x86/vmx_apic_timer_virt_test.c | 207 +++++++++++++++++- 1 file changed, 199 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_test.c b/t= ools/testing/selftests/kvm/x86/vmx_apic_timer_virt_test.c index ea465e9825d8..61aaf6faabce 100644 --- a/tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_apic_timer_virt_test.c @@ -16,6 +16,15 @@ =20 #include =20 +static bool nested; + +#define L2_GUEST_STACK_SIZE 256 +static unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + +static uint64_t l2_tsc_offset; +static uint64_t l2_tsc_multiplier; +static uint64_t l2_tsc_khz; + static uint64_t host_tsc_khz; static uint64_t max_guest_tsc_khz; =20 @@ -143,14 +152,15 @@ static void deadline_int_mask_test(void) =20 static void deadline_hlt_test(void) { + uint64_t tsc_khz =3D nested ? l2_tsc_khz : guest_tsc_khz; uint64_t tsc =3D rdtsc(); /* 1 msec future. */ - uint64_t future =3D tsc + guest_tsc_khz; + uint64_t future =3D tsc + tsc_khz + 1; uint64_t deadlines[] =3D { 1ull, 2ull, /* pick a positive value between [0, tsc]. */ - tsc > guest_tsc_khz ? tsc - guest_tsc_khz : tsc / 2 + 1, + tsc > tsc_khz ? tsc - tsc_khz : tsc / 2 + 1, tsc, /* If overflow, pick near future value > tsc. */ future > tsc ? future : ~0ull / 2 + tsc / 2, @@ -168,10 +178,134 @@ static void guest_code(void) deadline_int_test(); deadline_hlt_test(); =20 - x2apic_write_reg(APIC_LVTT, APIC_LVT_TIMER_TSCDEADLINE | - APIC_LVT_MASKED | TIMER_VECTOR); - deadline_no_int_test(); - deadline_int_mask_test(); + /* L1 doesn't emulate LVTT entry so that mask is not supported. */ + if (!nested) { + x2apic_write_reg(APIC_LVTT, APIC_LVT_TIMER_TSCDEADLINE | + APIC_LVT_MASKED | TIMER_VECTOR); + deadline_no_int_test(); + deadline_int_mask_test(); + } + + if (nested) + vmcall(); + else + GUEST_DONE(); +} + +static void skip_guest_instruction(void) +{ + uint64_t guest_rip, length; + + GUEST_ASSERT(!vmread(GUEST_RIP, &guest_rip)); + GUEST_ASSERT(!vmread(VM_EXIT_INSTRUCTION_LEN, &length)); + + GUEST_ASSERT(!vmwrite(GUEST_RIP, guest_rip + length)); + GUEST_ASSERT(!vmwrite(VM_EXIT_INSTRUCTION_LEN, 0)); +} + +static void l1_guest_code(struct vmx_pages *vmx_pages) +{ + union vmx_ctrl_msr ctls_msr, ctls2_msr; + uint64_t pin, ctls, ctls2, ctls3; + bool launch, done; + + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_vmcs(vmx_pages, guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + /* Check prerequisites */ + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS, &ctls_msr.val)); + GUEST_ASSERT(ctls_msr.clr & CPU_BASED_HLT_EXITING); + GUEST_ASSERT(ctls_msr.clr & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS); + GUEST_ASSERT(ctls_msr.clr & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS); + + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS2, &ctls2_msr.val)); + GUEST_ASSERT(ctls2_msr.clr & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); + + GUEST_ASSERT(!rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS3, &ctls3)); + GUEST_ASSERT(ctls3 & TERTIARY_EXEC_GUEST_APIC_TIMER); + + pin =3D vmreadz(PIN_BASED_VM_EXEC_CONTROL); + pin |=3D PIN_BASED_EXT_INTR_MASK; + GUEST_ASSERT(!vmwrite(PIN_BASED_VM_EXEC_CONTROL, pin)); + + ctls =3D vmreadz(CPU_BASED_VM_EXEC_CONTROL); + ctls |=3D CPU_BASED_HLT_EXITING | CPU_BASED_USE_TSC_OFFSETTING | + CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_TPR_SHADOW | + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS | + CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; + GUEST_ASSERT(!vmwrite(CPU_BASED_VM_EXEC_CONTROL, ctls)); + + /* guest apic timer requires virtual interrutp delivery */ + ctls2 =3D vmreadz(SECONDARY_VM_EXEC_CONTROL); + ctls2 |=3D SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; + vmwrite(SECONDARY_VM_EXEC_CONTROL, ctls2); + + ctls3 =3D vmreadz(TERTIARY_VM_EXEC_CONTROL); + ctls3 |=3D TERTIARY_EXEC_GUEST_APIC_TIMER; + GUEST_ASSERT(!vmwrite(TERTIARY_VM_EXEC_CONTROL, ctls3)); + + /* + * We don't emulate apic registers(including APIC_LVTT) for simplicity. + * Directly set vector for timer interrupt instead. + */ + GUEST_ASSERT(!vmwrite(GUEST_APIC_TIMER_VECTOR, TIMER_VECTOR)); + + GUEST_ASSERT(!vmwrite(TSC_OFFSET, l2_tsc_offset)); + if (l2_tsc_multiplier) { + GUEST_ASSERT(!vmwrite(TSC_MULTIPLIER, l2_tsc_multiplier)); + + GUEST_ASSERT(!vmread(SECONDARY_VM_EXEC_CONTROL, &ctls2)); + ctls2 |=3D SECONDARY_EXEC_TSC_SCALING; + GUEST_ASSERT(!vmwrite(SECONDARY_VM_EXEC_CONTROL, ctls2)); + } else { + GUEST_ASSERT(!vmread(SECONDARY_VM_EXEC_CONTROL, &ctls2)); + ctls2 &=3D ~SECONDARY_EXEC_TSC_SCALING; + GUEST_ASSERT(!vmwrite(SECONDARY_VM_EXEC_CONTROL, ctls2)); + } + + /* launch L2 */ + launch =3D true; + done =3D false; + + while (!done) { + uint64_t reason; + + if (launch) { + GUEST_ASSERT(!vmlaunch()); + launch =3D false; + } else + GUEST_ASSERT(!vmresume()); + + GUEST_ASSERT(!vmread(VM_EXIT_REASON, &reason)); + + switch (reason) { + case EXIT_REASON_HLT: { + uint64_t phy, tsc; + + skip_guest_instruction(); + GUEST_ASSERT(!vmread(GUEST_DEADLINE_PHY, &phy)); + + /* Don't wait for more than 1 sec. */ + tsc =3D rdtsc(); + if (tsc < phy && tsc < ~0ULL - guest_tsc_khz) + GUEST_ASSERT(tsc + guest_tsc_khz * 1000 >=3D tsc); + + while (tsc <=3D phy) + tsc =3D rdtsc(); + break; + } + case EXIT_REASON_VMCALL: + done =3D true; + break; + default: + GUEST_FAIL("unexpected exit reason 0x%lx", reason); + break; + } + } =20 GUEST_DONE(); } @@ -209,9 +343,17 @@ static int test_tsc_deadline(bool tsc_offset, uint64_t= guest_tsc_khz__) struct kvm_vcpu *vcpu; struct kvm_vm *vm; =20 - vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + if (nested) { + vm_vaddr_t vmx_pages_gva =3D 0; + + vm =3D vm_create_with_one_vcpu(&vcpu, l1_guest_code); + vcpu_alloc_vmx(vm, &vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); + } else + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); =20 if (guest_tsc_khz__) { + uint64_t l1_tsc_multiplier; int ret; =20 ret =3D __vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)guest_tsc_khz__); @@ -221,7 +363,34 @@ static int test_tsc_deadline(bool tsc_offset, uint64_t= guest_tsc_khz__) } =20 guest_tsc_khz =3D guest_tsc_khz__; - } + + /* + * Pick same to L1 tsc multplier. Any value to exercise + * corner cases is okay. + */ + l1_tsc_multiplier =3D ((__uint128_t)guest_tsc_khz__ * + (1ULL << 48)) / host_tsc_khz; + l2_tsc_multiplier =3D l1_tsc_multiplier; + /* + * l1_multiplier * l2_multiplier needs to be represented in + * the host. + */ + if ((__uint128_t)l1_tsc_multiplier * l2_tsc_multiplier > + ((__uint128_t)1ULL << (63 + 48))) { + + l2_tsc_multiplier =3D ((__uint128_t)1ULL << (63 + 48)) / + l1_tsc_multiplier; + if (!l2_tsc_multiplier) + l1_tsc_multiplier =3D 1; + } + + l2_tsc_khz =3D ((__uint128_t)l2_tsc_multiplier * guest_tsc_khz__) >> 48; + if (!l2_tsc_khz) { + l2_tsc_multiplier =3D 1ULL << 48; + l2_tsc_khz =3D guest_tsc_khz__; + } + } else + l2_tsc_khz =3D host_tsc_khz; =20 if (tsc_offset) { uint64_t offset; @@ -237,6 +406,9 @@ static int test_tsc_deadline(bool tsc_offset, uint64_t = guest_tsc_khz__) offset =3D -rdtsc(); vcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET, &offset); + + /* Pick a non-zero value */ + l2_tsc_offset =3D offset; } =20 vcpu_set_cpuid_feature(vcpu, X86_FEATURE_TSC_DEADLINE_TIMER); @@ -245,10 +417,18 @@ static int test_tsc_deadline(bool tsc_offset, uint64_= t guest_tsc_khz__) =20 sync_global_to_guest(vm, host_tsc_khz); sync_global_to_guest(vm, guest_tsc_khz); + sync_global_to_guest(vm, nested); + sync_global_to_guest(vm, l2_tsc_offset); + sync_global_to_guest(vm, l2_tsc_multiplier); + sync_global_to_guest(vm, l2_tsc_khz); run_vcpu(vcpu); =20 kvm_vm_free(vm); =20 + l2_tsc_offset =3D 0; + l2_tsc_multiplier =3D 0; + l2_tsc_khz =3D 0; + return 0; } =20 @@ -313,5 +493,16 @@ int main(int argc, char *argv[]) =20 test(); =20 + ctls.val =3D kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + if (ctls.clr & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) + ctls3 =3D kvm_get_feature_msr(MSR_IA32_VMX_PROCBASED_CTLS3); + else + ctls3 =3D 0; + if (kvm_cpu_has(X86_FEATURE_VMX) && + ctls3 & TERTIARY_EXEC_GUEST_APIC_TIMER) { + nested =3D true; + test(); + } + return 0; } --=20 2.45.2 From nobody Sat Feb 7 18:15:58 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 83D243EFD03; Tue, 3 Feb 2026 18:17:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.10 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142678; cv=none; b=gtnSxPS+snTlCnvecMJjrbrZ0W1f6ZzqeKfxO6dMPANQY5A/+DOUJ3DWAa7a7ox2VdPMvHK1FrTcCeqsbCcIme4EZdqcIIRJIxaEe4rsIIfBXxxoNj0XkS1sh2f9usqJO9GT+Flk9XY7i1NHQDo46vs52H95N7gDdwjj/DKp9po= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770142678; c=relaxed/simple; bh=kPME7/YSCiLjgGM8a4soCxooFyr40ldcGoCCSis39ac=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KDcofEIuGtwICjSLFjWcMqdRwfyN/ItW3p2CDD8XrX0sh3E2VJtcXs0uO2cg9VIw/5tjemiTSgQvTdRTzUNV0Ks5q2Io9Z520QS9VOE1uILXHdUh9CFwayksxKmHycenqtCzfqgf/Og5h/dRXaQYy9Gkg+q5FGcycfZAYxWbng0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=ejK3WZQp; arc=none smtp.client-ip=198.175.65.10 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="ejK3WZQp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1770142677; x=1801678677; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kPME7/YSCiLjgGM8a4soCxooFyr40ldcGoCCSis39ac=; b=ejK3WZQpY3n/PR4h3AK8gXIJNLnIiUjRY9Aa8EaGiPqwLBJgJZPUlyGR 3XWekEXP0wuo0AGt73oG/qm/aLtcASgruxz51SwFRrkhXpAeckL+BAEsd 2P50ghffOcUT7K71kaKm6G2AnU/K8DyUYzZBvBwX5YjeO2AEd5z/O2b6q S8DxnIiWK7iMvoMiL1sPzkYLBn6UTuB2Z3eDDEzEXOyQf1343VbdZn2ls Vp07brJc7WXyhJLlsO3SZxKDR4V41ZmNv/VKlmS7IGA21dzFAoos39orW ER9efoweN6XvFY2H47z9pizRFyXg01tYpc+R/YV3BSE1g+gC+dixtHOuH A==; X-CSE-ConnectionGUID: 2fJ7IJ8qQ4yySXW9BtBDkw== X-CSE-MsgGUID: Zhmc2xpzRHyAN3BWzncqfg== X-IronPort-AV: E=McAfee;i="6800,10657,11691"; a="88745893" X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="88745893" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:50 -0800 X-CSE-ConnectionGUID: azEcP9f/TQyeeTnrI1MIBQ== X-CSE-MsgGUID: q/oKJxdrTDe16q/KXRNXIw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,271,1763452800"; d="scan'208";a="209605567" Received: from khuang2-desk.gar.corp.intel.com (HELO localhost) ([10.124.221.188]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2026 10:17:49 -0800 From: isaku.yamahata@intel.com To: kvm@vger.kernel.org Cc: isaku.yamahata@intel.com, isaku.yamahata@gmail.com, Paolo Bonzini , Sean Christopherson , linux-kernel@vger.kernel.org Subject: [PATCH 32/32] Documentation: KVM: x86: Update documentation of struct vmcs12 Date: Tue, 3 Feb 2026 10:17:15 -0800 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Isaku Yamahata Update struct vmcs12 in the documentation to match the current implementation. Signed-off-by: Isaku Yamahata --- Documentation/virt/kvm/x86/nested-vmx.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Documentation/virt/kvm/x86/nested-vmx.rst b/Documentation/virt= /kvm/x86/nested-vmx.rst index ac2095d41f02..561fd0970f54 100644 --- a/Documentation/virt/kvm/x86/nested-vmx.rst +++ b/Documentation/virt/kvm/x86/nested-vmx.rst @@ -113,7 +113,14 @@ struct shadow_vmcs is ever changed. u64 guest_pdptr3; u64 host_ia32_pat; u64 host_ia32_efer; - u64 padding64[8]; /* room for future expansion */ + u64 vmread_bitmap; + u64 vmwrite_bitmap; + u64 vm_function_control; + u64 eptp_list_address; + u64 pml_address; + u64 encls_exiting_bitmap; + u64 tsc_multiplier; + u64 tertiary_vm_exec_control; natural_width cr0_guest_host_mask; natural_width cr4_guest_host_mask; natural_width cr0_read_shadow; @@ -217,6 +224,10 @@ struct shadow_vmcs is ever changed. u16 host_fs_selector; u16 host_gs_selector; u16 host_tr_selector; + u16 guest_pml_index; + u16 virtual_timer_vector; + u64 guest_deadline; + u64 guest_deadline_shadow; }; =20 =20 --=20 2.45.2