public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
* [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support
@ 2026-03-17 11:38 Tommaso Califano
  2026-03-17 11:38 ` [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support Tommaso Califano
                   ` (5 more replies)
  0 siblings, 6 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-17 11:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson,
	Tommaso Califano

From: Tommaso Califano <califano.tommaso@gmail.com>

QEMU's AMD SEV support currently requires KVM on expensive AMD EPYC
hardware, limiting development and testing of SEV-aware guest software to
users with server-grade machines.

This series introduces a TCG-emulated SEV guest mode that enables SEV
validation without hardware dependencies, focusing on functional testing
rather than reproducing the hardware’s cryptographic context.

The emulation exposes SEV from the guest's perspective:
 - Exposed CPUID leaf 0x8000001F to indicate active support.
 - Active bit 0 in MSR 0xc0010131 to enable SEV on the guest.
 - C-bit manipulation in PTEs/CR3 for paging consistency with the host.
 - Complete SEV attestation workflow for injecting secrets into guest
   memory (including direct kernel boot support).

The emulation uses a new QOM object "sev-emulated", derived from
"sev-guest", to maximize reuse of the existing SEV infrastructure while
maintaining a compiling dependency with KVM.
Below are the pros and cons of this choice.

In addition to inherited guest properties, two new ones are added (binary
files; default all-zero):
 - tik: 16-byte Transport Integrity Key (TIK) for measurement HMAC.
 - tek: 16-byte Transport Encryption Key (TEK) for secret payload
   decryption.

Code reuse benefits:
 - SEV detection via sev_enabled() and TYPE_SEV_COMMON object cast enables
   the required checks for emulation without adding new conditions to the
   codebase.
 - QAPI fields for query-sev/launch-measure inherited from SevCommonState
   and SevGuestState.
 - Identical QMP interface (query-sev, query-sev-launch-measure,
   sev-inject-launch-secret) as real SEV.
 - Shared state machine (sev_set_guest_state()); override backend vtable
   only (kvm_init → sev_emulated_init, launch_update_data, launch_finish,
   sev_launch_get_measure).

Trade-offs:
 - KVM linkage: sev-guest is KVM-centric; even if KVM is not used at
   runtime, its code is required for compilation, so it is not possible to
   use emulation with --disable-kvm.

Example usage:

	-cpu "EPYC-Milan" \
	-accel tcg \
	-object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1,\
		tik=/path/to/tik.bin,tek=/path/to/tek.bin \
	-machine memory-encryption=sev0

Build requirements:

	../qemu/configure --enable-gcrypt --enable-crypto-afalg

These provide libgcrypt support for crypto/hmac.h, crypto/cipher.h, and
crypto/random.h, used for:
 - HMAC-SHA256 launch measurement (TIK key).
 - Secret payload decryption (TEK key).
Note: --disable-kvm unsupported due to sev-guest inheritance (KVM code
linked, no runtime dependency).

Tommaso Califano (5):
  i386/sev: Add sev-emulated QOM object with TCG support
  target/i386: Add MSR SEV support and C-bit reset on TCG
  i386/sev: Implement SEV launch state sequence and query-sev
  i386/sev: Add launch measurement emulation and TIK property
  i386/sev: Implement emulated launch secret injection and TEK property

 accel/tcg/tcg-all.c                  |  18 +-
 qapi/qom.json                        |  19 ++
 target/i386/cpu.h                    |   2 +
 target/i386/sev.c                    | 404 +++++++++++++++++++++++++++
 target/i386/sev.h                    |   4 +
 target/i386/tcg/system/excp_helper.c |  31 ++
 target/i386/tcg/system/misc_helper.c |  13 +
 7 files changed, 490 insertions(+), 1 deletion(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-17 11:38 [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Tommaso Califano
@ 2026-03-17 11:38 ` Tommaso Califano
  2026-03-19 12:31   ` Markus Armbruster
  2026-03-19 17:49   ` Daniel P. Berrangé
  2026-03-17 11:38 ` [PATCH 2/5] target/i386: Add MSR SEV support and C-bit reset on TCG Tommaso Califano
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-17 11:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson,
	Tommaso Califano

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 = *ebx = *ecx = *edx = 0;
    if (sev_enabled()) {
        *eax = 0x2;
        *eax |= sev_es_enabled() ? 0x8 : 0;
        *eax |= sev_snp_enabled() ? 0x10 : 0;
        *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
        *ebx |= (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=sev0,cbitpos=47,reduced-phys-bits=1 \
    -machine memory-encryption=sev0

To the QEMU start arguments.

Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
---
 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"
 
 struct TCGState {
     AccelState parent_obj;
@@ -107,6 +107,9 @@ static int tcg_init_machine(AccelState *as, MachineState *ms)
     unsigned max_threads = 1;
 
 #ifndef CONFIG_USER_ONLY
+    int ret;
+    Error *local_err = NULL;
+    const char *cgs_type = NULL;
     CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type()));
     bool mttcg_supported = cc->tcg_ops->mttcg_supported;
 
@@ -163,6 +166,19 @@ static int tcg_init_machine(AccelState *as, MachineState *ms)
 
 #ifdef CONFIG_USER_ONLY
     qdev_create_fake_machine();
+#else
+    /* TCG SEV/Confidential Guest Support init */
+    if (ms->cgs) {
+        cgs_type = object_get_typename(OBJECT(ms->cgs));
+
+        if (g_str_has_prefix(cgs_type, "sev-emulated")) {
+            ret = confidential_guest_kvm_init(ms->cgs, &local_err);
+            if (ret < 0) {
+                error_report_err(local_err);
+                return ret;
+            }
+        }
+    }
 #endif
 
     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' } }
 
+##
+# @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 @@
 
 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)
 
 /* hard code sha256 digest size */
@@ -177,6 +178,21 @@ struct SevGuestState {
     OnOffAuto legacy_vm_type;
 };
 
+/**
+ * SevEmulatedState:
+ *
+ * The SevEmulatedState object is used for creating and managing a SEV emulated
+ * guest.
+ *
+ * # $QEMU \
+ *         -object sev-emulated,id=sev0 \
+ *         -machine ...,memory-encryption=sev0
+ */
+
+typedef struct SevEmulatedState {
+    SevGuestState parent_obj;
+} SevEmulatedState;
+
 struct SevSnpGuestState {
     SevCommonState parent_obj;
 
@@ -2936,6 +2952,46 @@ sev_guest_instance_init(Object *obj)
     sev_guest->legacy_vm_type = ON_OFF_AUTO_AUTO;
 }
 
+static int sev_emulated_init(ConfidentialGuestSupport *cgs, Error **errp)
+{
+    SevCommonState *sev_common = 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 >=32",
+                   __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 = true;
+    return 0;
+}
+
+static void sev_emulated_class_init(ObjectClass *oc, const void *data)
+{
+    ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
+    /* Override the sev-common method that uses kvm */
+    klass->kvm_init = sev_emulated_init;
+}
+
 /* guest info specific sev/sev-es */
 static const TypeInfo sev_guest_info = {
     .parent = TYPE_SEV_COMMON,
@@ -2945,6 +3001,14 @@ static const TypeInfo sev_guest_info = {
     .class_init = sev_guest_class_init,
 };
 
+/* emulated sev */
+static const TypeInfo sev_emulated_info = {
+    .parent = TYPE_SEV_GUEST,
+    .name = TYPE_SEV_EMULATED,
+    .instance_size = sizeof(SevEmulatedState),
+    .class_init = 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)
 
 #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"
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 2/5] target/i386: Add MSR SEV support and C-bit reset on TCG
  2026-03-17 11:38 [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Tommaso Califano
  2026-03-17 11:38 ` [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support Tommaso Califano
@ 2026-03-17 11:38 ` Tommaso Califano
  2026-03-17 11:38 ` [PATCH 3/5] i386/sev: Implement SEV launch state sequence and query-sev Tommaso Califano
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-17 11:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson,
	Tommaso Califano

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=sev0,cbitpos=47,reduced-phys-bits=1 \
    -machine memory-encryption=sev0

A SEV capable cpu profile must be selected to enable the emulation.

Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
---
 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)
 
+/* AMD SEV MSR */
+#define MSR_AMD64_SEV                   0xc0010131
 
 /* 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, const void *ctx,
     return 0;
 }
 
+bool
+sev_emulated_enabled(void)
+{
+   ConfidentialGuestSupport *cgs = 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;
 }
 
+uint64_t
+sev_emulated_convert_pte(uint64_t pte)
+{
+    if (unlikely(sev_emulated_enabled())) {
+        pte &= ~(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
 
 #if !defined(CONFIG_USER_ONLY)
@@ -197,5 +199,6 @@ void pc_system_parse_sev_metadata(uint8_t *flash_ptr, size_t flash_size);
 
 uint32_t sev_get_cbit_position(void);
 uint32_t sev_get_reduced_phys_bits(void);
+uint64_t sev_emulated_convert_pte(uint64_t);
 
 #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"
 
 typedef struct TranslateParams {
     target_ulong addr;
@@ -160,7 +161,13 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
     int prot;
 
  restart_all:
+#ifdef CONFIG_SEV
+    rsvd_mask = ~MAKE_64BIT_MASK(0,
+        env_archcpu(env)->phys_bits - sev_get_reduced_phys_bits());
+    rsvd_mask = sev_emulated_convert_pte(rsvd_mask);
+#else
     rsvd_mask = ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits);
+#endif
     rsvd_mask &= PG_ADDRESS_MASK;
     if (!(pg_mode & PG_MODE_NXE)) {
         rsvd_mask |= PG_NX_MASK;
@@ -179,6 +186,9 @@ static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
                 }
             restart_5:
                 pte = ptw_ldq(&pte_trans, ra);
+            #ifdef CONFIG_SEV
+                pte = 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 TranslateParams *in,
             }
         restart_4:
             pte = ptw_ldq(&pte_trans, ra);
+        #ifdef CONFIG_SEV
+            pte = 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 TranslateParams *in,
             }
         restart_3_lma:
             pte = ptw_ldq(&pte_trans, ra);
+        #ifdef CONFIG_SEV
+            pte = 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 TranslateParams *in,
             rsvd_mask |= PG_HI_USER_MASK;
         restart_3_nolma:
             pte = ptw_ldq(&pte_trans, ra);
+        #ifdef CONFIG_SEV
+            pte = 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 TranslateParams *in,
         }
     restart_2_pae:
         pte = ptw_ldq(&pte_trans, ra);
+    #ifdef CONFIG_SEV
+        pte = 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 TranslateParams *in,
             return false;
         }
         pte = ptw_ldq(&pte_trans, ra);
+    #ifdef CONFIG_SEV
+        pte = 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 TranslateParams *in,
         }
     restart_2_nopae:
         pte = ptw_ldl(&pte_trans, ra);
+    #ifdef CONFIG_SEV
+        pte = 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 TranslateParams *in,
             return false;
         }
         pte = ptw_ldl(&pte_trans, ra);
+    #ifdef CONFIG_SEV
+        pte = 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"
 
 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 = 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 = x86_cpu->ucode_rev;
         break;
+    case MSR_AMD64_SEV:
+        if (sev_emulated_enabled()) {
+            val = 1;
+        } else {
+            /* XXX: exception? */
+            val = 0;
+        }
+        break;
     case MSR_CORE_THREAD_COUNT: {
         val = cpu_x86_get_msr_core_thread_count(x86_cpu);
         break;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/5] i386/sev: Implement SEV launch state sequence and query-sev
  2026-03-17 11:38 [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Tommaso Califano
  2026-03-17 11:38 ` [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support Tommaso Califano
  2026-03-17 11:38 ` [PATCH 2/5] target/i386: Add MSR SEV support and C-bit reset on TCG Tommaso Califano
@ 2026-03-17 11:38 ` Tommaso Califano
  2026-03-17 11:38 ` [PATCH 4/5] i386/sev: Add launch measurement emulation and TIK property Tommaso Califano
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-17 11:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson,
	Tommaso Califano

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


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 4/5] i386/sev: Add launch measurement emulation and TIK property
  2026-03-17 11:38 [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Tommaso Califano
                   ` (2 preceding siblings ...)
  2026-03-17 11:38 ` [PATCH 3/5] i386/sev: Implement SEV launch state sequence and query-sev Tommaso Califano
@ 2026-03-17 11:38 ` Tommaso Califano
  2026-03-19 12:33   ` Markus Armbruster
  2026-03-17 11:38 ` [PATCH 5/5] i386/sev: Implement emulated launch secret injection and TEK property Tommaso Califano
  2026-03-17 13:01 ` [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Luigi Leonardi
  5 siblings, 1 reply; 21+ messages in thread
From: Tommaso Califano @ 2026-03-17 11:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson,
	Tommaso Califano

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=sev0,cbitpos=47,reduced-phys-bits=1,\
					tik=/path/to/tik.bin \
	-machine memory-encryption=sev0

Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
---
 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'}}
 
 ##
 # @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"
 
 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
 
+/* 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 {
 
 typedef struct SevEmulatedState {
     SevGuestState parent_obj;
+    uint8_t *tik;
     QEMUIOVector ld_data;
 } SevEmulatedState;
 
@@ -1431,6 +1437,89 @@ sev_launch_get_measure(Notifier *notifier, void *unused)
     trace_kvm_sev_launch_measurement(sev_guest->measurement);
 }
 
+static void
+sev_emulated_launch_get_measure(Notifier *notifier, void *unused)
+{
+    SevCommonState *sev_common = SEV_COMMON(MACHINE(qdev_get_machine())->cgs);
+    SevGuestState *sev_guest = SEV_GUEST(sev_common);
+    SevEmulatedState *sev_emulated = SEV_EMULATED(sev_guest);
+
+    uint8_t prefix = 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 = g_byte_array_sized_new(48);
+    QCryptoHmac *hmac = NULL;
+    Error *err = 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_data.iov,
+                        sev_emulated->ld_data.niov, &ld, &ld_len, &err) < 0){
+        error_report_err(err);
+        return;
+    }
+    assert(ld_len == 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] = prefix;
+    concat_data[1] = sev_common->api_major;
+    concat_data[2] = sev_common->api_minor;
+    concat_data[3] = 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 = 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 == 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 =
+            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 = MACHINE(qdev_get_machine())->cgs;
@@ -1466,6 +1555,10 @@ static Notifier sev_machine_done_notify = {
     .notify = sev_launch_get_measure,
 };
 
+static Notifier sev_emu_machine_done_notify = {
+    .notify = 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);
 
     cgs->ready = true;
+
+    qemu_add_machine_init_done_notifier(&sev_emu_machine_done_notify);
+
     return 0;
 }
 
@@ -3076,6 +3172,48 @@ sev_emulated_launch_finish(SevCommonState *sev_common)
     sev_set_guest_state(sev_common, SEV_STATE_RUNNING);
 }
 
+static void sev_emulated_read_key(uint8_t *key,
+                                const char *key_filename, Error **errp)
+{
+    gsize len;
+    FILE *fp = fopen(key_filename, "rb");
+
+    if (!fp) {
+        error_setg(errp, "SEV-EMULATED: Failed to open %s", key_filename);
+        return;
+    }
+
+    len = fread(key, 1, TEK_TIK_IV_SIZE, fp);
+
+    fclose(fp);
+
+    if (len != 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 = 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 = 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 = SEV_COMMON_CLASS(oc);
@@ -3084,6 +3222,22 @@ static void sev_emulated_class_init(ObjectClass *oc, const void *data)
     klass->kvm_init = sev_emulated_init;
     scc->launch_update_data = sev_emulated_launch_update_data;
     scc->launch_finish = 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 = SEV_EMULATED(obj);
+
+    /* Initialize the key for emulation */
+    sev_emulated->tik = g_malloc0(TEK_TIK_IV_SIZE);
 }
 
 /* guest info specific sev/sev-es */
@@ -3100,6 +3254,7 @@ static const TypeInfo sev_emulated_info = {
     .parent = TYPE_SEV_GUEST,
     .name = TYPE_SEV_EMULATED,
     .instance_size = sizeof(SevEmulatedState),
+    .instance_init = sev_emulated_instance_init,
     .class_init = sev_emulated_class_init
 };
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 5/5] i386/sev: Implement emulated launch secret injection and TEK property
  2026-03-17 11:38 [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Tommaso Califano
                   ` (3 preceding siblings ...)
  2026-03-17 11:38 ` [PATCH 4/5] i386/sev: Add launch measurement emulation and TIK property Tommaso Califano
@ 2026-03-17 11:38 ` Tommaso Califano
  2026-03-17 13:01 ` [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Luigi Leonardi
  5 siblings, 0 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-17 11:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson,
	Tommaso Califano

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–19,
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=sev0,cbitpos=47,reduced-phys-bits=1,\
			tik=/path/to/tik.bin,tek=/path/to/tek.bin \
	-machine memory-encryption=sev0

Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
---
 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' }}
 
 ##
 # @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"
 
@@ -202,6 +203,7 @@ struct SevGuestState {
 
 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;
 }
 
+static int sev_emulated_injection(void *hva, guchar *data,
+                            gsize data_sz, guchar *hdr)
+{
+
+    SevEmulatedState *sev_emulated =
+                SEV_EMULATED(MACHINE(qdev_get_machine())->cgs);
+    uint8_t iv[TEK_TIK_IV_SIZE];
+    QCryptoCipher *cipher = NULL;
+    g_autofree guchar *plaintext = g_new0(guchar, data_sz);
+    int ret = 0;
+    Error *err = NULL;
+
+    /* Prepare the cipher */
+    cipher = 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 = 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 = 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);
 
+    /*
+     * If SEV emulation is enabled, skip the KVM ioctl (sev_fd == -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 = sev_ioctl(sev_common->sev_fd, KVM_SEV_LAUNCH_SECRET,
                     &input, &error);
     if (ret) {
@@ -3214,6 +3277,25 @@ static void sev_emulated_set_tik(
     );
 }
 
+static char *sev_emulated_get_tek(Object *obj, Error **errp)
+{
+    SevEmulatedState *sev_emulated = 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 = 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 = SEV_COMMON_CLASS(oc);
@@ -3223,7 +3305,14 @@ static void sev_emulated_class_init(ObjectClass *oc, const void *data)
     scc->launch_update_data = sev_emulated_launch_update_data;
     scc->launch_finish = sev_emulated_launch_finish;
 
-    /* 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)
 
     /* Initialize the key for emulation */
     sev_emulated->tik = g_malloc0(TEK_TIK_IV_SIZE);
+    sev_emulated->tek = g_malloc0(TEK_TIK_IV_SIZE);
 }
 
 /* guest info specific sev/sev-es */
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support
  2026-03-17 11:38 [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Tommaso Califano
                   ` (4 preceding siblings ...)
  2026-03-17 11:38 ` [PATCH 5/5] i386/sev: Implement emulated launch secret injection and TEK property Tommaso Califano
@ 2026-03-17 13:01 ` Luigi Leonardi
  5 siblings, 0 replies; 21+ messages in thread
From: Luigi Leonardi @ 2026-03-17 13:01 UTC (permalink / raw)
  To: Tommaso Califano
  Cc: qemu-devel, kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Richard Henderson

On Tue, Mar 17, 2026 at 12:38:35PM +0100, Tommaso Califano wrote:
>From: Tommaso Califano <califano.tommaso@gmail.com>
>
>QEMU's AMD SEV support currently requires KVM on expensive AMD EPYC
>hardware, limiting development and testing of SEV-aware guest software to
>users with server-grade machines.
>
>This series introduces a TCG-emulated SEV guest mode that enables SEV
>validation without hardware dependencies, focusing on functional testing
>rather than reproducing the hardware’s cryptographic context.
>
>The emulation exposes SEV from the guest's perspective:
> - Exposed CPUID leaf 0x8000001F to indicate active support.
> - Active bit 0 in MSR 0xc0010131 to enable SEV on the guest.
> - C-bit manipulation in PTEs/CR3 for paging consistency with the host.
> - Complete SEV attestation workflow for injecting secrets into guest
>   memory (including direct kernel boot support).
>
>The emulation uses a new QOM object "sev-emulated", derived from
>"sev-guest", to maximize reuse of the existing SEV infrastructure while
>maintaining a compiling dependency with KVM.
>Below are the pros and cons of this choice.
>
>In addition to inherited guest properties, two new ones are added (binary
>files; default all-zero):
> - tik: 16-byte Transport Integrity Key (TIK) for measurement HMAC.
> - tek: 16-byte Transport Encryption Key (TEK) for secret payload
>   decryption.
>
>Code reuse benefits:
> - SEV detection via sev_enabled() and TYPE_SEV_COMMON object cast enables
>   the required checks for emulation without adding new conditions to the
>   codebase.
> - QAPI fields for query-sev/launch-measure inherited from SevCommonState
>   and SevGuestState.
> - Identical QMP interface (query-sev, query-sev-launch-measure,
>   sev-inject-launch-secret) as real SEV.
> - Shared state machine (sev_set_guest_state()); override backend vtable
>   only (kvm_init → sev_emulated_init, launch_update_data, launch_finish,
>   sev_launch_get_measure).
>
>Trade-offs:
> - KVM linkage: sev-guest is KVM-centric; even if KVM is not used at
>   runtime, its code is required for compilation, so it is not possible to
>   use emulation with --disable-kvm.
>
>Example usage:
>
>	-cpu "EPYC-Milan" \
>	-accel tcg \
>	-object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1,\
>		tik=/path/to/tik.bin,tek=/path/to/tek.bin \
>	-machine memory-encryption=sev0
>
>Build requirements:
>
>	../qemu/configure --enable-gcrypt --enable-crypto-afalg
>
>These provide libgcrypt support for crypto/hmac.h, crypto/cipher.h, and
>crypto/random.h, used for:
> - HMAC-SHA256 launch measurement (TIK key).
> - Secret payload decryption (TEK key).
>Note: --disable-kvm unsupported due to sev-guest inheritance (KVM code
>linked, no runtime dependency).
>
>

To give maintainers some more context: this is part of an ongoing work to
enable SNP emulation in QEMU, which would be very useful for development
purposes (eg coconut-SVSM). However, it should not be used in a production
environment as it provides no security guarantees.

Please consider this as an RFC.

Luigi



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-17 11:38 ` [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support Tommaso Califano
@ 2026-03-19 12:31   ` Markus Armbruster
  2026-03-20 14:25     ` Tommaso Califano
  2026-03-19 17:49   ` Daniel P. Berrangé
  1 sibling, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2026-03-19 12:31 UTC (permalink / raw)
  To: Tommaso Califano
  Cc: qemu-devel, kvm, Eduardo Habkost, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson

Tommaso Califano <califano.tommaso@gmail.com> writes:

> 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 = *ebx = *ecx = *edx = 0;
>     if (sev_enabled()) {
>         *eax = 0x2;
>         *eax |= sev_es_enabled() ? 0x8 : 0;
>         *eax |= sev_snp_enabled() ? 0x10 : 0;
>         *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
>         *ebx |= (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=sev0,cbitpos=47,reduced-phys-bits=1 \
>     -machine memory-encryption=sev0
>
> To the QEMU start arguments.
>
> Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>

[...]

> 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' } }
>  
> +##
> +# @SevEmulatedProperties:
> +#
> +# Properties for sev-emulated objects.
> +# This object functionally emulates AMD SEV hardware via TCG, so
> +# it does not require real hardware to run.

Wrap the paragraph, please:

   # 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

11.0 right now, but realistically 11.1.

> +##
> +{ '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',

Please insert before sev-guest to keep things more or less sorted.

> @@ -1318,6 +1332,7 @@
>        'secret_keyring':             { 'type': 'SecretKeyringProperties',
>                                        'if': 'CONFIG_SECRET_KEYRING' },
>        'sev-guest':                  'SevGuestProperties',
> +      'sev-emulated':               'SevEmulatedProperties',

Likewise.

>        'sev-snp-guest':              'SevSnpGuestProperties',
>        'tdx-guest':                  'TdxGuestProperties',
>        'thread-context':             'ThreadContextProperties',



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/5] i386/sev: Add launch measurement emulation and TIK property
  2026-03-17 11:38 ` [PATCH 4/5] i386/sev: Add launch measurement emulation and TIK property Tommaso Califano
@ 2026-03-19 12:33   ` Markus Armbruster
  2026-03-20 14:31     ` Tommaso Califano
  0 siblings, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2026-03-19 12:33 UTC (permalink / raw)
  To: Tommaso Califano
  Cc: qemu-devel, kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson

Tommaso Califano <califano.tommaso@gmail.com> writes:

> 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=sev0,cbitpos=47,reduced-phys-bits=1,\
> 					tik=/path/to/tik.bin \
> 	-machine memory-encryption=sev0
>
> Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
> ---
>  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).

Is this a file name?

Blank line here, please.

>  # Since: 10.1.0
>  ##
>  { 'struct': 'SevEmulatedProperties',
>    'base': 'SevGuestProperties',
> -  'data': {}}
> +  'data': {'*tik': 'str'}}
>  
>  ##
>  # @SevSnpGuestProperties:

[...]



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-17 11:38 ` [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support Tommaso Califano
  2026-03-19 12:31   ` Markus Armbruster
@ 2026-03-19 17:49   ` Daniel P. Berrangé
  2026-03-20  7:44     ` Markus Armbruster
  2026-03-20 12:39     ` Daniel P. Berrangé
  1 sibling, 2 replies; 21+ messages in thread
From: Daniel P. Berrangé @ 2026-03-19 17:49 UTC (permalink / raw)
  To: Tommaso Califano
  Cc: qemu-devel, kvm, Eduardo Habkost, Markus Armbruster, Zhao Liu,
	Marcelo Tosatti, Eric Blake, Oliver Steffen, Stefano Garzarella,
	Giuseppe Lettieri, Paolo Bonzini, Luigi Leonardi,
	Richard Henderson

On Tue, Mar 17, 2026 at 12:38:36PM +0100, Tommaso Califano wrote:
> With this change it is possible to run a VM with the SEV CPUID active
> adding:
> 
>     -accel tcg \
>     -object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
>     -machine memory-encryption=sev0

snip

> 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' } }
>  
> +##
> +# @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': {}}

This is deriving 'sev-emulated' from 'sev-guest' which means it
supports all the properties that 'sev-guest' does, which for
the record is:

 sev-guest options:
  dh-cert-file=<string>  - guest owners DH certificate (encoded with base64)
  kernel-hashes=<bool>   - add kernel hashes to guest firmware for measured Linux boot
  legacy-vm-type=<OnOffAuto> - use legacy VM type to maintain measurement compatibility with older QEMU or kernel versions.
  session-file=<string>  - guest owners session parameters (encoded with base64)
  sev-device=<string>    - SEV device to use


Of those properties

 * dh-cert-file + session-file are traditionally used
   as a means to transfer the TIK+TEK to the SEV firmware,
   with wrapping to protect them from the hypervisor.

   These can't be used with sev-emulated, as implemented,
   since they require a key derivation  from the PDH, a
   concept which IIUC is not implemented in this series.

   Instead, in a later patch 'tik' and 'tek' properties
   are added to 'sev-emulated', and to pass the TIK+TEK
   in clear text.

 * sev-device + legacy-vm-type - these are only relevant
   to the KVM integration, so not applicable for emulation

 * kernel-hashes - would be relevant if formally emulating
   LAUNCH_UPDATE_DATA for attestation, but IIUC, this is
   not done/used by this series
  

IOW, we're deriving from 'sev-guest' but AFAICT none of
its properties are relevant to the emulation. The
dh-cert-file and session-file could potentially be
relevant if implementing the PDH concept and key
derivation, but that's not done, instead the tik/tek
are passed explicitly.

What is the value we get from this sev-guest -> sev-emulated
inheritance ?  My gut feeling is that this perhaps isn't
the right way to be modelling things unless there's a plan
for future work that would benefit from them.

Another question related to modelling is whether there is
an intention to support SEV-SNP at a later date, would that
imply a sev-snp-emulated object type too ? If so, would it
inherit from sev-emulated or from sev-snp-guest ?

> +
>  ##
>  # @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 @@
>  
>  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)
>  
>  /* hard code sha256 digest size */
> @@ -177,6 +178,21 @@ struct SevGuestState {
>      OnOffAuto legacy_vm_type;
>  };
>  
> +/**
> + * SevEmulatedState:
> + *
> + * The SevEmulatedState object is used for creating and managing a SEV emulated
> + * guest.
> + *
> + * # $QEMU \
> + *         -object sev-emulated,id=sev0 \
> + *         -machine ...,memory-encryption=sev0
> + */
> +
> +typedef struct SevEmulatedState {
> +    SevGuestState parent_obj;
> +} SevEmulatedState;
> +
>  struct SevSnpGuestState {
>      SevCommonState parent_obj;
>  
> @@ -2936,6 +2952,46 @@ sev_guest_instance_init(Object *obj)
>      sev_guest->legacy_vm_type = ON_OFF_AUTO_AUTO;
>  }
>  
> +static int sev_emulated_init(ConfidentialGuestSupport *cgs, Error **errp)
> +{
> +    SevCommonState *sev_common = 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 >=32",
> +                   __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 = true;
> +    return 0;
> +}
> +
> +static void sev_emulated_class_init(ObjectClass *oc, const void *data)
> +{
> +    ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
> +    /* Override the sev-common method that uses kvm */
> +    klass->kvm_init = sev_emulated_init;
> +}
> +
>  /* guest info specific sev/sev-es */
>  static const TypeInfo sev_guest_info = {
>      .parent = TYPE_SEV_COMMON,
> @@ -2945,6 +3001,14 @@ static const TypeInfo sev_guest_info = {
>      .class_init = sev_guest_class_init,
>  };
>  
> +/* emulated sev */
> +static const TypeInfo sev_emulated_info = {
> +    .parent = TYPE_SEV_GUEST,
> +    .name = TYPE_SEV_EMULATED,
> +    .instance_size = sizeof(SevEmulatedState),
> +    .class_init = 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)
>  
>  #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"
>  
> -- 
> 2.53.0
> 

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-19 17:49   ` Daniel P. Berrangé
@ 2026-03-20  7:44     ` Markus Armbruster
  2026-03-20 12:40       ` Daniel P. Berrangé
  2026-03-20 12:39     ` Daniel P. Berrangé
  1 sibling, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2026-03-20  7:44 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Tommaso Califano, qemu-devel, kvm, Eduardo Habkost, Zhao Liu,
	Marcelo Tosatti, Eric Blake, Oliver Steffen, Stefano Garzarella,
	Giuseppe Lettieri, Paolo Bonzini, Luigi Leonardi,
	Richard Henderson

Daniel P. Berrangé <berrange@redhat.com> writes:

> On Tue, Mar 17, 2026 at 12:38:36PM +0100, Tommaso Califano wrote:
>> With this change it is possible to run a VM with the SEV CPUID active
>> adding:
>> 
>>     -accel tcg \
>>     -object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
>>     -machine memory-encryption=sev0
>
> snip
>
>> 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' } }
>>  
>> +##
>> +# @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': {}}
>
> This is deriving 'sev-emulated' from 'sev-guest' which means it
> supports all the properties that 'sev-guest' does, which for
> the record is:

Uh, I somehow misread the base as SevCommonProperties!  Had I read
correctly, I would've had similar questions.



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-19 17:49   ` Daniel P. Berrangé
  2026-03-20  7:44     ` Markus Armbruster
@ 2026-03-20 12:39     ` Daniel P. Berrangé
  2026-03-20 15:03       ` Tommaso Califano
  1 sibling, 1 reply; 21+ messages in thread
From: Daniel P. Berrangé @ 2026-03-20 12:39 UTC (permalink / raw)
  To: Tommaso Califano, qemu-devel, kvm, Eduardo Habkost,
	Markus Armbruster, Zhao Liu, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson

On Thu, Mar 19, 2026 at 05:49:18PM +0000, Daniel P. Berrangé wrote:
> On Tue, Mar 17, 2026 at 12:38:36PM +0100, Tommaso Califano wrote:
> > With this change it is possible to run a VM with the SEV CPUID active
> > adding:
> > 
> >     -accel tcg \
> >     -object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
> >     -machine memory-encryption=sev0
> 
> snip
> 
> > 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' } }
> >  
> > +##
> > +# @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': {}}
> 
> This is deriving 'sev-emulated' from 'sev-guest' which means it
> supports all the properties that 'sev-guest' does, which for
> the record is:
> 
>  sev-guest options:
>   dh-cert-file=<string>  - guest owners DH certificate (encoded with base64)
>   kernel-hashes=<bool>   - add kernel hashes to guest firmware for measured Linux boot
>   legacy-vm-type=<OnOffAuto> - use legacy VM type to maintain measurement compatibility with older QEMU or kernel versions.
>   session-file=<string>  - guest owners session parameters (encoded with base64)
>   sev-device=<string>    - SEV device to use

Sigh, I was mislead by  '-object sev-guest,help' omitting
information about anything that is not a class property.
So there is also

  - cbitpos=<int>
  - reduced-phys-bits=<int>
  - handle=<int>
  - policy=<int>

> 
> 
> Of those properties
> 
>  * dh-cert-file + session-file are traditionally used
>    as a means to transfer the TIK+TEK to the SEV firmware,
>    with wrapping to protect them from the hypervisor.
> 
>    These can't be used with sev-emulated, as implemented,
>    since they require a key derivation  from the PDH, a
>    concept which IIUC is not implemented in this series.
> 
>    Instead, in a later patch 'tik' and 'tek' properties
>    are added to 'sev-emulated', and to pass the TIK+TEK
>    in clear text.
> 
>  * sev-device + legacy-vm-type - these are only relevant
>    to the KVM integration, so not applicable for emulation
> 
>  * kernel-hashes - would be relevant if formally emulating
>    LAUNCH_UPDATE_DATA for attestation, but IIUC, this is
>    not done/used by this series
>   
> 
> IOW, we're deriving from 'sev-guest' but AFAICT none of
> its properties are relevant to the emulation. The
> dh-cert-file and session-file could potentially be
> relevant if implementing the PDH concept and key
> derivation, but that's not done, instead the tik/tek
> are passed explicitly.
> 
> What is the value we get from this sev-guest -> sev-emulated
> inheritance ?  My gut feeling is that this perhaps isn't
> the right way to be modelling things unless there's a plan
> for future work that would benefit from them.
> 
> Another question related to modelling is whether there is
> an intention to support SEV-SNP at a later date, would that
> imply a sev-snp-emulated object type too ? If so, would it
> inherit from sev-emulated or from sev-snp-guest ?
> 
> > +
> >  ##
> >  # @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 @@
> >  
> >  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)
> >  
> >  /* hard code sha256 digest size */
> > @@ -177,6 +178,21 @@ struct SevGuestState {
> >      OnOffAuto legacy_vm_type;
> >  };
> >  
> > +/**
> > + * SevEmulatedState:
> > + *
> > + * The SevEmulatedState object is used for creating and managing a SEV emulated
> > + * guest.
> > + *
> > + * # $QEMU \
> > + *         -object sev-emulated,id=sev0 \
> > + *         -machine ...,memory-encryption=sev0
> > + */
> > +
> > +typedef struct SevEmulatedState {
> > +    SevGuestState parent_obj;
> > +} SevEmulatedState;
> > +
> >  struct SevSnpGuestState {
> >      SevCommonState parent_obj;
> >  
> > @@ -2936,6 +2952,46 @@ sev_guest_instance_init(Object *obj)
> >      sev_guest->legacy_vm_type = ON_OFF_AUTO_AUTO;
> >  }
> >  
> > +static int sev_emulated_init(ConfidentialGuestSupport *cgs, Error **errp)
> > +{
> > +    SevCommonState *sev_common = 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 >=32",
> > +                   __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 = true;
> > +    return 0;
> > +}
> > +
> > +static void sev_emulated_class_init(ObjectClass *oc, const void *data)
> > +{
> > +    ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc);
> > +    /* Override the sev-common method that uses kvm */
> > +    klass->kvm_init = sev_emulated_init;
> > +}
> > +
> >  /* guest info specific sev/sev-es */
> >  static const TypeInfo sev_guest_info = {
> >      .parent = TYPE_SEV_COMMON,
> > @@ -2945,6 +3001,14 @@ static const TypeInfo sev_guest_info = {
> >      .class_init = sev_guest_class_init,
> >  };
> >  
> > +/* emulated sev */
> > +static const TypeInfo sev_emulated_info = {
> > +    .parent = TYPE_SEV_GUEST,
> > +    .name = TYPE_SEV_EMULATED,
> > +    .instance_size = sizeof(SevEmulatedState),
> > +    .class_init = 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)
> >  
> >  #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"
> >  
> > -- 
> > 2.53.0
> > 
> 
> With regards,
> Daniel
> -- 
> |: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
> |: https://libvirt.org          ~~          https://entangle-photo.org :|
> |: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
> 
> 

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-20  7:44     ` Markus Armbruster
@ 2026-03-20 12:40       ` Daniel P. Berrangé
  2026-03-20 15:23         ` Tommaso Califano
  2026-03-23  7:24         ` Markus Armbruster
  0 siblings, 2 replies; 21+ messages in thread
From: Daniel P. Berrangé @ 2026-03-20 12:40 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Tommaso Califano, qemu-devel, kvm, Eduardo Habkost, Zhao Liu,
	Marcelo Tosatti, Eric Blake, Oliver Steffen, Stefano Garzarella,
	Giuseppe Lettieri, Paolo Bonzini, Luigi Leonardi,
	Richard Henderson

On Fri, Mar 20, 2026 at 08:44:40AM +0100, Markus Armbruster wrote:
> Daniel P. Berrangé <berrange@redhat.com> writes:
> 
> > On Tue, Mar 17, 2026 at 12:38:36PM +0100, Tommaso Califano wrote:
> >> With this change it is possible to run a VM with the SEV CPUID active
> >> adding:
> >> 
> >>     -accel tcg \
> >>     -object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
> >>     -machine memory-encryption=sev0
> >
> > snip
> >
> >> 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' } }
> >>  
> >> +##
> >> +# @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': {}}
> >
> > This is deriving 'sev-emulated' from 'sev-guest' which means it
> > supports all the properties that 'sev-guest' does, which for
> > the record is:
> 
> Uh, I somehow misread the base as SevCommonProperties!  Had I read
> correctly, I would've had similar questions.

Even SevCommonProperties has stuff that's irrelevant for
emulation that I mentioned.

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-19 12:31   ` Markus Armbruster
@ 2026-03-20 14:25     ` Tommaso Califano
  2026-03-20 14:48       ` Markus Armbruster
  0 siblings, 1 reply; 21+ messages in thread
From: Tommaso Califano @ 2026-03-20 14:25 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, kvm, Eduardo Habkost, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson



Il 19/03/26 13:31, Markus Armbruster ha scritto:
> Tommaso Califano <califano.tommaso@gmail.com> writes:
> 
>> 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 = *ebx = *ecx = *edx = 0;
>>     if (sev_enabled()) {
>>         *eax = 0x2;
>>         *eax |= sev_es_enabled() ? 0x8 : 0;
>>         *eax |= sev_snp_enabled() ? 0x10 : 0;
>>         *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
>>         *ebx |= (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=sev0,cbitpos=47,reduced-phys-bits=1 \
>>     -machine memory-encryption=sev0
>>
>> To the QEMU start arguments.
>>
>> Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
> 
> [...]
> 
>> 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' } }
>>  
>> +##
>> +# @SevEmulatedProperties:
>> +#
>> +# Properties for sev-emulated objects.
>> +# This object functionally emulates AMD SEV hardware via TCG, so
>> +# it does not require real hardware to run.
> 
> Wrap the paragraph, please:
> 
>    # Properties for sev-emulated objects.  This object functionally
>    # emulates AMD SEV hardware via TCG, so it does not require real
>    # hardware to run.
> 

I'll do it.

>> +#
>> +# Since: 10.1.0
> 
> 11.0 right now, but realistically 11.1.
> 

I'll update it to 11.1.

>> +##
>> +{ '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',
> 
> Please insert before sev-guest to keep things more or less sorted.
> 

I'll do it, but I don't understand the convention. I'd organized them
by object derivation hierarchy, so what is the expected sorting order?

>> @@ -1318,6 +1332,7 @@
>>        'secret_keyring':             { 'type': 'SecretKeyringProperties',
>>                                        'if': 'CONFIG_SECRET_KEYRING' },
>>        'sev-guest':                  'SevGuestProperties',
>> +      'sev-emulated':               'SevEmulatedProperties',
> 
> Likewise.
> 

Yes.

>>        'sev-snp-guest':              'SevSnpGuestProperties',
>>        'tdx-guest':                  'TdxGuestProperties',
>>        'thread-context':             'ThreadContextProperties',
> 

Best regards,
Tommaso Califano


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/5] i386/sev: Add launch measurement emulation and TIK property
  2026-03-19 12:33   ` Markus Armbruster
@ 2026-03-20 14:31     ` Tommaso Califano
  0 siblings, 0 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-20 14:31 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, kvm, Eduardo Habkost, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson



Il 19/03/26 13:33, Markus Armbruster ha scritto:
> Tommaso Califano <califano.tommaso@gmail.com> writes:
> 
>> 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=sev0,cbitpos=47,reduced-phys-bits=1,\
>> 					tik=/path/to/tik.bin \
>> 	-machine memory-encryption=sev0
>>
>> Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
>> ---
>>  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).
> 
> Is this a file name?
> 

Yes, I'll specify it better writing "Path to the binary file..."

> Blank line here, please.
> 

I'll add it.

>>  # Since: 10.1.0
>>  ##
>>  { 'struct': 'SevEmulatedProperties',
>>    'base': 'SevGuestProperties',
>> -  'data': {}}
>> +  'data': {'*tik': 'str'}}
>>  
>>  ##
>>  # @SevSnpGuestProperties:
> 
> [...]
> 

Best regards,
Tommaso Califano


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-20 14:25     ` Tommaso Califano
@ 2026-03-20 14:48       ` Markus Armbruster
  2026-03-20 15:34         ` Tommaso Califano
  0 siblings, 1 reply; 21+ messages in thread
From: Markus Armbruster @ 2026-03-20 14:48 UTC (permalink / raw)
  To: Tommaso Califano
  Cc: qemu-devel, kvm, Eduardo Habkost, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson

Tommaso Califano <califano.tommaso@gmail.com> writes:

> Il 19/03/26 13:31, Markus Armbruster ha scritto:
>> Tommaso Califano <califano.tommaso@gmail.com> writes:
>> 
>>> 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 = *ebx = *ecx = *edx = 0;
>>>     if (sev_enabled()) {
>>>         *eax = 0x2;
>>>         *eax |= sev_es_enabled() ? 0x8 : 0;
>>>         *eax |= sev_snp_enabled() ? 0x10 : 0;
>>>         *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
>>>         *ebx |= (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=sev0,cbitpos=47,reduced-phys-bits=1 \
>>>     -machine memory-encryption=sev0
>>>
>>> To the QEMU start arguments.
>>>
>>> Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
>> 
>> [...]
>> 
>>> diff --git a/qapi/qom.json b/qapi/qom.json
>>> index c653248f85..35cda819ec 100644
>>> --- a/qapi/qom.json
>>> +++ b/qapi/qom.json

[...]

>>> @@ -1241,6 +1254,7 @@
>>>      { 'name': 'secret_keyring',
>>>        'if': 'CONFIG_SECRET_KEYRING' },
>>>      'sev-guest',
>>> +    'sev-emulated',
>>>      'sev-snp-guest',
>>>      'thread-context',
>>>      's390-pv-guest',
>> 
>> Please insert before sev-guest to keep things more or less sorted.
>> 
>
> I'll do it, but I don't understand the convention. I'd organized them
> by object derivation hierarchy, so what is the expected sorting order?

It looks alphabetical modulo lazy mistakes to me.

[...]



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-20 12:39     ` Daniel P. Berrangé
@ 2026-03-20 15:03       ` Tommaso Califano
  2026-03-20 15:32         ` Tommaso Califano
  0 siblings, 1 reply; 21+ messages in thread
From: Tommaso Califano @ 2026-03-20 15:03 UTC (permalink / raw)
  To: Daniel P. Berrangé, qemu-devel, kvm, Eduardo Habkost,
	Markus Armbruster, Zhao Liu, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson



Il 20/03/26 13:39, Daniel P. Berrangé ha scritto:
> On Thu, Mar 19, 2026 at 05:49:18PM +0000, Daniel P. Berrangé wrote:
>> On Tue, Mar 17, 2026 at 12:38:36PM +0100, Tommaso Califano wrote:
>>> With this change it is possible to run a VM with the SEV CPUID active
>>> adding:
>>>
>>>     -accel tcg \
>>>     -object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
>>>     -machine memory-encryption=sev0
>>
>> snip
>>
>>> 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' } }
>>>  
>>> +##
>>> +# @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': {}}
>>
>> This is deriving 'sev-emulated' from 'sev-guest' which means it
>> supports all the properties that 'sev-guest' does, which for
>> the record is:
>>
>>  sev-guest options:
>>   dh-cert-file=<string>  - guest owners DH certificate (encoded with base64)
>>   kernel-hashes=<bool>   - add kernel hashes to guest firmware for measured Linux boot
>>   legacy-vm-type=<OnOffAuto> - use legacy VM type to maintain measurement compatibility with older QEMU or kernel versions.
>>   session-file=<string>  - guest owners session parameters (encoded with base64)
>>   sev-device=<string>    - SEV device to use
> 
> Sigh, I was mislead by  '-object sev-guest,help' omitting
> information about anything that is not a class property.
> So there is also
> 
>   - cbitpos=<int>
>   - reduced-phys-bits=<int>
>   - handle=<int>
>   - policy=<int>
> 
>>
>>
>> Of those properties
>>
>>  * dh-cert-file + session-file are traditionally used
>>    as a means to transfer the TIK+TEK to the SEV firmware,
>>    with wrapping to protect them from the hypervisor.
>>
>>    These can't be used with sev-emulated, as implemented,
>>    since they require a key derivation  from the PDH, a
>>    concept which IIUC is not implemented in this series.
>>
>>    Instead, in a later patch 'tik' and 'tek' properties
>>    are added to 'sev-emulated', and to pass the TIK+TEK
>>    in clear text.
>>
>>  * sev-device + legacy-vm-type - these are only relevant
>>    to the KVM integration, so not applicable for emulation
>>
>>  * kernel-hashes - would be relevant if formally emulating
>>    LAUNCH_UPDATE_DATA for attestation, but IIUC, this is
>>    not done/used by this series
>>   
>>
>> IOW, we're deriving from 'sev-guest' but AFAICT none of
>> its properties are relevant to the emulation. The
>> dh-cert-file and session-file could potentially be
>> relevant if implementing the PDH concept and key
>> derivation, but that's not done, instead the tik/tek
>> are passed explicitly.
>>
>> What is the value we get from this sev-guest -> sev-emulated
>> inheritance ?  My gut feeling is that this perhaps isn't
>> the right way to be modelling things unless there's a plan
>> for future work that would benefit from them.
>>

I know most of these properties aren't used in emulation. I chose
to derive from `sev-guest' primarily for the policy property
(needed for SEV-ES future implementation).

For the TIK and TEK properties, I considered reusing dh-cert-file
and session-file, but since those keys are CPU-generated anyway,
I opted to simplify the cryptographic protocol given the fact
that security isn't the focus here.

That said, you're right that sev-guest inheritance may not add
much value. If you'd prefer interface consistency for testing
(reusing dh-cert-file/session-file) those properties could then
become relevant. Otherwise, for pure SEV emulation, deriving from
sev-common makes sense instead; though I'm unsure how that would
impact the SEV-ES implementation, perhaps we could re-add just the
policy property if needed.

>> Another question related to modelling is whether there is
>> an intention to support SEV-SNP at a later date, would that
>> imply a sev-snp-emulated object type too ? If so, would it
>> inherit from sev-emulated or from sev-snp-guest ?
>>

While I haven't studied it in depth, I think it will. It seems
best to derive a new object (sev-snp-emulated) from sev-guest-snp
because of the sev_snp_enabled() function, which will work through
TYPE_SEV_SNP_GUEST casting (similar to the current sev_enabled()
function).

Best regards,
Tommaso Califano



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-20 12:40       ` Daniel P. Berrangé
@ 2026-03-20 15:23         ` Tommaso Califano
  2026-03-23  7:24         ` Markus Armbruster
  1 sibling, 0 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-20 15:23 UTC (permalink / raw)
  To: Daniel P. Berrangé, Markus Armbruster
  Cc: qemu-devel, kvm, Eduardo Habkost, Zhao Liu, Marcelo Tosatti,
	Eric Blake, Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson



Il 20/03/26 13:40, Daniel P. Berrangé ha scritto:
> On Fri, Mar 20, 2026 at 08:44:40AM +0100, Markus Armbruster wrote:
>> Daniel P. Berrangé <berrange@redhat.com> writes:
>>
>>> On Tue, Mar 17, 2026 at 12:38:36PM +0100, Tommaso Califano wrote:
>>>> With this change it is possible to run a VM with the SEV CPUID active
>>>> adding:
>>>>
>>>>     -accel tcg \
>>>>     -object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
>>>>     -machine memory-encryption=sev0
>>>
>>> snip
>>>
>>>> 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' } }
>>>>  
>>>> +##
>>>> +# @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': {}}
>>>
>>> This is deriving 'sev-emulated' from 'sev-guest' which means it
>>> supports all the properties that 'sev-guest' does, which for
>>> the record is:
>>
>> Uh, I somehow misread the base as SevCommonProperties!  Had I read
>> correctly, I would've had similar questions.
> 
> Even SevCommonProperties has stuff that's irrelevant for
> emulation that I mentioned.
> 

Maybe I'm missing something, but the only sev-common property not being
used is `sev-device`, since "/dev/sev" doesn't exist in the emulated context.

That said, all other properties are functional:
  - cbitpos=<int>
  - reduced-phys-bits=<int>
  - kernel-hashes=<bool>

Additionally, deriving from sev-common ensures the TYPE_SEV_COMMON type
for the sev_enabled() cast.

So I think deriving from sev-common is beneficial.


Best regards,
Tommaso Califano


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-20 15:03       ` Tommaso Califano
@ 2026-03-20 15:32         ` Tommaso Califano
  0 siblings, 0 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-20 15:32 UTC (permalink / raw)
  To: Daniel P. Berrangé, qemu-devel, kvm, Eduardo Habkost,
	Markus Armbruster, Zhao Liu, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson



Il 20/03/26 16:03, Tommaso Califano ha scritto:
> 
> 
> Il 20/03/26 13:39, Daniel P. Berrangé ha scritto:
>> On Thu, Mar 19, 2026 at 05:49:18PM +0000, Daniel P. Berrangé wrote:
>>> On Tue, Mar 17, 2026 at 12:38:36PM +0100, Tommaso Califano wrote:
>>>> With this change it is possible to run a VM with the SEV CPUID active
>>>> adding:
>>>>
>>>>     -accel tcg \
>>>>     -object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
>>>>     -machine memory-encryption=sev0
>>>
>>> snip
>>>
>>>> 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' } }
>>>>  
>>>> +##
>>>> +# @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': {}}
>>>
>>> This is deriving 'sev-emulated' from 'sev-guest' which means it
>>> supports all the properties that 'sev-guest' does, which for
>>> the record is:
>>>
>>>  sev-guest options:
>>>   dh-cert-file=<string>  - guest owners DH certificate (encoded with base64)
>>>   kernel-hashes=<bool>   - add kernel hashes to guest firmware for measured Linux boot
>>>   legacy-vm-type=<OnOffAuto> - use legacy VM type to maintain measurement compatibility with older QEMU or kernel versions.
>>>   session-file=<string>  - guest owners session parameters (encoded with base64)
>>>   sev-device=<string>    - SEV device to use
>>
>> Sigh, I was mislead by  '-object sev-guest,help' omitting
>> information about anything that is not a class property.
>> So there is also
>>
>>   - cbitpos=<int>
>>   - reduced-phys-bits=<int>
>>   - handle=<int>
>>   - policy=<int>
>>
>>>
>>>
>>> Of those properties
>>>
>>>  * dh-cert-file + session-file are traditionally used
>>>    as a means to transfer the TIK+TEK to the SEV firmware,
>>>    with wrapping to protect them from the hypervisor.
>>>
>>>    These can't be used with sev-emulated, as implemented,
>>>    since they require a key derivation  from the PDH, a
>>>    concept which IIUC is not implemented in this series.
>>>
>>>    Instead, in a later patch 'tik' and 'tek' properties
>>>    are added to 'sev-emulated', and to pass the TIK+TEK
>>>    in clear text.
>>>
>>>  * sev-device + legacy-vm-type - these are only relevant
>>>    to the KVM integration, so not applicable for emulation
>>>
>>>  * kernel-hashes - would be relevant if formally emulating
>>>    LAUNCH_UPDATE_DATA for attestation, but IIUC, this is
>>>    not done/used by this series

LAUNCH_UPDATE_DATA is supported in the sense that the called
memory regions are saved for measurement calculation. With this
method, even if kernel-hashes is active, the measurement remains
correct and the attestation workflow stays the same.

Thinking of it now, I could add a small improvement by checking
if the memory region is already in the QEMUIOVector ld_data,
avoiding multiple addition of the same region.

>>>   
>>>
>>> IOW, we're deriving from 'sev-guest' but AFAICT none of
>>> its properties are relevant to the emulation. The
>>> dh-cert-file and session-file could potentially be
>>> relevant if implementing the PDH concept and key
>>> derivation, but that's not done, instead the tik/tek
>>> are passed explicitly.
>>>
>>> What is the value we get from this sev-guest -> sev-emulated
>>> inheritance ?  My gut feeling is that this perhaps isn't
>>> the right way to be modelling things unless there's a plan
>>> for future work that would benefit from them.
>>>
> 
> I know most of these properties aren't used in emulation. I chose
> to derive from `sev-guest' primarily for the policy property
> (needed for SEV-ES future implementation).
> 
> For the TIK and TEK properties, I considered reusing dh-cert-file
> and session-file, but since those keys are CPU-generated anyway,
> I opted to simplify the cryptographic protocol given the fact
> that security isn't the focus here.
> 
> That said, you're right that sev-guest inheritance may not add
> much value. If you'd prefer interface consistency for testing
> (reusing dh-cert-file/session-file) those properties could then
> become relevant. Otherwise, for pure SEV emulation, deriving from
> sev-common makes sense instead; though I'm unsure how that would
> impact the SEV-ES implementation, perhaps we could re-add just the
> policy property if needed.
> 
>>> Another question related to modelling is whether there is
>>> an intention to support SEV-SNP at a later date, would that
>>> imply a sev-snp-emulated object type too ? If so, would it
>>> inherit from sev-emulated or from sev-snp-guest ?
>>>
> 
> While I haven't studied it in depth, I think it will. It seems
> best to derive a new object (sev-snp-emulated) from sev-guest-snp
> because of the sev_snp_enabled() function, which will work through
> TYPE_SEV_SNP_GUEST casting (similar to the current sev_enabled()
> function).
> 

Apologies for the multiple emails; I forgot to explain the kernel-hashes
implementation.

Best regards,
Tommaso Califano



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-20 14:48       ` Markus Armbruster
@ 2026-03-20 15:34         ` Tommaso Califano
  0 siblings, 0 replies; 21+ messages in thread
From: Tommaso Califano @ 2026-03-20 15:34 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: qemu-devel, kvm, Eduardo Habkost, Zhao Liu,
	Daniel P. Berrangé, Marcelo Tosatti, Eric Blake,
	Oliver Steffen, Stefano Garzarella, Giuseppe Lettieri,
	Paolo Bonzini, Luigi Leonardi, Richard Henderson



Il 20/03/26 15:48, Markus Armbruster ha scritto:
> Tommaso Califano <califano.tommaso@gmail.com> writes:
> 
>> Il 19/03/26 13:31, Markus Armbruster ha scritto:
>>> Tommaso Califano <califano.tommaso@gmail.com> writes:
>>>
>>>> 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 = *ebx = *ecx = *edx = 0;
>>>>     if (sev_enabled()) {
>>>>         *eax = 0x2;
>>>>         *eax |= sev_es_enabled() ? 0x8 : 0;
>>>>         *eax |= sev_snp_enabled() ? 0x10 : 0;
>>>>         *ebx = sev_get_cbit_position() & 0x3f; /* EBX[5:0] */
>>>>         *ebx |= (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=sev0,cbitpos=47,reduced-phys-bits=1 \
>>>>     -machine memory-encryption=sev0
>>>>
>>>> To the QEMU start arguments.
>>>>
>>>> Signed-off-by: Tommaso Califano <califano.tommaso@gmail.com>
>>>
>>> [...]
>>>
>>>> diff --git a/qapi/qom.json b/qapi/qom.json
>>>> index c653248f85..35cda819ec 100644
>>>> --- a/qapi/qom.json
>>>> +++ b/qapi/qom.json
> 
> [...]
> 
>>>> @@ -1241,6 +1254,7 @@
>>>>      { 'name': 'secret_keyring',
>>>>        'if': 'CONFIG_SECRET_KEYRING' },
>>>>      'sev-guest',
>>>> +    'sev-emulated',
>>>>      'sev-snp-guest',
>>>>      'thread-context',
>>>>      's390-pv-guest',
>>>
>>> Please insert before sev-guest to keep things more or less sorted.
>>>
>>
>> I'll do it, but I don't understand the convention. I'd organized them
>> by object derivation hierarchy, so what is the expected sorting order?
> 
> It looks alphabetical modulo lazy mistakes to me.
> 
> [...]
> 

Thanks for the clarification.

Best regards,
Tommaso Califano


^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support
  2026-03-20 12:40       ` Daniel P. Berrangé
  2026-03-20 15:23         ` Tommaso Califano
@ 2026-03-23  7:24         ` Markus Armbruster
  1 sibling, 0 replies; 21+ messages in thread
From: Markus Armbruster @ 2026-03-23  7:24 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Tommaso Califano, qemu-devel, kvm, Eduardo Habkost, Zhao Liu,
	Marcelo Tosatti, Eric Blake, Oliver Steffen, Stefano Garzarella,
	Giuseppe Lettieri, Paolo Bonzini, Luigi Leonardi,
	Richard Henderson

Daniel P. Berrangé <berrange@redhat.com> writes:

> On Fri, Mar 20, 2026 at 08:44:40AM +0100, Markus Armbruster wrote:
>> Daniel P. Berrangé <berrange@redhat.com> writes:
>> 
>> > On Tue, Mar 17, 2026 at 12:38:36PM +0100, Tommaso Califano wrote:
>> >> With this change it is possible to run a VM with the SEV CPUID active
>> >> adding:
>> >> 
>> >>     -accel tcg \
>> >>     -object sev-emulated,id=sev0,cbitpos=47,reduced-phys-bits=1 \
>> >>     -machine memory-encryption=sev0
>> >
>> > snip
>> >
>> >> 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' } }
>> >>  
>> >> +##
>> >> +# @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': {}}
>> >
>> > This is deriving 'sev-emulated' from 'sev-guest' which means it
>> > supports all the properties that 'sev-guest' does, which for
>> > the record is:
>> 
>> Uh, I somehow misread the base as SevCommonProperties!  Had I read
>> correctly, I would've had similar questions.
>
> Even SevCommonProperties has stuff that's irrelevant for
> emulation that I mentioned.

Yes.  I was too hasty.  Glad you spotted it!



^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2026-03-23  7:25 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-17 11:38 [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Tommaso Califano
2026-03-17 11:38 ` [PATCH 1/5] i386/sev: Add sev-emulated QOM object with TCG support Tommaso Califano
2026-03-19 12:31   ` Markus Armbruster
2026-03-20 14:25     ` Tommaso Califano
2026-03-20 14:48       ` Markus Armbruster
2026-03-20 15:34         ` Tommaso Califano
2026-03-19 17:49   ` Daniel P. Berrangé
2026-03-20  7:44     ` Markus Armbruster
2026-03-20 12:40       ` Daniel P. Berrangé
2026-03-20 15:23         ` Tommaso Califano
2026-03-23  7:24         ` Markus Armbruster
2026-03-20 12:39     ` Daniel P. Berrangé
2026-03-20 15:03       ` Tommaso Califano
2026-03-20 15:32         ` Tommaso Califano
2026-03-17 11:38 ` [PATCH 2/5] target/i386: Add MSR SEV support and C-bit reset on TCG Tommaso Califano
2026-03-17 11:38 ` [PATCH 3/5] i386/sev: Implement SEV launch state sequence and query-sev Tommaso Califano
2026-03-17 11:38 ` [PATCH 4/5] i386/sev: Add launch measurement emulation and TIK property Tommaso Califano
2026-03-19 12:33   ` Markus Armbruster
2026-03-20 14:31     ` Tommaso Califano
2026-03-17 11:38 ` [PATCH 5/5] i386/sev: Implement emulated launch secret injection and TEK property Tommaso Califano
2026-03-17 13:01 ` [PATCH 0/5] i386/sev: Add TCG-emulated AMD SEV guest support Luigi Leonardi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox