From 3cf954ca259aec7195fcbacbad3ef9af29a4d050 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 9 Dec 2021 13:15:41 +0000 Subject: [PATCH] ANDROID: BACKPORT: KVM: arm64: Introduce KVM_CAP_ARM_PROTECTED_VM to set/query PVM firmware Expose a new capability, KVM_CAP_ARM_PROTECTED_VM, for protected VMs which allows the size of the PVM firmware region to be discovered from userspace and for the firmware load address to be specified if it is required. Signed-off-by: Will Deacon [willdeacon@: Fix trivial conflict in include/uapi/linux/kvm.h with other KVM_CAP_* definitions from upstream] Signed-off-by: Will Deacon Bug: 254819795 Change-Id: I819b9b2cfa227f1a0607a8f683aa01d4ae50704f --- arch/arm64/include/asm/kvm_pkvm.h | 1 + arch/arm64/include/uapi/asm/kvm.h | 9 ++++++ arch/arm64/kvm/arm.c | 14 +++++++-- arch/arm64/kvm/hyp/nvhe/pkvm.c | 8 ++++- arch/arm64/kvm/pkvm.c | 52 +++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 10 ++++++ 6 files changed, 91 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index e44c79558625..bec69219b989 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -17,6 +17,7 @@ #define HYP_MEMBLOCK_REGIONS 128 #define PVMFW_INVALID_LOAD_ADDR (-1) +int pkvm_vm_ioctl_enable_cap(struct kvm *kvm,struct kvm_enable_cap *cap); int pkvm_init_host_vm(struct kvm *kvm, unsigned long type); int pkvm_create_hyp_vm(struct kvm *kvm); void pkvm_destroy_hyp_vm(struct kvm *kvm); diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index afe7488ae4f0..c317504f3ae1 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -455,6 +455,15 @@ enum { #define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS #define KVM_PSCI_RET_DENIED PSCI_RET_DENIED +/* Protected KVM */ +#define KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FW_IPA 0 +#define KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO 1 + +struct kvm_protected_vm_info { + __u64 firmware_size; + __u64 __reserved[7]; +}; + /* arm64-specific kvm_run::system_event flags */ /* * Reset caused by a PSCI v1.1 SYSTEM_RESET2 call. diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index e34d883029aa..08645e18720f 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -79,9 +79,16 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, { int r; - if (cap->flags) - return -EINVAL; + /* Capabilities with flags */ + switch (cap->cap) { + case KVM_CAP_ARM_PROTECTED_VM: + return pkvm_vm_ioctl_enable_cap(kvm, cap); + default: + if (cap->flags) + return -EINVAL; + } + /* Capabilities without flags */ switch (cap->cap) { case KVM_CAP_ARM_NISV_TO_USER: if (kvm_vm_is_protected(kvm)) { @@ -360,6 +367,9 @@ static int pkvm_check_extension(struct kvm *kvm, long ext, int kvm_cap) FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA), PVM_ID_AA64ISAR1_ALLOW); break; + case KVM_CAP_ARM_PROTECTED_VM: + r = 1; + break; default: r = 0; break; diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 95b1393404be..be228104e6a3 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -456,11 +456,17 @@ static size_t pkvm_get_last_ran_size(void) static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm, int *last_ran, unsigned int nr_vcpus) { + u64 pvmfw_load_addr = PVMFW_INVALID_LOAD_ADDR; + hyp_vm->host_kvm = host_kvm; hyp_vm->kvm.created_vcpus = nr_vcpus; hyp_vm->kvm.arch.vtcr = host_mmu.arch.vtcr; - hyp_vm->kvm.arch.pkvm.pvmfw_load_addr = PVMFW_INVALID_LOAD_ADDR; hyp_vm->kvm.arch.pkvm.enabled = READ_ONCE(host_kvm->arch.pkvm.enabled); + + if (hyp_vm->kvm.arch.pkvm.enabled) + pvmfw_load_addr = READ_ONCE(host_kvm->arch.pkvm.pvmfw_load_addr); + hyp_vm->kvm.arch.pkvm.pvmfw_load_addr = pvmfw_load_addr; + hyp_vm->kvm.arch.mmu.last_vcpu_ran = last_ran; memset(hyp_vm->kvm.arch.mmu.last_vcpu_ran, -1, pkvm_get_last_ran_size()); } diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 7ee1b39daaff..6cad8440e324 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -252,6 +252,7 @@ int pkvm_init_host_vm(struct kvm *host_kvm, unsigned long type) if (!is_protected_kvm_enabled()) return -EINVAL; + host_kvm->arch.pkvm.pvmfw_load_addr = PVMFW_INVALID_LOAD_ADDR; host_kvm->arch.pkvm.enabled = true; return 0; } @@ -313,3 +314,54 @@ static int __init pkvm_firmware_rmem_clear(void) return 0; } device_initcall_sync(pkvm_firmware_rmem_clear); + +static int pkvm_vm_ioctl_set_fw_ipa(struct kvm *kvm, u64 ipa) +{ + int ret = 0; + + if (!pkvm_firmware_mem) + return -EINVAL; + + mutex_lock(&kvm->lock); + if (kvm->arch.pkvm.handle) { + ret = -EBUSY; + goto out_unlock; + } + + kvm->arch.pkvm.pvmfw_load_addr = ipa; +out_unlock: + mutex_unlock(&kvm->lock); + return ret; +} + +static int pkvm_vm_ioctl_info(struct kvm *kvm, + struct kvm_protected_vm_info __user *info) +{ + struct kvm_protected_vm_info kinfo = { + .firmware_size = pkvm_firmware_mem ? + pkvm_firmware_mem->size : + 0, + }; + + return copy_to_user(info, &kinfo, sizeof(kinfo)) ? -EFAULT : 0; +} + +int pkvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) +{ + if (!kvm_vm_is_protected(kvm)) + return -EINVAL; + + if (cap->args[1] || cap->args[2] || cap->args[3]) + return -EINVAL; + + switch (cap->flags) { + case KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FW_IPA: + return pkvm_vm_ioctl_set_fw_ipa(kvm, cap->args[0]); + case KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO: + return pkvm_vm_ioctl_info(kvm, (void __force __user *)cap->args[0]); + default: + return -EINVAL; + } + + return 0; +} diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 19c38d338cec..adc4e137c3bc 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1135,6 +1135,16 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SYSTEM_EVENT_DATA 215 #endif #define KVM_CAP_ARM_SYSTEM_SUSPEND 216 +#if 0 +#define KVM_CAP_S390_PROTECTED_DUMP 217 +#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 +#define KVM_CAP_X86_NOTIFY_VMEXIT 219 +#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220 +#define KVM_CAP_S390_ZPCI_OP 221 +#define KVM_CAP_S390_CPU_TOPOLOGY 222 +#define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223 +#endif +#define KVM_CAP_ARM_PROTECTED_VM 0xffbadab1 #ifdef KVM_CAP_IRQ_ROUTING