diff mbox

[RFC,v3,07/18] sev: add Secure Encrypted Virtulization (SEV) support

Message ID 147801558020.18237.18202763050547452134.stgit@brijesh-build-machine (mailing list archive)
State New, archived
Headers show

Commit Message

Brijesh Singh Nov. 1, 2016, 3:53 p.m. UTC
This patch adds the initial support required to integrate Secure
Encrypted Virtualization (SEV) feature. SEV is an extension to the
existing AMD-V technology found on AMD processors. The SEV feature
allows the memory contents of a virtual machine to be transparently
encrypted with a key unique to the guest VM.

In QEMU command line, SEV can be enabled via memory-encryption property
defined in security-policy object.

The patch adds the following new objects:

- sev-launch-info: provides the properties to set/get parameters used
  to boot SEV guest from unencrypted boot images.

  In this mode the OS images (kernel, initrd and  bios) provides by guest
  owner are unencrypted. The SEV guest boot process would encrypt the
  images using the guest owners PDH key provided through this object.

- sev-guest: a top level object to transition a guest into SEV-enabled

e.g to launch SEV guest from unencrypted boot images
 # $QEMU \
    -object sev-launch-info,id=launch0,nonce=abcd,pub-dh-qx=1234 \
    -object sev-guest,id,sev0 \
    -object security-policy,id=secure0,memory-encryption=sev0 \
    -machine ....,security-policy=secure0

Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 Makefile.target                |    2 
 docs/amd-memory-encryption.txt |  153 +++++++++++++++++
 include/sysemu/sev.h           |  112 +++++++++++++
 kvm-all.c                      |   26 +++
 qemu-options.hx                |   34 ++++
 sev.c                          |  350 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 676 insertions(+), 1 deletion(-)
 create mode 100644 docs/amd-memory-encryption.txt
 create mode 100644 include/sysemu/sev.h
 create mode 100644 sev.c
diff mbox

Patch

