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
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 :|
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 :|
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
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
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.
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 :|
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!
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
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',
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
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.
[...]
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
© 2016 - 2026 Red Hat, Inc.