target/i386: add Secure Encrypted Virtualization (SEV) object

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 <pbonzini@redhat.com>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Brijesh Singh 2018-03-08 06:48:41 -06:00 committed by Paolo Bonzini
parent 54e8953967
commit a9b4942f48
7 changed files with 353 additions and 0 deletions

View file

@ -5,6 +5,7 @@ obj-$(CONFIG_TCG) += int_helper.o mem_helper.o misc_helper.o mpx_helper.o
obj-$(CONFIG_TCG) += seg_helper.o smm_helper.o svm_helper.o
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o monitor.o
obj-$(CONFIG_KVM) += kvm.o hyperv.o
obj-$(CONFIG_SEV) += sev.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
# HAX support
ifdef CONFIG_WIN32

228
target/i386/sev.c Normal file
View file

@ -0,0 +1,228 @@
/*
* QEMU SEV support
*
* Copyright Advanced Micro Devices 2016-2018
*
* Author:
* Brijesh Singh <brijesh.singh@amd.com>
*
* 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);

61
target/i386/sev_i386.h Normal file
View file

@ -0,0 +1,61 @@
/*
* QEMU Secure Encrypted Virutualization (SEV) support
*
* Copyright: Advanced Micro Devices, 2016-2018
*
* Authors:
* Brijesh Singh <brijesh.singh@amd.com>
*
* 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