diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index d5148d006060..083c4e5b0e27 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -131,6 +131,8 @@ struct kvm_iommu_ops { phys_addr_t fault_pa, unsigned int len, bool is_write, int rd); void (*host_stage2_set_owner)(phys_addr_t addr, size_t size, u8 owner_id); + int (*host_stage2_adjust_mmio_range)(phys_addr_t addr, phys_addr_t *start, + phys_addr_t *end); }; extern struct kvm_iommu_ops kvm_iommu_ops; diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index badd206be6dc..1f5c53e604e8 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -346,6 +346,17 @@ 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. + */ + 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 (ret) + return ret; + } + hyp_spin_lock(&host_kvm.lock); ret = host_stage2_adjust_range(addr, &range); if (ret)