diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index fc2eef88eac1..4f4f71ce27ec 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -74,6 +74,7 @@ enum __kvm_host_smccc_func { __KVM_HOST_SMCCC_FUNC___pkvm_init_module, __KVM_HOST_SMCCC_FUNC___pkvm_register_hcall, __KVM_HOST_SMCCC_FUNC___pkvm_iommu_init, + __KVM_HOST_SMCCC_FUNC___pkvm_devices_init, __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize, /* Hypercalls available after pKVM finalisation */ diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h index 48c56b85009e..5b9d9fda6ad6 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h +++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h @@ -181,4 +181,6 @@ static inline int pkvm_init_power_domain(struct kvm_power_domain *pd, } } +int pkvm_init_devices(void); + #endif /* __ARM64_KVM_NVHE_PKVM_H__ */ diff --git a/arch/arm64/kvm/hyp/nvhe/device/device.c b/arch/arm64/kvm/hyp/nvhe/device/device.c index 4e8085fb4321..d64a30fa2287 100644 --- a/arch/arm64/kvm/hyp/nvhe/device/device.c +++ b/arch/arm64/kvm/hyp/nvhe/device/device.c @@ -3,6 +3,27 @@ * Copyright (C) 2023 Google LLC * Author: Mostafa Saleh */ +#include +#include +#include + +#include struct pkvm_device *registered_devices; unsigned long registered_devices_nr; + +int pkvm_init_devices(void) +{ + size_t dev_sz; + int ret; + + registered_devices = kern_hyp_va(registered_devices); + dev_sz = PAGE_ALIGN(size_mul(sizeof(struct pkvm_device), + registered_devices_nr)); + + ret = __pkvm_host_donate_hyp(hyp_virt_to_phys(registered_devices) >> PAGE_SHIFT, + dev_sz >> PAGE_SHIFT); + if (ret) + registered_devices_nr = 0; + return ret; +} diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index 41a531bf0943..2709ab003e76 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -1728,6 +1728,15 @@ static void handle___pkvm_ptdump(struct kvm_cpu_context *host_ctxt) cpu_reg(host_ctxt, 0) = SMCCC_RET_NOT_SUPPORTED; } +static void handle___pkvm_devices_init(struct kvm_cpu_context *host_ctxt) +{ + /* + * Devices must be initialised after the IOMMUs driver is initialised. + * We do this in a separate HVC to avoid complexity. + */ + cpu_reg(host_ctxt, 1) = pkvm_init_devices(); +} + static void handle___pkvm_host_iommu_map_sg(struct kvm_cpu_context *host_ctxt) { unsigned long ret; @@ -1766,6 +1775,7 @@ static const hcall_t host_hcall[] = { HANDLE_FUNC(__pkvm_init_module), HANDLE_FUNC(__pkvm_register_hcall), HANDLE_FUNC(__pkvm_iommu_init), + HANDLE_FUNC(__pkvm_devices_init), HANDLE_FUNC(__pkvm_prot_finalize), HANDLE_FUNC(__pkvm_host_share_hyp), diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 707ebd9a1ab3..a8da92e8f5a5 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -662,6 +662,10 @@ static int __init finalize_pkvm(void) pkvm_firmware_rmem_clear(); } + ret = kvm_call_hyp_nvhe(__pkvm_devices_init); + if (ret) + pr_warn("Assignable devices failed to initialize in the hypervisor %d", ret); + /* * Exclude HYP sections from kmemleak so that they don't get peeked * at, which would end badly once inaccessible.