]> git.proxmox.com Git - mirror_qemu.git/blame - target/i386/sev.c
sev/i386: register the guest memory range which may contain encrypted data
[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
d8575c6c
BS
14#include <linux/kvm.h>
15#include <linux/psp-sev.h>
16
17#include <sys/ioctl.h>
18
a9b4942f
BS
19#include "qemu/osdep.h"
20#include "qapi/error.h"
21#include "qom/object_interfaces.h"
22#include "qemu/base64.h"
23#include "sysemu/kvm.h"
24#include "sev_i386.h"
25#include "sysemu/sysemu.h"
d8575c6c 26#include "trace.h"
a9b4942f
BS
27
28#define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
29#define DEFAULT_SEV_DEVICE "/dev/sev"
30
d8575c6c
BS
31static SEVState *sev_state;
32
33static const char *const sev_fw_errlist[] = {
34 "",
35 "Platform state is invalid",
36 "Guest state is invalid",
37 "Platform configuration is invalid",
38 "Buffer too small",
39 "Platform is already owned",
40 "Certificate is invalid",
41 "Policy is not allowed",
42 "Guest is not active",
43 "Invalid address",
44 "Bad signature",
45 "Bad measurement",
46 "Asid is already owned",
47 "Invalid ASID",
48 "WBINVD is required",
49 "DF_FLUSH is required",
50 "Guest handle is invalid",
51 "Invalid command",
52 "Guest is active",
53 "Hardware error",
54 "Hardware unsafe",
55 "Feature not supported",
56 "Invalid parameter"
57};
58
59#define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
60
61static int
62sev_ioctl(int fd, int cmd, void *data, int *error)
63{
64 int r;
65 struct kvm_sev_cmd input;
66
67 memset(&input, 0x0, sizeof(input));
68
69 input.id = cmd;
70 input.sev_fd = fd;
71 input.data = (__u64)(unsigned long)data;
72
73 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &input);
74
75 if (error) {
76 *error = input.error;
77 }
78
79 return r;
80}
81
82static int
83sev_platform_ioctl(int fd, int cmd, void *data, int *error)
84{
85 int r;
86 struct sev_issue_cmd arg;
87
88 arg.cmd = cmd;
89 arg.data = (unsigned long)data;
90 r = ioctl(fd, SEV_ISSUE_CMD, &arg);
91 if (error) {
92 *error = arg.error;
93 }
94
95 return r;
96}
97
98static const char *
99fw_error_to_str(int code)
100{
101 if (code < 0 || code >= SEV_FW_MAX_ERROR) {
102 return "unknown error";
103 }
104
105 return sev_fw_errlist[code];
106}
107
2b308e44
BS
108static void
109sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size)
110{
111 int r;
112 struct kvm_enc_region range;
113
114 range.addr = (__u64)(unsigned long)host;
115 range.size = size;
116
117 trace_kvm_memcrypt_register_region(host, size);
118 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range);
119 if (r) {
120 error_report("%s: failed to register region (%p+%#zx) error '%s'",
121 __func__, host, size, strerror(errno));
122 exit(1);
123 }
124}
125
126static void
127sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size)
128{
129 int r;
130 struct kvm_enc_region range;
131
132 range.addr = (__u64)(unsigned long)host;
133 range.size = size;
134
135 trace_kvm_memcrypt_unregister_region(host, size);
136 r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range);
137 if (r) {
138 error_report("%s: failed to unregister region (%p+%#zx)",
139 __func__, host, size);
140 }
141}
142
143static struct RAMBlockNotifier sev_ram_notifier = {
144 .ram_block_added = sev_ram_block_added,
145 .ram_block_removed = sev_ram_block_removed,
146};
147
a9b4942f
BS
148static void
149qsev_guest_finalize(Object *obj)
150{
151}
152
153static char *
154qsev_guest_get_session_file(Object *obj, Error **errp)
155{
156 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
157
158 return s->session_file ? g_strdup(s->session_file) : NULL;
159}
160
161static void
162qsev_guest_set_session_file(Object *obj, const char *value, Error **errp)
163{
164 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
165
166 s->session_file = g_strdup(value);
167}
168
169static char *
170qsev_guest_get_dh_cert_file(Object *obj, Error **errp)
171{
172 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
173
174 return g_strdup(s->dh_cert_file);
175}
176
177static void
178qsev_guest_set_dh_cert_file(Object *obj, const char *value, Error **errp)
179{
180 QSevGuestInfo *s = QSEV_GUEST_INFO(obj);
181
182 s->dh_cert_file = g_strdup(value);
183}
184
185static char *
186qsev_guest_get_sev_device(Object *obj, Error **errp)
187{
188 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
189
190 return g_strdup(sev->sev_device);
191}
192
193static void
194qsev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
195{
196 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
197
198 sev->sev_device = g_strdup(value);
199}
200
201static void
202qsev_guest_class_init(ObjectClass *oc, void *data)
203{
204 object_class_property_add_str(oc, "sev-device",
205 qsev_guest_get_sev_device,
206 qsev_guest_set_sev_device,
207 NULL);
208 object_class_property_set_description(oc, "sev-device",
209 "SEV device to use", NULL);
210 object_class_property_add_str(oc, "dh-cert-file",
211 qsev_guest_get_dh_cert_file,
212 qsev_guest_set_dh_cert_file,
213 NULL);
214 object_class_property_set_description(oc, "dh-cert-file",
215 "guest owners DH certificate (encoded with base64)", NULL);
216 object_class_property_add_str(oc, "session-file",
217 qsev_guest_get_session_file,
218 qsev_guest_set_session_file,
219 NULL);
220 object_class_property_set_description(oc, "session-file",
221 "guest owners session parameters (encoded with base64)", NULL);
222}
223
224static void
225qsev_guest_set_handle(Object *obj, Visitor *v, const char *name,
226 void *opaque, Error **errp)
227{
228 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
229 uint32_t value;
230
231 visit_type_uint32(v, name, &value, errp);
232 sev->handle = value;
233}
234
235static void
236qsev_guest_set_policy(Object *obj, Visitor *v, const char *name,
237 void *opaque, Error **errp)
238{
239 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
240 uint32_t value;
241
242 visit_type_uint32(v, name, &value, errp);
243 sev->policy = value;
244}
245
246static void
247qsev_guest_set_cbitpos(Object *obj, Visitor *v, const char *name,
248 void *opaque, Error **errp)
249{
250 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
251 uint32_t value;
252
253 visit_type_uint32(v, name, &value, errp);
254 sev->cbitpos = value;
255}
256
257static void
258qsev_guest_set_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
259 void *opaque, Error **errp)
260{
261 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
262 uint32_t value;
263
264 visit_type_uint32(v, name, &value, errp);
265 sev->reduced_phys_bits = value;
266}
267
268static void
269qsev_guest_get_policy(Object *obj, Visitor *v, const char *name,
270 void *opaque, Error **errp)
271{
272 uint32_t value;
273 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
274
275 value = sev->policy;
276 visit_type_uint32(v, name, &value, errp);
277}
278
279static void
280qsev_guest_get_handle(Object *obj, Visitor *v, const char *name,
281 void *opaque, Error **errp)
282{
283 uint32_t value;
284 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
285
286 value = sev->handle;
287 visit_type_uint32(v, name, &value, errp);
288}
289
290static void
291qsev_guest_get_cbitpos(Object *obj, Visitor *v, const char *name,
292 void *opaque, Error **errp)
293{
294 uint32_t value;
295 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
296
297 value = sev->cbitpos;
298 visit_type_uint32(v, name, &value, errp);
299}
300
301static void
302qsev_guest_get_reduced_phys_bits(Object *obj, Visitor *v, const char *name,
303 void *opaque, Error **errp)
304{
305 uint32_t value;
306 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
307
308 value = sev->reduced_phys_bits;
309 visit_type_uint32(v, name, &value, errp);
310}
311
312static void
313qsev_guest_init(Object *obj)
314{
315 QSevGuestInfo *sev = QSEV_GUEST_INFO(obj);
316
317 sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
318 sev->policy = DEFAULT_GUEST_POLICY;
319 object_property_add(obj, "policy", "uint32", qsev_guest_get_policy,
320 qsev_guest_set_policy, NULL, NULL, NULL);
321 object_property_add(obj, "handle", "uint32", qsev_guest_get_handle,
322 qsev_guest_set_handle, NULL, NULL, NULL);
323 object_property_add(obj, "cbitpos", "uint32", qsev_guest_get_cbitpos,
324 qsev_guest_set_cbitpos, NULL, NULL, NULL);
325 object_property_add(obj, "reduced-phys-bits", "uint32",
326 qsev_guest_get_reduced_phys_bits,
327 qsev_guest_set_reduced_phys_bits, NULL, NULL, NULL);
328}
329
330/* sev guest info */
331static const TypeInfo qsev_guest_info = {
332 .parent = TYPE_OBJECT,
333 .name = TYPE_QSEV_GUEST_INFO,
334 .instance_size = sizeof(QSevGuestInfo),
335 .instance_finalize = qsev_guest_finalize,
336 .class_size = sizeof(QSevGuestInfoClass),
337 .class_init = qsev_guest_class_init,
338 .instance_init = qsev_guest_init,
339 .interfaces = (InterfaceInfo[]) {
340 { TYPE_USER_CREATABLE },
341 { }
342 }
343};
344
d8575c6c
BS
345static QSevGuestInfo *
346lookup_sev_guest_info(const char *id)
347{
348 Object *obj;
349 QSevGuestInfo *info;
350
351 obj = object_resolve_path_component(object_get_objects_root(), id);
352 if (!obj) {
353 return NULL;
354 }
355
356 info = (QSevGuestInfo *)
357 object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO);
358 if (!info) {
359 return NULL;
360 }
361
362 return info;
363}
364
365bool
366sev_enabled(void)
367{
368 return sev_state ? true : false;
369}
370
371uint64_t
372sev_get_me_mask(void)
373{
374 return sev_state ? sev_state->me_mask : ~0;
375}
376
377uint32_t
378sev_get_cbit_position(void)
379{
380 return sev_state ? sev_state->cbitpos : 0;
381}
382
383uint32_t
384sev_get_reduced_phys_bits(void)
385{
386 return sev_state ? sev_state->reduced_phys_bits : 0;
387}
388
389SevInfo *
390sev_get_info(void)
391{
392 SevInfo *info;
393
394 info = g_new0(SevInfo, 1);
395 info->enabled = sev_state ? true : false;
396
397 if (info->enabled) {
398 info->api_major = sev_state->api_major;
399 info->api_minor = sev_state->api_minor;
400 info->build_id = sev_state->build_id;
401 info->policy = sev_state->policy;
402 info->state = sev_state->state;
403 info->handle = sev_state->handle;
404 }
405
406 return info;
407}
408
409void *
410sev_guest_init(const char *id)
411{
412 SEVState *s;
413 char *devname;
414 int ret, fw_error;
415 uint32_t ebx;
416 uint32_t host_cbitpos;
417 struct sev_user_data_status status = {};
418
419 s = g_new0(SEVState, 1);
420 s->sev_info = lookup_sev_guest_info(id);
421 if (!s->sev_info) {
422 error_report("%s: '%s' is not a valid '%s' object",
423 __func__, id, TYPE_QSEV_GUEST_INFO);
424 goto err;
425 }
426
427 sev_state = s;
428 s->state = SEV_STATE_UNINIT;
429
430 host_cpuid(0x8000001F, 0, NULL, &ebx, NULL, NULL);
431 host_cbitpos = ebx & 0x3f;
432
433 s->cbitpos = object_property_get_int(OBJECT(s->sev_info), "cbitpos", NULL);
434 if (host_cbitpos != s->cbitpos) {
435 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
436 __func__, host_cbitpos, s->cbitpos);
437 goto err;
438 }
439
440 s->reduced_phys_bits = object_property_get_int(OBJECT(s->sev_info),
441 "reduced-phys-bits", NULL);
442 if (s->reduced_phys_bits < 1) {
443 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
444 "' requested '%d'", __func__, s->reduced_phys_bits);
445 goto err;
446 }
447
448 s->me_mask = ~(1UL << s->cbitpos);
449
450 devname = object_property_get_str(OBJECT(s->sev_info), "sev-device", NULL);
451 s->sev_fd = open(devname, O_RDWR);
452 if (s->sev_fd < 0) {
453 error_report("%s: Failed to open %s '%s'", __func__,
454 devname, strerror(errno));
455 goto err;
456 }
457 g_free(devname);
458
459 ret = sev_platform_ioctl(s->sev_fd, SEV_PLATFORM_STATUS, &status,
460 &fw_error);
461 if (ret) {
462 error_report("%s: failed to get platform status ret=%d"
463 "fw_error='%d: %s'", __func__, ret, fw_error,
464 fw_error_to_str(fw_error));
465 goto err;
466 }
467 s->build_id = status.build;
468 s->api_major = status.api_major;
469 s->api_minor = status.api_minor;
470
471 trace_kvm_sev_init();
472 ret = sev_ioctl(s->sev_fd, KVM_SEV_INIT, NULL, &fw_error);
473 if (ret) {
474 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
475 __func__, ret, fw_error, fw_error_to_str(fw_error));
476 goto err;
477 }
478
2b308e44
BS
479 ram_block_notifier_add(&sev_ram_notifier);
480
d8575c6c
BS
481 return s;
482err:
483 g_free(sev_state);
484 sev_state = NULL;
485 return NULL;
486}
487
a9b4942f
BS
488static void
489sev_register_types(void)
490{
491 type_register_static(&qsev_guest_info);
492}
493
494type_init(sev_register_types);