qxl: check release info object
[qemu/ar7.git] / target / i386 / sev.c
blobcd77f6b5d477d42e1ae7ffe36b527c8766c132ec
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;
134 ram_addr_t offset;
135 MemoryRegion *mr;
138 * The RAM device presents a memory region that should be treated
139 * as IO region and should not be pinned.
141 mr = memory_region_from_host(host, &offset);
142 if (mr && memory_region_is_ram_device(mr)) {
143 return;
146 range.addr = (__u64)(unsigned long)host;
147 range.size = size;
149 trace_kvm_memcrypt_register_region(host, size);
150 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
151 if (r) {
152 error_report("%s: failed to register region (%p+%#zx) error '%s'",
153 __func__, host, size, strerror(errno));
154 exit(1);
158 static void
159 sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
161 int r;
162 struct kvm_enc_region range;
164 range.addr = (__u64)(unsigned long)host;
165 range.size = size;
167 trace_kvm_memcrypt_unregister_region(host, size);
168 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
169 if (r) {
170 error_report("%s: failed to unregister region (%p+%#zx)",
171 __func__, host, size);
175 static struct RAMBlockNotifier sev_ram_notifier = {
176 .ram_block_added = sev_ram_block_added,
177 .ram_block_removed = sev_ram_block_removed,
180 static void
181 qsev_guest_finalize(Object *obj)
185 static char *
186 qsev_guest_get_session_file(Object *obj, Error **errp)
188 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
190 return s->session_file ? g_strdup(s->session_file) : NULL;
193 static void
194 qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
196 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
198 s->session_file = g_strdup(value);
201 static char *
202 qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
204 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
206 return g_strdup(s->dh_cert_file);
209 static void
210 qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
212 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
214 s->dh_cert_file = g_strdup(value);
217 static char *
218 qsev_guest_get_sev_device(Object *obj, Error **errp)
220 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
222 return g_strdup(sev->sev_device);
225 static void
226 qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
228 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
230 sev->sev_device = g_strdup(value);
233 static void
234 qsev_guest_class_init(ObjectClass *oc, void *data)
236 object_class_property_add_str(oc, "sev-device",
237 qsev_guest_get_sev_device,
238 qsev_guest_set_sev_device,
239 NULL);
240 object_class_property_set_description(oc, "sev-device",
241 "SEV device to use", NULL);
242 object_class_property_add_str(oc, "dh-cert-file",
243 qsev_guest_get_dh_cert_file,
244 qsev_guest_set_dh_cert_file,
245 NULL);
246 object_class_property_set_description(oc, "dh-cert-file",
247 "guest owners DH certificate (encoded with base64)", NULL);
248 object_class_property_add_str(oc, "session-file",
249 qsev_guest_get_session_file,
250 qsev_guest_set_session_file,
251 NULL);
252 object_class_property_set_description(oc, "session-file",
253 "guest owners session parameters (encoded with base64)", NULL);
256 static void
257 qsev_guest_set_handle(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->handle = value;
267 static void
268 qsev_guest_set_policy(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->policy = value;
278 static void
279 qsev_guest_set_cbitpos(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->cbitpos = value;
289 static void
290 qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
291 void *opaque, Error **errp)
293 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
294 uint32_t value;
296 visit_type_uint32(v, name, &value, errp);
297 sev->reduced_phys_bits = value;
300 static void
301 qsev_guest_get_policy(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->policy;
308 visit_type_uint32(v, name, &value, errp);
311 static void
312 qsev_guest_get_handle(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->handle;
319 visit_type_uint32(v, name, &value, errp);
322 static void
323 qsev_guest_get_cbitpos(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->cbitpos;
330 visit_type_uint32(v, name, &value, errp);
333 static void
334 qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
335 void *opaque, Error **errp)
337 uint32_t value;
338 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
340 value = sev->reduced_phys_bits;
341 visit_type_uint32(v, name, &value, errp);
344 static void
345 qsev_guest_init(Object *obj)
347 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
349 sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
350 sev->policy = DEFAULT_GUEST_POLICY;
351 object_property_add(obj, "policy", "uint32", qsev_guest_get_policy,
352 qsev_guest_set_policy, NULL, NULL, NULL);
353 object_property_add(obj, "handle", "uint32", qsev_guest_get_handle,
354 qsev_guest_set_handle, NULL, NULL, NULL);
355 object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos,
356 qsev_guest_set_cbitpos, NULL, NULL, NULL);
357 object_property_add(obj, "reduced-phys-bits", "uint32",
358 qsev_guest_get_reduced_phys_bits,
359 qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL);
362 /* sev guest info */
363 static const TypeInfo qsev_guest_info = {
364 .parent = TYPE_OBJECT,
365 .name = TYPE_QSEV_GUEST_INFO,
366 .instance_size = sizeof(QSevGuestInfo),
367 .instance_finalize = qsev_guest_finalize,
368 .class_size = sizeof(QSevGuestInfoClass),
369 .class_init = qsev_guest_class_init,
370 .instance_init = qsev_guest_init,
371 .interfaces = (InterfaceInfo[]) {
372 { TYPE_USER_CREATABLE },
377 static QSevGuestInfo *
378 lookup_sev_guest_info(const char *id)
380 Object *obj;
381 QSevGuestInfo *info;
383 obj = object_resolve_path_component(object_get_objects_root(), id);
384 if (!obj) {
385 return NULL;
388 info = (QSevGuestInfo *)
389 object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
390 if (!info) {
391 return NULL;
394 return info;
397 bool
398 sev_enabled(void)
400 return sev_state ? true : false;
403 uint64_t
404 sev_get_me_mask(void)
406 return sev_state ? sev_state->me_mask : ~0;
409 uint32_t
410 sev_get_cbit_position(void)
412 return sev_state ? sev_state->cbitpos : 0;
415 uint32_t
416 sev_get_reduced_phys_bits(void)
418 return sev_state ? sev_state->reduced_phys_bits : 0;
421 SevInfo *
422 sev_get_info(void)
424 SevInfo *info;
426 info = g_new0(SevInfo, 1);
427 info->enabled = sev_state ? true : false;
429 if (info->enabled) {
430 info->api_major = sev_state->api_major;
431 info->api_minor = sev_state->api_minor;
432 info->build_id = sev_state->build_id;
433 info->policy = sev_state->policy;
434 info->state = sev_state->state;
435 info->handle = sev_state->handle;
438 return info;
441 static int
442 sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
443 size_t *cert_chain_len)
445 guchar *pdh_data = NULL;
446 guchar *cert_chain_data = NULL;
447 struct sev_user_data_pdh_cert_export export = {};
448 int err, r;
450 /* query the certificate length */
451 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
452 if (r < 0) {
453 if (err != SEV_RET_INVALID_LEN) {
454 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
455 r, err, fw_error_to_str(err));
456 return 1;
460 pdh_data = g_new(guchar, export.pdh_cert_len);
461 cert_chain_data = g_new(guchar, export.cert_chain_len);
462 export.pdh_cert_address = (unsigned long)pdh_data;
463 export.cert_chain_address = (unsigned long)cert_chain_data;
465 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
466 if (r < 0) {
467 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
468 r, err, fw_error_to_str(err));
469 goto e_free;
472 *pdh = pdh_data;
473 *pdh_len = export.pdh_cert_len;
474 *cert_chain = cert_chain_data;
475 *cert_chain_len = export.cert_chain_len;
476 return 0;
478 e_free:
479 g_free(pdh_data);
480 g_free(cert_chain_data);
481 return 1;
484 SevCapability *
485 sev_get_capabilities(void)
487 SevCapability *cap = NULL;
488 guchar *pdh_data = NULL;
489 guchar *cert_chain_data = NULL;
490 size_t pdh_len = 0, cert_chain_len = 0;
491 uint32_t ebx;
492 int fd;
494 fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
495 if (fd < 0) {
496 error_report("%s: Failed to open %s '%s'", __func__,
497 DEFAULT_SEV_DEVICE, strerror(errno));
498 return NULL;
501 if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
502 &cert_chain_data, &cert_chain_len)) {
503 goto out;
506 cap = g_new0(SevCapability, 1);
507 cap->pdh = g_base64_encode(pdh_data, pdh_len);
508 cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
510 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
511 cap->cbitpos = ebx & 0x3f;
514 * When SEV feature is enabled, we loose one bit in guest physical
515 * addressing.
517 cap->reduced_phys_bits = 1;
519 out:
520 g_free(pdh_data);
521 g_free(cert_chain_data);
522 close(fd);
523 return cap;
526 static int
527 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
529 gsize sz;
530 gchar *base64;
531 GError *error = NULL;
533 if (!g_file_get_contents(filename, &base64, &sz, &error)) {
534 error_report("failed to read '%s' (%s)", filename, error->message);
535 return -1;
538 *data = g_base64_decode(base64, len);
539 return 0;
542 static int
543 sev_launch_start(SEVState *s)
545 gsize sz;
546 int ret = 1;
547 int fw_error, rc;
548 QSevGuestInfo *sev = s->sev_info;
549 struct kvm_sev_launch_start *start;
550 guchar *session = NULL, *dh_cert = NULL;
552 start = g_new0(struct kvm_sev_launch_start, 1);
554 start->handle = object_property_get_int(OBJECT(sev), "handle",
555 &error_abort);
556 start->policy = object_property_get_int(OBJECT(sev), "policy",
557 &error_abort);
558 if (sev->session_file) {
559 if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
560 goto out;
562 start->session_uaddr = (unsigned long)session;
563 start->session_len = sz;
566 if (sev->dh_cert_file) {
567 if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
568 goto out;
570 start->dh_uaddr = (unsigned long)dh_cert;
571 start->dh_len = sz;
574 trace_kvm_sev_launch_start(start->policy, session, dh_cert);
575 rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
576 if (rc < 0) {
577 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
578 __func__, ret, fw_error, fw_error_to_str(fw_error));
579 goto out;
582 object_property_set_int(OBJECT(sev), start->handle, "handle",
583 &error_abort);
584 sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
585 s->handle = start->handle;
586 s->policy = start->policy;
587 ret = 0;
589 out:
590 g_free(start);
591 g_free(session);
592 g_free(dh_cert);
593 return ret;
596 static int
597 sev_launch_update_data(uint8_t *addr, uint64_t len)
599 int ret, fw_error;
600 struct kvm_sev_launch_update_data update;
602 if (!addr || !len) {
603 return 1;
606 update.uaddr = (__u64)(unsigned long)addr;
607 update.len = len;
608 trace_kvm_sev_launch_update_data(addr, len);
609 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
610 &update, &fw_error);
611 if (ret) {
612 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
613 __func__, ret, fw_error, fw_error_to_str(fw_error));
616 return ret;
619 static void
620 sev_launch_get_measure(Notifier *notifier, void *unused)
622 int ret, error;
623 guchar *data;
624 SEVState *s = sev_state;
625 struct kvm_sev_launch_measure *measurement;
627 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
628 return;
631 measurement = g_new0(struct kvm_sev_launch_measure, 1);
633 /* query the measurement blob length */
634 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
635 measurement, &error);
636 if (!measurement->len) {
637 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
638 __func__, ret, error, fw_error_to_str(errno));
639 goto free_measurement;
642 data = g_new0(guchar, measurement->len);
643 measurement->uaddr = (unsigned long)data;
645 /* get the measurement blob */
646 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
647 measurement, &error);
648 if (ret) {
649 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
650 __func__, ret, error, fw_error_to_str(errno));
651 goto free_data;
654 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
656 /* encode the measurement value and emit the event */
657 s->measurement = g_base64_encode(data, measurement->len);
658 trace_kvm_sev_launch_measurement(s->measurement);
660 free_data:
661 g_free(data);
662 free_measurement:
663 g_free(measurement);
666 char *
667 sev_get_launch_measurement(void)
669 if (sev_state &&
670 sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
671 return g_strdup(sev_state->measurement);
674 return NULL;
677 static Notifier sev_machine_done_notify = {
678 .notify = sev_launch_get_measure,
681 static void
682 sev_launch_finish(SEVState *s)
684 int ret, error;
685 Error *local_err = NULL;
687 trace_kvm_sev_launch_finish();
688 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
689 if (ret) {
690 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
691 __func__, ret, error, fw_error_to_str(error));
692 exit(1);
695 sev_set_guest_state(SEV_STATE_RUNNING);
697 /* add migration blocker */
698 error_setg(&sev_mig_blocker,
699 "SEV: Migration is not implemented");
700 ret = migrate_add_blocker(sev_mig_blocker, &local_err);
701 if (local_err) {
702 error_report_err(local_err);
703 error_free(sev_mig_blocker);
704 exit(1);
708 static void
709 sev_vm_state_change(void *opaque, int running, RunState state)
711 SEVState *s = opaque;
713 if (running) {
714 if (!sev_check_state(SEV_STATE_RUNNING)) {
715 sev_launch_finish(s);
720 void *
721 sev_guest_init(const char *id)
723 SEVState *s;
724 char *devname;
725 int ret, fw_error;
726 uint32_t ebx;
727 uint32_t host_cbitpos;
728 struct sev_user_data_status status = {};
730 sev_state = s = g_new0(SEVState, 1);
731 s->sev_info = lookup_sev_guest_info(id);
732 if (!s->sev_info) {
733 error_report("%s: '%s' is not a valid '%s' object",
734 __func__, id, TYPE_QSEV_GUEST_INFO);
735 goto err;
738 s->state = SEV_STATE_UNINIT;
740 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
741 host_cbitpos = ebx & 0x3f;
743 s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
744 if (host_cbitpos != s->cbitpos) {
745 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
746 __func__, host_cbitpos, s->cbitpos);
747 goto err;
750 s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
751 "reduced-phys-bits", NULL);
752 if (s->reduced_phys_bits < 1) {
753 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
754 "' requested '%d'", __func__, s->reduced_phys_bits);
755 goto err;
758 s->me_mask = ~(1UL << s->cbitpos);
760 devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
761 s->sev_fd = open(devname, O_RDWR);
762 if (s->sev_fd < 0) {
763 error_report("%s: Failed to open %s '%s'", __func__,
764 devname, strerror(errno));
766 g_free(devname);
767 if (s->sev_fd < 0) {
768 goto err;
771 ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
772 &fw_error);
773 if (ret) {
774 error_report("%s: failed to get platform status ret=%d"
775 "fw_error='%d: %s'", __func__, ret, fw_error,
776 fw_error_to_str(fw_error));
777 goto err;
779 s->build_id = status.build;
780 s->api_major = status.api_major;
781 s->api_minor = status.api_minor;
783 trace_kvm_sev_init();
784 ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
785 if (ret) {
786 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
787 __func__, ret, fw_error, fw_error_to_str(fw_error));
788 goto err;
791 ret = sev_launch_start(s);
792 if (ret) {
793 error_report("%s: failed to create encryption context", __func__);
794 goto err;
797 ram_block_notifier_add(&sev_ram_notifier);
798 qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
799 qemu_add_vm_change_state_handler(sev_vm_state_change, s);
801 return s;
802 err:
803 g_free(sev_state);
804 sev_state = NULL;
805 return NULL;
809 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
811 assert(handle);
813 /* if SEV is in update state then encrypt the data else do nothing */
814 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
815 return sev_launch_update_data(ptr, len);
818 return 0;
821 static void
822 sev_register_types(void)
824 type_register_static(&qsev_guest_info);
827 type_init(sev_register_types);