1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/* 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 SNP_POLICY_SMT (1ULL << 16)
#define SNP_POLICY_RSVD_MBO (1ULL << 17)
#define SNP_POLICY_DBG (1ULL << 19)
#define GHCB_MSR_TERM_REQ 0x100
static inline bool is_sev_snp_vm(struct kvm_vm *vm)
{
return vm->type == KVM_X86_SNP_VM;
}
static inline bool is_sev_es_vm(struct kvm_vm *vm)
{
return is_sev_snp_vm(vm) || vm->type == KVM_X86_SEV_ES_VM;
}
static inline bool is_sev_vm(struct kvm_vm *vm)
{
return is_sev_es_vm(vm) || vm->type == KVM_X86_SEV_VM;
}
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);
void snp_vm_launch_start(struct kvm_vm *vm, uint64_t policy);
void snp_vm_launch_update(struct kvm_vm *vm);
void snp_vm_launch_finish(struct kvm_vm *vm);
struct kvm_vm *vm_sev_create_with_one_vcpu(uint32_t type, void *guest_code,
struct kvm_vcpu **cpu);
void vm_sev_launch(struct kvm_vm *vm, uint64_t policy, uint8_t *measurement);
kvm_static_assert(SEV_RET_SUCCESS == 0);
/*
* A SEV-SNP VM requires the policy reserved bit to always be set.
* The SMT policy bit is also required to be set based on SMT being
* available and active on the system.
*/
static inline u64 snp_default_policy(void)
{
return SNP_POLICY_RSVD_MBO | (is_smt_on() ? SNP_POLICY_SMT : 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); \
})
void sev_vm_init(struct kvm_vm *vm);
void sev_es_vm_init(struct kvm_vm *vm);
void snp_vm_init(struct kvm_vm *vm);
static inline void vmgexit(void)
{
__asm__ __volatile__("rep; vmmcall");
}
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);
}
static inline void snp_launch_update_data(struct kvm_vm *vm, vm_paddr_t gpa,
uint64_t hva, uint64_t size, uint8_t type)
{
struct kvm_sev_snp_launch_update update_data = {
.uaddr = hva,
.gfn_start = gpa >> PAGE_SHIFT,
.len = size,
.type = type,
};
vm_sev_ioctl(vm, KVM_SEV_SNP_LAUNCH_UPDATE, &update_data);
}
#endif /* SELFTEST_KVM_SEV_H */
|