From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
To: Brijesh Singh <brijesh.singh@amd.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 6/6] i386/sev: populate secrets and cpuid page and finalize the SNP launch
Date: Wed, 14 Jul 2021 18:29:40 +0100 [thread overview]
Message-ID: <YO8fBDve7yOP4BZi@work-vm> (raw)
In-Reply-To: <20210709215550.32496-7-brijesh.singh@amd.com>
* Brijesh Singh (brijesh.singh@amd.com) wrote:
> During the SNP guest launch sequence, a special secrets and cpuid page
> needs to be populated by the SEV-SNP firmware. The secrets page contains
> the VM Platform Communication Key (VMPCKs) used by the guest to send and
> receive secure messages to the PSP. And CPUID page will contain the CPUID
> value filtered through the PSP.
>
> The guest BIOS (OVMF) reserves these pages in MEMFD and location of it
> is available through the SNP boot block GUID. While finalizing the guest
> boot flow, lookup for the boot block and call the SNP_LAUNCH_UPDATE
> command to populate secrets and cpuid pages.
>
> In order to support early boot code, the OVMF may ask hypervisor to
> request the pre-validation of certain memory range. If such range is
> present the call LAUNCH_UPDATE command to validate those address range
> without affecting the measurement. See the SEV-SNP specification for
> further details.
>
> Finally, call the SNP_LAUNCH_FINISH to finalize the guest boot.
>
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
> target/i386/sev.c | 184 ++++++++++++++++++++++++++++++++++++++-
> target/i386/trace-events | 2 +
> 2 files changed, 184 insertions(+), 2 deletions(-)
>
> diff --git a/target/i386/sev.c b/target/i386/sev.c
> index 41dcb084d1..f438e09d33 100644
> --- a/target/i386/sev.c
> +++ b/target/i386/sev.c
> @@ -93,6 +93,19 @@ typedef struct __attribute__((__packed__)) SevInfoBlock {
> uint32_t reset_addr;
> } SevInfoBlock;
>
> +#define SEV_SNP_BOOT_BLOCK_GUID "bd39c0c2-2f8e-4243-83e8-1b74cebcb7d9"
> +typedef struct __attribute__((__packed__)) SevSnpBootInfoBlock {
> + /* Prevalidate range address */
> + uint32_t pre_validated_start;
> + uint32_t pre_validated_end;
> + /* Secrets page address */
> + uint32_t secrets_addr;
> + uint32_t secrets_len;
> + /* CPUID page address */
> + uint32_t cpuid_addr;
> + uint32_t cpuid_len;
> +} SevSnpBootInfoBlock;
> +
> static SevGuestState *sev_guest;
> static Error *sev_mig_blocker;
>
> @@ -1014,6 +1027,158 @@ static Notifier sev_machine_done_notify = {
> .notify = sev_launch_get_measure,
> };
>
> +static int
> +sev_snp_launch_update_gpa(uint32_t hwaddr, uint32_t size, uint8_t type)
> +{
> + void *hva;
> + MemoryRegion *mr = NULL;
> +
> + hva = gpa2hva(&mr, hwaddr, size, NULL);
> + if (!hva) {
> + error_report("SEV-SNP failed to get HVA for GPA 0x%x", hwaddr);
> + return 1;
> + }
> +
> + return sev_snp_launch_update(sev_guest, hva, size, type);
> +}
> +
> +struct snp_pre_validated_range {
> + uint32_t start;
> + uint32_t end;
> +};
Just a thought, but maybe use a 'Range' from include/qemu/range.h ?
Dave
> +static struct snp_pre_validated_range pre_validated[2];
> +
> +static bool
> +detectoverlap(uint32_t start, uint32_t end,
> + struct snp_pre_validated_range *overlap)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(pre_validated); i++) {
> + if (pre_validated[i].start < end && start < pre_validated[i].end) {
> + memcpy(overlap, &pre_validated[i], sizeof(*overlap));
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static void snp_ovmf_boot_block_setup(void)
> +{
> + struct snp_pre_validated_range overlap;
> + SevSnpBootInfoBlock *info;
> + uint32_t start, end, sz;
> + int ret;
> +
> + /*
> + * Extract the SNP boot block for the SEV-SNP guests by locating the
> + * SNP_BOOT GUID. The boot block contains the information such as location
> + * of secrets and CPUID page, additionaly it may contain the range of
> + * memory that need to be pre-validated for the boot.
> + */
> + if (!pc_system_ovmf_table_find(SEV_SNP_BOOT_BLOCK_GUID,
> + (uint8_t **)&info, NULL)) {
> + error_report("SEV-SNP: failed to find the SNP boot block");
> + exit(1);
> + }
> +
> + trace_kvm_sev_snp_ovmf_boot_block_info(info->secrets_addr,
> + info->secrets_len, info->cpuid_addr,
> + info->cpuid_len,
> + info->pre_validated_start,
> + info->pre_validated_end);
> +
> + /* Populate the secrets page */
> + ret = sev_snp_launch_update_gpa(info->secrets_addr, info->secrets_len,
> + KVM_SEV_SNP_PAGE_TYPE_SECRETS);
> + if (ret) {
> + error_report("SEV-SNP: failed to insert secret page GPA 0x%x",
> + info->secrets_addr);
> + exit(1);
> + }
> +
> + /* Populate the cpuid page */
> + ret = sev_snp_launch_update_gpa(info->cpuid_addr, info->cpuid_len,
> + KVM_SEV_SNP_PAGE_TYPE_CPUID);
> + if (ret) {
> + error_report("SEV-SNP: failed to insert cpuid page GPA 0x%x",
> + info->cpuid_addr);
> + exit(1);
> + }
> +
> + /*
> + * Pre-validate the range using the LAUNCH_UPDATE_DATA, if the
> + * pre-validation range contains the CPUID and Secret page GPA then skip
> + * it. This is because SEV-SNP firmware pre-validates those pages as part
> + * of adding secrets and cpuid LAUNCH_UPDATE type.
> + */
> + pre_validated[0].start = info->secrets_addr;
> + pre_validated[0].end = info->secrets_addr + info->secrets_len;
> + pre_validated[1].start = info->cpuid_addr;
> + pre_validated[1].end = info->cpuid_addr + info->cpuid_len;
> + start = info->pre_validated_start;
> + end = info->pre_validated_end;
> +
> + while (start < end) {
> + /* Check if the requested range overlaps with Secrets and CPUID page */
> + if (detectoverlap(start, end, &overlap)) {
> + if (start < overlap.start) {
> + sz = overlap.start - start;
> + if (sev_snp_launch_update_gpa(start, sz,
> + KVM_SEV_SNP_PAGE_TYPE_UNMEASURED)) {
> + error_report("SEV-SNP: failed to validate gpa 0x%x sz %d",
> + start, sz);
> + exit(1);
> + }
> + }
> +
> + start = overlap.end;
> + continue;
> + }
> +
> + /* Validate the remaining range */
> + if (sev_snp_launch_update_gpa(start, end - start,
> + KVM_SEV_SNP_PAGE_TYPE_UNMEASURED)) {
> + error_report("SEV-SNP: failed to validate gpa 0x%x sz %d",
> + start, end - start);
> + exit(1);
> + }
> +
> + start = end;
> + }
> +}
> +
> +static void
> +sev_snp_launch_finish(SevGuestState *sev)
> +{
> + int ret, error;
> + Error *local_err = NULL;
> + struct kvm_sev_snp_launch_finish *finish = &sev->snp_config.finish;
> +
> + trace_kvm_sev_snp_launch_finish();
> + ret = sev_ioctl(sev->sev_fd, KVM_SEV_SNP_LAUNCH_FINISH, finish, &error);
> + if (ret) {
> + error_report("%s: SNP_LAUNCH_FINISH ret=%d fw_error=%d '%s'",
> + __func__, ret, error, fw_error_to_str(error));
> + exit(1);
> + }
> +
> + sev_set_guest_state(sev, SEV_STATE_RUNNING);
> +
> + /* add migration blocker */
> + error_setg(&sev_mig_blocker,
> + "SEV: Migration is not implemented");
> + ret = migrate_add_blocker(sev_mig_blocker, &local_err);
> + if (local_err) {
> + error_report_err(local_err);
> + error_free(sev_mig_blocker);
> + exit(1);
> + }
> +}
> +
> +
> static void
> sev_launch_finish(SevGuestState *sev)
> {
> @@ -1048,7 +1213,12 @@ sev_vm_state_change(void *opaque, bool running, RunState state)
>
> if (running) {
> if (!sev_check_state(sev, SEV_STATE_RUNNING)) {
> - sev_launch_finish(sev);
> + if (sev_snp_enabled()) {
> + snp_ovmf_boot_block_setup();
> + sev_snp_launch_finish(sev);
> + } else {
> + sev_launch_finish(sev);
> + }
> }
> }
> }
> @@ -1164,7 +1334,17 @@ int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
> }
>
> ram_block_notifier_add(&sev_ram_notifier);
> - qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
> +
> + /*
> + * The machine done notify event is used by the SEV guest to get the
> + * measurement of the encrypted images. When SEV-SNP is enabled then
> + * measurement is part of the attestation report and the measurement
> + * command does not exist. So skip registering the notifier.
> + */
> + if (!sev_snp_enabled()) {
> + qemu_add_machine_init_done_notifier(&sev_machine_done_notify);
> + }
> +
> qemu_add_vm_change_state_handler(sev_vm_state_change, sev);
>
> cgs->ready = true;
> diff --git a/target/i386/trace-events b/target/i386/trace-events
> index 0c2d250206..db91287439 100644
> --- a/target/i386/trace-events
> +++ b/target/i386/trace-events
> @@ -13,3 +13,5 @@ kvm_sev_launch_secret(uint64_t hpa, uint64_t hva, uint64_t secret, int len) "hpa
> kvm_sev_attestation_report(const char *mnonce, const char *data) "mnonce %s data %s"
> kvm_sev_snp_launch_start(uint64_t policy) "policy 0x%" PRIx64
> kvm_sev_snp_launch_update(void *addr, uint64_t len, int type) "addr %p len 0x%" PRIx64 " type %d"
> +kvm_sev_snp_launch_finish(void) ""
> +kvm_sev_snp_ovmf_boot_block_info(uint32_t secrets_gpa, uint32_t slen, uint32_t cpuid_gpa, uint32_t clen, uint32_t s, uint32_t e) "secrets 0x%x+0x%x cpuid 0x%x+0x%x pre-validate 0x%x+0x%x"
> --
> 2.17.1
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
next prev parent reply other threads:[~2021-07-14 17:31 UTC|newest]
Thread overview: 45+ 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-12 15:48 ` Brijesh Singh
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 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 14:43 ` Daniel P. Berrangé
2021-07-12 15:56 ` Brijesh Singh
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-21 13:08 ` Markus Armbruster
2021-07-22 0:02 ` Michael Roth via
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 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 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 18:52 ` Brijesh Singh
2021-07-15 5:54 ` 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 [this message]
2021-07-14 18:53 ` Brijesh Singh
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: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 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=YO8fBDve7yOP4BZi@work-vm \
--to=dgilbert@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).