Update version for 4.1.1 release
[qemu/ar7.git] / target / i386 / sev.c
blobf1423cb0c0d1230aa4f7c4cf447a721ba6df93b0
1 /*
2 * QEMU SEV support
4 * Copyright Advanced Micro Devices 2016-2018
6 * Author:
7 * Brijesh Singh <brijesh.singh@amd.com>
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.
14 #include "qemu/osdep.h"
16 #include <linux/kvm.h>
17 #include <linux/psp-sev.h>
19 #include <sys/ioctl.h>
21 #include "qapi/error.h"
22 #include "qom/object_interfaces.h"
23 #include "qemu/base64.h"
24 #include "qemu/module.h"
25 #include "sysemu/kvm.h"
26 #include "sev_i386.h"
27 #include "sysemu/sysemu.h"
28 #include "trace.h"
29 #include "migration/blocker.h"
31 #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
32 #define DEFAULT_SEV_DEVICE "/dev/sev"
34 static SEVState *sev_state;
35 static Error *sev_mig_blocker;
37 static const char *const sev_fw_errlist[] = {
38 "",
39 "Platform state is invalid",
40 "Guest state is invalid",
41 "Platform configuration is invalid",
42 "Buffer too small",
43 "Platform is already owned",
44 "Certificate is invalid",
45 "Policy is not allowed",
46 "Guest is not active",
47 "Invalid address",
48 "Bad signature",
49 "Bad measurement",
50 "Asid is already owned",
51 "Invalid ASID",
52 "WBINVD is required",
53 "DF_FLUSH is required",
54 "Guest handle is invalid",
55 "Invalid command",
56 "Guest is active",
57 "Hardware error",
58 "Hardware unsafe",
59 "Feature not supported",
60 "Invalid parameter"
63 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
65 static int
66 sev_ioctl(int fd, int cmd, void *data, int *error)
68 int r;
69 struct kvm_sev_cmd input;
71 memset(&input, 0x0, sizeof(input));
73 input.id = cmd;
74 input.sev_fd = fd;
75 input.data = (__u64)(unsigned long)data;
77 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
79 if (error) {
80 *error = input.error;
83 return r;
86 static int
87 sev_platform_ioctl(int fd, int cmd, void *data, int *error)
89 int r;
90 struct sev_issue_cmd arg;
92 arg.cmd = cmd;
93 arg.data = (unsigned long)data;
94 r = ioctl(fd, SEV_ISSUE_CMD, &arg);
95 if (error) {
96 *error = arg.error;
99 return r;
102 static const char *
103 fw_error_to_str(int code)
105 if (code < 0 || code >= SEV_FW_MAX_ERROR) {
106 return "unknown error";
109 return sev_fw_errlist[code];
112 static bool
113 sev_check_state(SevState state)
115 assert(sev_state);
116 return sev_state->state == state ? true : false;
119 static void
120 sev_set_guest_state(SevState new_state)
122 assert(new_state < SEV_STATE__MAX);
123 assert(sev_state);
125 trace_kvm_sev_change_state(SevState_str(sev_state->state),
126 SevState_str(new_state));
127 sev_state->state = new_state;
130 static void
131 sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
133 int r;
134 struct kvm_enc_region range;
135 ram_addr_t offset;
136 MemoryRegion *mr;
139 * The RAM device presents a memory region that should be treated
140 * as IO region and should not be pinned.
142 mr = memory_region_from_host(host, &offset);
143 if (mr && memory_region_is_ram_device(mr)) {
144 return;
147 range.addr = (__u64)(unsigned long)host;
148 range.size = size;
150 trace_kvm_memcrypt_register_region(host, size);
151 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
152 if (r) {
153 error_report("%s: failed to register region (%p+%#zx) error '%s'",
154 __func__, host, size, strerror(errno));
155 exit(1);
159 static void
160 sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
162 int r;
163 struct kvm_enc_region range;
164 ram_addr_t offset;
165 MemoryRegion *mr;
168 * The RAM device presents a memory region that should be treated
169 * as IO region and should not have been pinned.
171 mr = memory_region_from_host(host, &offset);
172 if (mr && memory_region_is_ram_device(mr)) {
173 return;
176 range.addr = (__u64)(unsigned long)host;
177 range.size = size;
179 trace_kvm_memcrypt_unregister_region(host, size);
180 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
181 if (r) {
182 error_report("%s: failed to unregister region (%p+%#zx)",
183 __func__, host, size);
187 static struct RAMBlockNotifier sev_ram_notifier = {
188 .ram_block_added = sev_ram_block_added,
189 .ram_block_removed = sev_ram_block_removed,
192 static void
193 qsev_guest_finalize(Object *obj)
197 static char *
198 qsev_guest_get_session_file(Object *obj, Error **errp)
200 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
202 return s->session_file ? g_strdup(s->session_file) : NULL;
205 static void
206 qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
208 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
210 s->session_file = g_strdup(value);
213 static char *
214 qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
216 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
218 return g_strdup(s->dh_cert_file);
221 static void
222 qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
224 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
226 s->dh_cert_file = g_strdup(value);
229 static char *
230 qsev_guest_get_sev_device(Object *obj, Error **errp)
232 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
234 return g_strdup(sev->sev_device);
237 static void
238 qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
240 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
242 sev->sev_device = g_strdup(value);
245 static void
246 qsev_guest_class_init(ObjectClass *oc, void *data)
248 object_class_property_add_str(oc, "sev-device",
249 qsev_guest_get_sev_device,
250 qsev_guest_set_sev_device,
251 NULL);
252 object_class_property_set_description(oc, "sev-device",
253 "SEV device to use", NULL);
254 object_class_property_add_str(oc, "dh-cert-file",
255 qsev_guest_get_dh_cert_file,
256 qsev_guest_set_dh_cert_file,
257 NULL);
258 object_class_property_set_description(oc, "dh-cert-file",
259 "guest owners DH certificate (encoded with base64)", NULL);
260 object_class_property_add_str(oc, "session-file",
261 qsev_guest_get_session_file,
262 qsev_guest_set_session_file,
263 NULL);
264 object_class_property_set_description(oc, "session-file",
265 "guest owners session parameters (encoded with base64)", NULL);
268 static void
269 qsev_guest_set_handle(Object *obj, Visitor *v, const char *name,
270 void *opaque, Error **errp)
272 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
273 uint32_t value;
275 visit_type_uint32(v, name, &value, errp);
276 sev->handle = value;
279 static void
280 qsev_guest_set_policy(Object *obj, Visitor *v, const char *name,
281 void *opaque, Error **errp)
283 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
284 uint32_t value;
286 visit_type_uint32(v, name, &value, errp);
287 sev->policy = value;
290 static void
291 qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name,
292 void *opaque, Error **errp)
294 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
295 uint32_t value;
297 visit_type_uint32(v, name, &value, errp);
298 sev->cbitpos = value;
301 static void
302 qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
303 void *opaque, Error **errp)
305 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
306 uint32_t value;
308 visit_type_uint32(v, name, &value, errp);
309 sev->reduced_phys_bits = value;
312 static void
313 qsev_guest_get_policy(Object *obj, Visitor *v, const char *name,
314 void *opaque, Error **errp)
316 uint32_t value;
317 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
319 value = sev->policy;
320 visit_type_uint32(v, name, &value, errp);
323 static void
324 qsev_guest_get_handle(Object *obj, Visitor *v, const char *name,
325 void *opaque, Error **errp)
327 uint32_t value;
328 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
330 value = sev->handle;
331 visit_type_uint32(v, name, &value, errp);
334 static void
335 qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name,
336 void *opaque, Error **errp)
338 uint32_t value;
339 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
341 value = sev->cbitpos;
342 visit_type_uint32(v, name, &value, errp);
345 static void
346 qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
347 void *opaque, Error **errp)
349 uint32_t value;
350 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
352 value = sev->reduced_phys_bits;
353 visit_type_uint32(v, name, &value, errp);
356 static void
357 qsev_guest_init(Object *obj)
359 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
361 sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
362 sev->policy = DEFAULT_GUEST_POLICY;
363 object_property_add(obj, "policy", "uint32", qsev_guest_get_policy,
364 qsev_guest_set_policy, NULL, NULL, NULL);
365 object_property_add(obj, "handle", "uint32", qsev_guest_get_handle,
366 qsev_guest_set_handle, NULL, NULL, NULL);
367 object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos,
368 qsev_guest_set_cbitpos, NULL, NULL, NULL);
369 object_property_add(obj, "reduced-phys-bits", "uint32",
370 qsev_guest_get_reduced_phys_bits,
371 qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL);
374 /* sev guest info */
375 static const TypeInfo qsev_guest_info = {
376 .parent = TYPE_OBJECT,
377 .name = TYPE_QSEV_GUEST_INFO,
378 .instance_size = sizeof(QSevGuestInfo),
379 .instance_finalize = qsev_guest_finalize,
380 .class_size = sizeof(QSevGuestInfoClass),
381 .class_init = qsev_guest_class_init,
382 .instance_init = qsev_guest_init,
383 .interfaces = (InterfaceInfo[]) {
384 { TYPE_USER_CREATABLE },
389 static QSevGuestInfo *
390 lookup_sev_guest_info(const char *id)
392 Object *obj;
393 QSevGuestInfo *info;
395 obj = object_resolve_path_component(object_get_objects_root(), id);
396 if (!obj) {
397 return NULL;
400 info = (QSevGuestInfo *)
401 object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
402 if (!info) {
403 return NULL;
406 return info;
409 bool
410 sev_enabled(void)
412 return sev_state ? true : false;
415 uint64_t
416 sev_get_me_mask(void)
418 return sev_state ? sev_state->me_mask : ~0;
421 uint32_t
422 sev_get_cbit_position(void)
424 return sev_state ? sev_state->cbitpos : 0;
427 uint32_t
428 sev_get_reduced_phys_bits(void)
430 return sev_state ? sev_state->reduced_phys_bits : 0;
433 SevInfo *
434 sev_get_info(void)
436 SevInfo *info;
438 info = g_new0(SevInfo, 1);
439 info->enabled = sev_state ? true : false;
441 if (info->enabled) {
442 info->api_major = sev_state->api_major;
443 info->api_minor = sev_state->api_minor;
444 info->build_id = sev_state->build_id;
445 info->policy = sev_state->policy;
446 info->state = sev_state->state;
447 info->handle = sev_state->handle;
450 return info;
453 static int
454 sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
455 size_t *cert_chain_len)
457 guchar *pdh_data = NULL;
458 guchar *cert_chain_data = NULL;
459 struct sev_user_data_pdh_cert_export export = {};
460 int err, r;
462 /* query the certificate length */
463 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
464 if (r < 0) {
465 if (err != SEV_RET_INVALID_LEN) {
466 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
467 r, err, fw_error_to_str(err));
468 return 1;
472 pdh_data = g_new(guchar, export.pdh_cert_len);
473 cert_chain_data = g_new(guchar, export.cert_chain_len);
474 export.pdh_cert_address = (unsigned long)pdh_data;
475 export.cert_chain_address = (unsigned long)cert_chain_data;
477 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
478 if (r < 0) {
479 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
480 r, err, fw_error_to_str(err));
481 goto e_free;
484 *pdh = pdh_data;
485 *pdh_len = export.pdh_cert_len;
486 *cert_chain = cert_chain_data;
487 *cert_chain_len = export.cert_chain_len;
488 return 0;
490 e_free:
491 g_free(pdh_data);
492 g_free(cert_chain_data);
493 return 1;
496 SevCapability *
497 sev_get_capabilities(void)
499 SevCapability *cap = NULL;
500 guchar *pdh_data = NULL;
501 guchar *cert_chain_data = NULL;
502 size_t pdh_len = 0, cert_chain_len = 0;
503 uint32_t ebx;
504 int fd;
506 fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
507 if (fd < 0) {
508 error_report("%s: Failed to open %s '%s'", __func__,
509 DEFAULT_SEV_DEVICE, strerror(errno));
510 return NULL;
513 if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
514 &cert_chain_data, &cert_chain_len)) {
515 goto out;
518 cap = g_new0(SevCapability, 1);
519 cap->pdh = g_base64_encode(pdh_data, pdh_len);
520 cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
522 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
523 cap->cbitpos = ebx & 0x3f;
526 * When SEV feature is enabled, we loose one bit in guest physical
527 * addressing.
529 cap->reduced_phys_bits = 1;
531 out:
532 g_free(pdh_data);
533 g_free(cert_chain_data);
534 close(fd);
535 return cap;
538 static int
539 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
541 gsize sz;
542 gchar *base64;
543 GError *error = NULL;
545 if (!g_file_get_contents(filename, &base64, &sz, &error)) {
546 error_report("failed to read '%s' (%s)", filename, error->message);
547 return -1;
550 *data = g_base64_decode(base64, len);
551 return 0;
554 static int
555 sev_launch_start(SEVState *s)
557 gsize sz;
558 int ret = 1;
559 int fw_error, rc;
560 QSevGuestInfo *sev = s->sev_info;
561 struct kvm_sev_launch_start *start;
562 guchar *session = NULL, *dh_cert = NULL;
564 start = g_new0(struct kvm_sev_launch_start, 1);
566 start->handle = object_property_get_int(OBJECT(sev), "handle",
567 &error_abort);
568 start->policy = object_property_get_int(OBJECT(sev), "policy",
569 &error_abort);
570 if (sev->session_file) {
571 if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
572 goto out;
574 start->session_uaddr = (unsigned long)session;
575 start->session_len = sz;
578 if (sev->dh_cert_file) {
579 if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
580 goto out;
582 start->dh_uaddr = (unsigned long)dh_cert;
583 start->dh_len = sz;
586 trace_kvm_sev_launch_start(start->policy, session, dh_cert);
587 rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
588 if (rc < 0) {
589 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
590 __func__, ret, fw_error, fw_error_to_str(fw_error));
591 goto out;
594 object_property_set_int(OBJECT(sev), start->handle, "handle",
595 &error_abort);
596 sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
597 s->handle = start->handle;
598 s->policy = start->policy;
599 ret = 0;
601 out:
602 g_free(start);
603 g_free(session);
604 g_free(dh_cert);
605 return ret;
608 static int
609 sev_launch_update_data(uint8_t *addr, uint64_t len)
611 int ret, fw_error;
612 struct kvm_sev_launch_update_data update;
614 if (!addr || !len) {
615 return 1;
618 update.uaddr = (__u64)(unsigned long)addr;
619 update.len = len;
620 trace_kvm_sev_launch_update_data(addr, len);
621 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
622 &update, &fw_error);
623 if (ret) {
624 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
625 __func__, ret, fw_error, fw_error_to_str(fw_error));
628 return ret;
631 static void
632 sev_launch_get_measure(Notifier *notifier, void *unused)
634 int ret, error;
635 guchar *data;
636 SEVState *s = sev_state;
637 struct kvm_sev_launch_measure *measurement;
639 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
640 return;
643 measurement = g_new0(struct kvm_sev_launch_measure, 1);
645 /* query the measurement blob length */
646 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
647 measurement, &error);
648 if (!measurement->len) {
649 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
650 __func__, ret, error, fw_error_to_str(errno));
651 goto free_measurement;
654 data = g_new0(guchar, measurement->len);
655 measurement->uaddr = (unsigned long)data;
657 /* get the measurement blob */
658 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
659 measurement, &error);
660 if (ret) {
661 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
662 __func__, ret, error, fw_error_to_str(errno));
663 goto free_data;
666 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
668 /* encode the measurement value and emit the event */
669 s->measurement = g_base64_encode(data, measurement->len);
670 trace_kvm_sev_launch_measurement(s->measurement);
672 free_data:
673 g_free(data);
674 free_measurement:
675 g_free(measurement);
678 char *
679 sev_get_launch_measurement(void)
681 if (sev_state &&
682 sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
683 return g_strdup(sev_state->measurement);
686 return NULL;
689 static Notifier sev_machine_done_notify = {
690 .notify = sev_launch_get_measure,
693 static void
694 sev_launch_finish(SEVState *s)
696 int ret, error;
697 Error *local_err = NULL;
699 trace_kvm_sev_launch_finish();
700 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
701 if (ret) {
702 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
703 __func__, ret, error, fw_error_to_str(error));
704 exit(1);
707 sev_set_guest_state(SEV_STATE_RUNNING);
709 /* add migration blocker */
710 error_setg(&sev_mig_blocker,
711 "SEV: Migration is not implemented");
712 ret = migrate_add_blocker(sev_mig_blocker, &local_err);
713 if (local_err) {
714 error_report_err(local_err);
715 error_free(sev_mig_blocker);
716 exit(1);
720 static void
721 sev_vm_state_change(void *opaque, int running, RunState state)
723 SEVState *s = opaque;
725 if (running) {
726 if (!sev_check_state(SEV_STATE_RUNNING)) {
727 sev_launch_finish(s);
732 void *
733 sev_guest_init(const char *id)
735 SEVState *s;
736 char *devname;
737 int ret, fw_error;
738 uint32_t ebx;
739 uint32_t host_cbitpos;
740 struct sev_user_data_status status = {};
742 sev_state = s = g_new0(SEVState, 1);
743 s->sev_info = lookup_sev_guest_info(id);
744 if (!s->sev_info) {
745 error_report("%s: '%s' is not a valid '%s' object",
746 __func__, id, TYPE_QSEV_GUEST_INFO);
747 goto err;
750 s->state = SEV_STATE_UNINIT;
752 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
753 host_cbitpos = ebx & 0x3f;
755 s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
756 if (host_cbitpos != s->cbitpos) {
757 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
758 __func__, host_cbitpos, s->cbitpos);
759 goto err;
762 s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
763 "reduced-phys-bits", NULL);
764 if (s->reduced_phys_bits < 1) {
765 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
766 " requested '%d'", __func__, s->reduced_phys_bits);
767 goto err;
770 s->me_mask = ~(1UL << s->cbitpos);
772 devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
773 s->sev_fd = open(devname, O_RDWR);
774 if (s->sev_fd < 0) {
775 error_report("%s: Failed to open %s '%s'", __func__,
776 devname, strerror(errno));
778 g_free(devname);
779 if (s->sev_fd < 0) {
780 goto err;
783 ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
784 &fw_error);
785 if (ret) {
786 error_report("%s: failed to get platform status ret=%d "
787 "fw_error='%d: %s'", __func__, ret, fw_error,
788 fw_error_to_str(fw_error));
789 goto err;
791 s->build_id = status.build;
792 s->api_major = status.api_major;
793 s->api_minor = status.api_minor;
795 trace_kvm_sev_init();
796 ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
797 if (ret) {
798 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
799 __func__, ret, fw_error, fw_error_to_str(fw_error));
800 goto err;
803 ret = sev_launch_start(s);
804 if (ret) {
805 error_report("%s: failed to create encryption context", __func__);
806 goto err;
809 ram_block_notifier_add(&sev_ram_notifier);
810 qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
811 qemu_add_vm_change_state_handler(sev_vm_state_change, s);
813 return s;
814 err:
815 g_free(sev_state);
816 sev_state = NULL;
817 return NULL;
821 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
823 assert(handle);
825 /* if SEV is in update state then encrypt the data else do nothing */
826 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
827 return sev_launch_update_data(ptr, len);
830 return 0;
833 static void
834 sev_register_types(void)
836 type_register_static(&qsev_guest_info);
839 type_init(sev_register_types);