block: improve should_update_child
[qemu/ar7.git] / target / i386 / sev.c
blob20b2d325d81bdf6d4f280272157b521c3ab66217
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 "sysemu/kvm.h"
25 #include "sev_i386.h"
26 #include "sysemu/sysemu.h"
27 #include "trace.h"
28 #include "migration/blocker.h"
30 #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
31 #define DEFAULT_SEV_DEVICE "/dev/sev"
33 static SEVState *sev_state;
34 static Error *sev_mig_blocker;
36 static const char *const sev_fw_errlist[] = {
37 "",
38 "Platform state is invalid",
39 "Guest state is invalid",
40 "Platform configuration is invalid",
41 "Buffer too small",
42 "Platform is already owned",
43 "Certificate is invalid",
44 "Policy is not allowed",
45 "Guest is not active",
46 "Invalid address",
47 "Bad signature",
48 "Bad measurement",
49 "Asid is already owned",
50 "Invalid ASID",
51 "WBINVD is required",
52 "DF_FLUSH is required",
53 "Guest handle is invalid",
54 "Invalid command",
55 "Guest is active",
56 "Hardware error",
57 "Hardware unsafe",
58 "Feature not supported",
59 "Invalid parameter"
62 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
64 static int
65 sev_ioctl(int fd, int cmd, void *data, int *error)
67 int r;
68 struct kvm_sev_cmd input;
70 memset(&input, 0x0, sizeof(input));
72 input.id = cmd;
73 input.sev_fd = fd;
74 input.data = (__u64)(unsigned long)data;
76 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
78 if (error) {
79 *error = input.error;
82 return r;
85 static int
86 sev_platform_ioctl(int fd, int cmd, void *data, int *error)
88 int r;
89 struct sev_issue_cmd arg;
91 arg.cmd = cmd;
92 arg.data = (unsigned long)data;
93 r = ioctl(fd, SEV_ISSUE_CMD, &arg);
94 if (error) {
95 *error = arg.error;
98 return r;
101 static const char *
102 fw_error_to_str(int code)
104 if (code < 0 || code >= SEV_FW_MAX_ERROR) {
105 return "unknown error";
108 return sev_fw_errlist[code];
111 static bool
112 sev_check_state(SevState state)
114 assert(sev_state);
115 return sev_state->state == state ? true : false;
118 static void
119 sev_set_guest_state(SevState new_state)
121 assert(new_state < SEV_STATE__MAX);
122 assert(sev_state);
124 trace_kvm_sev_change_state(SevState_str(sev_state->state),
125 SevState_str(new_state));
126 sev_state->state = new_state;
129 static void
130 sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
132 int r;
133 struct kvm_enc_region range;
135 range.addr = (__u64)(unsigned long)host;
136 range.size = size;
138 trace_kvm_memcrypt_register_region(host, size);
139 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
140 if (r) {
141 error_report("%s: failed to register region (%p+%#zx) error '%s'",
142 __func__, host, size, strerror(errno));
143 exit(1);
147 static void
148 sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
150 int r;
151 struct kvm_enc_region range;
153 range.addr = (__u64)(unsigned long)host;
154 range.size = size;
156 trace_kvm_memcrypt_unregister_region(host, size);
157 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
158 if (r) {
159 error_report("%s: failed to unregister region (%p+%#zx)",
160 __func__, host, size);
164 static struct RAMBlockNotifier sev_ram_notifier = {
165 .ram_block_added = sev_ram_block_added,
166 .ram_block_removed = sev_ram_block_removed,
169 static void
170 qsev_guest_finalize(Object *obj)
174 static char *
175 qsev_guest_get_session_file(Object *obj, Error **errp)
177 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
179 return s->session_file ? g_strdup(s->session_file) : NULL;
182 static void
183 qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
185 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
187 s->session_file = g_strdup(value);
190 static char *
191 qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
193 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
195 return g_strdup(s->dh_cert_file);
198 static void
199 qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
201 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
203 s->dh_cert_file = g_strdup(value);
206 static char *
207 qsev_guest_get_sev_device(Object *obj, Error **errp)
209 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
211 return g_strdup(sev->sev_device);
214 static void
215 qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
217 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
219 sev->sev_device = g_strdup(value);
222 static void
223 qsev_guest_class_init(ObjectClass *oc, void *data)
225 object_class_property_add_str(oc, "sev-device",
226 qsev_guest_get_sev_device,
227 qsev_guest_set_sev_device,
228 NULL);
229 object_class_property_set_description(oc, "sev-device",
230 "SEV device to use", NULL);
231 object_class_property_add_str(oc, "dh-cert-file",
232 qsev_guest_get_dh_cert_file,
233 qsev_guest_set_dh_cert_file,
234 NULL);
235 object_class_property_set_description(oc, "dh-cert-file",
236 "guest owners DH certificate (encoded with base64)", NULL);
237 object_class_property_add_str(oc, "session-file",
238 qsev_guest_get_session_file,
239 qsev_guest_set_session_file,
240 NULL);
241 object_class_property_set_description(oc, "session-file",
242 "guest owners session parameters (encoded with base64)", NULL);
245 static void
246 qsev_guest_set_handle(Object *obj, Visitor *v, const char *name,
247 void *opaque, Error **errp)
249 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
250 uint32_t value;
252 visit_type_uint32(v, name, &value, errp);
253 sev->handle = value;
256 static void
257 qsev_guest_set_policy(Object *obj, Visitor *v, const char *name,
258 void *opaque, Error **errp)
260 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
261 uint32_t value;
263 visit_type_uint32(v, name, &value, errp);
264 sev->policy = value;
267 static void
268 qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name,
269 void *opaque, Error **errp)
271 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
272 uint32_t value;
274 visit_type_uint32(v, name, &value, errp);
275 sev->cbitpos = value;
278 static void
279 qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
280 void *opaque, Error **errp)
282 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
283 uint32_t value;
285 visit_type_uint32(v, name, &value, errp);
286 sev->reduced_phys_bits = value;
289 static void
290 qsev_guest_get_policy(Object *obj, Visitor *v, const char *name,
291 void *opaque, Error **errp)
293 uint32_t value;
294 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
296 value = sev->policy;
297 visit_type_uint32(v, name, &value, errp);
300 static void
301 qsev_guest_get_handle(Object *obj, Visitor *v, const char *name,
302 void *opaque, Error **errp)
304 uint32_t value;
305 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
307 value = sev->handle;
308 visit_type_uint32(v, name, &value, errp);
311 static void
312 qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name,
313 void *opaque, Error **errp)
315 uint32_t value;
316 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
318 value = sev->cbitpos;
319 visit_type_uint32(v, name, &value, errp);
322 static void
323 qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
324 void *opaque, Error **errp)
326 uint32_t value;
327 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
329 value = sev->reduced_phys_bits;
330 visit_type_uint32(v, name, &value, errp);
333 static void
334 qsev_guest_init(Object *obj)
336 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
338 sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
339 sev->policy = DEFAULT_GUEST_POLICY;
340 object_property_add(obj, "policy", "uint32", qsev_guest_get_policy,
341 qsev_guest_set_policy, NULL, NULL, NULL);
342 object_property_add(obj, "handle", "uint32", qsev_guest_get_handle,
343 qsev_guest_set_handle, NULL, NULL, NULL);
344 object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos,
345 qsev_guest_set_cbitpos, NULL, NULL, NULL);
346 object_property_add(obj, "reduced-phys-bits", "uint32",
347 qsev_guest_get_reduced_phys_bits,
348 qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL);
351 /* sev guest info */
352 static const TypeInfo qsev_guest_info = {
353 .parent = TYPE_OBJECT,
354 .name = TYPE_QSEV_GUEST_INFO,
355 .instance_size = sizeof(QSevGuestInfo),
356 .instance_finalize = qsev_guest_finalize,
357 .class_size = sizeof(QSevGuestInfoClass),
358 .class_init = qsev_guest_class_init,
359 .instance_init = qsev_guest_init,
360 .interfaces = (InterfaceInfo[]) {
361 { TYPE_USER_CREATABLE },
366 static QSevGuestInfo *
367 lookup_sev_guest_info(const char *id)
369 Object *obj;
370 QSevGuestInfo *info;
372 obj = object_resolve_path_component(object_get_objects_root(), id);
373 if (!obj) {
374 return NULL;
377 info = (QSevGuestInfo *)
378 object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
379 if (!info) {
380 return NULL;
383 return info;
386 bool
387 sev_enabled(void)
389 return sev_state ? true : false;
392 uint64_t
393 sev_get_me_mask(void)
395 return sev_state ? sev_state->me_mask : ~0;
398 uint32_t
399 sev_get_cbit_position(void)
401 return sev_state ? sev_state->cbitpos : 0;
404 uint32_t
405 sev_get_reduced_phys_bits(void)
407 return sev_state ? sev_state->reduced_phys_bits : 0;
410 SevInfo *
411 sev_get_info(void)
413 SevInfo *info;
415 info = g_new0(SevInfo, 1);
416 info->enabled = sev_state ? true : false;
418 if (info->enabled) {
419 info->api_major = sev_state->api_major;
420 info->api_minor = sev_state->api_minor;
421 info->build_id = sev_state->build_id;
422 info->policy = sev_state->policy;
423 info->state = sev_state->state;
424 info->handle = sev_state->handle;
427 return info;
430 static int
431 sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
432 size_t *cert_chain_len)
434 guchar *pdh_data = NULL;
435 guchar *cert_chain_data = NULL;
436 struct sev_user_data_pdh_cert_export export = {};
437 int err, r;
439 /* query the certificate length */
440 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
441 if (r < 0) {
442 if (err != SEV_RET_INVALID_LEN) {
443 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
444 r, err, fw_error_to_str(err));
445 return 1;
449 pdh_data = g_new(guchar, export.pdh_cert_len);
450 cert_chain_data = g_new(guchar, export.cert_chain_len);
451 export.pdh_cert_address = (unsigned long)pdh_data;
452 export.cert_chain_address = (unsigned long)cert_chain_data;
454 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
455 if (r < 0) {
456 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
457 r, err, fw_error_to_str(err));
458 goto e_free;
461 *pdh = pdh_data;
462 *pdh_len = export.pdh_cert_len;
463 *cert_chain = cert_chain_data;
464 *cert_chain_len = export.cert_chain_len;
465 return 0;
467 e_free:
468 g_free(pdh_data);
469 g_free(cert_chain_data);
470 return 1;
473 SevCapability *
474 sev_get_capabilities(void)
476 SevCapability *cap = NULL;
477 guchar *pdh_data = NULL;
478 guchar *cert_chain_data = NULL;
479 size_t pdh_len = 0, cert_chain_len = 0;
480 uint32_t ebx;
481 int fd;
483 fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
484 if (fd < 0) {
485 error_report("%s: Failed to open %s '%s'", __func__,
486 DEFAULT_SEV_DEVICE, strerror(errno));
487 return NULL;
490 if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
491 &cert_chain_data, &cert_chain_len)) {
492 goto out;
495 cap = g_new0(SevCapability, 1);
496 cap->pdh = g_base64_encode(pdh_data, pdh_len);
497 cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
499 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
500 cap->cbitpos = ebx & 0x3f;
503 * When SEV feature is enabled, we loose one bit in guest physical
504 * addressing.
506 cap->reduced_phys_bits = 1;
508 out:
509 g_free(pdh_data);
510 g_free(cert_chain_data);
511 close(fd);
512 return cap;
515 static int
516 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
518 gsize sz;
519 gchar *base64;
520 GError *error = NULL;
522 if (!g_file_get_contents(filename, &base64, &sz, &error)) {
523 error_report("failed to read '%s' (%s)", filename, error->message);
524 return -1;
527 *data = g_base64_decode(base64, len);
528 return 0;
531 static int
532 sev_launch_start(SEVState *s)
534 gsize sz;
535 int ret = 1;
536 int fw_error, rc;
537 QSevGuestInfo *sev = s->sev_info;
538 struct kvm_sev_launch_start *start;
539 guchar *session = NULL, *dh_cert = NULL;
541 start = g_new0(struct kvm_sev_launch_start, 1);
543 start->handle = object_property_get_int(OBJECT(sev), "handle",
544 &error_abort);
545 start->policy = object_property_get_int(OBJECT(sev), "policy",
546 &error_abort);
547 if (sev->session_file) {
548 if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
549 goto out;
551 start->session_uaddr = (unsigned long)session;
552 start->session_len = sz;
555 if (sev->dh_cert_file) {
556 if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
557 goto out;
559 start->dh_uaddr = (unsigned long)dh_cert;
560 start->dh_len = sz;
563 trace_kvm_sev_launch_start(start->policy, session, dh_cert);
564 rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
565 if (rc < 0) {
566 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
567 __func__, ret, fw_error, fw_error_to_str(fw_error));
568 goto out;
571 object_property_set_int(OBJECT(sev), start->handle, "handle",
572 &error_abort);
573 sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
574 s->handle = start->handle;
575 s->policy = start->policy;
576 ret = 0;
578 out:
579 g_free(start);
580 g_free(session);
581 g_free(dh_cert);
582 return ret;
585 static int
586 sev_launch_update_data(uint8_t *addr, uint64_t len)
588 int ret, fw_error;
589 struct kvm_sev_launch_update_data update;
591 if (!addr || !len) {
592 return 1;
595 update.uaddr = (__u64)(unsigned long)addr;
596 update.len = len;
597 trace_kvm_sev_launch_update_data(addr, len);
598 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
599 &update, &fw_error);
600 if (ret) {
601 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
602 __func__, ret, fw_error, fw_error_to_str(fw_error));
605 return ret;
608 static void
609 sev_launch_get_measure(Notifier *notifier, void *unused)
611 int ret, error;
612 guchar *data;
613 SEVState *s = sev_state;
614 struct kvm_sev_launch_measure *measurement;
616 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
617 return;
620 measurement = g_new0(struct kvm_sev_launch_measure, 1);
622 /* query the measurement blob length */
623 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
624 measurement, &error);
625 if (!measurement->len) {
626 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
627 __func__, ret, error, fw_error_to_str(errno));
628 goto free_measurement;
631 data = g_new0(guchar, measurement->len);
632 measurement->uaddr = (unsigned long)data;
634 /* get the measurement blob */
635 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
636 measurement, &error);
637 if (ret) {
638 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
639 __func__, ret, error, fw_error_to_str(errno));
640 goto free_data;
643 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
645 /* encode the measurement value and emit the event */
646 s->measurement = g_base64_encode(data, measurement->len);
647 trace_kvm_sev_launch_measurement(s->measurement);
649 free_data:
650 g_free(data);
651 free_measurement:
652 g_free(measurement);
655 char *
656 sev_get_launch_measurement(void)
658 if (sev_state &&
659 sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
660 return g_strdup(sev_state->measurement);
663 return NULL;
666 static Notifier sev_machine_done_notify = {
667 .notify = sev_launch_get_measure,
670 static void
671 sev_launch_finish(SEVState *s)
673 int ret, error;
674 Error *local_err = NULL;
676 trace_kvm_sev_launch_finish();
677 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
678 if (ret) {
679 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
680 __func__, ret, error, fw_error_to_str(error));
681 exit(1);
684 sev_set_guest_state(SEV_STATE_RUNNING);
686 /* add migration blocker */
687 error_setg(&sev_mig_blocker,
688 "SEV: Migration is not implemented");
689 ret = migrate_add_blocker(sev_mig_blocker, &local_err);
690 if (local_err) {
691 error_report_err(local_err);
692 error_free(sev_mig_blocker);
693 exit(1);
697 static void
698 sev_vm_state_change(void *opaque, int running, RunState state)
700 SEVState *s = opaque;
702 if (running) {
703 if (!sev_check_state(SEV_STATE_RUNNING)) {
704 sev_launch_finish(s);
709 void *
710 sev_guest_init(const char *id)
712 SEVState *s;
713 char *devname;
714 int ret, fw_error;
715 uint32_t ebx;
716 uint32_t host_cbitpos;
717 struct sev_user_data_status status = {};
719 sev_state = s = g_new0(SEVState, 1);
720 s->sev_info = lookup_sev_guest_info(id);
721 if (!s->sev_info) {
722 error_report("%s: '%s' is not a valid '%s' object",
723 __func__, id, TYPE_QSEV_GUEST_INFO);
724 goto err;
727 s->state = SEV_STATE_UNINIT;
729 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
730 host_cbitpos = ebx & 0x3f;
732 s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
733 if (host_cbitpos != s->cbitpos) {
734 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
735 __func__, host_cbitpos, s->cbitpos);
736 goto err;
739 s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
740 "reduced-phys-bits", NULL);
741 if (s->reduced_phys_bits < 1) {
742 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
743 "' requested '%d'", __func__, s->reduced_phys_bits);
744 goto err;
747 s->me_mask = ~(1UL << s->cbitpos);
749 devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
750 s->sev_fd = open(devname, O_RDWR);
751 if (s->sev_fd < 0) {
752 error_report("%s: Failed to open %s '%s'", __func__,
753 devname, strerror(errno));
755 g_free(devname);
756 if (s->sev_fd < 0) {
757 goto err;
760 ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
761 &fw_error);
762 if (ret) {
763 error_report("%s: failed to get platform status ret=%d"
764 "fw_error='%d: %s'", __func__, ret, fw_error,
765 fw_error_to_str(fw_error));
766 goto err;
768 s->build_id = status.build;
769 s->api_major = status.api_major;
770 s->api_minor = status.api_minor;
772 trace_kvm_sev_init();
773 ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
774 if (ret) {
775 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
776 __func__, ret, fw_error, fw_error_to_str(fw_error));
777 goto err;
780 ret = sev_launch_start(s);
781 if (ret) {
782 error_report("%s: failed to create encryption context", __func__);
783 goto err;
786 ram_block_notifier_add(&sev_ram_notifier);
787 qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
788 qemu_add_vm_change_state_handler(sev_vm_state_change, s);
790 return s;
791 err:
792 g_free(sev_state);
793 sev_state = NULL;
794 return NULL;
798 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
800 assert(handle);
802 /* if SEV is in update state then encrypt the data else do nothing */
803 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
804 return sev_launch_update_data(ptr, len);
807 return 0;
810 static void
811 sev_register_types(void)
813 type_register_static(&qsev_guest_info);
816 type_init(sev_register_types);