qom/object: Use common get/set uint helpers
[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 DEFAULT_GUEST_POLICY 0x1 /* disable debug */
33 #define DEFAULT_SEV_DEVICE "/dev/sev"
34
35 static SEVState *sev_state;
36 static Error *sev_mig_blocker;
37
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"
62 };
63
64 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
65
66 static int
67 sev_ioctl(int fd, int cmd, void *data, int *error)
68 {
69 int r;
70 struct kvm_sev_cmd input;
71
72 memset(&input, 0x0, sizeof(input));
73
74 input.id = cmd;
75 input.sev_fd = fd;
76 input.data = (__u64)(unsigned long)data;
77
78 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
79
80 if (error) {
81 *error = input.error;
82 }
83
84 return r;
85 }
86
87 static int
88 sev_platform_ioctl(int fd, int cmd, void *data, int *error)
89 {
90 int r;
91 struct sev_issue_cmd arg;
92
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;
98 }
99
100 return r;
101 }
102
103 static const char *
104 fw_error_to_str(int code)
105 {
106 if (code < 0 || code >= SEV_FW_MAX_ERROR) {
107 return "unknown error";
108 }
109
110 return sev_fw_errlist[code];
111 }
112
113 static bool
114 sev_check_state(SevState state)
115 {
116 assert(sev_state);
117 return sev_state->state == state ? true : false;
118 }
119
120 static void
121 sev_set_guest_state(SevState new_state)
122 {
123 assert(new_state < SEV_STATE__MAX);
124 assert(sev_state);
125
126 trace_kvm_sev_change_state(SevState_str(sev_state->state),
127 SevState_str(new_state));
128 sev_state->state = new_state;
129 }
130
131 static void
132 sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
133 {
134 int r;
135 struct kvm_enc_region range;
136 ram_addr_t offset;
137 MemoryRegion *mr;
138
139 /*
140 * The RAM device presents a memory region that should be treated
141 * as IO region and should not be pinned.
142 */
143 mr = memory_region_from_host(host, &offset);
144 if (mr && memory_region_is_ram_device(mr)) {
145 return;
146 }
147
148 range.addr = (__u64)(unsigned long)host;
149 range.size = size;
150
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);
157 }
158 }
159
160 static void
161 sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
162 {
163 int r;
164 struct kvm_enc_region range;
165 ram_addr_t offset;
166 MemoryRegion *mr;
167
168 /*
169 * The RAM device presents a memory region that should be treated
170 * as IO region and should not have been pinned.
171 */
172 mr = memory_region_from_host(host, &offset);
173 if (mr && memory_region_is_ram_device(mr)) {
174 return;
175 }
176
177 range.addr = (__u64)(unsigned long)host;
178 range.size = size;
179
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);
185 }
186 }
187
188 static struct RAMBlockNotifier sev_ram_notifier = {
189 .ram_block_added = sev_ram_block_added,
190 .ram_block_removed = sev_ram_block_removed,
191 };
192
193 static void
194 qsev_guest_finalize(Object *obj)
195 {
196 }
197
198 static char *
199 qsev_guest_get_session_file(Object *obj, Error **errp)
200 {
201 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
202
203 return s->session_file ? g_strdup(s->session_file) : NULL;
204 }
205
206 static void
207 qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
208 {
209 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
210
211 s->session_file = g_strdup(value);
212 }
213
214 static char *
215 qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
216 {
217 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
218
219 return g_strdup(s->dh_cert_file);
220 }
221
222 static void
223 qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
224 {
225 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
226
227 s->dh_cert_file = g_strdup(value);
228 }
229
230 static char *
231 qsev_guest_get_sev_device(Object *obj, Error **errp)
232 {
233 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
234
235 return g_strdup(sev->sev_device);
236 }
237
238 static void
239 qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
240 {
241 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
242
243 sev->sev_device = g_strdup(value);
244 }
245
246 static void
247 qsev_guest_class_init(ObjectClass *oc, void *data)
248 {
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);
267 }
268
269 static void
270 qsev_guest_init(Object *obj)
271 {
272 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
273
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);
285 }
286
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 },
298 { }
299 }
300 };
301
302 static QSevGuestInfo *
303 lookup_sev_guest_info(const char *id)
304 {
305 Object *obj;
306 QSevGuestInfo *info;
307
308 obj = object_resolve_path_component(object_get_objects_root(), id);
309 if (!obj) {
310 return NULL;
311 }
312
313 info = (QSevGuestInfo *)
314 object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
315 if (!info) {
316 return NULL;
317 }
318
319 return info;
320 }
321
322 bool
323 sev_enabled(void)
324 {
325 return sev_state ? true : false;
326 }
327
328 uint64_t
329 sev_get_me_mask(void)
330 {
331 return sev_state ? sev_state->me_mask : ~0;
332 }
333
334 uint32_t
335 sev_get_cbit_position(void)
336 {
337 return sev_state ? sev_state->cbitpos : 0;
338 }
339
340 uint32_t
341 sev_get_reduced_phys_bits(void)
342 {
343 return sev_state ? sev_state->reduced_phys_bits : 0;
344 }
345
346 SevInfo *
347 sev_get_info(void)
348 {
349 SevInfo *info;
350
351 info = g_new0(SevInfo, 1);
352 info->enabled = sev_state ? true : false;
353
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;
361 }
362
363 return info;
364 }
365
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)
369 {
370 guchar *pdh_data = NULL;
371 guchar *cert_chain_data = NULL;
372 struct sev_user_data_pdh_cert_export export = {};
373 int err, r;
374
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;
382 }
383 }
384
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;
389
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;
395 }
396
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;
402
403 e_free:
404 g_free(pdh_data);
405 g_free(cert_chain_data);
406 return 1;
407 }
408
409 SevCapability *
410 sev_get_capabilities(void)
411 {
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;
418
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;
424 }
425
426 if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
427 &cert_chain_data, &cert_chain_len)) {
428 goto out;
429 }
430
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);
434
435 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
436 cap->cbitpos = ebx & 0x3f;
437
438 /*
439 * When SEV feature is enabled, we loose one bit in guest physical
440 * addressing.
441 */
442 cap->reduced_phys_bits = 1;
443
444 out:
445 g_free(pdh_data);
446 g_free(cert_chain_data);
447 close(fd);
448 return cap;
449 }
450
451 static int
452 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
453 {
454 gsize sz;
455 gchar *base64;
456 GError *error = NULL;
457
458 if (!g_file_get_contents(filename, &base64, &sz, &error)) {
459 error_report("failed to read '%s' (%s)", filename, error->message);
460 return -1;
461 }
462
463 *data = g_base64_decode(base64, len);
464 return 0;
465 }
466
467 static int
468 sev_launch_start(SEVState *s)
469 {
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;
476
477 start = g_new0(struct kvm_sev_launch_start, 1);
478
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;
486 }
487 start->session_uaddr = (unsigned long)session;
488 start->session_len = sz;
489 }
490
491 if (sev->dh_cert_file) {
492 if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
493 goto out;
494 }
495 start->dh_uaddr = (unsigned long)dh_cert;
496 start->dh_len = sz;
497 }
498
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;
505 }
506
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;
513
514 out:
515 g_free(start);
516 g_free(session);
517 g_free(dh_cert);
518 return ret;
519 }
520
521 static int
522 sev_launch_update_data(uint8_t *addr, uint64_t len)
523 {
524 int ret, fw_error;
525 struct kvm_sev_launch_update_data update;
526
527 if (!addr || !len) {
528 return 1;
529 }
530
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));
539 }
540
541 return ret;
542 }
543
544 static void
545 sev_launch_get_measure(Notifier *notifier, void *unused)
546 {
547 int ret, error;
548 guchar *data;
549 SEVState *s = sev_state;
550 struct kvm_sev_launch_measure *measurement;
551
552 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
553 return;
554 }
555
556 measurement = g_new0(struct kvm_sev_launch_measure, 1);
557
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;
565 }
566
567 data = g_new0(guchar, measurement->len);
568 measurement->uaddr = (unsigned long)data;
569
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;
577 }
578
579 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
580
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);
584
585 free_data:
586 g_free(data);
587 free_measurement:
588 g_free(measurement);
589 }
590
591 char *
592 sev_get_launch_measurement(void)
593 {
594 if (sev_state &&
595 sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
596 return g_strdup(sev_state->measurement);
597 }
598
599 return NULL;
600 }
601
602 static Notifier sev_machine_done_notify = {
603 .notify = sev_launch_get_measure,
604 };
605
606 static void
607 sev_launch_finish(SEVState *s)
608 {
609 int ret, error;
610 Error *local_err = NULL;
611
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);
618 }
619
620 sev_set_guest_state(SEV_STATE_RUNNING);
621
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);
630 }
631 }
632
633 static void
634 sev_vm_state_change(void *opaque, int running, RunState state)
635 {
636 SEVState *s = opaque;
637
638 if (running) {
639 if (!sev_check_state(SEV_STATE_RUNNING)) {
640 sev_launch_finish(s);
641 }
642 }
643 }
644
645 void *
646 sev_guest_init(const char *id)
647 {
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 = {};
654
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;
661 }
662
663 s->state = SEV_STATE_UNINIT;
664
665 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
666 host_cbitpos = ebx & 0x3f;
667
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;
673 }
674
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;
681 }
682
683 s->me_mask = ~(1UL << s->cbitpos);
684
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));
690 }
691 g_free(devname);
692 if (s->sev_fd < 0) {
693 goto err;
694 }
695
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;
703 }
704 s->build_id = status.build;
705 s->api_major = status.api_major;
706 s->api_minor = status.api_minor;
707
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;
714 }
715
716 ret = sev_launch_start(s);
717 if (ret) {
718 error_report("%s: failed to create encryption context", __func__);
719 goto err;
720 }
721
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);
725
726 return s;
727 err:
728 g_free(sev_state);
729 sev_state = NULL;
730 return NULL;
731 }
732
733 int
734 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
735 {
736 assert(handle);
737
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);
741 }
742
743 return 0;
744 }
745
746 static void
747 sev_register_types(void)
748 {
749 type_register_static(&qsev_guest_info);
750 }
751
752 type_init(sev_register_types);