From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60598) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evjUd-0001Iv-9o for qemu-devel@nongnu.org; Tue, 13 Mar 2018 08:57:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evjUZ-0000jU-5V for qemu-devel@nongnu.org; Tue, 13 Mar 2018 08:57:27 -0400 Received: from mail-wr0-x244.google.com ([2a00:1450:400c:c0c::244]:33253) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1evjUY-0000ig-RN for qemu-devel@nongnu.org; Tue, 13 Mar 2018 08:57:23 -0400 Received: by mail-wr0-x244.google.com with SMTP id r8so7234874wrg.0 for ; Tue, 13 Mar 2018 05:57:22 -0700 (PDT) Sender: Paolo Bonzini From: Paolo Bonzini Date: Tue, 13 Mar 2018 13:56:23 +0100 Message-Id: <1520945798-50640-8-git-send-email-pbonzini@redhat.com> In-Reply-To: <1520945798-50640-1-git-send-email-pbonzini@redhat.com> References: <1520945798-50640-1-git-send-email-pbonzini@redhat.com> Subject: [Qemu-devel] [PULL 07/22] target/i386: add Secure Encrypted Virtualization (SEV) object List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Brijesh Singh , Richard Henderson , Eduardo Habkost From: Brijesh Singh Add a new memory encryption object 'sev-guest'. The object will be used to create encrypted VMs on AMD EPYC CPU. The object provides the properties to pass guest owner's public Diffie-hellman key, guest policy and session information required to create the memory encryption context within the SEV firmware. e.g to launch SEV guest # $QEMU \ -object sev-guest,id=sev0 \ -machine ....,memory-encryption=sev0 Cc: Paolo Bonzini Cc: Richard Henderson Cc: Eduardo Habkost Signed-off-by: Brijesh Singh Signed-off-by: Paolo Bonzini --- default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + docs/amd-memory-encryption.txt | 17 +++ qemu-options.hx | 44 +++++++ target/i386/Makefile.objs | 1 + target/i386/sev.c | 228 +++++++++++++++++++++++++++++++++++++ target/i386/sev_i386.h | 61 ++++++++++ 7 files changed, 353 insertions(+) create mode 100644 target/i386/sev.c create mode 100644 target/i386/sev_i386.h diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 3326e3e..8973579 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -63,3 +63,4 @@ CONFIG_PXB=y CONFIG_ACPI_VMGENID=y CONFIG_FW_CFG_DMA=y CONFIG_I2C=y +CONFIG_SEV=$(CONFIG_KVM) diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 1c6cda1..5e27a7a 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -63,3 +63,4 @@ CONFIG_PXB=y CONFIG_ACPI_VMGENID=y CONFIG_FW_CFG_DMA=y CONFIG_I2C=y +CONFIG_SEV=$(CONFIG_KVM) diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt index 9486a22..f483795 100644 --- a/docs/amd-memory-encryption.txt +++ b/docs/amd-memory-encryption.txt @@ -35,10 +35,21 @@ in bad measurement). The guest policy is a 4-byte data structure containing several flags that restricts what can be done on running SEV guest. See KM Spec section 3 and 6.2 for more details. +The guest policy can be provided via the 'policy' property (see below) + +# ${QEMU} \ + sev-guest,id=sev0,policy=0x1...\ + Guest owners provided DH certificate and session parameters will be used to establish a cryptographic session with the guest owner to negotiate keys used for the attestation. +The DH certificate and session blob can be provided via 'dh-cert-file' and +'session-file' property (see below + +# ${QEMU} \ + sev-guest,id=sev0,dh-cert-file=,session-file= + LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context created via LAUNCH_START command. If required, this command can be called multiple times to encrypt different memory regions. The command also calculates @@ -59,6 +70,12 @@ context. See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the complete flow chart. +To launch a SEV guest + +# ${QEMU} \ + -machine ...,memory-encryption=sev0 \ + -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1 + Debugging ----------- Since memory contents of SEV guest is encrypted hence hypervisor access to the diff --git a/qemu-options.hx b/qemu-options.hx index 4c28014..6113bce 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4353,6 +4353,50 @@ contents of @code{iv.b64} to the second secret data=$SECRET,iv=$( + * + * 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 "qapi/error.h" +#include "qom/object_interfaces.h" +#include "qemu/base64.h" +#include "sysemu/kvm.h" +#include "sev_i386.h" +#include "sysemu/sysemu.h" + +#define DEFAULT_GUEST_POLICY 0x1 /* disable debug */ +#define DEFAULT_SEV_DEVICE "/dev/sev" + +static void +qsev_guest_finalize(Object *obj) +{ +} + +static char * +qsev_guest_get_session_file(Object *obj, Error **errp) +{ + QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + + return s->session_file ? g_strdup(s->session_file) : NULL; +} + +static void +qsev_guest_set_session_file(Object *obj, const char *value, Error **errp) +{ + QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + + s->session_file = g_strdup(value); +} + +static char * +qsev_guest_get_dh_cert_file(Object *obj, Error **errp) +{ + QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + + return g_strdup(s->dh_cert_file); +} + +static void +qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp) +{ + QSevGuestInfo *s = QSEV_GUEST_INFO(obj); + + s->dh_cert_file = g_strdup(value); +} + +static char * +qsev_guest_get_sev_device(Object *obj, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + return g_strdup(sev->sev_device); +} + +static void +qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + sev->sev_device = g_strdup(value); +} + +static void +qsev_guest_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_str(oc, "sev-device", + qsev_guest_get_sev_device, + qsev_guest_set_sev_device, + NULL); + object_class_property_set_description(oc, "sev-device", + "SEV device to use", NULL); + object_class_property_add_str(oc, "dh-cert-file", + qsev_guest_get_dh_cert_file, + qsev_guest_set_dh_cert_file, + NULL); + object_class_property_set_description(oc, "dh-cert-file", + "guest owners DH certificate (encoded with base64)", NULL); + object_class_property_add_str(oc, "session-file", + qsev_guest_get_session_file, + qsev_guest_set_session_file, + NULL); + object_class_property_set_description(oc, "session-file", + "guest owners session parameters (encoded with base64)", NULL); +} + +static void +qsev_guest_set_handle(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + uint32_t value; + + visit_type_uint32(v, name, &value, errp); + sev->handle = value; +} + +static void +qsev_guest_set_policy(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + uint32_t value; + + visit_type_uint32(v, name, &value, errp); + sev->policy = value; +} + +static void +qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + uint32_t value; + + visit_type_uint32(v, name, &value, errp); + sev->cbitpos = value; +} + +static void +qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + uint32_t value; + + visit_type_uint32(v, name, &value, errp); + sev->reduced_phys_bits = value; +} + +static void +qsev_guest_get_policy(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + value = sev->policy; + visit_type_uint32(v, name, &value, errp); +} + +static void +qsev_guest_get_handle(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + value = sev->handle; + visit_type_uint32(v, name, &value, errp); +} + +static void +qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + value = sev->cbitpos; + visit_type_uint32(v, name, &value, errp); +} + +static void +qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t value; + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + value = sev->reduced_phys_bits; + visit_type_uint32(v, name, &value, errp); +} + +static void +qsev_guest_init(Object *obj) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE); + sev->policy = DEFAULT_GUEST_POLICY; + object_property_add(obj, "policy", "uint32", qsev_guest_get_policy, + qsev_guest_set_policy, NULL, NULL, NULL); + object_property_add(obj, "handle", "uint32", qsev_guest_get_handle, + qsev_guest_set_handle, NULL, NULL, NULL); + object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos, + qsev_guest_set_cbitpos, NULL, NULL, NULL); + object_property_add(obj, "reduced-phys-bits", "uint32", + qsev_guest_get_reduced_phys_bits, + qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL); +} + +/* sev guest info */ +static const TypeInfo qsev_guest_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QSEV_GUEST_INFO, + .instance_size = sizeof(QSevGuestInfo), + .instance_finalize = qsev_guest_finalize, + .class_size = sizeof(QSevGuestInfoClass), + .class_init = qsev_guest_class_init, + .instance_init = qsev_guest_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void +sev_register_types(void) +{ + type_register_static(&qsev_guest_info); +} + +type_init(sev_register_types); diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h new file mode 100644 index 0000000..caf879c --- /dev/null +++ b/target/i386/sev_i386.h @@ -0,0 +1,61 @@ +/* + * QEMU Secure Encrypted Virutualization (SEV) support + * + * Copyright: Advanced Micro Devices, 2016-2018 + * + * Authors: + * Brijesh Singh + * + * 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_I386_H +#define QEMU_SEV_I386_H + +#include "qom/object.h" +#include "qapi/error.h" +#include "sysemu/kvm.h" +#include "qemu/error-report.h" + +#define SEV_POLICY_NODBG 0x1 +#define SEV_POLICY_NOKS 0x2 +#define SEV_POLICY_ES 0x4 +#define SEV_POLICY_NOSEND 0x8 +#define SEV_POLICY_DOMAIN 0x10 +#define SEV_POLICY_SEV 0x20 + +#define TYPE_QSEV_GUEST_INFO "sev-guest" +#define QSEV_GUEST_INFO(obj) \ + OBJECT_CHECK(QSevGuestInfo, (obj), TYPE_QSEV_GUEST_INFO) + +typedef struct QSevGuestInfo QSevGuestInfo; +typedef struct QSevGuestInfoClass QSevGuestInfoClass; + +/** + * QSevGuestInfo: + * + * The QSevGuestInfo object is used for creating a SEV guest. + * + * # $QEMU \ + * -object sev-guest,id=sev0 \ + * -machine ...,memory-encryption=sev0 + */ +struct QSevGuestInfo { + Object parent_obj; + + char *sev_device; + uint32_t policy; + uint32_t handle; + char *dh_cert_file; + char *session_file; + uint32_t cbitpos; + uint32_t reduced_phys_bits; +}; + +struct QSevGuestInfoClass { + ObjectClass parent_class; +}; + +#endif -- 1.8.3.1