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 "qemu/osdep.h"
16 #include <linux/kvm.h>
17 #include <linux/psp-sev.h>
19 #include <sys/ioctl.h>
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"
27 #include "sysemu/sysemu.h"
28 #include "sysemu/runstate.h"
30 #include "migration/blocker.h"
32 #define TYPE_SEV_GUEST "sev-guest"
33 #define SEV_GUEST(obj) \
34 OBJECT_CHECK(SevGuestState, (obj), TYPE_SEV_GUEST)
36 typedef struct SevGuestState SevGuestState
;
41 * The SevGuestState object is used for creating and managing a SEV
45 * -object sev-guest,id=sev0 \
46 * -machine ...,memory-encryption=sev0
48 struct SevGuestState
{
51 /* configuration parameters */
57 uint32_t reduced_phys_bits
;
70 #define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
71 #define DEFAULT_SEV_DEVICE "/dev/sev"
73 static SevGuestState
*sev_guest
;
74 static Error
*sev_mig_blocker
;
76 static const char *const sev_fw_errlist
[] = {
78 "Platform state is invalid",
79 "Guest state is invalid",
80 "Platform configuration is invalid",
82 "Platform is already owned",
83 "Certificate is invalid",
84 "Policy is not allowed",
85 "Guest is not active",
89 "Asid is already owned",
92 "DF_FLUSH is required",
93 "Guest handle is invalid",
98 "Feature not supported",
102 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
105 sev_ioctl(int fd
, int cmd
, void *data
, int *error
)
108 struct kvm_sev_cmd input
;
110 memset(&input
, 0x0, sizeof(input
));
114 input
.data
= (__u64
)(unsigned long)data
;
116 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_OP
, &input
);
119 *error
= input
.error
;
126 sev_platform_ioctl(int fd
, int cmd
, void *data
, int *error
)
129 struct sev_issue_cmd arg
;
132 arg
.data
= (unsigned long)data
;
133 r
= ioctl(fd
, SEV_ISSUE_CMD
, &arg
);
142 fw_error_to_str(int code
)
144 if (code
< 0 || code
>= SEV_FW_MAX_ERROR
) {
145 return "unknown error";
148 return sev_fw_errlist
[code
];
152 sev_check_state(const SevGuestState
*sev
, SevState state
)
155 return sev
->state
== state
? true : false;
159 sev_set_guest_state(SevGuestState
*sev
, SevState new_state
)
161 assert(new_state
< SEV_STATE__MAX
);
164 trace_kvm_sev_change_state(SevState_str(sev
->state
),
165 SevState_str(new_state
));
166 sev
->state
= new_state
;
170 sev_ram_block_added(RAMBlockNotifier
*n
, void *host
, size_t size
)
173 struct kvm_enc_region range
;
178 * The RAM device presents a memory region that should be treated
179 * as IO region and should not be pinned.
181 mr
= memory_region_from_host(host
, &offset
);
182 if (mr
&& memory_region_is_ram_device(mr
)) {
186 range
.addr
= (__u64
)(unsigned long)host
;
189 trace_kvm_memcrypt_register_region(host
, size
);
190 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_REG_REGION
, &range
);
192 error_report("%s: failed to register region (%p+%#zx) error '%s'",
193 __func__
, host
, size
, strerror(errno
));
199 sev_ram_block_removed(RAMBlockNotifier
*n
, void *host
, size_t size
)
202 struct kvm_enc_region range
;
207 * The RAM device presents a memory region that should be treated
208 * as IO region and should not have been pinned.
210 mr
= memory_region_from_host(host
, &offset
);
211 if (mr
&& memory_region_is_ram_device(mr
)) {
215 range
.addr
= (__u64
)(unsigned long)host
;
218 trace_kvm_memcrypt_unregister_region(host
, size
);
219 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_UNREG_REGION
, &range
);
221 error_report("%s: failed to unregister region (%p+%#zx)",
222 __func__
, host
, size
);
226 static struct RAMBlockNotifier sev_ram_notifier
= {
227 .ram_block_added
= sev_ram_block_added
,
228 .ram_block_removed
= sev_ram_block_removed
,
232 sev_guest_finalize(Object
*obj
)
237 sev_guest_get_session_file(Object
*obj
, Error
**errp
)
239 SevGuestState
*s
= SEV_GUEST(obj
);
241 return s
->session_file
? g_strdup(s
->session_file
) : NULL
;
245 sev_guest_set_session_file(Object
*obj
, const char *value
, Error
**errp
)
247 SevGuestState
*s
= SEV_GUEST(obj
);
249 s
->session_file
= g_strdup(value
);
253 sev_guest_get_dh_cert_file(Object
*obj
, Error
**errp
)
255 SevGuestState
*s
= SEV_GUEST(obj
);
257 return g_strdup(s
->dh_cert_file
);
261 sev_guest_set_dh_cert_file(Object
*obj
, const char *value
, Error
**errp
)
263 SevGuestState
*s
= SEV_GUEST(obj
);
265 s
->dh_cert_file
= g_strdup(value
);
269 sev_guest_get_sev_device(Object
*obj
, Error
**errp
)
271 SevGuestState
*sev
= SEV_GUEST(obj
);
273 return g_strdup(sev
->sev_device
);
277 sev_guest_set_sev_device(Object
*obj
, const char *value
, Error
**errp
)
279 SevGuestState
*sev
= SEV_GUEST(obj
);
281 sev
->sev_device
= g_strdup(value
);
285 sev_guest_class_init(ObjectClass
*oc
, void *data
)
287 object_class_property_add_str(oc
, "sev-device",
288 sev_guest_get_sev_device
,
289 sev_guest_set_sev_device
);
290 object_class_property_set_description(oc
, "sev-device",
291 "SEV device to use");
292 object_class_property_add_str(oc
, "dh-cert-file",
293 sev_guest_get_dh_cert_file
,
294 sev_guest_set_dh_cert_file
);
295 object_class_property_set_description(oc
, "dh-cert-file",
296 "guest owners DH certificate (encoded with base64)");
297 object_class_property_add_str(oc
, "session-file",
298 sev_guest_get_session_file
,
299 sev_guest_set_session_file
);
300 object_class_property_set_description(oc
, "session-file",
301 "guest owners session parameters (encoded with base64)");
305 sev_guest_instance_init(Object
*obj
)
307 SevGuestState
*sev
= SEV_GUEST(obj
);
309 sev
->sev_device
= g_strdup(DEFAULT_SEV_DEVICE
);
310 sev
->policy
= DEFAULT_GUEST_POLICY
;
311 object_property_add_uint32_ptr(obj
, "policy", &sev
->policy
,
312 OBJ_PROP_FLAG_READWRITE
);
313 object_property_add_uint32_ptr(obj
, "handle", &sev
->handle
,
314 OBJ_PROP_FLAG_READWRITE
);
315 object_property_add_uint32_ptr(obj
, "cbitpos", &sev
->cbitpos
,
316 OBJ_PROP_FLAG_READWRITE
);
317 object_property_add_uint32_ptr(obj
, "reduced-phys-bits",
318 &sev
->reduced_phys_bits
,
319 OBJ_PROP_FLAG_READWRITE
);
323 static const TypeInfo sev_guest_info
= {
324 .parent
= TYPE_OBJECT
,
325 .name
= TYPE_SEV_GUEST
,
326 .instance_size
= sizeof(SevGuestState
),
327 .instance_finalize
= sev_guest_finalize
,
328 .class_init
= sev_guest_class_init
,
329 .instance_init
= sev_guest_instance_init
,
330 .interfaces
= (InterfaceInfo
[]) {
331 { TYPE_USER_CREATABLE
},
336 static SevGuestState
*
337 lookup_sev_guest_info(const char *id
)
342 obj
= object_resolve_path_component(object_get_objects_root(), id
);
347 info
= (SevGuestState
*)
348 object_dynamic_cast(obj
, TYPE_SEV_GUEST
);
363 sev_get_me_mask(void)
365 return sev_guest
? sev_guest
->me_mask
: ~0;
369 sev_get_cbit_position(void)
371 return sev_guest
? sev_guest
->cbitpos
: 0;
375 sev_get_reduced_phys_bits(void)
377 return sev_guest
? sev_guest
->reduced_phys_bits
: 0;
385 info
= g_new0(SevInfo
, 1);
386 info
->enabled
= sev_enabled();
389 info
->api_major
= sev_guest
->api_major
;
390 info
->api_minor
= sev_guest
->api_minor
;
391 info
->build_id
= sev_guest
->build_id
;
392 info
->policy
= sev_guest
->policy
;
393 info
->state
= sev_guest
->state
;
394 info
->handle
= sev_guest
->handle
;
401 sev_get_pdh_info(int fd
, guchar
**pdh
, size_t *pdh_len
, guchar
**cert_chain
,
402 size_t *cert_chain_len
, Error
**errp
)
404 guchar
*pdh_data
= NULL
;
405 guchar
*cert_chain_data
= NULL
;
406 struct sev_user_data_pdh_cert_export export
= {};
409 /* query the certificate length */
410 r
= sev_platform_ioctl(fd
, SEV_PDH_CERT_EXPORT
, &export
, &err
);
412 if (err
!= SEV_RET_INVALID_LEN
) {
413 error_setg(errp
, "failed to export PDH cert ret=%d fw_err=%d (%s)",
414 r
, err
, fw_error_to_str(err
));
419 pdh_data
= g_new(guchar
, export
.pdh_cert_len
);
420 cert_chain_data
= g_new(guchar
, export
.cert_chain_len
);
421 export
.pdh_cert_address
= (unsigned long)pdh_data
;
422 export
.cert_chain_address
= (unsigned long)cert_chain_data
;
424 r
= sev_platform_ioctl(fd
, SEV_PDH_CERT_EXPORT
, &export
, &err
);
426 error_setg(errp
, "failed to export PDH cert ret=%d fw_err=%d (%s)",
427 r
, err
, fw_error_to_str(err
));
432 *pdh_len
= export
.pdh_cert_len
;
433 *cert_chain
= cert_chain_data
;
434 *cert_chain_len
= export
.cert_chain_len
;
439 g_free(cert_chain_data
);
444 sev_get_capabilities(Error
**errp
)
446 SevCapability
*cap
= NULL
;
447 guchar
*pdh_data
= NULL
;
448 guchar
*cert_chain_data
= NULL
;
449 size_t pdh_len
= 0, cert_chain_len
= 0;
453 fd
= open(DEFAULT_SEV_DEVICE
, O_RDWR
);
455 error_setg_errno(errp
, errno
, "Failed to open %s",
460 if (sev_get_pdh_info(fd
, &pdh_data
, &pdh_len
,
461 &cert_chain_data
, &cert_chain_len
, errp
)) {
465 cap
= g_new0(SevCapability
, 1);
466 cap
->pdh
= g_base64_encode(pdh_data
, pdh_len
);
467 cap
->cert_chain
= g_base64_encode(cert_chain_data
, cert_chain_len
);
469 host_cpuid(0x8000001F, 0, NULL
, &ebx
, NULL
, NULL
);
470 cap
->cbitpos
= ebx
& 0x3f;
473 * When SEV feature is enabled, we loose one bit in guest physical
476 cap
->reduced_phys_bits
= 1;
480 g_free(cert_chain_data
);
486 sev_read_file_base64(const char *filename
, guchar
**data
, gsize
*len
)
490 GError
*error
= NULL
;
492 if (!g_file_get_contents(filename
, &base64
, &sz
, &error
)) {
493 error_report("failed to read '%s' (%s)", filename
, error
->message
);
497 *data
= g_base64_decode(base64
, len
);
502 sev_launch_start(SevGuestState
*sev
)
507 struct kvm_sev_launch_start
*start
;
508 guchar
*session
= NULL
, *dh_cert
= NULL
;
510 start
= g_new0(struct kvm_sev_launch_start
, 1);
512 start
->handle
= sev
->handle
;
513 start
->policy
= sev
->policy
;
514 if (sev
->session_file
) {
515 if (sev_read_file_base64(sev
->session_file
, &session
, &sz
) < 0) {
518 start
->session_uaddr
= (unsigned long)session
;
519 start
->session_len
= sz
;
522 if (sev
->dh_cert_file
) {
523 if (sev_read_file_base64(sev
->dh_cert_file
, &dh_cert
, &sz
) < 0) {
526 start
->dh_uaddr
= (unsigned long)dh_cert
;
530 trace_kvm_sev_launch_start(start
->policy
, session
, dh_cert
);
531 rc
= sev_ioctl(sev
->sev_fd
, KVM_SEV_LAUNCH_START
, start
, &fw_error
);
533 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
534 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
538 sev_set_guest_state(sev
, SEV_STATE_LAUNCH_UPDATE
);
539 sev
->handle
= start
->handle
;
550 sev_launch_update_data(SevGuestState
*sev
, uint8_t *addr
, uint64_t len
)
553 struct kvm_sev_launch_update_data update
;
559 update
.uaddr
= (__u64
)(unsigned long)addr
;
561 trace_kvm_sev_launch_update_data(addr
, len
);
562 ret
= sev_ioctl(sev
->sev_fd
, KVM_SEV_LAUNCH_UPDATE_DATA
,
565 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
566 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
573 sev_launch_get_measure(Notifier
*notifier
, void *unused
)
575 SevGuestState
*sev
= sev_guest
;
578 struct kvm_sev_launch_measure
*measurement
;
580 if (!sev_check_state(sev
, SEV_STATE_LAUNCH_UPDATE
)) {
584 measurement
= g_new0(struct kvm_sev_launch_measure
, 1);
586 /* query the measurement blob length */
587 ret
= sev_ioctl(sev
->sev_fd
, KVM_SEV_LAUNCH_MEASURE
,
588 measurement
, &error
);
589 if (!measurement
->len
) {
590 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
591 __func__
, ret
, error
, fw_error_to_str(errno
));
592 goto free_measurement
;
595 data
= g_new0(guchar
, measurement
->len
);
596 measurement
->uaddr
= (unsigned long)data
;
598 /* get the measurement blob */
599 ret
= sev_ioctl(sev
->sev_fd
, KVM_SEV_LAUNCH_MEASURE
,
600 measurement
, &error
);
602 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
603 __func__
, ret
, error
, fw_error_to_str(errno
));
607 sev_set_guest_state(sev
, SEV_STATE_LAUNCH_SECRET
);
609 /* encode the measurement value and emit the event */
610 sev
->measurement
= g_base64_encode(data
, measurement
->len
);
611 trace_kvm_sev_launch_measurement(sev
->measurement
);
620 sev_get_launch_measurement(void)
623 sev_guest
->state
>= SEV_STATE_LAUNCH_SECRET
) {
624 return g_strdup(sev_guest
->measurement
);
630 static Notifier sev_machine_done_notify
= {
631 .notify
= sev_launch_get_measure
,
635 sev_launch_finish(SevGuestState
*sev
)
638 Error
*local_err
= NULL
;
640 trace_kvm_sev_launch_finish();
641 ret
= sev_ioctl(sev
->sev_fd
, KVM_SEV_LAUNCH_FINISH
, 0, &error
);
643 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
644 __func__
, ret
, error
, fw_error_to_str(error
));
648 sev_set_guest_state(sev
, SEV_STATE_RUNNING
);
650 /* add migration blocker */
651 error_setg(&sev_mig_blocker
,
652 "SEV: Migration is not implemented");
653 ret
= migrate_add_blocker(sev_mig_blocker
, &local_err
);
655 error_report_err(local_err
);
656 error_free(sev_mig_blocker
);
662 sev_vm_state_change(void *opaque
, int running
, RunState state
)
664 SevGuestState
*sev
= opaque
;
667 if (!sev_check_state(sev
, SEV_STATE_RUNNING
)) {
668 sev_launch_finish(sev
);
674 sev_guest_init(const char *id
)
680 uint32_t host_cbitpos
;
681 struct sev_user_data_status status
= {};
683 ret
= ram_block_discard_disable(true);
685 error_report("%s: cannot disable RAM discard", __func__
);
689 sev
= lookup_sev_guest_info(id
);
691 error_report("%s: '%s' is not a valid '%s' object",
692 __func__
, id
, TYPE_SEV_GUEST
);
697 sev
->state
= SEV_STATE_UNINIT
;
699 host_cpuid(0x8000001F, 0, NULL
, &ebx
, NULL
, NULL
);
700 host_cbitpos
= ebx
& 0x3f;
702 if (host_cbitpos
!= sev
->cbitpos
) {
703 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
704 __func__
, host_cbitpos
, sev
->cbitpos
);
708 if (sev
->reduced_phys_bits
< 1) {
709 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
710 " requested '%d'", __func__
, sev
->reduced_phys_bits
);
714 sev
->me_mask
= ~(1UL << sev
->cbitpos
);
716 devname
= object_property_get_str(OBJECT(sev
), "sev-device", NULL
);
717 sev
->sev_fd
= open(devname
, O_RDWR
);
718 if (sev
->sev_fd
< 0) {
719 error_report("%s: Failed to open %s '%s'", __func__
,
720 devname
, strerror(errno
));
723 if (sev
->sev_fd
< 0) {
727 ret
= sev_platform_ioctl(sev
->sev_fd
, SEV_PLATFORM_STATUS
, &status
,
730 error_report("%s: failed to get platform status ret=%d "
731 "fw_error='%d: %s'", __func__
, ret
, fw_error
,
732 fw_error_to_str(fw_error
));
735 sev
->build_id
= status
.build
;
736 sev
->api_major
= status
.api_major
;
737 sev
->api_minor
= status
.api_minor
;
739 trace_kvm_sev_init();
740 ret
= sev_ioctl(sev
->sev_fd
, KVM_SEV_INIT
, NULL
, &fw_error
);
742 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
743 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
747 ret
= sev_launch_start(sev
);
749 error_report("%s: failed to create encryption context", __func__
);
753 ram_block_notifier_add(&sev_ram_notifier
);
754 qemu_add_machine_init_done_notifier(&sev_machine_done_notify
);
755 qemu_add_vm_change_state_handler(sev_vm_state_change
, sev
);
760 ram_block_discard_disable(false);
765 sev_encrypt_data(void *handle
, uint8_t *ptr
, uint64_t len
)
767 SevGuestState
*sev
= handle
;
771 /* if SEV is in update state then encrypt the data else do nothing */
772 if (sev_check_state(sev
, SEV_STATE_LAUNCH_UPDATE
)) {
773 return sev_launch_update_data(sev
, ptr
, len
);
780 sev_register_types(void)
782 type_register_static(&sev_guest_info
);
785 type_init(sev_register_types
);