]> Git Repo - qemu.git/blob - target/i386/sev.c
qom: Drop parameter @errp of object_property_add() & friends
[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 <[email protected]>
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     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)");
264 }
265
266 static void
267 qsev_guest_init(Object *obj)
268 {
269     QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
270
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);
282 }
283
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 },
295         { }
296     }
297 };
298
299 static QSevGuestInfo *
300 lookup_sev_guest_info(const char *id)
301 {
302     Object *obj;
303     QSevGuestInfo *info;
304
305     obj = object_resolve_path_component(object_get_objects_root(), id);
306     if (!obj) {
307         return NULL;
308     }
309
310     info = (QSevGuestInfo *)
311             object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
312     if (!info) {
313         return NULL;
314     }
315
316     return info;
317 }
318
319 bool
320 sev_enabled(void)
321 {
322     return sev_state ? true : false;
323 }
324
325 uint64_t
326 sev_get_me_mask(void)
327 {
328     return sev_state ? sev_state->me_mask : ~0;
329 }
330
331 uint32_t
332 sev_get_cbit_position(void)
333 {
334     return sev_state ? sev_state->cbitpos : 0;
335 }
336
337 uint32_t
338 sev_get_reduced_phys_bits(void)
339 {
340     return sev_state ? sev_state->reduced_phys_bits : 0;
341 }
342
343 SevInfo *
344 sev_get_info(void)
345 {
346     SevInfo *info;
347
348     info = g_new0(SevInfo, 1);
349     info->enabled = sev_state ? true : false;
350
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;
358     }
359
360     return info;
361 }
362
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)
366 {
367     guchar *pdh_data = NULL;
368     guchar *cert_chain_data = NULL;
369     struct sev_user_data_pdh_cert_export export = {};
370     int err, r;
371
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;
379         }
380     }
381
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;
386
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;
392     }
393
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;
399
400 e_free:
401     g_free(pdh_data);
402     g_free(cert_chain_data);
403     return 1;
404 }
405
406 SevCapability *
407 sev_get_capabilities(void)
408 {
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;
415
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;
421     }
422
423     if (sev_get_pdh_info(fd, &pdh_data, &pdh_len,
424                          &cert_chain_data, &cert_chain_len)) {
425         goto out;
426     }
427
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);
431
432     host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
433     cap->cbitpos = ebx & 0x3f;
434
435     /*
436      * When SEV feature is enabled, we loose one bit in guest physical
437      * addressing.
438      */
439     cap->reduced_phys_bits = 1;
440
441 out:
442     g_free(pdh_data);
443     g_free(cert_chain_data);
444     close(fd);
445     return cap;
446 }
447
448 static int
449 sev_read_file_base64(const char *filename, guchar **data, gsize *len)
450 {
451     gsize sz;
452     gchar *base64;
453     GError *error = NULL;
454
455     if (!g_file_get_contents(filename, &base64, &sz, &error)) {
456         error_report("failed to read '%s' (%s)", filename, error->message);
457         return -1;
458     }
459
460     *data = g_base64_decode(base64, len);
461     return 0;
462 }
463
464 static int
465 sev_launch_start(SEVState *s)
466 {
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;
473
474     start = g_new0(struct kvm_sev_launch_start, 1);
475
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;
483         }
484         start->session_uaddr = (unsigned long)session;
485         start->session_len = sz;
486     }
487
488     if (sev->dh_cert_file) {
489         if (sev_read_file_base64(sev->dh_cert_file, &dh_cert, &sz) < 0) {
490             goto out;
491         }
492         start->dh_uaddr = (unsigned long)dh_cert;
493         start->dh_len = sz;
494     }
495
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;
502     }
503
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;
510
511 out:
512     g_free(start);
513     g_free(session);
514     g_free(dh_cert);
515     return ret;
516 }
517
518 static int
519 sev_launch_update_data(uint8_t *addr, uint64_t len)
520 {
521     int ret, fw_error;
522     struct kvm_sev_launch_update_data update;
523
524     if (!addr || !len) {
525         return 1;
526     }
527
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));
536     }
537
538     return ret;
539 }
540
541 static void
542 sev_launch_get_measure(Notifier *notifier, void *unused)
543 {
544     int ret, error;
545     guchar *data;
546     SEVState *s = sev_state;
547     struct kvm_sev_launch_measure *measurement;
548
549     if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE)) {
550         return;
551     }
552
553     measurement = g_new0(struct kvm_sev_launch_measure, 1);
554
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;
562     }
563
564     data = g_new0(guchar, measurement->len);
565     measurement->uaddr = (unsigned long)data;
566
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;
574     }
575
576     sev_set_guest_state(SEV_STATE_LAUNCH_SECRET);
577
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);
581
582 free_data:
583     g_free(data);
584 free_measurement:
585     g_free(measurement);
586 }
587
588 char *
589 sev_get_launch_measurement(void)
590 {
591     if (sev_state &&
592         sev_state->state >= SEV_STATE_LAUNCH_SECRET) {
593         return g_strdup(sev_state->measurement);
594     }
595
596     return NULL;
597 }
598
599 static Notifier sev_machine_done_notify = {
600     .notify = sev_launch_get_measure,
601 };
602
603 static void
604 sev_launch_finish(SEVState *s)
605 {
606     int ret, error;
607     Error *local_err = NULL;
608
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);
615     }
616
617     sev_set_guest_state(SEV_STATE_RUNNING);
618
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);
627     }
628 }
629
630 static void
631 sev_vm_state_change(void *opaque, int running, RunState state)
632 {
633     SEVState *s = opaque;
634
635     if (running) {
636         if (!sev_check_state(SEV_STATE_RUNNING)) {
637             sev_launch_finish(s);
638         }
639     }
640 }
641
642 void *
643 sev_guest_init(const char *id)
644 {
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 = {};
651
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;
658     }
659
660     s->state = SEV_STATE_UNINIT;
661
662     host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
663     host_cbitpos = ebx & 0x3f;
664
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;
670     }
671
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;
678     }
679
680     s->me_mask = ~(1UL << s->cbitpos);
681
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));
687     }
688     g_free(devname);
689     if (s->sev_fd < 0) {
690         goto err;
691     }
692
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;
700     }
701     s->build_id = status.build;
702     s->api_major = status.api_major;
703     s->api_minor = status.api_minor;
704
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;
711     }
712
713     ret = sev_launch_start(s);
714     if (ret) {
715         error_report("%s: failed to create encryption context", __func__);
716         goto err;
717     }
718
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);
722
723     return s;
724 err:
725     g_free(sev_state);
726     sev_state = NULL;
727     return NULL;
728 }
729
730 int
731 sev_encrypt_data(void *handle, uint8_t *ptr, uint64_t len)
732 {
733     assert(handle);
734
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);
738     }
739
740     return 0;
741 }
742
743 static void
744 sev_register_types(void)
745 {
746     type_register_static(&qsev_guest_info);
747 }
748
749 type_init(sev_register_types);
This page took 0.076289 seconds and 4 git commands to generate.