diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index ac63d40cb6a7..aaaf01fcb284 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1709,4 +1709,6 @@ static inline void kvm_iommu_sg_free(struct kvm_iommu_sg *sg, unsigned int nents int kvm_iommu_share_hyp_sg(struct kvm_iommu_sg *sg, unsigned int nents); int kvm_iommu_unshare_hyp_sg(struct kvm_iommu_sg *sg, unsigned int nents); +#define __KVM_HAVE_ARCH_ASSIGNED_DEVICE_GROUP + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index a8da92e8f5a5..a90482c4cb85 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include @@ -1424,3 +1426,104 @@ int __pkvm_topup_hyp_alloc_mgt_gfp(unsigned long id, unsigned long nr_pages, return ret; } EXPORT_SYMBOL(__pkvm_topup_hyp_alloc_mgt_gfp); + +static int __pkvm_donate_resource(struct resource *r) +{ + if (!PAGE_ALIGNED(resource_size(r)) || !PAGE_ALIGNED(r->start)) + return -EINVAL; + + return kvm_call_hyp_nvhe(__pkvm_host_donate_hyp_mmio, + __phys_to_pfn(r->start), + resource_size(r) >> PAGE_SHIFT); + +} + +static int __pkvm_reclaim_resource(struct resource *r) +{ + if (!PAGE_ALIGNED(resource_size(r)) || !PAGE_ALIGNED(r->start)) + return -EINVAL; + + return kvm_call_hyp_nvhe(__pkvm_host_reclaim_hyp_mmio, + __phys_to_pfn(r->start), + resource_size(r) >> PAGE_SHIFT); +} + +static int __pkvm_arch_assign_device(struct device *dev, void *data) +{ + struct platform_device *pdev; + struct resource *r; + int index = 0; + int ret = 0; + + if (!dev_is_platform(dev)) + return -EOPNOTSUPP; + + pdev = to_platform_device(dev); + + while ((r = platform_get_resource(pdev, IORESOURCE_MEM, index++))) { + ret = __pkvm_donate_resource(r); + if (ret) + break; + } + + if (ret) { + while (index--) { + r = platform_get_resource(pdev, IORESOURCE_MEM, index); + __pkvm_reclaim_resource(r); + } + } + return ret; +} + +static int __pkvm_arch_reclaim_device(struct device *dev, void *data) +{ + struct platform_device *pdev; + struct resource *r; + int index = 0; + + pdev = to_platform_device(dev); + + while ((r = platform_get_resource(pdev, IORESOURCE_MEM, index++))) + __pkvm_reclaim_resource(r); + + return 0; +} + +int kvm_arch_assign_device(struct device *dev) +{ + if (!is_protected_kvm_enabled()) + return 0; + + return __pkvm_arch_assign_device(dev, NULL); +} + +int kvm_arch_assign_group(struct iommu_group *group) +{ + int ret; + + if (!is_protected_kvm_enabled()) + return 0; + + ret = iommu_group_for_each_dev(group, NULL, __pkvm_arch_assign_device); + + if (ret) + iommu_group_for_each_dev(group, NULL, __pkvm_arch_reclaim_device); + + return ret; +} + +void kvm_arch_reclaim_device(struct device *dev) +{ + if (!is_protected_kvm_enabled()) + return; + + __pkvm_arch_reclaim_device(dev, NULL); +} + +void kvm_arch_reclaim_group(struct iommu_group *group) +{ + if (!is_protected_kvm_enabled()) + return; + + iommu_group_for_each_dev(group, NULL, __pkvm_arch_reclaim_device); +}