diff --git a/Makefile.target b/Makefile.target
index 7a5080e..004c3cd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -137,7 +137,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/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
new file mode 100644
index 0000000..682f8e9
--- /dev/null
+++ b/docs/amd-memory-encryption.txt
@@ -0,0 +1,153 @@ 
+Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
+
+SEV feature allows the memory contents of a virtual machine (VM) to be
+transparently  encrypted with a key unique to the guest VM. The memory
+controller contains a high performance encryption engine which can be
+programmed with multiple keys for used by different VMs in the system.
+The programming and management of these keys is handled by the AMD  Secure
+Processor firmware which exposes commands for these tasks.
+
+At highest level the SEV key management APIs are divided into two sections:
+
+* Platform management commands
+* Guest management commands
+
+In this doc we will focus on Guest management commands. 
+
+SEV is capable of supporting both light-weight virtual containers as well as
+conventional VM within an enterprise cloud environment. In either case, there
+are two parties concerned in the deployment of SEV guest: the guest owner and
+the platform owner. For example, in a cloud environment, the platform owner
+would be cloud vendor and the guest owner would be the user that wishes to run
+their workload in the cloud.
+
+1. Guest Management Commands
+-----------------------------
+
+The guest management commands provide the support for common guest lifecycle
+events. These events include launching, running, snapshotting, migrating and
+decommission guest. The guest management commands are issued through
+KVM_SEV_ISSUE_CMD ioctl.
+
+1.1 Launch
+
+When a guest is launched, its memory must first be encrypted using guest owners
+key before SEV can be enabled in hardware. There are two types of launches:
+
+1.1.1 unencrypted
+
+Boot images (such as bios, kernel, initrd) provided by the guest owner to
+bootstrap the guest is unencrypted. The firmware provides interfaces to
+bootstrap the memory encryption for this purpose: LAUNCH_START, LAUNCH_UPDATE,
+and LAUNCH_FINISH. These three commands together generate a fresh memory
+encryption key for the guest, encrypt guest memory and provide an attestation
+of the successful launch.
+
+LAUNCH_START is called first to create a guest context within the firmware.
+To create this context, qemu user must provide guest's security policy, guest
+owners public Diffie-Hellman key (P-256 defined in section D.1.2.3 of
+[FIPS 186-4]) and nonce. The guest security policy is a 4-byte data structure
+containing several flags that restrict what the hypervisor can do on the running
+SEV guest. The guest security policy should be provided by the guest owner, any
+changes in policy by hypervisor would result in the wrong measurement. The policy
+is applied to the lifetime of the guest. Guest owners public diffie-hellman (pdh)
+key is used to establish a cryptographic session with the guest owner to
+negotiate keys used for attestation. If the hypervisor requests this guest to
+share key with another SEV guest then hypervisor must set 'key-sharing' and
+'handle' in LAUNCH_START command. The key sharing is permitted only if guest
+policy allows it.
+
+LAUNCH_UPDATE 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 the measurement
+of the memory contents as it encrypts.
+
+LAUNCH_FINISH command finalizes the guest launch and generates measurement.
+This measurement is a signature of the memory contents that can be sent to the
+guest owner as an attestation that the memory was encrypted correctly by the
+firmware. The guest owner may wait to provide the guest confidential information
+until it can verify the attestation measurement. Since the guest owner knows the
+initial contents of the guest at boot, the attestation measurement can be
+verified by comparing it to what the guest owner expects.
+
+SEV support can be enabled via 'memory-encryption' parameters defined in
+security-policy object. If memory-encryption is enabled, then hypervisor
+uses MemoryRegionReadWriteOps callbacks to access guest memory.
+
+Before vm_start, rom_reset copies boot images from internal rom to guest memory
+as shown below.
+
+                       +----------------------+
+                       |   qemu_system_reset  |
+                       +----------------------+
+                                |
+                                |
+                                V
+                    +-----------------------------+
+                    |      rom_reset (loader.c)   |
+                    +-----------------------------+
+                           |    |      |
+       +-------------------+    |      +-----------------+
+       |                        |                        |
+       V                        V                        V
+  +--------------+      +------------------+       +----------------+
+  | LAUNCH_START |      | memory_rom_write |       | LAUNCH_FINISH  |
+  +--------------+      +------------------+       +----------------+
+                                |
+                                | 
+                                V
+                         +------------------+
+                         |  LAUNCH_UPDATE   |
+                         +------------------+
+
+Input to LAUNCH_START command can be provided through the properties defined in
+'sev-launch-info' object.
+
+e.g to launch SEV guest from unencrypted boot images
+
+# ${QEMU} \
+      -object sev-launch-info,id=launch0,dh-pub-qx=abcd,dh-pub-qy=1234,nonce=1234\
+      -object sev-guest,id=sev0\
+      -object security-policy,id=mypolicy,memory-encryption=sev0\
+      -machine ...,security-policy=mypolicy
+
+e.g launch this SEV guest using another SEV guest key (key sharing)
+
+# ${QEMU} \
+      -object sev-launch-info,id=launch0,key-sharing=on,handle=1234\
+      -object sev-guest,id=sev0\
+      -object security-policy,id=mypolicy,memory-encryption=sev0\
+      -machine ...,security-policy=mypolicy
+
+1.1.2 pre-encrypted
+
+1.2 Snapshot
+
+1.3 Restore
+
+1.4 Live Migration
+
+1.5 Debugging
+
+Since memory contents of SEV guest is encrypted hence hypervisor access to the
+guest memory will get a cipher text. If guest policy allows debugging, then
+hypervisor is allowed to access guest memory. Hypervisor can use DEBUG_DECRYPT
+command to decrypt guest memory region for debug purposes. Similarly hypervisor
+can use DEBUG_ENCRYPT command to write into guest memory.
+
+2. References
+-----------------
+
+AMD Memory Encryption whitepaper:
+http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
+
+Secure Encrypted Virutualization Key Management:
+http://support.amd.com/TechDocs/55766_SEV-KM API_Spec.pdf
+
+KVM Forum slides:
+http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
+
+AMD64 Architecture Programmer's Manual:
+   http://support.amd.com/TechDocs/24593.pdf
+   SME is section 7.10
+   SEV is section 15.34
diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h
new file mode 100644
index 0000000..5ca39d1
--- /dev/null
+++ b/include/sysemu/sev.h
@@ -0,0 +1,112 @@ 
+/*
+ * QEMU Secure Encrypted Virutualization (SEV) support
+ *
+ * Copyright: Advanced Micro Devices, 2016
+ *
+ * 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_H
+#define QEMU_SEV_H
+
+#include <linux/kvm.h>
+
+#include "qom/object.h"
+#include "qapi/error.h"
+#include "sysemu/kvm.h"
+
+#define TYPE_QSEV_LAUNCH_INFO "sev-launch-info"
+#define QSEV_LAUNCH_INFO(obj)                  \
+    OBJECT_CHECK(QSevLaunchInfo, (obj), TYPE_QSEV_LAUNCH_INFO)
+
+typedef struct QSevLaunchInfo QSevLaunchInfo;
+typedef struct QSevLaunchInfoClass QSevLaunchInfoClass;
+
+/**
+ * QSevLaunchInfo:
+ *
+ * The QSevLaunchInfo object provides parameters to launch a SEV
+ * guest from unnencrypted boot images. SEV will encrypt the boot images using
+ * guest owner's key before launching the guest.
+ *
+ * # $QEMU -object sev-launch-info,id=launch0,dh-pub-qx=abcd \
+ *         ....
+ */
+struct QSevLaunchInfo {
+    Object parent_obj;
+    char *nonce;
+    char *dh_pub_qx;
+    char *dh_pub_qy;
+};
+
+struct QSevLaunchInfoClass {
+    ObjectClass parent_class;
+};
+
+#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.
+ *
+ * e.g to launch a SEV guest from unencrypted boot images
+ *
+ * # $QEMU -object sev-launch-info,id=launch0 \
+ *         -object sev-guest,id=sev0 \
+ *         -object security-policy,id=secure0,memory-encryption=sev0 \
+ *         -machine ...security-policy=secure0
+ */
+struct QSevGuestInfo {
+    Object parent_obj;
+
+    QSevLaunchInfo *launch_info;
+};
+
+struct QSevGuestInfoClass {
+    ObjectClass parent_class;
+};
+
+struct SEVState {
+    uint8_t state;
+    QSevGuestInfo *sev_info;
+};
+
+typedef struct SEVState SEVState;
+
+enum {
+    INVALID_TYPE = 0,
+    USE_LAUNCH_INFO,
+    USE_RECEIVE_INFO
+};
+
+enum {
+    SEV_STATE_INVALID = 0,
+    SEV_STATE_LAUNCHING,
+    SEV_STATE_RECEIVING,
+    SEV_STATE_SENDING,
+    SEV_STATE_RUNNING
+};
+
+bool sev_enabled(void);
+void *sev_guest_init(const char *keyid);
+int sev_guest_launch_start(void *handle);
+int sev_guest_launch_finish(void *handle);
+void sev_guest_set_debug_ops(void *handle, MemoryRegion *mr);
+int sev_guest_mem_dec(void *handle, uint8_t *dst,
+        const uint8_t *src, uint32_t len);
+int sev_guest_mem_enc(void *handle, uint8_t *dst,
+        const uint8_t *src, uint32_t len);
+
+#endif
+
diff --git a/kvm-all.c b/kvm-all.c
index 86c810e..e712b96 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -37,6 +37,7 @@ 
 #include "trace.h"
 #include "hw/irq.h"
 #include "sysemu/security-policy.h"
