]> git.proxmox.com Git - mirror_qemu.git/blob - target/i386/sev.c
target/riscv: vector widening floating-point reduction instructions
[mirror_qemu.git] / target / i386 / sev.c
1 /*
2 * QEMU SEV support
3 *
4 * Copyright Advanced Micro Devices 2016-2018
5 *
6 * Author:
7 * Brijesh Singh <brijesh.singh@amd.com>
8 *
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.
11 *
12 */
13
14 #include "qemu/osdep.h"
15
16 #include <linux/kvm.h>
17 #include <linux/psp-sev.h>
18
19 #include <sys/ioctl.h>
20
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"
31
32 #define TYPE_SEV_GUEST "sev-guest"
33 #define SEV_GUEST(obj) \
34 OBJECT_CHECK(SevGuestState, (obj), TYPE_SEV_GUEST)
35
36 typedef struct SevGuestState SevGuestState;
37
38 /**
39 * SevGuestState:
40 *
41 * The SevGuestState object is used for creating and managing a SEV
42 * guest.
43 *
44 * # $QEMU \
45 * -object sev-guest,id=sev0 \
46 * -machine ...,memory-encryption=sev0
47 */
48 struct SevGuestState {
49 Object parent_obj;
50
51 /* configuration parameters */
52 char *sev_device;
53 uint32_t policy;
54 char *dh_cert_file;
55 char *session_file;
56 uint32_t cbitpos;
57 uint32_t reduced_phys_bits;
58
59 /* runtime state */
60 uint32_t handle;
61 uint8_t api_major;
62 uint8_t api_minor;
63 uint8_t build_id;
64 uint64_t me_mask;
65 int sev_fd;
66 SevState state;
67 gchar *measurement;
68 };
69
70 #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
71 #define DEFAULT_SEV_DEVICE "/dev/sev"
72
73 static SevGuestState *sev_guest;
74 static Error *sev_mig_blocker;
75
76 static const char *const sev_fw_errlist[] = {
77 "",
78 "Platform state is invalid",
79 "Guest state is invalid",
80 "Platform configuration is invalid",
81 "Buffer too small",
82 "Platform is already owned",
83 "Certificate is invalid",
84 "Policy is not allowed",
85 "Guest is not active",
86 "Invalid address",
87 "Bad signature",
88 "Bad measurement",
89 "Asid is already owned",
90 "Invalid ASID",
91 "WBINVD is required",
92 "DF_FLUSH is required",
93 "Guest handle is invalid",
94 "Invalid command",
95 "Guest is active",
96 "Hardware error",
97 "Hardware unsafe",
98 "Feature not supported",
99 "Invalid parameter"
100 };
101
102 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
103
104 static int
105 sev_ioctl(int fd, int cmd, void *data, int *error)
106 {
107 int r;
108 struct kvm_sev_cmd input;
109
110 memset(&input, 0x0, sizeof(input));
111
112 input.id = cmd;
113 input.sev_fd = fd;
114 input.data = (__u64)(unsigned long)data;
115
116 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
117
118 if (error) {
119 *error = input.error;
120 }
121
122 return r;
123 }
124
125 static int
126 sev_platform_ioctl(int fd, int cmd, void *data, int *error)
127 {
128 int r;
129 struct sev_issue_cmd arg;
130
131 arg.cmd = cmd;
132 arg.data = (unsigned long)data;
133 r = ioctl(fd, SEV_ISSUE_CMD, &arg);
134 if (error) {
135 *error = arg.error;
136 }
137
138 return r;
139 }
140
141 static const char *
142 fw_error_to_str(int code)
143 {
144 if (code < 0 || code >= SEV_FW_MAX_ERROR) {
145 return "unknown error";
146 }
147
148 return sev_fw_errlist[code];
149 }
150
151 static bool
152 sev_check_state(const SevGuestState *sev, SevState state)
153 {
154 assert(sev);
155 return sev->state == state ? true : false;
156 }
157
158 static void
159 sev_set_guest_state(SevGuestState *sev, SevState new_state)
160 {
161 assert(new_state < SEV_STATE__MAX);
162 assert(sev);
163
164 trace_kvm_sev_change_state(SevState_str(sev->state),
165 SevState_str(new_state));
166 sev->state = new_state;
167 }
168
169 static void
170 sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
171 {
172 int r;
173 struct kvm_enc_region range;
174 ram_addr_t offset;
175 MemoryRegion *mr;
176
177 /*
178 * The RAM device presents a memory region that should be treated
179 * as IO region and should not be pinned.
180 */
181 mr = memory_region_from_host(host, &offset);
182 if (mr && memory_region_is_ram_device(mr)) {
183 return;
184 }
185
186 range.addr = (__u64)(unsigned long)host;
187 range.size = size;
188
189 trace_kvm_memcrypt_register_region(host, size);
190 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
191 if (r) {
192 error_report("%s: failed to register region (%p+%#zx) error '%s'",
193 __func__, host, size, strerror(errno));
194 exit(1);
195 }
196 }
197
198 static void
199 sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
200 {
201 int r;
202 struct kvm_enc_region range;
203 ram_addr_t offset;
204 MemoryRegion *mr;
205
206 /*
207 * The RAM device presents a memory region that should be treated
208 * as IO region and should not have been pinned.
209 */
210 mr = memory_region_from_host(host, &offset);
211 if (mr && memory_region_is_ram_device(mr)) {
212 return;
213 }
214
215 range.addr = (__u64)(unsigned long)host;
216 range.size = size;
217
218 trace_kvm_memcrypt_unregister_region(host, size);
219 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
220 if (r) {
221 error_report("%s: failed to unregister region (%p+%#zx)",
222 __func__, host, size);
223 }
224 }
225
226 static struct RAMBlockNotifier sev_ram_notifier = {
227 .ram_block_added = sev_ram_block_added,
228 .ram_block_removed = sev_ram_block_removed,
229 };
230
231 static void
232 sev_guest_finalize(Object *obj)
233 {
234 }
235
236 static char *
237 sev_guest_get_session_file(Object *obj, Error **errp)
238 {
239 SevGuestState *s = SEV_GUEST(obj);
240
241 return s->session_file ? g_strdup(s->session_file) : NULL;
242 }
243
244 static void
245 sev_guest_set_session_file(Object *obj, const char *value, Error **errp)
246 {
247 SevGuestState *s = SEV_GUEST(obj);
248
249 s->session_file = g_strdup(value);
250 }
251
252 static char *
253 sev_guest_get_dh_cert_file(Object *obj, Error **errp)
254 {
255 SevGuestState *s = SEV_GUEST(obj);
256
257 return g_strdup(s->dh_cert_file);
258 }
259
260 static void
261 sev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
262 {
263 SevGuestState *s = SEV_GUEST(obj);
264
265 s->dh_cert_file = g_strdup(value);
266 }
267
268 static char *
269 sev_guest_get_sev_device(Object *obj, Error **errp)
270 {
271 SevGuestState *sev = SEV_GUEST(obj);
272
273 return g_strdup(sev->sev_device);
274 }
275
276 static void
277 sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
278 {
279 SevGuestState *sev = SEV_GUEST(obj);
280
281 sev->sev_device = g_strdup(value);
282 }
283
284 static void
285 sev_guest_class_init(ObjectClass *oc, void *data)
286 {
287 object_class_property_add_str(oc, "sev-device",
288 sev_guest_get_sev_device,
289 sev_guest_set_sev_device);
290 object_class_property_set_description(oc, "sev-device",
291 "SEV device to use");
292 object_class_property_add_str(oc, "dh-cert-file",
293 sev_guest_get_dh_cert_file,
294 sev_guest_set_dh_cert_file);
295 object_class_property_set_description(oc, "dh-cert-file",
296 "guest owners DH certificate (encoded with base64)");
297 object_class_property_add_str(oc, "session-file",
298 sev_guest_get_session_file,
299 sev_guest_set_session_file);
300 object_class_property_set_description(oc, "session-file",
301 "guest owners session parameters (encoded with base64)");
302 }
303
304 static void
305 sev_guest_instance_init(Object *obj)
306 {
307 SevGuestState *sev = SEV_GUEST(obj);
308
309 sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
310 sev->policy = DEFAULT_GUEST_POLICY;
311 object_property_add_uint32_ptr(obj, "policy", &sev->policy,
312 OBJ_PROP_FLAG_READWRITE);
313 object_property_add_uint32_ptr(obj, "handle", &sev->handle,
314 OBJ_PROP_FLAG_READWRITE);
315 object_property_add_uint32_ptr(obj, "cbitpos", &sev->cbitpos,
316 OBJ_PROP_FLAG_READWRITE);
317 object_property_add_uint32_ptr(obj, "reduced-phys-bits",
318 &sev->reduced_phys_bits,
319 OBJ_PROP_FLAG_READWRITE);
320 }
321
322 /* sev guest info */
323 static const TypeInfo sev_guest_info = {
324 .parent = TYPE_OBJECT,
325 .name = TYPE_SEV_GUEST,
326 .instance_size = sizeof(SevGuestState),
327 .instance_finalize = sev_guest_finalize,
328 .class_init = sev_guest_class_init,
329 .instance_init = sev_guest_instance_init,
330 .interfaces = (InterfaceInfo[]) {
331 { TYPE_USER_CREATABLE },
332 { }
333 }
334 };
335
336 static SevGuestState *
337 lookup_sev_guest_info(const char *id)
338 {
339 Object *obj;
340 SevGuestState *info;
341
342 obj = object_resolve_path_component(object_get_objects_root(), id);
343 if (!obj) {
344 return NULL;
345 }
346
347 info = (SevGuestState *)
348 object_dynamic_cast(obj, TYPE_SEV_GUEST);
349 if (!info) {
350 return NULL;
351 }
352
353 return info;
354 }
355
356 bool
357 sev_enabled(void)
358 {
359 return !!sev_guest;
360 }
361
362 uint64_t
363 sev_get_me_mask(void)
364 {
365 return sev_guest ? sev_guest->me_mask : ~0;
366 }
367
368 uint32_t
369 sev_get_cbit_position(void)
370 {
371 return sev_guest ? sev_guest->cbitpos : 0;
372 }
373
374 uint32_t
375 sev_get_reduced_phys_bits(void)
376 {
377 return sev_guest ? sev_guest->reduced_phys_bits : 0;
378 }
379
380 SevInfo *
381 sev_get_info(void)
382 {
383 SevInfo *info;
384
385 info = g_new0(SevInfo, 1);
386 info->enabled = sev_enabled();
387
388 if (info->enabled) {
389 info->api_major = sev_guest->api_major;
390 info->api_minor = sev_guest->api_minor;
391 info->build_id = sev_guest->build_id;
392 info->policy = sev_guest->policy;
393 info->state = sev_guest->state;
394 info->handle = sev_guest->handle;
395 }
396
397 return info;
398 }
399
400 static int
401 sev_get_pdh_info(int fd, guchar **pdh, size_t *pdh_len, guchar **cert_chain,
402 size_t *cert_chain_len)
403 {
404 guchar *pdh_data = NULL;
405 guchar *cert_chain_data = NULL;
406 struct sev_user_data_pdh_cert_export export = {};
407 int err, r;
408
409 /* query the certificate length */
410 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
411 if (r < 0) {
412 if (err != SEV_RET_INVALID_LEN) {
413 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
414 r, err, fw_error_to_str(err));
415 return 1;
416 }
417 }
418
419 pdh_data = g_new(guchar, export.pdh_cert_len);
420 cert_chain_data = g_new(guchar, export.cert_chain_len);
421 export.pdh_cert_address = (unsigned long)pdh_data;
422 export.cert_chain_address = (unsigned long)cert_chain_data;
423
424 r = sev_platform_ioctl(fd, SEV_PDH_CERT_EXPORT, &export, &err);
425 if (r < 0) {
426 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
427 r, err, fw_error_to_str(err));
428 goto e_free;
429 }
430
431 *pdh = pdh_data;
432 *pdh_len = export.pdh_cert_len;
433 *cert_chain = cert_chain_data;
434 *cert_chain_len = export.cert_chain_len;
435 return 0;
436
437 e_free:
438 g_free(pdh_data);
439 g_free(cert_chain_data);
440 return 1;
441 }
442
443 SevCapability *
444 sev_get_capabilities(void)
445 {
446 SevCapability *cap = NULL;
447 guchar *pdh_data = NULL;
448 guchar *cert_chain_data = NULL;
449 size_t pdh_len = 0, cert_chain_len = 0;
450 uint32_t ebx;
451 int fd;
452
453 fd = open(DEFAULT_SEV_DEVICE, O_RDWR);
454 if (fd < 0) {
455 error_report("%s: Failed to open %s '%s'", __func__,
456 DEFAULT_SEV_DEVICE, strerror(errno));
457 return NULL;
458 }
459
460 if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
461 &cert_chain_data, &cert_chain_len)) {
462 goto out;
463 }
464
465 cap = g_new0(SevCapability, 1);
466 cap->pdh = g_base64_encode(pdh_data, pdh_len);
467 cap->cert_chain = g_base64_encode(cert_chain_data, cert_chain_len);
468
469 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
470 cap->cbitpos = ebx & 0x3f;
471
472 /*
473 * When SEV feature is enabled, we loose one bit in guest physical
474 * addressing.
475 */
476 cap->reduced_phys_bits = 1;
477
478 out:
479 g_free(pdh_data);
480 g_free(cert_chain_data);
481 close(fd);
482 return cap;
483 }
484
485 static int
486 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
487 {
488 gsize sz;
489 gchar *base64;
490 GError *error = NULL;
491
492 if (!g_file_get_contents(filename, &base64, &sz, &error)) {
493 error_report("failed to read '%s' (%s)", filename, error->message);
494 return -1;
495 }
496
497 *data = g_base64_decode(base64, len);
498 return 0;
499 }
500
501 static int
502 sev_launch_start(SevGuestState *sev)
503 {
504 gsize sz;
505 int ret = 1;
506 int fw_error, rc;
507 struct kvm_sev_launch_start *start;
508 guchar *session = NULL, *dh_cert = NULL;
509
510 start = g_new0(struct kvm_sev_launch_start, 1);
511
512 start->handle = sev->handle;
513 start->policy = sev->policy;
514 if (sev->session_file) {
515 if (sev_read_file_base64(sev->session_file, &session, &sz) < 0) {
516 goto out;
517 }
518 start->session_uaddr = (unsigned long)session;
519 start->session_len = sz;
520 }
521
522 if (sev->dh_cert_file) {
523 if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
524 goto out;
525 }
526 start->dh_uaddr = (unsigned long)dh_cert;
527 start->dh_len = sz;
528 }
529
530 trace_kvm_sev_launch_start(start->policy, session, dh_cert);
531 rc = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_START, start, &fw_error);
532 if (rc < 0) {
533 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
534 __func__, ret, fw_error, fw_error_to_str(fw_error));
535 goto out;
536 }
537
538 sev_set_guest_state(sev, SEV_STATE_LAUNCH_UPDATE);
539 sev->handle = start->handle;
540 ret = 0;
541
542 out:
543 g_free(start);
544 g_free(session);
545 g_free(dh_cert);
546 return ret;
547 }
548
549 static int
550 sev_launch_update_data(SevGuestState *sev, uint8_t *addr, uint64_t len)
551 {
552 int ret, fw_error;
553 struct kvm_sev_launch_update_data update;
554
555 if (!addr || !len) {
556 return 1;
557 }
558
559 update.uaddr = (__u64)(unsigned long)addr;
560 update.len = len;
561 trace_kvm_sev_launch_update_data(addr, len);
562 ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_UPDATE_DATA,
563 &update, &fw_error);
564 if (ret) {
565 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
566 __func__, ret, fw_error, fw_error_to_str(fw_error));
567 }
568
569 return ret;
570 }
571
572 static void
573 sev_launch_get_measure(Notifier *notifier, void *unused)
574 {
575 SevGuestState *sev = sev_guest;
576 int ret, error;
577 guchar *data;
578 struct kvm_sev_launch_measure *measurement;
579
580 if (!sev_check_state(sev, SEV_STATE_LAUNCH_UPDATE)) {
581 return;
582 }
583
584 measurement = g_new0(struct kvm_sev_launch_measure, 1);
585
586 /* query the measurement blob length */
587 ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_MEASURE,
588 measurement, &error);
589 if (!measurement->len) {
590 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
591 __func__, ret, error, fw_error_to_str(errno));
592 goto free_measurement;
593 }
594
595 data = g_new0(guchar, measurement->len);
596 measurement->uaddr = (unsigned long)data;
597
598 /* get the measurement blob */
599 ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_MEASURE,
600 measurement, &error);
601 if (ret) {
602 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
603 __func__, ret, error, fw_error_to_str(errno));
604 goto free_data;
605 }
606
607 sev_set_guest_state(sev, SEV_STATE_LAUNCH_SECRET);
608
609 /* encode the measurement value and emit the event */
610 sev->measurement = g_base64_encode(data, measurement->len);
611 trace_kvm_sev_launch_measurement(sev->measurement);
612
613 free_data:
614 g_free(data);
615 free_measurement:
616 g_free(measurement);
617 }
618
619 char *
620 sev_get_launch_measurement(void)
621 {
622 if (sev_guest &&
623 sev_guest->state >= SEV_STATE_LAUNCH_SECRET) {
624 return g_strdup(sev_guest->measurement);
625 }
626
627 return NULL;
628 }
629
630 static Notifier sev_machine_done_notify = {
631 .notify = sev_launch_get_measure,
632 };
633
634 static void
635 sev_launch_finish(SevGuestState *sev)
636 {
637 int ret, error;
638 Error *local_err = NULL;
639
640 trace_kvm_sev_launch_finish();
641 ret = sev_ioctl(sev->sev_fd, KVM_SEV_LAUNCH_FINISH, 0, &error);
642 if (ret) {
643 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
644 __func__, ret, error, fw_error_to_str(error));
645 exit(1);
646 }
647
648 sev_set_guest_state(sev, SEV_STATE_RUNNING);
649
650 /* add migration blocker */
651 error_setg(&sev_mig_blocker,
652 "SEV: Migration is not implemented");
653 ret = migrate_add_blocker(sev_mig_blocker, &local_err);
654 if (local_err) {
655 error_report_err(local_err);
656 error_free(sev_mig_blocker);
657 exit(1);
658 }
659 }
660
661 static void
662 sev_vm_state_change(void *opaque, int running, RunState state)
663 {
664 SevGuestState *sev = opaque;
665
666 if (running) {
667 if (!sev_check_state(sev, SEV_STATE_RUNNING)) {
668 sev_launch_finish(sev);
669 }
670 }
671 }
672
673 void *
674 sev_guest_init(const char *id)
675 {
676 SevGuestState *sev;
677 char *devname;
678 int ret, fw_error;
679 uint32_t ebx;
680 uint32_t host_cbitpos;
681 struct sev_user_data_status status = {};
682
683 sev = lookup_sev_guest_info(id);
684 if (!sev) {
685 error_report("%s: '%s' is not a valid '%s' object",
686 __func__, id, TYPE_SEV_GUEST);
687 goto err;
688 }
689
690 sev_guest = sev;
691 sev->state = SEV_STATE_UNINIT;
692
693 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
694 host_cbitpos = ebx & 0x3f;
695
696 if (host_cbitpos != sev->cbitpos) {
697 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
698 __func__, host_cbitpos, sev->cbitpos);
699 goto err;
700 }
701
702 if (sev->reduced_phys_bits < 1) {
703 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
704 " requested '%d'", __func__, sev->reduced_phys_bits);
705 goto err;
706 }
707
708 sev->me_mask = ~(1UL << sev->cbitpos);
709
710 devname = object_property_get_str(OBJECT(sev), "sev-device", NULL);
711 sev->sev_fd = open(devname, O_RDWR);
712 if (sev->sev_fd < 0) {
713 error_report("%s: Failed to open %s '%s'", __func__,
714 devname, strerror(errno));
715 }
716 g_free(devname);
717 if (sev->sev_fd < 0) {
718 goto err;
719 }
720
721 ret = sev_platform_ioctl(sev->sev_fd, SEV_PLATFORM_STATUS, &status,
722 &fw_error);
723 if (ret) {
724 error_report("%s: failed to get platform status ret=%d "
725 "fw_error='%d: %s'", __func__, ret, fw_error,
726 fw_error_to_str(fw_error));
727 goto err;
728 }
729 sev->build_id = status.build;
730 sev->api_major = status.api_major;
731 sev->api_minor = status.api_minor;
732
733 trace_kvm_sev_init();
734 ret = sev_ioctl(sev->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
735 if (ret) {
736 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
737 __func__, ret, fw_error, fw_error_to_str(fw_error));
738 goto err;
739 }
740
741 ret = sev_launch_start(sev);
742 if (ret) {
743 error_report("%s: failed to create encryption context", __func__);
744 goto err;
745 }
746
747 ram_block_notifier_add(&sev_ram_notifier);
748 qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
749 qemu_add_vm_change_state_handler(sev_vm_state_change, sev);
750
751 return sev;
752 err:
753 sev_guest = NULL;
754 return NULL;
755 }
756
757 int
758 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
759 {
760 SevGuestState *sev = handle;
761
762 assert(sev);
763
764 /* if SEV is in update state then encrypt the data else do nothing */
765 if (sev_check_state(sev, SEV_STATE_LAUNCH_UPDATE)) {
766 return sev_launch_update_data(sev, ptr, len);
767 }
768
769 return 0;
770 }
771
772 static void
773 sev_register_types(void)
774 {
775 type_register_static(&sev_guest_info);
776 }
777
778 type_init(sev_register_types);