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