From nobody Mon Apr 6 23:29:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1773752126; cv=none; d=zohomail.com; s=zohoarc; b=bebQlQDW1UPYDQOsnMes8QjD8jDHk8mvIIQWlAdEh7M0DVM91tUiAHKZ9OzVRlNhM7RKpu0S6LCcnemUZ+I/z2mv09ObI/4JJ1g4AAulHZxRIT2mjPGAPcGnlM7oGmL+pLBm1r6XqsVO5YvBmpMaat4pUbFSTf2qzlnB9wqlohE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773752126; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=C4OeY00TqioDsqTaCkdbJqegZ4L5ieZAJ4YmiLwi1M0=; b=RgJnOW8cy56O8K4mdH3Ist682Ph3AZm2YZg9jwHCpmTIN9bn7XHIPgnwCdGBOEFIUOxMGUv/hy8/KruQiZUZ0oUd7u7rMtiGGSWtpoBF0zDcyha7CBGS5C5XZHSurX4gyej8Dsv72agzYBwTWR2IIQ6NIq/Rd/59nAOpccazvCk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1773752126185737.8099907604231; Tue, 17 Mar 2026 05:55:26 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w2TwU-0008V0-72; Tue, 17 Mar 2026 08:54:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w2Sl2-0003Ss-6U for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:44 -0400 Received: from mail-wm1-x329.google.com ([2a00:1450:4864:20::329]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w2Skx-0007sD-IM for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:41 -0400 Received: by mail-wm1-x329.google.com with SMTP id 5b1f17b1804b1-4856cd3f1ffso15050215e9.3 for ; Tue, 17 Mar 2026 04:38:38 -0700 (PDT) Received: from DesktopTC.localdomain (host-87-27-45-215.business.telecomitalia.it. [87.27.45.215]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4856eaee04fsm62721365e9.13.2026.03.17.04.38.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Mar 2026 04:38:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773747516; x=1774352316; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=C4OeY00TqioDsqTaCkdbJqegZ4L5ieZAJ4YmiLwi1M0=; b=cQKgiCYTYNqoGYiL/FdDj9mXpDUUt31ZMyseFUHKk3pbeKbMHTJn2s26HlWpImL+bp vFWpjHIBUuj/Y8dkyoPDlhiUN4uDr9StVySVdL3XcOpQkI5XRh03+RZw5N3uYuRp+KY4 gHTKTk5ALbfjm9lxXu58rWfk8G87zE75v6GAq4aap0XuHYf44x4noGU3HTOOvagpz0Vt ovB5u+jx9AuOM1PwQZONIX6wuLESllzPLd0+VVBM2M7K8jbhCPFKt0fHOcJdaoWCx6J7 GJ8ck9u6LhoSUl0ZCQEpvuGH20jf/D4ginjgQWfp2vTSpCskpMioRHfQ2BNQm6Mc3nDd XPHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773747516; x=1774352316; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=C4OeY00TqioDsqTaCkdbJqegZ4L5ieZAJ4YmiLwi1M0=; b=FCb9VjKitQKxc0K7AZ7lAui5b7AeGqQLBTzRiJr7Ffz8oUoS+VwbN/UAca4G3RWttz zYgEVUpue1v2yndRns07ywtUg2/wfUao2izyXI/iQCiwhKXHyuTg12PpE68o0SyI9szK ikswqDgGzGAm20QiT6LdQ2uI186IbT2FRMpPouZMHOCAqN+H/z+LWSbcDR/8SKFNufiu YLZL5ErGKJPaL1A0rMwj8xRAeSc7BFKXXUFBdSjxxmN9Y5tf9Mw+lsNW1VZ7ZAGV4z0T vxlQLkgmw+j8+6KONl7+X7Ohs5bIgrZjR3AuyZraD8LIfU31N30+mnryWDT7fCyOWXGs wOLw== X-Gm-Message-State: AOJu0Yyb2f8ZuXAGH5BLsqaokxLTnG7x8uZUai3QbEb0iS3cRomqqD4K 65gOp0V0m3oWeNsZ9MRoVlM9RqmdQmQCn3AiqKuWm4tugwJJ2TSCyhgQeQKYLOW3 X-Gm-Gg: ATEYQzznjPkzVCIMPgyuNHG0H4Ip1egTlZDWelGxY6QdEwLXc8XyTgeOOyXs+XyWRwq Dp+nc1FBVhfG9to0jly7FSnfswj8k5xZxwAXkUQUc/l9rhGZl9RM9OqxExUfSAqVaoSkJYbt8b8 9Ia1uT6as37lJ3DJvU2tWxAC73gt8MRZRxsVQr4QeTiZxEnVDEdEHyLs13ubnzEBZqPIizQ+blE jyX6nGdVot7/9/I+JF95IMEwolA0WDTCG8m0fUrInhAqzrlft5wumtL3pyZMFqi4l/mF3iOIIdv pXuYjzB4ESNxtNuC+5urxZSIbcsEdlaI4pAJcqpeof4ZyCgJSPDmh/jNMqCUJTNC224aZaxdX6K gYzgQefZL8AiL1qgBqye4x/ixFLf8pEuoEP8QvwLIA3L9IjD8sl7fYKwcn0rkl/OHu1vDJ6oBEz ZV2RDJVWBst9cYjofHxfdgUwVyq5lNnKHqEgjm+/m7eULVk3TRX77xO9doYMoplyxCgKCFEaFYN Gmhc4Hd/UHN799yw+h6 X-Received: by 2002:a05:600c:8519:b0:485:5812:bb9e with SMTP id 5b1f17b1804b1-4855812bbddmr316994945e9.0.1773747515544; Tue, 17 Mar 2026 04:38:35 -0700 (PDT) From: Tommaso Califano To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, Eduardo Habkost , Markus Armbruster , Zhao Liu , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Marcelo Tosatti , Eric Blake , Oliver Steffen , Stefano Garzarella , Giuseppe Lettieri , Paolo Bonzini , Luigi Leonardi , Richard Henderson , Tommaso Califano Subject: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support Date: Tue, 17 Mar 2026 12:38:36 +0100 Message-ID: <20260317113840.33017-2-califano.tommaso@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260317113840.33017-1-califano.tommaso@gmail.com> References: <20260317113840.33017-1-califano.tommaso@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::329; envelope-from=califano.tommaso@gmail.com; helo=mail-wm1-x329.google.com X-Spam_score_int: -3 X-Spam_score: -0.4 X-Spam_bar: / X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, MIME_BASE64_TEXT=1.741, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 17 Mar 2026 08:54:34 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1773752128777154100 Content-Type: text/plain; charset="utf-8" QEMU's AMD SEV support requires KVM on costly AMD EPYC processors, limiting development and testing to users with specialized server hardware. This makes it hard to validate SEV guest behavior, like OVMF boots or SEV-aware software, on common dev machines. A solution to this is the emulation of SEV from the guest's perspective using TCG. This change begins this process with the exposure of the SEV CPUID leaf. In target/i386/cpu.c:cpu_x86_cpuid() case 0x8000001F: case 0x8000001F: *eax =3D *ebx =3D *ecx =3D *edx =3D 0; if (sev_enabled()) { *eax =3D 0x2; *eax |=3D sev_es_enabled() ? 0x8 : 0; *eax |=3D sev_snp_enabled() ? 0x10 : 0; *ebx =3D sev_get_cbit_position() & 0x3f; /* EBX[5:0] */ *ebx |=3D (sev_get_reduced_phys_bits() & 0x3f) << 6; /* EBX[11:6] */ } break; sev_enabled() verifies if the QOM object is TYPE_SEV_GUEST; TYPE_SEV_EMULATED is derived from TYPE_SEV_GUEST with SevEmulatedState to satisfy this check with minimal changes. In particular this allows to bypass all the sev_enabled() checks for future features. Since KVM hardware isn't available, override the QOM's kvm_init() and add a conditional confidential_guest_kvm_init() call during machine_init() to set up emulated confidential support using the ConfidentialGuestSupport structure. With this change it is possible to run a VM with the SEV CPUID active adding: -accel tcg \ -object sev-emulated,id=3Dsev0,cbitpos=3D47,reduced-phys-bits=3D1 \ -machine memory-encryption=3Dsev0 To the QEMU start arguments. Signed-off-by: Tommaso Califano --- accel/tcg/tcg-all.c | 18 ++++++++++++- qapi/qom.json | 15 +++++++++++ target/i386/sev.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ target/i386/sev.h | 1 + 4 files changed, 98 insertions(+), 1 deletion(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 8eb4a6b89e..d55827e214 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -45,7 +45,7 @@ #include "accel/accel-cpu-ops.h" #include "accel/tcg/cpu-ops.h" #include "internal-common.h" - +#include "system/confidential-guest-support.h" =20 struct TCGState { AccelState parent_obj; @@ -107,6 +107,9 @@ static int tcg_init_machine(AccelState *as, MachineStat= e *ms) unsigned max_threads =3D 1; =20 #ifndef CONFIG_USER_ONLY + int ret; + Error *local_err =3D NULL; + const char *cgs_type =3D NULL; CPUClass *cc =3D CPU_CLASS(object_class_by_name(target_cpu_type())); bool mttcg_supported =3D cc->tcg_ops->mttcg_supported; =20 @@ -163,6 +166,19 @@ static int tcg_init_machine(AccelState *as, MachineSta= te *ms) =20 #ifdef CONFIG_USER_ONLY qdev_create_fake_machine(); +#else + /* TCG SEV/Confidential Guest Support init */ + if (ms->cgs) { + cgs_type =3D object_get_typename(OBJECT(ms->cgs)); + + if (g_str_has_prefix(cgs_type, "sev-emulated")) { + ret =3D confidential_guest_kvm_init(ms->cgs, &local_err); + if (ret < 0) { + error_report_err(local_err); + return ret; + } + } + } #endif =20 return 0; diff --git a/qapi/qom.json b/qapi/qom.json index c653248f85..35cda819ec 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1057,6 +1057,19 @@ '*handle': 'uint32', '*legacy-vm-type': 'OnOffAuto' } } =20 +## +# @SevEmulatedProperties: +# +# Properties for sev-emulated objects. +# This object functionally emulates AMD SEV hardware via TCG, so +# it does not require real hardware to run. +# +# Since: 10.1.0 +## +{ 'struct': 'SevEmulatedProperties', + 'base': 'SevGuestProperties', + 'data': {}} + ## # @SevSnpGuestProperties: # @@ -1241,6 +1254,7 @@ { 'name': 'secret_keyring', 'if': 'CONFIG_SECRET_KEYRING' }, 'sev-guest', + 'sev-emulated', 'sev-snp-guest', 'thread-context', 's390-pv-guest', @@ -1318,6 +1332,7 @@ 'secret_keyring': { 'type': 'SecretKeyringProperties', 'if': 'CONFIG_SECRET_KEYRING' }, 'sev-guest': 'SevGuestProperties', + 'sev-emulated': 'SevEmulatedProperties', 'sev-snp-guest': 'SevSnpGuestProperties', 'tdx-guest': 'TdxGuestProperties', 'thread-context': 'ThreadContextProperties', diff --git a/target/i386/sev.c b/target/i386/sev.c index 9dde972c11..2502e860e2 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -51,6 +51,7 @@ =20 OBJECT_DECLARE_TYPE(SevCommonState, SevCommonStateClass, SEV_COMMON) OBJECT_DECLARE_TYPE(SevGuestState, SevCommonStateClass, SEV_GUEST) +OBJECT_DECLARE_TYPE(SevEmulatedState, SevCommonStateClass, SEV_EMULATED) OBJECT_DECLARE_TYPE(SevSnpGuestState, SevCommonStateClass, SEV_SNP_GUEST) =20 /* hard code sha256 digest size */ @@ -177,6 +178,21 @@ struct SevGuestState { OnOffAuto legacy_vm_type; }; =20 +/** + * SevEmulatedState: + * + * The SevEmulatedState object is used for creating and managing a SEV emu= lated + * guest. + * + * # $QEMU \ + * -object sev-emulated,id=3Dsev0 \ + * -machine ...,memory-encryption=3Dsev0 + */ + +typedef struct SevEmulatedState { + SevGuestState parent_obj; +} SevEmulatedState; + struct SevSnpGuestState { SevCommonState parent_obj; =20 @@ -2936,6 +2952,46 @@ sev_guest_instance_init(Object *obj) sev_guest->legacy_vm_type =3D ON_OFF_AUTO_AUTO; } =20 +static int sev_emulated_init(ConfidentialGuestSupport *cgs, Error **errp) +{ + SevCommonState *sev_common =3D SEV_COMMON(cgs); + + /* + * The cbitpos value will be placed in bit positions 5:0 of the EBX + * register of CPUID 0x8000001F. We need to verify the range as the + * comparison with the host cbitpos is missing. + */ + if (sev_common->cbitpos < 32 || + sev_common->cbitpos > 63) { + error_setg(errp, "%s: cbitpos check failed, requested '%d'," + "the firmware requires >=3D32", + __func__, sev_common->cbitpos); + return -1; + } + + /* + * The reduced-phys-bits value will be placed in bit positions 11:6 of + * the EBX register of CPUID 0x8000001F, so verify the supplied value + * is in the range of 1 to 63. + */ + if (sev_common->reduced_phys_bits < 1 || + sev_common->reduced_phys_bits > 63) { + error_setg(errp, "%s: reduced_phys_bits check failed," + " it should be in the range of 1 to 63, requested '%d'", + __func__, sev_common->reduced_phys_bits); + return -1; + } + cgs->ready =3D true; + return 0; +} + +static void sev_emulated_class_init(ObjectClass *oc, const void *data) +{ + ConfidentialGuestSupportClass *klass =3D CONFIDENTIAL_GUEST_SUPPORT_CL= ASS(oc); + /* Override the sev-common method that uses kvm */ + klass->kvm_init =3D sev_emulated_init; +} + /* guest info specific sev/sev-es */ static const TypeInfo sev_guest_info =3D { .parent =3D TYPE_SEV_COMMON, @@ -2945,6 +3001,14 @@ static const TypeInfo sev_guest_info =3D { .class_init =3D sev_guest_class_init, }; =20 +/* emulated sev */ +static const TypeInfo sev_emulated_info =3D { + .parent =3D TYPE_SEV_GUEST, + .name =3D TYPE_SEV_EMULATED, + .instance_size =3D sizeof(SevEmulatedState), + .class_init =3D sev_emulated_class_init +}; + static void sev_snp_guest_get_policy(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) @@ -3207,6 +3271,7 @@ static void sev_register_types(void) { type_register_static(&sev_common_info); + type_register_static(&sev_emulated_info); type_register_static(&sev_guest_info); type_register_static(&sev_snp_guest_info); } diff --git a/target/i386/sev.h b/target/i386/sev.h index 4358df40e4..839656e2be 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -33,6 +33,7 @@ bool sev_snp_enabled(void); #if !defined(CONFIG_USER_ONLY) =20 #define TYPE_SEV_COMMON "sev-common" +#define TYPE_SEV_EMULATED "sev-emulated" #define TYPE_SEV_GUEST "sev-guest" #define TYPE_SEV_SNP_GUEST "sev-snp-guest" =20 --=20 2.53.0 From nobody Mon Apr 6 23:29:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1773752121; cv=none; d=zohomail.com; s=zohoarc; b=G7TRHWjJmG2XgJYcXPOdxYlBlf3V3V6mXG/zJa1Uhpu5YuvLIHcpy3gnzmth709O4bnGuSa6Y7CAAEgXDlnjo9+AHrXi6PgxpkI/ZjFECK6anpFH5+PDxDm51Jfof4kxNSoVfVn3tADU3bQ6NmeKZmYRo3xpbNvyGoQ0lkRrOhw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773752121; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=bY4KGqTqEcM2o4+nGwsRQwEX89TAOhW7Y8KDW5BEpQ4=; b=eAaA41ZSN531q0zPBs7pIuFcsKBAQ+A6bZr5j2BRfbQYNcuV5rGtw0FCVCxMRSPN5n6JNTrhSVPdC/Jesk7A2Q9SQ3x/lIaRD2iRmTm4L7bmbarR1gHJHzQ4ce7Qb7p9WowjsUvPa+IeBBlb7f5TVi2mNGzbeMxYe39GG1otwzY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1773752121291622.6401160956228; Tue, 17 Mar 2026 05:55:21 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w2TwV-0008Vp-Vs; Tue, 17 Mar 2026 08:54:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w2Sl2-0003Sr-6p for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:46 -0400 Received: from mail-wm1-x332.google.com ([2a00:1450:4864:20::332]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w2Skx-0007sG-7K for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:43 -0400 Received: by mail-wm1-x332.google.com with SMTP id 5b1f17b1804b1-48535a0ef86so47057755e9.1 for ; Tue, 17 Mar 2026 04:38:38 -0700 (PDT) Received: from DesktopTC.localdomain (host-87-27-45-215.business.telecomitalia.it. [87.27.45.215]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4856eaee04fsm62721365e9.13.2026.03.17.04.38.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Mar 2026 04:38:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773747517; x=1774352317; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=bY4KGqTqEcM2o4+nGwsRQwEX89TAOhW7Y8KDW5BEpQ4=; b=ajqP3Rdr2tuI0IfzmuiUwD5Q1CvtVU7N9P0zatn8x9hoI9Pq7oEGr+CdWs1PmvM7HN ifO/aMEuulGnbDR7YNjJfhspegEp37vRxMMkimC85RArojMibbb2JIBJAAS2Pg1wMjY8 YVUZRjovvZIvWB4Ga0sSfLRymPHlw1LNKs5yFmVxmsu1prUaxTNePmPD5F06PDDKpq6P dRYnhwi4qFoRPvNQ1zxpnofTf5QQ7SXpGdVEC1JUyd6VWw7wbFikQkdTfai4D7hFfPr9 zm/U7H63XxwG1TKKoeRCRFnoI5A9mV3pc+MJNDlreEpCikJnvcQSSb4Fz3m/u1PG+d3k qsyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773747517; x=1774352317; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=bY4KGqTqEcM2o4+nGwsRQwEX89TAOhW7Y8KDW5BEpQ4=; b=ErzLOoVVMWwZieTbsBcPD65rqgTPgmmNdG/g7rLPb9sC557arAcZt5auTwCWFgJBLU 5R7Q/2mCQ9E6uwjY+Jeufp66/ozoKFFly0tdAroa73a0WWxK8ujE4VDiA/Rra7bYNRhL GOLFkxarroZI2Yszt19LM+MDkf8jydT15fAw4+F0Tl0jdmkpaqnu4WgQaKCjvAgJORvE 7fmj93kx4PMy+Sw69jn4zUz5QjSFU9recA6asA+aUCtMqmBUsDWtB9SHH/pO/CnX2jm4 wF+KVsioXVDSMWXsJoy4SaiI6HxmEYPddSbaPi4gaQtfkfl2DhsXegF2AwvGjXDJXlbd Y2wg== X-Gm-Message-State: AOJu0YwOj6ZQGakP3mkk4UdEdSX59wapstMzR66zgrSkUHxyuVqsVHbj a2NHepGXEoaODfsnZ5iPf79QAPw2WxiMKqanEJsjEKGEfGCZXK73O5pPAAZwE303 X-Gm-Gg: ATEYQzzhQDAnk3R9g3jiS9TMR89zNEZHR17Q6fjOKnA2ea4tr6BCfQrtj6end3bpJyU ure2O6Yn4+Od9Xrkfh87yur7/DGeloKeHbAwMhxAeFz6ok3wvEUtiD2+mnQ81x/3j+2IKJ94h2c +KGJeL2soVmVGIh2afOTysWam9veR7PBbQ/TBmUDGzwRWDdsYjihm35nwaxCkC0zRPpvYY6lZp9 /jO540HvSaqHPsulWW4r3wuAcMs5HaW8nSJsa3uxV0Wb2ap6XAc1X/gtJyuw6uwmG6UoBhegQ/v EM5rYj98VouINfKP59vS+Kkr+IJRa+VXWwDrxWInJA82l2fVQxhb/6J/rt5HaCma+FOAp+cVtI6 qMWW3zuXmYbzokpudfxrp0XCXOXNYSabRLwUurR6Bc3cvw+GtLGR8j67z28ZB2kITmz9RGwkgXP +JShUJJf9DkjPzLxuj7roJGPZQ3rfzbl0tgYlXeE8BZDZfPVPCIIFK9wxla5VY4eFn7i7X2BWvu z1EMkuuc56SVSrPgocL X-Received: by 2002:a05:600c:a09:b0:483:9139:4c1d with SMTP id 5b1f17b1804b1-485566e1a4cmr296742155e9.14.1773747516835; Tue, 17 Mar 2026 04:38:36 -0700 (PDT) From: Tommaso Califano To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, Eduardo Habkost , Markus Armbruster , Zhao Liu , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Marcelo Tosatti , Eric Blake , Oliver Steffen , Stefano Garzarella , Giuseppe Lettieri , Paolo Bonzini , Luigi Leonardi , Richard Henderson , Tommaso Califano Subject: [PATCH 2/5] target/i386: Add MSR SEV support and C-bit reset on TCG Date: Tue, 17 Mar 2026 12:38:37 +0100 Message-ID: <20260317113840.33017-3-califano.tommaso@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260317113840.33017-1-califano.tommaso@gmail.com> References: <20260317113840.33017-1-califano.tommaso@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::332; envelope-from=califano.tommaso@gmail.com; helo=mail-wm1-x332.google.com X-Spam_score_int: -3 X-Spam_score: -0.4 X-Spam_bar: / X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, MIME_BASE64_TEXT=1.741, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 17 Mar 2026 08:54:34 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1773752121989158500 Content-Type: text/plain; charset="utf-8" Exposing SEV CPUID leaf informs the guest of SEV support, but activation of the features requires setting bit 0 in the SEV MSR (0xc0010131). sev_emulated_enable() is implemented to enable the MSR only when emulation is active. This is invoked from helper_rdmsr() to control MSR write behavior. SEV MSR activation prompts OVMF to use C-bits in PTEs, altering paging. To address this, C-bits are reset in all PTEs and CR3 via sev_emulated_convert_pte(). This change enables the features of the guest adding to QEMU arguments: -cpu "EPYC-Milan" \ -accel tcg \ -object sev-emulated,id=3Dsev0,cbitpos=3D47,reduced-phys-bits=3D1 \ -machine memory-encryption=3Dsev0 A SEV capable cpu profile must be selected to enable the emulation. Signed-off-by: Tommaso Califano --- target/i386/cpu.h | 2 ++ target/i386/sev.c | 18 ++++++++++++++++ target/i386/sev.h | 3 +++ target/i386/tcg/system/excp_helper.c | 31 ++++++++++++++++++++++++++++ target/i386/tcg/system/misc_helper.c | 13 ++++++++++++ 5 files changed, 67 insertions(+) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 0b539155c4..dc2f82837f 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -659,6 +659,8 @@ typedef enum X86Seg { #define ESA_FEATURE_ALIGN64_MASK (1U << ESA_FEATURE_ALIGN64_BIT) #define ESA_FEATURE_XFD_MASK (1U << ESA_FEATURE_XFD_BIT) =20 +/* AMD SEV MSR */ +#define MSR_AMD64_SEV 0xc0010131 =20 /* CPUID feature bits available in XCR0 */ #define CPUID_XSTATE_XCR0_MASK (XSTATE_FP_MASK | XSTATE_SSE_MASK | \ diff --git a/target/i386/sev.c b/target/i386/sev.c index 2502e860e2..cdadd83ab5 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -690,6 +690,14 @@ static int sev_set_cpu_context(uint16_t cpu_index, con= st void *ctx, return 0; } =20 +bool +sev_emulated_enabled(void) +{ + ConfidentialGuestSupport *cgs =3D MACHINE(qdev_get_machine())->cgs; + + return !!object_dynamic_cast(OBJECT(cgs), TYPE_SEV_EMULATED); +} + bool sev_enabled(void) { @@ -731,6 +739,16 @@ sev_get_reduced_phys_bits(void) return sev_common ? sev_common->reduced_phys_bits : 0; } =20 +uint64_t +sev_emulated_convert_pte(uint64_t pte) +{ + if (unlikely(sev_emulated_enabled())) { + pte &=3D ~(1ULL << sev_get_cbit_position()); + } + + return pte; +} + static SevInfo *sev_get_info(void) { SevInfo *info; diff --git a/target/i386/sev.h b/target/i386/sev.h index 839656e2be..d69275d40f 100644 --- a/target/i386/sev.h +++ b/target/i386/sev.h @@ -24,10 +24,12 @@ #define sev_enabled() 0 #define sev_es_enabled() 0 #define sev_snp_enabled() 0 +#define sev_emulated_enabled() 0 #else bool sev_enabled(void); bool sev_es_enabled(void); bool sev_snp_enabled(void); +bool sev_emulated_enabled(void); #endif =20 #if !defined(CONFIG_USER_ONLY) @@ -197,5 +199,6 @@ void pc_system_parse_sev_metadata(uint8_t *flash_ptr, s= ize_t flash_size); =20 uint32_t sev_get_cbit_position(void); uint32_t sev_get_reduced_phys_bits(void); +uint64_t sev_emulated_convert_pte(uint64_t); =20 #endif diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/= excp_helper.c index d7ea77c855..307a4a7e6b 100644 --- a/target/i386/tcg/system/excp_helper.c +++ b/target/i386/tcg/system/excp_helper.c @@ -26,6 +26,7 @@ #include "exec/target_page.h" #include "exec/tlb-flags.h" #include "tcg/helper-tcg.h" +#include "sev.h" =20 typedef struct TranslateParams { target_ulong addr; @@ -160,7 +161,13 @@ static bool mmu_translate(CPUX86State *env, const Tran= slateParams *in, int prot; =20 restart_all: +#ifdef CONFIG_SEV + rsvd_mask =3D ~MAKE_64BIT_MASK(0, + env_archcpu(env)->phys_bits - sev_get_reduced_phys_bits()); + rsvd_mask =3D sev_emulated_convert_pte(rsvd_mask); +#else rsvd_mask =3D ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits); +#endif rsvd_mask &=3D PG_ADDRESS_MASK; if (!(pg_mode & PG_MODE_NXE)) { rsvd_mask |=3D PG_NX_MASK; @@ -179,6 +186,9 @@ static bool mmu_translate(CPUX86State *env, const Trans= lateParams *in, } restart_5: pte =3D ptw_ldq(&pte_trans, ra); + #ifdef CONFIG_SEV + pte =3D sev_emulated_convert_pte(pte); + #endif if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } @@ -203,6 +213,9 @@ static bool mmu_translate(CPUX86State *env, const Trans= lateParams *in, } restart_4: pte =3D ptw_ldq(&pte_trans, ra); + #ifdef CONFIG_SEV + pte =3D sev_emulated_convert_pte(pte); + #endif if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } @@ -223,6 +236,9 @@ static bool mmu_translate(CPUX86State *env, const Trans= lateParams *in, } restart_3_lma: pte =3D ptw_ldq(&pte_trans, ra); + #ifdef CONFIG_SEV + pte =3D sev_emulated_convert_pte(pte); + #endif if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } @@ -251,6 +267,9 @@ static bool mmu_translate(CPUX86State *env, const Trans= lateParams *in, rsvd_mask |=3D PG_HI_USER_MASK; restart_3_nolma: pte =3D ptw_ldq(&pte_trans, ra); + #ifdef CONFIG_SEV + pte =3D sev_emulated_convert_pte(pte); + #endif if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } @@ -272,6 +291,9 @@ static bool mmu_translate(CPUX86State *env, const Trans= lateParams *in, } restart_2_pae: pte =3D ptw_ldq(&pte_trans, ra); + #ifdef CONFIG_SEV + pte =3D sev_emulated_convert_pte(pte); + #endif if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } @@ -297,6 +319,9 @@ static bool mmu_translate(CPUX86State *env, const Trans= lateParams *in, return false; } pte =3D ptw_ldq(&pte_trans, ra); + #ifdef CONFIG_SEV + pte =3D sev_emulated_convert_pte(pte); + #endif if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } @@ -316,6 +341,9 @@ static bool mmu_translate(CPUX86State *env, const Trans= lateParams *in, } restart_2_nopae: pte =3D ptw_ldl(&pte_trans, ra); + #ifdef CONFIG_SEV + pte =3D sev_emulated_convert_pte(pte); + #endif if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } @@ -344,6 +372,9 @@ static bool mmu_translate(CPUX86State *env, const Trans= lateParams *in, return false; } pte =3D ptw_ldl(&pte_trans, ra); + #ifdef CONFIG_SEV + pte =3D sev_emulated_convert_pte(pte); + #endif if (!(pte & PG_PRESENT_MASK)) { goto do_fault; } diff --git a/target/i386/tcg/system/misc_helper.c b/target/i386/tcg/system/= misc_helper.c index bb79d4e470..aa6ed5cda1 100644 --- a/target/i386/tcg/system/misc_helper.c +++ b/target/i386/tcg/system/misc_helper.c @@ -27,6 +27,7 @@ #include "exec/cputlb.h" #include "tcg/helper-tcg.h" #include "hw/i386/apic.h" +#include "target/i386/sev.h" =20 void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) { @@ -89,6 +90,10 @@ void helper_write_crN(CPUX86State *env, int reg, target_= ulong t0) cpu_x86_update_cr0(env, t0); break; case 3: + #ifdef CONFIG_SEV + /* If SEV emulation is active, reset the C-bit */ + t0 =3D sev_emulated_convert_pte(t0); + #endif if ((env->efer & MSR_EFER_LMA) && (t0 & ((~0ULL) << env_archcpu(env)->phys_bits))) { cpu_vmexit(env, SVM_EXIT_ERR, 0, GETPC()); @@ -468,6 +473,14 @@ void helper_rdmsr(CPUX86State *env) case MSR_IA32_UCODE_REV: val =3D x86_cpu->ucode_rev; break; + case MSR_AMD64_SEV: + if (sev_emulated_enabled()) { + val =3D 1; + } else { + /* XXX: exception? */ + val =3D 0; + } + break; case MSR_CORE_THREAD_COUNT: { val =3D cpu_x86_get_msr_core_thread_count(x86_cpu); break; --=20 2.53.0 From nobody Mon Apr 6 23:29:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1773752103; cv=none; d=zohomail.com; s=zohoarc; b=buwveLncDzDhhw9vbxDzdziYRzYQn0Sw1U8ptohNrnbu0zTGIbOYTy/mz8wsz4927F1THMylEmWpqVSGxo5nZ91xs4sop/h1tQINOK+PECkyVwVGc584Who3VLsEofPRUWnWLnjcpVZ0F4P+8Ttl/uBLkZY0YUHaqMREOIB95U4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773752103; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Ku09qmzrODTSmfxYbubtxjPnJjnmpj9GC4sIO5Jhb34=; b=CpdkaLi3GebpDDE99aHtYIMbXkXmbE25HltfcYJ/xhxrl0r439JRKGTAjP5mHtvnfPgG1/MJd2tmxHxAyy4aG830FT8aR+96xrfFocxNIrYdT0672f+mj1qSsotdUHvlsrItMt+D8xrF2FkRcOzDIYnKJIuln70gXPZ9n/gfGWs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1773752103400541.3703796675342; Tue, 17 Mar 2026 05:55:03 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w2TwV-0008Vk-66; Tue, 17 Mar 2026 08:54:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w2Sl2-0003Su-7j for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:46 -0400 Received: from mail-wm1-x32c.google.com ([2a00:1450:4864:20::32c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w2Sky-0007sO-9m for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:43 -0400 Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-48538c5956bso6797525e9.0 for ; Tue, 17 Mar 2026 04:38:39 -0700 (PDT) Received: from DesktopTC.localdomain (host-87-27-45-215.business.telecomitalia.it. [87.27.45.215]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4856eaee04fsm62721365e9.13.2026.03.17.04.38.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Mar 2026 04:38:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773747518; x=1774352318; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Ku09qmzrODTSmfxYbubtxjPnJjnmpj9GC4sIO5Jhb34=; b=DgdnWjrRirWolBl5ZIq5Nl2ecAu72y6PPtMmYqfxWcPzXaCp9V/Uf7i9Sl31GUIxTI 4ZZ2pGFpmP0ksfuhvH74mUwiFNIXiXEprr6VfVRPC4KZDEXm1vwLO7u7kAhwkgfmlrUj IQIR0GLgMp1pIwG20guUHGlMsXwjwcZWbGv7dIK5EHdQS+Uqgbt4UQQBzhdTwG3yCcvu /MlEVgSd0DSik8p5SpUy5mKfgmmGRHmcLs+MWkgvzzk38Jy7jMspfmeM+BVvq/DJkqXc DQMEQyF8qES2OsyhpfQEISxTlO3K4b/fj8MSAMybxGu3Vij/nYWxjNHneyrt/wM3PGyt PrxQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773747518; x=1774352318; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Ku09qmzrODTSmfxYbubtxjPnJjnmpj9GC4sIO5Jhb34=; b=mvKSoeJ/IdrjL3Yixp0bYY3+ddTarcRud3VHvMJQCjLRjYJghnEETZbG+ZGEnHglz6 Jz1ji7Zf7Hgr6wzJiMQlGid1GZ+3RCAHUOFI0u+wD/rKxkxW0QtFd3rB3qePr0FMCPcE dd2CftSWkgJDC94y5vylKGScnAlXCcUOdIBlXbD73p3ciY+Rd5/VwROySmgp+6YdgzEg fWdCZioFZ4S8whF6qULqMz1njhzmMqh8Fy+qhOz2TJUBtuzlxVuCm5pei1Sn4Sxh/s4c nrhJZdV7YPnK4m/DV9gnzNcQIzNFDqqexXvR8aBUJ0AIf9/uaC6NJxIxkelAaUf/lwXq vJoQ== X-Gm-Message-State: AOJu0YzW5c1hIgK87az46WJzN3CYLxvSqWWW4X+VasVkVzOGG+PHZDGe LlAWxZjRZz8RFuiVCHwJL6TWf8uBKUbcyM+B26PyIikupgENrJAJyE9TBzlsyutg X-Gm-Gg: ATEYQzwI92N3jqtX1HMeOqxnL1o6BHiikgh60uRgZ1JXfxkegeTwtDLWWjG1F4THQoC yrb8sZLwzTSgfDqqIrKv631koTvzaw7JhzOxiwIKlH04sezX/YJDGSiX4wZkDcT4mHFbajyzSk2 lyDCzOuQsomtcVApYL64P5vXHJeNDItDsq5jX+Keug5zYJaFBsYycPaBoJs3zIVk19NYGe/6XAH eIOu2i3IYfcYy9WIOpxlKAhhrcf2mGrsmN4a3Gi8qMUmMarEwSmAod3T8ZkIJM277jj/4dSbtfZ joZ07HP4/m1DB/LuPHMK41yOIpGrqgCaAAbSaUWfX6lm8+bIVpo7I+V1bpVXyCaD1qS5vcUcyim XzNXNalLDwx36GZXQv+LtE/EEPKRp5Ru0uCO+RR9YcQUkaw7fDSBY0914DUprBZRy4+YdQHgY+9 9XDMz8EBbTFpPV+PZh3Ie5JlGNg8GR9UbQHBe4r0OXeV3rnTE6I8MT52jpSNnHUm8izTtNXSAwa aTyXdf/P6aO7nf7AG7v X-Received: by 2002:a05:600c:c4aa:b0:477:9890:9ab8 with SMTP id 5b1f17b1804b1-4856eaaa656mr52729155e9.3.1773747517861; Tue, 17 Mar 2026 04:38:37 -0700 (PDT) From: Tommaso Califano To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, Eduardo Habkost , Markus Armbruster , Zhao Liu , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Marcelo Tosatti , Eric Blake , Oliver Steffen , Stefano Garzarella , Giuseppe Lettieri , Paolo Bonzini , Luigi Leonardi , Richard Henderson , Tommaso Califano Subject: [PATCH 3/5] i386/sev: Implement SEV launch state sequence and query-sev Date: Tue, 17 Mar 2026 12:38:38 +0100 Message-ID: <20260317113840.33017-4-califano.tommaso@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260317113840.33017-1-califano.tommaso@gmail.com> References: <20260317113840.33017-1-califano.tommaso@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::32c; envelope-from=califano.tommaso@gmail.com; helo=mail-wm1-x32c.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 17 Mar 2026 08:54:34 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1773752104619154100 Content-Type: text/plain; charset="utf-8" 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=E2=80=94without= real cryptography needs=E2=80=94SEV_STATE_LAUNCH_START (crypto context initializ= ation) is skipped, proceeding directly to LAUNCH_UPDATE. Here, instead of encrypting firmware and (if kernel-hashes=3Don) 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=3Doff 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 --- 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, SevCommonStateClas= s, SEV_SNP_GUEST) #define FLAGS_SEGCACHE_TO_VMSA(flags) \ ((((flags) & 0xff00) >> 8) | (((flags) & 0xf00000) >> 12)) =20 +/* 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 { =20 typedef struct SevEmulatedState { SevGuestState parent_obj; + QEMUIOVector ld_data; } SevEmulatedState; =20 struct SevSnpGuestState { @@ -915,6 +922,12 @@ static SevCapability *sev_get_capabilities(Error **err= p) SevCommonState *sev_common; char *sev_device; =20 + 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_rep= ort(const char *mnonce, return NULL; } =20 + if (sev_emulated_enabled()) { + error_setg(errp, "SEV emulation does not support" + "attestation report"); + return NULL; + } + /* lets decode the mnonce string */ buf =3D g_base64_decode(mnonce, &len); if (!buf) { @@ -1752,6 +1771,21 @@ static int sev_kvm_type(X86ConfidentialGuest *cg) */ kvm_type =3D (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 !=3D KVM_X86_DEFAULT_VM) { + warn_report("Only legacy VM are supported in emulated mode:" + " using KVM_X86_DEFAULT_VM"); + kvm_type =3D KVM_X86_DEFAULT_VM; + } + sev_common->kvm_type =3D kvm_type; + goto out; + } + if (!kvm_is_vm_type_supported(kvm_type)) { if (sev_guest->legacy_vm_type =3D=3D ON_OFF_AUTO_AUTO) { error_report("SEV: host kernel does not support requested %s V= M 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 =3D SEV_COMMON(cgs); + SevGuestState *sev_guest =3D SEV_GUEST(sev_common); + SevEmulatedState *sev_emulated =3D SEV_EMULATED(sev_guest); + + sev_common->state =3D SEV_STATE_UNINIT; =20 /* * The cbitpos value will be placed in bit positions 5:0 of the EBX @@ -2999,15 +3037,53 @@ static int sev_emulated_init(ConfidentialGuestSuppo= rt *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 encry= pt. + * This avoids the launch start call. + */ + sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_UPDATE); + sev_common->sev_fd =3D INVALID_FD; + sev_common->build_id =3D FAKE_BUILD_ID; + sev_common->api_major =3D FAKE_API_MAJOR; + sev_common->api_minor =3D 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 =3D true; return 0; } =20 +static int sev_emulated_launch_update_data(SevCommonState *sev_common, + hwaddr gpa, uint8_t *addr, size_t len, Error **errp) +{ + SevEmulatedState *sev_emulated =3D 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 =3D SEV_COMMON_CLASS(oc); ConfidentialGuestSupportClass *klass =3D CONFIDENTIAL_GUEST_SUPPORT_CL= ASS(oc); - /* Override the sev-common method that uses kvm */ + /* Override the sev-common methods that use kvm */ klass->kvm_init =3D sev_emulated_init; + scc->launch_update_data =3D sev_emulated_launch_update_data; + scc->launch_finish =3D sev_emulated_launch_finish; } =20 /* guest info specific sev/sev-es */ --=20 2.53.0 From nobody Mon Apr 6 23:29:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1773752154; cv=none; d=zohomail.com; s=zohoarc; b=Md/Pmd7J1ajOtYFf4v1gmrtKkTsfK4jTDQIsAb6rhIRMcgBXNTxfUICIsELwoqx+hM7adPdMRoieAzn7CJOmHH9pR/x7BHuYHnIQvYh3K+SzeuOrlE0D/uxuF89XH/jxC1WpRgDyE+tlIoO0MPesWMyPGqPkVuwr7nadojONV3U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773752154; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=HnctF6qlKuP/O4jPD04oEBtM7p9ArQpqPxLkJHbnIDY=; b=Sfe2LG02G6dXz29ww09bj1MpfIXIj16FVjbYMNU0xhE/mbjHqtcUlR8bdSEVdwxJ+fOwynwoZxqCpuzcJCxW1c+xv0iDD6B7aF6Dxt7GHXCFl2o2vuamFd/wnA1FQVKcd0vvrKEvBVv/BBIbBC0HCJS9Dj6c8qKpKwua/VahPdA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1773752154979823.1233937471364; Tue, 17 Mar 2026 05:55:54 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w2Twa-00007J-BK; Tue, 17 Mar 2026 08:54:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w2Sl8-0003TY-7b for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:52 -0400 Received: from mail-wm1-x330.google.com ([2a00:1450:4864:20::330]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w2Sl1-0007sR-UX for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:47 -0400 Received: by mail-wm1-x330.google.com with SMTP id 5b1f17b1804b1-4853fd7b59aso34847605e9.2 for ; Tue, 17 Mar 2026 04:38:40 -0700 (PDT) Received: from DesktopTC.localdomain (host-87-27-45-215.business.telecomitalia.it. [87.27.45.215]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4856eaee04fsm62721365e9.13.2026.03.17.04.38.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Mar 2026 04:38:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773747519; x=1774352319; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=HnctF6qlKuP/O4jPD04oEBtM7p9ArQpqPxLkJHbnIDY=; b=GNtH5DdBy96pLfCJFhcIhQbLBOzVk9rkw8Jw939jyy5QH7umx8pk0Bm8axqKvG68a+ Y26SrfzVvOgXJreIQhFvNJNh5DKen0FCAJHU3kTUTEzxpQg9z14FS4nVp7z87voCKz4P cY+hJPj0dvxe8apPNQymT50PlkpNK+9eVnBU/qZFw/fIsv+siM8UaczS34ktxinRfRtC 7alzR5HID+ErBDNLzpzv74n41HQyHApjskez5fgXC+wqpHcjEB7LEbSZzo0PSSnfRLOf KAMLo+n2r65iGDNLuYVCri9VYwFnIUKwxTTjawN2EPUP1HPgU9rZ0K6BDklJSg1nIsZb L6hA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773747519; x=1774352319; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=HnctF6qlKuP/O4jPD04oEBtM7p9ArQpqPxLkJHbnIDY=; b=MD9oca9+CL1wk+qdzk3ypzCihO55t/Cq8jebj7QCTdUcPkToHWz/JZpahXWADy6XDk 1s4QFpGs0eYANlkhcwcYPA+A2e2PZSWrZvK39cL4LIGkRVCcUj6hIjVzQ8nzFeMT8iZZ o5YLe/GK+Dbny2DmRaGIKBH0aivEIgQONxMGLxaanjM7k6rL9T0Tr2nA5KkCNwzrDAO+ 3EFxjtDsZPmGz+1HNj8G4b0qHUsXCuzNuyYIvhm+NhsAeTpbjqabuz94LoVII2cWQdHP p2WD37bDZxkfOh0b2jI9mBBm2+5J0FGOif61lKwvu/YhdJvkZbULf68Q2iruk3YoRWtU /tKQ== X-Gm-Message-State: AOJu0YzLCWHhMZCZe4FEGdPqS3wdFKHUAFnsQkJt2OcC4EwXkpxep1kY 3dKvJysB75dF7VQeiLC+oORhXunXeJtDQFTj2DKWXmGBuCwvLhEFKXNWkdn7KqdM X-Gm-Gg: ATEYQzzLhYohRN5Gb0PSrU9yQNCAbLa+EI+AQ7ThD3X3+rchhH/pzN0Gb1X1JepsaSb QV0dmrQj5RMwjRv+yuVRyXYbiC21M3Bo8e+K5tLVW/F270wV45U3kNx253vzFuhnolKBlLDr1KG d+dNzFMd/ti4VA+T3i1CAEcviJg7JVj38Fr4EhZ+OP1YK0HgRSWM8ryUIVy63H1oL+Z+SOXynKo qefwNSrfkfKvJV+hFGnxQKU0hXvNbg/WV26dkeZP2kI8JMaCaFMS/29WEkD2EGcI8tvSBzu5UUH ljTjOtgsERaFmyZ3QCqN7KUJFNOtembXhmoVIzud6pzJy00+lPiMEEcWLi6AKg85tBa+aeBy1x5 Tz33vMXONcY2I2LmMhPTALo2M09W9GsMV8q0JXoa772g8BQqbzX+qAcO9s4hwKGw5XqjlZRu5q+ GZJ3a6sQm9fBzk1LJs0dOwKrjbF9Lw0BJW4XuM8Nk32FrPQ0IQ+c4Q0oFz8b0oW4DaHfLKG9Mth NhUmojLE2vy+cFQqvoaEIsZmXA5rDU= X-Received: by 2002:a05:600c:5251:b0:485:3ff1:d5c5 with SMTP id 5b1f17b1804b1-485566cdc17mr272033305e9.7.1773747519106; Tue, 17 Mar 2026 04:38:39 -0700 (PDT) From: Tommaso Califano To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, Eduardo Habkost , Markus Armbruster , Zhao Liu , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Marcelo Tosatti , Eric Blake , Oliver Steffen , Stefano Garzarella , Giuseppe Lettieri , Paolo Bonzini , Luigi Leonardi , Richard Henderson , Tommaso Califano Subject: [PATCH 4/5] i386/sev: Add launch measurement emulation and TIK property Date: Tue, 17 Mar 2026 12:38:39 +0100 Message-ID: <20260317113840.33017-5-califano.tommaso@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260317113840.33017-1-califano.tommaso@gmail.com> References: <20260317113840.33017-1-califano.tommaso@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::330; envelope-from=califano.tommaso@gmail.com; helo=mail-wm1-x330.google.com X-Spam_score_int: -3 X-Spam_score: -0.4 X-Spam_bar: / X-Spam_report: (-0.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, MIME_BASE64_TEXT=1.741, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 17 Mar 2026 08:54:34 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1773752157171154100 Content-Type: text/plain; charset="utf-8" The next step for completing the SEV launch emulation is to implement the "query-sev-launch-measure" feature, responsible for returning the measurement. In this case the measurement will be computed in QEMU. Implement sev_emulated_launch_get_measure() to emulate the LAUNCH_MEASURE command per AMD SEV API spec section 6.5.1. It generates a random 16-byte mnonce, computes the launch digest as SHA-256 over ld_data, then derives the measurement via HMAC-SHA256 (TIK;0x04|| API version || build ID || policy || launch digest || mnonce). The base64-encoded result (32-byte HMAC + 16-byte mnonce) populates "query-sev-launch-measure" data, advancing state to LAUNCH_SECRET for secret injection. The TIK is supplied via 16-byte binary file specified in new SevEmulatedProperty "tik" path; absent this, keys default to zeroed. Example QEMU arguments with the key passed: -cpu "EPYC-Milan" \ -accel tcg \ -object sev-emulated,id=3Dsev0,cbitpos=3D47,reduced-phys-bits=3D1,\ tik=3D/path/to/tik.bin \ -machine memory-encryption=3Dsev0 Signed-off-by: Tommaso Califano --- qapi/qom.json | 3 +- target/i386/sev.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/qapi/qom.json b/qapi/qom.json index 35cda819ec..affb5024b5 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1064,11 +1064,12 @@ # This object functionally emulates AMD SEV hardware via TCG, so # it does not require real hardware to run. # +# @tik: binary file of the SEV TIK (default: all 0). # Since: 10.1.0 ## { 'struct': 'SevEmulatedProperties', 'base': 'SevGuestProperties', - 'data': {}} + 'data': {'*tik': 'str'}} =20 ## # @SevSnpGuestProperties: diff --git a/target/i386/sev.c b/target/i386/sev.c index 5904f2c983..5b1c001633 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -48,6 +48,8 @@ #include "hw/i386/e820_memory_layout.h" #include "qemu/queue.h" #include "qemu/cutils.h" +#include "crypto/hmac.h" +#include "crypto/random.h" =20 OBJECT_DECLARE_TYPE(SevCommonState, SevCommonStateClass, SEV_COMMON) OBJECT_DECLARE_TYPE(SevGuestState, SevCommonStateClass, SEV_GUEST) @@ -72,6 +74,9 @@ OBJECT_DECLARE_TYPE(SevSnpGuestState, SevCommonStateClass= , SEV_SNP_GUEST) #define FAKE_API_MAJOR 1 #define FAKE_API_MINOR 40 =20 +/* SEV TEK, TIK and IV size in byte for emulation */ +#define TEK_TIK_IV_SIZE 16 + typedef struct QEMU_PACKED SevHashTableEntry { QemuUUID guid; uint16_t len; @@ -197,6 +202,7 @@ struct SevGuestState { =20 typedef struct SevEmulatedState { SevGuestState parent_obj; + uint8_t *tik; QEMUIOVector ld_data; } SevEmulatedState; =20 @@ -1431,6 +1437,89 @@ sev_launch_get_measure(Notifier *notifier, void *unu= sed) trace_kvm_sev_launch_measurement(sev_guest->measurement); } =20 +static void +sev_emulated_launch_get_measure(Notifier *notifier, void *unused) +{ + SevCommonState *sev_common =3D SEV_COMMON(MACHINE(qdev_get_machine())-= >cgs); + SevGuestState *sev_guest =3D SEV_GUEST(sev_common); + SevEmulatedState *sev_emulated =3D SEV_EMULATED(sev_guest); + + uint8_t prefix =3D 0x04; + uint8_t concat_data[56]; + uint8_t mnonce[16]; + uint8_t *hmac_raw; + uint8_t *ld; + gsize hmac_len, ld_len; + GByteArray *measure_raw =3D g_byte_array_sized_new(48); + QCryptoHmac *hmac =3D NULL; + Error *err =3D NULL; + + if (!sev_check_state(sev_common, SEV_STATE_LAUNCH_UPDATE)) { + return; + } + + /* Generate the mnonce (16B) */ + if (qcrypto_random_bytes(mnonce, sizeof(mnonce), &err) < 0) { + error_report_err(err); + return; + } + + /* Compute the Launch Digest (ld) */ + if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALGO_SHA256, sev_emulated->ld_dat= a.iov, + sev_emulated->ld_data.niov, &ld, &ld_len, &err) < = 0){ + error_report_err(err); + return; + } + assert(ld_len =3D=3D HASH_SIZE); + + /* + * The HMAC is calculated as specified in SEV API spec in section 6.5.= 1: + * HMAC(0x04 || API_MAJOR || API_MINOR || BUILD || GCTX.POLICY + * || GCTX.LD || MNONCE; GCTX.TIK) + */ + concat_data[0] =3D prefix; + concat_data[1] =3D sev_common->api_major; + concat_data[2] =3D sev_common->api_minor; + concat_data[3] =3D sev_common->build_id; + memcpy(&concat_data[4], &sev_guest->policy, 4); + memcpy(&concat_data[8], ld, ld_len); + memcpy(&concat_data[40], mnonce, 16); + + g_free(ld); + + /* Initialize HMAC with TIK */ + hmac =3D qcrypto_hmac_new(QCRYPTO_HASH_ALGO_SHA256, + (uint8_t *)sev_emulated->tik, + TEK_TIK_IV_SIZE, + &err); + if (!hmac) { + error_report_err(err); + return; + } + + /* Compute the HMAC */ + if (qcrypto_hmac_bytes(hmac, (char *)concat_data, sizeof(concat_data), + &hmac_raw, &hmac_len, &err) < 0) { + error_report_err(err); + qcrypto_hmac_free(hmac); + return; + } + qcrypto_hmac_free(hmac); + assert(hmac_len =3D=3D HASH_SIZE); + + /* Construct the measurement: HMAC(32B) + mnonce(16B) */ + g_byte_array_append(measure_raw, hmac_raw, 32); + g_byte_array_append(measure_raw, mnonce, 16); + + g_free(hmac_raw); + + sev_guest->measurement =3D + g_base64_encode(measure_raw->data, measure_raw->len); + g_byte_array_free(measure_raw, TRUE); + + sev_set_guest_state(sev_common, SEV_STATE_LAUNCH_SECRET); +} + static char *sev_get_launch_measurement(void) { ConfidentialGuestSupport *cgs =3D MACHINE(qdev_get_machine())->cgs; @@ -1466,6 +1555,10 @@ static Notifier sev_machine_done_notify =3D { .notify =3D sev_launch_get_measure, }; =20 +static Notifier sev_emu_machine_done_notify =3D { + .notify =3D sev_emulated_launch_get_measure, +}; + static void sev_launch_finish(SevCommonState *sev_common) { @@ -3054,6 +3147,9 @@ static int sev_emulated_init(ConfidentialGuestSupport= *cgs, Error **errp) qemu_add_vm_change_state_handler(sev_vm_state_change, sev_common); =20 cgs->ready =3D true; + + qemu_add_machine_init_done_notifier(&sev_emu_machine_done_notify); + return 0; } =20 @@ -3076,6 +3172,48 @@ sev_emulated_launch_finish(SevCommonState *sev_commo= n) sev_set_guest_state(sev_common, SEV_STATE_RUNNING); } =20 +static void sev_emulated_read_key(uint8_t *key, + const char *key_filename, Error **errp) +{ + gsize len; + FILE *fp =3D fopen(key_filename, "rb"); + + if (!fp) { + error_setg(errp, "SEV-EMULATED: Failed to open %s", key_filename); + return; + } + + len =3D fread(key, 1, TEK_TIK_IV_SIZE, fp); + + fclose(fp); + + if (len !=3D TEK_TIK_IV_SIZE) { + error_setg(errp, "parameter length: key size %" G_GSIZE_FORMAT + " is not equal to %u", + len, TEK_TIK_IV_SIZE); + return; + } +} + +static char *sev_emulated_get_tik(Object *obj, Error **errp) +{ + SevEmulatedState *sev_emulated =3D SEV_EMULATED(obj); + + return g_memdup2(sev_emulated->tik, TEK_TIK_IV_SIZE); +} + +static void sev_emulated_set_tik( + Object *obj, const char *key_filename, Error **errp) +{ + SevEmulatedState *sev_emulated =3D SEV_EMULATED(obj); + + sev_emulated_read_key( + sev_emulated->tik, + key_filename, + errp + ); +} + static void sev_emulated_class_init(ObjectClass *oc, const void *data) { SevCommonStateClass *scc =3D SEV_COMMON_CLASS(oc); @@ -3084,6 +3222,22 @@ static void sev_emulated_class_init(ObjectClass *oc,= const void *data) klass->kvm_init =3D sev_emulated_init; scc->launch_update_data =3D sev_emulated_launch_update_data; scc->launch_finish =3D sev_emulated_launch_finish; + + /* Adding emulation specific property */ + object_class_property_add_str(oc, "tik", + sev_emulated_get_tik, + sev_emulated_set_tik); + object_class_property_set_description(oc, "tik", + "Path to the binary file containing the" + "SEV Transport Integrity Key (16 bytes)"); +} + +static void sev_emulated_instance_init(Object *obj) +{ + SevEmulatedState *sev_emulated =3D SEV_EMULATED(obj); + + /* Initialize the key for emulation */ + sev_emulated->tik =3D g_malloc0(TEK_TIK_IV_SIZE); } =20 /* guest info specific sev/sev-es */ @@ -3100,6 +3254,7 @@ static const TypeInfo sev_emulated_info =3D { .parent =3D TYPE_SEV_GUEST, .name =3D TYPE_SEV_EMULATED, .instance_size =3D sizeof(SevEmulatedState), + .instance_init =3D sev_emulated_instance_init, .class_init =3D sev_emulated_class_init }; =20 --=20 2.53.0 From nobody Mon Apr 6 23:29:14 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1773752155; cv=none; d=zohomail.com; s=zohoarc; b=NuLXda6L2LyFzfdIix151kzKaFnyykB3zGpS07OnDrg8tZ/4IMjeXDAkAN11qa5XSCG/S7l/KpqAIp5lvsCC4gybCOF/pGf24xPLwtx2LjRt2Wqi0gZknYuwkAkPLf+c+22HcXaADX6CnP/l1Lc7hbOwROJfr+odauz1XeBJ7cs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773752155; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=f/Z6YxY4bjtcLuIq1xD2AVGk/omLNPN8GtNtXsnHqh4=; b=KzqAGYO2J37AfaOHR4ecKFwptQDjOmn9QcT4Pqq8fmyN2a7Y03B5McmiSSJkP3tVRDdg/xaqg+KysXKk0jXRNMvbmzxMq2ujfcFCyJ3se8oUGE7latqORgSvxuVjkdxNm+IpJg8YJP0zfefKlz+/6N9yNQfcvFioEu1Wp0WQZdY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1773752155776650.8407808870872; Tue, 17 Mar 2026 05:55:55 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w2TwW-0008W5-QR; Tue, 17 Mar 2026 08:54:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1w2Sl8-0003TZ-7a for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:52 -0400 Received: from mail-wm1-x32a.google.com ([2a00:1450:4864:20::32a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1w2Sl1-0007sX-V0 for qemu-devel@nongnu.org; Tue, 17 Mar 2026 07:38:47 -0400 Received: by mail-wm1-x32a.google.com with SMTP id 5b1f17b1804b1-4853aec185aso46339015e9.1 for ; Tue, 17 Mar 2026 04:38:41 -0700 (PDT) Received: from DesktopTC.localdomain (host-87-27-45-215.business.telecomitalia.it. [87.27.45.215]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4856eaee04fsm62721365e9.13.2026.03.17.04.38.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Mar 2026 04:38:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773747520; x=1774352320; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=f/Z6YxY4bjtcLuIq1xD2AVGk/omLNPN8GtNtXsnHqh4=; b=dZgjt1tuHtTQaV91SwAtR2ZRACg7l0Q1ecx9hk1SFMm3EuuFYhWGQNvKVLZgyVY/ZR AgdAXY5ZvfX4KZF9mGaMSJtBNcUExloAvZLjG/mpoKFHpAMkbdpUvStfVPBJfzPZ3Z4Z Tl/rSy2U2O5es1IBWb3mykOcyR6AzEpCY1gx7zsWXD6HG45CzHEGIFU0csN1sc9k/p2x 9h8Os/wya/h0kmSvd8PjubdsBZRp6pBk9nFFSRPc//UjnQT/RQHUzUwPrMuxenDuVWxA lE7O7gsR+OyHJq40o6RTykkYVjS4AJ78aShNYsYS21oDhtxzritmlc4MN3QryWe+BDJ4 j4Vg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773747520; x=1774352320; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=f/Z6YxY4bjtcLuIq1xD2AVGk/omLNPN8GtNtXsnHqh4=; b=JrVOhyT3GGxkdXM0vPPvzZ09T7VnrEOJD2DKyO/wYgNKFFq1+F7AWAdckykSJJ/g6e w8KqaEyQPg3ri0mhTLhtCu1hMM4TF+85pttwcVbJde2BFL+5mYNbCzKwqChFtz9IVMgw H2VELZkcZA2NC0GxKYCMacGYXDGFaB4XNM90iHffizYj0dStEMkkxuly9zXUoYdfwrap 9gxBTuk+MvoBkHTCme53nKd6Fk6KPPbg8oCoGT1thbCKOtHkMPAFieVQLNIwKBwdvvl5 Lvfek3jyEaytssP8ra6SZpWQGM/RFMk9qji2a3lrVVu5mtikC70wWJu42Zpt4EPW1Ehv gsPg== X-Gm-Message-State: AOJu0YxdfQmmy21BPgzb1givLka+HfkibxBZrmxAeGQbAYK6zTnE6C96 nAl17zZVQPsu4KXm0XjmineJnnPLMB53tknQSwcGpH2tIYdhmnEOQa7NdF0GT0eA X-Gm-Gg: ATEYQzzJOfNH95WC62xT54R+f1+8kZkjzbj2CweL76QP4Fpb0gHEbS9msunmcigzrV0 JYv+F2wUIhFnzXF2CZopkqNDqsZJJsUG6uMDIclp2elcKUR0mCVSkuOScd6RESM3HacuS2Jgpve H2lFXZYIqXh6m/RxGJm09wpOeg6anQDL7hy2yI/909DP4AnGhMwAdrUXrSxRWLVANs9NGogACHB yeKtGsH7jy4I7Au9GNR9vW14nhLukZRQCix+lX2g3kn7MvXl19r3SRxIJH3Inrg/9mjd2UzH44C HdKuOOxEQyOzI4JZolHnC9FXTUrvY0yrs6vikX7l7sIefitCAIIRyCQYuPIuqi1MRxgZ5SO4C4G ryXVK8GCkNo2JNpVI3B1lcAkfV2o+4qJG6anoaK1SjkKAjTEsn/aRxYC45FpxyFrqPCGNIlRzHp u3kKZj+I8syl8NJwHiVfL7cOnMWCFhn67oe3GCi8/+xVpIc96qqmd+qlvkw7ggbYv1A1rZYlqVS aW1qpNGWSi4AXWM7xQw X-Received: by 2002:a05:600c:4e4a:b0:485:4135:5c92 with SMTP id 5b1f17b1804b1-4855649360amr279452545e9.0.1773747520221; Tue, 17 Mar 2026 04:38:40 -0700 (PDT) From: Tommaso Califano To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, Eduardo Habkost , Markus Armbruster , Zhao Liu , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Marcelo Tosatti , Eric Blake , Oliver Steffen , Stefano Garzarella , Giuseppe Lettieri , Paolo Bonzini , Luigi Leonardi , Richard Henderson , Tommaso Califano Subject: [PATCH 5/5] i386/sev: Implement emulated launch secret injection and TEK property Date: Tue, 17 Mar 2026 12:38:40 +0100 Message-ID: <20260317113840.33017-6-califano.tommaso@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260317113840.33017-1-califano.tommaso@gmail.com> References: <20260317113840.33017-1-califano.tommaso@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::32a; envelope-from=califano.tommaso@gmail.com; helo=mail-wm1-x32a.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 17 Mar 2026 08:54:34 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1773752157439154100 Content-Type: text/plain; charset="utf-8" The final step to complete SEV attestation is the implementation of "sev-inject-launch-secret", which enables injecting a secret into guest memory. The function sev_emulated_injection() performs this step. It is invoked from the existing sev_inject_launch_secret() when sev_emulated_enabled() is active, allowing the bypass of the KVM_SEV_LAUNCH_SECRET ioctl. Upon invocation, it decrypts the secret packet using AES-128-CTR with the configured TEK, extracting the IV from header bytes 4=E2=80=9319, and writes the decrypted payload to the guest-specified memory address. After injection, the SEV state transitions to RUNNING, completing the TCG-emulated SEV launch sequence for testing guests without AMD SEV hardware. The TEK is provided through a 16-byte binary file, similar to the TIK, and specified via the new SevEmulatedProperty "tek" path. If unspecified, the key defaults to all zeroes. Example of all QEMU arguments: -cpu "EPYC-Milan" \ -accel tcg \ -object sev-emulated,id=3Dsev0,cbitpos=3D47,reduced-phys-bits=3D1,\ tik=3D/path/to/tik.bin,tek=3D/path/to/tek.bin \ -machine memory-encryption=3Dsev0 Signed-off-by: Tommaso Califano --- qapi/qom.json | 5 ++- target/i386/sev.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/qapi/qom.json b/qapi/qom.json index affb5024b5..405b6fc858 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1065,11 +1065,14 @@ # it does not require real hardware to run. # # @tik: binary file of the SEV TIK (default: all 0). +# +# @tek: binary file of the SEV TEK (default: all 0). # Since: 10.1.0 ## { 'struct': 'SevEmulatedProperties', 'base': 'SevGuestProperties', - 'data': {'*tik': 'str'}} + 'data': {'*tik': 'str', + '*tek': 'str' }} =20 ## # @SevSnpGuestProperties: diff --git a/target/i386/sev.c b/target/i386/sev.c index 5b1c001633..89b3fe3507 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -48,6 +48,7 @@ #include "hw/i386/e820_memory_layout.h" #include "qemu/queue.h" #include "qemu/cutils.h" +#include "crypto/cipher.h" #include "crypto/hmac.h" #include "crypto/random.h" =20 @@ -202,6 +203,7 @@ struct SevGuestState { =20 typedef struct SevEmulatedState { SevGuestState parent_obj; + uint8_t *tek; uint8_t *tik; QEMUIOVector ld_data; } SevEmulatedState; @@ -2219,6 +2221,58 @@ sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t= len, Error **errp) return 0; } =20 +static int sev_emulated_injection(void *hva, guchar *data, + gsize data_sz, guchar *hdr) +{ + + SevEmulatedState *sev_emulated =3D + SEV_EMULATED(MACHINE(qdev_get_machine())->cgs); + uint8_t iv[TEK_TIK_IV_SIZE]; + QCryptoCipher *cipher =3D NULL; + g_autofree guchar *plaintext =3D g_new0(guchar, data_sz); + int ret =3D 0; + Error *err =3D NULL; + + /* Prepare the cipher */ + cipher =3D qcrypto_cipher_new( + QCRYPTO_CIPHER_ALGO_AES_128, + QCRYPTO_CIPHER_MODE_CTR, + sev_emulated->tek, + TEK_TIK_IV_SIZE, + &err + ); + if (!cipher) { + error_report_err(err); + return 1; + } + + /* Extract the IV from the header */ + memcpy(iv, hdr + 4, TEK_TIK_IV_SIZE); + ret =3D qcrypto_cipher_setiv(cipher, iv, TEK_TIK_IV_SIZE, &err); + if (ret < 0) { + error_report_err(err); + qcrypto_cipher_free(cipher); + return 1; + } + + /* Decrypt the payload */ + ret =3D qcrypto_cipher_decrypt(cipher, + data, + plaintext, + data_sz, + &err); + if (ret < 0) { + error_report_err(err); + qcrypto_cipher_free(cipher); + return 1; + } + qcrypto_cipher_free(cipher); + memcpy(hva, plaintext, data_sz); + + return 0; +} + + int sev_inject_launch_secret(const char *packet_hdr, const char *secret, uint64_t gpa, Error **errp) { @@ -2273,6 +2327,15 @@ int sev_inject_launch_secret(const char *packet_hdr,= const char *secret, trace_kvm_sev_launch_secret(gpa, input.guest_uaddr, input.trans_uaddr, input.trans_len); =20 + /* + * If SEV emulation is enabled, skip the KVM ioctl (sev_fd =3D=3D -1) = and + * inject the secret directly into guest memory via + * sev_emulated_injection(). + */ + if (sev_emulated_enabled()) { + return sev_emulated_injection(hva, data, data_sz, hdr); + } + ret =3D sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_SECRET, &input, &error); if (ret) { @@ -3214,6 +3277,25 @@ static void sev_emulated_set_tik( ); } =20 +static char *sev_emulated_get_tek(Object *obj, Error **errp) +{ + SevEmulatedState *sev_emulated =3D SEV_EMULATED(obj); + + return g_memdup2(sev_emulated->tek, TEK_TIK_IV_SIZE); +} + +static void sev_emulated_set_tek( + Object *obj, const char *key_filename, Error **errp) +{ + SevEmulatedState *sev_emulated =3D SEV_EMULATED(obj); + + sev_emulated_read_key( + sev_emulated->tek, + key_filename, + errp + ); +} + static void sev_emulated_class_init(ObjectClass *oc, const void *data) { SevCommonStateClass *scc =3D SEV_COMMON_CLASS(oc); @@ -3223,7 +3305,14 @@ static void sev_emulated_class_init(ObjectClass *oc,= const void *data) scc->launch_update_data =3D sev_emulated_launch_update_data; scc->launch_finish =3D sev_emulated_launch_finish; =20 - /* Adding emulation specific property */ + /* Adding emulation specific properties */ + object_class_property_add_str(oc, "tek", + sev_emulated_get_tek, + sev_emulated_set_tek); + object_class_property_set_description(oc, "tek", + "Path to the binary file containing the" + "SEV Transport Encryption Key (16 bytes)"); + object_class_property_add_str(oc, "tik", sev_emulated_get_tik, sev_emulated_set_tik); @@ -3238,6 +3327,7 @@ static void sev_emulated_instance_init(Object *obj) =20 /* Initialize the key for emulation */ sev_emulated->tik =3D g_malloc0(TEK_TIK_IV_SIZE); + sev_emulated->tek =3D g_malloc0(TEK_TIK_IV_SIZE); } =20 /* guest info specific sev/sev-es */ --=20 2.53.0