mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
ANDROID: KVM: arm64: iommu: Avoid mapping devices in host stage-2
Introduce a linked list of IOMMU devices and
'pkvm_iommu_host_stage2_adjust_range' called from host DABT handler.
The function will adjust the memory range that is about to be mapped
to avoid MMIO regions of all devices in the linked list. If the host
tried to access a device MMIO region, the access is declined.
The function replaces the existing call to
'kvm_iommu.ops.host_stage2_adjust_mmio_range' callback.
Bug: 190463801
Change-Id: Iacd6b74147fea2fef04846a91f0a5e550daaf074
Signed-off-by: David Brazdil <dbrazdil@google.com>
(cherry picked from commit d7adab5f9f)
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
committed by
Mostafa Saleh
parent
cef8d94087
commit
079b8f1017
@@ -18,7 +18,15 @@ struct pkvm_iommu_ops {
|
||||
int (*init)(void *data, size_t size);
|
||||
};
|
||||
|
||||
struct pkvm_iommu {
|
||||
struct list_head list;
|
||||
phys_addr_t pa;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
int __pkvm_iommu_driver_init(enum pkvm_iommu_driver_id id, void *data, size_t size);
|
||||
int pkvm_iommu_host_stage2_adjust_range(phys_addr_t addr, phys_addr_t *start,
|
||||
phys_addr_t *end);
|
||||
|
||||
struct kvm_iommu_ops {
|
||||
int (*init)(void);
|
||||
|
||||
@@ -25,6 +25,14 @@ struct pkvm_iommu_driver {
|
||||
|
||||
static struct pkvm_iommu_driver iommu_drivers[PKVM_IOMMU_NR_DRIVERS];
|
||||
|
||||
/* IOMMU device list. Must only be accessed with host_mmu.lock held. */
|
||||
static LIST_HEAD(iommu_list);
|
||||
|
||||
static void assert_host_component_locked(void)
|
||||
{
|
||||
hyp_assert_lock_held(&host_mmu.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find IOMMU driver by its ID. The input ID is treated as unstrusted
|
||||
* and is properly validated.
|
||||
@@ -101,3 +109,36 @@ out:
|
||||
driver_release_init(drv, /*success=*/!ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check host memory access against IOMMUs' MMIO regions.
|
||||
* Returns -EPERM if the address is within the bounds of a registered device.
|
||||
* Otherwise returns zero and adjusts boundaries of the new mapping to avoid
|
||||
* MMIO regions of registered IOMMUs.
|
||||
*/
|
||||
int pkvm_iommu_host_stage2_adjust_range(phys_addr_t addr, phys_addr_t *start,
|
||||
phys_addr_t *end)
|
||||
{
|
||||
struct pkvm_iommu *dev;
|
||||
phys_addr_t new_start = *start;
|
||||
phys_addr_t new_end = *end;
|
||||
phys_addr_t dev_start, dev_end;
|
||||
|
||||
assert_host_component_locked();
|
||||
|
||||
list_for_each_entry(dev, &iommu_list, list) {
|
||||
dev_start = dev->pa;
|
||||
dev_end = dev_start + dev->size;
|
||||
|
||||
if (addr < dev_start)
|
||||
new_end = min(new_end, dev_start);
|
||||
else if (addr >= dev_end)
|
||||
new_start = max(new_start, dev_end);
|
||||
else
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
*start = new_start;
|
||||
*end = new_end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -625,13 +625,13 @@ static int host_stage2_idmap(u64 addr)
|
||||
|
||||
prot = is_memory ? PKVM_HOST_MEM_PROT : PKVM_HOST_MMIO_PROT;
|
||||
|
||||
/**
|
||||
* Let device drivers adjust the permitted range first.
|
||||
* host_stage2_adjust_range() should be last to also properly align it.
|
||||
/*
|
||||
* Adjust against IOMMU devices first. host_stage2_adjust_range() should
|
||||
* be called last for proper alignment.
|
||||
*/
|
||||
if (!is_memory && kvm_iommu_ops.host_stage2_adjust_mmio_range) {
|
||||
ret = kvm_iommu_ops.host_stage2_adjust_mmio_range(addr, &range.start,
|
||||
&range.end);
|
||||
if (!is_memory) {
|
||||
ret = pkvm_iommu_host_stage2_adjust_range(addr, &range.start,
|
||||
&range.end);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user