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-11-Neeraj.Upadhyay@amd.com>
Date: Tue, 23 Sep 2025 10:39:17 +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 10/35] KVM: selftests: Add MSR access support for SEV-ES guests

For SEV-ES guests, RDMSR/WRMSR of the intercepted MSRs trap and
generate a #VC (VMM Communication) exception. The guest must then
handle this exception and communicate the desired MSR operation to the
hypervisor using the GHCB protocol.

Add the necessary selftest infrastructure to support this flow, enabling
tests to correctly perform MSR operations from within an SEV-ES guest.

Two mechanisms are introduced:

1.  #VC Exception Handling: Provide a #VC handler, which inspects the
    trapping instruction and the register state and does a GHCB
    request to forward the MSR operation to the host .

2.  Paravirtual Interface: Provide a direct, "paravirtual" way to test
    the MSR GHCB protocol. This allows test code to request an MSR read
    or write without needing to execute a trapping instruction,
    simplifying certain test scenarios.

Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@....com>
---
 tools/testing/selftests/kvm/include/x86/sev.h |  2 +
 tools/testing/selftests/kvm/lib/x86/sev.c     | 83 ++++++++++++++++++-
 2 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/include/x86/sev.h b/tools/testing/selftests/kvm/include/x86/sev.h
index a4fbea0d3562..9c1fe6be5e68 100644
--- a/tools/testing/selftests/kvm/include/x86/sev.h
+++ b/tools/testing/selftests/kvm/include/x86/sev.h
@@ -165,4 +165,6 @@ static inline void snp_launch_update_data(struct kvm_vm *vm, vm_paddr_t gpa,
 
 void sev_es_ucall_port_write(uint32_t port, uint64_t data);
 
+void sev_es_vc_handler(struct ex_regs *regs);
+void sev_es_pv_msr_rw(uint64_t msr, uint64_t *data, bool write);
 #endif /* SELFTEST_KVM_SEV_H */
diff --git a/tools/testing/selftests/kvm/lib/x86/sev.c b/tools/testing/selftests/kvm/lib/x86/sev.c
index edefba7f49ce..57ae5a388b8c 100644
--- a/tools/testing/selftests/kvm/lib/x86/sev.c
+++ b/tools/testing/selftests/kvm/lib/x86/sev.c
@@ -12,7 +12,8 @@
 #define IOIO_DATA_8 (1 << 4)
 #define IOIO_REP (1 << 3)
 
-#define SW_EXIT_CODE_IOIO 0x7b
+#define SW_EXIT_CODE_IOIO	0x7b
+#define SW_EXIT_CODE_MSR	0x7c
 
 struct ghcb_entry {
 	struct ghcb ghcb;
@@ -356,3 +357,83 @@ void sev_es_ucall_port_write(uint32_t port, uint64_t data)
 
 	ghcb_free(entry);
 }
+
+static void __sev_es_msr_rw(struct ghcb_entry *entry, uint64_t msr,
+		uint32_t *low, uint32_t *high, bool write)
+{
+	uint64_t exitinfo1 = write ? 1 : 0;
+	struct ghcb *ghcb = &entry->ghcb;
+	uint32_t ret;
+
+	ghcb_set_sw_exit_code(ghcb, SW_EXIT_CODE_MSR);
+	ghcb_set_sw_exit_info_1(ghcb, exitinfo1);
+	ghcb_set_sw_exit_info_2(ghcb, 0);
+
+	ghcb_set_rcx(ghcb, msr);
+	if (write) {
+		ghcb_set_rax(ghcb, *low);
+		ghcb_set_rdx(ghcb, *high);
+	}
+
+	do_vmg_exit(entry->gpa);
+
+	ret = ghcb->save.sw_exit_info_1 & 0xffffffff;
+	__GUEST_ASSERT(!ret, "%smsr failed, ret: %u", write ? "wr" : "rd", ret);
+
+	if (!write) {
+		*low = ghcb->save.rax;
+		*high = ghcb->save.rdx;
+	}
+}
+
+void sev_es_pv_msr_rw(uint64_t msr, uint64_t *data, bool write)
+{
+	struct ghcb_entry *entry;
+	uint32_t low, high;
+
+	entry = ghcb_alloc();
+	register_ghcb_page(entry->gpa);
+
+	if (write) {
+		low = *data & ((1ULL << 32) - 1);
+		high = *data >> 32;
+	}
+	__sev_es_msr_rw(entry, msr, &low, &high, write);
+
+	if (!write)
+		*data = low | (uint64_t)high << 32;
+
+	ghcb_free(entry);
+}
+
+static void sev_es_vc_msr_handler(struct ex_regs *regs)
+{
+	struct ghcb_entry *entry;
+	bool write;
+
+	/* wrmsr encoding has second byte = 0x30 */
+	write = (*((char *)regs->rip + 1) == 0x30);
+
+	entry = ghcb_alloc();
+	register_ghcb_page(entry->gpa);
+
+	__sev_es_msr_rw(entry, regs->rcx, (uint32_t *)&regs->rax,
+			(uint32_t *)&regs->rdx, write);
+
+	ghcb_free(entry);
+}
+
+void sev_es_vc_handler(struct ex_regs *regs)
+{
+	uint64_t exit_code = regs->error_code;
+
+	switch (exit_code) {
+	case SVM_EXIT_MSR:
+		sev_es_vc_msr_handler(regs);
+		/* rdmsr/wrmsr instruction size = 2 */
+		regs->rip += 2;
+		break;
+	default:
+		__GUEST_ASSERT(0, "No VC handler\n");
+	}
+}
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