@@ -27,6 +27,17 @@ static int sev_fd;
#define SEV_FW_MAX_ERROR 0x17
+static SevGuestState current_sev_guest_state = SEV_STATE_UNINIT;
+
+static char sev_state_str[SEV_STATE_MAX][10] = {
+ "uninit",
+ "lupdate",
+ "secret",
+ "running",
+ "supdate",
+ "rupdate",
+};
+
static char sev_fw_errlist[SEV_FW_MAX_ERROR][100] = {
"",
"Platform state is invalid",
@@ -85,6 +96,16 @@ fw_error_to_str(int code)
}
static void
+sev_set_guest_state(SevGuestState new_state)
+{
+ assert(new_state < SEV_STATE_MAX);
+
+ trace_kvm_sev_change_state(sev_state_str[current_sev_guest_state],
+ sev_state_str[new_state]);
+ current_sev_guest_state = new_state;
+}
+
+static void
sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
{
int r;
@@ -291,6 +312,76 @@ lookup_sev_guest_info(const char *id)
return info;
}
+static int
+sev_read_file_base64(const char *filename, guchar **data, gsize *len)
+{
+ gsize sz;
+ gchar *base64;
+ GError *error = NULL;
+
+ if (!g_file_get_contents(filename, &base64, &sz, &error)) {
+ error_report("failed to read '%s' (%s)", filename, error->message);
+ return -1;
+ }
+
+ *data = g_base64_decode(base64, len);
+ return 0;
+}
+
+static int
+sev_launch_start(SEVState *s)
+{
+ gsize sz;
+ int ret = 1;
+ int fw_error;
+ QSevGuestInfo *sev = s->sev_info;
+ struct kvm_sev_launch_start *start;
+ guchar *session = NULL, *dh_cert = NULL;
+
+ start = g_malloc0(sizeof(*start));
+ if (!start) {
+ return 1;
+ }
+
+ start->handle = object_property_get_int(OBJECT(sev), "handle",
+ &error_abort);
+ start->policy = object_property_get_int(OBJECT(sev), "policy",
+ &error_abort);
+ if (sev->session_file) {
+ if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
+ return 1;
+ }
+ start->session_uaddr = (unsigned long)session;
+ start->session_len = sz;
+ }
+
+ if (sev->dh_cert_file) {
+ if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
+ return 1;
+ }
+ start->dh_uaddr = (unsigned long)dh_cert;
+ start->dh_len = sz;
+ }
+
+ trace_kvm_sev_launch_start(start->policy, session, dh_cert);
+ ret = sev_ioctl(KVM_SEV_LAUNCH_START, start, &fw_error);
+ if (ret < 0) {
+ error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
+ __func__, ret, fw_error, fw_error_to_str(fw_error));
+ return 1;
+ }
+
+ object_property_set_int(OBJECT(sev), start->handle, "handle",
+ &error_abort);
+ sev_set_guest_state(SEV_STATE_LUPDATE);
+
+ g_free(start);
+ g_free(session);
+ g_free(dh_cert);
+
+ return 0;
+}
+
void *
sev_guest_init(const char *id)
{
@@ -327,6 +418,12 @@ sev_guest_init(const char *id)
goto err;
}
+ ret = sev_launch_start(s);
+ if (ret) {
+ error_report("%s: failed to create encryption context", __func__);
+ goto err;
+ }
+
ram_block_notifier_add(&sev_ram_notifier);
return s;
@@ -17,3 +17,5 @@ kvm_irqchip_release_virq(int virq) "virq %d"
kvm_sev_init(void) ""
kvm_memcrypt_register_region(void *addr, size_t len) "addr %p len 0x%lu"
kvm_memcrypt_unregister_region(void *addr, size_t len) "addr %p len 0x%lu"
+kvm_sev_change_state(char *old, char *new) "%s -> %s"
+kvm_sev_launch_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p"
@@ -51,6 +51,16 @@ struct QSevGuestInfoClass {
ObjectClass parent_class;
};
+typedef enum {
+ SEV_STATE_UNINIT = 0,
+ SEV_STATE_LUPDATE,
+ SEV_STATE_SECRET,
+ SEV_STATE_RUNNING,
+ SEV_STATE_SUPDATE,
+ SEV_STATE_RUPDATE,
+ SEV_STATE_MAX
+} SevGuestState;
+
struct SEVState {
QSevGuestInfo *sev_info;
};
The KVM_SEV_LAUNCH_START command creates a new VM encryption key (VEK). The encryption key created with the command will be used for encrypting the bootstrap images (such as guest bios). Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: kvm@vger.kernel.org Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> --- accel/kvm/sev.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ accel/kvm/trace-events | 2 ++ include/sysemu/sev.h | 10 ++++++ 3 files changed, 109 insertions(+)