diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index cf6ce6fe2bb3..ef0a97a6d5ac 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -401,8 +401,12 @@ int pkvm_iommu_register(struct device *dev, u64 drv, int pkvm_iommu_suspend(struct device *dev); int pkvm_iommu_resume(struct device *dev); -/* Reject future calls to pkvm_iommu_driver_init() and pkvm_iommu_register(). */ -int pkvm_iommu_finalize(void); +/* + * Reject future calls to pkvm_iommu_driver_init() and pkvm_iommu_register() + * and report errors if found. Incase of errors pKVM can take proper actions + * as erasing pvmfw. + */ +int pkvm_iommu_finalize(int err); struct vcpu_reset_state { unsigned long pc; diff --git a/arch/arm64/kvm/hyp/include/nvhe/iommu.h b/arch/arm64/kvm/hyp/include/nvhe/iommu.h index 639277053e6d..ffa7dcfc7952 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/iommu.h +++ b/arch/arm64/kvm/hyp/include/nvhe/iommu.h @@ -91,7 +91,7 @@ int __pkvm_iommu_register(unsigned long dev_id, unsigned long drv_id, void *kern_mem_va, size_t mem_size); int __pkvm_iommu_pm_notify(unsigned long dev_id, enum pkvm_iommu_pm_event event); -int __pkvm_iommu_finalize(void); +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, diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index 8d8f7e255dec..970c0f94680d 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -1171,7 +1171,9 @@ static void handle___pkvm_iommu_pm_notify(struct kvm_cpu_context *host_ctxt) static void handle___pkvm_iommu_finalize(struct kvm_cpu_context *host_ctxt) { - cpu_reg(host_ctxt, 1) = __pkvm_iommu_finalize(); + DECLARE_REG(int, err, host_ctxt, 1); + + cpu_reg(host_ctxt, 1) = __pkvm_iommu_finalize(err); } static void handle___pkvm_alloc_module_va(struct kvm_cpu_context *host_ctxt) diff --git a/arch/arm64/kvm/hyp/nvhe/iommu.c b/arch/arm64/kvm/hyp/nvhe/iommu.c index a6073f443c8f..f9431dca570e 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu.c @@ -14,6 +14,7 @@ #include #include #include +#include #define DRV_ID(drv_addr) ((unsigned long)drv_addr) @@ -450,7 +451,7 @@ out_unlock: return ret; } -int __pkvm_iommu_finalize(void) +int __pkvm_iommu_finalize(int err) { int ret = 0; @@ -460,6 +461,14 @@ int __pkvm_iommu_finalize(void) else ret = -EPERM; hyp_spin_unlock(&iommu_registration_lock); + + /* + * If finalize failed in EL1 driver for any reason, this means we can't trust the DMA + * isolation. So we have to inform pKVM to properly protect itself. + */ + if (!ret && err) + pkvm_handle_system_misconfiguration(NO_DMA_ISOLATION); + return ret; } diff --git a/arch/arm64/kvm/iommu.c b/arch/arm64/kvm/iommu.c index 08b318a2aae9..5fe0b3080fc3 100644 --- a/arch/arm64/kvm/iommu.c +++ b/arch/arm64/kvm/iommu.c @@ -58,8 +58,8 @@ int pkvm_iommu_resume(struct device *dev) } EXPORT_SYMBOL_GPL(pkvm_iommu_resume); -int pkvm_iommu_finalize(void) +int pkvm_iommu_finalize(int err) { - return kvm_call_hyp_nvhe(__pkvm_iommu_finalize); + return kvm_call_hyp_nvhe(__pkvm_iommu_finalize, err); } EXPORT_SYMBOL_GPL(pkvm_iommu_finalize);