From: Peter Gonda <pgonda@xxxxxxxxxx> Add GHCB management functionality similar to the ucall management. Allows for selftest vCPUs to acquire GHCBs for their usage. Cc: Vishal Annapurve <vannapurve@xxxxxxxxxx> Cc: Ackerley Tng <ackerleytng@xxxxxxxxxx> Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx> Cc: Claudio Imbrenda <imbrenda@xxxxxxxxxxxxx> Cc: Sean Christopherson <seanjc@xxxxxxxxxx> Cc: Carlos Bilbao <carlos.bilbao@xxxxxxx> Cc: Tom Lendacky <thomas.lendacky@xxxxxxx> Cc: Michael Roth <michael.roth@xxxxxxx> Cc: kvm@xxxxxxxxxxxxxxx Cc: linux-kselftest@xxxxxxxxxxxxxxx Signed-off-by: Peter Gonda <pgonda@xxxxxxxxxx> Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@xxxxxxx> --- tools/testing/selftests/kvm/include/x86/sev.h | 1 + .../testing/selftests/kvm/lib/x86/processor.c | 9 +++ tools/testing/selftests/kvm/lib/x86/sev.c | 78 +++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/tools/testing/selftests/kvm/include/x86/sev.h b/tools/testing/selftests/kvm/include/x86/sev.h index fd5d5261e10e..0b4411847cbf 100644 --- a/tools/testing/selftests/kvm/include/x86/sev.h +++ b/tools/testing/selftests/kvm/include/x86/sev.h @@ -43,6 +43,7 @@ enum sev_guest_state { bool is_sev_vm(struct kvm_vm *vm); bool is_sev_es_vm(struct kvm_vm *vm); bool is_sev_snp_vm(struct kvm_vm *vm); +int ghcb_nr_pages_required(uint64_t page_size); void sev_vm_launch(struct kvm_vm *vm, uint32_t policy); void sev_vm_launch_measure(struct kvm_vm *vm, uint8_t *measurement); diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index a92dc1dad085..7129dfb652c4 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -651,6 +651,15 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm) sync_global_to_guest(vm, guest_tsc_khz); } +int kvm_arch_vm_additional_pages_required(struct vm_shape shape, uint64_t page_size) +{ + if (shape.type == KVM_X86_SEV_ES_VM || + shape.type == KVM_X86_SNP_VM) + return ghcb_nr_pages_required(page_size); + + return 0; +} + void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) { struct kvm_regs regs; diff --git a/tools/testing/selftests/kvm/lib/x86/sev.c b/tools/testing/selftests/kvm/lib/x86/sev.c index 17d493e9907a..dd7ccf0324c5 100644 --- a/tools/testing/selftests/kvm/lib/x86/sev.c +++ b/tools/testing/selftests/kvm/lib/x86/sev.c @@ -3,6 +3,80 @@ #include <stdbool.h> #include "sev.h" +#include "linux/bitmap.h" +#include "svm.h" +#include "svm_util.h" + +struct ghcb_entry { + struct ghcb ghcb; + + /* Guest physical address of this GHCB. */ + void *gpa; + + /* Host virtual address of this struct. */ + struct ghcb_entry *hva; +}; + +struct ghcb_header { + struct ghcb_entry ghcbs[KVM_MAX_VCPUS]; + DECLARE_BITMAP(in_use, KVM_MAX_VCPUS); +}; + +static struct ghcb_header *ghcb_pool; + +int ghcb_nr_pages_required(uint64_t page_size) +{ + return align_up(sizeof(struct ghcb_header), page_size) / page_size; +} + +void ghcb_init(struct kvm_vm *vm) +{ + struct ghcb_header *hdr; + struct ghcb_entry *entry; + vm_vaddr_t vaddr; + int i; + + vaddr = vm_vaddr_alloc_shared(vm, sizeof(*hdr), KVM_UTIL_MIN_VADDR, + MEM_REGION_DATA); + hdr = (struct ghcb_header *)addr_gva2hva(vm, vaddr); + memset(hdr, 0, sizeof(*hdr)); + + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + entry = &hdr->ghcbs[i]; + entry->hva = entry; + entry->gpa = (void *)addr_hva2gpa(vm, &entry->ghcb); + } + + write_guest_global(vm, ghcb_pool, (struct ghcb_header *)vaddr); +} + +static struct ghcb_entry *ghcb_alloc(void) +{ + return &ghcb_pool->ghcbs[0]; + struct ghcb_entry *entry; + int i; + + if (!ghcb_pool) + goto ucall_failed; + + for (i = 0; i < KVM_MAX_VCPUS; ++i) { + if (!test_and_set_bit(i, ghcb_pool->in_use)) { + entry = &ghcb_pool->ghcbs[i]; + memset(&entry->ghcb, 0, sizeof(entry->ghcb)); + return entry; + } + } + +ucall_failed: + return NULL; +} + +static void ghcb_free(struct ghcb_entry *entry) +{ + /* Beware, here be pointer arithmetic. */ + clear_bit(entry - ghcb_pool->ghcbs, ghcb_pool->in_use); +} + bool is_sev_snp_vm(struct kvm_vm *vm) { @@ -117,7 +191,11 @@ void sev_vm_launch(struct kvm_vm *vm, uint32_t policy) struct kvm_sev_guest_status status; int ctr; + if (is_sev_es_vm(vm)) + ghcb_init(vm); + 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); -- 2.34.1