Merge tag 'kvm-x86-selftests-6.9' of https://github.com/kvm-x86/linux into HEAD
KVM selftests changes for 6.9: - Add macros to reduce the amount of boilerplate code needed to write "simple" selftests, and to utilize selftest TAP infrastructure, which is especially beneficial for KVM selftests with multiple testcases. - Add basic smoke tests for SEV and SEV-ES, along with a pile of library support for handling private/encrypted/protected memory. - Fix benign bugs where tests neglect to close() guest_memfd files.
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef SELFTEST_KVM_UTIL_ARCH_H
|
||||
#define SELFTEST_KVM_UTIL_ARCH_H
|
||||
|
||||
struct kvm_vm_arch {};
|
||||
|
||||
#endif // SELFTEST_KVM_UTIL_ARCH_H
|
||||
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Macros for defining a KVM test
|
||||
*
|
||||
* Copyright (C) 2022, Google LLC.
|
||||
*/
|
||||
|
||||
#ifndef SELFTEST_KVM_TEST_HARNESS_H
|
||||
#define SELFTEST_KVM_TEST_HARNESS_H
|
||||
|
||||
#include "kselftest_harness.h"
|
||||
|
||||
#define KVM_ONE_VCPU_TEST_SUITE(name) \
|
||||
FIXTURE(name) { \
|
||||
struct kvm_vcpu *vcpu; \
|
||||
}; \
|
||||
\
|
||||
FIXTURE_SETUP(name) { \
|
||||
(void)vm_create_with_one_vcpu(&self->vcpu, NULL); \
|
||||
} \
|
||||
\
|
||||
FIXTURE_TEARDOWN(name) { \
|
||||
kvm_vm_free(self->vcpu->vm); \
|
||||
}
|
||||
|
||||
#define KVM_ONE_VCPU_TEST(suite, test, guestcode) \
|
||||
static void __suite##_##test(struct kvm_vcpu *vcpu); \
|
||||
\
|
||||
TEST_F(suite, test) \
|
||||
{ \
|
||||
vcpu_arch_set_entry_point(self->vcpu, guestcode); \
|
||||
__suite##_##test(self->vcpu); \
|
||||
} \
|
||||
static void __suite##_##test(struct kvm_vcpu *vcpu)
|
||||
|
||||
#endif /* SELFTEST_KVM_TEST_HARNESS_H */
|
||||
@@ -18,9 +18,11 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/kvm.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "kvm_util_arch.h"
|
||||
#include "sparsebit.h"
|
||||
|
||||
/*
|
||||
@@ -46,6 +48,7 @@ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */
|
||||
struct userspace_mem_region {
|
||||
struct kvm_userspace_memory_region2 region;
|
||||
struct sparsebit *unused_phy_pages;
|
||||
struct sparsebit *protected_phy_pages;
|
||||
int fd;
|
||||
off_t offset;
|
||||
enum vm_mem_backing_src_type backing_src_type;
|
||||
@@ -90,6 +93,7 @@ enum kvm_mem_region_type {
|
||||
struct kvm_vm {
|
||||
int mode;
|
||||
unsigned long type;
|
||||
uint8_t subtype;
|
||||
int kvm_fd;
|
||||
int fd;
|
||||
unsigned int pgtable_levels;
|
||||
@@ -111,6 +115,9 @@ struct kvm_vm {
|
||||
vm_vaddr_t idt;
|
||||
vm_vaddr_t handlers;
|
||||
uint32_t dirty_ring_size;
|
||||
uint64_t gpa_tag_mask;
|
||||
|
||||
struct kvm_vm_arch arch;
|
||||
|
||||
/* Cache of information for binary stats interface */
|
||||
int stats_fd;
|
||||
@@ -191,10 +198,14 @@ enum vm_guest_mode {
|
||||
};
|
||||
|
||||
struct vm_shape {
|
||||
enum vm_guest_mode mode;
|
||||
unsigned int type;
|
||||
uint32_t type;
|
||||
uint8_t mode;
|
||||
uint8_t subtype;
|
||||
uint16_t padding;
|
||||
};
|
||||
|
||||
kvm_static_assert(sizeof(struct vm_shape) == sizeof(uint64_t));
|
||||
|
||||
#define VM_TYPE_DEFAULT 0
|
||||
|
||||
#define VM_SHAPE(__mode) \
|
||||
@@ -564,6 +575,13 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
|
||||
uint64_t guest_paddr, uint32_t slot, uint64_t npages,
|
||||
uint32_t flags, int guest_memfd_fd, uint64_t guest_memfd_offset);
|
||||
|
||||
#ifndef vm_arch_has_protected_memory
|
||||
static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
|
||||
void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa);
|
||||
void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot);
|
||||
@@ -573,6 +591,9 @@ vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_mi
|
||||
vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min);
|
||||
vm_vaddr_t __vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min,
|
||||
enum kvm_mem_region_type type);
|
||||
vm_vaddr_t vm_vaddr_alloc_shared(struct kvm_vm *vm, size_t sz,
|
||||
vm_vaddr_t vaddr_min,
|
||||
enum kvm_mem_region_type type);
|
||||
vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages);
|
||||
vm_vaddr_t __vm_vaddr_alloc_page(struct kvm_vm *vm,
|
||||
enum kvm_mem_region_type type);
|
||||
@@ -585,6 +606,12 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva);
|
||||
vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva);
|
||||
void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa);
|
||||
|
||||
|
||||
static inline vm_paddr_t vm_untag_gpa(struct kvm_vm *vm, vm_paddr_t gpa)
|
||||
{
|
||||
return gpa & ~vm->gpa_tag_mask;
|
||||
}
|
||||
|
||||
void vcpu_run(struct kvm_vcpu *vcpu);
|
||||
int _vcpu_run(struct kvm_vcpu *vcpu);
|
||||
|
||||
@@ -827,10 +854,23 @@ const char *exit_reason_str(unsigned int exit_reason);
|
||||
|
||||
vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min,
|
||||
uint32_t memslot);
|
||||
vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
|
||||
vm_paddr_t paddr_min, uint32_t memslot);
|
||||
vm_paddr_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
|
||||
vm_paddr_t paddr_min, uint32_t memslot,
|
||||
bool protected);
|
||||
vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm);
|
||||
|
||||
static inline vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num,
|
||||
vm_paddr_t paddr_min, uint32_t memslot)
|
||||
{
|
||||
/*
|
||||
* By default, allocate memory as protected for VMs that support
|
||||
* protected memory, as the majority of memory for such VMs is
|
||||
* protected, i.e. using shared memory is effectively opt-in.
|
||||
*/
|
||||
return __vm_phy_pages_alloc(vm, num, paddr_min, memslot,
|
||||
vm_arch_has_protected_memory(vm));
|
||||
}
|
||||
|
||||
/*
|
||||
* ____vm_create() does KVM_CREATE_VM and little else. __vm_create() also
|
||||
* loads the test binary into guest memory and creates an IRQ chip (x86 only).
|
||||
@@ -969,15 +1009,18 @@ static inline void vcpu_dump(FILE *stream, struct kvm_vcpu *vcpu,
|
||||
* Input Args:
|
||||
* vm - Virtual Machine
|
||||
* vcpu_id - The id of the VCPU to add to the VM.
|
||||
* guest_code - The vCPU's entry point
|
||||
*/
|
||||
struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
|
||||
void *guest_code);
|
||||
struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id);
|
||||
void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code);
|
||||
|
||||
static inline struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
|
||||
void *guest_code)
|
||||
{
|
||||
return vm_arch_vcpu_add(vm, vcpu_id, guest_code);
|
||||
struct kvm_vcpu *vcpu = vm_arch_vcpu_add(vm, vcpu_id);
|
||||
|
||||
vcpu_arch_set_entry_point(vcpu, guest_code);
|
||||
|
||||
return vcpu;
|
||||
}
|
||||
|
||||
/* Re-create a vCPU after restarting a VM, e.g. for state save/restore tests. */
|
||||
@@ -1081,6 +1124,8 @@ void kvm_selftest_arch_init(void);
|
||||
|
||||
void kvm_arch_vm_post_create(struct kvm_vm *vm);
|
||||
|
||||
bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr);
|
||||
|
||||
uint32_t guest_get_vcpuid(void);
|
||||
|
||||
#endif /* SELFTEST_KVM_UTIL_BASE_H */
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef SELFTEST_KVM_UTIL_ARCH_H
|
||||
#define SELFTEST_KVM_UTIL_ARCH_H
|
||||
|
||||
struct kvm_vm_arch {};
|
||||
|
||||
#endif // SELFTEST_KVM_UTIL_ARCH_H
|
||||
@@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef SELFTEST_KVM_UTIL_ARCH_H
|
||||
#define SELFTEST_KVM_UTIL_ARCH_H
|
||||
|
||||
struct kvm_vm_arch {};
|
||||
|
||||
#endif // SELFTEST_KVM_UTIL_ARCH_H
|
||||
@@ -30,26 +30,26 @@ typedef uint64_t sparsebit_num_t;
|
||||
|
||||
struct sparsebit *sparsebit_alloc(void);
|
||||
void sparsebit_free(struct sparsebit **sbitp);
|
||||
void sparsebit_copy(struct sparsebit *dstp, struct sparsebit *src);
|
||||
void sparsebit_copy(struct sparsebit *dstp, const struct sparsebit *src);
|
||||
|
||||
bool sparsebit_is_set(struct sparsebit *sbit, sparsebit_idx_t idx);
|
||||
bool sparsebit_is_set_num(struct sparsebit *sbit,
|
||||
bool sparsebit_is_set(const struct sparsebit *sbit, sparsebit_idx_t idx);
|
||||
bool sparsebit_is_set_num(const struct sparsebit *sbit,
|
||||
sparsebit_idx_t idx, sparsebit_num_t num);
|
||||
bool sparsebit_is_clear(struct sparsebit *sbit, sparsebit_idx_t idx);
|
||||
bool sparsebit_is_clear_num(struct sparsebit *sbit,
|
||||
bool sparsebit_is_clear(const struct sparsebit *sbit, sparsebit_idx_t idx);
|
||||
bool sparsebit_is_clear_num(const struct sparsebit *sbit,
|
||||
sparsebit_idx_t idx, sparsebit_num_t num);
|
||||
sparsebit_num_t sparsebit_num_set(struct sparsebit *sbit);
|
||||
bool sparsebit_any_set(struct sparsebit *sbit);
|
||||
bool sparsebit_any_clear(struct sparsebit *sbit);
|
||||
bool sparsebit_all_set(struct sparsebit *sbit);
|
||||
bool sparsebit_all_clear(struct sparsebit *sbit);
|
||||
sparsebit_idx_t sparsebit_first_set(struct sparsebit *sbit);
|
||||
sparsebit_idx_t sparsebit_first_clear(struct sparsebit *sbit);
|
||||
sparsebit_idx_t sparsebit_next_set(struct sparsebit *sbit, sparsebit_idx_t prev);
|
||||
sparsebit_idx_t sparsebit_next_clear(struct sparsebit *sbit, sparsebit_idx_t prev);
|
||||
sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *sbit,
|
||||
sparsebit_num_t sparsebit_num_set(const struct sparsebit *sbit);
|
||||
bool sparsebit_any_set(const struct sparsebit *sbit);
|
||||
bool sparsebit_any_clear(const struct sparsebit *sbit);
|
||||
bool sparsebit_all_set(const struct sparsebit *sbit);
|
||||
bool sparsebit_all_clear(const struct sparsebit *sbit);
|
||||
sparsebit_idx_t sparsebit_first_set(const struct sparsebit *sbit);
|
||||
sparsebit_idx_t sparsebit_first_clear(const struct sparsebit *sbit);
|
||||
sparsebit_idx_t sparsebit_next_set(const struct sparsebit *sbit, sparsebit_idx_t prev);
|
||||
sparsebit_idx_t sparsebit_next_clear(const struct sparsebit *sbit, sparsebit_idx_t prev);
|
||||
sparsebit_idx_t sparsebit_next_set_num(const struct sparsebit *sbit,
|
||||
sparsebit_idx_t start, sparsebit_num_t num);
|
||||
sparsebit_idx_t sparsebit_next_clear_num(struct sparsebit *sbit,
|
||||
sparsebit_idx_t sparsebit_next_clear_num(const struct sparsebit *sbit,
|
||||
sparsebit_idx_t start, sparsebit_num_t num);
|
||||
|
||||
void sparsebit_set(struct sparsebit *sbitp, sparsebit_idx_t idx);
|
||||
@@ -62,9 +62,29 @@ void sparsebit_clear_num(struct sparsebit *sbitp,
|
||||
sparsebit_idx_t start, sparsebit_num_t num);
|
||||
void sparsebit_clear_all(struct sparsebit *sbitp);
|
||||
|
||||
void sparsebit_dump(FILE *stream, struct sparsebit *sbit,
|
||||
void sparsebit_dump(FILE *stream, const struct sparsebit *sbit,
|
||||
unsigned int indent);
|
||||
void sparsebit_validate_internal(struct sparsebit *sbit);
|
||||
void sparsebit_validate_internal(const struct sparsebit *sbit);
|
||||
|
||||
/*
|
||||
* Iterate over an inclusive ranges within sparsebit @s. In each iteration,
|
||||
* @range_begin and @range_end will take the beginning and end of the set
|
||||
* range, which are of type sparsebit_idx_t.
|
||||
*
|
||||
* For example, if the range [3, 7] (inclusive) is set, within the
|
||||
* iteration,@range_begin will take the value 3 and @range_end will take
|
||||
* the value 7.
|
||||
*
|
||||
* Ensure that there is at least one bit set before using this macro with
|
||||
* sparsebit_any_set(), because sparsebit_first_set() will abort if none
|
||||
* are set.
|
||||
*/
|
||||
#define sparsebit_for_each_set_range(s, range_begin, range_end) \
|
||||
for (range_begin = sparsebit_first_set(s), \
|
||||
range_end = sparsebit_next_clear(s, range_begin) - 1; \
|
||||
range_begin && range_end; \
|
||||
range_begin = sparsebit_next_set(s, range_end), \
|
||||
range_end = sparsebit_next_clear(s, range_begin) - 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef SELFTEST_KVM_UTIL_ARCH_H
|
||||
#define SELFTEST_KVM_UTIL_ARCH_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct kvm_vm_arch {
|
||||
uint64_t c_bit;
|
||||
uint64_t s_bit;
|
||||
int sev_fd;
|
||||
bool is_pt_protected;
|
||||
};
|
||||
|
||||
static inline bool __vm_arch_has_protected_memory(struct kvm_vm_arch *arch)
|
||||
{
|
||||
return arch->c_bit || arch->s_bit;
|
||||
}
|
||||
|
||||
#define vm_arch_has_protected_memory(vm) \
|
||||
__vm_arch_has_protected_memory(&(vm)->arch)
|
||||
|
||||
#endif // SELFTEST_KVM_UTIL_ARCH_H
|
||||
@@ -23,6 +23,12 @@
|
||||
extern bool host_cpu_is_intel;
|
||||
extern bool host_cpu_is_amd;
|
||||
|
||||
enum vm_guest_x86_subtype {
|
||||
VM_SUBTYPE_NONE = 0,
|
||||
VM_SUBTYPE_SEV,
|
||||
VM_SUBTYPE_SEV_ES,
|
||||
};
|
||||
|
||||
#define NMI_VECTOR 0x02
|
||||
|
||||
#define X86_EFLAGS_FIXED (1u << 1)
|
||||
@@ -273,6 +279,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, EAX, 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)
|
||||
|
||||
#define X86_PROPERTY_MAX_CENTAUR_LEAF KVM_X86_CPU_PROPERTY(0xC0000000, 0, EAX, 0, 31)
|
||||
@@ -1059,6 +1066,7 @@ do { \
|
||||
} while (0)
|
||||
|
||||
void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits);
|
||||
void kvm_init_vm_address_properties(struct kvm_vm *vm);
|
||||
bool vm_is_unrestricted_guest(struct kvm_vm *vm);
|
||||
|
||||
struct ex_regs {
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Helpers used for SEV guests
|
||||
*
|
||||
*/
|
||||
#ifndef SELFTEST_KVM_SEV_H
|
||||
#define SELFTEST_KVM_SEV_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "linux/psp-sev.h"
|
||||
|
||||
#include "kvm_util.h"
|
||||
#include "svm_util.h"
|
||||
#include "processor.h"
|
||||
|
||||
enum sev_guest_state {
|
||||
SEV_GUEST_STATE_UNINITIALIZED = 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)
|
||||
|
||||
#define GHCB_MSR_TERM_REQ 0x100
|
||||
|
||||
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_code,
|
||||
struct kvm_vcpu **cpu);
|
||||
|
||||
kvm_static_assert(SEV_RET_SUCCESS == 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 the
|
||||
* 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 (casting
|
||||
* 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 = { .c = { \
|
||||
.id = (cmd), \
|
||||
.data = (uint64_t)(arg), \
|
||||
.sev_fd = (vm)->arch.sev_fd, \
|
||||
} }; \
|
||||
\
|
||||
r = __vm_ioctl(vm, KVM_MEMORY_ENCRYPT_OP, &sev_cmd.raw); \
|
||||
r ?: sev_cmd.c.error; \
|
||||
})
|
||||
|
||||
#define vm_sev_ioctl(vm, cmd, arg) \
|
||||
({ \
|
||||
int ret = __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 = 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 = 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 = {
|
||||
.addr = region->region.userspace_addr,
|
||||
.size = 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 gpa,
|
||||
uint64_t size)
|
||||
{
|
||||
struct kvm_sev_launch_update_data update_data = {
|
||||
.uaddr = (unsigned long)addr_gpa2hva(vm, gpa),
|
||||
.len = size,
|
||||
};
|
||||
|
||||
vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_DATA, &update_data);
|
||||
}
|
||||
|
||||
#endif /* SELFTEST_KVM_SEV_H */
|
||||
Reference in New Issue
Block a user