From nobody Mon Feb 9 07:20:16 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0AE0212B60 for ; Fri, 23 Feb 2024 00:43:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708648999; cv=none; b=ZsDGDEPuG8QZMmQOyXZwq/GjBKJHdph9dnc7PPvAMhrNfDfzzzdDJ4tois7Y+zp14XQFn0ZEw8S6feEfk2VzvSpgKAUse8T9hSJTZcXU71hykdiwVk0lq3gxahM7e6p3uj1LiN82vS+mw9rZ/A9ji+qir4JyhWrsXfz9FPSId0M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708648999; c=relaxed/simple; bh=3dMbCHQzR52bpjGwYgn8QVji/JNHNDJooagZhaAHL4A=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=IOn/WVMYnlYoq0+W9UeN6vKBzahQNKW5U7ENrmrc6+PA3mxEt89EMHx1pMU7TWqPY5xxS2d33OEWxrcZEwPiI8DLZJB0hejl6V0NxxBHjcBrWXpjyqFwvKBK7xb4wcoH4yQ2zkHf4HRJVI2D3aiaP2/Tym5SYSe0zm3fgcAUvpI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=F43k/3EB; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="F43k/3EB" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-5ce63e72bc3so290247a12.0 for ; Thu, 22 Feb 2024 16:43:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708648997; x=1709253797; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=QrUKJwHQx6OZ5c5u7S9Sq3lEDPXCQDh1cyYXS22x5bg=; b=F43k/3EB1FyU0k5KVxse9yz12kI+aBYwgTACzj4eXLLnKLAOUDMCiHdffpA5MZ9GEB jJcI5oPGjqMqGWW2T/dtwkxlEKNX35pxU5i6uGVpfD7bXgZhPuIPo7WYo1aEB8zuOqwt v5baZnIB+4GKAIgzyPahht1SPXmQopzHuohtsxaUXD6zOkkJKQugTrNUCHVKriUnQrDN PGAbPEvZEn3GevVqAlZo35dEOOdz1Iw2sJCWNQDz7Yq5NHtJSlN7F3RTnJZD/xmU2avJ wke8iy0HbL/hULQLoEb+dvjC6CNFZ/6INRZMUx01XOJZOD8ww9V4OVJ38NrPHVWpfdii vBeQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708648997; x=1709253797; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=QrUKJwHQx6OZ5c5u7S9Sq3lEDPXCQDh1cyYXS22x5bg=; b=ljHLFwQC7itn4qeqeKE24v2kIatypP1CVB6zLFdvcqetIt18H8vIQztAPiOjC4+DFm ME40t4evIzOEmCUcMiCh0RhBnJ/Wtk5Yn1ivbvciMRj7MtBJMkjdtTTWPUs+kmaVUb2O TjekWEH05dDCm0AC8Ip5Czr6FyT5qiTa8dvEzHF6MAV7lIcjp8CaoxJql/tmr8M+gVs+ 7Swh40DbPkbYcqvts/RlhqGGzbMXABrgx73rLxOzpqUWjokWSYaG316G+tG8DiDBd3wv XSnaD4ib4PpGNi92wOIKYneVmZwq1n47eDJPFEZso1FcTAszWyp9vN+6MF06RwQs2egh FFrA== X-Forwarded-Encrypted: i=1; AJvYcCUVoc5HETD3wezrD7ShkF8VKUIjvnKR3B0G8ftLYuArCj30dWi9lY3t0eUq/kSijGXhQwigVJrfo+ShOr+RDfniMT0xBaYAy+jkPISK X-Gm-Message-State: AOJu0YxQUysEDoVFKdxb1lgeV5B+uerHBngh8+IkafvxSjUAd+LXSqeH zYwpN0y4SMAFGfNGS6iNQcanVswFhlIg8K3mhXWtk4M5RRq0eSUAyUAksW90PepxfmDuP5JB7UP Lrw== X-Google-Smtp-Source: AGHT+IEgZ6Xp4G0QNWZNXsSNaAdKPYaYAdXhVJMDIaBglQolhzxGBOSmSPQxMCreq2B5dM1DsELErPwgM6A= X-Received: from zagreus.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:5c37]) (user=seanjc job=sendgmr) by 2002:a05:6a02:a0e:b0:5dc:85a6:d74d with SMTP id cm14-20020a056a020a0e00b005dc85a6d74dmr962pgb.2.1708648997232; Thu, 22 Feb 2024 16:43:17 -0800 (PST) Reply-To: Sean Christopherson Date: Thu, 22 Feb 2024 16:42:55 -0800 In-Reply-To: <20240223004258.3104051-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240223004258.3104051-1-seanjc@google.com> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog Message-ID: <20240223004258.3104051-9-seanjc@google.com> Subject: [PATCH v9 08/11] KVM: selftests: Add library for creating and interacting with SEV guests From: Sean Christopherson To: Paolo Bonzini , Marc Zyngier , Oliver Upton , Anup Patel , Paul Walmsley , Palmer Dabbelt , Albert Ou , Christian Borntraeger , Janosch Frank , Claudio Imbrenda , Sean Christopherson Cc: kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, kvm-riscv@lists.infradead.org, linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, Vishal Annapurve , Ackerley Tng , Andrew Jones , Tom Lendacky , Michael Roth , Carlos Bilbao , Peter Gonda , Itaru Kitayama Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Peter Gonda Add a library/APIs for creating and interfacing with SEV guests, all of which need some amount of common functionality, e.g. an open file handle for the SEV driver (/dev/sev), ioctl() wrappers to pass said file handle to KVM, tracking of the C-bit, etc. Add an x86-specific hook to initialize address properties, a.k.a. the location of the C-bit. An arch specific hook is rather gross, but x86 already has a dedicated #ifdef-protected kvm_get_cpu_address_width() hook, i.e. the ugliest code already exists. Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vishal Annapurve Cc: Ackerly Tng cc: Andrew Jones Cc: Tom Lendacky Cc: Michael Roth Tested-by: Carlos Bilbao Originally-by: Michael Roth Signed-off-by: Peter Gonda Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/Makefile | 1 + .../kvm/include/x86_64/kvm_util_arch.h | 2 + .../selftests/kvm/include/x86_64/processor.h | 8 ++ .../selftests/kvm/include/x86_64/sev.h | 105 +++++++++++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 1 + .../selftests/kvm/lib/x86_64/processor.c | 17 +++ tools/testing/selftests/kvm/lib/x86_64/sev.c | 110 ++++++++++++++++++ 7 files changed, 244 insertions(+) create mode 100644 tools/testing/selftests/kvm/include/x86_64/sev.h create mode 100644 tools/testing/selftests/kvm/lib/x86_64/sev.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests= /kvm/Makefile index ce58098d80fd..169b6ee8f733 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -38,6 +38,7 @@ LIBKVM_x86_64 +=3D lib/x86_64/hyperv.c LIBKVM_x86_64 +=3D lib/x86_64/memstress.c LIBKVM_x86_64 +=3D lib/x86_64/pmu.c LIBKVM_x86_64 +=3D lib/x86_64/processor.c +LIBKVM_x86_64 +=3D lib/x86_64/sev.c LIBKVM_x86_64 +=3D lib/x86_64/svm.c LIBKVM_x86_64 +=3D lib/x86_64/ucall.c LIBKVM_x86_64 +=3D lib/x86_64/vmx.c diff --git a/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h b/t= ools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h index 17bb38236d97..205ed788aeb8 100644 --- a/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h +++ b/tools/testing/selftests/kvm/include/x86_64/kvm_util_arch.h @@ -8,6 +8,8 @@ struct kvm_vm_arch { uint64_t c_bit; uint64_t s_bit; + int sev_fd; + bool is_pt_protected; }; =20 static inline bool __vm_arch_has_protected_memory(struct kvm_vm_arch *arch) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools= /testing/selftests/kvm/include/x86_64/processor.h index 0f4792083d01..3bd03b088dda 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -23,6 +23,12 @@ extern bool host_cpu_is_intel; extern bool host_cpu_is_amd; =20 +enum vm_guest_x86_subtype { + VM_SUBTYPE_NONE =3D 0, + VM_SUBTYPE_SEV, + VM_SUBTYPE_SEV_ES, +}; + /* Forced emulation prefix, used to invoke the emulator unconditionally. */ #define KVM_FEP "ud2; .byte 'k', 'v', 'm';" =20 @@ -276,6 +282,7 @@ struct kvm_x86_cpu_property { #define X86_PROPERTY_MAX_EXT_LEAF KVM_X86_CPU_PROPERTY(0x80000000, 0, EAX= , 0, 31) #define X86_PROPERTY_MAX_PHY_ADDR KVM_X86_CPU_PROPERTY(0x80000008, 0, EAX= , 0, 7) #define X86_PROPERTY_MAX_VIRT_ADDR KVM_X86_CPU_PROPERTY(0x80000008, 0, EA= X, 8, 15) +#define X86_PROPERTY_SEV_C_BIT KVM_X86_CPU_PROPERTY(0x8000001F, 0, EBX, = 0, 5) #define X86_PROPERTY_PHYS_ADDR_REDUCTION KVM_X86_CPU_PROPERTY(0x8000001F, = 0, EBX, 6, 11) =20 #define X86_PROPERTY_MAX_CENTAUR_LEAF KVM_X86_CPU_PROPERTY(0xC0000000, 0,= EAX, 0, 31) @@ -1093,6 +1100,7 @@ do { \ } while (0) =20 void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bit= s); +void kvm_init_vm_address_properties(struct kvm_vm *vm); bool vm_is_unrestricted_guest(struct kvm_vm *vm); =20 struct ex_regs { diff --git a/tools/testing/selftests/kvm/include/x86_64/sev.h b/tools/testi= ng/selftests/kvm/include/x86_64/sev.h new file mode 100644 index 000000000000..de5283bef752 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86_64/sev.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Helpers used for SEV guests + * + */ +#ifndef SELFTEST_KVM_SEV_H +#define SELFTEST_KVM_SEV_H + +#include +#include + +#include "linux/psp-sev.h" + +#include "kvm_util.h" +#include "svm_util.h" +#include "processor.h" + +enum sev_guest_state { + SEV_GUEST_STATE_UNINITIALIZED =3D 0, + SEV_GUEST_STATE_LAUNCH_UPDATE, + SEV_GUEST_STATE_LAUNCH_SECRET, + SEV_GUEST_STATE_RUNNING, +}; + +#define SEV_POLICY_NO_DBG (1UL << 0) +#define SEV_POLICY_ES (1UL << 2) + +void sev_vm_launch(struct kvm_vm *vm, uint32_t policy); +void sev_vm_launch_measure(struct kvm_vm *vm, uint8_t *measurement); +void sev_vm_launch_finish(struct kvm_vm *vm); + +struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t policy, void *guest_co= de, + struct kvm_vcpu **cpu); + +kvm_static_assert(SEV_RET_SUCCESS =3D=3D 0); + +/* + * The KVM_MEMORY_ENCRYPT_OP uAPI is utter garbage and takes an "unsigned = long" + * instead of a proper struct. The size of the parameter is embedded in t= he + * ioctl number, i.e. is ABI and thus immutable. Hack around the mess by + * creating an overlay to pass in an "unsigned long" without a cast (casti= ng + * will make the compiler unhappy due to dereferencing an aliased pointer). + */ +#define __vm_sev_ioctl(vm, cmd, arg) \ +({ \ + int r; \ + \ + union { \ + struct kvm_sev_cmd c; \ + unsigned long raw; \ + } sev_cmd =3D { .c =3D { \ + .id =3D (cmd), \ + .data =3D (uint64_t)(arg), \ + .sev_fd =3D (vm)->arch.sev_fd, \ + } }; \ + \ + r =3D __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &sev_cmd.raw); \ + r ?: sev_cmd.c.error; \ +}) + +#define vm_sev_ioctl(vm, cmd, arg) \ +({ \ + int ret =3D __vm_sev_ioctl(vm, cmd, arg); \ + \ + __TEST_ASSERT_VM_VCPU_IOCTL(!ret, #cmd, ret, vm); \ +}) + +static inline void sev_vm_init(struct kvm_vm *vm) +{ + vm->arch.sev_fd =3D open_sev_dev_path_or_exit(); + + vm_sev_ioctl(vm, KVM_SEV_INIT, NULL); +} + + +static inline void sev_es_vm_init(struct kvm_vm *vm) +{ + vm->arch.sev_fd =3D open_sev_dev_path_or_exit(); + + vm_sev_ioctl(vm, KVM_SEV_ES_INIT, NULL); +} + +static inline void sev_register_encrypted_memory(struct kvm_vm *vm, + struct userspace_mem_region *region) +{ + struct kvm_enc_region range =3D { + .addr =3D region->region.userspace_addr, + .size =3D region->region.memory_size, + }; + + vm_ioctl(vm, KVM_MEMORY_ENCRYPT_REG_REGION, &range); +} + +static inline void sev_launch_update_data(struct kvm_vm *vm, vm_paddr_t gp= a, + uint64_t size) +{ + struct kvm_sev_launch_update_data update_data =3D { + .uaddr =3D (unsigned long)addr_gpa2hva(vm, gpa), + .len =3D size, + }; + + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_DATA, &update_data); +} + +#endif /* SELFTEST_KVM_SEV_H */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/sel= ftests/kvm/lib/kvm_util.c index 19511137d1ae..b2262b5fad9e 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -317,6 +317,7 @@ struct kvm_vm *____vm_create(struct vm_shape shape) case VM_MODE_PXXV48_4K: #ifdef __x86_64__ kvm_get_cpu_address_width(&vm->pa_bits, &vm->va_bits); + kvm_init_vm_address_properties(vm); /* * Ignore KVM support for 5-level paging (vm->va_bits =3D=3D 57), * it doesn't take effect unless a CR4.LA57 is set, which it diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/tes= ting/selftests/kvm/lib/x86_64/processor.c index 6c1d2c0ec584..aa92220bf5da 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -9,6 +9,7 @@ #include "test_util.h" #include "kvm_util.h" #include "processor.h" +#include "sev.h" =20 #ifndef NUM_INTERRUPTS #define NUM_INTERRUPTS 256 @@ -278,6 +279,9 @@ uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, = uint64_t vaddr, { uint64_t *pml4e, *pdpe, *pde; =20 + TEST_ASSERT(!vm->arch.is_pt_protected, + "Walking page tables of protected guests is impossible"); + TEST_ASSERT(*level >=3D PG_LEVEL_NONE && *level < PG_LEVEL_NUM, "Invalid PG_LEVEL_* '%d'", *level); =20 @@ -573,6 +577,11 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm) vm_create_irqchip(vm); sync_global_to_guest(vm, host_cpu_is_intel); sync_global_to_guest(vm, host_cpu_is_amd); + + if (vm->subtype =3D=3D VM_SUBTYPE_SEV) + sev_vm_init(vm); + else if (vm->subtype =3D=3D VM_SUBTYPE_SEV_ES) + sev_es_vm_init(vm); } =20 struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, @@ -1063,6 +1072,14 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits= , unsigned int *va_bits) } } =20 +void kvm_init_vm_address_properties(struct kvm_vm *vm) +{ + if (vm->subtype =3D=3D VM_SUBTYPE_SEV) { + vm->arch.c_bit =3D BIT_ULL(this_cpu_property(X86_PROPERTY_SEV_C_BIT)); + vm->gpa_tag_mask =3D vm->arch.c_bit; + } +} + static void set_idt_entry(struct kvm_vm *vm, int vector, unsigned long add= r, int dpl, unsigned short selector) { diff --git a/tools/testing/selftests/kvm/lib/x86_64/sev.c b/tools/testing/s= elftests/kvm/lib/x86_64/sev.c new file mode 100644 index 000000000000..9f5a3dbb5e65 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86_64/sev.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include +#include + +#include "sev.h" + +/* + * sparsebit_next_clear() can return 0 if [x, 2**64-1] are all set, and the + * -1 would then cause an underflow back to 2**64 - 1. This is expected and + * correct. + * + * If the last range in the sparsebit is [x, y] and we try to iterate, + * sparsebit_next_set() will return 0, and sparsebit_next_clear() will try + * and find the first range, but that's correct because the condition + * expression would cause us to quit the loop. + */ +static void encrypt_region(struct kvm_vm *vm, struct userspace_mem_region = *region) +{ + const struct sparsebit *protected_phy_pages =3D region->protected_phy_pag= es; + const vm_paddr_t gpa_base =3D region->region.guest_phys_addr; + const sparsebit_idx_t lowest_page_in_region =3D gpa_base >> vm->page_shif= t; + sparsebit_idx_t i, j; + + if (!sparsebit_any_set(protected_phy_pages)) + return; + + sev_register_encrypted_memory(vm, region); + + sparsebit_for_each_set_range(protected_phy_pages, i, j) { + const uint64_t size =3D (j - i + 1) * vm->page_size; + const uint64_t offset =3D (i - lowest_page_in_region) * vm->page_size; + + sev_launch_update_data(vm, gpa_base + offset, size); + } +} + +void sev_vm_launch(struct kvm_vm *vm, uint32_t policy) +{ + struct kvm_sev_launch_start launch_start =3D { + .policy =3D policy, + }; + struct userspace_mem_region *region; + struct kvm_sev_guest_status status; + int ctr; + + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_START, &launch_start); + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status); + + TEST_ASSERT_EQ(status.policy, policy); + TEST_ASSERT_EQ(status.state, SEV_GUEST_STATE_LAUNCH_UPDATE); + + hash_for_each(vm->regions.slot_hash, ctr, region, slot_node) + encrypt_region(vm, region); + + vm->arch.is_pt_protected =3D true; +} + +void sev_vm_launch_measure(struct kvm_vm *vm, uint8_t *measurement) +{ + struct kvm_sev_launch_measure launch_measure; + struct kvm_sev_guest_status guest_status; + + launch_measure.len =3D 256; + launch_measure.uaddr =3D (__u64)measurement; + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_MEASURE, &launch_measure); + + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &guest_status); + TEST_ASSERT_EQ(guest_status.state, SEV_GUEST_STATE_LAUNCH_SECRET); +} + +void sev_vm_launch_finish(struct kvm_vm *vm) +{ + struct kvm_sev_guest_status status; + + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status); + TEST_ASSERT(status.state =3D=3D SEV_GUEST_STATE_LAUNCH_UPDATE || + status.state =3D=3D SEV_GUEST_STATE_LAUNCH_SECRET, + "Unexpected guest state: %d", status.state); + + vm_sev_ioctl(vm, KVM_SEV_LAUNCH_FINISH, NULL); + + vm_sev_ioctl(vm, KVM_SEV_GUEST_STATUS, &status); + TEST_ASSERT_EQ(status.state, SEV_GUEST_STATE_RUNNING); +} + +struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t policy, void *guest_co= de, + struct kvm_vcpu **cpu) +{ + struct vm_shape shape =3D { + .type =3D VM_TYPE_DEFAULT, + .mode =3D VM_MODE_DEFAULT, + .subtype =3D VM_SUBTYPE_SEV, + }; + struct kvm_vm *vm; + struct kvm_vcpu *cpus[1]; + uint8_t measurement[512]; + + vm =3D __vm_create_with_vcpus(shape, 1, 0, guest_code, cpus); + *cpu =3D cpus[0]; + + sev_vm_launch(vm, policy); + + /* TODO: Validate the measurement is as expected. */ + sev_vm_launch_measure(vm, measurement); + + sev_vm_launch_finish(vm); + + return vm; +} --=20 2.44.0.rc0.258.g7320e95886-goog