From 5abfa90f247fb546167b2f3a8d201f10707cca30 Mon Sep 17 00:00:00 2001 From: Brijesh Singh 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 Cc: kvm@vger.kernel.org Signed-off-by: Brijesh Singh [BR: FATE#322124] Signed-off-by: Bruce Rogers --- 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; };