+#include "sysemu/sev.h"
 
 #include "hw/boards.h"
 
@@ -1818,6 +1819,31 @@  static int kvm_init(MachineState *ms)
 
     kvm_state = s;
 
+    if (ms->security_policy) {
+        char *id;
+
+        /* if security-policy is enabled  then check whether memory encryption
+         * property is defined. If so, enable hardware memory encryption.
+         */
+        id = security_policy_get_memory_encryption_id(ms->security_policy);
+        if (id) {
+
+            /* check if its SEV guest policy */
+            kvm_state->ehandle = sev_guest_init(id);
+            if (!kvm_state->ehandle) {
+                fprintf(stderr,
+                        "failed to initialize SEV guest\n");
+                goto err;
+            }
+            kvm_state->mem_encrypt_start = sev_guest_launch_start;
+            kvm_state->mem_encrypt_finish = sev_guest_launch_finish;
+            kvm_state->mem_encrypt_debug_ops = sev_guest_set_debug_ops;
+            kvm_state->mem_encrypt_dec = sev_guest_mem_dec;
+            kvm_state->mem_encrypt_enc = sev_guest_mem_enc;
+            g_free(id);
+        }
+    }
+
     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/qemu-options.hx b/qemu-options.hx
index 7a65015..1c1f93d 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4048,6 +4048,40 @@  can be set to the unquie ID of memory encryption object.
 
 On AMD processor, memory encryption is supported via 'sev-guest' object.
 
+@item -object sev-guest,id=@var{id}
+
+Create a Secure Encrypted Virtualization (SEV) guest object, which be used to
+provide the memory encryption support on AMD processors.
+
+e.g to launch a SEV guest
+@example
+ # $QEMU \
+     -object sev-launch-info,id=launch0 \
+     -object sev-guest-info,id=sev0 \
+     -object security-policy,id=secure0-guest,memory-encryption=sev0 \
+     -machine ...,security-policy=secure0
+@end example
+
+@item -object sev-launch-info,id=@var{id}[,nonce=@var{string}][,dh-pub-qx=@var{string}][,dh-pub-qy=@var{string}]
+
+Create a SEV launch info object, which can be used to pass various parameters
+required to boot SEV guest from  unencrypted boot images.
+The id parameter is a unique ID that should be used in sev-guest-info object
+when creating a unencrypted SEV guest.
+
+The 'nonce' parameter should be set with a nonce generated by guest owner.
+
+The 'dh-pub-qx' and 'dh-pub-qy' parameters should be set with guest owners
+ECDH public key.
+
+e.g to launch SEV guest from unencrypted boot images
+@example
+ # $QEMU \
+     -object sev-launch-info,id=launch0,nonce=abcd \
+     -object sev-guest,id=sev0 \
+@end example
+
+@end table
 ETEXI
 
 
