f3c3b22dd7
- Add AMD SEV (Secure Encrypted Virtualization) support by taking the v7 series of the patches posted to qemu ml. (fate#322124) - Update python3 related patches now that they are upstream OBS-URL: https://build.opensuse.org/request/show/574394 OBS-URL: https://build.opensuse.org/package/show/Virtualization/qemu?expand=0&rev=390
190 lines
5.2 KiB
Diff
190 lines
5.2 KiB
Diff
From 5abfa90f247fb546167b2f3a8d201f10707cca30 Mon Sep 17 00:00:00 2001
|
|
From: Brijesh Singh <brijesh.singh@amd.com>
|
|
Date: Tue, 6 Feb 2018 19:08:09 -0600
|
|
Subject: [PATCH] sev: add command to create launch memory encryption context
|
|
|
|
The KVM_SEV_LAUNCH_START command creates a new VM encryption key (VEK).
|
|
The encryption key created with the command will be used for encrypting
|
|
the bootstrap images (such as guest bios).
|
|
|
|
Cc: Paolo Bonzini <pbonzini@redhat.com>
|
|
Cc: kvm@vger.kernel.org
|
|
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
|
|
[BR: FATE#322124]
|
|
Signed-off-by: Bruce Rogers <brogers@suse.com>
|
|
---
|
|
accel/kvm/sev.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
accel/kvm/trace-events | 2 +
|
|
include/sysemu/sev.h | 10 +++++
|
|
3 files changed, 111 insertions(+)
|
|
|
|
diff --git a/accel/kvm/sev.c b/accel/kvm/sev.c
|
|
index 2c4bbba3c3..2ecc6a1d1a 100644
|
|
--- a/accel/kvm/sev.c
|
|
+++ b/accel/kvm/sev.c
|
|
@@ -29,6 +29,17 @@ static int sev_fd;
|
|
|
|
#define SEV_FW_MAX_ERROR 0x17
|
|
|
|
+static SevGuestState current_sev_guest_state = SEV_STATE_UNINIT;
|
|
+
|
|
+static const char *const sev_state_str[] = {
|
|
+ "uninit",
|
|
+ "lupdate",
|
|
+ "secret",
|
|
+ "running",
|
|
+ "supdate",
|
|
+ "rupdate",
|
|
+};
|
|
+
|
|
static const char *const sev_fw_errlist[] = {
|
|
"",
|
|
"Platform state is invalid",
|
|
@@ -86,6 +97,16 @@ fw_error_to_str(int code)
|
|
return sev_fw_errlist[code];
|
|
}
|
|
|
|
+static void
|
|
+sev_set_guest_state(SevGuestState new_state)
|
|
+{
|
|
+ assert(new_state < SEV_STATE_MAX);
|
|
+
|
|
+ trace_kvm_sev_change_state(sev_state_str[current_sev_guest_state],
|
|
+ sev_state_str[new_state]);
|
|
+ current_sev_guest_state = new_state;
|
|
+}
|
|
+
|
|
static void
|
|
sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
|
|
{
|
|
@@ -337,6 +358,7 @@ sev_get_me_mask(void)
|
|
void
|
|
sev_get_current_state(char **state)
|
|
{
|
|
+ *state = g_strdup(sev_state_str[current_sev_guest_state]);
|
|
}
|
|
|
|
bool
|
|
@@ -355,6 +377,76 @@ sev_get_policy(uint32_t *policy)
|
|
{
|
|
}
|
|
|
|
+static int
|
|
+sev_read_file_base64(const char *filename, guchar **data, gsize *len)
|
|
+{
|
|
+ gsize sz;
|
|
+ gchar *base64;
|
|
+ GError *error = NULL;
|
|
+
|
|
+ if (!g_file_get_contents(filename, &base64, &sz, &error)) {
|
|
+ error_report("failed to read '%s' (%s)", filename, error->message);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ *data = g_base64_decode(base64, len);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+sev_launch_start(SEVState *s)
|
|
+{
|
|
+ gsize sz;
|
|
+ int ret = 1;
|
|
+ int fw_error;
|
|
+ QSevGuestInfo *sev = s->sev_info;
|
|
+ struct kvm_sev_launch_start *start;
|
|
+ guchar *session = NULL, *dh_cert = NULL;
|
|
+
|
|
+ start = g_malloc0(sizeof(*start));
|
|
+ if (!start) {
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ start->handle = object_property_get_int(OBJECT(sev), "handle",
|
|
+ &error_abort);
|
|
+ start->policy = object_property_get_int(OBJECT(sev), "policy",
|
|
+ &error_abort);
|
|
+ if (sev->session_file) {
|
|
+ if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
|
|
+ return 1;
|
|
+ }
|
|
+ start->session_uaddr = (unsigned long)session;
|
|
+ start->session_len = sz;
|
|
+ }
|
|
+
|
|
+ if (sev->dh_cert_file) {
|
|
+ if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
|
|
+ return 1;
|
|
+ }
|
|
+ start->dh_uaddr = (unsigned long)dh_cert;
|
|
+ start->dh_len = sz;
|
|
+ }
|
|
+
|
|
+ trace_kvm_sev_launch_start(start->policy, session, dh_cert);
|
|
+ ret = sev_ioctl(KVM_SEV_LAUNCH_START, start, &fw_error);
|
|
+ if (ret < 0) {
|
|
+ error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
|
|
+ __func__, ret, fw_error, fw_error_to_str(fw_error));
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ object_property_set_int(OBJECT(sev), start->handle, "handle",
|
|
+ &error_abort);
|
|
+ sev_set_guest_state(SEV_STATE_LUPDATE);
|
|
+
|
|
+ g_free(start);
|
|
+ g_free(session);
|
|
+ g_free(dh_cert);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
void *
|
|
sev_guest_init(const char *id)
|
|
{
|
|
@@ -398,6 +490,13 @@ sev_guest_init(const char *id)
|
|
goto err;
|
|
}
|
|
|
|
+ ret = sev_launch_start(s);
|
|
+ if (ret) {
|
|
+ error_report("%s: failed to create encryption context", __func__);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+
|
|
sev_active = true;
|
|
ram_block_notifier_add(&sev_ram_notifier);
|
|
|
|
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
|
|
index 364c84bd7a..5d993ca08e 100644
|
|
--- a/accel/kvm/trace-events
|
|
+++ b/accel/kvm/trace-events
|
|
@@ -17,3 +17,5 @@ kvm_irqchip_release_virq(int virq) "virq %d"
|
|
kvm_sev_init(void) ""
|
|
kvm_memcrypt_register_region(void *addr, size_t len) "addr %p len 0x%lu"
|
|
kvm_memcrypt_unregister_region(void *addr, size_t len) "addr %p len 0x%lu"
|
|
+kvm_sev_change_state(const char *old, const char *new) "%s -> %s"
|
|
+kvm_sev_launch_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p"
|
|
diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
|
|
index 121e7e4aa4..08014a9c94 100644
|
|
--- a/include/sysemu/sev.h
|
|
+++ b/include/sysemu/sev.h
|
|
@@ -58,6 +58,16 @@ struct QSevGuestInfoClass {
|
|
ObjectClass parent_class;
|
|
};
|
|
|
|
+typedef enum {
|
|
+ SEV_STATE_UNINIT = 0,
|
|
+ SEV_STATE_LUPDATE,
|
|
+ SEV_STATE_SECRET,
|
|
+ SEV_STATE_RUNNING,
|
|
+ SEV_STATE_SUPDATE,
|
|
+ SEV_STATE_RUPDATE,
|
|
+ SEV_STATE_MAX
|
|
+} SevGuestState;
|
|
+
|
|
struct SEVState {
|
|
QSevGuestInfo *sev_info;
|
|
};
|