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 for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250228093024.114983-27-Neeraj.Upadhyay@amd.com>
Date: Fri, 28 Feb 2025 15:00:19 +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 26/31] KVM: selftests: Add test to verify APIC MSR accesses for SAVIC guest

Extend SAVIC test to verify APIC MSR accesses in SAVIC enabled
mode. Verify the behavior of reads and writes using rdmsr/wrmsr
for various APIC registers. In addition, test whether wrmsr
based writes are propagated to guest backing page.

Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@....com>
---
 .../testing/selftests/kvm/include/x86/apic.h  |   1 +
 .../testing/selftests/kvm/include/x86/savic.h |   3 +
 tools/testing/selftests/kvm/lib/x86/savic.c   |   7 +-
 tools/testing/selftests/kvm/x86/savic_test.c  | 192 +++++++++++++++++-
 4 files changed, 198 insertions(+), 5 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86/apic.h b/tools/testing/selftests/kvm/include/x86/apic.h
index aa3a5d54c404..af555638086f 100644
--- a/tools/testing/selftests/kvm/include/x86/apic.h
+++ b/tools/testing/selftests/kvm/include/x86/apic.h
@@ -33,6 +33,7 @@
 #define	APIC_SPIV	0xF0
 #define		APIC_SPIV_FOCUS_DISABLED	(1 << 9)
 #define		APIC_SPIV_APIC_ENABLED		(1 << 8)
+#define APIC_ISR	0x100
 #define APIC_TMR        0x180
 #define APIC_IRR	0x200
 #define	APIC_ICR	0x300
diff --git a/tools/testing/selftests/kvm/include/x86/savic.h b/tools/testing/selftests/kvm/include/x86/savic.h
index cb432eb527b3..33f19f5e39b3 100644
--- a/tools/testing/selftests/kvm/include/x86/savic.h
+++ b/tools/testing/selftests/kvm/include/x86/savic.h
@@ -6,6 +6,9 @@
 #ifndef SELFTEST_KVM_SAVIC_H
 #define SELFTEST_KVM_SAVIC_H
 
+#define APIC_REG_OFF(VEC)		(VEC / 32 * 16)
+#define APIC_VEC_POS(VEC)		(VEC % 32)
+
 struct guest_apic_page;
 
 void guest_apic_pages_init(struct kvm_vm *vm);
diff --git a/tools/testing/selftests/kvm/lib/x86/savic.c b/tools/testing/selftests/kvm/lib/x86/savic.c
index d4c9fcf835ad..c637e486b6e8 100644
--- a/tools/testing/selftests/kvm/lib/x86/savic.c
+++ b/tools/testing/selftests/kvm/lib/x86/savic.c
@@ -9,6 +9,7 @@
 #include "kvm_util.h"
 #include "sev.h"
 #include "ex_regs.h"
+#include "savic.h"
 
 struct apic_page {
 	u8 apic_regs[PAGE_SIZE];
@@ -45,9 +46,6 @@ enum lapic_lvt_entry {
 #define SVM_EXIT_AVIC_UNACCELERATED_ACCESS      0x402
 #define SVM_EXIT_AVIC_INCOMPLETE_IPI            0x401
 
-#define REG_OFF(VEC)		(VEC / 32 * 16)
-#define VEC_POS(VEC)		(VEC % 32)
-
 #define SAVIC_NMI_REQ_OFFSET            0x278
 
 /*
@@ -363,7 +361,8 @@ static void send_ipi(int cpu, int vector, bool nmi)
 	if (nmi)
 		savic_write_reg(apic_page, SAVIC_NMI_REQ_OFFSET, 1);
 	else
-		savic_write_reg(apic_page, APIC_IRR + REG_OFF(vector), BIT(VEC_POS(vector)));
+		savic_write_reg(apic_page, APIC_IRR + APIC_REG_OFF(vector),
+				BIT(APIC_VEC_POS(vector)));
 }
 
 static bool is_cpu_present(int cpu)
diff --git a/tools/testing/selftests/kvm/x86/savic_test.c b/tools/testing/selftests/kvm/x86/savic_test.c
index ca1d7352bc3e..8cba7a81bce2 100644
--- a/tools/testing/selftests/kvm/x86/savic_test.c
+++ b/tools/testing/selftests/kvm/x86/savic_test.c
@@ -29,6 +29,7 @@ enum savic_test_state {
 	SAVIC_TEST_STATE(X2APIC_ENABLE),
 	/* APIC regs state on Secure AVIC enablement */
 	SAVIC_TEST_STATE(SAVIC_EN),
+	SAVIC_TEST_STATE(SAVIC_APIC_MSR_ACCESSES),
 };
 
 /* APIC reg values written by host. */
@@ -288,6 +289,193 @@ static void guest_savic_enabled(int id)
 	savic_write_apic_regs(apage);
 }
 
