dsoundaudio: dsound_get_buffer_in should honor *size
[qemu/ar7.git] / target / i386 / sev.c
blob846018a12d281ad7aa61acd9471abe053dc0e94b
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 "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"
32 #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
33 #define DEFAULT_SEV_DEVICE "/dev/sev"
35 static SEVState *sev_state;
36 static Error *sev_mig_blocker;
38 static 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"
64 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
66 static int
67 sev_ioctl(int fd, int cmd, void *data, int *error)
69 int r;
70 struct kvm_sev_cmd input;
72 memset(&input, 0x0, sizeof(input));
74 input.id = cmd;
75 input.sev_fd = fd;
76 input.data = (__u64)(unsigned long)data;
78 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
80 if (error) {
81 *error = input.error;
84 return r;
87 static int
88 sev_platform_ioctl(int fd, int cmd, void *data, int *error)
90 int r;
91 struct sev_issue_cmd arg;
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;
100 return r;
103 static const char *
104 fw_error_to_str(int code)
106 if (code < 0 || code >= SEV_FW_MAX_ERROR) {
107 return "unknown error";
110 return sev_fw_errlist[code];
113 static bool
114 sev_check_state(SevState state)
116 assert(sev_state);
117 return sev_state->state == state ? true : false;
120 static void
121 sev_set_guest_state(SevState new_state)
123 assert(new_state < SEV_STATE__MAX);
124 assert(sev_state);
126 trace_kvm_sev_change_state(SevState_str(sev_state->state),
127 SevState_str(new_state));
128 sev_state->state = new_state;
131 static void
132 sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
134 int r;
135 struct kvm_enc_region range;
136 ram_addr_t offset;
137 MemoryRegion *mr;
140 * The RAM device presents a memory region that should be treated
141 * as IO region and should not be pinned.
143 mr = memory_region_from_host(host, &offset);
144 if (mr && memory_region_is_ram_device(mr)) {
145 return;
148 range.addr = (__u64)(unsigned long)host;
149 range.size = size;
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);
160 static void
161 sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
163 int r;
164 struct kvm_enc_region range;
165 ram_addr_t offset;
166 MemoryRegion *mr;
169 * The RAM device presents a memory region that should be treated
170 * as IO region and should not have been pinned.
172 mr = memory_region_from_host(host, &offset);
173 if (mr && memory_region_is_ram_device(mr)) {
174 return;
177 range.addr = (__u64)(unsigned long)host;
178 range.size = size;
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);
188 static struct RAMBlockNotifier sev_ram_notifier = {
189 .ram_block_added = sev_ram_block_added,
190 .ram_block_removed = sev_ram_block_removed,
193 static void
194 qsev_guest_finalize(Object *obj)
198 static char *
199 qsev_guest_get_session_file(Object *obj, Error **errp)
201 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
203 return s->session_file ? g_strdup(s->session_file) : NULL;
206 static void
207 qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
209 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
211 s->session_file = g_strdup(value);
214 static char *
215 qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
217 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
219 return g_strdup(s->dh_cert_file);
222 static void
223 qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
225 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
227 s->dh_cert_file = g_strdup(value);
230 static char *
231 qsev_guest_get_sev_device(Object *obj, Error **errp)
233 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
235 return g_strdup(sev->sev_device);
238 static void
239 qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
241 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
243 sev->sev_device = g_strdup(value);
246 static void
247 qsev_guest_class_init(ObjectClass *oc, void *data)
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);
269 static void
270 qsev_guest_init(Object *obj)
272 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
274 sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
275 sev->policy = DEFAULT_GUEST_POLICY;
276 object_property_add_uint32_ptr(obj, "policy", &sev->policy,
277 OBJ_PROP_FLAG_READWRITE, NULL);
278 object_property_add_uint32_ptr(obj, "handle", &sev->handle,
279 OBJ_PROP_FLAG_READWRITE, NULL);
280 object_property_add_uint32_ptr(obj, "cbitpos", &sev->cbitpos,
281 OBJ_PROP_FLAG_READWRITE, NULL);
282 object_property_add_uint32_ptr(obj, "reduced-phys-bits",
283 &sev->reduced_phys_bits,
284 OBJ_PROP_FLAG_READWRITE, NULL);
287 /* sev guest info */
288 static const TypeInfo qsev_guest_info = {
289 .parent = TYPE_OBJECT,
290 .name = TYPE_QSEV_GUEST_INFO,
291 .instance_size = sizeof(QSevGuestInfo),
292 .instance_finalize = qsev_guest_finalize,
293 .class_size = sizeof(QSevGuestInfoClass),
294 .class_init = qsev_guest_class_init,
295 .instance_init = qsev_guest_init,
296 .interfaces = (InterfaceInfo[]) {
297 { TYPE_USER_CREATABLE },
302 static QSevGuestInfo *
303 lookup_sev_guest_info(const char *id)
305 Object *obj;
306 QSevGuestInfo *info;
308 obj = object_resolve_path_component(object_get_objects_root(), id);
309 if (!obj) {
310 return NULL;
313 info = (QSevGuestInfo *)
314 object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
315 if (!info) {
316 return NULL;
319 return info;
322 bool
323 sev_enabled(void)
325 return sev_state ? true : false;
328 uint64_t
329 sev_get_me_mask(void)
331 return sev_state ? sev_state->me_mask : ~0;
334 uint32_t
335 sev_get_cbit_position(void)
337 return sev_state ? sev_state->cbitpos : 0;
340 uint32_t
341 sev_get_reduced_phys_bits(void)
343 return sev_state ? sev_state->reduced_phys_bits : 0;
346 SevInfo *
347 sev_get_info(void)
349 SevInfo *info;
351 info = g_new0(SevInfo, 1);
352 info->enabled = sev_state ? true : false;
354 if (info->enabled) {
355 info->api_major = sev_state->api_major;
356 info->api_minor = sev_state->api_minor;
357 info->build_id = sev_state->build_id;
358 info->policy = sev_state->policy;
359 info->state = sev_state->state;
360 info->handle = sev_state->handle;
363 return info;
366 static int
367 sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
368 size_t *cert_chain_len)
370 guchar *pdh_data = NULL;
371 guchar *cert_chain_data = NULL;
372 struct sev_user_data_pdh_cert_export export = {};
373 int err, r;
375 /* query the certificate length */
376 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
377 if (r < 0) {
378 if (err != SEV_RET_INVALID_LEN) {
379 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
380 r, err, fw_error_to_str(err));
381 return 1;
385 pdh_data = g_new(guchar, export.pdh_cert_len);
386 cert_chain_data = g_new(guchar, export.cert_chain_len);
387 export.pdh_cert_address = (unsigned long)pdh_data;
388 export.cert_chain_address = (unsigned long)cert_chain_data;
390 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
391 if (r < 0) {
392 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
393 r, err, fw_error_to_str(err));
394 goto e_free;
397 *pdh = pdh_data;
398 *pdh_len = export.pdh_cert_len;
399 *cert_chain = cert_chain_data;
400 *cert_chain_len = export.cert_chain_len;
401 return 0;
403 e_free:
404 g_free(pdh_data);
405 g_free(cert_chain_data);
406 return 1;
409 SevCapability *
410 sev_get_capabilities(void)
412 SevCapability *cap = NULL;
413 guchar *pdh_data = NULL;
414 guchar *cert_chain_data = NULL;
415 size_t pdh_len = 0, cert_chain_len = 0;
416 uint32_t ebx;
417 int fd;
419 fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
420 if (fd < 0) {
421 error_report("%s: Failed to open %s '%s'", __func__,
422 DEFAULT_SEV_DEVICE, strerror(errno));
423 return NULL;
426 if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
427 &cert_chain_data, &cert_chain_len)) {
428 goto out;
431 cap = g_new0(SevCapability, 1);
432 cap->pdh = g_base64_encode(pdh_data, pdh_len);
433 cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
435 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
436 cap->cbitpos = ebx & 0x3f;
439 * When SEV feature is enabled, we loose one bit in guest physical
440 * addressing.
442 cap->reduced_phys_bits = 1;
444 out:
445 g_free(pdh_data);
446 g_free(cert_chain_data);
447 close(fd);
448 return cap;
451 static int
452 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
454 gsize sz;
455 gchar *base64;
456 GError *error = NULL;
458 if (!g_file_get_contents(filename, &base64, &sz, &error)) {
459 error_report("failed to read '%s' (%s)", filename, error->message);
460 return -1;
463 *data = g_base64_decode(base64, len);
464 return 0;
467 static int
468 sev_launch_start(SEVState *s)
470 gsize sz;
471 int ret = 1;
472 int fw_error, rc;
473 QSevGuestInfo *sev = s->sev_info;
474 struct kvm_sev_launch_start *start;
475 guchar *session = NULL, *dh_cert = NULL;
477 start = g_new0(struct kvm_sev_launch_start, 1);
479 start->handle = object_property_get_int(OBJECT(sev), "handle",
480 &error_abort);
481 start->policy = object_property_get_int(OBJECT(sev), "policy",
482 &error_abort);
483 if (sev->session_file) {
484 if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
485 goto out;
487 start->session_uaddr = (unsigned long)session;
488 start->session_len = sz;
491 if (sev->dh_cert_file) {
492 if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
493 goto out;
495 start->dh_uaddr = (unsigned long)dh_cert;
496 start->dh_len = sz;
499 trace_kvm_sev_launch_start(start->policy, session, dh_cert);
500 rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
501 if (rc < 0) {
502 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
503 __func__, ret, fw_error, fw_error_to_str(fw_error));
504 goto out;
507 object_property_set_int(OBJECT(sev), start->handle, "handle",
508 &error_abort);
509 sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
510 s->handle = start->handle;
511 s->policy = start->policy;
512 ret = 0;
514 out:
515 g_free(start);
516 g_free(session);
517 g_free(dh_cert);
518 return ret;
521 static int
522 sev_launch_update_data(uint8_t *addr, uint64_t len)
524 int ret, fw_error;
525 struct kvm_sev_launch_update_data update;
527 if (!addr || !len) {
528 return 1;
531 update.uaddr = (__u64)(unsigned long)addr;
532 update.len = len;
533 trace_kvm_sev_launch_update_data(addr, len);
534 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
535 &update, &fw_error);
536 if (ret) {
537 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
538 __func__, ret, fw_error, fw_error_to_str(fw_error));
541 return ret;
544 static void
545 sev_launch_get_measure(Notifier *notifier, void *unused)
547 int ret, error;
548 guchar *data;
549 SEVState *s = sev_state;
550 struct kvm_sev_launch_measure *measurement;
552 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
553 return;
556 measurement = g_new0(struct kvm_sev_launch_measure, 1);
558 /* query the measurement blob length */
559 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
560 measurement, &error);
561 if (!measurement->len) {
562 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
563 __func__, ret, error, fw_error_to_str(errno));
564 goto free_measurement;
567 data = g_new0(guchar, measurement->len);
568 measurement->uaddr = (unsigned long)data;
570 /* get the measurement blob */
571 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
572 measurement, &error);
573 if (ret) {
574 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
575 __func__, ret, error, fw_error_to_str(errno));
576 goto free_data;
579 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
581 /* encode the measurement value and emit the event */
582 s->measurement = g_base64_encode(data, measurement->len);
583 trace_kvm_sev_launch_measurement(s->measurement);
585 free_data:
586 g_free(data);
587 free_measurement:
588 g_free(measurement);
591 char *
592 sev_get_launch_measurement(void)
594 if (sev_state &&
595 sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
596 return g_strdup(sev_state->measurement);
599 return NULL;
602 static Notifier sev_machine_done_notify = {
603 .notify = sev_launch_get_measure,
606 static void
607 sev_launch_finish(SEVState *s)
609 int ret, error;
610 Error *local_err = NULL;
612 trace_kvm_sev_launch_finish();
613 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
614 if (ret) {
615 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
616 __func__, ret, error, fw_error_to_str(error));
617 exit(1);
620 sev_set_guest_state(SEV_STATE_RUNNING);
622 /* add migration blocker */
623 error_setg(&sev_mig_blocker,
624 "SEV: Migration is not implemented");
625 ret = migrate_add_blocker(sev_mig_blocker, &local_err);
626 if (local_err) {
627 error_report_err(local_err);
628 error_free(sev_mig_blocker);
629 exit(1);
633 static void
634 sev_vm_state_change(void *opaque, int running, RunState state)
636 SEVState *s = opaque;
638 if (running) {
639 if (!sev_check_state(SEV_STATE_RUNNING)) {
640 sev_launch_finish(s);
645 void *
646 sev_guest_init(const char *id)
648 SEVState *s;
649 char *devname;
650 int ret, fw_error;
651 uint32_t ebx;
652 uint32_t host_cbitpos;
653 struct sev_user_data_status status = {};
655 sev_state = s = g_new0(SEVState, 1);
656 s->sev_info = lookup_sev_guest_info(id);
657 if (!s->sev_info) {
658 error_report("%s: '%s' is not a valid '%s' object",
659 __func__, id, TYPE_QSEV_GUEST_INFO);
660 goto err;
663 s->state = SEV_STATE_UNINIT;
665 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
666 host_cbitpos = ebx & 0x3f;
668 s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
669 if (host_cbitpos != s->cbitpos) {
670 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
671 __func__, host_cbitpos, s->cbitpos);
672 goto err;
675 s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
676 "reduced-phys-bits", NULL);
677 if (s->reduced_phys_bits < 1) {
678 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
679 " requested '%d'", __func__, s->reduced_phys_bits);
680 goto err;
683 s->me_mask = ~(1UL << s->cbitpos);
685 devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
686 s->sev_fd = open(devname, O_RDWR);
687 if (s->sev_fd < 0) {
688 error_report("%s: Failed to open %s '%s'", __func__,
689 devname, strerror(errno));
691 g_free(devname);
692 if (s->sev_fd < 0) {
693 goto err;
696 ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
697 &fw_error);
698 if (ret) {
699 error_report("%s: failed to get platform status ret=%d "
700 "fw_error='%d: %s'", __func__, ret, fw_error,
701 fw_error_to_str(fw_error));
702 goto err;
704 s->build_id = status.build;
705 s->api_major = status.api_major;
706 s->api_minor = status.api_minor;
708 trace_kvm_sev_init();
709 ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
710 if (ret) {
711 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
712 __func__, ret, fw_error, fw_error_to_str(fw_error));
713 goto err;
716 ret = sev_launch_start(s);
717 if (ret) {
718 error_report("%s: failed to create encryption context", __func__);
719 goto err;
722 ram_block_notifier_add(&sev_ram_notifier);
723 qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
724 qemu_add_vm_change_state_handler(sev_vm_state_change, s);
726 return s;
727 err:
728 g_free(sev_state);
729 sev_state = NULL;
730 return NULL;
734 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
736 assert(handle);
738 /* if SEV is in update state then encrypt the data else do nothing */
739 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
740 return sev_launch_update_data(ptr, len);
743 return 0;
746 static void
747 sev_register_types(void)
749 type_register_static(&qsev_guest_info);
752 type_init(sev_register_types);