summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--target/i386/sev-stub.c5
-rw-r--r--target/i386/sev.c63
-rw-r--r--target/i386/sev_i386.h2
-rw-r--r--target/i386/trace-events1
4 files changed, 71 insertions, 0 deletions
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index c86d8c1392..2f61c32ec9 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -39,3 +39,8 @@ uint32_t sev_get_reduced_phys_bits(void)
 {
     return 0;
 }
+
+char *sev_get_launch_measurement(void)
+{
+    return NULL;
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 2d14879166..0132beaf24 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -516,6 +516,68 @@ sev_launch_update_data(uint8_t *addr, uint64_t len)
     return ret;
 }
 
+static void
+sev_launch_get_measure(Notifier *notifier, void *unused)
+{
+    int ret, error;
+    guchar *data;
+    SEVState *s = sev_state;
+    struct kvm_sev_launch_measure *measurement;
+
+    if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
+        return;
+    }
+
+    measurement = g_new0(struct kvm_sev_launch_measure, 1);
+
+    /* query the measurement blob length */
+    ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
+                    measurement, &error);
+    if (!measurement->len) {
+        error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
+                     __func__, ret, error, fw_error_to_str(errno));
+        goto free_measurement;
+    }
+
+    data = g_new0(guchar, measurement->len);
+    measurement->uaddr = (unsigned long)data;
+
+    /* get the measurement blob */
+    ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
+                    measurement, &error);
+    if (ret) {
+        error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
+                     __func__, ret, error, fw_error_to_str(errno));
+        goto free_data;
+    }
+
+    sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
+
+    /* encode the measurement value and emit the event */
+    s->measurement = g_base64_encode(data, measurement->len);
+    trace_kvm_sev_launch_measurement(s->measurement);
+
+free_data:
+    g_free(data);
+free_measurement:
+    g_free(measurement);
+}
+
+char *
+sev_get_launch_measurement(void)
+{
+    if (sev_state &&
+        sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
+        return g_strdup(sev_state->measurement);
+    }
+
+    return NULL;
+}
+
+static Notifier sev_machine_done_notify = {
+    .notify = sev_launch_get_measure,
+};
+
 void *
 sev_guest_init(const char *id)
 {
@@ -593,6 +655,7 @@ sev_guest_init(const char *id)
     }
 
     ram_block_notifier_add(&sev_ram_notifier);
+    qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
 
     return s;
 err:
diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index 924cebcab0..6e37077577 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -37,6 +37,7 @@ extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
 extern uint32_t sev_get_cbit_position(void);
 extern uint32_t sev_get_reduced_phys_bits(void);
+extern char *sev_get_launch_measurement(void);
 
 typedef struct QSevGuestInfo QSevGuestInfo;
 typedef struct QSevGuestInfoClass QSevGuestInfoClass;
@@ -78,6 +79,7 @@ struct SEVState {
     uint32_t handle;
     int sev_fd;
     SevState state;
+    gchar *measurement;
 };
 
 typedef struct SEVState SEVState;
diff --git a/target/i386/trace-events b/target/i386/trace-events
index 4aa87ef3ee..ce6c71b375 100644
--- a/target/i386/trace-events
+++ b/target/i386/trace-events
@@ -13,3 +13,4 @@ kvm_memcrypt_unregister_region(void *addr, size_t len) "addr %p len 0x%zu"
 kvm_sev_change_state(const char *old, const char *new) "%s -> %s"
 kvm_sev_launch_start(int policy, void *session, void *pdh) "policy 0x%x session %p pdh %p"
 kvm_sev_launch_update_data(void *addr, uint64_t len) "addr %p len 0x%" PRIu64
+kvm_sev_launch_measurement(const char *value) "data %s"