diff mbox series

[v6,3/3] KVM: selftests: Add self IPI HLT test

Message ID 20250128124812.7324-4-manali.shukla@amd.com (mailing list archive)
State New
Headers show
Series Add support for the Idle HLT intercept feature | expand

Commit Message

Manali Shukla Jan. 28, 2025, 12:48 p.m. UTC
From: Manali Shukla <Manali.Shukla@amd.com>

The IPI HLT test simulates a scenario where a pending event is present
while the HLT instruction is executed.

This test evaluates the idle HLT intercept feature of the AMD
architecture, if available. If the feature is not present, the test
exercises halt-exits/guest-entry for pending interrupts.  It can be
extended in the future to include cross-vCPU IPI testing.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Manali Shukla <Manali.Shukla@amd.com>
---
 tools/testing/selftests/kvm/Makefile.kvm      |  1 +
 .../selftests/kvm/include/x86/processor.h     |  1 +
 tools/testing/selftests/kvm/ipi_hlt_test.c    | 81 +++++++++++++++++++
 3 files changed, 83 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/ipi_hlt_test.c

Comments

Neeraj Upadhyay Jan. 29, 2025, 5:26 a.m. UTC | #1
On 1/28/2025 6:18 PM, Manali Shukla wrote:
> From: Manali Shukla <Manali.Shukla@amd.com>
> 
> The IPI HLT test simulates a scenario where a pending event is present
> while the HLT instruction is executed.
> 
> This test evaluates the idle HLT intercept feature of the AMD
> architecture, if available. If the feature is not present, the test
> exercises halt-exits/guest-entry for pending interrupts.  It can be
> extended in the future to include cross-vCPU IPI testing.
> 
> Suggested-by: Sean Christopherson <seanjc@google.com>
> Signed-off-by: Manali Shukla <Manali.Shukla@amd.com>
> ---

Reviewed-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>


- Neeraj
diff mbox series

Patch

diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 4277b983cace..d6eda8c19fed 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -135,6 +135,7 @@  TEST_GEN_PROGS_x86 += steal_time
 TEST_GEN_PROGS_x86 += kvm_binary_stats_test
 TEST_GEN_PROGS_x86 += system_counter_offset_test
 TEST_GEN_PROGS_x86 += pre_fault_memory_test
+TEST_GEN_PROGS_x86 += ipi_hlt_test
 
 # Compiled outputs used by test targets
 TEST_GEN_PROGS_EXTENDED_x86 += x86/nx_huge_pages_test
diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h
index e28c3e462fa7..fe0ed8d33e37 100644
--- a/tools/testing/selftests/kvm/include/x86/processor.h
+++ b/tools/testing/selftests/kvm/include/x86/processor.h
@@ -200,6 +200,7 @@  struct kvm_x86_cpu_feature {
 #define X86_FEATURE_PAUSEFILTER         KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 10)
 #define X86_FEATURE_PFTHRESHOLD         KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 12)
 #define	X86_FEATURE_VGIF		KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 16)
+#define X86_FEATURE_IDLE_HLT		KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 30)
 #define X86_FEATURE_SEV			KVM_X86_CPU_FEATURE(0x8000001F, 0, EAX, 1)
 #define X86_FEATURE_SEV_ES		KVM_X86_CPU_FEATURE(0x8000001F, 0, EAX, 3)
 #define	X86_FEATURE_PERFMON_V2		KVM_X86_CPU_FEATURE(0x80000022, 0, EAX, 0)
diff --git a/tools/testing/selftests/kvm/ipi_hlt_test.c b/tools/testing/selftests/kvm/ipi_hlt_test.c
new file mode 100644
index 000000000000..449845fa2a82
--- /dev/null
+++ b/tools/testing/selftests/kvm/ipi_hlt_test.c
@@ -0,0 +1,81 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  Copyright (C) 2024 Advanced Micro Devices, Inc.
+ *
+ */
+#include <kvm_util.h>
+#include <processor.h>
+#include <test_util.h>
+#include "apic.h"
+
+#define INTR_VECTOR     0x30
+#define NUM_ITERATIONS   1000
+
+static bool irq_received;
+
+/*
+ * The guest code instruments the scenario where there is a V_INTR pending
+ * event available while hlt instruction is executed.
+ */
+
+static void guest_code(void)
+{
+	uint64_t icr_val;
+	int i;
+
+	x2apic_enable();
+
+	icr_val = (APIC_DEST_SELF | APIC_INT_ASSERT | INTR_VECTOR);
+
+	for (i = 0; i < NUM_ITERATIONS; i++) {
+		cli();
+		x2apic_write_reg(APIC_ICR, icr_val);
+		safe_halt();
+		GUEST_ASSERT(READ_ONCE(irq_received));
+		WRITE_ONCE(irq_received, false);
+	}
+	GUEST_DONE();
+}
+
+static void guest_intr_handler(struct ex_regs *regs)
+{
+	WRITE_ONCE(irq_received, true);
+	x2apic_write_reg(APIC_EOI, 0x00);
+}
+
+int main(int argc, char *argv[])
+{
+	struct kvm_vm *vm;
+	struct kvm_vcpu *vcpu;
+	struct ucall uc;
+	uint64_t halt_exits;
+
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_BINARY_STATS_FD));
+
+	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+	vm_install_exception_handler(vm, INTR_VECTOR, guest_intr_handler);
+
+	vcpu_run(vcpu);
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+
+	halt_exits = vcpu_get_stat(vcpu, halt_exits);
+
+	switch (get_ucall(vcpu, &uc)) {
+	case UCALL_ABORT:
+		REPORT_GUEST_ASSERT(uc);
+		/* NOT REACHED */
+	case UCALL_DONE:
+		break;
+	default:
+		TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
+	}
+
+	if (kvm_cpu_has(X86_FEATURE_IDLE_HLT))
+		TEST_ASSERT_EQ(halt_exits, 0);
+	else
+		TEST_ASSERT_EQ(halt_exits, NUM_ITERATIONS);
+
+	kvm_vm_free(vm);
+	return 0;
+}