From: Peter Gonda <pgonda@google.com>
To: pgonda@google.com, seanjc@google.com
Cc: linux-kernel@vger.kernel.org,
Vishal Annapurve <vannapurve@google.com>,
Ackerley Tng <ackerleytng@google.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Claudio Imbrenda <imbrenda@linux.ibm.com>,
Carlos Bilbao <carlos.bilbao@amd.com>,
Tom Lendacky <thomas.lendacky@amd.com>,
Michael Roth <michael.roth@amd.com>,
kvm@vger.kernel.org, linux-kselftest@vger.kernel.org
Subject: [PATCH 6/6] Add ability for SEV-ES guests to use ucalls via GHCB
Date: Tue, 9 Apr 2024 06:39:59 -0700 [thread overview]
Message-ID: <20240409133959.2888018-7-pgonda@google.com> (raw)
In-Reply-To: <20240409133959.2888018-1-pgonda@google.com>
Modifies ucall handling for SEV-ES VMs. Instead of using an out
instruction and storing the ucall pointer in RDI, SEV-ES guests use a
outsb VMGEXIT to move the ucall pointer as the data. Allows for SEV-ES
to use ucalls instead of relying the SEV-ES MSR based termination protocol.
Cc: Vishal Annapurve <vannapurve@google.com>
Cc: Ackerley Tng <ackerleytng@google.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Claudio Imbrenda <imbrenda@linux.ibm.com>
Cc: Sean Christopherson <seanjc@google.com>
Cc: Carlos Bilbao <carlos.bilbao@amd.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Michael Roth <michael.roth@amd.com>
Cc: kvm@vger.kernel.org
Cc: linux-kselftest@vger.kernel.org
Signed-off-by: Peter Gonda <pgonda@google.com>
---
.../selftests/kvm/include/x86_64/sev.h | 2 +
tools/testing/selftests/kvm/lib/x86_64/sev.c | 67 ++++++++++++++++++-
.../testing/selftests/kvm/lib/x86_64/ucall.c | 17 +++++
.../selftests/kvm/x86_64/sev_smoke_test.c | 17 +----
4 files changed, 84 insertions(+), 19 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/x86_64/sev.h b/tools/testing/selftests/kvm/include/x86_64/sev.h
index 691dc005e2a1..26447caccd40 100644
--- a/tools/testing/selftests/kvm/include/x86_64/sev.h
+++ b/tools/testing/selftests/kvm/include/x86_64/sev.h
@@ -109,4 +109,6 @@ static inline void sev_launch_update_data(struct kvm_vm *vm, vm_paddr_t gpa,
bool is_sev_enabled(void);
bool is_sev_es_enabled(void);
+void sev_es_ucall_port_write(uint32_t port, uint64_t data);
+
#endif /* SELFTEST_KVM_SEV_H */
diff --git a/tools/testing/selftests/kvm/lib/x86_64/sev.c b/tools/testing/selftests/kvm/lib/x86_64/sev.c
index 5b3f0a8a931a..276477f2c2cf 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/sev.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/sev.c
@@ -8,11 +8,18 @@
#include "svm.h"
#include "svm_util.h"
+#define IOIO_TYPE_STR (1 << 2)
+#define IOIO_SEG_DS (1 << 11 | 1 << 10)
+#define IOIO_DATA_8 (1 << 4)
+#define IOIO_REP (1 << 3)
+
+#define SW_EXIT_CODE_IOIO 0x7b
+
struct ghcb_entry {
struct ghcb ghcb;
/* Guest physical address of this GHCB. */
- void *gpa;
+ uint64_t gpa;
/* Host virtual address of this struct. */
struct ghcb_entry *hva;
@@ -45,16 +52,22 @@ void ghcb_init(struct kvm_vm *vm)
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
entry = &hdr->ghcbs[i];
entry->hva = entry;
- entry->gpa = addr_hva2gpa(vm, &entry->ghcb);
+ entry->gpa = (uint64_t)addr_hva2gpa(vm, &entry->ghcb);
}
write_guest_global(vm, ghcb_pool, (struct ghcb_header *)vaddr);
}
+static void sev_es_terminate(void)
+{
+ wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ);
+}
+
static struct ghcb_entry *ghcb_alloc(void)
{
return &ghcb_pool->ghcbs[0];
struct ghcb_entry *entry;
+ struct ghcb *ghcb;
int i;
if (!ghcb_pool)
@@ -63,12 +76,18 @@ static struct ghcb_entry *ghcb_alloc(void)
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
if (!test_and_set_bit(i, ghcb_pool->in_use)) {
entry = &ghcb_pool->ghcbs[i];
- memset(&entry->ghcb, 0, sizeof(entry->ghcb));
+ ghcb = &entry->ghcb;
+
+ memset(&ghcb, 0, sizeof(*ghcb));
+ ghcb->ghcb_usage = 0;
+ ghcb->protocol_version = 1;
+
return entry;
}
}
ucall_failed:
+ sev_es_terminate();
return NULL;
}
@@ -200,3 +219,45 @@ bool is_sev_es_enabled(void)
return is_sev_enabled() &&
rdmsr(MSR_AMD64_SEV) & MSR_AMD64_SEV_ES_ENABLED;
}
+
+static uint64_t setup_exitinfo1_portio(uint32_t port)
+{
+ uint64_t exitinfo1 = 0;
+
+ exitinfo1 |= IOIO_TYPE_STR;
+ exitinfo1 |= ((port & 0xffff) << 16);
+ exitinfo1 |= IOIO_SEG_DS;
+ exitinfo1 |= IOIO_DATA_8;
+ exitinfo1 |= IOIO_REP;
+
+ return exitinfo1;
+}
+
+static void do_vmg_exit(uint64_t ghcb_gpa)
+{
+ wrmsr(MSR_AMD64_SEV_ES_GHCB, ghcb_gpa);
+ __asm__ __volatile__("rep; vmmcall");
+}
+
+void sev_es_ucall_port_write(uint32_t port, uint64_t data)
+{
+ struct ghcb_entry *entry;
+ struct ghcb *ghcb;
+ const uint64_t exitinfo1 = setup_exitinfo1_portio(port);
+
+ entry = ghcb_alloc();
+ ghcb = &entry->ghcb;
+
+ ghcb_set_sw_exit_code(ghcb, SW_EXIT_CODE_IOIO);
+ ghcb_set_sw_exit_info_1(ghcb, exitinfo1);
+ ghcb_set_sw_exit_info_2(ghcb, sizeof(data));
+
+ // Setup the SW Stratch buffer pointer.
+ ghcb_set_sw_scratch(ghcb,
+ entry->gpa + offsetof(struct ghcb, shared_buffer));
+ memcpy(&ghcb->shared_buffer, &data, sizeof(data));
+
+ do_vmg_exit(entry->gpa);
+
+ ghcb_free(entry);
+}
diff --git a/tools/testing/selftests/kvm/lib/x86_64/ucall.c b/tools/testing/selftests/kvm/lib/x86_64/ucall.c
index 1265cecc7dd1..24da2f4316d8 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/ucall.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/ucall.c
@@ -5,6 +5,8 @@
* Copyright (C) 2018, Red Hat, Inc.
*/
#include "kvm_util.h"
+#include "processor.h"
+#include "sev.h"
#define UCALL_PIO_PORT ((uint16_t)0x1000)
@@ -21,6 +23,10 @@ void ucall_arch_do_ucall(vm_vaddr_t uc)
#define HORRIFIC_L2_UCALL_CLOBBER_HACK \
"rcx", "rsi", "r8", "r9", "r10", "r11"
+ if (is_sev_es_enabled()) {
+ sev_es_ucall_port_write(UCALL_PIO_PORT, uc);
+ }
+
asm volatile("push %%rbp\n\t"
"push %%r15\n\t"
"push %%r14\n\t"
@@ -48,8 +54,19 @@ void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
struct kvm_regs regs;
+ uint64_t addr;
+
+ if (vcpu->vm->subtype == VM_SUBTYPE_SEV_ES) {
+ TEST_ASSERT(
+ run->io.count == 8 && run->io.size == 1,
+ "SEV-ES ucall exit requires 8 byte string out\n");
+
+ addr = *(uint64_t *)((uint8_t *)(run) + run->io.data_offset);
+ return (void *)addr;
+ }
vcpu_regs_get(vcpu, ®s);
+
return (void *)regs.rdi;
}
return NULL;
diff --git a/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c b/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c
index 1d84e78e7ae2..2448533a9a41 100644
--- a/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c
+++ b/tools/testing/selftests/kvm/x86_64/sev_smoke_test.c
@@ -18,12 +18,7 @@ static void guest_sev_es_code(void)
/* TODO: Check CPUID after GHCB-based hypercall support is added. */
GUEST_ASSERT(is_sev_es_enabled());
- /*
- * TODO: Add GHCB and ucall support for SEV-ES guests. For now, simply
- * force "termination" to signal "done" via the GHCB MSR protocol.
- */
- wrmsr(MSR_AMD64_SEV_ES_GHCB, GHCB_MSR_TERM_REQ);
- __asm__ __volatile__("rep; vmmcall");
+ GUEST_DONE();
}
static void guest_sev_code(void)
@@ -45,16 +40,6 @@ static void test_sev(void *guest_code, uint64_t policy)
for (;;) {
vcpu_run(vcpu);
- if (policy & SEV_POLICY_ES) {
- TEST_ASSERT(vcpu->run->exit_reason == KVM_EXIT_SYSTEM_EVENT,
- "Wanted SYSTEM_EVENT, got %s",
- exit_reason_str(vcpu->run->exit_reason));
- TEST_ASSERT_EQ(vcpu->run->system_event.type, KVM_SYSTEM_EVENT_SEV_TERM);
- TEST_ASSERT_EQ(vcpu->run->system_event.ndata, 1);
- TEST_ASSERT_EQ(vcpu->run->system_event.data[0], GHCB_MSR_TERM_REQ);
- break;
- }
-
switch (get_ucall(vcpu, &uc)) {
case UCALL_SYNC:
continue;
--
2.44.0.478.gd926399ef9-goog
next prev parent reply other threads:[~2024-04-09 13:40 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-09 13:39 [PATCH 0/6] Add initial GHCB support for SEV-ES selftests Peter Gonda
2024-04-09 13:39 ` [PATCH 1/6] Add GHCB with setters and getters Peter Gonda
2024-04-23 23:07 ` Sean Christopherson
2024-04-09 13:39 ` [PATCH 2/6] Add arch specific additional guest pages Peter Gonda
2024-04-09 13:39 ` [PATCH 3/6] Add vm_vaddr_alloc_pages_shared() Peter Gonda
2024-04-09 13:39 ` [PATCH 4/6] Add GHCB allocations and helpers Peter Gonda
2024-04-24 0:58 ` Sean Christopherson
2024-04-24 14:39 ` Sean Christopherson
2024-04-24 20:13 ` Sean Christopherson
2024-04-09 13:39 ` [PATCH 5/6] Add is_sev_enabled() helpers Peter Gonda
2024-04-23 23:12 ` Sean Christopherson
2024-04-09 13:39 ` Peter Gonda [this message]
2024-04-23 23:50 ` [PATCH 6/6] Add ability for SEV-ES guests to use ucalls via GHCB Sean Christopherson
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=20240409133959.2888018-7-pgonda@google.com \
--to=pgonda@google.com \
--cc=ackerleytng@google.com \
--cc=carlos.bilbao@amd.com \
--cc=imbrenda@linux.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=michael.roth@amd.com \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=thomas.lendacky@amd.com \
--cc=vannapurve@google.com \
/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.