You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
531 lines
19 KiB
531 lines
19 KiB
1 month ago
|
From 900859fd3445b9a71f1a9a8befda17f0c33f3923 Mon Sep 17 00:00:00 2001
|
||
|
From: Brijesh Singh <brijesh.singh@amd.com>
|
||
|
Date: Thu, 30 May 2024 06:16:19 -0500
|
||
|
Subject: [PATCH 059/100] i386/sev: Introduce 'sev-snp-guest' object
|
||
|
|
||
|
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
|
||
|
RH-MergeRequest: 245: SEV-SNP support
|
||
|
RH-Jira: RHEL-39544
|
||
|
RH-Acked-by: Thomas Huth <thuth@redhat.com>
|
||
|
RH-Acked-by: Bandan Das <bdas@redhat.com>
|
||
|
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||
|
RH-Commit: [59/91] 3e585113d209176c2b97ad5e4fe943f19dfdcaeb (bonzini/rhel-qemu-kvm)
|
||
|
|
||
|
SEV-SNP support relies on a different set of properties/state than the
|
||
|
existing 'sev-guest' object. This patch introduces the 'sev-snp-guest'
|
||
|
object, which can be used to configure an SEV-SNP guest. For example,
|
||
|
a default-configured SEV-SNP guest with no additional information
|
||
|
passed in for use with attestation:
|
||
|
|
||
|
-object sev-snp-guest,id=sev0
|
||
|
|
||
|
or a fully-specified SEV-SNP guest where all spec-defined binary
|
||
|
blobs are passed in as base64-encoded strings:
|
||
|
|
||
|
-object sev-snp-guest,id=sev0, \
|
||
|
policy=0x30000, \
|
||
|
init-flags=0, \
|
||
|
id-block=YWFhYWFhYWFhYWFhYWFhCg==, \
|
||
|
id-auth=CxHK/OKLkXGn/KpAC7Wl1FSiisWDbGTEKz..., \
|
||
|
author-key-enabled=on, \
|
||
|
host-data=LNkCWBRC5CcdGXirbNUV1OrsR28s..., \
|
||
|
guest-visible-workarounds=AA==, \
|
||
|
|
||
|
See the QAPI schema updates included in this patch for more usage
|
||
|
details.
|
||
|
|
||
|
In some cases these blobs may be up to 4096 characters, but this is
|
||
|
generally well below the default limit for linux hosts where
|
||
|
command-line sizes are defined by the sysconf-configurable ARG_MAX
|
||
|
value, which defaults to 2097152 characters for Ubuntu hosts, for
|
||
|
example.
|
||
|
|
||
|
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
|
||
|
Co-developed-by: Michael Roth <michael.roth@amd.com>
|
||
|
Acked-by: Markus Armbruster <armbru@redhat.com> (for QAPI schema)
|
||
|
Signed-off-by: Michael Roth <michael.roth@amd.com>
|
||
|
Co-developed-by: Pankaj Gupta <pankaj.gupta@amd.com>
|
||
|
Signed-off-by: Pankaj Gupta <pankaj.gupta@amd.com>
|
||
|
Message-ID: <20240530111643.1091816-8-pankaj.gupta@amd.com>
|
||
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||
|
(cherry picked from commit 7b34df44260b391e33bc3acf1ced30019d9aadf1)
|
||
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
||
|
---
|
||
|
docs/system/i386/amd-memory-encryption.rst | 70 +++++-
|
||
|
qapi/qom.json | 58 +++++
|
||
|
target/i386/sev.c | 253 +++++++++++++++++++++
|
||
|
target/i386/sev.h | 1 +
|
||
|
4 files changed, 380 insertions(+), 2 deletions(-)
|
||
|
|
||
|
diff --git a/docs/system/i386/amd-memory-encryption.rst b/docs/system/i386/amd-memory-encryption.rst
|
||
|
index e9bc142bc1..748f5094ba 100644
|
||
|
--- a/docs/system/i386/amd-memory-encryption.rst
|
||
|
+++ b/docs/system/i386/amd-memory-encryption.rst
|
||
|
@@ -25,8 +25,8 @@ support for notifying a guest's operating system when certain types of VMEXITs
|
||
|
are about to occur. This allows the guest to selectively share information with
|
||
|
the hypervisor to satisfy the requested function.
|
||
|
|
||
|
-Launching
|
||
|
----------
|
||
|
+Launching (SEV and SEV-ES)
|
||
|
+--------------------------
|
||
|
|
||
|
Boot images (such as bios) must be encrypted before a guest can be booted. The
|
||
|
``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images: ``LAUNCH_START``,
|
||
|
@@ -161,6 +161,72 @@ The value of GCTX.LD is
|
||
|
If kernel hashes are not used, or SEV-ES is disabled, use empty blobs for
|
||
|
``kernel_hashes_blob`` and ``vmsas_blob`` as needed.
|
||
|
|
||
|
+Launching (SEV-SNP)
|
||
|
+-------------------
|
||
|
+Boot images (such as bios) must be encrypted before a guest can be booted. The
|
||
|
+``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images:
|
||
|
+``SNP_LAUNCH_START``, ``SNP_LAUNCH_UPDATE``, and ``SNP_LAUNCH_FINISH``. These
|
||
|
+three commands communicate with SEV-SNP firmware to generate a fresh memory
|
||
|
+encryption key for the VM, encrypt the boot images for a successful launch. For
|
||
|
+more details on the SEV-SNP firmware interfaces used by these commands please
|
||
|
+see the SEV-SNP Firmware ABI.
|
||
|
+
|
||
|
+``SNP_LAUNCH_START`` is called first to create a cryptographic launch context
|
||
|
+within the firmware. To create this context, the guest owner must provide a
|
||
|
+guest policy and other parameters as described in the SEV-SNP firmware
|
||
|
+specification. The launch parameters should be specified as described in the
|
||
|
+QAPI schema for the sev-snp-guest object.
|
||
|
+
|
||
|
+The ``SNP_LAUNCH_START`` uses the following parameters, which can be configured
|
||
|
+by the corresponding parameters documented in the QAPI schema for the
|
||
|
+'sev-snp-guest' object.
|
||
|
+
|
||
|
++--------+-------+----------+-------------------------------------------------+
|
||
|
+| key | type | default | meaning |
|
||
|
++---------------------------+-------------------------------------------------+
|
||
|
+| policy | hex | 0x30000 | a 64-bit guest policy |
|
||
|
++---------------------------+-------------------------------------------------+
|
||
|
+| guest-visible-workarounds | string| 0 | 16-byte base64 encoded string|
|
||
|
+| | | | for guest OS visible |
|
||
|
+| | | | workarounds. |
|
||
|
++---------------------------+-------------------------------------------------+
|
||
|
+
|
||
|
+``SNP_LAUNCH_UPDATE`` encrypts the memory region using the cryptographic context
|
||
|
+created via the ``SNP_LAUNCH_START`` command. If required, this command can be
|
||
|
+called multiple times to encrypt different memory regions. The command also
|
||
|
+calculates the measurement of the memory contents as it encrypts.
|
||
|
+
|
||
|
+``SNP_LAUNCH_FINISH`` finalizes the guest launch flow. Optionally, while
|
||
|
+finalizing the launch the firmware can perform checks on the launch digest
|
||
|
+computing through the ``SNP_LAUNCH_UPDATE``. To perform the check the user must
|
||
|
+supply the id block, authentication blob and host data that should be included
|
||
|
+in the attestation report. See the SEV-SNP spec for further details.
|
||
|
+
|
||
|
+The ``SNP_LAUNCH_FINISH`` uses the following parameters, which can be configured
|
||
|
+by the corresponding parameters documented in the QAPI schema for the
|
||
|
+'sev-snp-guest' object.
|
||
|
+
|
||
|
++--------------------+-------+----------+-------------------------------------+
|
||
|
+| key | type | default | meaning |
|
||
|
++--------------------+-------+----------+-------------------------------------+
|
||
|
+| id-block | string| none | base64 encoded ID block |
|
||
|
++--------------------+-------+----------+-------------------------------------+
|
||
|
+| id-auth | string| none | base64 encoded authentication |
|
||
|
+| | | | information |
|
||
|
++--------------------+-------+----------+-------------------------------------+
|
||
|
+| author-key-enabled | bool | 0 | auth block contains author key |
|
||
|
++--------------------+-------+----------+-------------------------------------+
|
||
|
+| host_data | string| none | host provided data |
|
||
|
++--------------------+-------+----------+-------------------------------------+
|
||
|
+
|
||
|
+To launch a SEV-SNP guest (additional parameters are documented in the QAPI
|
||
|
+schema for the 'sev-snp-guest' object)::
|
||
|
+
|
||
|
+ # ${QEMU} \
|
||
|
+ -machine ...,confidential-guest-support=sev0 \
|
||
|
+ -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1
|
||
|
+
|
||
|
+
|
||
|
Debugging
|
||
|
---------
|
||
|
|
||
|
diff --git a/qapi/qom.json b/qapi/qom.json
|
||
|
index 056b38f491..8bd299265e 100644
|
||
|
--- a/qapi/qom.json
|
||
|
+++ b/qapi/qom.json
|
||
|
@@ -929,6 +929,62 @@
|
||
|
'*handle': 'uint32',
|
||
|
'*legacy-vm-type': 'bool' } }
|
||
|
|
||
|
+##
|
||
|
+# @SevSnpGuestProperties:
|
||
|
+#
|
||
|
+# Properties for sev-snp-guest objects. Most of these are direct
|
||
|
+# arguments for the KVM_SNP_* interfaces documented in the Linux
|
||
|
+# kernel source under
|
||
|
+# Documentation/arch/x86/amd-memory-encryption.rst, which are in turn
|
||
|
+# closely coupled with the SNP_INIT/SNP_LAUNCH_* firmware commands
|
||
|
+# documented in the SEV-SNP Firmware ABI Specification (Rev 0.9).
|
||
|
+#
|
||
|
+# More usage information is also available in the QEMU source tree
|
||
|
+# under docs/amd-memory-encryption.
|
||
|
+#
|
||
|
+# @policy: the 'POLICY' parameter to the SNP_LAUNCH_START command, as
|
||
|
+# defined in the SEV-SNP firmware ABI (default: 0x30000)
|
||
|
+#
|
||
|
+# @guest-visible-workarounds: 16-byte, base64-encoded blob to report
|
||
|
+# hypervisor-defined workarounds, corresponding to the 'GOSVW'
|
||
|
+# parameter of the SNP_LAUNCH_START command defined in the SEV-SNP
|
||
|
+# firmware ABI (default: all-zero)
|
||
|
+#
|
||
|
+# @id-block: 96-byte, base64-encoded blob to provide the 'ID Block'
|
||
|
+# structure for the SNP_LAUNCH_FINISH command defined in the
|
||
|
+# SEV-SNP firmware ABI (default: all-zero)
|
||
|
+#
|
||
|
+# @id-auth: 4096-byte, base64-encoded blob to provide the 'ID
|
||
|
+# Authentication Information Structure' for the SNP_LAUNCH_FINISH
|
||
|
+# command defined in the SEV-SNP firmware ABI (default: all-zero)
|
||
|
+#
|
||
|
+# @author-key-enabled: true if 'id-auth' blob contains the 'AUTHOR_KEY'
|
||
|
+# field defined SEV-SNP firmware ABI (default: false)
|
||
|
+#
|
||
|
+# @host-data: 32-byte, base64-encoded, user-defined blob to provide to
|
||
|
+# the guest, as documented for the 'HOST_DATA' parameter of the
|
||
|
+# SNP_LAUNCH_FINISH command in the SEV-SNP firmware ABI (default:
|
||
|
+# all-zero)
|
||
|
+#
|
||
|
+# @vcek-disabled: Guests are by default allowed to choose between VLEK
|
||
|
+# (Versioned Loaded Endorsement Key) or VCEK (Versioned Chip
|
||
|
+# Endorsement Key) when requesting attestation reports from
|
||
|
+# firmware. Set this to true to disable the use of VCEK.
|
||
|
+# (default: false) (since: 9.1)
|
||
|
+#
|
||
|
+# Since: 9.1
|
||
|
+##
|
||
|
+{ 'struct': 'SevSnpGuestProperties',
|
||
|
+ 'base': 'SevCommonProperties',
|
||
|
+ 'data': {
|
||
|
+ '*policy': 'uint64',
|
||
|
+ '*guest-visible-workarounds': 'str',
|
||
|
+ '*id-block': 'str',
|
||
|
+ '*id-auth': 'str',
|
||
|
+ '*author-key-enabled': 'bool',
|
||
|
+ '*host-data': 'str',
|
||
|
+ '*vcek-disabled': 'bool' } }
|
||
|
+
|
||
|
##
|
||
|
# @ThreadContextProperties:
|
||
|
#
|
||
|
@@ -1007,6 +1063,7 @@
|
||
|
{ 'name': 'secret_keyring',
|
||
|
'if': 'CONFIG_SECRET_KEYRING' },
|
||
|
'sev-guest',
|
||
|
+ 'sev-snp-guest',
|
||
|
'thread-context',
|
||
|
's390-pv-guest',
|
||
|
'throttle-group',
|
||
|
@@ -1077,6 +1134,7 @@
|
||
|
'secret_keyring': { 'type': 'SecretKeyringProperties',
|
||
|
'if': 'CONFIG_SECRET_KEYRING' },
|
||
|
'sev-guest': 'SevGuestProperties',
|
||
|
+ 'sev-snp-guest': 'SevSnpGuestProperties',
|
||
|
'thread-context': 'ThreadContextProperties',
|
||
|
'throttle-group': 'ThrottleGroupProperties',
|
||
|
'tls-creds-anon': 'TlsCredsAnonProperties',
|
||
|
diff --git a/target/i386/sev.c b/target/i386/sev.c
|
||
|
index 28a018ed83..a81b3228d4 100644
|
||
|
--- a/target/i386/sev.c
|
||
|
+++ b/target/i386/sev.c
|
||
|
@@ -42,6 +42,7 @@
|
||
|
|
||
|
OBJECT_DECLARE_TYPE(SevCommonState, SevCommonStateClass, SEV_COMMON)
|
||
|
OBJECT_DECLARE_TYPE(SevGuestState, SevCommonStateClass, SEV_GUEST)
|
||
|
+OBJECT_DECLARE_TYPE(SevSnpGuestState, SevCommonStateClass, SEV_SNP_GUEST)
|
||
|
|
||
|
struct SevCommonState {
|
||
|
X86ConfidentialGuest parent_obj;
|
||
|
@@ -96,8 +97,22 @@ struct SevGuestState {
|
||
|
bool legacy_vm_type;
|
||
|
};
|
||
|
|
||
|
+struct SevSnpGuestState {
|
||
|
+ SevCommonState parent_obj;
|
||
|
+
|
||
|
+ /* configuration parameters */
|
||
|
+ char *guest_visible_workarounds;
|
||
|
+ char *id_block;
|
||
|
+ char *id_auth;
|
||
|
+ char *host_data;
|
||
|
+
|
||
|
+ struct kvm_sev_snp_launch_start kvm_start_conf;
|
||
|
+ struct kvm_sev_snp_launch_finish kvm_finish_conf;
|
||
|
+};
|
||
|
+
|
||
|
#define DEFAULT_GUEST_POLICY 0x1 /* disable debug */
|
||
|
#define DEFAULT_SEV_DEVICE "/dev/sev"
|
||
|
+#define DEFAULT_SEV_SNP_POLICY 0x30000
|
||
|
|
||
|
#define SEV_INFO_BLOCK_GUID "00f771de-1a7e-4fcb-890e-68c77e2fb44e"
|
||
|
typedef struct __attribute__((__packed__)) SevInfoBlock {
|
||
|
@@ -1500,11 +1515,249 @@ static const TypeInfo sev_guest_info = {
|
||
|
.class_init = sev_guest_class_init,
|
||
|
};
|
||
|
|
||
|
+static void
|
||
|
+sev_snp_guest_get_policy(Object *obj, Visitor *v, const char *name,
|
||
|
+ void *opaque, Error **errp)
|
||
|
+{
|
||
|
+ visit_type_uint64(v, name,
|
||
|
+ (uint64_t *)&SEV_SNP_GUEST(obj)->kvm_start_conf.policy,
|
||
|
+ errp);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_set_policy(Object *obj, Visitor *v, const char *name,
|
||
|
+ void *opaque, Error **errp)
|
||
|
+{
|
||
|
+ visit_type_uint64(v, name,
|
||
|
+ (uint64_t *)&SEV_SNP_GUEST(obj)->kvm_start_conf.policy,
|
||
|
+ errp);
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+sev_snp_guest_get_guest_visible_workarounds(Object *obj, Error **errp)
|
||
|
+{
|
||
|
+ return g_strdup(SEV_SNP_GUEST(obj)->guest_visible_workarounds);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_set_guest_visible_workarounds(Object *obj, const char *value,
|
||
|
+ Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+ struct kvm_sev_snp_launch_start *start = &sev_snp_guest->kvm_start_conf;
|
||
|
+ g_autofree guchar *blob;
|
||
|
+ gsize len;
|
||
|
+
|
||
|
+ g_free(sev_snp_guest->guest_visible_workarounds);
|
||
|
+
|
||
|
+ /* store the base64 str so we don't need to re-encode in getter */
|
||
|
+ sev_snp_guest->guest_visible_workarounds = g_strdup(value);
|
||
|
+
|
||
|
+ blob = qbase64_decode(sev_snp_guest->guest_visible_workarounds,
|
||
|
+ -1, &len, errp);
|
||
|
+ if (!blob) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (len != sizeof(start->gosvw)) {
|
||
|
+ error_setg(errp, "parameter length of %lu exceeds max of %lu",
|
||
|
+ len, sizeof(start->gosvw));
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy(start->gosvw, blob, len);
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+sev_snp_guest_get_id_block(Object *obj, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+
|
||
|
+ return g_strdup(sev_snp_guest->id_block);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_set_id_block(Object *obj, const char *value, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+ struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
|
||
|
+ gsize len;
|
||
|
+
|
||
|
+ g_free(sev_snp_guest->id_block);
|
||
|
+ g_free((guchar *)finish->id_block_uaddr);
|
||
|
+
|
||
|
+ /* store the base64 str so we don't need to re-encode in getter */
|
||
|
+ sev_snp_guest->id_block = g_strdup(value);
|
||
|
+
|
||
|
+ finish->id_block_uaddr =
|
||
|
+ (uint64_t)qbase64_decode(sev_snp_guest->id_block, -1, &len, errp);
|
||
|
+
|
||
|
+ if (!finish->id_block_uaddr) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (len != KVM_SEV_SNP_ID_BLOCK_SIZE) {
|
||
|
+ error_setg(errp, "parameter length of %lu not equal to %u",
|
||
|
+ len, KVM_SEV_SNP_ID_BLOCK_SIZE);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ finish->id_block_en = (len) ? 1 : 0;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+sev_snp_guest_get_id_auth(Object *obj, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+
|
||
|
+ return g_strdup(sev_snp_guest->id_auth);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_set_id_auth(Object *obj, const char *value, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+ struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
|
||
|
+ gsize len;
|
||
|
+
|
||
|
+ g_free(sev_snp_guest->id_auth);
|
||
|
+ g_free((guchar *)finish->id_auth_uaddr);
|
||
|
+
|
||
|
+ /* store the base64 str so we don't need to re-encode in getter */
|
||
|
+ sev_snp_guest->id_auth = g_strdup(value);
|
||
|
+
|
||
|
+ finish->id_auth_uaddr =
|
||
|
+ (uint64_t)qbase64_decode(sev_snp_guest->id_auth, -1, &len, errp);
|
||
|
+
|
||
|
+ if (!finish->id_auth_uaddr) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (len > KVM_SEV_SNP_ID_AUTH_SIZE) {
|
||
|
+ error_setg(errp, "parameter length:ID_AUTH %lu exceeds max of %u",
|
||
|
+ len, KVM_SEV_SNP_ID_AUTH_SIZE);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static bool
|
||
|
+sev_snp_guest_get_author_key_enabled(Object *obj, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+
|
||
|
+ return !!sev_snp_guest->kvm_finish_conf.auth_key_en;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_set_author_key_enabled(Object *obj, bool value, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+
|
||
|
+ sev_snp_guest->kvm_finish_conf.auth_key_en = value;
|
||
|
+}
|
||
|
+
|
||
|
+static bool
|
||
|
+sev_snp_guest_get_vcek_disabled(Object *obj, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+
|
||
|
+ return !!sev_snp_guest->kvm_finish_conf.vcek_disabled;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_set_vcek_disabled(Object *obj, bool value, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+
|
||
|
+ sev_snp_guest->kvm_finish_conf.vcek_disabled = value;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+sev_snp_guest_get_host_data(Object *obj, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+
|
||
|
+ return g_strdup(sev_snp_guest->host_data);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+ struct kvm_sev_snp_launch_finish *finish = &sev_snp_guest->kvm_finish_conf;
|
||
|
+ g_autofree guchar *blob;
|
||
|
+ gsize len;
|
||
|
+
|
||
|
+ g_free(sev_snp_guest->host_data);
|
||
|
+
|
||
|
+ /* store the base64 str so we don't need to re-encode in getter */
|
||
|
+ sev_snp_guest->host_data = g_strdup(value);
|
||
|
+
|
||
|
+ blob = qbase64_decode(sev_snp_guest->host_data, -1, &len, errp);
|
||
|
+
|
||
|
+ if (!blob) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (len != sizeof(finish->host_data)) {
|
||
|
+ error_setg(errp, "parameter length of %lu not equal to %lu",
|
||
|
+ len, sizeof(finish->host_data));
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy(finish->host_data, blob, len);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_class_init(ObjectClass *oc, void *data)
|
||
|
+{
|
||
|
+ object_class_property_add(oc, "policy", "uint64",
|
||
|
+ sev_snp_guest_get_policy,
|
||
|
+ sev_snp_guest_set_policy, NULL, NULL);
|
||
|
+ object_class_property_add_str(oc, "guest-visible-workarounds",
|
||
|
+ sev_snp_guest_get_guest_visible_workarounds,
|
||
|
+ sev_snp_guest_set_guest_visible_workarounds);
|
||
|
+ object_class_property_add_str(oc, "id-block",
|
||
|
+ sev_snp_guest_get_id_block,
|
||
|
+ sev_snp_guest_set_id_block);
|
||
|
+ object_class_property_add_str(oc, "id-auth",
|
||
|
+ sev_snp_guest_get_id_auth,
|
||
|
+ sev_snp_guest_set_id_auth);
|
||
|
+ object_class_property_add_bool(oc, "author-key-enabled",
|
||
|
+ sev_snp_guest_get_author_key_enabled,
|
||
|
+ sev_snp_guest_set_author_key_enabled);
|
||
|
+ object_class_property_add_bool(oc, "vcek-required",
|
||
|
+ sev_snp_guest_get_vcek_disabled,
|
||
|
+ sev_snp_guest_set_vcek_disabled);
|
||
|
+ object_class_property_add_str(oc, "host-data",
|
||
|
+ sev_snp_guest_get_host_data,
|
||
|
+ sev_snp_guest_set_host_data);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+sev_snp_guest_instance_init(Object *obj)
|
||
|
+{
|
||
|
+ SevSnpGuestState *sev_snp_guest = SEV_SNP_GUEST(obj);
|
||
|
+
|
||
|
+ /* default init/start/finish params for kvm */
|
||
|
+ sev_snp_guest->kvm_start_conf.policy = DEFAULT_SEV_SNP_POLICY;
|
||
|
+}
|
||
|
+
|
||
|
+/* guest info specific to sev-snp */
|
||
|
+static const TypeInfo sev_snp_guest_info = {
|
||
|
+ .parent = TYPE_SEV_COMMON,
|
||
|
+ .name = TYPE_SEV_SNP_GUEST,
|
||
|
+ .instance_size = sizeof(SevSnpGuestState),
|
||
|
+ .class_init = sev_snp_guest_class_init,
|
||
|
+ .instance_init = sev_snp_guest_instance_init,
|
||
|
+};
|
||
|
+
|
||
|
static void
|
||
|
sev_register_types(void)
|
||
|
{
|
||
|
type_register_static(&sev_common_info);
|
||
|
type_register_static(&sev_guest_info);
|
||
|
+ type_register_static(&sev_snp_guest_info);
|
||
|
}
|
||
|
|
||
|
type_init(sev_register_types);
|
||
|
diff --git a/target/i386/sev.h b/target/i386/sev.h
|
||
|
index 668374eef3..bedc667eeb 100644
|
||
|
--- a/target/i386/sev.h
|
||
|
+++ b/target/i386/sev.h
|
||
|
@@ -22,6 +22,7 @@
|
||
|
|
||
|
#define TYPE_SEV_COMMON "sev-common"
|
||
|
#define TYPE_SEV_GUEST "sev-guest"
|
||
|
+#define TYPE_SEV_SNP_GUEST "sev-snp-guest"
|
||
|
|
||
|
#define SEV_POLICY_NODBG 0x1
|
||
|
#define SEV_POLICY_NOKS 0x2
|
||
|
--
|
||
|
2.39.3
|
||
|
|