diff --git a/sev.c b/sev.c
new file mode 100644
index 0000000..487dba6
--- /dev/null
+++ b/sev.c
@@ -0,0 +1,350 @@ 
+/*
+ * QEMU SEV support
+ *
+ * Copyright Advanced Micro Devices 2016
+ *
+ * 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 "sysemu/sev.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+
+#define DEBUG_SEV
+#ifdef DEBUG_SEV
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stdout, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+static MemoryRegionRAMReadWriteOps sev_ops;
+static bool sev_allowed;
+
+static void
+qsev_guest_finalize(Object *obj)
+{
+}
+
+static void
+qsev_guest_class_init(ObjectClass *oc, void *data)
+{
+}
+
+static QSevGuestInfo *
+lookup_sev_guest_info(const char *id)
+{
+    Object *obj;
+    QSevGuestInfo *info;
+
+    obj = object_resolve_path_component(
+        object_get_objects_root(), id);
+    if (!obj) {
+        return NULL;
+    }
+
+    info = (QSevGuestInfo *)
+            object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
+    if (!info) {
+        return NULL;
+    }
+
+    return info;
+}
+
+static void
+qsev_guest_init(Object *obj)
+{
+    QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
+
+    object_property_add_link(obj, "launch", TYPE_QSEV_LAUNCH_INFO,
+                             (Object **)&sev->launch_info,
+                             object_property_allow_set_link,
+                             OBJ_PROP_LINK_UNREF_ON_RELEASE, 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
+qsev_launch_finalize(Object *obj)
+{
+}
+
+static char *
+qsev_launch_get_nonce(Object *obj, Error **errp)
+{
+    QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj);
+
+    return g_strdup(launch->nonce);
+}
+
+static void
+qsev_launch_set_nonce(Object *obj, const char *value, Error **errp)
+{
+    QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj);
+
+    launch->nonce = g_strdup(value);
+}
+
+static char *
+qsev_launch_get_dh_pub_qx(Object *obj, Error **errp)
+{
+    QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj);
+
+    return g_strdup(launch->dh_pub_qx);
+}
+
+static void
+qsev_launch_set_dh_pub_qx(Object *obj, const char *value, Error **errp)
+{
+    QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj);
+
+    launch->dh_pub_qx = g_strdup(value);
+}
+
+static char *
+qsev_launch_get_dh_pub_qy(Object *obj, Error **errp)
+{
+    QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj);
+
+    return g_strdup(launch->dh_pub_qy);
+}
+
+static void
+qsev_launch_set_dh_pub_qy(Object *obj, const char *value, Error **errp)
+{
+    QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj);
+
+    launch->dh_pub_qy = g_strdup(value);
+}
+
+static void
+qsev_launch_class_init(ObjectClass *oc, void *data)
+{
+    object_class_property_add_str(oc, "nonce",
+                                  qsev_launch_get_nonce,
+                                  qsev_launch_set_nonce,
+                                  NULL);
+    object_class_property_set_description(oc, "nonce",
+            "a nonce provided by guest owner", NULL);
+
+    object_class_property_add_str(oc, "dh-pub-qx",
+                                  qsev_launch_get_dh_pub_qx,
+                                  qsev_launch_set_dh_pub_qx,
+                                  NULL);
+    object_class_property_set_description(oc, "dh-pub-qx",
+            "Qx parameter of owner's ECDH public key", NULL);
+
+    object_class_property_add_str(oc, "dh-pub-qy",
+                                  qsev_launch_get_dh_pub_qy,
+                                  qsev_launch_set_dh_pub_qy,
+                                  NULL);
+    object_class_property_set_description(oc, "dh-pub-qy",
+            "Qy parameter of owner's ECDH public key", NULL);
+}
+
+static void
+qsev_launch_init(Object *obj)
+{
+}
+
+/* guest launch */
+static const TypeInfo qsev_launch_info = {
+    .parent = TYPE_OBJECT,
+    .name = TYPE_QSEV_LAUNCH_INFO,
+    .instance_size = sizeof(QSevLaunchInfo),
+    .instance_finalize = qsev_launch_finalize,
+    .class_size = sizeof(QSevLaunchInfoClass),
+    .class_init = qsev_launch_class_init,
+    .instance_init = qsev_launch_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_USER_CREATABLE },
+        { }
+    }
+};
+
+
+static int
+sev_launch_start(SEVState *s)
+{
+    return 0;
+}
+
+static int
+sev_launch_finish(SEVState *s)
+{
+    return 0;
+}
+
+static int
+sev_mem_write(uint8_t *dst, const uint8_t *src, uint32_t len, MemTxAttrs attrs)
+{
+    SEVState *s = kvm_memory_encryption_get_handle();
+
+    assert(s != NULL && s->state != SEV_STATE_INVALID);
+
+    return 0;
+}
+
+static int
+sev_mem_read(uint8_t *dst, const uint8_t *src, uint32_t len, MemTxAttrs attrs)
+{
+    SEVState *s = kvm_memory_encryption_get_handle();
+
+    assert(s != NULL && s->state != SEV_STATE_INVALID);
+
+    return 0;
+}
+
+static int
+sev_get_launch_type(SEVState *s)
+{
+    QSevGuestInfo *sev_info = s->sev_info;
+
+    /* if <link>QSevLaunchInfo is set then we are configured to use
+     * launch_info object.
+     */
+    if (object_property_get_link(OBJECT(sev_info), "launch", &error_abort)) {
+        return USE_LAUNCH_INFO;
+    }
+
+    return INVALID_TYPE;
+}
+
+void *
+sev_guest_init(const char *id)
+{
+    Object *obj;
+    SEVState *s;
+
+    s = g_malloc0(sizeof(SEVState));
+    if (!s) {
+        return NULL;
+    }
+
+    s->sev_info = lookup_sev_guest_info(id);
+    if (!s->sev_info) {
+        fprintf(stderr, "'%s' not a valid '%s' object\n",
+                id, TYPE_QSEV_GUEST_INFO);
+        goto err;
+    }
+
+    obj = object_resolve_path_type("", TYPE_QSEV_LAUNCH_INFO, NULL);
+    if (obj) {
+        object_property_set_link(OBJECT(s->sev_info), obj, "launch",
+                &error_abort);
+    }
+
+    sev_allowed = true;
+    return s;
+err:
+    g_free(s);
+    return NULL;
+}
+
+int
+sev_guest_launch_start(void *handle)
+{
+    SEVState *s = (SEVState *)handle;
+
+    assert(s != NULL);
+
+    /* If we are in prelaunch state then create memory encryption context based
+     * on the sev launch object created by user.
+     */
+    if (runstate_check(RUN_STATE_PRELAUNCH)) {
+        if (sev_get_launch_type(s) == USE_LAUNCH_INFO) {
+            return sev_launch_start(s);
+        }
+    }
+
+    return 1;
+}
+
+int
+sev_guest_launch_finish(void *handle)
+{
+    SEVState *s = (SEVState *)handle;
+
+    assert(s != NULL);
+
+    if (s->state == SEV_STATE_LAUNCHING) {
+        return sev_launch_finish(s);
+    }
+
+    return 1;
+}
+
+void
+sev_guest_set_debug_ops(void *handle, MemoryRegion *mr)
+{
+    SEVState *s = (SEVState *)handle;
+
+    assert(s != NULL);
+
+    sev_ops.read = sev_mem_read;
+    sev_ops.write = sev_mem_write;
+
+    memory_region_set_ram_debug_ops(mr, &sev_ops);
+}
+
+int
+sev_guest_mem_dec(void *handle, uint8_t *dst, const uint8_t *src, uint32_t len)
+{
+    SEVState *s = (SEVState *)handle;
+
+    assert(s != NULL && s->state != SEV_STATE_INVALID);
+
+    /* use SEV debug command to decrypt memory */
+    return 1;
+}
+
+int
+sev_guest_mem_enc(void *handle, uint8_t *dst, const uint8_t *src, uint32_t len)
+{
+    SEVState *s = (SEVState *)handle;
+
+    assert(s != NULL && s->state != SEV_STATE_INVALID);
+
+    /* use SEV debug command to decrypt memory */
+    return 1;
+}
+
+bool
+sev_enabled(void)
+{
+    return sev_allowed;
+}
+
+static void
+sev_policy_register_types(void)
+{
+    type_register_static(&qsev_guest_info);
+    type_register_static(&qsev_launch_info);
+}
+
+type_init(sev_policy_register_types);