ANDROID: KVM: arm64: devices: Add request_mmio guest HVC
request_mmio is a guest HVC that is used to authenticate a device MMIO resource, it returns a unique token, that can be used by the guest. Bug: 357781595 Bug: 348382247 Change-Id: I87d67ce9c14578702dda1b157411fdc622327286 Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
committed by
Treehugger Robot
parent
e0a0783241
commit
774b9063c8
@@ -74,6 +74,8 @@ u64 __pkvm_ptdump_walk_range(pkvm_handle_t handle, struct pkvm_ptdump_log_hdr *l
|
||||
int hyp_check_range_owned(u64 addr, u64 size);
|
||||
int __pkvm_install_guest_mmio(struct pkvm_hyp_vcpu *hyp_vcpu, u64 pfn, u64 gfn);
|
||||
|
||||
int __pkvm_guest_get_valid_phys_page(struct pkvm_hyp_vm *vm, u64 *phys, u64 ipa);
|
||||
|
||||
bool addr_is_memory(phys_addr_t phys);
|
||||
int host_stage2_idmap_locked(phys_addr_t addr, u64 size,
|
||||
enum kvm_pgtable_prot prot,
|
||||
|
||||
@@ -162,6 +162,8 @@ int pkvm_host_hvc_pd(u64 device_id, u64 on);
|
||||
int pkvm_init_scmi_pd(struct kvm_power_domain *pd,
|
||||
const struct kvm_power_domain_ops *ops);
|
||||
|
||||
bool pkvm_device_request_mmio(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code);
|
||||
|
||||
/*
|
||||
* Register a power domain. When the hypervisor catches power requests from the
|
||||
* host for this power domain, it calls the power ops with @pd as argument.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <nvhe/mm.h>
|
||||
#include <nvhe/pkvm.h>
|
||||
|
||||
#include <kvm/arm_hypercalls.h>
|
||||
#include <kvm/device.h>
|
||||
|
||||
struct pkvm_device *registered_devices;
|
||||
@@ -234,3 +235,70 @@ out_ret:
|
||||
hyp_spin_unlock(&device_spinlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pkvm_get_device_pa(struct pkvm_hyp_vcpu *hyp_vcpu, u64 ipa, u64 *pa, u64 *exit_code)
|
||||
{
|
||||
struct kvm_hyp_req *req;
|
||||
int ret;
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
|
||||
ret = __pkvm_guest_get_valid_phys_page(vm, pa, ipa);
|
||||
if (ret == -ENOENT) {
|
||||
/* Page not mapped, create a request*/
|
||||
req = pkvm_hyp_req_reserve(hyp_vcpu, KVM_HYP_REQ_TYPE_MAP);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
req->map.guest_ipa = ipa;
|
||||
req->map.size = PAGE_SIZE;
|
||||
*exit_code = ARM_EXCEPTION_HYP_REQ;
|
||||
/* Repeat next time. */
|
||||
write_sysreg_el2(read_sysreg_el2(SYS_ELR) - 4, SYS_ELR);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool pkvm_device_request_mmio(struct pkvm_hyp_vcpu *hyp_vcpu, u64 *exit_code)
|
||||
{
|
||||
int i, j, ret;
|
||||
struct kvm_vcpu *vcpu = &hyp_vcpu->vcpu;
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
|
||||
u64 ipa = smccc_get_arg1(vcpu);
|
||||
u64 token;
|
||||
|
||||
/* arg2 and arg3 reserved for future use. */
|
||||
if (smccc_get_arg2(vcpu) || smccc_get_arg3(vcpu) || !PAGE_ALIGNED(ipa))
|
||||
goto out_inval;
|
||||
|
||||
ret = pkvm_get_device_pa(hyp_vcpu, ipa, &token, exit_code);
|
||||
if (ret == -ENOENT)
|
||||
return false;
|
||||
else if (ret)
|
||||
goto out_inval;
|
||||
|
||||
hyp_spin_lock(&device_spinlock);
|
||||
for (i = 0 ; i < registered_devices_nr ; ++i) {
|
||||
struct pkvm_device *dev = ®istered_devices[i];
|
||||
|
||||
if (dev->ctxt != vm)
|
||||
continue;
|
||||
|
||||
for (j = 0 ; j < dev->nr_resources; ++j) {
|
||||
struct pkvm_dev_resource *res = &dev->resources[j];
|
||||
|
||||
if ((token >= res->base) && (token + PAGE_SIZE <= res->base + res->size)) {
|
||||
smccc_set_retval(vcpu, SMCCC_RET_SUCCESS, token, 0, 0);
|
||||
goto out_ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
smccc_set_retval(vcpu, SMCCC_RET_INVALID_PARAMETER, 0, 0, 0);
|
||||
out_ret:
|
||||
hyp_spin_unlock(&device_spinlock);
|
||||
return true;
|
||||
out_inval:
|
||||
smccc_set_retval(vcpu, SMCCC_RET_INVALID_PARAMETER, 0, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1837,6 +1837,18 @@ static int guest_get_valid_pte(struct pkvm_hyp_vm *vm, u64 *phys, u64 ipa, u8 or
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __pkvm_guest_get_valid_phys_page(struct pkvm_hyp_vm *vm, u64 *phys, u64 ipa)
|
||||
{
|
||||
kvm_pte_t pte;
|
||||
int ret;
|
||||
|
||||
guest_lock_component(vm);
|
||||
ret = guest_get_valid_pte(vm, phys, ipa, 0, &pte);
|
||||
guest_unlock_component(vm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally we would like to use check_unshare()... but this wouldn't let us
|
||||
* restrict the unshare range to the actual guest stage-2 mapping.
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <kvm/arm_hypercalls.h>
|
||||
#include <kvm/arm_psci.h>
|
||||
#include <kvm/device.h>
|
||||
|
||||
#include <asm/kvm_emulate.h>
|
||||
|
||||
@@ -1659,6 +1660,8 @@ bool kvm_handle_pvm_hvc64(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
if (smccc_trng_available)
|
||||
return pkvm_forward_trng(vcpu);
|
||||
break;
|
||||
case ARM_SMCCC_VENDOR_HYP_KVM_DEV_REQ_MMIO_FUNC_ID:
|
||||
return pkvm_device_request_mmio(hyp_vcpu, exit_code);
|
||||
default:
|
||||
return pkvm_handle_psci(hyp_vcpu);
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
#define ARM_SMCCC_KVM_FUNC_PKVM_RESV_60 60
|
||||
#define ARM_SMCCC_KVM_FUNC_PKVM_RESV_61 61
|
||||
#define ARM_SMCCC_KVM_FUNC_PKVM_RESV_62 62
|
||||
#define ARM_SMCCC_KVM_FUNC_PKVM_RESV_63 63
|
||||
#define ARM_SMCCC_KVM_FUNC_DEV_REQ_MMIO 63
|
||||
/* End of pKVM hypercall range */
|
||||
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
|
||||
#define ARM_SMCCC_KVM_NUM_FUNCS 128
|
||||
@@ -227,6 +227,12 @@
|
||||
ARM_SMCCC_OWNER_VENDOR_HYP, \
|
||||
ARM_SMCCC_KVM_FUNC_MEM_RELINQUISH)
|
||||
|
||||
#define ARM_SMCCC_VENDOR_HYP_KVM_DEV_REQ_MMIO_FUNC_ID \
|
||||
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
||||
ARM_SMCCC_SMC_64, \
|
||||
ARM_SMCCC_OWNER_VENDOR_HYP, \
|
||||
ARM_SMCCC_KVM_FUNC_DEV_REQ_MMIO)
|
||||
|
||||
/* ptp_kvm counter type ID */
|
||||
#define KVM_PTP_VIRT_COUNTER 0
|
||||
#define KVM_PTP_PHYS_COUNTER 1
|
||||
|
||||
Reference in New Issue
Block a user