ANDROID: KVM: arm64: iommu: Add memcache for guest pvIOMMU

Guest pvIOMMU would need memory for page tables, this is done through
the host donating pages to the guest, and will be owned by the
hypervisor as the guest has no direct access (or knowledge) of the
IOMMU page tables.

This is done through a new memcache per vcpu dedicated for each
vcpu.

And the requests for memory will be communiacted via kvm_hyp_req and
fullfilled by the IOMMU driver or with a default function.

Bug: 357781595
Bug: 348382247
Bug: 236685427
Change-Id: I8a32072dc21879165e7921dad83f312447360539
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
Mostafa Saleh
2023-11-16 15:59:50 +00:00
committed by Carlos Llamas
parent b0fccd926d
commit 9dabecc2a2
5 changed files with 43 additions and 10 deletions
+17
View File
@@ -915,6 +915,9 @@ struct kvm_vcpu_arch {
/* Per-vcpu CCSIDR override or NULL */
u32 *ccsidr;
/* mem cache for pvIOMMU usage in guests. */
struct kvm_hyp_memcache iommu_mc;
/* PAGE_SIZE bound list of requests from the hypervisor to the host. */
struct kvm_hyp_req *hyp_reqs;
};
@@ -1716,6 +1719,8 @@ struct kvm_iommu_driver {
int (*get_device_iommu_num_ids)(struct device *dev);
int (*get_device_iommu_id)(struct device *dev, u32 id,
pkvm_handle_t *out_iommu, u32 *out_sid);
void *(*guest_alloc)(void *flags, unsigned long order);
void (*guest_free)(void *addr, void *flags, unsigned long order);
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
ANDROID_KABI_RESERVE(3);
@@ -1737,6 +1742,9 @@ pkvm_handle_t kvm_get_iommu_id_by_of(struct device_node *np);
int pkvm_iommu_suspend(struct device *dev);
int pkvm_iommu_resume(struct device *dev);
int kvm_iommu_guest_alloc_mc(struct kvm_hyp_memcache *mc, u32 pgsize, u32 nr_pages);
void kvm_iommu_guest_free_mc(struct kvm_hyp_memcache *mc);
struct kvm_iommu_sg {
phys_addr_t phys;
size_t pgsize;
@@ -1760,4 +1768,13 @@ int kvm_iommu_device_id(struct device *dev, u32 idx,
pkvm_handle_t *out_iommu, u32 *out_sid);
#define __KVM_HAVE_ARCH_ASSIGNED_DEVICE_GROUP
static inline phys_addr_t kvm_host_pa(void *addr)
{
return __pa(addr);
}
static inline void *kvm_host_va(phys_addr_t phys)
{
return __va(phys);
}
#endif /* __ARM64_KVM_HOST_H__ */
+3
View File
@@ -388,6 +388,9 @@ static int handle_hyp_req_mem(struct kvm_vcpu *vcpu,
atomic64_add(nr_pages << PAGE_SHIFT, &kvm->stat.protected_hyp_mem);
return ret;
case REQ_MEM_DEST_HYP_IOMMU:
return kvm_iommu_guest_alloc_mc(&vcpu->arch.iommu_mc,
req->mem.sz_alloc, req->mem.nr_pages);
};
pr_warn("Unknown kvm_hyp_req mem dest: %d\n", req->mem.dest);
+21
View File
@@ -142,3 +142,24 @@ int kvm_iommu_device_id(struct device *dev, u32 idx,
return -ENODEV;
}
EXPORT_SYMBOL_GPL(kvm_iommu_device_id);
int kvm_iommu_guest_alloc_mc(struct kvm_hyp_memcache *mc, u32 pgsize, u32 nr_pages)
{
u8 order = get_order(pgsize);
/* Driver might have dedicated allocator especially if it needs large pages. */
if (iommu_driver && iommu_driver->guest_alloc && iommu_driver->guest_free)
return __topup_hyp_memcache(mc, nr_pages, iommu_driver->guest_alloc,
kvm_host_pa, 0, order);
return topup_hyp_memcache(mc, nr_pages, order);
}
void kvm_iommu_guest_free_mc(struct kvm_hyp_memcache *mc)
{
if (iommu_driver && iommu_driver->guest_alloc && iommu_driver->guest_free)
__free_hyp_memcache(mc, iommu_driver->guest_free,
kvm_host_va, 0);
else
free_hyp_memcache(mc);
}
-10
View File
@@ -280,16 +280,6 @@ static int kvm_host_page_count(void *addr)
return page_count(virt_to_page(addr));
}
static phys_addr_t kvm_host_pa(void *addr)
{
return __pa(addr);
}
static void *kvm_host_va(phys_addr_t phys)
{
return __va(phys);
}
static void clean_dcache_guest_page(void *va, size_t size)
{
__clean_dcache_guest_page(va, size);
+2
View File
@@ -434,6 +434,8 @@ out_free:
kvm_unshare_hyp(hyp_reqs, hyp_reqs + 1);
host_vcpu->arch.hyp_reqs = NULL;
free_page((unsigned long)hyp_reqs);
kvm_iommu_guest_free_mc(&host_vcpu->arch.iommu_mc);
}
}