dmar: Disable protected memory regions after initialization

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".
Disable the protection when address translation is enabled.
I stumbled upon this while investigation a failing coredump on a device
which has this feature enabled.

Sponsored by:		Stormshield
Obtained from:		Semihalf
Reviewed by:		kib
Differential revision:	https://reviews.freebsd.org/D32591
This commit is contained in:
Kornel Duleba 2021-10-21 16:02:26 +02:00 committed by Wojciech Macek
parent 3c02da8096
commit 06e6ca6dd3
4 changed files with 36 additions and 0 deletions

View File

@ -631,6 +631,10 @@ dmar_get_ctx_for_dev1(struct dmar_unit *dmar, device_t dev, uint16_t rid,
* 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) {

View File

@ -227,6 +227,7 @@ int dmar_flush_write_bufs(struct dmar_unit *unit);
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);

View File

@ -1065,6 +1065,10 @@ dmar_instantiate_rmrr_ctxs(struct iommu_unit *unit)
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) {

View File

@ -489,6 +489,33 @@ dmar_flush_write_bufs(struct dmar_unit *unit)
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)
{