diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c --- a/sys/x86/iommu/intel_ctx.c +++ b/sys/x86/iommu/intel_ctx.c @@ -631,6 +631,10 @@ * to avoid unneeded command. */ if (enable && !rmrr_init && (dmar->hw_gcmd & DMAR_GCMD_TE) == 0) { + error = dmar_disable_protected_regions(dmar); + if (error != 0) + printf("dmar%d: Failed to disable protected regions\n", + dmar->iommu.unit); error = dmar_enable_translation(dmar); if (error == 0) { if (bootverbose) { diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h --- a/sys/x86/iommu/intel_dmar.h +++ b/sys/x86/iommu/intel_dmar.h @@ -227,6 +227,7 @@ void dmar_flush_pte_to_ram(struct dmar_unit *unit, dmar_pte_t *dst); void dmar_flush_ctx_to_ram(struct dmar_unit *unit, dmar_ctx_entry_t *dst); void dmar_flush_root_to_ram(struct dmar_unit *unit, dmar_root_entry_t *dst); +int dmar_disable_protected_regions(struct dmar_unit *unit); int dmar_enable_translation(struct dmar_unit *unit); int dmar_disable_translation(struct dmar_unit *unit); int dmar_load_irt_ptr(struct dmar_unit *unit); diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c --- a/sys/x86/iommu/intel_drv.c +++ b/sys/x86/iommu/intel_drv.c @@ -1065,6 +1065,10 @@ KASSERT((dmar->hw_gcmd & DMAR_GCMD_TE) == 0, ("dmar%d: RMRR not handled but translation is already enabled", dmar->iommu.unit)); + error = dmar_disable_protected_regions(dmar); + if (error != 0) + printf("dmar%d: Failed to disable protected regions\n", + dmar->iommu.unit); error = dmar_enable_translation(dmar); if (bootverbose) { if (error == 0) { diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c --- a/sys/x86/iommu/intel_utils.c +++ b/sys/x86/iommu/intel_utils.c @@ -489,6 +489,33 @@ return (error); } +/* + * Some BIOSes protect memory region they reside in by using DMAR to + * prevent devices from doing any DMA transactions to that part of RAM. + * AMI refers to this as "DMA Control Guarantee". + * We need to disable this when address translation is enabled. + */ +int +dmar_disable_protected_regions(struct dmar_unit *unit) +{ + uint32_t reg; + int error; + + DMAR_ASSERT_LOCKED(unit); + + /* Check if we support the feature. */ + if ((unit->hw_cap & (DMAR_CAP_PLMR | DMAR_CAP_PHMR)) == 0) + return (0); + + reg = dmar_read4(unit, DMAR_PMEN_REG); + reg &= ~DMAR_PMEN_EPM; + dmar_write4(unit, DMAR_PMEN_REG, reg); + DMAR_WAIT_UNTIL(((dmar_read4(unit, DMAR_PMEN_REG) & DMAR_PMEN_PRS) + != 0)); + + return (error); +} + int dmar_enable_translation(struct dmar_unit *unit) {