Reapply "ANDROID: KVM: arm64: Introduce KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FFA uapi"
This reverts commit 72b2c64a2c.
It is now safe to reapply this commit during the KMI update.
Cc: Sebastian Ene <sebastianene@google.com>
Change-Id: I5e01add3804628ed6bfe2e67efa6e411e49510ec
[cmllamas: fixed trivial revert conflicts]
Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
@@ -131,6 +131,7 @@ enum __kvm_host_smccc_func {
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_host_map_guest_mmio,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_pviommu_attach,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_pviommu_add_vsid,
|
||||
__KVM_HOST_SMCCC_FUNC___pkvm_host_get_ffa_version,
|
||||
|
||||
/*
|
||||
* Start of the dynamically registered hypercalls. Start a bit
|
||||
|
||||
@@ -298,6 +298,7 @@ struct kvm_protected_vm {
|
||||
struct kvm_hyp_memcache teardown_iommu_mc;
|
||||
gpa_t pvmfw_load_addr;
|
||||
bool enabled;
|
||||
u32 ffa_support;
|
||||
};
|
||||
|
||||
struct kvm_mpidr_data {
|
||||
|
||||
@@ -480,10 +480,13 @@ enum {
|
||||
/* Protected KVM */
|
||||
#define KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FW_IPA 0
|
||||
#define KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO 1
|
||||
#define KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FFA 2
|
||||
|
||||
struct kvm_protected_vm_info {
|
||||
__u64 firmware_size;
|
||||
__u64 __reserved[7];
|
||||
__u32 ffa_version;
|
||||
__u32 pad;
|
||||
__u64 __reserved[6];
|
||||
};
|
||||
|
||||
/* arm64-specific kvm_run::system_event flags */
|
||||
|
||||
@@ -29,6 +29,7 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id);
|
||||
bool kvm_guest_ffa_handler(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code);
|
||||
struct ffa_mem_transfer *find_transfer_by_handle(u64 ffa_handle, struct kvm_ffa_buffers *buf);
|
||||
int kvm_dying_guest_reclaim_ffa_resources(struct pkvm_hyp_vm *vm);
|
||||
u32 ffa_get_hypervisor_version(void);
|
||||
|
||||
static inline bool is_ffa_call(u64 func_id)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include <nvhe/trap_handler.h>
|
||||
#include <nvhe/spinlock.h>
|
||||
|
||||
#define VM_FFA_SUPPORTED(vcpu) ((vcpu)->kvm->arch.pkvm.ffa_support)
|
||||
|
||||
/*
|
||||
* A buffer to hold the maximum descriptor size we can see from the host,
|
||||
* which is required when the SPMD returns a fragmented FFA_MEM_RETRIEVE_RESP
|
||||
@@ -1187,6 +1189,12 @@ bool kvm_guest_ffa_handler(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!VM_FFA_SUPPORTED(vcpu)) {
|
||||
ffa_to_smccc_error(&res, FFA_RET_NOT_SUPPORTED);
|
||||
ffa_set_retval(ctxt, &res);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (func_id) {
|
||||
case FFA_FEATURES:
|
||||
do_ffa_guest_features(&res, ctxt);
|
||||
@@ -1293,6 +1301,9 @@ int kvm_dying_guest_reclaim_ffa_resources(struct pkvm_hyp_vm *vm)
|
||||
struct ffa_mem_transfer *transfer;
|
||||
int ret = 0;
|
||||
|
||||
if (!vm->kvm.arch.pkvm.ffa_support)
|
||||
return 0;
|
||||
|
||||
hyp_spin_lock(&kvm_ffa_hyp_lock);
|
||||
if (!ffa_buf->tx && !ffa_buf->rx)
|
||||
goto unlock;
|
||||
@@ -1320,6 +1331,18 @@ unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 ffa_get_hypervisor_version(void)
|
||||
{
|
||||
u32 version = 0;
|
||||
|
||||
hyp_spin_lock(&version_lock);
|
||||
if (has_version_negotiated)
|
||||
version = hyp_ffa_version;
|
||||
hyp_spin_unlock(&version_lock);
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
int hyp_ffa_init(void *pages)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
|
||||
@@ -1901,6 +1901,11 @@ static void handle___pkvm_pviommu_add_vsid(struct kvm_cpu_context *host_ctxt)
|
||||
cpu_reg(host_ctxt, 1) = pkvm_pviommu_add_vsid(host_kvm, pviommu, iommu, sid, vsid);
|
||||
}
|
||||
|
||||
static void handle___pkvm_host_get_ffa_version(struct kvm_cpu_context *host_ctxt)
|
||||
{
|
||||
cpu_reg(host_ctxt, 1) = ffa_get_hypervisor_version();
|
||||
}
|
||||
|
||||
typedef void (*hcall_t)(struct kvm_cpu_context *);
|
||||
|
||||
#define HANDLE_FUNC(x) [__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
|
||||
@@ -1982,6 +1987,7 @@ static const hcall_t host_hcall[] = {
|
||||
HANDLE_FUNC(__pkvm_host_map_guest_mmio),
|
||||
HANDLE_FUNC(__pkvm_pviommu_attach),
|
||||
HANDLE_FUNC(__pkvm_pviommu_add_vsid),
|
||||
HANDLE_FUNC(__pkvm_host_get_ffa_version),
|
||||
};
|
||||
|
||||
static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
|
||||
|
||||
@@ -610,6 +610,7 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm,
|
||||
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.pkvm.ffa_support = READ_ONCE(host_kvm->arch.pkvm.ffa_support);
|
||||
hyp_vm->kvm.arch.mmu.last_vcpu_ran = (int __percpu *)last_ran;
|
||||
memset(last_ran, -1, pkvm_get_last_ran_size());
|
||||
pkvm_init_features_from_host(hyp_vm, host_kvm);
|
||||
|
||||
@@ -832,16 +832,61 @@ out_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 pkvm_get_ffa_version(void)
|
||||
{
|
||||
static u32 ffa_version;
|
||||
u32 ret;
|
||||
|
||||
ret = READ_ONCE(ffa_version);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = kvm_call_hyp_nvhe(__pkvm_host_get_ffa_version);
|
||||
WRITE_ONCE(ffa_version, ret);
|
||||
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 = pvmfw_size,
|
||||
.ffa_version = pkvm_get_ffa_version(),
|
||||
};
|
||||
|
||||
return copy_to_user(info, &kinfo, sizeof(kinfo)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int pkvm_vm_ioctl_ffa_support(struct kvm *kvm, u32 enable)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 ffa_version;
|
||||
|
||||
/* Restrict userspace from having an IPC channel over FF-A with secure */
|
||||
if (!capable(CAP_IPC_OWNER))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* If the host hasn't negotiated a version don't enable the
|
||||
* FF-A capability.
|
||||
*/
|
||||
ffa_version = pkvm_get_ffa_version();
|
||||
if (!ffa_version)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
if (kvm->arch.pkvm.handle) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
kvm->arch.pkvm.ffa_support = enable;
|
||||
out_unlock:
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pkvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
|
||||
{
|
||||
if (!kvm_vm_is_protected(kvm))
|
||||
@@ -855,6 +900,8 @@ int pkvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
|
||||
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]);
|
||||
case KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FFA:
|
||||
return pkvm_vm_ioctl_ffa_support(kvm, cap->args[0]);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user