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