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 DEFAULT_GUEST_POLICY 0x1 /* disable debug */
33 #define DEFAULT_SEV_DEVICE "/dev/sev"
35 static SEVState
*sev_state
;
36 static Error
*sev_mig_blocker
;
38 static const char *const sev_fw_errlist
[] = {
40 "Platform state is invalid",
41 "Guest state is invalid",
42 "Platform configuration is invalid",
44 "Platform is already owned",
45 "Certificate is invalid",
46 "Policy is not allowed",
47 "Guest is not active",
51 "Asid is already owned",
54 "DF_FLUSH is required",
55 "Guest handle is invalid",
60 "Feature not supported",
64 #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist)
67 sev_ioctl(int fd
, int cmd
, void *data
, int *error
)
70 struct kvm_sev_cmd input
;
72 memset(&input
, 0x0, sizeof(input
));
76 input
.data
= (__u64
)(unsigned long)data
;
78 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_OP
, &input
);
88 sev_platform_ioctl(int fd
, int cmd
, void *data
, int *error
)
91 struct sev_issue_cmd arg
;
94 arg
.data
= (unsigned long)data
;
95 r
= ioctl(fd
, SEV_ISSUE_CMD
, &arg
);
104 fw_error_to_str(int code
)
106 if (code
< 0 || code
>= SEV_FW_MAX_ERROR
) {
107 return "unknown error";
110 return sev_fw_errlist
[code
];
114 sev_check_state(SevState state
)
117 return sev_state
->state
== state
? true : false;
121 sev_set_guest_state(SevState new_state
)
123 assert(new_state
< SEV_STATE__MAX
);
126 trace_kvm_sev_change_state(SevState_str(sev_state
->state
),
127 SevState_str(new_state
));
128 sev_state
->state
= new_state
;
132 sev_ram_block_added(RAMBlockNotifier
*n
, void *host
, size_t size
)
135 struct kvm_enc_region range
;
140 * The RAM device presents a memory region that should be treated
141 * as IO region and should not be pinned.
143 mr
= memory_region_from_host(host
, &offset
);
144 if (mr
&& memory_region_is_ram_device(mr
)) {
148 range
.addr
= (__u64
)(unsigned long)host
;
151 trace_kvm_memcrypt_register_region(host
, size
);
152 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_REG_REGION
, &range
);
154 error_report("%s: failed to register region (%p+%#zx) error '%s'",
155 __func__
, host
, size
, strerror(errno
));
161 sev_ram_block_removed(RAMBlockNotifier
*n
, void *host
, size_t size
)
164 struct kvm_enc_region range
;
169 * The RAM device presents a memory region that should be treated
170 * as IO region and should not have been pinned.
172 mr
= memory_region_from_host(host
, &offset
);
173 if (mr
&& memory_region_is_ram_device(mr
)) {
177 range
.addr
= (__u64
)(unsigned long)host
;
180 trace_kvm_memcrypt_unregister_region(host
, size
);
181 r
= kvm_vm_ioctl(kvm_state
, KVM_MEMORY_ENCRYPT_UNREG_REGION
, &range
);
183 error_report("%s: failed to unregister region (%p+%#zx)",
184 __func__
, host
, size
);
188 static struct RAMBlockNotifier sev_ram_notifier
= {
189 .ram_block_added
= sev_ram_block_added
,
190 .ram_block_removed
= sev_ram_block_removed
,
194 qsev_guest_finalize(Object
*obj
)
199 qsev_guest_get_session_file(Object
*obj
, Error
**errp
)
201 QSevGuestInfo
*s
= QSEV_GUEST_INFO(obj
);
203 return s
->session_file
? g_strdup(s
->session_file
) : NULL
;
207 qsev_guest_set_session_file(Object
*obj
, const char *value
, Error
**errp
)
209 QSevGuestInfo
*s
= QSEV_GUEST_INFO(obj
);
211 s
->session_file
= g_strdup(value
);
215 qsev_guest_get_dh_cert_file(Object
*obj
, Error
**errp
)
217 QSevGuestInfo
*s
= QSEV_GUEST_INFO(obj
);
219 return g_strdup(s
->dh_cert_file
);
223 qsev_guest_set_dh_cert_file(Object
*obj
, const char *value
, Error
**errp
)
225 QSevGuestInfo
*s
= QSEV_GUEST_INFO(obj
);
227 s
->dh_cert_file
= g_strdup(value
);
231 qsev_guest_get_sev_device(Object
*obj
, Error
**errp
)
233 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
235 return g_strdup(sev
->sev_device
);
239 qsev_guest_set_sev_device(Object
*obj
, const char *value
, Error
**errp
)
241 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
243 sev
->sev_device
= g_strdup(value
);
247 qsev_guest_class_init(ObjectClass
*oc
, void *data
)
249 object_class_property_add_str(oc
, "sev-device",
250 qsev_guest_get_sev_device
,
251 qsev_guest_set_sev_device
,
253 object_class_property_set_description(oc
, "sev-device",
254 "SEV device to use", NULL
);
255 object_class_property_add_str(oc
, "dh-cert-file",
256 qsev_guest_get_dh_cert_file
,
257 qsev_guest_set_dh_cert_file
,
259 object_class_property_set_description(oc
, "dh-cert-file",
260 "guest owners DH certificate (encoded with base64)", NULL
);
261 object_class_property_add_str(oc
, "session-file",
262 qsev_guest_get_session_file
,
263 qsev_guest_set_session_file
,
265 object_class_property_set_description(oc
, "session-file",
266 "guest owners session parameters (encoded with base64)", NULL
);
270 qsev_guest_init(Object
*obj
)
272 QSevGuestInfo
*sev
= QSEV_GUEST_INFO(obj
);
274 sev
->sev_device
= g_strdup(DEFAULT_SEV_DEVICE
);
275 sev
->policy
= DEFAULT_GUEST_POLICY
;
276 object_property_add_uint32_ptr(obj
, "policy", &sev
->policy
,
277 OBJ_PROP_FLAG_READWRITE
, NULL
);
278 object_property_add_uint32_ptr(obj
, "handle", &sev
->handle
,
279 OBJ_PROP_FLAG_READWRITE
, NULL
);
280 object_property_add_uint32_ptr(obj
, "cbitpos", &sev
->cbitpos
,
281 OBJ_PROP_FLAG_READWRITE
, NULL
);
282 object_property_add_uint32_ptr(obj
, "reduced-phys-bits",
283 &sev
->reduced_phys_bits
,
284 OBJ_PROP_FLAG_READWRITE
, NULL
);
288 static const TypeInfo qsev_guest_info
= {
289 .parent
= TYPE_OBJECT
,
290 .name
= TYPE_QSEV_GUEST_INFO
,
291 .instance_size
= sizeof(QSevGuestInfo
),
292 .instance_finalize
= qsev_guest_finalize
,
293 .class_size
= sizeof(QSevGuestInfoClass
),
294 .class_init
= qsev_guest_class_init
,
295 .instance_init
= qsev_guest_init
,
296 .interfaces
= (InterfaceInfo
[]) {
297 { TYPE_USER_CREATABLE
},
302 static QSevGuestInfo
*
303 lookup_sev_guest_info(const char *id
)
308 obj
= object_resolve_path_component(object_get_objects_root(), id
);
313 info
= (QSevGuestInfo
*)
314 object_dynamic_cast(obj
, TYPE_QSEV_GUEST_INFO
);
325 return sev_state
? true : false;
329 sev_get_me_mask(void)
331 return sev_state
? sev_state
->me_mask
: ~0;
335 sev_get_cbit_position(void)
337 return sev_state
? sev_state
->cbitpos
: 0;
341 sev_get_reduced_phys_bits(void)
343 return sev_state
? sev_state
->reduced_phys_bits
: 0;
351 info
= g_new0(SevInfo
, 1);
352 info
->enabled
= sev_state
? true : false;
355 info
->api_major
= sev_state
->api_major
;
356 info
->api_minor
= sev_state
->api_minor
;
357 info
->build_id
= sev_state
->build_id
;
358 info
->policy
= sev_state
->policy
;
359 info
->state
= sev_state
->state
;
360 info
->handle
= sev_state
->handle
;
367 sev_get_pdh_info(int fd
, guchar
**pdh
, size_t *pdh_len
, guchar
**cert_chain
,
368 size_t *cert_chain_len
)
370 guchar
*pdh_data
= NULL
;
371 guchar
*cert_chain_data
= NULL
;
372 struct sev_user_data_pdh_cert_export export
= {};
375 /* query the certificate length */
376 r
= sev_platform_ioctl(fd
, SEV_PDH_CERT_EXPORT
, &export
, &err
);
378 if (err
!= SEV_RET_INVALID_LEN
) {
379 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
380 r
, err
, fw_error_to_str(err
));
385 pdh_data
= g_new(guchar
, export
.pdh_cert_len
);
386 cert_chain_data
= g_new(guchar
, export
.cert_chain_len
);
387 export
.pdh_cert_address
= (unsigned long)pdh_data
;
388 export
.cert_chain_address
= (unsigned long)cert_chain_data
;
390 r
= sev_platform_ioctl(fd
, SEV_PDH_CERT_EXPORT
, &export
, &err
);
392 error_report("failed to export PDH cert ret=%d fw_err=%d (%s)",
393 r
, err
, fw_error_to_str(err
));
398 *pdh_len
= export
.pdh_cert_len
;
399 *cert_chain
= cert_chain_data
;
400 *cert_chain_len
= export
.cert_chain_len
;
405 g_free(cert_chain_data
);
410 sev_get_capabilities(void)
412 SevCapability
*cap
= NULL
;
413 guchar
*pdh_data
= NULL
;
414 guchar
*cert_chain_data
= NULL
;
415 size_t pdh_len
= 0, cert_chain_len
= 0;
419 fd
= open(DEFAULT_SEV_DEVICE
, O_RDWR
);
421 error_report("%s: Failed to open %s '%s'", __func__
,
422 DEFAULT_SEV_DEVICE
, strerror(errno
));
426 if (sev_get_pdh_info(fd
, &pdh_data
, &pdh_len
,
427 &cert_chain_data
, &cert_chain_len
)) {
431 cap
= g_new0(SevCapability
, 1);
432 cap
->pdh
= g_base64_encode(pdh_data
, pdh_len
);
433 cap
->cert_chain
= g_base64_encode(cert_chain_data
, cert_chain_len
);
435 host_cpuid(0x8000001F, 0, NULL
, &ebx
, NULL
, NULL
);
436 cap
->cbitpos
= ebx
& 0x3f;
439 * When SEV feature is enabled, we loose one bit in guest physical
442 cap
->reduced_phys_bits
= 1;
446 g_free(cert_chain_data
);
452 sev_read_file_base64(const char *filename
, guchar
**data
, gsize
*len
)
456 GError
*error
= NULL
;
458 if (!g_file_get_contents(filename
, &base64
, &sz
, &error
)) {
459 error_report("failed to read '%s' (%s)", filename
, error
->message
);
463 *data
= g_base64_decode(base64
, len
);
468 sev_launch_start(SEVState
*s
)
473 QSevGuestInfo
*sev
= s
->sev_info
;
474 struct kvm_sev_launch_start
*start
;
475 guchar
*session
= NULL
, *dh_cert
= NULL
;
477 start
= g_new0(struct kvm_sev_launch_start
, 1);
479 start
->handle
= object_property_get_int(OBJECT(sev
), "handle",
481 start
->policy
= object_property_get_int(OBJECT(sev
), "policy",
483 if (sev
->session_file
) {
484 if (sev_read_file_base64(sev
->session_file
, &session
, &sz
) < 0) {
487 start
->session_uaddr
= (unsigned long)session
;
488 start
->session_len
= sz
;
491 if (sev
->dh_cert_file
) {
492 if (sev_read_file_base64(sev
->dh_cert_file
, &dh_cert
, &sz
) < 0) {
495 start
->dh_uaddr
= (unsigned long)dh_cert
;
499 trace_kvm_sev_launch_start(start
->policy
, session
, dh_cert
);
500 rc
= sev_ioctl(s
->sev_fd
, KVM_SEV_LAUNCH_START
, start
, &fw_error
);
502 error_report("%s: LAUNCH_START ret=%d fw_error=%d '%s'",
503 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
507 object_property_set_int(OBJECT(sev
), start
->handle
, "handle",
509 sev_set_guest_state(SEV_STATE_LAUNCH_UPDATE
);
510 s
->handle
= start
->handle
;
511 s
->policy
= start
->policy
;
522 sev_launch_update_data(uint8_t *addr
, uint64_t len
)
525 struct kvm_sev_launch_update_data update
;
531 update
.uaddr
= (__u64
)(unsigned long)addr
;
533 trace_kvm_sev_launch_update_data(addr
, len
);
534 ret
= sev_ioctl(sev_state
->sev_fd
, KVM_SEV_LAUNCH_UPDATE_DATA
,
537 error_report("%s: LAUNCH_UPDATE ret=%d fw_error=%d '%s'",
538 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
545 sev_launch_get_measure(Notifier
*notifier
, void *unused
)
549 SEVState
*s
= sev_state
;
550 struct kvm_sev_launch_measure
*measurement
;
552 if (!sev_check_state(SEV_STATE_LAUNCH_UPDATE
)) {
556 measurement
= g_new0(struct kvm_sev_launch_measure
, 1);
558 /* query the measurement blob length */
559 ret
= sev_ioctl(sev_state
->sev_fd
, KVM_SEV_LAUNCH_MEASURE
,
560 measurement
, &error
);
561 if (!measurement
->len
) {
562 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
563 __func__
, ret
, error
, fw_error_to_str(errno
));
564 goto free_measurement
;
567 data
= g_new0(guchar
, measurement
->len
);
568 measurement
->uaddr
= (unsigned long)data
;
570 /* get the measurement blob */
571 ret
= sev_ioctl(sev_state
->sev_fd
, KVM_SEV_LAUNCH_MEASURE
,
572 measurement
, &error
);
574 error_report("%s: LAUNCH_MEASURE ret=%d fw_error=%d '%s'",
575 __func__
, ret
, error
, fw_error_to_str(errno
));
579 sev_set_guest_state(SEV_STATE_LAUNCH_SECRET
);
581 /* encode the measurement value and emit the event */
582 s
->measurement
= g_base64_encode(data
, measurement
->len
);
583 trace_kvm_sev_launch_measurement(s
->measurement
);
592 sev_get_launch_measurement(void)
595 sev_state
->state
>= SEV_STATE_LAUNCH_SECRET
) {
596 return g_strdup(sev_state
->measurement
);
602 static Notifier sev_machine_done_notify
= {
603 .notify
= sev_launch_get_measure
,
607 sev_launch_finish(SEVState
*s
)
610 Error
*local_err
= NULL
;
612 trace_kvm_sev_launch_finish();
613 ret
= sev_ioctl(sev_state
->sev_fd
, KVM_SEV_LAUNCH_FINISH
, 0, &error
);
615 error_report("%s: LAUNCH_FINISH ret=%d fw_error=%d '%s'",
616 __func__
, ret
, error
, fw_error_to_str(error
));
620 sev_set_guest_state(SEV_STATE_RUNNING
);
622 /* add migration blocker */
623 error_setg(&sev_mig_blocker
,
624 "SEV: Migration is not implemented");
625 ret
= migrate_add_blocker(sev_mig_blocker
, &local_err
);
627 error_report_err(local_err
);
628 error_free(sev_mig_blocker
);
634 sev_vm_state_change(void *opaque
, int running
, RunState state
)
636 SEVState
*s
= opaque
;
639 if (!sev_check_state(SEV_STATE_RUNNING
)) {
640 sev_launch_finish(s
);
646 sev_guest_init(const char *id
)
652 uint32_t host_cbitpos
;
653 struct sev_user_data_status status
= {};
655 sev_state
= s
= g_new0(SEVState
, 1);
656 s
->sev_info
= lookup_sev_guest_info(id
);
658 error_report("%s: '%s' is not a valid '%s' object",
659 __func__
, id
, TYPE_QSEV_GUEST_INFO
);
663 s
->state
= SEV_STATE_UNINIT
;
665 host_cpuid(0x8000001F, 0, NULL
, &ebx
, NULL
, NULL
);
666 host_cbitpos
= ebx
& 0x3f;
668 s
->cbitpos
= object_property_get_int(OBJECT(s
->sev_info
), "cbitpos", NULL
);
669 if (host_cbitpos
!= s
->cbitpos
) {
670 error_report("%s: cbitpos check failed, host '%d' requested '%d'",
671 __func__
, host_cbitpos
, s
->cbitpos
);
675 s
->reduced_phys_bits
= object_property_get_int(OBJECT(s
->sev_info
),
676 "reduced-phys-bits", NULL
);
677 if (s
->reduced_phys_bits
< 1) {
678 error_report("%s: reduced_phys_bits check failed, it should be >=1,"
679 " requested '%d'", __func__
, s
->reduced_phys_bits
);
683 s
->me_mask
= ~(1UL << s
->cbitpos
);
685 devname
= object_property_get_str(OBJECT(s
->sev_info
), "sev-device", NULL
);
686 s
->sev_fd
= open(devname
, O_RDWR
);
688 error_report("%s: Failed to open %s '%s'", __func__
,
689 devname
, strerror(errno
));
696 ret
= sev_platform_ioctl(s
->sev_fd
, SEV_PLATFORM_STATUS
, &status
,
699 error_report("%s: failed to get platform status ret=%d "
700 "fw_error='%d: %s'", __func__
, ret
, fw_error
,
701 fw_error_to_str(fw_error
));
704 s
->build_id
= status
.build
;
705 s
->api_major
= status
.api_major
;
706 s
->api_minor
= status
.api_minor
;
708 trace_kvm_sev_init();
709 ret
= sev_ioctl(s
->sev_fd
, KVM_SEV_INIT
, NULL
, &fw_error
);
711 error_report("%s: failed to initialize ret=%d fw_error=%d '%s'",
712 __func__
, ret
, fw_error
, fw_error_to_str(fw_error
));
716 ret
= sev_launch_start(s
);
718 error_report("%s: failed to create encryption context", __func__
);
722 ram_block_notifier_add(&sev_ram_notifier
);
723 qemu_add_machine_init_done_notifier(&sev_machine_done_notify
);
724 qemu_add_vm_change_state_handler(sev_vm_state_change
, s
);
734 sev_encrypt_data(void *handle
, uint8_t *ptr
, uint64_t len
)
738 /* if SEV is in update state then encrypt the data else do nothing */
739 if (sev_check_state(SEV_STATE_LAUNCH_UPDATE
)) {
740 return sev_launch_update_data(ptr
, len
);
747 sev_register_types(void)
749 type_register_static(&qsev_guest_info
);
752 type_init(sev_register_types
);