4 * Copyright Advanced Micro Devices 2016-2018
7 * Brijesh Singh <brijesh.singh@amd.com>
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.
14 #include <linux/kvm.h>
15 #include <linux/psp-sev.h>
17 #include <sys/ioctl.h>
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"
25 #include "sysemu/sysemu.h"
28 #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
29 #define DEFAULT_SEV_DEVICE "/dev/sev"
31 static SEVState
*sev_state
;
33 static const char *const sev_fw_errlist
[] = {
35 "Platform state is invalid",
36 "Guest state is invalid",
37 "Platform configuration is invalid",
39 "Platform is already owned",
40 "Certificate is invalid",
41 "Policy is not allowed",
42 "Guest is not active",
46 "Asid is already owned",
49 "DF_FLUSH is required",
50 "Guest handle is invalid",
55 "Feature not supported",
59 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
62 sev_ioctl(int fd
, int cmd
, void *data
, int *error
)
65 struct kvm_sev_cmd input
;
67 memset(&input
, 0x0, sizeof(input
));
71 input
.data
= (__u64
)(unsigned long)data
;
73 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_OP
, &input
);
83 sev_platform_ioctl(int fd
, int cmd
, void *data
, int *error
)
86 struct sev_issue_cmd arg
;
89 arg
.data
= (unsigned long)data
;
90 r
= ioctl(fd
, SEV_ISSUE_CMD
, &arg
);
99 fw_error_to_str(int code
)
101 if (code
< 0 || code
>= SEV_FW_MAX_ERROR
) {
102 return "unknown error";
105 return sev_fw_errlist
[code
];
109 sev_check_state(SevState state
)
112 return sev_state
->state
== state
? true : false;
116 sev_set_guest_state(SevState new_state
)
118 assert(new_state
< SEV_STATE__MAX
);
121 trace_kvm_sev_change_state(SevState_str(sev_state
->state
),
122 SevState_str(new_state
));
123 sev_state
->state
= new_state
;
127 sev_ram_block_added(RAMBlockNotifier
*n
, void *host
, size_t size
)
130 struct kvm_enc_region range
;
132 range
.addr
= (__u64
)(unsigned long)host
;
135 trace_kvm_memcrypt_register_region(host
, size
);
136 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_REG_REGION
, &range
);
138 error_report("%s: failed to register region (%p+%#zx) error '%s'",
139 __func__
, host
, size
, strerror(errno
));
145 sev_ram_block_removed(RAMBlockNotifier
*n
, void *host
, size_t size
)
148 struct kvm_enc_region range
;
150 range
.addr
= (__u64
)(unsigned long)host
;
153 trace_kvm_memcrypt_unregister_region(host
, size
);
154 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_UNREG_REGION
, &range
);
156 error_report("%s: failed to unregister region (%p+%#zx)",
157 __func__
, host
, size
);
161 static struct RAMBlockNotifier sev_ram_notifier
= {
162 .ram_block_added
= sev_ram_block_added
,
163 .ram_block_removed
= sev_ram_block_removed
,
167 qsev_guest_finalize(Object
*obj
)
172 qsev_guest_get_session_file(Object
*obj
, Error
**errp
)
174 QSevGuestInfo
*s
= QSEV_GUEST_INFO(obj
);
176 return s
->session_file
? g_strdup(s
->session_file
) : NULL
;
180 qsev_guest_set_session_file(Object
*obj
, const char *value
, Error
**errp
)
182 QSevGuestInfo
*s
= QSEV_GUEST_INFO(obj
);
184 s
->session_file
= g_strdup(value
);
188 qsev_guest_get_dh_cert_file(Object
*obj
, Error
**errp
)
190 QSevGuestInfo
*s
= QSEV_GUEST_INFO(obj
);
192 return g_strdup(s
->dh_cert_file
);
196 qsev_guest_set_dh_cert_file(Object
*obj
, const char *value
, Error
**errp
)
198 QSevGuestInfo
*s
= QSEV_GUEST_INFO(obj
);
200 s
->dh_cert_file
= g_strdup(value
);
204 qsev_guest_get_sev_device(Object
*obj
, Error
**errp
)
206 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
208 return g_strdup(sev
->sev_device
);
212 qsev_guest_set_sev_device(Object
*obj
, const char *value
, Error
**errp
)
214 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
216 sev
->sev_device
= g_strdup(value
);
220 qsev_guest_class_init(ObjectClass
*oc
, void *data
)
222 object_class_property_add_str(oc
, "sev-device",
223 qsev_guest_get_sev_device
,
224 qsev_guest_set_sev_device
,
226 object_class_property_set_description(oc
, "sev-device",
227 "SEV device to use", NULL
);
228 object_class_property_add_str(oc
, "dh-cert-file",
229 qsev_guest_get_dh_cert_file
,
230 qsev_guest_set_dh_cert_file
,
232 object_class_property_set_description(oc
, "dh-cert-file",
233 "guest owners DH certificate (encoded with base64)", NULL
);
234 object_class_property_add_str(oc
, "session-file",
235 qsev_guest_get_session_file
,
236 qsev_guest_set_session_file
,
238 object_class_property_set_description(oc
, "session-file",
239 "guest owners session parameters (encoded with base64)", NULL
);
243 qsev_guest_set_handle(Object
*obj
, Visitor
*v
, const char *name
,
244 void *opaque
, Error
**errp
)
246 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
249 visit_type_uint32(v
, name
, &value
, errp
);
254 qsev_guest_set_policy(Object
*obj
, Visitor
*v
, const char *name
,
255 void *opaque
, Error
**errp
)
257 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
260 visit_type_uint32(v
, name
, &value
, errp
);
265 qsev_guest_set_cbitpos(Object
*obj
, Visitor
*v
, const char *name
,
266 void *opaque
, Error
**errp
)
268 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
271 visit_type_uint32(v
, name
, &value
, errp
);
272 sev
->cbitpos
= value
;
276 qsev_guest_set_reduced_phys_bits(Object
*obj
, Visitor
*v
, const char *name
,
277 void *opaque
, Error
**errp
)
279 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
282 visit_type_uint32(v
, name
, &value
, errp
);
283 sev
->reduced_phys_bits
= value
;
287 qsev_guest_get_policy(Object
*obj
, Visitor
*v
, const char *name
,
288 void *opaque
, Error
**errp
)
291 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
294 visit_type_uint32(v
, name
, &value
, errp
);
298 qsev_guest_get_handle(Object
*obj
, Visitor
*v
, const char *name
,
299 void *opaque
, Error
**errp
)
302 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
305 visit_type_uint32(v
, name
, &value
, errp
);
309 qsev_guest_get_cbitpos(Object
*obj
, Visitor
*v
, const char *name
,
310 void *opaque
, Error
**errp
)
313 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
315 value
= sev
->cbitpos
;
316 visit_type_uint32(v
, name
, &value
, errp
);
320 qsev_guest_get_reduced_phys_bits(Object
*obj
, Visitor
*v
, const char *name
,
321 void *opaque
, Error
**errp
)
324 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
326 value
= sev
->reduced_phys_bits
;
327 visit_type_uint32(v
, name
, &value
, errp
);
331 qsev_guest_init(Object
*obj
)
333 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
335 sev
->sev_device
= g_strdup(DEFAULT_SEV_DEVICE
);
336 sev
->policy
= DEFAULT_GUEST_POLICY
;
337 object_property_add(obj
, "policy", "uint32", qsev_guest_get_policy
,
338 qsev_guest_set_policy
, NULL
, NULL
, NULL
);
339 object_property_add(obj
, "handle", "uint32", qsev_guest_get_handle
,
340 qsev_guest_set_handle
, NULL
, NULL
, NULL
);
341 object_property_add(obj
, "cbitpos", "uint32", qsev_guest_get_cbitpos
,
342 qsev_guest_set_cbitpos
, NULL
, NULL
, NULL
);
343 object_property_add(obj
, "reduced-phys-bits", "uint32",
344 qsev_guest_get_reduced_phys_bits
,
345 qsev_guest_set_reduced_phys_bits
, NULL
, NULL
, NULL
);
349 static const TypeInfo qsev_guest_info
= {
350 .parent
= TYPE_OBJECT
,
351 .name
= TYPE_QSEV_GUEST_INFO
,
352 .instance_size
= sizeof(QSevGuestInfo
),
353 .instance_finalize
= qsev_guest_finalize
,
354 .class_size
= sizeof(QSevGuestInfoClass
),
355 .class_init
= qsev_guest_class_init
,
356 .instance_init
= qsev_guest_init
,
357 .interfaces
= (InterfaceInfo
[]) {
358 { TYPE_USER_CREATABLE
},
363 static QSevGuestInfo
*
364 lookup_sev_guest_info(const char *id
)
369 obj
= object_resolve_path_component(object_get_objects_root(), id
);
374 info
= (QSevGuestInfo
*)
375 object_dynamic_cast(obj
, TYPE_QSEV_GUEST_INFO
);
386 return sev_state
? true : false;
390 sev_get_me_mask(void)
392 return sev_state
? sev_state
->me_mask
: ~0;
396 sev_get_cbit_position(void)
398 return sev_state
? sev_state
->cbitpos
: 0;
402 sev_get_reduced_phys_bits(void)
404 return sev_state
? sev_state
->reduced_phys_bits
: 0;
412 info
= g_new0(SevInfo
, 1);
413 info
->enabled
= sev_state
? true : false;
416 info
->api_major
= sev_state
->api_major
;
417 info
->api_minor
= sev_state
->api_minor
;
418 info
->build_id
= sev_state
->build_id
;
419 info
->policy
= sev_state
->policy
;
420 info
->state
= sev_state
->state
;
421 info
->handle
= sev_state
->handle
;
428 sev_read_file_base64(const char *filename
, guchar
**data
, gsize
*len
)
432 GError
*error
= NULL
;
434 if (!g_file_get_contents(filename
, &base64
, &sz
, &error
)) {
435 error_report("failed to read '%s' (%s)", filename
, error
->message
);
439 *data
= g_base64_decode(base64
, len
);
444 sev_launch_start(SEVState
*s
)
449 QSevGuestInfo
*sev
= s
->sev_info
;
450 struct kvm_sev_launch_start
*start
;
451 guchar
*session
= NULL
, *dh_cert
= NULL
;
453 start
= g_new0(struct kvm_sev_launch_start
, 1);
455 start
->handle
= object_property_get_int(OBJECT(sev
), "handle",
457 start
->policy
= object_property_get_int(OBJECT(sev
), "policy",
459 if (sev
->session_file
) {
460 if (sev_read_file_base64(sev
->session_file
, &session
, &sz
) < 0) {
463 start
->session_uaddr
= (unsigned long)session
;
464 start
->session_len
= sz
;
467 if (sev
->dh_cert_file
) {
468 if (sev_read_file_base64(sev
->dh_cert_file
, &dh_cert
, &sz
) < 0) {
471 start
->dh_uaddr
= (unsigned long)dh_cert
;
475 trace_kvm_sev_launch_start(start
->policy
, session
, dh_cert
);
476 ret
= sev_ioctl(s
->sev_fd
, KVM_SEV_LAUNCH_START
, start
, &fw_error
);
478 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
479 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
483 object_property_set_int(OBJECT(sev
), start
->handle
, "handle",
485 sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE
);
486 s
->handle
= start
->handle
;
487 s
->policy
= start
->policy
;
497 sev_launch_update_data(uint8_t *addr
, uint64_t len
)
500 struct kvm_sev_launch_update_data update
;
506 update
.uaddr
= (__u64
)(unsigned long)addr
;
508 trace_kvm_sev_launch_update_data(addr
, len
);
509 ret
= sev_ioctl(sev_state
->sev_fd
, KVM_SEV_LAUNCH_UPDATE_DATA
,
512 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
513 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
520 sev_launch_get_measure(Notifier
*notifier
, void *unused
)
524 SEVState
*s
= sev_state
;
525 struct kvm_sev_launch_measure
*measurement
;
527 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE
)) {
531 measurement
= g_new0(struct kvm_sev_launch_measure
, 1);
533 /* query the measurement blob length */
534 ret
= sev_ioctl(sev_state
->sev_fd
, KVM_SEV_LAUNCH_MEASURE
,
535 measurement
, &error
);
536 if (!measurement
->len
) {
537 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
538 __func__
, ret
, error
, fw_error_to_str(errno
));
539 goto free_measurement
;
542 data
= g_new0(guchar
, measurement
->len
);
543 measurement
->uaddr
= (unsigned long)data
;
545 /* get the measurement blob */
546 ret
= sev_ioctl(sev_state
->sev_fd
, KVM_SEV_LAUNCH_MEASURE
,
547 measurement
, &error
);
549 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
550 __func__
, ret
, error
, fw_error_to_str(errno
));
554 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET
);
556 /* encode the measurement value and emit the event */
557 s
->measurement
= g_base64_encode(data
, measurement
->len
);
558 trace_kvm_sev_launch_measurement(s
->measurement
);
567 sev_get_launch_measurement(void)
570 sev_state
->state
>= SEV_STATE_LAUNCH_SECRET
) {
571 return g_strdup(sev_state
->measurement
);
577 static Notifier sev_machine_done_notify
= {
578 .notify
= sev_launch_get_measure
,
582 sev_guest_init(const char *id
)
588 uint32_t host_cbitpos
;
589 struct sev_user_data_status status
= {};
591 s
= g_new0(SEVState
, 1);
592 s
->sev_info
= lookup_sev_guest_info(id
);
594 error_report("%s: '%s' is not a valid '%s' object",
595 __func__
, id
, TYPE_QSEV_GUEST_INFO
);
600 s
->state
= SEV_STATE_UNINIT
;
602 host_cpuid(0x8000001F, 0, NULL
, &ebx
, NULL
, NULL
);
603 host_cbitpos
= ebx
& 0x3f;
605 s
->cbitpos
= object_property_get_int(OBJECT(s
->sev_info
), "cbitpos", NULL
);
606 if (host_cbitpos
!= s
->cbitpos
) {
607 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
608 __func__
, host_cbitpos
, s
->cbitpos
);
612 s
->reduced_phys_bits
= object_property_get_int(OBJECT(s
->sev_info
),
613 "reduced-phys-bits", NULL
);
614 if (s
->reduced_phys_bits
< 1) {
615 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
616 "' requested '%d'", __func__
, s
->reduced_phys_bits
);
620 s
->me_mask
= ~(1UL << s
->cbitpos
);
622 devname
= object_property_get_str(OBJECT(s
->sev_info
), "sev-device", NULL
);
623 s
->sev_fd
= open(devname
, O_RDWR
);
625 error_report("%s: Failed to open %s '%s'", __func__
,
626 devname
, strerror(errno
));
631 ret
= sev_platform_ioctl(s
->sev_fd
, SEV_PLATFORM_STATUS
, &status
,
634 error_report("%s: failed to get platform status ret=%d"
635 "fw_error='%d: %s'", __func__
, ret
, fw_error
,
636 fw_error_to_str(fw_error
));
639 s
->build_id
= status
.build
;
640 s
->api_major
= status
.api_major
;
641 s
->api_minor
= status
.api_minor
;
643 trace_kvm_sev_init();
644 ret
= sev_ioctl(s
->sev_fd
, KVM_SEV_INIT
, NULL
, &fw_error
);
646 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
647 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
651 ret
= sev_launch_start(s
);
653 error_report("%s: failed to create encryption context", __func__
);
657 ram_block_notifier_add(&sev_ram_notifier
);
658 qemu_add_machine_init_done_notifier(&sev_machine_done_notify
);
668 sev_encrypt_data(void *handle
, uint8_t *ptr
, uint64_t len
)
672 /* if SEV is in update state then encrypt the data else do nothing */
673 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE
)) {
674 return sev_launch_update_data(ptr
, len
);
681 sev_register_types(void)
683 type_register_static(&qsev_guest_info
);
686 type_init(sev_register_types
);