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