From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
To: Brijesh Singh <brijesh.singh@amd.com>, armbru@redhat.com
Cc: qemu-devel@nongnu.org, "Connor Kuehl" <ckuehl@redhat.com>,
"Philippe Mathieu-Daudé" <philmd@redhat.com>,
"Michael S . Tsirkin" <mst@redhat.com>,
"James Bottomley" <jejb@linux.ibm.com>,
"Tom Lendacky" <thomas.lendacky@amd.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Dov Murik" <dovmurik@linux.ibm.com>,
"David Gibson" <david@gibson.dropbear.id.au>,
"Daniel P. Berrangé" <berrange@redhat.com>,
kvm@vger.kernel.org, "Michael Roth" <michael.roth@amd.com>,
"Eduardo Habkost" <ehabkost@redhat.com>
Subject: Re: [RFC PATCH 2/6] i386/sev: extend sev-guest property to include SEV-SNP
Date: Mon, 12 Jul 2021 15:34:17 +0100 [thread overview]
Message-ID: <YOxS6R5NADizMui2@work-vm> (raw)
In-Reply-To: <20210709215550.32496-3-brijesh.singh@amd.com>
cc'ing in armbru, since he knows about our command line - have we got a
neater way of doing this, or something else that reads config file?
Could the existing -readconfig work?
Although this is a fairly large chunk of data, I don't think it's any
larger than our block device configs on a bad day.
Dave
* Brijesh Singh (brijesh.singh@amd.com) wrote:
> To launch the SEV-SNP guest, a user can specify up to 8 parameters.
> Passing all parameters through command line can be difficult. To simplify
> the launch parameter passing, introduce a .ini-like config file that can be
> used for passing the parameters to the launch flow.
>
> The contents of the config file will look like this:
>
> $ cat snp-launch.init
>
> # SNP launch parameters
> [SEV-SNP]
> init_flags = 0
> policy = 0x1000
> id_block = "YWFhYWFhYWFhYWFhYWFhCg=="
Wouldn't the 'gosvw' and 'hostdata' also be in there?
Dave
>
> Add 'snp' property that can be used to indicate that SEV guest launch
> should enable the SNP support.
>
> SEV-SNP guest launch examples:
>
> 1) launch without additional parameters
>
> $(QEMU_CLI) \
> -object sev-guest,id=sev0,snp=on
>
> 2) launch with optional parameters
> $(QEMU_CLI) \
> -object sev-guest,id=sev0,snp=on,launch-config=<file>
>
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
> docs/amd-memory-encryption.txt | 81 +++++++++++-
> qapi/qom.json | 6 +
> target/i386/sev.c | 227 +++++++++++++++++++++++++++++++++
> 3 files changed, 312 insertions(+), 2 deletions(-)
>
> diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
> index ffca382b5f..322bf38f68 100644
> --- a/docs/amd-memory-encryption.txt
> +++ b/docs/amd-memory-encryption.txt
> @@ -22,8 +22,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,
> LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
> @@ -113,6 +113,83 @@ a SEV-ES guest:
> - Requires in-kernel irqchip - the burden is placed on the hypervisor to
> manage booting APs.
>
> +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:
> +KVM_SNP_INIT, SNP_LAUNCH_START, SNP_LAUNCH_UPDATE, and SNP_LAUNCH_FINISH. These
> +four commands together generate a fresh memory encryption key for the VM,
> +encrypt the boot images for a successful launch.
> +
> +KVM_SNP_INIT is called first to initialize the SEV-SNP firmware and SNP
> +features in the KVM. The feature flags value can be provided through the
> +launch-config file.
> +
> ++------------+-------+----------+---------------------------------+
> +| key | type | default | meaning |
> ++------------+-------+----------+---------------------------------+
> +| init_flags | hex | 0 | SNP feature flags |
> ++-----------------------------------------------------------------+
> +
> +Note: currently the init_flags must be zero.
> +
> +SNP_LAUNCH_START is called first to create a cryptographic launch context
> +within the firmware. To create this context, guest owner must provide a guest
> +policy and other parameters as described in the SEV-SNP firmware
> +specification. The launch parameters should be specified in the launch-config
> +ini file and should be treated as a binary blob and must be passed as-is to
> +the SEV-SNP firmware.
> +
> +The SNP_LAUNCH_START uses the following parameters from the launch-config
> +file. See the SEV-SNP specification for more details.
> +
> ++--------+-------+----------+----------------------------------------------+
> +| key | type | default | meaning |
> ++--------+-------+----------+----------------------------------------------+
> +| policy | hex | 0x30000 | a 64-bit guest policy |
> +| imi_en | bool | 0 | 1 when IMI is enabled |
> +| ma_end | bool | 0 | 1 when migration agent is used |
> +| gosvw | string| 0 | 16-byte base64 encoded string for the guest |
> +| | | | OS visible workaround. |
> ++--------+-------+----------+----------------------------------------------+
> +
> +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 from the launch-config file.
> +
> ++------------+-------+----------+----------------------------------------------+
> +| key | type | default | meaning |
> ++------------+-------+----------+----------------------------------------------+
> +| id_block | string| none | base64 encoded ID block |
> ++------------+-------+----------+----------------------------------------------+
> +| id_auth | string| none | base64 encoded authentication information |
> ++------------+-------+----------+----------------------------------------------+
> +| auth_key_en| bool | 0 | auth block contains author key |
> ++------------+-------+----------+----------------------------------------------+
> +| host_data | string| none | host provided data |
> ++------------+-------+----------+----------------------------------------------+
> +
> +To launch a SEV-SNP guest
> +
> +# ${QEMU} \
> + -machine ...,confidential-guest-support=sev0 \
> + -object sev-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,snp=on
> +
> +To launch a SEV-SNP guest with launch configuration
> +
> +# ${QEMU} \
> + -machine ...,confidential-guest-support=sev0 \
> + -object sev-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,snp=on,launch-config=<config>
> +
> Debugging
> -----------
> Since the memory contents of a SEV guest are encrypted, hypervisor access to
> diff --git a/qapi/qom.json b/qapi/qom.json
> index 652be317b8..bdf89fda27 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -749,6 +749,10 @@
> # @reduced-phys-bits: number of bits in physical addresses that become
> # unavailable when SEV is enabled
> #
> +# @snp: SEV-SNP is enabled (default: 0)
> +#
> +# @launch-config: launch config file to use
> +#
> # Since: 2.12
> ##
> { 'struct': 'SevGuestProperties',
> @@ -758,6 +762,8 @@
> '*policy': 'uint32',
> '*handle': 'uint32',
> '*cbitpos': 'uint32',
> + '*snp': 'bool',
> + '*launch-config': 'str',
> 'reduced-phys-bits': 'uint32' } }
>
> ##
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 83df8c09f6..6b238ef969 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -37,6 +37,11 @@
> #define TYPE_SEV_GUEST "sev-guest"
> OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
>
> +struct snp_launch_config {
> + struct kvm_snp_init init;
> + struct kvm_sev_snp_launch_start start;
> + struct kvm_sev_snp_launch_finish finish;
> +};
>
> /**
> * SevGuestState:
> @@ -58,6 +63,8 @@ struct SevGuestState {
> char *session_file;
> uint32_t cbitpos;
> uint32_t reduced_phys_bits;
> + char *launch_config_file;
> + bool snp;
>
> /* runtime state */
> uint32_t handle;
> @@ -72,10 +79,13 @@ struct SevGuestState {
> uint32_t reset_cs;
> uint32_t reset_ip;
> bool reset_data_valid;
> +
> + struct snp_launch_config snp_config;
> };
>
> #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 {
> @@ -298,6 +308,212 @@ sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
> sev->sev_device = g_strdup(value);
> }
>
> +static void
> +sev_guest_set_snp(Object *obj, bool value, Error **errp)
> +{
> + SevGuestState *sev = SEV_GUEST(obj);
> +
> + sev->snp = value;
> +}
> +
> +static bool
> +sev_guest_get_snp(Object *obj, Error **errp)
> +{
> + SevGuestState *sev = SEV_GUEST(obj);
> +
> + return sev->snp;
> +}
> +
> +
> +static char *
> +sev_guest_get_launch_config_file(Object *obj, Error **errp)
> +{
> + SevGuestState *s = SEV_GUEST(obj);
> +
> + return g_strdup(s->launch_config_file);
> +}
> +
> +static int
> +config_read_uint64(GKeyFile *f, const char *key, uint64_t *value, Error **errp)
> +{
> + g_autoptr(GError) error = NULL;
> + g_autofree gchar *str = NULL;
> + uint64_t res;
> +
> + str = g_key_file_get_string(f, "SEV-SNP", key, &error);
> + if (!str) {
> + /* key not found */
> + return 0;
> + }
> +
> + res = g_ascii_strtoull(str, NULL, 16);
> + if (res == G_MAXUINT64) {
> + error_setg(errp, "Failed to convert %s", str);
> + return 1;
> + }
> +
> + *value = res;
> + return 0;
> +}
> +
> +static int
> +config_read_bool(GKeyFile *f, const char *key, bool *value, Error **errp)
> +{
> + g_autoptr(GError) error = NULL;
> + gboolean val;
> +
> + val = g_key_file_get_boolean(f, "SEV-SNP", key, &error);
> + if (!val && g_error_matches(error, G_KEY_FILE_ERROR,
> + G_KEY_FILE_ERROR_INVALID_VALUE)) {
> + error_setg(errp, "%s", error->message);
> + return 1;
> + }
> +
> + *value = val;
> + return 0;
> +}
> +
> +static int
> +config_read_blob(GKeyFile *f, const char *key, uint8_t *blob, uint32_t len,
> + Error **errp)
> +{
> + g_autoptr(GError) error = NULL;
> + g_autofree guchar *data = NULL;
> + g_autofree gchar *base64 = NULL;
> + gsize size;
> +
> + base64 = g_key_file_get_string(f, "SEV-SNP", key, &error);
> + if (!base64) {
> + /* key not found */
> + return 0;
> + }
> +
> + /* lets decode the value string */
> + data = g_base64_decode(base64, &size);
> + if (!data) {
> + error_setg(errp, "failed to decode '%s'", key);
> + return 1;
> + }
> +
> + /* verify the length */
> + if (len != size) {
> + error_setg(errp, "invalid length for key '%s' (expected %d got %ld)",
> + key, len, size);
> + return 1;
> + }
> +
> + memcpy(blob, data, size);
> + return 0;
> +}
> +
> +static int
> +snp_parse_launch_config(SevGuestState *sev, const char *file, Error **errp)
> +{
> + g_autoptr(GError) error = NULL;
> + g_autoptr(GKeyFile) key_file = g_key_file_new();
> + struct kvm_sev_snp_launch_start *start = &sev->snp_config.start;
> + struct kvm_snp_init *init = &sev->snp_config.init;
> + struct kvm_sev_snp_launch_finish *finish = &sev->snp_config.finish;
> + uint8_t *id_block = NULL, *id_auth = NULL;
> +
> + if (!g_key_file_load_from_file(key_file, file, G_KEY_FILE_NONE, &error)) {
> + error_setg(errp, "Error loading config file: %s", error->message);
> + return 1;
> + }
> +
> + /* Check the group first */
> + if (!g_key_file_has_group(key_file, "SEV-SNP")) {
> + error_setg(errp, "Error parsing config file, group SEV-SNP not found");
> + return 1;
> + }
> +
> + /* Get the init_flags used in KVM_SNP_INIT */
> + if (config_read_uint64(key_file, "init_flags",
> + (uint64_t *)&init->flags, errp)) {
> + goto err;
> + }
> +
> + /* Get the policy used in LAUNCH_START */
> + if (config_read_uint64(key_file, "policy",
> + (uint64_t *)&start->policy, errp)) {
> + goto err;
> + }
> +
> + /* Get IMI_EN used in LAUNCH_START */
> + if (config_read_bool(key_file, "imi_en", (bool *)&start->imi_en, errp)) {
> + goto err;
> + }
> +
> + /* Get MA_EN used in LAUNCH_START */
> + if (config_read_bool(key_file, "imi_en", (bool *)&start->ma_en, errp)) {
> + goto err;
> + }
> +
> + /* Get GOSVW used in LAUNCH_START */
> + if (config_read_blob(key_file, "gosvw", (uint8_t *)&start->gosvw,
> + sizeof(start->gosvw), errp)) {
> + goto err;
> + }
> +
> + /* Get ID block used in LAUNCH_FINISH */
> + if (g_key_file_has_key(key_file, "SEV-SNP", "id_block", &error)) {
> +
> + id_block = g_malloc(KVM_SEV_SNP_ID_BLOCK_SIZE);
> +
> + if (config_read_blob(key_file, "id_block", id_block,
> + KVM_SEV_SNP_ID_BLOCK_SIZE, errp)) {
> + goto err;
> + }
> +
> + finish->id_block_uaddr = (unsigned long)id_block;
> + finish->id_block_en = 1;
> + }
> +
> + /* Get authentication block used in LAUNCH_FINISH */
> + if (g_key_file_has_key(key_file, "SEV-SNP", "id_auth", &error)) {
> +
> + id_auth = g_malloc(KVM_SEV_SNP_ID_AUTH_SIZE);
> +
> + if (config_read_blob(key_file, "auth_block", id_auth,
> + KVM_SEV_SNP_ID_AUTH_SIZE, errp)) {
> + goto err;
> + }
> +
> + finish->id_auth_uaddr = (unsigned long)id_auth;
> +
> + /* Get AUTH_KEY_EN used in LAUNCH_FINISH */
> + if (config_read_bool(key_file, "auth_key_en",
> + (bool *)&finish->auth_key_en, errp)) {
> + goto err;
> + }
> + }
> +
> + /* Get host_data used in LAUNCH_FINISH */
> + if (config_read_blob(key_file, "host_data", (uint8_t *)&finish->host_data,
> + sizeof(finish->host_data), errp)) {
> + goto err;
> + }
> +
> + return 0;
> +
> +err:
> + g_free(id_block);
> + g_free(id_auth);
> + return 1;
> +}
> +
> +static void
> +sev_guest_set_launch_config_file(Object *obj, const char *value, Error **errp)
> +{
> + SevGuestState *s = SEV_GUEST(obj);
> +
> + if (snp_parse_launch_config(s, value, errp)) {
> + return;
> + }
> +
> + s->launch_config_file = g_strdup(value);
> +}
> +
> static void
> sev_guest_class_init(ObjectClass *oc, void *data)
> {
> @@ -316,6 +532,16 @@ sev_guest_class_init(ObjectClass *oc, void *data)
> sev_guest_set_session_file);
> object_class_property_set_description(oc, "session-file",
> "guest owners session parameters (encoded with base64)");
> + object_class_property_add_bool(oc, "snp",
> + sev_guest_get_snp,
> + sev_guest_set_snp);
> + object_class_property_set_description(oc, "snp",
> + "enable SEV-SNP support");
> + object_class_property_add_str(oc, "launch-config",
> + sev_guest_get_launch_config_file,
> + sev_guest_set_launch_config_file);
> + object_class_property_set_description(oc, "launch-config",
> + "the file provides the SEV-SNP guest launch parameters");
> }
>
> static void
> @@ -325,6 +551,7 @@ sev_guest_instance_init(Object *obj)
>
> sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
> sev->policy = DEFAULT_GUEST_POLICY;
> + sev->snp_config.start.policy = DEFAULT_SEV_SNP_POLICY;
> object_property_add_uint32_ptr(obj, "policy", &sev->policy,
> OBJ_PROP_FLAG_READWRITE);
> object_property_add_uint32_ptr(obj, "handle", &sev->handle,
> --
> 2.17.1
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
WARNING: multiple messages have this Message-ID (diff)
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
To: Brijesh Singh <brijesh.singh@amd.com>, armbru@redhat.com
Cc: "Tom Lendacky" <thomas.lendacky@amd.com>,
"Daniel P. Berrangé" <berrange@redhat.com>,
"Eduardo Habkost" <ehabkost@redhat.com>,
kvm@vger.kernel.org, "Michael S . Tsirkin" <mst@redhat.com>,
"Connor Kuehl" <ckuehl@redhat.com>,
"Michael Roth" <michael.roth@amd.com>,
"James Bottomley" <jejb@linux.ibm.com>,
qemu-devel@nongnu.org, "Dov Murik" <dovmurik@linux.ibm.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Philippe Mathieu-Daudé" <philmd@redhat.com>,
"David Gibson" <david@gibson.dropbear.id.au>
Subject: Re: [RFC PATCH 2/6] i386/sev: extend sev-guest property to include SEV-SNP
Date: Mon, 12 Jul 2021 15:34:17 +0100 [thread overview]
Message-ID: <YOxS6R5NADizMui2@work-vm> (raw)
In-Reply-To: <20210709215550.32496-3-brijesh.singh@amd.com>
cc'ing in armbru, since he knows about our command line - have we got a
neater way of doing this, or something else that reads config file?
Could the existing -readconfig work?
Although this is a fairly large chunk of data, I don't think it's any
larger than our block device configs on a bad day.
Dave
* Brijesh Singh (brijesh.singh@amd.com) wrote:
> To launch the SEV-SNP guest, a user can specify up to 8 parameters.
> Passing all parameters through command line can be difficult. To simplify
> the launch parameter passing, introduce a .ini-like config file that can be
> used for passing the parameters to the launch flow.
>
> The contents of the config file will look like this:
>
> $ cat snp-launch.init
>
> # SNP launch parameters
> [SEV-SNP]
> init_flags = 0
> policy = 0x1000
> id_block = "YWFhYWFhYWFhYWFhYWFhCg=="
Wouldn't the 'gosvw' and 'hostdata' also be in there?
Dave
>
> Add 'snp' property that can be used to indicate that SEV guest launch
> should enable the SNP support.
>
> SEV-SNP guest launch examples:
>
> 1) launch without additional parameters
>
> $(QEMU_CLI) \
> -object sev-guest,id=sev0,snp=on
>
> 2) launch with optional parameters
> $(QEMU_CLI) \
> -object sev-guest,id=sev0,snp=on,launch-config=<file>
>
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
> docs/amd-memory-encryption.txt | 81 +++++++++++-
> qapi/qom.json | 6 +
> target/i386/sev.c | 227 +++++++++++++++++++++++++++++++++
> 3 files changed, 312 insertions(+), 2 deletions(-)
>
> diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt
> index ffca382b5f..322bf38f68 100644
> --- a/docs/amd-memory-encryption.txt
> +++ b/docs/amd-memory-encryption.txt
> @@ -22,8 +22,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,
> LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
> @@ -113,6 +113,83 @@ a SEV-ES guest:
> - Requires in-kernel irqchip - the burden is placed on the hypervisor to
> manage booting APs.
>
> +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:
> +KVM_SNP_INIT, SNP_LAUNCH_START, SNP_LAUNCH_UPDATE, and SNP_LAUNCH_FINISH. These
> +four commands together generate a fresh memory encryption key for the VM,
> +encrypt the boot images for a successful launch.
> +
> +KVM_SNP_INIT is called first to initialize the SEV-SNP firmware and SNP
> +features in the KVM. The feature flags value can be provided through the
> +launch-config file.
> +
> ++------------+-------+----------+---------------------------------+
> +| key | type | default | meaning |
> ++------------+-------+----------+---------------------------------+
> +| init_flags | hex | 0 | SNP feature flags |
> ++-----------------------------------------------------------------+
> +
> +Note: currently the init_flags must be zero.
> +
> +SNP_LAUNCH_START is called first to create a cryptographic launch context
> +within the firmware. To create this context, guest owner must provide a guest
> +policy and other parameters as described in the SEV-SNP firmware
> +specification. The launch parameters should be specified in the launch-config
> +ini file and should be treated as a binary blob and must be passed as-is to
> +the SEV-SNP firmware.
> +
> +The SNP_LAUNCH_START uses the following parameters from the launch-config
> +file. See the SEV-SNP specification for more details.
> +
> ++--------+-------+----------+----------------------------------------------+
> +| key | type | default | meaning |
> ++--------+-------+----------+----------------------------------------------+
> +| policy | hex | 0x30000 | a 64-bit guest policy |
> +| imi_en | bool | 0 | 1 when IMI is enabled |
> +| ma_end | bool | 0 | 1 when migration agent is used |
> +| gosvw | string| 0 | 16-byte base64 encoded string for the guest |
> +| | | | OS visible workaround. |
> ++--------+-------+----------+----------------------------------------------+
> +
> +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 from the launch-config file.
> +
> ++------------+-------+----------+----------------------------------------------+
> +| key | type | default | meaning |
> ++------------+-------+----------+----------------------------------------------+
> +| id_block | string| none | base64 encoded ID block |
> ++------------+-------+----------+----------------------------------------------+
> +| id_auth | string| none | base64 encoded authentication information |
> ++------------+-------+----------+----------------------------------------------+
> +| auth_key_en| bool | 0 | auth block contains author key |
> ++------------+-------+----------+----------------------------------------------+
> +| host_data | string| none | host provided data |
> ++------------+-------+----------+----------------------------------------------+
> +
> +To launch a SEV-SNP guest
> +
> +# ${QEMU} \
> + -machine ...,confidential-guest-support=sev0 \
> + -object sev-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,snp=on
> +
> +To launch a SEV-SNP guest with launch configuration
> +
> +# ${QEMU} \
> + -machine ...,confidential-guest-support=sev0 \
> + -object sev-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,snp=on,launch-config=<config>
> +
> Debugging
> -----------
> Since the memory contents of a SEV guest are encrypted, hypervisor access to
> diff --git a/qapi/qom.json b/qapi/qom.json
> index 652be317b8..bdf89fda27 100644
> --- a/qapi/qom.json
> +++ b/qapi/qom.json
> @@ -749,6 +749,10 @@
> # @reduced-phys-bits: number of bits in physical addresses that become
> # unavailable when SEV is enabled
> #
> +# @snp: SEV-SNP is enabled (default: 0)
> +#
> +# @launch-config: launch config file to use
> +#
> # Since: 2.12
> ##
> { 'struct': 'SevGuestProperties',
> @@ -758,6 +762,8 @@
> '*policy': 'uint32',
> '*handle': 'uint32',
> '*cbitpos': 'uint32',
> + '*snp': 'bool',
> + '*launch-config': 'str',
> 'reduced-phys-bits': 'uint32' } }
>
> ##
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 83df8c09f6..6b238ef969 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -37,6 +37,11 @@
> #define TYPE_SEV_GUEST "sev-guest"
> OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
>
> +struct snp_launch_config {
> + struct kvm_snp_init init;
> + struct kvm_sev_snp_launch_start start;
> + struct kvm_sev_snp_launch_finish finish;
> +};
>
> /**
> * SevGuestState:
> @@ -58,6 +63,8 @@ struct SevGuestState {
> char *session_file;
> uint32_t cbitpos;
> uint32_t reduced_phys_bits;
> + char *launch_config_file;
> + bool snp;
>
> /* runtime state */
> uint32_t handle;
> @@ -72,10 +79,13 @@ struct SevGuestState {
> uint32_t reset_cs;
> uint32_t reset_ip;
> bool reset_data_valid;
> +
> + struct snp_launch_config snp_config;
> };
>
> #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 {
> @@ -298,6 +308,212 @@ sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
> sev->sev_device = g_strdup(value);
> }
>
> +static void
> +sev_guest_set_snp(Object *obj, bool value, Error **errp)
> +{
> + SevGuestState *sev = SEV_GUEST(obj);
> +
> + sev->snp = value;
> +}
> +
> +static bool
> +sev_guest_get_snp(Object *obj, Error **errp)
> +{
> + SevGuestState *sev = SEV_GUEST(obj);
> +
> + return sev->snp;
> +}
> +
> +
> +static char *
> +sev_guest_get_launch_config_file(Object *obj, Error **errp)
> +{
> + SevGuestState *s = SEV_GUEST(obj);
> +
> + return g_strdup(s->launch_config_file);
> +}
> +
> +static int
> +config_read_uint64(GKeyFile *f, const char *key, uint64_t *value, Error **errp)
> +{
> + g_autoptr(GError) error = NULL;
> + g_autofree gchar *str = NULL;
> + uint64_t res;
> +
> + str = g_key_file_get_string(f, "SEV-SNP", key, &error);
> + if (!str) {
> + /* key not found */
> + return 0;
> + }
> +
> + res = g_ascii_strtoull(str, NULL, 16);
> + if (res == G_MAXUINT64) {
> + error_setg(errp, "Failed to convert %s", str);
> + return 1;
> + }
> +
> + *value = res;
> + return 0;
> +}
> +
> +static int
> +config_read_bool(GKeyFile *f, const char *key, bool *value, Error **errp)
> +{
> + g_autoptr(GError) error = NULL;
> + gboolean val;
> +
> + val = g_key_file_get_boolean(f, "SEV-SNP", key, &error);
> + if (!val && g_error_matches(error, G_KEY_FILE_ERROR,
> + G_KEY_FILE_ERROR_INVALID_VALUE)) {
> + error_setg(errp, "%s", error->message);
> + return 1;
> + }
> +
> + *value = val;
> + return 0;
> +}
> +
> +static int
> +config_read_blob(GKeyFile *f, const char *key, uint8_t *blob, uint32_t len,
> + Error **errp)
> +{
> + g_autoptr(GError) error = NULL;
> + g_autofree guchar *data = NULL;
> + g_autofree gchar *base64 = NULL;
> + gsize size;
> +
> + base64 = g_key_file_get_string(f, "SEV-SNP", key, &error);
> + if (!base64) {
> + /* key not found */
> + return 0;
> + }
> +
> + /* lets decode the value string */
> + data = g_base64_decode(base64, &size);
> + if (!data) {
> + error_setg(errp, "failed to decode '%s'", key);
> + return 1;
> + }
> +
> + /* verify the length */
> + if (len != size) {
> + error_setg(errp, "invalid length for key '%s' (expected %d got %ld)",
> + key, len, size);
> + return 1;
> + }
> +
> + memcpy(blob, data, size);
> + return 0;
> +}
> +
> +static int
> +snp_parse_launch_config(SevGuestState *sev, const char *file, Error **errp)
> +{
> + g_autoptr(GError) error = NULL;
> + g_autoptr(GKeyFile) key_file = g_key_file_new();
> + struct kvm_sev_snp_launch_start *start = &sev->snp_config.start;
> + struct kvm_snp_init *init = &sev->snp_config.init;
> + struct kvm_sev_snp_launch_finish *finish = &sev->snp_config.finish;
> + uint8_t *id_block = NULL, *id_auth = NULL;
> +
> + if (!g_key_file_load_from_file(key_file, file, G_KEY_FILE_NONE, &error)) {
> + error_setg(errp, "Error loading config file: %s", error->message);
> + return 1;
> + }
> +
> + /* Check the group first */
> + if (!g_key_file_has_group(key_file, "SEV-SNP")) {
> + error_setg(errp, "Error parsing config file, group SEV-SNP not found");
> + return 1;
> + }
> +
> + /* Get the init_flags used in KVM_SNP_INIT */
> + if (config_read_uint64(key_file, "init_flags",
> + (uint64_t *)&init->flags, errp)) {
> + goto err;
> + }
> +
> + /* Get the policy used in LAUNCH_START */
> + if (config_read_uint64(key_file, "policy",
> + (uint64_t *)&start->policy, errp)) {
> + goto err;
> + }
> +
> + /* Get IMI_EN used in LAUNCH_START */
> + if (config_read_bool(key_file, "imi_en", (bool *)&start->imi_en, errp)) {
> + goto err;
> + }
> +
> + /* Get MA_EN used in LAUNCH_START */
> + if (config_read_bool(key_file, "imi_en", (bool *)&start->ma_en, errp)) {
> + goto err;
> + }
> +
> + /* Get GOSVW used in LAUNCH_START */
> + if (config_read_blob(key_file, "gosvw", (uint8_t *)&start->gosvw,
> + sizeof(start->gosvw), errp)) {
> + goto err;
> + }
> +
> + /* Get ID block used in LAUNCH_FINISH */
> + if (g_key_file_has_key(key_file, "SEV-SNP", "id_block", &error)) {
> +
> + id_block = g_malloc(KVM_SEV_SNP_ID_BLOCK_SIZE);
> +
> + if (config_read_blob(key_file, "id_block", id_block,
> + KVM_SEV_SNP_ID_BLOCK_SIZE, errp)) {
> + goto err;
> + }
> +
> + finish->id_block_uaddr = (unsigned long)id_block;
> + finish->id_block_en = 1;
> + }
> +
> + /* Get authentication block used in LAUNCH_FINISH */
> + if (g_key_file_has_key(key_file, "SEV-SNP", "id_auth", &error)) {
> +
> + id_auth = g_malloc(KVM_SEV_SNP_ID_AUTH_SIZE);
> +
> + if (config_read_blob(key_file, "auth_block", id_auth,
> + KVM_SEV_SNP_ID_AUTH_SIZE, errp)) {
> + goto err;
> + }
> +
> + finish->id_auth_uaddr = (unsigned long)id_auth;
> +
> + /* Get AUTH_KEY_EN used in LAUNCH_FINISH */
> + if (config_read_bool(key_file, "auth_key_en",
> + (bool *)&finish->auth_key_en, errp)) {
> + goto err;
> + }
> + }
> +
> + /* Get host_data used in LAUNCH_FINISH */
> + if (config_read_blob(key_file, "host_data", (uint8_t *)&finish->host_data,
> + sizeof(finish->host_data), errp)) {
> + goto err;
> + }
> +
> + return 0;
> +
> +err:
> + g_free(id_block);
> + g_free(id_auth);
> + return 1;
> +}
> +
> +static void
> +sev_guest_set_launch_config_file(Object *obj, const char *value, Error **errp)
> +{
> + SevGuestState *s = SEV_GUEST(obj);
> +
> + if (snp_parse_launch_config(s, value, errp)) {
> + return;
> + }
> +
> + s->launch_config_file = g_strdup(value);
> +}
> +
> static void
> sev_guest_class_init(ObjectClass *oc, void *data)
> {
> @@ -316,6 +532,16 @@ sev_guest_class_init(ObjectClass *oc, void *data)
> sev_guest_set_session_file);
> object_class_property_set_description(oc, "session-file",
> "guest owners session parameters (encoded with base64)");
> + object_class_property_add_bool(oc, "snp",
> + sev_guest_get_snp,
> + sev_guest_set_snp);
> + object_class_property_set_description(oc, "snp",
> + "enable SEV-SNP support");
> + object_class_property_add_str(oc, "launch-config",
> + sev_guest_get_launch_config_file,
> + sev_guest_set_launch_config_file);
> + object_class_property_set_description(oc, "launch-config",
> + "the file provides the SEV-SNP guest launch parameters");
> }
>
> static void
> @@ -325,6 +551,7 @@ sev_guest_instance_init(Object *obj)
>
> sev->sev_device = g_strdup(DEFAULT_SEV_DEVICE);
> sev->policy = DEFAULT_GUEST_POLICY;
> + sev->snp_config.start.policy = DEFAULT_SEV_SNP_POLICY;
> object_property_add_uint32_ptr(obj, "policy", &sev->policy,
> OBJ_PROP_FLAG_READWRITE);
> object_property_add_uint32_ptr(obj, "handle", &sev->handle,
> --
> 2.17.1
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
next prev parent reply other threads:[~2021-07-12 14:34 UTC|newest]
Thread overview: 65+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-09 21:55 [RFC PATCH 0/6] Add AMD Secure Nested Paging (SEV-SNP) support Brijesh Singh
2021-07-09 21:55 ` [RFC PATCH 1/6] linux-header: add the SNP specific command Brijesh Singh
2021-07-10 20:32 ` Michael S. Tsirkin
2021-07-10 20:32 ` Michael S. Tsirkin
2021-07-12 15:48 ` Brijesh Singh
2021-07-19 11:35 ` Dov Murik
2021-07-19 11:35 ` Dov Murik
2021-07-19 14:40 ` Brijesh Singh
2021-07-09 21:55 ` [RFC PATCH 2/6] i386/sev: extend sev-guest property to include SEV-SNP Brijesh Singh
2021-07-12 6:09 ` Dov Murik
2021-07-12 6:09 ` Dov Murik
2021-07-12 14:34 ` Dr. David Alan Gilbert [this message]
2021-07-12 14:34 ` Dr. David Alan Gilbert
2021-07-12 15:59 ` Brijesh Singh
2021-07-12 16:16 ` Dr. David Alan Gilbert
2021-07-12 16:16 ` Dr. David Alan Gilbert
2021-07-12 14:43 ` Daniel P. Berrangé
2021-07-12 14:43 ` Daniel P. Berrangé
2021-07-12 15:56 ` Brijesh Singh
2021-07-12 16:24 ` Daniel P. Berrangé
2021-07-12 16:24 ` Daniel P. Berrangé
2021-07-13 13:54 ` Brijesh Singh
2021-07-13 13:46 ` Markus Armbruster
2021-07-14 14:18 ` Brijesh Singh
2021-07-20 19:42 ` Michael Roth
2021-07-20 21:54 ` Daniel P. Berrangé
2021-07-20 21:54 ` Daniel P. Berrangé
2021-07-21 13:08 ` Markus Armbruster
2021-07-22 0:02 ` Michael Roth
2021-07-22 0:02 ` Michael Roth via
2021-07-13 18:21 ` Eric Blake
2021-07-13 18:21 ` Eric Blake
2021-07-09 21:55 ` [RFC PATCH 3/6] i386/sev: initialize SNP context Brijesh Singh
2021-07-15 9:32 ` Dov Murik
2021-07-15 9:32 ` Dov Murik
2021-07-15 13:24 ` Brijesh Singh
2021-07-09 21:55 ` [RFC PATCH 4/6] i386/sev: add the SNP launch start context Brijesh Singh
2021-07-19 12:34 ` Dov Murik
2021-07-19 12:34 ` Dov Murik
2021-07-19 15:27 ` Brijesh Singh
2021-07-09 21:55 ` [RFC PATCH 5/6] i386/sev: add support to encrypt BIOS when SEV-SNP is enabled Brijesh Singh
2021-07-14 17:08 ` Connor Kuehl
2021-07-14 17:08 ` Connor Kuehl
2021-07-14 18:52 ` Brijesh Singh
2021-07-15 5:54 ` Dov Murik
2021-07-15 5:54 ` Dov Murik
2021-07-19 13:00 ` Dov Murik
2021-07-19 13:00 ` Dov Murik
2021-07-09 21:55 ` [RFC PATCH 6/6] i386/sev: populate secrets and cpuid page and finalize the SNP launch Brijesh Singh
2021-07-14 17:29 ` Dr. David Alan Gilbert
2021-07-14 17:29 ` Dr. David Alan Gilbert
2021-07-14 18:53 ` Brijesh Singh
2021-07-19 11:24 ` Dov Murik
2021-07-19 11:24 ` Dov Murik
2021-07-19 14:45 ` Brijesh Singh
2021-07-12 17:00 ` [RFC PATCH 0/6] Add AMD Secure Nested Paging (SEV-SNP) support Tom Lendacky
2021-07-13 8:05 ` Dov Murik
2021-07-13 8:05 ` Dov Murik
2021-07-13 8:31 ` Dr. David Alan Gilbert
2021-07-13 8:31 ` Dr. David Alan Gilbert
2021-07-13 13:57 ` Brijesh Singh
2021-07-13 14:01 ` Brijesh Singh
2021-07-14 9:52 ` Dr. David Alan Gilbert
2021-07-14 9:52 ` Dr. David Alan Gilbert
2021-07-14 14:23 ` Brijesh Singh
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YOxS6R5NADizMui2@work-vm \
--to=dgilbert@redhat.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=brijesh.singh@amd.com \
--cc=ckuehl@redhat.com \
--cc=david@gibson.dropbear.id.au \
--cc=dovmurik@linux.ibm.com \
--cc=ehabkost@redhat.com \
--cc=jejb@linux.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=michael.roth@amd.com \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=philmd@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=thomas.lendacky@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.