4 * Copyright Advanced Micro Devices 2016-2018
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 "qemu/module.h"
25 #include "sysemu/kvm.h"
27 #include "sysemu/sysemu.h"
29 #include "migration/blocker.h"
31 #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
32 #define DEFAULT_SEV_DEVICE "/dev/sev"
34 static SEVState *sev_state;
35 static Error *sev_mig_blocker;
37 static const char *const sev_fw_errlist[] = {
39 "Platform state is invalid",
40 "Guest state is invalid",
41 "Platform configuration is invalid",
43 "Platform is already owned",
44 "Certificate is invalid",
45 "Policy is not allowed",
46 "Guest is not active",
50 "Asid is already owned",
53 "DF_FLUSH is required",
54 "Guest handle is invalid",
59 "Feature not supported",
63 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
66 sev_ioctl(int fd, int cmd, void *data, int *error)
69 struct kvm_sev_cmd input;
71 memset(&input, 0x0, sizeof(input));
75 input.data = (__u64)(unsigned long)data;
77 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
87 sev_platform_ioctl(int fd, int cmd, void *data, int *error)
90 struct sev_issue_cmd arg;
93 arg.data = (unsigned long)data;
94 r = ioctl(fd, SEV_ISSUE_CMD, &arg);
103 fw_error_to_str(int code)
105 if (code < 0 || code >= SEV_FW_MAX_ERROR) {
106 return "unknown error";
109 return sev_fw_errlist[code];
113 sev_check_state(SevState state)
116 return sev_state->state == state ? true : false;
120 sev_set_guest_state(SevState new_state)
122 assert(new_state < SEV_STATE__MAX);
125 trace_kvm_sev_change_state(SevState_str(sev_state->state),
126 SevState_str(new_state));
127 sev_state->state = new_state;
131 sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
134 struct kvm_enc_region range;
139 * The RAM device presents a memory region that should be treated
140 * as IO region and should not be pinned.
142 mr = memory_region_from_host(host, &offset);
143 if (mr && memory_region_is_ram_device(mr)) {
147 range.addr = (__u64)(unsigned long)host;
150 trace_kvm_memcrypt_register_region(host, size);
151 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
153 error_report("%s: failed to register region (%p+%#zx) error '%s'",
154 __func__, host, size, strerror(errno));
160 sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
163 struct kvm_enc_region range;
168 * The RAM device presents a memory region that should be treated
169 * as IO region and should not have been pinned.
171 mr = memory_region_from_host(host, &offset);
172 if (mr && memory_region_is_ram_device(mr)) {
176 range.addr = (__u64)(unsigned long)host;
179 trace_kvm_memcrypt_unregister_region(host, size);
180 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
182 error_report("%s: failed to unregister region (%p+%#zx)",
183 __func__, host, size);
187 static struct RAMBlockNotifier sev_ram_notifier = {
188 .ram_block_added = sev_ram_block_added,
189 .ram_block_removed = sev_ram_block_removed,
193 qsev_guest_finalize(Object *obj)
198 qsev_guest_get_session_file(Object *obj, Error **errp)
200 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
202 return s->session_file ? g_strdup(s->session_file) : NULL;
206 qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
208 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
210 s->session_file = g_strdup(value);
214 qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
216 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
218 return g_strdup(s->dh_cert_file);
222 qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
224 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
226 s->dh_cert_file = g_strdup(value);
230 qsev_guest_get_sev_device(Object *obj, Error **errp)
232 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
234 return g_strdup(sev->sev_device);
238 qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
240 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
242 sev->sev_device = g_strdup(value);
246 qsev_guest_class_init(ObjectClass *oc, void *data)
248 object_class_property_add_str(oc, "sev-device",
249 qsev_guest_get_sev_device,
250 qsev_guest_set_sev_device,
252 object_class_property_set_description(oc, "sev-device",
253 "SEV device to use", NULL);
254 object_class_property_add_str(oc, "dh-cert-file",
255 qsev_guest_get_dh_cert_file,
256 qsev_guest_set_dh_cert_file,
258 object_class_property_set_description(oc, "dh-cert-file",
259 "guest owners DH certificate (encoded with base64)", NULL);
260 object_class_property_add_str(oc, "session-file",
261 qsev_guest_get_session_file,
262 qsev_guest_set_session_file,
264 object_class_property_set_description(oc, "session-file",
265 "guest owners session parameters (encoded with base64)", NULL);
269 qsev_guest_set_handle(Object *obj, Visitor *v, const char *name,
270 void *opaque, Error **errp)
272 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
275 visit_type_uint32(v, name, &value, errp);
280 qsev_guest_set_policy(Object *obj, Visitor *v, const char *name,
281 void *opaque, Error **errp)
283 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
286 visit_type_uint32(v, name, &value, errp);
291 qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name,
292 void *opaque, Error **errp)
294 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
297 visit_type_uint32(v, name, &value, errp);
298 sev->cbitpos = value;
302 qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
303 void *opaque, Error **errp)
305 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
308 visit_type_uint32(v, name, &value, errp);
309 sev->reduced_phys_bits = value;
313 qsev_guest_get_policy(Object *obj, Visitor *v, const char *name,
314 void *opaque, Error **errp)
317 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
320 visit_type_uint32(v, name, &value, errp);
324 qsev_guest_get_handle(Object *obj, Visitor *v, const char *name,
325 void *opaque, Error **errp)
328 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
331 visit_type_uint32(v, name, &value, errp);
335 qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name,
336 void *opaque, Error **errp)
339 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
341 value = sev->cbitpos;
342 visit_type_uint32(v, name, &value, errp);
346 qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
347 void *opaque, Error **errp)
350 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
352 value = sev->reduced_phys_bits;
353 visit_type_uint32(v, name, &value, errp);
357 qsev_guest_init(Object *obj)
359 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
361 sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
362 sev->policy = DEFAULT_GUEST_POLICY;
363 object_property_add(obj, "policy", "uint32", qsev_guest_get_policy,
364 qsev_guest_set_policy, NULL, NULL, NULL);
365 object_property_add(obj, "handle", "uint32", qsev_guest_get_handle,
366 qsev_guest_set_handle, NULL, NULL, NULL);
367 object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos,
368 qsev_guest_set_cbitpos, NULL, NULL, NULL);
369 object_property_add(obj, "reduced-phys-bits", "uint32",
370 qsev_guest_get_reduced_phys_bits,
371 qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL);
375 static const TypeInfo qsev_guest_info = {
376 .parent = TYPE_OBJECT,
377 .name = TYPE_QSEV_GUEST_INFO,
378 .instance_size = sizeof(QSevGuestInfo),
379 .instance_finalize = qsev_guest_finalize,
380 .class_size = sizeof(QSevGuestInfoClass),
381 .class_init = qsev_guest_class_init,
382 .instance_init = qsev_guest_init,
383 .interfaces = (InterfaceInfo[]) {
384 { TYPE_USER_CREATABLE },
389 static QSevGuestInfo *
390 lookup_sev_guest_info(const char *id)
395 obj = object_resolve_path_component(object_get_objects_root(), id);
400 info = (QSevGuestInfo *)
401 object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
412 return sev_state ? true : false;
416 sev_get_me_mask(void)
418 return sev_state ? sev_state->me_mask : ~0;
422 sev_get_cbit_position(void)
424 return sev_state ? sev_state->cbitpos : 0;
428 sev_get_reduced_phys_bits(void)
430 return sev_state ? sev_state->reduced_phys_bits : 0;
438 info = g_new0(SevInfo, 1);
439 info->enabled = sev_state ? true : false;
442 info->api_major = sev_state->api_major;
443 info->api_minor = sev_state->api_minor;
444 info->build_id = sev_state->build_id;
445 info->policy = sev_state->policy;
446 info->state = sev_state->state;
447 info->handle = sev_state->handle;
454 sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
455 size_t *cert_chain_len)
457 guchar *pdh_data = NULL;
458 guchar *cert_chain_data = NULL;
459 struct sev_user_data_pdh_cert_export export = {};
462 /* query the certificate length */
463 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
465 if (err != SEV_RET_INVALID_LEN) {
466 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
467 r, err, fw_error_to_str(err));
472 pdh_data = g_new(guchar, export.pdh_cert_len);
473 cert_chain_data = g_new(guchar, export.cert_chain_len);
474 export.pdh_cert_address = (unsigned long)pdh_data;
475 export.cert_chain_address = (unsigned long)cert_chain_data;
477 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
479 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
480 r, err, fw_error_to_str(err));
485 *pdh_len = export.pdh_cert_len;
486 *cert_chain = cert_chain_data;
487 *cert_chain_len = export.cert_chain_len;
492 g_free(cert_chain_data);
497 sev_get_capabilities(void)
499 SevCapability *cap = NULL;
500 guchar *pdh_data = NULL;
501 guchar *cert_chain_data = NULL;
502 size_t pdh_len = 0, cert_chain_len = 0;
506 fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
508 error_report("%s: Failed to open %s '%s'", __func__,
509 DEFAULT_SEV_DEVICE, strerror(errno));
513 if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
514 &cert_chain_data, &cert_chain_len)) {
518 cap = g_new0(SevCapability, 1);
519 cap->pdh = g_base64_encode(pdh_data, pdh_len);
520 cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
522 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
523 cap->cbitpos = ebx & 0x3f;
526 * When SEV feature is enabled, we loose one bit in guest physical
529 cap->reduced_phys_bits = 1;
533 g_free(cert_chain_data);
539 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
543 GError *error = NULL;
545 if (!g_file_get_contents(filename, &base64, &sz, &error)) {
546 error_report("failed to read '%s' (%s)", filename, error->message);
550 *data = g_base64_decode(base64, len);
555 sev_launch_start(SEVState *s)
560 QSevGuestInfo *sev = s->sev_info;
561 struct kvm_sev_launch_start *start;
562 guchar *session = NULL, *dh_cert = NULL;
564 start = g_new0(struct kvm_sev_launch_start, 1);
566 start->handle = object_property_get_int(OBJECT(sev), "handle",
568 start->policy = object_property_get_int(OBJECT(sev), "policy",
570 if (sev->session_file) {
571 if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
574 start->session_uaddr = (unsigned long)session;
575 start->session_len = sz;
578 if (sev->dh_cert_file) {
579 if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
582 start->dh_uaddr = (unsigned long)dh_cert;
586 trace_kvm_sev_launch_start(start->policy, session, dh_cert);
587 rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
589 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
590 __func__, ret, fw_error, fw_error_to_str(fw_error));
594 object_property_set_int(OBJECT(sev), start->handle, "handle",
596 sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
597 s->handle = start->handle;
598 s->policy = start->policy;
609 sev_launch_update_data(uint8_t *addr, uint64_t len)
612 struct kvm_sev_launch_update_data update;
618 update.uaddr = (__u64)(unsigned long)addr;
620 trace_kvm_sev_launch_update_data(addr, len);
621 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
624 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
625 __func__, ret, fw_error, fw_error_to_str(fw_error));
632 sev_launch_get_measure(Notifier *notifier, void *unused)
636 SEVState *s = sev_state;
637 struct kvm_sev_launch_measure *measurement;
639 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
643 measurement = g_new0(struct kvm_sev_launch_measure, 1);
645 /* query the measurement blob length */
646 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
647 measurement, &error);
648 if (!measurement->len) {
649 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
650 __func__, ret, error, fw_error_to_str(errno));
651 goto free_measurement;
654 data = g_new0(guchar, measurement->len);
655 measurement->uaddr = (unsigned long)data;
657 /* get the measurement blob */
658 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
659 measurement, &error);
661 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
662 __func__, ret, error, fw_error_to_str(errno));
666 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
668 /* encode the measurement value and emit the event */
669 s->measurement = g_base64_encode(data, measurement->len);
670 trace_kvm_sev_launch_measurement(s->measurement);
679 sev_get_launch_measurement(void)
682 sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
683 return g_strdup(sev_state->measurement);
689 static Notifier sev_machine_done_notify = {
690 .notify = sev_launch_get_measure,
694 sev_launch_finish(SEVState *s)
697 Error *local_err = NULL;
699 trace_kvm_sev_launch_finish();
700 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
702 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
703 __func__, ret, error, fw_error_to_str(error));
707 sev_set_guest_state(SEV_STATE_RUNNING);
709 /* add migration blocker */
710 error_setg(&sev_mig_blocker,
711 "SEV: Migration is not implemented");
712 ret = migrate_add_blocker(sev_mig_blocker, &local_err);
714 error_report_err(local_err);
715 error_free(sev_mig_blocker);
721 sev_vm_state_change(void *opaque, int running, RunState state)
723 SEVState *s = opaque;
726 if (!sev_check_state(SEV_STATE_RUNNING)) {
727 sev_launch_finish(s);
733 sev_guest_init(const char *id)
739 uint32_t host_cbitpos;
740 struct sev_user_data_status status = {};
742 sev_state = s = g_new0(SEVState, 1);
743 s->sev_info = lookup_sev_guest_info(id);
745 error_report("%s: '%s' is not a valid '%s' object",
746 __func__, id, TYPE_QSEV_GUEST_INFO);
750 s->state = SEV_STATE_UNINIT;
752 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
753 host_cbitpos = ebx & 0x3f;
755 s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
756 if (host_cbitpos != s->cbitpos) {
757 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
758 __func__, host_cbitpos, s->cbitpos);
762 s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
763 "reduced-phys-bits", NULL);
764 if (s->reduced_phys_bits < 1) {
765 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
766 "' requested '%d'", __func__, s->reduced_phys_bits);
770 s->me_mask = ~(1UL << s->cbitpos);
772 devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
773 s->sev_fd = open(devname, O_RDWR);
775 error_report("%s: Failed to open %s '%s'", __func__,
776 devname, strerror(errno));
783 ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
786 error_report("%s: failed to get platform status ret=%d"
787 "fw_error='%d: %s'", __func__, ret, fw_error,
788 fw_error_to_str(fw_error));
791 s->build_id = status.build;
792 s->api_major = status.api_major;
793 s->api_minor = status.api_minor;
795 trace_kvm_sev_init();
796 ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
798 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
799 __func__, ret, fw_error, fw_error_to_str(fw_error));
803 ret = sev_launch_start(s);
805 error_report("%s: failed to create encryption context", __func__);
809 ram_block_notifier_add(&sev_ram_notifier);
810 qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
811 qemu_add_vm_change_state_handler(sev_vm_state_change, s);
821 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
825 /* if SEV is in update state then encrypt the data else do nothing */
826 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
827 return sev_launch_update_data(ptr, len);
834 sev_register_types(void)
836 type_register_static(&qsev_guest_info);
839 type_init(sev_register_types);