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: <20250228093024.114983-29-Neeraj.Upadhyay@amd.com>
Date: Fri, 28 Feb 2025 15:00:21 +0530
From: Neeraj Upadhyay <Neeraj.Upadhyay@....com>
To: <kvm@...r.kernel.org>, <seanjc@...gle.com>, <pbonzini@...hat.com>
CC: <linux-kernel@...r.kernel.org>, <Thomas.Lendacky@....com>,
	<nikunj@....com>, <Santosh.Shukla@....com>, <Vasant.Hegde@....com>,
	<Suravee.Suthikulpanit@....com>, <bp@...en8.de>, <David.Kaplan@....com>,
	<huibo.wang@....com>, <naveen.rao@....com>, <pgonda@...gle.com>,
	<linux-kselftest@...r.kernel.org>, <shuah@...nel.org>
Subject: [RFC PATCH 28/31] KVM: selftests: Add IOAPIC tests for Secure AVIC

Extend Secure AVIC tests to test edge and level
ioapic based interrupt flow. In addition, test
RTC_GSI IOAPIC line which has special casing
in KVM. Add new interfaces to read and write to
IOAPIC redirect tables.

Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@....com>
---
 .../testing/selftests/kvm/include/kvm_util.h  |   1 +
 .../testing/selftests/kvm/include/x86/apic.h  |  49 ++++
 .../testing/selftests/kvm/include/x86/savic.h |   1 +
 tools/testing/selftests/kvm/lib/kvm_util.c    |  17 ++
 .../testing/selftests/kvm/lib/x86/processor.c |   2 +-
 tools/testing/selftests/kvm/lib/x86/savic.c   |  11 +
 tools/testing/selftests/kvm/x86/savic_test.c  | 270 +++++++++++++++++-
 7 files changed, 347 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 7f97bade5797..33326c5975c0 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -861,6 +861,7 @@ void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu);
 void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...);
 
 void kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level);
+void kvm_irq_line_status(struct kvm_vm *vm, uint32_t irq, int level);
 int _kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level);
 
 #define KVM_MAX_IRQ_ROUTES		4096
diff --git a/tools/testing/selftests/kvm/include/x86/apic.h b/tools/testing/selftests/kvm/include/x86/apic.h
index af555638086f..765c463dff33 100644
--- a/tools/testing/selftests/kvm/include/x86/apic.h
+++ b/tools/testing/selftests/kvm/include/x86/apic.h
@@ -12,6 +12,7 @@
 #include "ucall_common.h"
 
 #define APIC_DEFAULT_GPA		0xfee00000ULL
+#define IOAPIC_DEFAULT_GPA		0xfec00000ULL
 
 /* APIC base address MSR and fields */
 #define MSR_IA32_APICBASE		0x0000001b
@@ -122,5 +123,53 @@ static inline void x2apic_write_reg_fault(unsigned int reg, uint64_t value)
 		       APIC_BASE_MSR + (reg >> 4), value, fault);
 }
 
