[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support
From: |
Daniel P. Berrange |
Subject: |
Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support |
Date: |
Wed, 14 Sep 2016 09:37:15 +0100 |
User-agent: |
Mutt/1.7.0 (2016-08-17) |
On Tue, Sep 13, 2016 at 10:47:47AM -0400, Brijesh Singh wrote:
> 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"
We do not want to be inventing new config options for this - we should
be using QOM via -object to create this.
> 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;
> + }
Use 'g_new0' for allocation and dont check the return
value since g_new0 aborts on oom.
> +
> + if (!strcmp(type, "unencrypted")) {
> + sev_info->type = UNENCRYPTED_GUEST;
> + } else if (!strcmp(type, "encrypted")) {
> + sev_info->type = PRE_ENCRYPTED_GUEST;
You should define an enum in qapi-schema.json for these
values, and use an enum property for 'type' in the QOM
object you then create. This automatically then handles
the string <-> int conversion
> + } 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;
> +}
All the command line argument handling in this file should be removed.
Instead you should define a user creatable object type to represent
the properties you need to have configured. If you want a simple
example of how to define a QOM object type, take a look at the code
in crypto/secret.c
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, (continued)
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Michael S. Tsirkin, 2016/09/13
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Eduardo Habkost, 2016/09/13
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Daniel P. Berrange, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Eduardo Habkost, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Daniel P. Berrange, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Brijesh Singh, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Daniel P. Berrange, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Michael S. Tsirkin, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Brijesh Singh, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support, Michael S. Tsirkin, 2016/09/14
Re: [Qemu-devel] [RFC PATCH v1 06/22] sev: add initial SEV support,
Daniel P. Berrange <=
[Qemu-devel] [RFC PATCH v1 18/22] i386: clear C-bit in SEV guest page table walk, Brijesh Singh, 2016/09/13
[Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Brijesh Singh, 2016/09/13
- Re: [Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Paolo Bonzini, 2016/09/13
- Re: [Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Brijesh Singh, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Paolo Bonzini, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Brijesh Singh, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Paolo Bonzini, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Brijesh Singh, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Paolo Bonzini, 2016/09/14
- Re: [Qemu-devel] [RFC PATCH v1 15/22] i386: sev: register RAM read/write ops for BIOS and PC.RAM region, Brijesh Singh, 2016/09/14