With prior patches exposing SEV CPUID and MSR, the guest recognizes SEV
as active, but SEV progress states and "query-sev" QMP output remain
incorrect, breaking the attestation workflow.
For TCG emulation aimed at debugging and testing SEV guests—without real
cryptography needs—SEV_STATE_LAUNCH_START (crypto context initialization)
is skipped, proceeding directly to LAUNCH_UPDATE. Here, instead of
encrypting firmware and (if kernel-hashes=on) kernel, this memory
locations are tracked for future Launch Digest (LD) computation,
required for the launch measurement in the next phase. These regions are
stored in the QEMUIOVector ld_data within SevEmulatedState using
sev_emulated_launch_update_data().
For the last state, sev_emulated_launch_finish() handles the transition to
RUNNING state for the VM, while preserving the migration blocker.
sev_emulated_init() initializes all fields for accurate "query-sev" output
alongside state setup.
This is preparatory for sev_launch_measurement() implementation.
Note: In sev_kvm_type(), there is a condition that forces the legacy VM
type for consistency. Normally, this function is never called during a
TCG run. However, since sev-emulated derives from sev-guest, it is possible
to run it with KVM support. This leads to incomplete emulation (MSR will be
inactive, and C-bit management will be missing), although it still
functions. In such cases, when the function is invoked and
legacy-vm-type=off is set, KVM compatibility checks will inevitably fail.
Instead, this allows the VM to boot, issuing a warning about the change.
Additionally, qmp_query_sev_capabilities and
qmp_query_sev_attestation_report return a new error indicating that these
functions are not supported if emulation is active.
From this point, the VM follows the correct state transitions
(except LAUNCH_SECRET), and the data reported by "query-sev" is consistent.
Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
---
target/i386/sev.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 77 insertions(+), 1 deletion(-)
diff --git a/target/i386/sev.c b/target/i386/sev.c
index cdadd83ab5..5904f2c983 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -66,6 +66,12 @@ OBJECT_DECLARE_TYPE(SevSnpGuestState, SevCommonStateClass, SEV_SNP_GUEST)
#define FLAGS_SEGCACHE_TO_VMSA(flags) \
((((flags) & 0xff00) >> 8) | (((flags) & 0xf00000) >> 12))
+/* SEV-EMULATED default values */
+#define INVALID_FD -1
+#define FAKE_BUILD_ID 40
+#define FAKE_API_MAJOR 1
+#define FAKE_API_MINOR 40
+
typedef struct QEMU_PACKED SevHashTableEntry {
QemuUUID guid;
uint16_t len;
@@ -191,6 +197,7 @@ struct SevGuestState {
typedef struct SevEmulatedState {
SevGuestState parent_obj;
+ QEMUIOVector ld_data;
} SevEmulatedState;
struct SevSnpGuestState {
@@ -915,6 +922,12 @@ static SevCapability *sev_get_capabilities(Error **errp)
SevCommonState *sev_common;
char *sev_device;
+ if (sev_emulated_enabled()) {
+ error_setg(errp, "SEV emulation does not support"
+ "returning capabilities");
+ return NULL;
+ }
+
if (!kvm_enabled()) {
error_setg(errp, "KVM not enabled");
return NULL;
@@ -1024,6 +1037,12 @@ static SevAttestationReport *sev_get_attestation_report(const char *mnonce,
return NULL;
}
+ if (sev_emulated_enabled()) {
+ error_setg(errp, "SEV emulation does not support"
+ "attestation report");
+ return NULL;
+ }
+
/* lets decode the mnonce string */
buf = g_base64_decode(mnonce, &len);
if (!buf) {
@@ -1752,6 +1771,21 @@ static int sev_kvm_type(X86ConfidentialGuest *cg)
*/
kvm_type = (sev_guest->policy & SEV_POLICY_ES) ?
KVM_X86_SEV_ES_VM : KVM_X86_SEV_VM;
+
+ /*
+ * If we are in emulated mode, force the legacy VM type as the only
+ * actively supported option.
+ */
+ if (sev_emulated_enabled()) {
+ if (kvm_type != KVM_X86_DEFAULT_VM) {
+ warn_report("Only legacy VM are supported in emulated mode:"
+ " using KVM_X86_DEFAULT_VM");
+ kvm_type = KVM_X86_DEFAULT_VM;
+ }
+ sev_common->kvm_type = kvm_type;
+ goto out;
+ }
+
if (!kvm_is_vm_type_supported(kvm_type)) {
if (sev_guest->legacy_vm_type == ON_OFF_AUTO_AUTO) {
error_report("SEV: host kernel does not support requested %s VM type, which is required "
@@ -2973,6 +3007,10 @@ sev_guest_instance_init(Object *obj)
static int sev_emulated_init(ConfidentialGuestSupport *cgs, Error **errp)
{
SevCommonState *sev_common = SEV_COMMON(cgs);
+ SevGuestState *sev_guest = SEV_GUEST(sev_common);
+ SevEmulatedState *sev_emulated = SEV_EMULATED(sev_guest);
+
+ sev_common->state = SEV_STATE_UNINIT;
/*
* The cbitpos value will be placed in bit positions 5:0 of the EBX
@@ -2999,15 +3037,53 @@ static int sev_emulated_init(ConfidentialGuestSupport *cgs, Error **errp)
__func__, sev_common->reduced_phys_bits);
return -1;
}
+ /*
+ * The device does not exist so we initialize the values as default.
+ * We can skip to SEV_STATE_LAUNCH_UPDATE as there is nothing to encrypt.
+ * This avoids the launch start call.
+ */
+ sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE);
+ sev_common->sev_fd = INVALID_FD;
+ sev_common->build_id = FAKE_BUILD_ID;
+ sev_common->api_major = FAKE_API_MAJOR;
+ sev_common->api_minor = FAKE_API_MINOR;
+
+ /* Initialize the iovec for the measurements blobs */
+ qemu_iovec_init(&sev_emulated->ld_data, 3);
+
+ qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common);
+
cgs->ready = true;
return 0;
}
+static int sev_emulated_launch_update_data(SevCommonState *sev_common,
+ hwaddr gpa, uint8_t *addr, size_t len, Error **errp)
+{
+ SevEmulatedState *sev_emulated = SEV_EMULATED(sev_common);
+
+ if (!addr || !len) {
+ return 1;
+ }
+ qemu_iovec_add(&sev_emulated->ld_data, addr, len);
+
+ return 0;
+}
+
+static void
+sev_emulated_launch_finish(SevCommonState *sev_common)
+{
+ sev_set_guest_state(sev_common, SEV_STATE_RUNNING);
+}
+
static void sev_emulated_class_init(ObjectClass *oc, const void *data)
{
+ SevCommonStateClass *scc = SEV_COMMON_CLASS(oc);
ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
- /* Override the sev-common method that uses kvm */
+ /* Override the sev-common methods that use kvm */
klass->kvm_init = sev_emulated_init;
+ scc->launch_update_data = sev_emulated_launch_update_data;
+ scc->launch_finish = sev_emulated_launch_finish;
}
/* guest info specific sev/sev-es */
--
2.53.0
© 2016 - 2026 Red Hat, Inc.