From nobody Thu Apr 2 06:28:45 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.12]) (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 262DC42B726; Thu, 5 Mar 2026 17:44:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.12 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772732692; cv=none; b=Je5bF5lPoweFZDrwkb/ArfLCqA73HAR183sdb6NqiFM/vtPAF7ZwcJganMDV5tZsecJYMBw8yoarwP1Z7U4ocutOolbVU4ChC8FHKm4RF9vfaX7/1YKI+9eiJfbyb/yqoHF6i4ZcdNRgh8oOIWi64+V+Uef4dLZa8bi0lU9puoA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772732692; c=relaxed/simple; bh=spcndoUGI5XlK+jmdgdjo62MVw2tY3NFyl+mMfxYVqs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HWRv/b0+MvaC5R5EkL92hVRXre45sUv+N177Vs4tJXI2Uk1CzJaRK1b6a6THqhOlBLMeEyL4bqzbNX8LqR5j5b6htFP7AD7AuDZZXlVIqBw5Z2AZy6mfc2D4IvW0DSgOnvAk03MUBOncIlCSID8q+2raW7XpBBeBXp9Z0EkYYT4= 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=TjIkdH++; arc=none smtp.client-ip=192.198.163.12 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="TjIkdH++" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1772732691; x=1804268691; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=spcndoUGI5XlK+jmdgdjo62MVw2tY3NFyl+mMfxYVqs=; b=TjIkdH++le2LEn/wfHFJc0QYMuSaD977X5XCrg5SkAwom5lVTB2KGAW+ SgOQpgC5j6i78B/UNtePyStXiyXGnfcDX3hF1OWfoF92KlXrD/wdSqIhc WXZ+JkjuoDJC2LkBsPwjqwKod6LNdYpXxQ7b3H83JXbUaXraldgQoV4WG 1ECgcMPf1d/pcxWWL2Y/UHLd3d1ZmNpSNhie1m74atgJjNdx3OyPgNPx2 s2Zl1IhJVYtPxYMkoyNu2toFkcEFwfrUxrMNilxwCJQx+hGxNtS+FNlzi MpmbNlBrF1rSRekoSuZUpWrWqmwL6Inw2Wv3E7tlJEJ+cNKgeZ3NemEAt A==; X-CSE-ConnectionGUID: d+342vkIQEq1GU9mPQJT8A== X-CSE-MsgGUID: tPNJNpPDSk+REsEguHAN0w== X-IronPort-AV: E=McAfee;i="6800,10657,11720"; a="77701140" X-IronPort-AV: E=Sophos;i="6.23,103,1770624000"; d="scan'208";a="77701140" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by fmvoesa106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Mar 2026 09:44:51 -0800 X-CSE-ConnectionGUID: 2dDjGYQLT1mFQvFSfx/Ssg== X-CSE-MsgGUID: LdFyQG0lTO+j6WL3rwMnrA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,103,1770624000"; d="scan'208";a="256647666" Received: from mdroper-mobl2.amr.corp.intel.com (HELO localhost) ([10.124.220.244]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Mar 2026 09:44:51 -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 v2 29/36] KVM: selftests: Add tests nested state of APIC timer virtualization Date: Thu, 5 Mar 2026 09:44:09 -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 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 --- Changes: v1 -> v2: - format fixes. --- tools/testing/selftests/kvm/include/x86/vmx.h | 4 + .../selftests/kvm/x86/nested_set_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 4be103c7b367..7a8fcf6f58ff 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/nested_set_state_test.c b/tool= s/testing/selftests/kvm/x86/nested_set_state_test.c index 9651282df4d3..ed668a006c06 100644 --- a/tools/testing/selftests/kvm/x86/nested_set_state_test.c +++ b/tools/testing/selftests/kvm/x86/nested_set_state_test.c @@ -24,6 +24,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) { @@ -84,6 +86,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 |=3D X86_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. */ @@ -343,6 +572,8 @@ void test_svm_nested_state(struct kvm_vcpu *vcpu) TEST_ASSERT_EQ(state->hdr.svm.vmcb_pa, 0); TEST_ASSERT_EQ(state->flags, KVM_STATE_NESTED_GIF_SET); =20 + test_vmx_tertiary_ctls(vcpu, state, state_sz); + free(state); } =20 @@ -353,6 +584,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_cpu_has(X86_FEATURE_VMX) || kvm_cpu_has(X86_FEATURE_SVM)); --=20 2.45.2