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