xref: /openbmc/qemu/target/i386/sev.c (revision 89854803)
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, *cert_chain_data;
434     struct sev_user_data_pdh_cert_export export = {};
435     int err, r;
436 
437     /* query the certificate length */
438     r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
439     if (r < 0) {
440         if (err != SEV_RET_INVALID_LEN) {
441             error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
442                          r, err, fw_error_to_str(err));
443             return 1;
444         }
445     }
446 
447     pdh_data = g_new(guchar, export.pdh_cert_len);
448     cert_chain_data = g_new(guchar, export.cert_chain_len);
449     export.pdh_cert_address = (unsigned long)pdh_data;
450     export.cert_chain_address = (unsigned long)cert_chain_data;
451 
452     r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
453     if (r < 0) {
454         error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
455                      r, err, fw_error_to_str(err));
456         goto e_free;
457     }
458 
459     *pdh = pdh_data;
460     *pdh_len = export.pdh_cert_len;
461     *cert_chain = cert_chain_data;
462     *cert_chain_len = export.cert_chain_len;
463     return 0;
464 
465 e_free:
466     g_free(pdh_data);
467     g_free(cert_chain_data);
468     return 1;
469 }
470 
471 SevCapability *
472 sev_get_capabilities(void)
473 {
474     SevCapability *cap;
475     guchar *pdh_data, *cert_chain_data;
476     size_t pdh_len = 0, cert_chain_len = 0;
477     uint32_t ebx;
478     int fd;
479 
480     fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
481     if (fd < 0) {
482         error_report("%s: Failed to open %s '%s'", __func__,
483                      DEFAULT_SEV_DEVICE, strerror(errno));
484         return NULL;
485     }
486 
487     if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
488                          &cert_chain_data, &cert_chain_len)) {
489         return NULL;
490     }
491 
492     cap = g_new0(SevCapability, 1);
493     cap->pdh = g_base64_encode(pdh_data, pdh_len);
494     cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
495 
496     host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
497     cap->cbitpos = ebx & 0x3f;
498 
499     /*
500      * When SEV feature is enabled, we loose one bit in guest physical
501      * addressing.
502      */
503     cap->reduced_phys_bits = 1;
504 
505     g_free(pdh_data);
506     g_free(cert_chain_data);
507 
508     close(fd);
509     return cap;
510 }
511 
512 static int
513 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
514 {
515     gsize sz;
516     gchar *base64;
517     GError *error = NULL;
518 
519     if (!g_file_get_contents(filename, &base64, &sz, &error)) {
520         error_report("failed to read '%s' (%s)", filename, error->message);
521         return -1;
522     }
523 
524     *data = g_base64_decode(base64, len);
525     return 0;
526 }
527 
528 static int
529 sev_launch_start(SEVState *s)
530 {
531     gsize sz;
532     int ret = 1;
533     int fw_error;
534     QSevGuestInfo *sev = s->sev_info;
535     struct kvm_sev_launch_start *start;
536     guchar *session = NULL, *dh_cert = NULL;
537 
538     start = g_new0(struct kvm_sev_launch_start, 1);
539 
540     start->handle = object_property_get_int(OBJECT(sev), "handle",
541                                             &error_abort);
542     start->policy = object_property_get_int(OBJECT(sev), "policy",
543                                             &error_abort);
544     if (sev->session_file) {
545         if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
546             return 1;
547         }
548         start->session_uaddr = (unsigned long)session;
549         start->session_len = sz;
550     }
551 
552     if (sev->dh_cert_file) {
553         if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
554             return 1;
555         }
556         start->dh_uaddr = (unsigned long)dh_cert;
557         start->dh_len = sz;
558     }
559 
560     trace_kvm_sev_launch_start(start->policy, session, dh_cert);
561     ret = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
562     if (ret < 0) {
563         error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
564                 __func__, ret, fw_error, fw_error_to_str(fw_error));
565         return 1;
566     }
567 
568     object_property_set_int(OBJECT(sev), start->handle, "handle",
569                             &error_abort);
570     sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
571     s->handle = start->handle;
572     s->policy = start->policy;
573 
574     g_free(start);
575     g_free(session);
576     g_free(dh_cert);
577 
578     return 0;
579 }
580 
581 static int
582 sev_launch_update_data(uint8_t *addr, uint64_t len)
583 {
584     int ret, fw_error;
585     struct kvm_sev_launch_update_data update;
586 
587     if (!addr || !len) {
588         return 1;
589     }
590 
591     update.uaddr = (__u64)(unsigned long)addr;
592     update.len = len;
593     trace_kvm_sev_launch_update_data(addr, len);
594     ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
595                     &update, &fw_error);
596     if (ret) {
597         error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
598                 __func__, ret, fw_error, fw_error_to_str(fw_error));
599     }
600 
601     return ret;
602 }
603 
604 static void
605 sev_launch_get_measure(Notifier *notifier, void *unused)
606 {
607     int ret, error;
608     guchar *data;
609     SEVState *s = sev_state;
610     struct kvm_sev_launch_measure *measurement;
611 
612     if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
613         return;
614     }
615 
616     measurement = g_new0(struct kvm_sev_launch_measure, 1);
617 
618     /* query the measurement blob length */
619     ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
620                     measurement, &error);
621     if (!measurement->len) {
622         error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
623                      __func__, ret, error, fw_error_to_str(errno));
624         goto free_measurement;
625     }
626 
627     data = g_new0(guchar, measurement->len);
628     measurement->uaddr = (unsigned long)data;
629 
630     /* get the measurement blob */
631     ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
632                     measurement, &error);
633     if (ret) {
634         error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
635                      __func__, ret, error, fw_error_to_str(errno));
636         goto free_data;
637     }
638 
639     sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
640 
641     /* encode the measurement value and emit the event */
642     s->measurement = g_base64_encode(data, measurement->len);
643     trace_kvm_sev_launch_measurement(s->measurement);
644 
645 free_data:
646     g_free(data);
647 free_measurement:
648     g_free(measurement);
649 }
650 
651 char *
652 sev_get_launch_measurement(void)
653 {
654     if (sev_state &&
655         sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
656         return g_strdup(sev_state->measurement);
657     }
658 
659     return NULL;
660 }
661 
662 static Notifier sev_machine_done_notify = {
663     .notify = sev_launch_get_measure,
664 };
665 
666 static void
667 sev_launch_finish(SEVState *s)
668 {
669     int ret, error;
670     Error *local_err = NULL;
671 
672     trace_kvm_sev_launch_finish();
673     ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
674     if (ret) {
675         error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
676                      __func__, ret, error, fw_error_to_str(error));
677         exit(1);
678     }
679 
680     sev_set_guest_state(SEV_STATE_RUNNING);
681 
682     /* add migration blocker */
683     error_setg(&sev_mig_blocker,
684                "SEV: Migration is not implemented");
685     ret = migrate_add_blocker(sev_mig_blocker, &local_err);
686     if (local_err) {
687         error_report_err(local_err);
688         error_free(sev_mig_blocker);
689         exit(1);
690     }
691 }
692 
693 static void
694 sev_vm_state_change(void *opaque, int running, RunState state)
695 {
696     SEVState *s = opaque;
697 
698     if (running) {
699         if (!sev_check_state(SEV_STATE_RUNNING)) {
700             sev_launch_finish(s);
701         }
702     }
703 }
704 
705 void *
706 sev_guest_init(const char *id)
707 {
708     SEVState *s;
709     char *devname;
710     int ret, fw_error;
711     uint32_t ebx;
712     uint32_t host_cbitpos;
713     struct sev_user_data_status status = {};
714 
715     s = g_new0(SEVState, 1);
716     s->sev_info = lookup_sev_guest_info(id);
717     if (!s->sev_info) {
718         error_report("%s: '%s' is not a valid '%s' object",
719                      __func__, id, TYPE_QSEV_GUEST_INFO);
720         goto err;
721     }
722 
723     sev_state = s;
724     s->state = SEV_STATE_UNINIT;
725 
726     host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
727     host_cbitpos = ebx & 0x3f;
728 
729     s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
730     if (host_cbitpos != s->cbitpos) {
731         error_report("%s: cbitpos check failed, host '%d' requested '%d'",
732                      __func__, host_cbitpos, s->cbitpos);
733         goto err;
734     }
735 
736     s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
737                                         "reduced-phys-bits", NULL);
738     if (s->reduced_phys_bits < 1) {
739         error_report("%s: reduced_phys_bits check failed, it should be >=1,"
740                      "' requested '%d'", __func__, s->reduced_phys_bits);
741         goto err;
742     }
743 
744     s->me_mask = ~(1UL << s->cbitpos);
745 
746     devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
747     s->sev_fd = open(devname, O_RDWR);
748     if (s->sev_fd < 0) {
749         error_report("%s: Failed to open %s '%s'", __func__,
750                      devname, strerror(errno));
751     }
752     g_free(devname);
753     if (s->sev_fd < 0) {
754         goto err;
755     }
756 
757     ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
758                              &fw_error);
759     if (ret) {
760         error_report("%s: failed to get platform status ret=%d"
761                      "fw_error='%d: %s'", __func__, ret, fw_error,
762                      fw_error_to_str(fw_error));
763         goto err;
764     }
765     s->build_id = status.build;
766     s->api_major = status.api_major;
767     s->api_minor = status.api_minor;
768 
769     trace_kvm_sev_init();
770     ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
771     if (ret) {
772         error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
773                      __func__, ret, fw_error, fw_error_to_str(fw_error));
774         goto err;
775     }
776 
777     ret = sev_launch_start(s);
778     if (ret) {
779         error_report("%s: failed to create encryption context", __func__);
780         goto err;
781     }
782 
783     ram_block_notifier_add(&sev_ram_notifier);
784     qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
785     qemu_add_vm_change_state_handler(sev_vm_state_change, s);
786 
787     return s;
788 err:
789     g_free(sev_state);
790     sev_state = NULL;
791     return NULL;
792 }
793 
794 int
795 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
796 {
797     assert(handle);
798 
799     /* if SEV is in update state then encrypt the data else do nothing */
800     if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
801         return sev_launch_update_data(ptr, len);
802     }
803 
804     return 0;
805 }
806 
807 static void
808 sev_register_types(void)
809 {
810     type_register_static(&qsev_guest_info);
811 }
812 
813 type_init(sev_register_types);
814