mirror of
https://github.com/torvalds/linux.git
synced 2026-04-19 15:24:02 -04:00
Extend sev_smoke_test to also run a minimal SEV-ES smoke test so that it's possible to test KVM's unique VMRUN=>#VMEXIT path for SEV-ES guests without needing a full blown SEV-ES capable VM, which requires a rather absurd amount of properly configured collateral. Punt on proper GHCB and ucall support, and instead use the GHCB MSR protocol to signal test completion. The most important thing at this point is to have _any_ kind of testing of KVM's __svm_sev_es_vcpu_run(). Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Michael Roth <michael.roth@amd.com> Cc: Peter Gonda <pgonda@google.com> Cc: Carlos Bilbao <carlos.bilbao@amd.com> Tested-by: Carlos Bilbao <carlos.bilbao@amd.com> Link: https://lore.kernel.org/r/20240223004258.3104051-12-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
108 lines
2.7 KiB
C
108 lines
2.7 KiB
C
/* 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 */
|