+struct ioapic_redirect_entry {
+	uint8_t vector;
+	uint8_t delivery_mode:3;
+	uint8_t dest_mode:1;
+	uint8_t delivery_status:1;
+	uint8_t polarity:1;
+	uint8_t remote_irr:1;
+	uint8_t trig_mode:1;
+	uint8_t mask:1;
+	uint8_t reserve:7;
+	uint8_t reserved[4];
+	uint8_t dest_id;
+};
+
+enum trigger_mode {
+	TRIGGER_EDGE = 0,
+	TRIGGER_LEVEL,
+	TRIGGER_MAX,
+};
+
+static void *ioapic_addr = (void *)IOAPIC_DEFAULT_GPA;
+
+static inline void ioapic_write_reg(uint32_t reg, uint32_t val)
+{
+	*(volatile uint32_t *)ioapic_addr = reg;
+	*(volatile u32 *)(ioapic_addr + 0x10) = val;
+}
+
+static inline void ioapic_write_redir(unsigned int line, struct ioapic_redirect_entry e)
+{
+	ioapic_write_reg(0x10 + line * 2 + 0, ((uint32_t *)&e)[0]);
+	ioapic_write_reg(0x10 + line * 2 + 1, ((uint32_t *)&e)[1]);
+}
+
+static inline uint32_t ioapic_read_reg(unsigned int reg)
+{
+	*(volatile uint32_t *)ioapic_addr = reg;
+	return *(volatile uint32_t *)(ioapic_addr + 0x10);
+}
+
+static inline struct ioapic_redirect_entry ioapic_read_redir(unsigned int line)
+{
+	struct ioapic_redirect_entry e;
+
+	((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0);
+	((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1);
 
+	return e;
+}
 #endif /* SELFTEST_KVM_APIC_H */
diff --git a/tools/testing/selftests/kvm/include/x86/savic.h b/tools/testing/selftests/kvm/include/x86/savic.h
index 33f19f5e39b3..73965edfef5c 100644
--- a/tools/testing/selftests/kvm/include/x86/savic.h
+++ b/tools/testing/selftests/kvm/include/x86/savic.h
@@ -21,4 +21,5 @@ void savic_enable(void);
 int savic_nr_pages_required(uint64_t page_size);
 void savic_vc_handler(struct ex_regs *regs);
 struct guest_apic_page *get_guest_apic_page(void);
+void savic_allow_vector(int vec);
 #endif
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 93b8e2ccc7b3..900fbad7258c 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1861,6 +1861,23 @@ void kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level)
 	TEST_ASSERT(ret >= 0, KVM_IOCTL_ERROR(KVM_IRQ_LINE, ret));
 }
 
+int _kvm_irq_line_status(struct kvm_vm *vm, uint32_t irq, int level)
+{
+	struct kvm_irq_level irq_level = {
+		.irq    = irq,
+		.level  = level,
+	};
+
+	return __vm_ioctl(vm, KVM_IRQ_LINE_STATUS, &irq_level);
+}
+
+void kvm_irq_line_status(struct kvm_vm *vm, uint32_t irq, int level)
+{
+	int ret = _kvm_irq_line_status(vm, irq, level);
+
+	TEST_ASSERT(ret >= 0, KVM_IOCTL_ERROR(KVM_IRQ_LINE_STATUS, ret));
+}
+
 struct kvm_irq_routing *kvm_gsi_routing_create(void)
 {
 	struct kvm_irq_routing *routing;
diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c
index 09474be27986..da2f8d974f60 100644
--- a/tools/testing/selftests/kvm/lib/x86/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86/processor.c
@@ -229,7 +229,7 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level)
 		    "PTE already present for 4k page at vaddr: 0x%lx", vaddr);
 	*pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK);
 
