diff --git a/arch/arm64/kvm/hyp/include/nvhe/iommu.h b/arch/arm64/kvm/hyp/include/nvhe/iommu.h index ad05bf0bf764..54fb96562186 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/iommu.h +++ b/arch/arm64/kvm/hyp/include/nvhe/iommu.h @@ -93,8 +93,6 @@ int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, int __pkvm_iommu_pm_notify(unsigned long dev_id, enum pkvm_iommu_pm_event event); int __pkvm_iommu_finalize(int err); -int pkvm_iommu_host_stage2_adjust_range(phys_addr_t addr, phys_addr_t *start, - phys_addr_t *end); bool pkvm_iommu_host_dabt_handler(struct kvm_cpu_context *host_ctxt, u32 esr, phys_addr_t fault_pa); void pkvm_iommu_host_stage2_idmap(phys_addr_t start, phys_addr_t end, diff --git a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h index ab36d866c11b..19574e12566f 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h +++ b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h @@ -72,6 +72,7 @@ int __pkvm_host_share_hyp(u64 pfn); int __pkvm_host_unshare_hyp(u64 pfn); int __pkvm_host_reclaim_page(struct pkvm_hyp_vm *vm, u64 pfn, u64 ipa); int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages); +int __pkvm_host_donate_hyp_locked(u64 pfn, u64 nr_pages); int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages); int __pkvm_host_share_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu); int __pkvm_host_donate_guest(u64 pfn, u64 gfn, struct pkvm_hyp_vcpu *vcpu); diff --git a/arch/arm64/kvm/hyp/nvhe/iommu.c b/arch/arm64/kvm/hyp/nvhe/iommu.c index 4c56afee5e2c..6c5ac9be7214 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu.c @@ -392,6 +392,7 @@ int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, .id = dev_id, .ops = drv->ops, .pa = dev_pa, + .va = hyp_phys_to_virt(dev_pa), .size = dev_size, .flags = flags, }; @@ -421,22 +422,11 @@ int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, goto out_free; } - /* - * Unmap the device's MMIO range from host stage-2. If registration - * is successful, future attempts to re-map will be blocked by - * pkvm_iommu_host_stage2_adjust_range. - */ - ret = host_stage2_unmap_reg_locked(dev_pa, dev_size); + ret = __pkvm_host_donate_hyp_locked(hyp_phys_to_pfn(dev_pa), + PAGE_ALIGN(dev_size) >> PAGE_SHIFT); if (ret) goto out_free; - /* Create EL2 mapping for the device. */ - ret = __pkvm_create_private_mapping(dev_pa, dev_size, - PAGE_HYP_DEVICE, (unsigned long *)(&dev->va)); - if (ret){ - goto out_free; - } - /* Register device and prevent host from mapping the MMIO range. */ list_add_tail(&dev->list, &iommu_list); if (dev->parent) @@ -495,39 +485,6 @@ int __pkvm_iommu_pm_notify(unsigned long dev_id, enum pkvm_iommu_pm_event event) 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; -} - bool pkvm_iommu_host_dabt_handler(struct kvm_cpu_context *host_ctxt, u32 esr, phys_addr_t pa) { diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 41c7f55df964..a158beff7057 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -789,17 +789,6 @@ static int host_stage2_idmap(struct kvm_vcpu_fault_info *fault, u64 addr) } } - /* - * Adjust against IOMMU devices first. host_stage2_adjust_range() should - * be called last for proper alignment. - */ - if (!is_memory) { - ret = pkvm_iommu_host_stage2_adjust_range(addr, &range.start, - &range.end); - if (ret) - return ret; - } - ret = host_stage2_adjust_range(addr, &range, level); if (ret) return ret; @@ -1922,6 +1911,17 @@ int __pkvm_host_unshare_hyp(u64 pfn) } int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages) +{ + int ret; + + host_lock_component(); + ret = __pkvm_host_donate_hyp_locked(pfn, nr_pages); + host_unlock_component(); + + return ret; +} + +int __pkvm_host_donate_hyp_locked(u64 pfn, u64 nr_pages) { int ret; u64 host_addr = hyp_pfn_to_phys(pfn); @@ -1942,13 +1942,12 @@ int __pkvm_host_donate_hyp(u64 pfn, u64 nr_pages) }, }; - host_lock_component(); + hyp_assert_lock_held(&host_mmu.lock); hyp_lock_component(); ret = do_donate(&donation); hyp_unlock_component(); - host_unlock_component(); return ret; }