+static int savic_wrmsr(uint32_t reg, uint64_t val)
+{
+	switch (reg) {
+	case APIC_LVR:
+	case APIC_LDR:
+	case APIC_ISR:
+	case APIC_TMR:
+	case APIC_IRR:
+	case APIC_TMCCT:
+		x2apic_write_reg_fault(reg, val);
+		return -1;
+	default:
+		x2apic_write_reg(reg, val);
+		break;
+	}
+
+	return 0;
+}
+
+static uint64_t savic_rdmsr(uint32_t reg)
+{
+	uint64_t val;
+	uint32_t msr = APIC_BASE_MSR + (reg >> 4);
+
+	switch (reg) {
+	case APIC_EOI:
+		uint8_t fault = rdmsr_safe(msr, &val);
+
+		__GUEST_ASSERT(fault == GP_VECTOR,
+				"Wanted #GP on RDMSR(%x) = %x, got 0x%x\n",
+				msr, GP_VECTOR, fault);
+		return val;
+	default:
+		return x2apic_read_reg(reg);
+	}
+}
+
+static void guest_verify_host_guest_reg(struct guest_apic_page *apage, uint32_t reg,
+		uint64_t val, char *regname)
+{
+	uint64_t hval, gval, gval2;
+
+	if (savic_wrmsr(reg, val) == -1) {
+		savic_write_reg(apage, reg, val);
+		/*
+		 * Write using PV interface if wrmsr fails. Skip for
+		 * regs which trigger GP
+		 */
+		if (reg != APIC_LVR && reg != APIC_TMR && reg != APIC_IRR)
+			savic_hv_write_reg(reg, val);
+	}
+
+	gval = savic_read_reg(apage, reg);
+	gval2 = savic_rdmsr(reg);
+	hval = savic_hv_read_reg(reg);
+	__GUEST_ASSERT(gval == val, "Unexpected Guest %s 0x%lx, expected val:0x%lx\n",
+			regname, gval, val);
+	__GUEST_ASSERT(gval == gval2, "Unexpected Guest %s backing page value : 0x%lx, msr read val:0x%lx\n",
+			regname, gval, gval2);
+
+	switch (reg) {
+	case APIC_LVR:
+	case APIC_LDR:
+	case APIC_ISR:
+	case APIC_TMICT:
+	case APIC_TDCR:
+	case APIC_LVTT:
+	case APIC_LVTTHMR:
+	case APIC_LVTPC:
+	case APIC_LVT0:
+	case APIC_LVT1:
+	case APIC_LVTERR:
+		__GUEST_ASSERT(hval == gval, "Guest 0x%lx host 0x%lx %s mismatch\n",
+			gval, hval, regname);
+		break;
+	case APIC_TASKPRI:
+	case APIC_SPIV:
+	case APIC_ICR:
+	case APIC_TMR:
+	case APIC_IRR:
+		__GUEST_ASSERT(hval != gval, "Guest 0x%lx host 0x%lx reg: %x %s must not match\n",
+			gval, hval, reg, regname);
+		break;
+	default:
+		break;
+	}
+}
+
+static inline uint32_t x2apic_ldr(uint32_t id)
+{
+	return ((id >> 4) << 16) | (1 << (id & 0xf));
+}
+
+static void guest_savic_apic_msr_accesses(int id)
+{
+	struct guest_apic_page *apage = get_guest_apic_page();
+	uint64_t val, hval;
+	uint32_t reg;
+	int vec;
+	int i;
+	uint32_t lvt_regs[] = {
+		APIC_LVTT, APIC_LVTTHMR, APIC_LVTPC,
+		APIC_LVT0, APIC_LVT1, APIC_LVTERR
+	};
+
+	reg = APIC_LVR;
+	val = savic_hv_read_reg(reg);
+	/* APIC_LVR state is in sync between host and guest. */
+	guest_verify_host_guest_reg(apage, reg, val, "APIC_LVR");
+
+	reg = APIC_TASKPRI;
+	val = 0x30;
+	/* Write new TASKPRI to host using PV interface. */
+	savic_hv_write_reg(reg, val);
+	val = 0x40;
+	/* TASKPRI is accelerated and state is not up-to-date in host. */
+	guest_verify_host_guest_reg(apage, reg, val, "APIC_TASKPRI");
+
+	reg = APIC_PROCPRI;
+	val = x2apic_read_reg(reg);
+	/* APIC_PROCPRI is updated with the APIC_TASKPRI update above. */
+	GUEST_ASSERT((val & 0xf0) == (x2apic_read_reg(APIC_TASKPRI) & 0xf0));
+	GUEST_ASSERT((val & 0xf0) == 0x40);
+	vec = 0x20;
+	x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | vec);
+	/* Interrupt remains pending in APIC_IRR. */
+	val = savic_read_reg(apage, APIC_IRR + APIC_REG_OFF(vec));
+	GUEST_ASSERT((val & BIT_ULL(APIC_VEC_POS(vec))) == BIT_ULL(APIC_VEC_POS(vec)));
+	savic_wrmsr(APIC_TASKPRI, 0x0);
+
+	/* Triggers GP fault */
+	savic_rdmsr(APIC_EOI);
+
+	reg = APIC_LDR;
+	val = x2apic_ldr(savic_rdmsr(APIC_ID));
+	hval = savic_hv_read_reg(APIC_LDR);
+	__GUEST_ASSERT(val == hval, "APIC_LDR mismatch between host %lx and guest %lx",
+			hval, val);
+
+	/* APIC_SPIV state is not visible to host. */
+	reg = APIC_SPIV;
+	val = savic_rdmsr(APIC_SPIV) & ~APIC_SPIV_APIC_ENABLED;
+	savic_hv_write_reg(reg, val);
+	val = savic_rdmsr(APIC_SPIV) | APIC_SPIV_APIC_ENABLED;
+	guest_verify_host_guest_reg(apage, reg, val, "APIC_SPIV");
+
+	reg = APIC_ISR;
+	(void) savic_rdmsr(reg);
+	/* Triggers GP fault */
+	savic_wrmsr(reg, 0x10);
+
+	/* APIC_TMR is not synced to host. */
+	reg = APIC_TMR;
+	val = 0x10000;
+	guest_verify_host_guest_reg(apage, reg, val, "APIC_TMR");
+	vec = 0x20;
+	savic_write_reg(apage, reg + APIC_REG_OFF(vec),  BIT_ULL(APIC_VEC_POS(vec)));
+	GUEST_ASSERT(x2apic_read_reg(reg + APIC_REG_OFF(vec)) & BIT_ULL(APIC_VEC_POS(vec)));
+
+	reg = APIC_IRR;
+	val = 0x10000;
+	guest_verify_host_guest_reg(apage, reg, val, "APIC_IRR");
+	savic_write_reg(apage, reg, 0x0);
+
+	reg = APIC_TMICT;
+	val = 0x555;
+	guest_verify_host_guest_reg(apage, reg, val, "APIC_TMICT");
+
+	reg = APIC_TMCCT;
+	savic_rdmsr(reg);
+	savic_wrmsr(reg, 0xf);
+
+	reg = APIC_TDCR;
+	val = 0x1;
+	savic_hv_write_reg(reg, val);
+	val = 0x3;
+	guest_verify_host_guest_reg(apage, reg, val, "APIC_TDCR");
+
+	for (i = 0; i < ARRAY_SIZE(lvt_regs); i++) {
+		reg = lvt_regs[i];
+		val = 0x41;
+		savic_hv_write_reg(reg, val);
+		val = 0x42;
+		guest_verify_host_guest_reg(apage, reg, val, "APIC_LVTx");
+	}
+}
+
 static void guest_code(int id)
 {
 	GUEST_ASSERT(rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SNP_SECURE_AVIC);
@@ -302,6 +490,8 @@ static void guest_code(int id)
 
 	SAVIC_GUEST_SYNC(SAVIC_EN, guest_savic_enabled);
 
+	SAVIC_GUEST_SYNC(SAVIC_APIC_MSR_ACCESSES, guest_savic_apic_msr_accesses);
+
 	GUEST_DONE();
 }
 
@@ -448,7 +638,7 @@ int main(int argc, char *argv[])
 
 	vcpu_args_set(vcpus[0], 1, vcpus[0]->id);
 
-	vm_install_exception_handler(vm, 29, sev_es_vc_handler);
+	vm_install_exception_handler(vm, 29, savic_vc_handler);
 	vm_sev_launch(vm, snp_default_policy(), NULL);
 
 	r = pthread_create(&threads[0], NULL, vcpu_thread, vcpus[0]);
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