qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support


From: Brijesh Singh
Subject: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support
Date: Tue, 13 Sep 2016 10:47:47 -0400
User-agent: StGit/0.17.1-dirty

This patch adds the initial support required to integrate Secure
Encrypted Virtualization feature, the patch include the following
changes:

- adds sev.c and sev.h files: the file will contain SEV APIs implemention.
- add kvm_sev_enabled(): similar to kvm_enabled() this function can be
  used to check if sev is enabled on this guest.
- implement functions to parse SEV specific configuration file.

A typical SEV config file looks like this:

[sev-launch]
        flags = "00000000"
        policy  = "000000"
        dh_pub_qx = "0123456789abcdef0123456789abcdef"
        dh_pub_qy = "0123456789abcdef0123456789abcdef"
        nonce = "0123456789abcdef"
        vcpu_count = "1"
        vcpu_length = "30"
        vcpu_mask = "00ab"


Signed-off-by: Brijesh Singh <address@hidden>
---
 Makefile.target      |    2 
 include/sysemu/kvm.h |   10 ++
 include/sysemu/sev.h |   27 +++++
 kvm-all.c            |    6 +
 sev.c                |  282 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 326 insertions(+), 1 deletion(-)
 create mode 100644 include/sysemu/sev.h
 create mode 100644 sev.c

diff --git a/Makefile.target b/Makefile.target
index a440bcb..74ad204 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -136,7 +136,7 @@ ifdef CONFIG_SOFTMMU
 obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o
 obj-y += qtest.o bootdevice.o
 obj-y += hw/
-obj-$(CONFIG_KVM) += kvm-all.o
+obj-$(CONFIG_KVM) += kvm-all.o sev.o
 obj-y += memory.o cputlb.o
 obj-y += memory_mapping.o
 obj-y += dump.o
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index c9c2436..7f83de0 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -40,6 +40,7 @@
 #endif
 
 extern bool kvm_allowed;
+extern bool kvm_sev_allowed;
 extern bool kvm_kernel_irqchip;
 extern bool kvm_split_irqchip;
 extern bool kvm_async_interrupts_allowed;
@@ -56,6 +57,14 @@ extern bool kvm_ioeventfd_any_length_allowed;
 
 #if defined CONFIG_KVM || !defined NEED_CPU_H
 #define kvm_enabled()           (kvm_allowed)
+
+/**
+ * kvm_sev_enabled:
+ *
+ * Returns: true if guest is running into SEV-enabled mode.
+ */
+#define kvm_sev_enabled()       (kvm_sev_allowed)
+
 /**
  * kvm_irqchip_in_kernel:
  *
@@ -171,6 +180,7 @@ extern bool kvm_ioeventfd_any_length_allowed;
 
 #else
 #define kvm_enabled()           (0)
+#define kvm_sev_enabled()       (false)
 #define kvm_irqchip_in_kernel() (false)
 #define kvm_irqchip_is_split() (false)
 #define kvm_async_interrupts_enabled() (false)
diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
new file mode 100644
index 0000000..0ee8aff
--- /dev/null
+++ b/include/sysemu/sev.h
@@ -0,0 +1,27 @@
+/*
+ * QEMU SEV support
+ *
+ * Copyright: Advanced Micro Devices, 2016
+ *
+ * Authors:
+ *  Brijesh Singh <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_SEV_H
+#define QEMU_SEV_H
+
+#include "sysemu/kvm.h"
+
+/**
+ * sev_init - initialize Secure Encrypted Virtualization on this guest
+ * @kvm_state - KVM handle
+ * Returns: 1 on error, 0 on success
+ */
+int sev_init(KVMState *kvm_state);
+
+#endif
+
diff --git a/kvm-all.c b/kvm-all.c
index ebf35b0..e194849 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -36,6 +36,7 @@
 #include "qemu/event_notifier.h"
 #include "trace.h"
 #include "hw/irq.h"
+#include "sysemu/sev.h"
 
 #include "hw/boards.h"
 
