xref: /openbmc/qemu/target/i386/sev.c (revision 438c78da)
1 /*
2  * QEMU SEV support
3  *
4  * Copyright Advanced Micro Devices 2016-2018
5  *
6  * Author:
7  *      Brijesh Singh <brijesh.singh@amd.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  *
12  */
13 
14 #include <linux/kvm.h>
15 #include <linux/psp-sev.h>
16 
17 #include <sys/ioctl.h>
18 
19 #include "qemu/osdep.h"
20 #include "qapi/error.h"
21 #include "qom/object_interfaces.h"
22 #include "qemu/base64.h"
23 #include "sysemu/kvm.h"
24 #include "sev_i386.h"
25 #include "sysemu/sysemu.h"
26 #include "trace.h"
27 #include "migration/blocker.h"
28 
29 #define DEFAULT_GUEST_POLICY    0x1 /* disable debug */
30 #define DEFAULT_SEV_DEVICE      "/dev/sev"
31 
32 static SEVState *sev_state;
33 static Error *sev_mig_blocker;
34 
35 static const char *const sev_fw_errlist[] = {
36     "",
37     "Platform state is invalid",
38     "Guest state is invalid",
39     "Platform configuration is invalid",
40     "Buffer too small",
41     "Platform is already owned",
42     "Certificate is invalid",
43     "Policy is not allowed",
44     "Guest is not active",
45     "Invalid address",
46     "Bad signature",
47     "Bad measurement",
48     "Asid is already owned",
49     "Invalid ASID",
50     "WBINVD is required",
51     "DF_FLUSH is required",
52     "Guest handle is invalid",
53     "Invalid command",
54     "Guest is active",
55     "Hardware error",
56     "Hardware unsafe",
57     "Feature not supported",
58     "Invalid parameter"
59 };
60 
61 #define SEV_FW_MAX_ERROR      ARRAY_SIZE(sev_fw_errlist)
62 
63 static int
64 sev_ioctl(int fd, int cmd, void *data, int *error)
65 {
66     int r;
67     struct kvm_sev_cmd input;
68 
69     memset(&input, 0x0, sizeof(input));
70 
71     input.id = cmd;
72     input.sev_fd = fd;
73     input.data = (__u64)(unsigned long)data;
74 
75     r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
76 
77     if (error) {
78         *error = input.error;
79     }
80 
81     return r;
82 }
83 
84 static int
85 sev_platform_ioctl(int fd, int cmd, void *data, int *error)
86 {
87     int r;
88     struct sev_issue_cmd arg;
89 
90     arg.cmd = cmd;
91     arg.data = (unsigned long)data;
92     r = ioctl(fd, SEV_ISSUE_CMD, &arg);
93     if (error) {
94         *error = arg.error;
95     }
96 
97     return r;
98 }
99 
100 static const char *
101 fw_error_to_str(int code)
102 {
103     if (code < 0 || code >= SEV_FW_MAX_ERROR) {
104         return "unknown error";
105     }
106 
107     return sev_fw_errlist[code];
108 }
109 
110 static bool
111 sev_check_state(SevState state)
112 {
113     assert(sev_state);
114     return sev_state->state == state ? true : false;
115 }
116 
117 static void
118 sev_set_guest_state(SevState new_state)
119 {
120     assert(new_state < SEV_STATE__MAX);
121     assert(sev_state);
122 
123     trace_kvm_sev_change_state(SevState_str(sev_state->state),
124                                SevState_str(new_state));
125     sev_state->state = new_state;
126 }
127 
128 static void
129 sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
130 {
131     int r;
132     struct kvm_enc_region range;
133 
134     range.addr = (__u64)(unsigned long)host;
135     range.size = size;
136 
137     trace_kvm_memcrypt_register_region(host, size);
138     r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
139     if (r) {
140         error_report("%s: failed to register region (%p+%#zx) error '%s'",
141                      __func__, host, size, strerror(errno));
142         exit(1);
143     }
144 }
145 
146 static void
147 sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
148 {
149     int r;
150     struct kvm_enc_region range;
151 
152     range.addr = (__u64)(unsigned long)host;
153     range.size = size;
154 
155     trace_kvm_memcrypt_unregister_region(host, size);
156     r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
157     if (r) {
158         error_report("%s: failed to unregister region (%p+%#zx)",
159                      __func__, host, size);
160     }
161 }
162 
163 static struct RAMBlockNotifier sev_ram_notifier = {
164     .ram_block_added = sev_ram_block_added,
165     .ram_block_removed = sev_ram_block_removed,
166 };
167 
168 static void
169 qsev_guest_finalize(Object *obj)
170 {
171 }
172 
173 static char *
174 qsev_guest_get_session_file(Object *obj, Error **errp)
175 {
176     QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
177 
178     return s->session_file ? g_strdup(s->session_file) : NULL;
179 }
180 
181 static void
182 qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
183 {
184     QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
185 
186     s->session_file = g_strdup(value);
187 }
188 
189 static char *
190 qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
191 {
192     QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
193 
194     return g_strdup(s->dh_cert_file);
195 }
196 
197 static void
198 qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
199 {
200     QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
201 
202     s->dh_cert_file = g_strdup(value);
203 }
204 
205 static char *
206 qsev_guest_get_sev_device(Object *obj, Error **errp)
207 {
208     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
209 
210     return g_strdup(sev->sev_device);
211 }
212 
213 static void
214 qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
215 {
216     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
217 
218     sev->sev_device = g_strdup(value);
219 }
220 
221 static void
222 qsev_guest_class_init(ObjectClass *oc, void *data)
223 {
224     object_class_property_add_str(oc, "sev-device",
225                                   qsev_guest_get_sev_device,
226                                   qsev_guest_set_sev_device,
227                                   NULL);
228     object_class_property_set_description(oc, "sev-device",
229             "SEV device to use", NULL);
230     object_class_property_add_str(oc, "dh-cert-file",
231                                   qsev_guest_get_dh_cert_file,
232                                   qsev_guest_set_dh_cert_file,
233                                   NULL);
234     object_class_property_set_description(oc, "dh-cert-file",
235             "guest owners DH certificate (encoded with base64)", NULL);
236     object_class_property_add_str(oc, "session-file",
237                                   qsev_guest_get_session_file,
238                                   qsev_guest_set_session_file,
239                                   NULL);
240     object_class_property_set_description(oc, "session-file",
241             "guest owners session parameters (encoded with base64)", NULL);
242 }
243 
244 static void
245 qsev_guest_set_handle(Object *obj, Visitor *v, const char *name,
246                       void *opaque, Error **errp)
247 {
248     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
249     uint32_t value;
250 
251     visit_type_uint32(v, name, &value, errp);
252     sev->handle = value;
253 }
254 
255 static void
256 qsev_guest_set_policy(Object *obj, Visitor *v, const char *name,
257                       void *opaque, Error **errp)
258 {
259     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
260     uint32_t value;
261 
262     visit_type_uint32(v, name, &value, errp);
263     sev->policy = value;
264 }
265 
266 static void
267 qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name,
268                        void *opaque, Error **errp)
269 {
270     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
271     uint32_t value;
272 
273     visit_type_uint32(v, name, &value, errp);
274     sev->cbitpos = value;
275 }
276 
277 static void
278 qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
279                                    void *opaque, Error **errp)
280 {
281     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
282     uint32_t value;
283 
284     visit_type_uint32(v, name, &value, errp);
285     sev->reduced_phys_bits = value;
286 }
287 
288 static void
289 qsev_guest_get_policy(Object *obj, Visitor *v, const char *name,
290                       void *opaque, Error **errp)
291 {
292     uint32_t value;
293     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
294 
295     value = sev->policy;
296     visit_type_uint32(v, name, &value, errp);
297 }
298 
299 static void
300 qsev_guest_get_handle(Object *obj, Visitor *v, const char *name,
301                       void *opaque, Error **errp)
302 {
303     uint32_t value;
304     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
305 
306     value = sev->handle;
307     visit_type_uint32(v, name, &value, errp);
308 }
309 
310 static void
311 qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name,
312                        void *opaque, Error **errp)
313 {
314     uint32_t value;
315     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
316 
317     value = sev->cbitpos;
318     visit_type_uint32(v, name, &value, errp);
319 }
320 
321 static void
322 qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
323                                    void *opaque, Error **errp)
324 {
325     uint32_t value;
326     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
327 
328     value = sev->reduced_phys_bits;
329     visit_type_uint32(v, name, &value, errp);
330 }
331 
332 static void
333 qsev_guest_init(Object *obj)
334 {
335     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
336 
337     sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
338     sev->policy = DEFAULT_GUEST_POLICY;
339     object_property_add(obj, "policy", "uint32", qsev_guest_get_policy,
340                         qsev_guest_set_policy, NULL, NULL, NULL);
341     object_property_add(obj, "handle", "uint32", qsev_guest_get_handle,
342                         qsev_guest_set_handle, NULL, NULL, NULL);
343     object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos,
344                         qsev_guest_set_cbitpos, NULL, NULL, NULL);
345     object_property_add(obj, "reduced-phys-bits", "uint32",
346                         qsev_guest_get_reduced_phys_bits,
347                         qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL);
348 }
349 
350 /* sev guest info */
351 static const TypeInfo qsev_guest_info = {
352     .parent = TYPE_OBJECT,
353     .name = TYPE_QSEV_GUEST_INFO,
354     .instance_size = sizeof(QSevGuestInfo),
355     .instance_finalize = qsev_guest_finalize,
356     .class_size = sizeof(QSevGuestInfoClass),
357     .class_init = qsev_guest_class_init,
358     .instance_init = qsev_guest_init,
359     .interfaces = (InterfaceInfo[]) {
360         { TYPE_USER_CREATABLE },
361         { }
362     }
363 };
364 
365 static QSevGuestInfo *
366 lookup_sev_guest_info(const char *id)
367 {
368     Object *obj;
369     QSevGuestInfo *info;
370 
371     obj = object_resolve_path_component(object_get_objects_root(), id);
372     if (!obj) {
373         return NULL;
374     }
375 
376     info = (QSevGuestInfo *)
377             object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
378     if (!info) {
379         return NULL;
380     }
381 
382     return info;
383 }
384 
385 bool
386 sev_enabled(void)
387 {
388     return sev_state ? true : false;
389 }
390 
391 uint64_t
392 sev_get_me_mask(void)
393 {
394     return sev_state ? sev_state->me_mask : ~0;
395 }
396 
397 uint32_t
398 sev_get_cbit_position(void)
399 {
400     return sev_state ? sev_state->cbitpos : 0;
401 }
402 
403 uint32_t
404 sev_get_reduced_phys_bits(void)
405 {
406     return sev_state ? sev_state->reduced_phys_bits : 0;
407 }
408 
409 SevInfo *
410 sev_get_info(void)
411 {
412     SevInfo *info;
413 
414     info = g_new0(SevInfo, 1);
415     info->enabled = sev_state ? true : false;
416 
417     if (info->enabled) {
418         info->api_major = sev_state->api_major;
419         info->api_minor = sev_state->api_minor;
420         info->build_id = sev_state->build_id;
421         info->policy = sev_state->policy;
422         info->state = sev_state->state;
423         info->handle = sev_state->handle;
424     }
425 
426     return info;
427 }
428 
429 static int
430 sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
431                  size_t *cert_chain_len)
432 {
433     guchar *pdh_data = NULL;
434     guchar *cert_chain_data = NULL;
435     struct sev_user_data_pdh_cert_export export = {};
436     int err, r;
437 
438     /* query the certificate length */
439     r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
440     if (r < 0) {
441         if (err != SEV_RET_INVALID_LEN) {
442             error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
443                          r, err, fw_error_to_str(err));
444             return 1;
445         }
446     }
447 
448     pdh_data = g_new(guchar, export.pdh_cert_len);
449     cert_chain_data = g_new(guchar, export.cert_chain_len);
450     export.pdh_cert_address = (unsigned long)pdh_data;
451     export.cert_chain_address = (unsigned long)cert_chain_data;
452 
453     r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
454     if (r < 0) {
455         error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
456                      r, err, fw_error_to_str(err));
457         goto e_free;
458     }
459 
460     *pdh = pdh_data;
461     *pdh_len = export.pdh_cert_len;
462     *cert_chain = cert_chain_data;
463     *cert_chain_len = export.cert_chain_len;
464     return 0;
465 
466 e_free:
467     g_free(pdh_data);
468     g_free(cert_chain_data);
469     return 1;
470 }
471 
472 SevCapability *
473 sev_get_capabilities(void)
474 {
475     SevCapability *cap = NULL;
476     guchar *pdh_data = NULL;
477     guchar *cert_chain_data = NULL;
478     size_t pdh_len = 0, cert_chain_len = 0;
479     uint32_t ebx;
480     int fd;
481 
482     fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
483     if (fd < 0) {
484         error_report("%s: Failed to open %s '%s'", __func__,
485                      DEFAULT_SEV_DEVICE, strerror(errno));
486         return NULL;
487     }
488 
489     if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
490                          &cert_chain_data, &cert_chain_len)) {
491         goto out;
492     }
493 
494     cap = g_new0(SevCapability, 1);
495     cap->pdh = g_base64_encode(pdh_data, pdh_len);
496     cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
497 
498     host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
499     cap->cbitpos = ebx & 0x3f;
500 
501     /*
502      * When SEV feature is enabled, we loose one bit in guest physical
503      * addressing.
504      */
505     cap->reduced_phys_bits = 1;
506 
507 out:
508     g_free(pdh_data);
509     g_free(cert_chain_data);
510     close(fd);
511     return cap;
512 }
513 
514 static int
515 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
516 {
517     gsize sz;
518     gchar *base64;
519     GError *error = NULL;
520 
521     if (!g_file_get_contents(filename, &base64, &sz, &error)) {
522         error_report("failed to read '%s' (%s)", filename, error->message);
523         return -1;
524     }
525 
526     *data = g_base64_decode(base64, len);
527     return 0;
528 }
529 
530 static int
531 sev_launch_start(SEVState *s)
532 {
533     gsize sz;
534     int ret = 1;
535     int fw_error, rc;
536     QSevGuestInfo *sev = s->sev_info;
537     struct kvm_sev_launch_start *start;
538     guchar *session = NULL, *dh_cert = NULL;
539 
540     start = g_new0(struct kvm_sev_launch_start, 1);
541 
542     start->handle = object_property_get_int(OBJECT(sev), "handle",
543                                             &error_abort);
544     start->policy = object_property_get_int(OBJECT(sev), "policy",
545                                             &error_abort);
546     if (sev->session_file) {
547         if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
548             goto out;
549         }
550         start->session_uaddr = (unsigned long)session;
551         start->session_len = sz;
552     }
553 
554     if (sev->dh_cert_file) {
555         if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
556             goto out;
557         }
558         start->dh_uaddr = (unsigned long)dh_cert;
559         start->dh_len = sz;
560     }
561 
562     trace_kvm_sev_launch_start(start->policy, session, dh_cert);
563     rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
564     if (rc < 0) {
565         error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
566                 __func__, ret, fw_error, fw_error_to_str(fw_error));
567         goto out;
568     }
569 
570     object_property_set_int(OBJECT(sev), start->handle, "handle",
571                             &error_abort);
572     sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
573     s->handle = start->handle;
574     s->policy = start->policy;
575     ret = 0;
576 
577 out:
578     g_free(start);
579     g_free(session);
580     g_free(dh_cert);
581     return ret;
582 }
583 
584 static int
585 sev_launch_update_data(uint8_t *addr, uint64_t len)
586 {
587     int ret, fw_error;
588     struct kvm_sev_launch_update_data update;
589 
590     if (!addr || !len) {
591         return 1;
592     }
593 
594     update.uaddr = (__u64)(unsigned long)addr;
595     update.len = len;
596     trace_kvm_sev_launch_update_data(addr, len);
597     ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
598                     &update, &fw_error);
599     if (ret) {
600         error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
601                 __func__, ret, fw_error, fw_error_to_str(fw_error));
602     }
603 
604     return ret;
605 }
606 
607 static void
608 sev_launch_get_measure(Notifier *notifier, void *unused)
609 {
610     int ret, error;
611     guchar *data;
612     SEVState *s = sev_state;
613     struct kvm_sev_launch_measure *measurement;
614 
615     if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
616         return;
617     }
618 
619     measurement = g_new0(struct kvm_sev_launch_measure, 1);
620 
621     /* query the measurement blob length */
622     ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
623                     measurement, &error);
624     if (!measurement->len) {
625         error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
626                      __func__, ret, error, fw_error_to_str(errno));
627         goto free_measurement;
628     }
629 
630     data = g_new0(guchar, measurement->len);
631     measurement->uaddr = (unsigned long)data;
632 
633     /* get the measurement blob */
634     ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
635                     measurement, &error);
636     if (ret) {
637         error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
638                      __func__, ret, error, fw_error_to_str(errno));
639         goto free_data;
640     }
641 
642     sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
643 
644     /* encode the measurement value and emit the event */
645     s->measurement = g_base64_encode(data, measurement->len);
646     trace_kvm_sev_launch_measurement(s->measurement);
647 
648 free_data:
649     g_free(data);
650 free_measurement:
651     g_free(measurement);
652 }
653 
654 char *
655 sev_get_launch_measurement(void)
656 {
657     if (sev_state &&
658         sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
659         return g_strdup(sev_state->measurement);
660     }
661 
662     return NULL;
663 }
664 
665 static Notifier sev_machine_done_notify = {
666     .notify = sev_launch_get_measure,
667 };
668 
669 static void
670 sev_launch_finish(SEVState *s)
671 {
672     int ret, error;
673     Error *local_err = NULL;
674 
675     trace_kvm_sev_launch_finish();
676     ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
677     if (ret) {
678         error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
679                      __func__, ret, error, fw_error_to_str(error));
680         exit(1);
681     }
682 
683     sev_set_guest_state(SEV_STATE_RUNNING);
684 
685     /* add migration blocker */
686     error_setg(&sev_mig_blocker,
687                "SEV: Migration is not implemented");
688     ret = migrate_add_blocker(sev_mig_blocker, &local_err);
689     if (local_err) {
690         error_report_err(local_err);
691         error_free(sev_mig_blocker);
692         exit(1);
693     }
694 }
695 
696 static void
697 sev_vm_state_change(void *opaque, int running, RunState state)
698 {
699     SEVState *s = opaque;
700 
701     if (running) {
702         if (!sev_check_state(SEV_STATE_RUNNING)) {
703             sev_launch_finish(s);
704         }
705     }
706 }
707 
708 void *
709 sev_guest_init(const char *id)
710 {
711     SEVState *s;
712     char *devname;
713     int ret, fw_error;
714     uint32_t ebx;
715     uint32_t host_cbitpos;
716     struct sev_user_data_status status = {};
717 
718     sev_state = s = g_new0(SEVState, 1);
719     s->sev_info = lookup_sev_guest_info(id);
720     if (!s->sev_info) {
721         error_report("%s: '%s' is not a valid '%s' object",
722                      __func__, id, TYPE_QSEV_GUEST_INFO);
723         goto err;
724     }
725 
726     s->state = SEV_STATE_UNINIT;
727 
728     host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
729     host_cbitpos = ebx & 0x3f;
730 
731     s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
732     if (host_cbitpos != s->cbitpos) {
733         error_report("%s: cbitpos check failed, host '%d' requested '%d'",
734                      __func__, host_cbitpos, s->cbitpos);
735         goto err;
736     }
737 
738     s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
739                                         "reduced-phys-bits", NULL);
740     if (s->reduced_phys_bits < 1) {
741         error_report("%s: reduced_phys_bits check failed, it should be >=1,"
742                      "' requested '%d'", __func__, s->reduced_phys_bits);
743         goto err;
744     }
745 
746     s->me_mask = ~(1UL << s->cbitpos);
747 
748     devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
749     s->sev_fd = open(devname, O_RDWR);
750     if (s->sev_fd < 0) {
751         error_report("%s: Failed to open %s '%s'", __func__,
752                      devname, strerror(errno));
753     }
754     g_free(devname);
755     if (s->sev_fd < 0) {
756         goto err;
757     }
758 
759     ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
760                              &fw_error);
761     if (ret) {
762         error_report("%s: failed to get platform status ret=%d"
763                      "fw_error='%d: %s'", __func__, ret, fw_error,
764                      fw_error_to_str(fw_error));
765         goto err;
766     }
767     s->build_id = status.build;
768     s->api_major = status.api_major;
769     s->api_minor = status.api_minor;
770 
771     trace_kvm_sev_init();
772     ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
773     if (ret) {
774         error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
775                      __func__, ret, fw_error, fw_error_to_str(fw_error));
776         goto err;
777     }
778 
779     ret = sev_launch_start(s);
780     if (ret) {
781         error_report("%s: failed to create encryption context", __func__);
782         goto err;
783     }
784 
785     ram_block_notifier_add(&sev_ram_notifier);
786     qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
787     qemu_add_vm_change_state_handler(sev_vm_state_change, s);
788 
789     return s;
790 err:
791     g_free(sev_state);
792     sev_state = NULL;
793     return NULL;
794 }
795 
796 int
797 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
798 {
799     assert(handle);
800 
801     /* if SEV is in update state then encrypt the data else do nothing */
802     if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
803         return sev_launch_update_data(ptr, len);
804     }
805 
806     return 0;
807 }
808 
809 static void
810 sev_register_types(void)
811 {
812     type_register_static(&qsev_guest_info);
813 }
814 
815 type_init(sev_register_types);
816