lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <18f54797d5a705719a8fb8dfce74fc4cfb5d1e18.1770116051.git.isaku.yamahata@intel.com>
Date: Tue,  3 Feb 2026 10:17:08 -0800
From: isaku.yamahata@...el.com
To: kvm@...r.kernel.org
Cc: isaku.yamahata@...el.com,
	isaku.yamahata@...il.com,
	Paolo Bonzini <pbonzini@...hat.com>,
	Sean Christopherson <seanjc@...gle.com>,
	linux-kernel@...r.kernel.org
Subject: [PATCH 25/32] KVM: selftests: Add nVMX support to timer_latency test case

From: Isaku Yamahata <isaku.yamahata@...el.com>

Support nVMX for the timer_latency test case to exercise the nVMX APIC
timer virtualization.

Signed-off-by: Isaku Yamahata <isaku.yamahata@...el.com>
---
 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
 
+/*
+ * Definitions of Tertiary Processor-Based VM-Execution Controls.
+ * It's 64 bit unlike primary/secondary processor based vm-execution controls.
+ */
+#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		= 0x00000000,
 	POSTED_INTR_NV			= 0x00000002,
+	GUEST_APIC_TIMER_VECTOR         = 0x0000000a,
 	GUEST_ES_SELECTOR		= 0x00000800,
 	GUEST_CS_SELECTOR		= 0x00000802,
 	GUEST_SS_SELECTOR		= 0x00000804,
@@ -163,6 +171,8 @@ enum vmcs_field {
 	ENCLS_EXITING_BITMAP_HIGH	= 0x0000202F,
 	TSC_MULTIPLIER			= 0x00002032,
 	TSC_MULTIPLIER_HIGH		= 0x00002033,
+	TERTIARY_VM_EXEC_CONTROL        = 0x00002034,
+	TERTIARY_VM_EXEC_CONTROL_HIGH   = 0x00002035,
 	GUEST_PHYSICAL_ADDRESS		= 0x00002400,
 	GUEST_PHYSICAL_ADDRESS_HIGH	= 0x00002401,
 	VMCS_LINK_POINTER		= 0x00002800,
diff --git a/tools/testing/selftests/kvm/x86/timer_latency.c b/tools/testing/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];
 
 #define LOCAL_TIMER_VECTOR	0xec
 
@@ -30,6 +34,7 @@ struct options {
 	bool use_oneshot_timer;
 	bool use_x2apic;
 	bool use_poll;
+	bool nested;
 
 	uint64_t timer_inc_ns;
 	uint64_t allowed_timer_latency_ns;
@@ -304,6 +309,65 @@ static void guest_code(void)
 	GUEST_DONE();
 }
 
+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 = vmreadz(PIN_BASED_VM_EXEC_CONTROL);
+	pin |= PIN_BASED_EXT_INTR_MASK;
+	GUEST_ASSERT(!vmwrite(PIN_BASED_VM_EXEC_CONTROL, pin));
+
+	ctls = vmreadz(CPU_BASED_VM_EXEC_CONTROL);
+	ctls |= 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 = vmreadz(SECONDARY_VM_EXEC_CONTROL);
+	ctls2 |= SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE |
+		SECONDARY_EXEC_APIC_REGISTER_VIRT |
+		SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;
+	vmwrite(SECONDARY_VM_EXEC_CONTROL, ctls2);
+
+	ctls3 = vmreadz(TERTIARY_VM_EXEC_CONTROL);
+	ctls3 |= 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) == 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);
 }
 
+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;
 
-	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	if (options.nested) {
+		vm_vaddr_t vmx_pages_gva = 0;
+		struct vmx_pages *vmx;
+
+		vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code);
+
+		vmx = 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 = 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("");
 
 	exit(EXIT_SUCCESS);
@@ -514,8 +608,10 @@ int main(int argc, char **argv)
 {
 	int opt;
 	unsigned int duration = TEST_DURATION_DEFAULT_IN_SEC;
+	bool nested_only = false;
+	bool no_nest = false;
 
-	while ((opt = getopt(argc, argv, "hld:p:a:otxXP")) != -1) {
+	while ((opt = getopt(argc, argv, "hld:p:a:otxXPnN")) != -1) {
 		switch (opt) {
 		case 'l':
 			options.use_poll = true;
@@ -553,6 +649,15 @@ int main(int argc, char **argv)
 			options.print_result = true;
 			break;
 
+		case 'n':
+			nested_only = true;
+			no_nest = false;
+			break;
+		case 'N':
+			nested_only = false;
+			no_nest = 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));
 
-	run_test(duration);
+	if (!nested_only) {
+		options.nested = false;
+		run_test(duration);
+	}
+
+	if (!no_nest) {
+		union vmx_ctrl_msr ctls;
+		uint64_t ctls3;
+
+		ctls.val = kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS);
+		TEST_REQUIRE(ctls.clr & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS);
+
+		ctls3 = 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 = true;
+		options.use_oneshot_timer = false;
+
+		options.nested = true;
+		run_test(duration);
+	}
 
 	return 0;
 }
-- 
2.45.2


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