mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git
synced 2026-04-19 12:03:56 -04:00
Use the kernel's canonical $(ARCH) paths instead of the raw target triple for KVM selftests directories. KVM selftests are quite nearly the only place in the entire kernel that using the target triple for directories, tools/testing/selftests/drivers/s390x being the lone holdout. Using the kernel's preferred nomenclature eliminates the minor, but annoying, friction of having to translate to KVM's selftests directories, e.g. for pattern matching, opening files, running selftests, etc. Opportunsitically delete file comments that reference the full path of the file, as they are obviously prone to becoming stale, and serve no known purpose. Reviewed-by: Muhammad Usama Anjum <usama.anjum@collabora.com> Acked-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Acked-by: Andrew Jones <ajones@ventanamicro.com> Link: https://lore.kernel.org/r/20241128005547.4077116-16-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
142 lines
3.9 KiB
C
142 lines
3.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#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 = region->protected_phy_pages;
|
|
const vm_paddr_t gpa_base = region->region.guest_phys_addr;
|
|
const sparsebit_idx_t lowest_page_in_region = gpa_base >> vm->page_shift;
|
|
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 = (j - i + 1) * vm->page_size;
|
|
const uint64_t offset = (i - lowest_page_in_region) * vm->page_size;
|
|
|
|
sev_launch_update_data(vm, gpa_base + offset, size);
|
|
}
|
|
}
|
|
|
|
void sev_vm_init(struct kvm_vm *vm)
|
|
{
|
|
if (vm->type == KVM_X86_DEFAULT_VM) {
|
|
assert(vm->arch.sev_fd == -1);
|
|
vm->arch.sev_fd = open_sev_dev_path_or_exit();
|
|
vm_sev_ioctl(vm, KVM_SEV_INIT, NULL);
|
|
} else {
|
|
struct kvm_sev_init init = { 0 };
|
|
assert(vm->type == KVM_X86_SEV_VM);
|
|
vm_sev_ioctl(vm, KVM_SEV_INIT2, &init);
|
|
}
|
|
}
|
|
|
|
void sev_es_vm_init(struct kvm_vm *vm)
|
|
{
|
|
if (vm->type == KVM_X86_DEFAULT_VM) {
|
|
assert(vm->arch.sev_fd == -1);
|
|
vm->arch.sev_fd = open_sev_dev_path_or_exit();
|
|
vm_sev_ioctl(vm, KVM_SEV_ES_INIT, NULL);
|
|
} else {
|
|
struct kvm_sev_init init = { 0 };
|
|
assert(vm->type == KVM_X86_SEV_ES_VM);
|
|
vm_sev_ioctl(vm, KVM_SEV_INIT2, &init);
|
|
}
|
|
}
|
|
|
|
void sev_vm_launch(struct kvm_vm *vm, uint32_t policy)
|
|
{
|
|
struct kvm_sev_launch_start launch_start = {
|
|
.policy = 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);
|
|
|
|
if (policy & SEV_POLICY_ES)
|
|
vm_sev_ioctl(vm, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
|
|
|
|
vm->arch.is_pt_protected = 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 = 256;
|
|
launch_measure.uaddr = (__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 == SEV_GUEST_STATE_LAUNCH_UPDATE ||
|
|
status.state == 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 type, void *guest_code,
|
|
struct kvm_vcpu **cpu)
|
|
{
|
|
struct vm_shape shape = {
|
|
.mode = VM_MODE_DEFAULT,
|
|
.type = type,
|
|
};
|
|
struct kvm_vm *vm;
|
|
struct kvm_vcpu *cpus[1];
|
|
|
|
vm = __vm_create_with_vcpus(shape, 1, 0, guest_code, cpus);
|
|
*cpu = cpus[0];
|
|
|
|
return vm;
|
|
}
|
|
|
|
void vm_sev_launch(struct kvm_vm *vm, uint32_t policy, uint8_t *measurement)
|
|
{
|
|
sev_vm_launch(vm, policy);
|
|
|
|
if (!measurement)
|
|
measurement = alloca(256);
|
|
|
|
sev_vm_launch_measure(vm, measurement);
|
|
|
|
sev_vm_launch_finish(vm);
|
|
}
|