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