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 <[email protected]> --- 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
