All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Roth <michael.roth@amd.com>
To: linux-kselftest@vger.kernel.org
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	x86@kernel.org, Nathan Tempelman <natet@google.com>,
	Marc Orr <marcorr@google.com>,
	Steve Rutherford <srutherford@google.com>,
	Sean Christopherson <seanjc@google.com>,
	Mingwei Zhang <mizhang@google.com>,
	Brijesh Singh <brijesh.singh@amd.com>,
	Tom Lendacky <thomas.lendacky@amd.com>,
	Varad Gautam <varad.gautam@suse.com>,
	Shuah Khan <shuah@kernel.org>,
	Vitaly Kuznetsov <vkuznets@redhat.com>,
	David Woodhouse <dwmw@amazon.co.uk>,
	Ricardo Koller <ricarkol@google.com>,
	Jim Mattson <jmattson@google.com>,
	Wanpeng Li <wanpengli@tencent.com>,
	Joerg Roedel <joro@8bytes.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	"H . Peter Anvin" <hpa@zytor.com>
Subject: [RFC 11/16] KVM: selftests: add library for handling SEV-ES-related exits
Date: Tue,  5 Oct 2021 18:44:54 -0500	[thread overview]
Message-ID: <20211005234459.430873-12-michael.roth@amd.com> (raw)
In-Reply-To: <20211005234459.430873-1-michael.roth@amd.com>

Add (or copy from kernel) routines related to handling #VC exceptions
(only for cpuid currently) or issuing vmgexits. These will be used
mostly by guest code.

Signed-off-by: Michael Roth <michael.roth@amd.com>
---
 tools/testing/selftests/kvm/Makefile          |   2 +-
 .../kvm/include/x86_64/sev_exitlib.h          |  14 +
 .../selftests/kvm/include/x86_64/svm.h        |  35 +++
 .../selftests/kvm/include/x86_64/svm_util.h   |   1 +
 .../selftests/kvm/lib/x86_64/sev_exitlib.c    | 249 ++++++++++++++++++
 5 files changed, 300 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/kvm/include/x86_64/sev_exitlib.h
 create mode 100644 tools/testing/selftests/kvm/lib/x86_64/sev_exitlib.c

diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index aa8901bdbd22..7b3261cc60a3 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -35,7 +35,7 @@ endif
 
 LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/rbtree.c lib/sparsebit.c lib/test_util.c lib/guest_modes.c lib/perf_test_util.c
 LIBKVM_x86_64 = lib/x86_64/apic.c lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c lib/x86_64/handlers.S
-LIBKVM_x86_64 += lib/x86_64/sev.c
+LIBKVM_x86_64 += lib/x86_64/sev.c lib/x86_64/sev_exitlib.c
 LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c lib/aarch64/handlers.S
 LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c
 
