ANDROID: KVM: arm64: Donate device MMIO before assignment

Implement new KVM arch functions to donate/reclaim devices/groups.

Bug: 357781595
Bug: 348382247
Change-Id: Ida0066127d6019cec505309e41525c4ba0f56292
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
Mostafa Saleh
2024-10-01 13:47:34 +00:00
parent 7f5d9d5261
commit 5a1732d9a9
2 changed files with 105 additions and 0 deletions
+2
View File
@@ -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__ */
+103
View File
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/iommu.h>
#include <linux/kmemleak.h>
#include <linux/kvm_host.h>
#include <linux/memblock.h>
@@ -14,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/sort.h>
#include <asm/kvm_host.h>
@@ -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);
}