sm501: Optimize small overlapping blits
[qemu/ar7.git] / target / i386 / sev.c
blob51cdbe5496729b307580cf4ccf2697ad925dcf22
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 object_class_property_set_description(oc, "sev-device",
253 "SEV device to use");
254 object_class_property_add_str(oc, "dh-cert-file",
255 qsev_guest_get_dh_cert_file,
256 qsev_guest_set_dh_cert_file);
257 object_class_property_set_description(oc, "dh-cert-file",
258 "guest owners DH certificate (encoded with base64)");
259 object_class_property_add_str(oc, "session-file",
260 qsev_guest_get_session_file,
261 qsev_guest_set_session_file);
262 object_class_property_set_description(oc, "session-file",
263 "guest owners session parameters (encoded with base64)");
266 static void
267 qsev_guest_init(Object *obj)
269 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
271 sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
272 sev->policy = DEFAULT_GUEST_POLICY;
273 object_property_add_uint32_ptr(obj, "policy", &sev->policy,
274 OBJ_PROP_FLAG_READWRITE);
275 object_property_add_uint32_ptr(obj, "handle", &sev->handle,
276 OBJ_PROP_FLAG_READWRITE);
277 object_property_add_uint32_ptr(obj, "cbitpos", &sev->cbitpos,
278 OBJ_PROP_FLAG_READWRITE);
279 object_property_add_uint32_ptr(obj, "reduced-phys-bits",
280 &sev->reduced_phys_bits,
281 OBJ_PROP_FLAG_READWRITE);
284 /* sev guest info */
285 static const TypeInfo qsev_guest_info = {
286 .parent = TYPE_OBJECT,
287 .name = TYPE_QSEV_GUEST_INFO,
288 .instance_size = sizeof(QSevGuestInfo),
289 .instance_finalize = qsev_guest_finalize,
290 .class_size = sizeof(QSevGuestInfoClass),
291 .class_init = qsev_guest_class_init,
292 .instance_init = qsev_guest_init,
293 .interfaces = (InterfaceInfo[]) {
294 { TYPE_USER_CREATABLE },
299 static QSevGuestInfo *
300 lookup_sev_guest_info(const char *id)
302 Object *obj;
303 QSevGuestInfo *info;
305 obj = object_resolve_path_component(object_get_objects_root(), id);
306 if (!obj) {
307 return NULL;
310 info = (QSevGuestInfo *)
311 object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
312 if (!info) {
313 return NULL;
316 return info;
319 bool
320 sev_enabled(void)
322 return sev_state ? true : false;
325 uint64_t
326 sev_get_me_mask(void)
328 return sev_state ? sev_state->me_mask : ~0;
331 uint32_t
332 sev_get_cbit_position(void)
334 return sev_state ? sev_state->cbitpos : 0;
337 uint32_t
338 sev_get_reduced_phys_bits(void)
340 return sev_state ? sev_state->reduced_phys_bits : 0;
343 SevInfo *
344 sev_get_info(void)
346 SevInfo *info;
348 info = g_new0(SevInfo, 1);
349 info->enabled = sev_state ? true : false;
351 if (info->enabled) {
352 info->api_major = sev_state->api_major;
353 info->api_minor = sev_state->api_minor;
354 info->build_id = sev_state->build_id;
355 info->policy = sev_state->policy;
356 info->state = sev_state->state;
357 info->handle = sev_state->handle;
360 return info;
363 static int
364 sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
365 size_t *cert_chain_len)
367 guchar *pdh_data = NULL;
368 guchar *cert_chain_data = NULL;
369 struct sev_user_data_pdh_cert_export export = {};
370 int err, r;
372 /* query the certificate length */
373 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
374 if (r < 0) {
375 if (err != SEV_RET_INVALID_LEN) {
376 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
377 r, err, fw_error_to_str(err));
378 return 1;
382 pdh_data = g_new(guchar, export.pdh_cert_len);
383 cert_chain_data = g_new(guchar, export.cert_chain_len);
384 export.pdh_cert_address = (unsigned long)pdh_data;
385 export.cert_chain_address = (unsigned long)cert_chain_data;
387 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
388 if (r < 0) {
389 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
390 r, err, fw_error_to_str(err));
391 goto e_free;
394 *pdh = pdh_data;
395 *pdh_len = export.pdh_cert_len;
396 *cert_chain = cert_chain_data;
397 *cert_chain_len = export.cert_chain_len;
398 return 0;
400 e_free:
401 g_free(pdh_data);
402 g_free(cert_chain_data);
403 return 1;
406 SevCapability *
407 sev_get_capabilities(void)
409 SevCapability *cap = NULL;
410 guchar *pdh_data = NULL;
411 guchar *cert_chain_data = NULL;
412 size_t pdh_len = 0, cert_chain_len = 0;
413 uint32_t ebx;
414 int fd;
416 fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
417 if (fd < 0) {
418 error_report("%s: Failed to open %s '%s'", __func__,
419 DEFAULT_SEV_DEVICE, strerror(errno));
420 return NULL;
423 if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
424 &cert_chain_data, &cert_chain_len)) {
425 goto out;
428 cap = g_new0(SevCapability, 1);
429 cap->pdh = g_base64_encode(pdh_data, pdh_len);
430 cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
432 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
433 cap->cbitpos = ebx & 0x3f;
436 * When SEV feature is enabled, we loose one bit in guest physical
437 * addressing.
439 cap->reduced_phys_bits = 1;
441 out:
442 g_free(pdh_data);
443 g_free(cert_chain_data);
444 close(fd);
445 return cap;
448 static int
449 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
451 gsize sz;
452 gchar *base64;
453 GError *error = NULL;
455 if (!g_file_get_contents(filename, &base64, &sz, &error)) {
456 error_report("failed to read '%s' (%s)", filename, error->message);
457 return -1;
460 *data = g_base64_decode(base64, len);
461 return 0;
464 static int
465 sev_launch_start(SEVState *s)
467 gsize sz;
468 int ret = 1;
469 int fw_error, rc;
470 QSevGuestInfo *sev = s->sev_info;
471 struct kvm_sev_launch_start *start;
472 guchar *session = NULL, *dh_cert = NULL;
474 start = g_new0(struct kvm_sev_launch_start, 1);
476 start->handle = object_property_get_int(OBJECT(sev), "handle",
477 &error_abort);
478 start->policy = object_property_get_int(OBJECT(sev), "policy",
479 &error_abort);
480 if (sev->session_file) {
481 if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
482 goto out;
484 start->session_uaddr = (unsigned long)session;
485 start->session_len = sz;
488 if (sev->dh_cert_file) {
489 if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
490 goto out;
492 start->dh_uaddr = (unsigned long)dh_cert;
493 start->dh_len = sz;
496 trace_kvm_sev_launch_start(start->policy, session, dh_cert);
497 rc = sev_ioctl(s->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
498 if (rc < 0) {
499 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
500 __func__, ret, fw_error, fw_error_to_str(fw_error));
501 goto out;
504 object_property_set_int(OBJECT(sev), start->handle, "handle",
505 &error_abort);
506 sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE);
507 s->handle = start->handle;
508 s->policy = start->policy;
509 ret = 0;
511 out:
512 g_free(start);
513 g_free(session);
514 g_free(dh_cert);
515 return ret;
518 static int
519 sev_launch_update_data(uint8_t *addr, uint64_t len)
521 int ret, fw_error;
522 struct kvm_sev_launch_update_data update;
524 if (!addr || !len) {
525 return 1;
528 update.uaddr = (__u64)(unsigned long)addr;
529 update.len = len;
530 trace_kvm_sev_launch_update_data(addr, len);
531 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
532 &update, &fw_error);
533 if (ret) {
534 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
535 __func__, ret, fw_error, fw_error_to_str(fw_error));
538 return ret;
541 static void
542 sev_launch_get_measure(Notifier *notifier, void *unused)
544 int ret, error;
545 guchar *data;
546 SEVState *s = sev_state;
547 struct kvm_sev_launch_measure *measurement;
549 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
550 return;
553 measurement = g_new0(struct kvm_sev_launch_measure, 1);
555 /* query the measurement blob length */
556 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
557 measurement, &error);
558 if (!measurement->len) {
559 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
560 __func__, ret, error, fw_error_to_str(errno));
561 goto free_measurement;
564 data = g_new0(guchar, measurement->len);
565 measurement->uaddr = (unsigned long)data;
567 /* get the measurement blob */
568 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_MEASURE,
569 measurement, &error);
570 if (ret) {
571 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
572 __func__, ret, error, fw_error_to_str(errno));
573 goto free_data;
576 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
578 /* encode the measurement value and emit the event */
579 s->measurement = g_base64_encode(data, measurement->len);
580 trace_kvm_sev_launch_measurement(s->measurement);
582 free_data:
583 g_free(data);
584 free_measurement:
585 g_free(measurement);
588 char *
589 sev_get_launch_measurement(void)
591 if (sev_state &&
592 sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
593 return g_strdup(sev_state->measurement);
596 return NULL;
599 static Notifier sev_machine_done_notify = {
600 .notify = sev_launch_get_measure,
603 static void
604 sev_launch_finish(SEVState *s)
606 int ret, error;
607 Error *local_err = NULL;
609 trace_kvm_sev_launch_finish();
610 ret = sev_ioctl(sev_state->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
611 if (ret) {
612 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
613 __func__, ret, error, fw_error_to_str(error));
614 exit(1);
617 sev_set_guest_state(SEV_STATE_RUNNING);
619 /* add migration blocker */
620 error_setg(&sev_mig_blocker,
621 "SEV: Migration is not implemented");
622 ret = migrate_add_blocker(sev_mig_blocker, &local_err);
623 if (local_err) {
624 error_report_err(local_err);
625 error_free(sev_mig_blocker);
626 exit(1);
630 static void
631 sev_vm_state_change(void *opaque, int running, RunState state)
633 SEVState *s = opaque;
635 if (running) {
636 if (!sev_check_state(SEV_STATE_RUNNING)) {
637 sev_launch_finish(s);
642 void *
643 sev_guest_init(const char *id)
645 SEVState *s;
646 char *devname;
647 int ret, fw_error;
648 uint32_t ebx;
649 uint32_t host_cbitpos;
650 struct sev_user_data_status status = {};
652 sev_state = s = g_new0(SEVState, 1);
653 s->sev_info = lookup_sev_guest_info(id);
654 if (!s->sev_info) {
655 error_report("%s: '%s' is not a valid '%s' object",
656 __func__, id, TYPE_QSEV_GUEST_INFO);
657 goto err;
660 s->state = SEV_STATE_UNINIT;
662 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
663 host_cbitpos = ebx & 0x3f;
665 s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
666 if (host_cbitpos != s->cbitpos) {
667 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
668 __func__, host_cbitpos, s->cbitpos);
669 goto err;
672 s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
673 "reduced-phys-bits", NULL);
674 if (s->reduced_phys_bits < 1) {
675 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
676 " requested '%d'", __func__, s->reduced_phys_bits);
677 goto err;
680 s->me_mask = ~(1UL << s->cbitpos);
682 devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
683 s->sev_fd = open(devname, O_RDWR);
684 if (s->sev_fd < 0) {
685 error_report("%s: Failed to open %s '%s'", __func__,
686 devname, strerror(errno));
688 g_free(devname);
689 if (s->sev_fd < 0) {
690 goto err;
693 ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
694 &fw_error);
695 if (ret) {
696 error_report("%s: failed to get platform status ret=%d "
697 "fw_error='%d: %s'", __func__, ret, fw_error,
698 fw_error_to_str(fw_error));
699 goto err;
701 s->build_id = status.build;
702 s->api_major = status.api_major;
703 s->api_minor = status.api_minor;
705 trace_kvm_sev_init();
706 ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
707 if (ret) {
708 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
709 __func__, ret, fw_error, fw_error_to_str(fw_error));
710 goto err;
713 ret = sev_launch_start(s);
714 if (ret) {
715 error_report("%s: failed to create encryption context", __func__);
716 goto err;
719 ram_block_notifier_add(&sev_ram_notifier);
720 qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
721 qemu_add_vm_change_state_handler(sev_vm_state_change, s);
723 return s;
724 err:
725 g_free(sev_state);
726 sev_state = NULL;
727 return NULL;
731 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
733 assert(handle);
735 /* if SEV is in update state then encrypt the data else do nothing */
736 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
737 return sev_launch_update_data(ptr, len);
740 return 0;
743 static void
744 sev_register_types(void)
746 type_register_static(&qsev_guest_info);
749 type_init(sev_register_types);