-	if (paddr == APIC_DEFAULT_GPA) {
+	if (paddr == APIC_DEFAULT_GPA || paddr == IOAPIC_DEFAULT_GPA) {
 		*pte |= vm->arch.s_bit;
 		return;
 	}
diff --git a/tools/testing/selftests/kvm/lib/x86/savic.c b/tools/testing/selftests/kvm/lib/x86/savic.c
index c637e486b6e8..ee2d6b66d6ce 100644
--- a/tools/testing/selftests/kvm/lib/x86/savic.c
+++ b/tools/testing/selftests/kvm/lib/x86/savic.c
@@ -46,6 +46,7 @@ enum lapic_lvt_entry {
 #define SVM_EXIT_AVIC_UNACCELERATED_ACCESS      0x402
 #define SVM_EXIT_AVIC_INCOMPLETE_IPI            0x401
 
+#define SAVIC_ALLOWED_IRR               (APIC_IRR + 0x4)
 #define SAVIC_NMI_REQ_OFFSET            0x278
 
 /*
@@ -108,6 +109,16 @@ struct guest_apic_page *get_guest_apic_page(void)
 	return &apic_page_pool->guest_apic_page[x2apic_read_reg(APIC_ID)];
 }
 
+void savic_allow_vector(int vec)
+{
+	struct guest_apic_page *apage = get_guest_apic_page();
+
+	savic_write_reg(apage, SAVIC_ALLOWED_IRR + APIC_REG_OFF(vec),
+			savic_read_reg(apage, SAVIC_ALLOWED_IRR + APIC_REG_OFF(vec)) |
+			BIT_ULL(APIC_VEC_POS(vec)));
+
+}
+
 /*
  * Write APIC reg offset in the guest APIC backing page.
  *
diff --git a/tools/testing/selftests/kvm/x86/savic_test.c b/tools/testing/selftests/kvm/x86/savic_test.c
index 5c52254f7b1c..3399ccefc37d 100644
--- a/tools/testing/selftests/kvm/x86/savic_test.c
+++ b/tools/testing/selftests/kvm/x86/savic_test.c
@@ -14,9 +14,15 @@
 #include "savic.h"
 
 #define NR_SAVIC_VCPUS	1
-#define IDLE_HLT_INTR_VECTOR     0x30
 #define NUM_ITERATIONS 2000
 
+#define IDLE_HLT_INTR_VECTOR     0x30
+#define IOAPIC_VECTOR_START      0x81
+#define IOAPIC_NUM_EDGE_VECTORS 2
+#define IOAPIC_NUM_LEVEL_VECTORS 2
+#define RTC_GSI	8
+#define RTC_GSI_IRQ 0x85
+
 static bool irq_received;
 static struct kvm_vcpu *vcpus[NR_SAVIC_VCPUS];
 static pthread_t threads[NR_SAVIC_VCPUS];
@@ -34,6 +40,8 @@ enum savic_test_state {
 	SAVIC_TEST_STATE(SAVIC_EN),
 	SAVIC_TEST_STATE(SAVIC_APIC_MSR_ACCESSES),
 	SAVIC_TEST_STATE(SAVIC_IDLE_HALT),
+	SAVIC_TEST_STATE(SAVIC_IOAPIC),
+	SAVIC_TEST_STATE(SAVIC_IOAPIC2),
 };
 
 /* APIC reg values written by host. */
@@ -108,6 +116,17 @@ enum context {
 
 static struct kvm_lapic_state apic_state[NR_SAVIC_VCPUS];
 
+/* Data struct shared between host main thread and vCPUs */
+struct test_data_page {
+	uint64_t ioapic_eirq1_count;
+	uint64_t ioapic_eirq2_count;
+	uint64_t ioapic_lirq1_count;
+	uint64_t ioapic_lirq2_count;
+	uint64_t ioapic_rtc_gsi_irq_count;
+};
+
+static struct test_data_page *test_data[NR_SAVIC_VCPUS];
+
 /*
  * Write APIC reg from host or guest context.
  *
@@ -519,6 +538,177 @@ static void guest_savic_idle_halt(int id)
 	}
 }
 
+static void _ioapic_level_irq_handler(int vec)
+{
+	uint32_t isr, tmr;
+	int offset, pos;
+
+	offset = APIC_REG_OFF(vec);
+	pos = APIC_VEC_POS(vec);
+	isr = savic_hv_read_reg(APIC_ISR + offset);
+	tmr = savic_hv_read_reg(APIC_TMR + offset);
+
+	__GUEST_ASSERT(tmr & BIT_ULL(pos),
+		"IOAPIC level vector %d trigger mode in not set in host TMR: %x",
+		vec, tmr);
+	__GUEST_ASSERT(isr & BIT_ULL(pos),
+			"IOAPIC level vector %d in not set in host ISR: %x",
+			vec, isr);
+
+	x2apic_write_reg(APIC_EOI, 0x00);
+	savic_hv_write_reg(APIC_EOI, 0);
+
+	isr = savic_hv_read_reg(APIC_ISR + offset);
+	__GUEST_ASSERT(!(isr & BIT_ULL(pos)),
+		"IOAPIC level vector %d set in host ISR after EOI",
+		vec);
+}
+
+static void ioapic_level_irq1_intr_handler(struct ex_regs *regs)
+{
+	struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)];
+	int vec;
+
+	vec = IOAPIC_VECTOR_START + IOAPIC_NUM_EDGE_VECTORS;
+	WRITE_ONCE(data->ioapic_lirq1_count, data->ioapic_lirq1_count + 1);
+	_ioapic_level_irq_handler(vec);
+}
+
+static void ioapic_level_irq2_intr_handler(struct ex_regs *regs)
+{
+	struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)];
+	int vec;
+
+	vec = IOAPIC_VECTOR_START + IOAPIC_NUM_EDGE_VECTORS + 1;
+	WRITE_ONCE(data->ioapic_lirq2_count, data->ioapic_lirq2_count + 1);
+	_ioapic_level_irq_handler(vec);
+}
+
+static void ioapic_edge_irq1_intr_handler(struct ex_regs *regs)
+{
+	struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)];
+
+	WRITE_ONCE(data->ioapic_eirq1_count, data->ioapic_eirq1_count + 1);
+	x2apic_write_reg(APIC_EOI, 0x00);
+}
+
+static void ioapic_edge_irq2_intr_handler(struct ex_regs *regs)
+{
+	struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)];
+
+	WRITE_ONCE(data->ioapic_eirq2_count, data->ioapic_eirq2_count + 1);
+	x2apic_write_reg(APIC_EOI, 0x00);
+}
+
+static void ioapic_rtc_gsi_intr_handler(struct ex_regs *regs)
+{
+	struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)];
+
+	WRITE_ONCE(data->ioapic_rtc_gsi_irq_count, data->ioapic_rtc_gsi_irq_count + 1);
+	x2apic_write_reg(APIC_EOI, 0x00);
+}
+
+static void __savic_ioapic(int count)
+{
+	struct test_data_page *data = test_data[x2apic_read_reg(APIC_ID)];
+	int vec = IOAPIC_VECTOR_START;
+
+	__GUEST_ASSERT(READ_ONCE(data->ioapic_eirq1_count) == count,
+			"Invalid ioapic edge irq %d count: %ld, expected: %d",
+			vec, READ_ONCE(data->ioapic_eirq1_count), count);
+	__GUEST_ASSERT(READ_ONCE(data->ioapic_eirq2_count) == count,
+			"Invalid ioapic edge irq %d count: %ld, expected: %d",
+			vec + 1, READ_ONCE(data->ioapic_eirq2_count), count);
+	__GUEST_ASSERT(READ_ONCE(data->ioapic_lirq1_count) == count,
+			"Invalid ioapic level irq %d count: %ld, expected: %d",
+			vec + 2, READ_ONCE(data->ioapic_lirq1_count), count);
+	__GUEST_ASSERT(READ_ONCE(data->ioapic_lirq2_count) == count,
+			"Invalid ioapic level irq %d count: %ld, expected: %d",
+			vec + 3, READ_ONCE(data->ioapic_lirq2_count), count);
+	__GUEST_ASSERT(READ_ONCE(data->ioapic_rtc_gsi_irq_count) == count,
+			"Invalid ioapic RTC irq %d count: %ld, expected: %d",
+			RTC_GSI_IRQ, READ_ONCE(data->ioapic_rtc_gsi_irq_count),
+			count);
+}
+
+static void savic_ioapic(int id)
+{
+	__savic_ioapic(1);
+}
+
+static void savic_ioapic2(int id)
+{
+	__savic_ioapic(2);
+}
+
+static void ioapic_set_redir(unsigned int line, unsigned int vec,
+			     enum trigger_mode trig_mode)
+{
+	struct ioapic_redirect_entry e = {
+		.vector = vec,
+		.delivery_mode = 0,
+		.dest_mode = 0,
+		.trig_mode = trig_mode,
+		.mask = 0,
+		.dest_id = 0,
+		.delivery_status = 0,
+		.remote_irr = 0,
+	};
+
+	ioapic_write_redir(line, e);
+}
+
+static void guest_setup_ioapic(int id)
+{
+	int vec = IOAPIC_VECTOR_START;
+	struct ioapic_redirect_entry e;
+	int i, line = 0;
+
+	for (i = 0; i < IOAPIC_NUM_EDGE_VECTORS; i++) {
+		ioapic_set_redir(line, vec, TRIGGER_EDGE);
+		e = ioapic_read_redir(line);
+		__GUEST_ASSERT(
+			e.vector == vec && e.trig_mode == TRIGGER_EDGE &&
+			e.dest_id == 0,
+			"Invalid IOAPIC redir entry for line : %d, trig_mode: %d vector: %d",
+			line, e.trig_mode, e.vector);
+		vec++;
+		line++;
+	}
+
+	for (i = 0; i < IOAPIC_NUM_LEVEL_VECTORS; i++) {
+		ioapic_set_redir(line, vec, TRIGGER_LEVEL);
+		e = ioapic_read_redir(line);
+		__GUEST_ASSERT(
+			e.vector == vec && e.trig_mode == TRIGGER_LEVEL &&
+			e.dest_id == 0,
+			"Invalid IOAPIC redir entry for line : %d, trig_mode: %d vector: %d",
+			line, e.trig_mode, e.vector);
+		line++;
+		vec++;
+	}
+
+	vec = RTC_GSI_IRQ;
+	line = RTC_GSI;
+	ioapic_set_redir(line, vec, TRIGGER_EDGE);
+	e = ioapic_read_redir(line);
+	__GUEST_ASSERT(
+		e.vector == vec && e.trig_mode == TRIGGER_EDGE &&
+		e.dest_id == 0,
+		"Invalid IOAPIC redir entry for line : %d, trig_mode: %d vector: %d",
+		line, e.trig_mode, e.vector);
+
+	x2apic_write_reg(APIC_TASKPRI, 0);
+
+	for (i = 0; i < (IOAPIC_NUM_EDGE_VECTORS + IOAPIC_NUM_LEVEL_VECTORS); i++) {
+		vec = IOAPIC_VECTOR_START + i;
+		savic_allow_vector(vec);
+	}
+
+	vec = RTC_GSI_IRQ;
+	savic_allow_vector(vec);
+}
+
 static void guest_code(int id)
 {
 	GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SNP_SECURE_AVIC);
@@ -537,6 +727,10 @@ static void guest_code(int id)
 
 	SAVIC_GUEST_SYNC(SAVIC_IDLE_HALT, guest_savic_idle_halt);
 
+	guest_setup_ioapic(id);
+	SAVIC_GUEST_SYNC(SAVIC_IOAPIC, savic_ioapic);
+	SAVIC_GUEST_SYNC(SAVIC_IOAPIC2, savic_ioapic2);
+
 	GUEST_DONE();
 }
 
@@ -611,6 +805,46 @@ static void host_post_savic_en_end(int id)
 	test_apic_vals(id, false, CTXT_HOST, true, true);
 }
 
+static void host_send_ioapic_irq(struct kvm_vm *vm, int id)
+{
+	int i;
+	int vec, offset, pos;
+	uint32_t regval;
+
+	kvm_irq_line(vm, 0, 1);
+	kvm_irq_line(vm, 1, 1);
+	kvm_irq_line(vm, 0, 0);
+	kvm_irq_line(vm, 1, 0);
+	kvm_irq_line(vm, 2, 1);
+	kvm_irq_line(vm, 2, 0);
+	kvm_irq_line(vm, 3, 1);
+	kvm_irq_line(vm, 3, 0);
+	kvm_irq_line_status(vm, RTC_GSI, 1);
+	kvm_irq_line_status(vm, RTC_GSI, 0);
+
+	vcpu_ioctl(vcpus[id], KVM_GET_LAPIC, &apic_state[id]);
+
+	for (i = 0; i < IOAPIC_NUM_EDGE_VECTORS; i++) {
+		vec = IOAPIC_VECTOR_START + i;
+		offset = APIC_REG_OFF(vec);
+		regval = *(uint32_t *)&apic_state[id].regs[APIC_TMR + offset];
+		pos = APIC_VEC_POS(vec);
+		TEST_ASSERT(!(regval & BIT_ULL(pos)), "TMR should be 0 for vector: %x", vec);
+		regval = *(uint32_t *)&apic_state[id].regs[APIC_IRR + offset];
+		TEST_ASSERT(regval & BIT_ULL(pos), "IRR should be 1 for vector: %x", vec);
+	}
+
+	for (i = 0; i < IOAPIC_NUM_LEVEL_VECTORS; i++) {
+		vec = IOAPIC_VECTOR_START + 2 + i;
+		offset = APIC_REG_OFF(vec);
+		regval = *(uint32_t *)&apic_state[id].regs[APIC_TMR + offset];
+		pos = APIC_VEC_POS(vec);
+		TEST_ASSERT(regval & BIT_ULL(pos), "TMR should be 1 for vector: %x", vec);
+		regval = *(uint32_t *)&apic_state[id].regs[APIC_IRR + offset];
+		TEST_ASSERT(regval & BIT_ULL(pos), "IRR should be 1 for vector: %x", vec);
+	}
+}
+
 static void host_test_savic(struct kvm_vm *vm, int id, enum savic_test_state test_state)
 {
 	switch (test_state) {
@@ -632,6 +866,12 @@ static void host_test_savic(struct kvm_vm *vm, int id, enum savic_test_state tes
 	case SAVIC_EN_END:
 		host_post_savic_en_end(id);
 		break;
+	case SAVIC_IOAPIC_START:
+		host_send_ioapic_irq(vm, id);
+		break;
+	case SAVIC_IOAPIC2_START:
+		host_send_ioapic_irq(vm, id);
+		break;
 	default:
 		break;
 	}
@@ -660,7 +900,6 @@ static void *vcpu_thread(void *arg)
 		default:
 			TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
 		}
-
 	}
 
 	return NULL;
@@ -670,6 +909,11 @@ static void install_exception_handlers(struct kvm_vm *vm)
 {
 	vm_install_exception_handler(vm, IDLE_HLT_INTR_VECTOR, guest_idle_hlt_intr_handler);
 	vm_install_exception_handler(vm, 29, savic_vc_handler);
+	vm_install_exception_handler(vm, IOAPIC_VECTOR_START, ioapic_edge_irq1_intr_handler);
+	vm_install_exception_handler(vm, IOAPIC_VECTOR_START + 1, ioapic_edge_irq2_intr_handler);
+	vm_install_exception_handler(vm, IOAPIC_VECTOR_START + 2, ioapic_level_irq1_intr_handler);
+	vm_install_exception_handler(vm, IOAPIC_VECTOR_START + 3, ioapic_level_irq2_intr_handler);
+	vm_install_exception_handler(vm, RTC_GSI_IRQ, ioapic_rtc_gsi_intr_handler);
 }
 
 int main(int argc, char *argv[])
@@ -677,8 +921,10 @@ int main(int argc, char *argv[])
 	struct kvm_sev_init args = { .vmsa_features = BIT_ULL(SVM_FEAT_SECURE_AVIC) |
 					BIT_ULL(SVM_FEAT_ALLOWED_SEV_FEATURES_VALID)
 				   };
+	struct test_data_page *shared_data[NR_SAVIC_VCPUS];
+	vm_vaddr_t test_data_page_vaddr;
 	struct kvm_vm *vm;
-	int r;
+	int i, r;
 
 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SNP));
 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SECURE_AVIC));
@@ -687,11 +933,21 @@ int main(int argc, char *argv[])
 	vm = _vm_sev_create_with_one_vcpu(KVM_X86_SNP_VM, guest_code, &vcpus[0], &args);
 
 	virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
+	virt_pg_map(vm, IOAPIC_DEFAULT_GPA, IOAPIC_DEFAULT_GPA);
 
 	install_exception_handlers(vm);
 
 	vcpu_args_set(vcpus[0], 1, vcpus[0]->id);
 
+	for (i = 0; i < NR_SAVIC_VCPUS; i++) {
+		test_data_page_vaddr = vm_vaddr_alloc_page_shared(vm);
+		test_data[i] = (struct test_data_page *)test_data_page_vaddr;
+		shared_data[i] = addr_gva2hva(vm, test_data_page_vaddr);
+		vm_mem_set_shared(vm, addr_hva2gpa(vm, shared_data[i]), getpagesize());
+	}
+
+	sync_global_to_guest(vm, test_data);
+
 	vm_sev_launch(vm, snp_default_policy(), NULL);
 
 	r = pthread_create(&threads[0], NULL, vcpu_thread, vcpus[0]);
@@ -699,6 +955,14 @@ int main(int argc, char *argv[])
 
 	pthread_join(threads[0], NULL);
 
+	for (i = 0; i < NR_SAVIC_VCPUS; i++) {
+		struct test_data_page *shared_state = shared_data[i];
+
+		fprintf(stderr, "VCPU %d ioapic edge irq1 count: %ld edge irq2 count: %ld\n", i, shared_state->ioapic_eirq1_count, shared_state->ioapic_eirq2_count);
+		fprintf(stderr, "VCPU %d ioapic level irq1 count: %ld level irq2 count: %ld\n", i, shared_state->ioapic_lirq1_count, shared_state->ioapic_lirq2_count);
+		fprintf(stderr, "VCPU %d ioapic RTC GSI irq1 count: %ld\n", i, shared_state->ioapic_rtc_gsi_irq_count);
+	}
+
 	kvm_vm_free(vm);
 
 	return 0;
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