diff --git a/tools/testing/selftests/kvm/include/x86_64/sev_exitlib.h b/tools/testing/selftests/kvm/include/x86_64/sev_exitlib.h
new file mode 100644
index 000000000000..4b67b4004dfa
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/x86_64/sev_exitlib.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * VC/vmgexit/GHCB-related helpers for SEV-ES/SEV-SNP guests.
+ *
+ * Copyright (C) 2021 Advanced Micro Devices
+ */
+
+#ifndef SELFTEST_KVM_SEV_EXITLIB_H
+#define SELFTEST_KVM_SEV_EXITLIB_H
+
+int sev_es_handle_vc(void *ghcb, u64 ghcb_gpa, struct ex_regs *regs);
+void sev_es_terminate(int reason);
+
+#endif /* SELFTEST_KVM_SEV_EXITLIB_H */
diff --git a/tools/testing/selftests/kvm/include/x86_64/svm.h b/tools/testing/selftests/kvm/include/x86_64/svm.h
index f4ea2355dbc2..d633caea4b7d 100644
--- a/tools/testing/selftests/kvm/include/x86_64/svm.h
+++ b/tools/testing/selftests/kvm/include/x86_64/svm.h
@@ -204,6 +204,41 @@ struct __attribute__ ((__packed__)) vmcb_save_area {
 	u64 br_to;
 	u64 last_excp_from;
 	u64 last_excp_to;
+
+	/*
+	 * The following part of the save area is valid only for
+	 * SEV-ES guests when referenced through the GHCB or for
+	 * saving to the host save area.
+	 */
+	u8 reserved_7[80];
+	u32 pkru;
+	u8 reserved_7a[20];
+	u64 reserved_8;		/* rax already available at 0x01f8 */
+	u64 rcx;
+	u64 rdx;
+	u64 rbx;
+	u64 reserved_9;		/* rsp already available at 0x01d8 */
+	u64 rbp;
+	u64 rsi;
+	u64 rdi;
+	u64 r8;
+	u64 r9;
+	u64 r10;
+	u64 r11;
+	u64 r12;
+	u64 r13;
+	u64 r14;
+	u64 r15;
+	u8 reserved_10[16];
+	u64 sw_exit_code;
+	u64 sw_exit_info_1;
+	u64 sw_exit_info_2;
+	u64 sw_scratch;
+	u64 sev_features;
+	u8 reserved_11[48];
+	u64 xcr0;
+	u8 valid_bitmap[16];
+	u64 x87_state_gpa;
 };
 
 struct __attribute__ ((__packed__)) vmcb {
diff --git a/tools/testing/selftests/kvm/include/x86_64/svm_util.h b/tools/testing/selftests/kvm/include/x86_64/svm_util.h
index b7531c83b8ae..4319bb6f4691 100644
--- a/tools/testing/selftests/kvm/include/x86_64/svm_util.h
+++ b/tools/testing/selftests/kvm/include/x86_64/svm_util.h
@@ -16,6 +16,7 @@
 #define CPUID_SVM_BIT		2
 #define CPUID_SVM		BIT_ULL(CPUID_SVM_BIT)
 
+#define SVM_EXIT_CPUID		0x072
 #define SVM_EXIT_VMMCALL	0x081
 
 struct svm_test_data {
diff --git a/tools/testing/selftests/kvm/lib/x86_64/sev_exitlib.c b/tools/testing/selftests/kvm/lib/x86_64/sev_exitlib.c
new file mode 100644
index 000000000000..b3f7b0297e5b
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86_64/sev_exitlib.c
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * GHCB/#VC/instruction helpers for use with SEV-ES/SEV-SNP guests.
+ *
+ * Partially copied from arch/x86/kernel/sev*.c
+ *
+ * Copyright (C) 2021 Advanced Micro Devices
+ */
+
+#include <linux/bitops.h>
+#include <kvm_util.h>			/* needed by kvm_util_internal.h */
+#include "../kvm_util_internal.h"	/* needed by processor.h */
+#include "processor.h"			/* for struct ex_regs */
+#include "svm_util.h"			/* for additional SVM_EXIT_* definitions */
+#include "svm.h"			/* for VMCB/VMSA layout */
+#include "sev_exitlib.h"
+
+#define PAGE_SHIFT 12
+
+#define MSR_SEV_ES_GHCB 0xc0010130
+
+#define VMGEXIT() { asm volatile("rep; vmmcall\n\r"); }
+
+#define GHCB_PROTOCOL_MAX	1
+#define GHCB_DEFAULT_USAGE	0
+
+/* Guest-requested termination codes */
+#define GHCB_TERMINATE 0x100UL
+#define GHCB_TERMINATE_REASON(reason_set, reason_val)	\
+	(((((u64)reason_set) &  0x7) << 12) |			\
+	 ((((u64)reason_val) & 0xff) << 16))
+
+#define GHCB_TERMINATE_REASON_UNSPEC 0
+
+/* GHCB MSR protocol for CPUID */
+#define GHCB_CPUID_REQ_EAX 0
+#define GHCB_CPUID_REQ_EBX 1
+#define GHCB_CPUID_REQ_ECX 2
+#define GHCB_CPUID_REQ_EDX 3
+#define GHCB_CPUID_REQ_CODE 0x4UL
+#define GHCB_CPUID_REQ(fn, reg) \
+	(GHCB_CPUID_REQ_CODE | (((uint64_t)reg & 3) << 30) | (((uint64_t)fn) << 32))
+#define GHCB_CPUID_RESP_CODE 0x5UL
+#define GHCB_CPUID_RESP(resp) ((resp) & 0xfff)
+
+/* GHCB MSR protocol for GHCB registration */
+#define GHCB_REG_GPA_REQ_CODE 0x12UL
+#define GHCB_REG_GPA_REQ(gfn) \
+	(((unsigned long)((gfn) & GENMASK_ULL(51, 0)) << 12) | GHCB_REG_GPA_REQ_CODE)
+#define GHCB_REG_GPA_RESP_CODE 0x13UL
+#define GHCB_REG_GPA_RESP(resp) ((resp) & GENMASK_ULL(11, 0))
+#define GHCB_REG_GPA_RESP_VAL(resp) ((resp) >> 12)
+
+/* GHCB format/accessors */
+
+struct ghcb {
+	struct vmcb_save_area save;
+	u8 reserved_save[2048 - sizeof(struct vmcb_save_area)];
+	u8 shared_buffer[2032];
+	u8 reserved_1[10];
+	u16 protocol_version;
+	u32 ghcb_usage;
+};
+
+#define GHCB_BITMAP_IDX(field)							\
+	(offsetof(struct vmcb_save_area, field) / sizeof(u64))
+
+#define DEFINE_GHCB_ACCESSORS(field)						\
+	static inline bool ghcb_##field##_is_valid(const struct ghcb *ghcb)	\
+	{									\
+		return test_bit(GHCB_BITMAP_IDX(field),				\
+				(unsigned long *)&ghcb->save.valid_bitmap);	\
+	}									\
+										\
+	static inline u64 ghcb_get_##field(struct ghcb *ghcb)			\
+	{									\
+		return ghcb->save.field;					\
+	}									\
+										\
+	static inline u64 ghcb_get_##field##_if_valid(struct ghcb *ghcb)	\
+	{									\
+		return ghcb_##field##_is_valid(ghcb) ? ghcb->save.field : 0;	\
+	}									\
+										\
+	static inline void ghcb_set_##field(struct ghcb *ghcb, u64 value)	\
+	{									\
+		__set_bit(GHCB_BITMAP_IDX(field),				\
+			  (unsigned long *)&ghcb->save.valid_bitmap);		\
+		ghcb->save.field = value;					\
+	}
+
+DEFINE_GHCB_ACCESSORS(cpl)
+DEFINE_GHCB_ACCESSORS(rip)
+DEFINE_GHCB_ACCESSORS(rsp)
+DEFINE_GHCB_ACCESSORS(rax)
+DEFINE_GHCB_ACCESSORS(rcx)
+DEFINE_GHCB_ACCESSORS(rdx)
+DEFINE_GHCB_ACCESSORS(rbx)
+DEFINE_GHCB_ACCESSORS(rbp)
+DEFINE_GHCB_ACCESSORS(rsi)
+DEFINE_GHCB_ACCESSORS(rdi)
+DEFINE_GHCB_ACCESSORS(r8)
+DEFINE_GHCB_ACCESSORS(r9)
+DEFINE_GHCB_ACCESSORS(r10)
+DEFINE_GHCB_ACCESSORS(r11)
+DEFINE_GHCB_ACCESSORS(r12)
+DEFINE_GHCB_ACCESSORS(r13)
+DEFINE_GHCB_ACCESSORS(r14)
+DEFINE_GHCB_ACCESSORS(r15)
+DEFINE_GHCB_ACCESSORS(sw_exit_code)
+DEFINE_GHCB_ACCESSORS(sw_exit_info_1)
+DEFINE_GHCB_ACCESSORS(sw_exit_info_2)
+DEFINE_GHCB_ACCESSORS(sw_scratch)
+DEFINE_GHCB_ACCESSORS(xcr0)
+
+static uint64_t sev_es_rdmsr_ghcb(void)
+{
+	uint64_t lo, hi;
+
+	asm volatile("rdmsr"
+		     : "=a" (lo), "=d" (hi)
+		     : "c" (MSR_SEV_ES_GHCB));
+
+	return ((hi << 32) | lo);
+}
+
+static void sev_es_wrmsr_ghcb(uint64_t val)
+{
+	uint64_t lo, hi;
+
+	lo = val & 0xFFFFFFFF;
+	hi = val >> 32;
+
+	asm volatile("wrmsr"
+		     :: "c" (MSR_SEV_ES_GHCB), "a" (lo), "d" (hi)
+		     : "memory");
+}
+
+void sev_es_terminate(int reason)
+{
+	uint64_t val = GHCB_TERMINATE;
+
+	val |= GHCB_TERMINATE_REASON(2, reason);
+
+	sev_es_wrmsr_ghcb(val);
+	VMGEXIT();
+
+	while (true)
+		asm volatile("hlt" : : : "memory");
+}
+
+static int sev_es_ghcb_hv_call(struct ghcb *ghcb, u64 ghcb_gpa, u64 exit_code)
+{
+	ghcb->protocol_version = GHCB_PROTOCOL_MAX;
+	ghcb->ghcb_usage = GHCB_DEFAULT_USAGE;
+
+	ghcb_set_sw_exit_code(ghcb, exit_code);
+	ghcb_set_sw_exit_info_1(ghcb, 0);
+	ghcb_set_sw_exit_info_2(ghcb, 0);
+
+	sev_es_wrmsr_ghcb(ghcb_gpa);
+
+	VMGEXIT();
+
+	/* Only #VC exceptions are currently handled. */
+	if ((ghcb->save.sw_exit_info_1 & 0xffffffff) == 1)
+		sev_es_terminate(GHCB_TERMINATE_REASON_UNSPEC);
+
+	return 0;
+}
+
+static int handle_vc_cpuid(struct ghcb *ghcb, u64 ghcb_gpa, struct ex_regs *regs)
+{
+	int ret;
+
+	ghcb_set_rax(ghcb, regs->rax);
+	ghcb_set_rcx(ghcb, regs->rcx);
+
+	/* ignore additional XSAVE states for now */
+	ghcb_set_xcr0(ghcb, 1);
+
+	ret = sev_es_ghcb_hv_call(ghcb, ghcb_gpa, SVM_EXIT_CPUID);
+	if (ret)
+		return ret;
+
+	if (!(ghcb_rax_is_valid(ghcb) &&
+	      ghcb_rbx_is_valid(ghcb) &&
+	      ghcb_rcx_is_valid(ghcb) &&
+	      ghcb_rdx_is_valid(ghcb)))
+		return 1;
+
+	regs->rax = ghcb->save.rax;
+	regs->rbx = ghcb->save.rbx;
+	regs->rcx = ghcb->save.rcx;
+	regs->rdx = ghcb->save.rdx;
+
+	regs->rip += 2;
+
+	return 0;
+}
+
+static int handle_msr_vc_cpuid(struct ex_regs *regs)
+{
+	uint32_t fn = regs->rax & 0xFFFFFFFF;
+	uint64_t resp;
+
+	sev_es_wrmsr_ghcb(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_EAX));
+	VMGEXIT();
+	resp = sev_es_rdmsr_ghcb();
+	if (GHCB_CPUID_RESP(resp) != GHCB_CPUID_RESP_CODE)
+		return 1;
+	regs->rax = resp >> 32;
+
+	sev_es_wrmsr_ghcb(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_EBX));
+	VMGEXIT();
+	resp = sev_es_rdmsr_ghcb();
+	if (GHCB_CPUID_RESP(resp) != GHCB_CPUID_RESP_CODE)
+		return 1;
+	regs->rbx = resp >> 32;
+
+	sev_es_wrmsr_ghcb(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_ECX));
+	VMGEXIT();
+	resp = sev_es_rdmsr_ghcb();
+	if (GHCB_CPUID_RESP(resp) != GHCB_CPUID_RESP_CODE)
+		return 1;
+	regs->rcx = resp >> 32;
+
+	sev_es_wrmsr_ghcb(GHCB_CPUID_REQ(fn, GHCB_CPUID_REQ_EDX));
+	VMGEXIT();
+	resp = sev_es_rdmsr_ghcb();
+	if (GHCB_CPUID_RESP(resp) != GHCB_CPUID_RESP_CODE)
+		return 1;
+	regs->rdx = resp >> 32;
+
+	regs->rip += 2;
+
+	return 0;
+}
+
+int sev_es_handle_vc(void *ghcb, u64 ghcb_gpa, struct ex_regs *regs)
+{
+	if (regs->error_code != SVM_EXIT_CPUID)
+		return 1;
+
+	if (!ghcb)
+		return handle_msr_vc_cpuid(regs);
+
+	return handle_vc_cpuid(ghcb, ghcb_gpa, regs);
+}
-- 
2.25.1


  parent reply	other threads:[~2021-10-05 23:46 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-05 23:44 [RFC 00/16] KVM: selftests: Add tests for SEV, SEV-ES, and SEV-SNP guests Michael Roth
2021-10-05 23:44 ` [RFC 01/16] KVM: selftests: move vm_phy_pages_alloc() earlier in file Michael Roth
2021-10-18 15:00   ` Mingwei Zhang
2021-10-21  3:45     ` Michael Roth
2021-10-21 15:20       ` Paolo Bonzini
2021-10-26 15:52       ` Mingwei Zhang
2021-11-01 17:43         ` Mingwei Zhang
2021-10-05 23:44 ` [RFC 02/16] KVM: selftests: add hooks for managing encrypted guest memory Michael Roth
2021-10-13  2:20   ` Krish Sadhukhan
2021-10-13 15:07     ` Michael Roth
2021-10-21 15:22       ` Paolo Bonzini
2021-10-18 15:00   ` Mingwei Zhang
2021-10-21  3:37     ` Michael Roth
2021-10-21 15:22       ` Paolo Bonzini
2021-10-26 15:48       ` Mingwei Zhang
2021-11-01 17:44         ` Mingwei Zhang
2021-10-05 23:44 ` [RFC 03/16] KVM: selftests: handle encryption bits in page tables Michael Roth
2021-10-21 15:26   ` Paolo Bonzini
2021-10-24 16:49     ` Michael Roth
2021-10-25  7:34       ` Paolo Bonzini
2021-10-25 14:14         ` Michael Roth
2021-10-05 23:44 ` [RFC 09/16] KVM: selftests: account for error code in #VC exception frame Michael Roth
2021-10-05 23:44 ` [RFC 10/16] KVM: selftests: add support for creating SEV-ES guests Michael Roth
2021-10-05 23:44 ` Michael Roth [this message]
2021-10-05 23:44 ` [RFC 12/16] KVM: selftests: add SEV-ES boot tests Michael Roth
2021-10-05 23:44 ` [RFC 13/16] KVM: selftests: add support for creating SEV-SNP guests Michael Roth
2021-10-05 23:44 ` [RFC 14/16] KVM: selftests: add helpers for SEV-SNP-related instructions/exits Michael Roth
2021-10-05 23:44 ` [RFC 15/16] KVM: selftests: add SEV-SNP boot tests Michael Roth
2021-10-05 23:44 ` [RFC 16/16] KVM: selftests: add SEV-SNP tests for page-state changes Michael Roth
2021-10-06 20:28 ` [RFC 04/16] KVM: selftests: add library for creating/interacting with SEV guests Michael Roth
2021-10-06 20:59   ` Michael Roth
2021-10-06 20:36 ` [RFC 04/16] KVM: selftests: set CPUID before setting sregs in vcpu creation Michael Roth
2021-10-08 19:03   ` Nathan Tempelman
2021-10-13  1:45   ` Krish Sadhukhan
2021-10-13 15:05     ` Michael Roth
2021-10-21 15:29   ` Paolo Bonzini
2021-10-06 20:36 ` [RFC 05/16] KVM: selftests: add support for encrypted vm_vaddr_* allocations Michael Roth
2021-10-06 20:37 ` [RFC 06/16] KVM: selftests: add library for creating/interacting with SEV guests Michael Roth
2021-10-11  3:17   ` Marc Orr
2021-10-12  1:15     ` Michael Roth
2021-10-12 12:55       ` Michael Roth
2021-10-21 15:43         ` Paolo Bonzini
2021-11-04  5:25       ` Mingwei Zhang
2021-11-04 13:44         ` Tom Lendacky
2021-10-14  1:26   ` Krish Sadhukhan
2021-10-16  2:56   ` Krish Sadhukhan
2021-10-21 15:39   ` Paolo Bonzini
2021-10-25  3:58     ` Michael Roth
2021-10-06 20:37 ` [RFC 07/16] KVM: selftests: add SEV boot tests Michael Roth
2021-10-16  2:55   ` Krish Sadhukhan
2021-10-21  3:35     ` Michael Roth
2021-10-06 20:37 ` [RFC 08/16] KVM: SVM: include CR3 in initial VMSA state for SEV-ES guests Michael Roth
2021-10-21 16:43   ` Paolo Bonzini
2021-10-25  3:59     ` Michael Roth
2021-10-21 16:48 ` [RFC 00/16] KVM: selftests: Add tests for SEV, SEV-ES, and SEV-SNP guests Paolo Bonzini
2021-10-25  4:27   ` Michael Roth
2021-10-25  7:35     ` Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211005234459.430873-12-michael.roth@amd.com \
    --to=michael.roth@amd.com \
    --cc=bp@alien8.de \
    --cc=brijesh.singh@amd.com \
    --cc=dwmw@amazon.co.uk \
    --cc=hpa@zytor.com \
    --cc=jmattson@google.com \
    --cc=joro@8bytes.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=marcorr@google.com \
    --cc=mingo@redhat.com \
    --cc=mizhang@google.com \
    --cc=natet@google.com \
    --cc=ricarkol@google.com \
    --cc=seanjc@google.com \
    --cc=shuah@kernel.org \
    --cc=srutherford@google.com \
    --cc=tglx@linutronix.de \
    --cc=thomas.lendacky@amd.com \
    --cc=varad.gautam@suse.com \
    --cc=vkuznets@redhat.com \
    --cc=wanpengli@tencent.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.