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