@@ -119,6 +120,7 @@ bool kvm_readonly_mem_allowed;
 bool kvm_vm_attributes_allowed;
 bool kvm_direct_msi_allowed;
 bool kvm_ioeventfd_any_length_allowed;
+bool kvm_sev_allowed;
 
 static const KVMCapabilityInfo kvm_required_capabilites[] = {
     KVM_CAP_INFO(USER_MEMORY),
@@ -1745,6 +1747,10 @@ static int kvm_init(MachineState *ms)
 
     kvm_state = s;
 
+    if (!sev_init(kvm_state)) {
+        kvm_sev_allowed = true;
+    }
+
     if (kvm_eventfds_allowed) {
         s->memory_listener.listener.eventfd_add = kvm_mem_ioeventfd_add;
         s->memory_listener.listener.eventfd_del = kvm_mem_ioeventfd_del;
diff --git a/sev.c b/sev.c
new file mode 100644
index 0000000..2d71ca6
--- /dev/null
+++ b/sev.c
@@ -0,0 +1,282 @@
+/*
+ * QEMU SEV support
+ *
+ * Copyright Advanced Micro Devices 2016
+ *
+ * Author:
+ *      Brijesh Singh <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kvm.h>
+
+#include "qemu-common.h"
+#include "qemu/atomic.h"
+#include "qemu/option.h"
+#include "qemu/config-file.h"
+#include "qemu/error-report.h"
+#include "hw/hw.h"
+#include "hw/pci/msi.h"
+#include "hw/s390x/adapter.h"
+#include "exec/gdbstub.h"
+#include "sysemu/kvm_int.h"
+#include "sysemu/sev.h"
+#include "qemu/bswap.h"
+#include "exec/memory.h"
+#include "exec/ram_addr.h"
+#include "exec/address-spaces.h"
+#include "qemu/event_notifier.h"
+#include "trace.h"
+#include "hw/irq.h"
+
+//#define DEBUG_SEV
+
+#ifdef DEBUG_SEV
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+struct SEVInfo {
+    uint8_t state;  /* guest current state */
+    uint8_t type;   /* guest type (encrypted, unencrypted) */
+    struct kvm_sev_launch_start *launch_start;
+    struct kvm_sev_launch_update *launch_update;
+    struct kvm_sev_launch_finish *launch_finish;
+};
+
+typedef struct SEVInfo SEVInfo;
+static SEVInfo *sev_info;
+static const char *cfg_file;
+
+enum {
+    LAUNCH_OPTS = 0,
+};
+
+enum {
+    PRE_ENCRYPTED_GUEST = 0,
+    UNENCRYPTED_GUEST,
+};
+
+static QemuOptsList launch_opts = {
+    .name = "sev-launch",
+    .head = QTAILQ_HEAD_INITIALIZER(launch_opts.head),
+    .desc = {
+        {
+            .name = "flags",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "policy",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "dh_pub_qx",
+            .type = QEMU_OPT_STRING,
+        },
+        {
+            .name = "dh_pub_qy",
+            .type = QEMU_OPT_STRING,
+        },
+        {
+            .name = "nonce",
+            .type = QEMU_OPT_STRING,
+        },
+        {
+            .name = "vcpu_length",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "vcpu_count",
+            .type = QEMU_OPT_NUMBER,
+        },
+        {
+            .name = "vcpu_mask",
+            .type = QEMU_OPT_STRING,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList *config_groups[] = {
+    &launch_opts,
+    NULL
+};
+
+struct add_rule_data {
+    SEVInfo *s;
+    int action;
+};
+
+static unsigned int read_config_u32(QemuOpts *opts, const char *key)
+{
+    unsigned int val;
+
+    val = qemu_opt_get_number_del(opts, key, -1);
+    DPRINTF(" %s = %08x\n", key, val);
+
+    return val;
+}
+
+static int read_config_u8(QemuOpts *opts, const char *key, uint8_t *val)
+{
+    int i;
+    const char *v;
+
+    v = qemu_opt_get(opts, key);
+    if (!v) {
+        return 0;
+    }
+
+    DPRINTF(" %s = ", key);
+    i = 0;
+    while (*v) {
+        sscanf(v, "%2hhx", &val[i]);
+        DPRINTF("%02hhx", val[i]);
+        v += 2;
+        i++;
+    }
+    DPRINTF("\n");
+
+    return i;
+}
+
+static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
+{
+    struct add_rule_data *d = opaque;
+
+    switch (d->action) {
+        case LAUNCH_OPTS: {
+            struct kvm_sev_launch_start *start;
+            struct kvm_sev_launch_update *update;
+            struct kvm_sev_launch_finish *finish;
+
+            /* LAUNCH_START parameters */
+            start = g_malloc0(sizeof(*start));
+
+            DPRINTF("Parsing 'sev-launch' parameters\n");
+            start->flags = read_config_u32(opts, "flags");
+            start->policy = read_config_u32(opts, "policy");
+            read_config_u8(opts, "nonce", start->nonce);
+            read_config_u8(opts, "dh_pub_qx", start->dh_pub_qx);
+            read_config_u8(opts, "dh_pub_qy", start->dh_pub_qy);
+            sev_info->launch_start = start;
+
+            /* LAUNCH_UPDATE */
+            update = g_malloc0(sizeof(*update));
+            sev_info->launch_update = update;
+
+            /* LAUNCH_FINISH parameters */
+            finish = g_malloc0(sizeof(*finish));
+
+            finish->vcpu_count = read_config_u32(opts, "vcpu_count");
+            finish->vcpu_length = read_config_u32(opts, "vcpu_length");
+            if (qemu_opt_get(opts, "vcpu_mask")) {
+                finish->vcpu_mask_length =
+                                    strlen(qemu_opt_get(opts, "vcpu_mask")) / 
2;
+                finish->vcpu_mask_addr = (unsigned long)
+                                        g_malloc0(finish->vcpu_length);
+                read_config_u8(opts, "vcpu_mask",
+                        (uint8_t *)finish->vcpu_mask_addr);
+            }
+
+            sev_info->launch_finish = finish;
+
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int parse_add_rules(QemuOptsList *list, struct add_rule_data *d)
+{
+    Error *local_err = NULL;
+
+    qemu_opts_foreach(list, add_rule, d, &local_err);
+    if (local_err) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int parse_sev_cfg(SEVInfo *s, int type, const char *filename)
+{
+    FILE *f;
+    int ret = 0;
+    struct add_rule_data d;
+
+    if (filename) {
+        f = fopen(filename, "r");
+        if (f == NULL) {
+            return 1;
+        }
+
+        ret = qemu_config_parse(f, config_groups, filename);
+        if (ret < 0) {
+            fprintf(stderr, "SEV: could not parse config file\n");
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    switch (type) {
+    case LAUNCH_OPTS:
+        d.s = s;
+        d.action = type;
+        ret = parse_add_rules(&launch_opts, &d);
+        break;
+    }
+
+    return ret;
+
+}
+
+int sev_init(KVMState *kvm_state)
+{
+    QemuOpts *opts;
+    const char *type;
+
+    opts = qemu_find_opts_singleton("sev");
+    cfg_file = qemu_opt_get(opts, "config");
+    if (!cfg_file) {
+        return 1;
+    }
+
+    type = qemu_opt_get(opts, "type");
+    if (!type) {
+        return 1;
+    }
+
+    sev_info = calloc(1, sizeof(*sev_info));
+    if (!sev_info) {
+        return 1;
+    }
+
+    if (!strcmp(type, "unencrypted")) {
+        sev_info->type = UNENCRYPTED_GUEST;
+    } else if (!strcmp(type, "encrypted")) {
+        sev_info->type = PRE_ENCRYPTED_GUEST;
+    } else {
+        fprintf(stderr, "SEV: unsupported type '%s'\n", type);
+        goto err;
+    }
+
+    /* call SEV launch start APIs based on guest type */
+
+    return 0;
+err:
+    free(sev_info);
+    sev_info = NULL;
+    return 1;
+}
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]