1
2
3
4
5
6
7
8
9
10
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
30#define DEFAULT_SEV_DEVICE "/dev/sev"
31
32static SEVState *sev_state;
33static Error *sev_mig_blocker;
34
35static 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
63static int
64sev_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
84static int
85sev_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
100static const char *
101fw_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
110static bool
111sev_check_state(SevState state)
112{
113 assert(sev_state);
114 return sev_state->state == state ? true : false;
115}
116
117static void
118sev_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
128static void
129sev_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
146static void
147sev_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
163static struct RAMBlockNotifier sev_ram_notifier = {
164 .ram_block_added = sev_ram_block_added,
165 .ram_block_removed = sev_ram_block_removed,
166};
167
168static void
169qsev_guest_finalize(Object *obj)
170{
171}
172
173static char *
174qsev_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
181static void
182qsev_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
189static char *
190qsev_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
197static void
198qsev_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
205static char *
206qsev_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
213static void
214qsev_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
221static void
222qsev_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
244static void
245qsev_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
255static void
256qsev_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
266static void
267qsev_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
277static void
278qsev_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
288static void
289qsev_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
299static void
300qsev_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
310static void
311qsev_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
321static void
322qsev_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
332static void
333qsev_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
351static 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
365static QSevGuestInfo *
366lookup_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
385bool
386sev_enabled(void)
387{
388 return sev_state ? true : false;
389}
390
391uint64_t
392sev_get_me_mask(void)
393{
394 return sev_state ? sev_state->me_mask : ~0;
395}
396
397uint32_t
398sev_get_cbit_position(void)
399{
400 return sev_state ? sev_state->cbitpos : 0;
401}
402
403uint32_t
404sev_get_reduced_phys_bits(void)
405{
406 return sev_state ? sev_state->reduced_phys_bits : 0;
407}
408
409SevInfo *
410sev_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
429static int
430sev_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
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
466e_free:
467 g_free(pdh_data);
468 g_free(cert_chain_data);
469 return 1;
470}
471
472SevCapability *
473sev_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
503
504
505 cap->reduced_phys_bits = 1;
506
507out:
508 g_free(pdh_data);
509 g_free(cert_chain_data);
510 close(fd);
511 return cap;
512}
513
514static int
515sev_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
530static int
531sev_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
577out:
578 g_free(start);
579 g_free(session);
580 g_free(dh_cert);
581 return ret;
582}
583
584static int
585sev_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
607static void
608sev_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
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
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
645 s->measurement = g_base64_encode(data, measurement->len);
646 trace_kvm_sev_launch_measurement(s->measurement);
647
648free_data:
649 g_free(data);
650free_measurement:
651 g_free(measurement);
652}
653
654char *
655sev_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
665static Notifier sev_machine_done_notify = {
666 .notify = sev_launch_get_measure,
667};
668
669static void
670sev_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
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
696static void
697sev_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
708void *
709sev_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;
790err:
791 g_free(sev_state);
792 sev_state = NULL;
793 return NULL;
794}
795
796int
797sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
798{
799 assert(handle);
800
801
802 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
803 return sev_launch_update_data(ptr, len);
804 }
805
806 return 0;
807}
808
809static void
810sev_register_types(void)
811{
812 type_register_static(&qsev_guest_info);
813}
814
815type_init(sev_register_types);
816