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: <20250923050942.206116-33-Neeraj.Upadhyay@amd.com>
Date: Tue, 23 Sep 2025 10:39:39 +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>, <tiala@...rosoft.com>
Subject: [RFC PATCH v2 32/35] KVM: selftests: Add IOAPIC tests for Secure AVIC

Extend the Secure AVIC (SAVIC) selftest to validate the delivery of
external interrupts via the IOAPIC. This is a critical validation step,
as the interrupt injection path for SAVIC guests is different from
traditional APIC modes and requires explicit guest cooperation.

In SAVIC mode, for the hardware to inject an external interrupt, the
guest must first grant permission for the corresponding vector. This
is done by setting a bit in a designated "allowed IRR" region within
its private APIC backing page. If the vector is not allowed, the
interrupt is dropped by the hardware.

Add a new test case to savic_test.c and verify this entire flow of IOAPIC
interrupt injection for both edge and level-triggered interrupts. Also
test the special-cased RTC GSI (IRQ 8).

To support this, add new helpers for reading/writing the IOAPIC MMIO
region and updating the IOAPIC redirection table.

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  | 253 +++++++++++++++++-
 7 files changed, 330 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index e5f322994f44..513e68f88179 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -952,6 +952,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 23272f797f5f..e830425d5d60 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1964,6 +1964,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 fc57b948c041..af2604483e60 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 da01bb5deae1..c941fd3f22df 100644
--- a/tools/testing/selftests/kvm/lib/x86/savic.c
+++ b/tools/testing/selftests/kvm/lib/x86/savic.c
@@ -45,6 +45,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
 
 /*
@@ -107,6 +108,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 9108ac0077a9..aa8a7244aa55 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];
@@ -28,8 +34,21 @@ static pthread_t threads[NR_SAVIC_VCPUS];
 enum savic_test_state {
 	SAVIC_TEST_STATE(SAVIC_APIC_MSR_ACCESSES),
 	SAVIC_TEST_STATE(SAVIC_IDLE_HALT),
+	SAVIC_TEST_STATE(SAVIC_IOAPIC),
+	SAVIC_TEST_STATE(SAVIC_IOAPIC2),
+};
+
+/* 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];
+
 #define SAVIC_GUEST_SYNC(sync, func) ({\
 	GUEST_SYNC(sync ## _START); \
 	func(id); \
@@ -262,6 +281,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);
@@ -274,9 +464,41 @@ 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();
 }
 
+static void host_send_ioapic_irq(struct kvm_vm *vm, int id)
+{
+	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);
+}
+
+static void host_test_savic(struct kvm_vm *vm, int id, enum savic_test_state test_state)
+{
+	switch (test_state) {
+	case SAVIC_IOAPIC_START:
+		host_send_ioapic_irq(vm, id);
+		break;
+	case SAVIC_IOAPIC2_START:
+		host_send_ioapic_irq(vm, id);
+		break;
+	default:
+		break;
+	}
+}
+
 static void *vcpu_thread(void *arg)
 {
 	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)arg;
@@ -288,6 +510,7 @@ static void *vcpu_thread(void *arg)
 		vcpu_run(vcpu);
 		switch (get_ucall(vcpu, &uc)) {
 		case UCALL_SYNC:
+			host_test_savic(vcpu->vm, vcpu->id, uc.args[1]);
 			break;
 		case UCALL_DONE:
 			return NULL;
@@ -299,7 +522,6 @@ static void *vcpu_thread(void *arg)
 		default:
 			TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
 		}
-
 	}
 
 	return NULL;
@@ -309,6 +531,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[])
@@ -316,8 +543,10 @@ int main(int argc, char *argv[])
 	struct kvm_sev_init args = {
 		.vmsa_features = BIT_ULL(SVM_FEAT_SECURE_AVIC)
 	};
+	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_SEV_SNP));
 	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SECURE_AVIC));
@@ -326,11 +555,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]);
@@ -338,6 +577,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