diff options
Diffstat (limited to 'drivers/iommu/intel_irq_remapping.c')
| -rw-r--r-- | drivers/iommu/intel_irq_remapping.c | 48 | 
1 files changed, 40 insertions, 8 deletions
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index af8904de1d4..f3b8f23b5d8 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)  {  	struct ir_table *table = iommu->ir_table;  	struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); +	struct irq_cfg *cfg = irq_get_chip_data(irq);  	u16 index, start_index;  	unsigned int mask = 0;  	unsigned long flags; @@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)  	for (i = index; i < index + count; i++)  		table->base[i].present = 1; +	cfg->remapped = 1;  	irq_iommu->iommu = iommu;  	irq_iommu->irte_index =  index;  	irq_iommu->sub_handle = 0; @@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle)  static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)  {  	struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); +	struct irq_cfg *cfg = irq_get_chip_data(irq);  	unsigned long flags;  	if (!irq_iommu) @@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha  	raw_spin_lock_irqsave(&irq_2_ir_lock, flags); +	cfg->remapped = 1;  	irq_iommu->iommu = iommu;  	irq_iommu->irte_index = index;  	irq_iommu->sub_handle = subhandle; @@ -425,11 +429,22 @@ static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode)  	/* Enable interrupt-remapping */  	iommu->gcmd |= DMA_GCMD_IRE; +	iommu->gcmd &= ~DMA_GCMD_CFI;  /* Block compatibility-format MSIs */  	writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);  	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,  		      readl, (sts & DMA_GSTS_IRES), sts); +	/* +	 * With CFI clear in the Global Command register, we should be +	 * protected from dangerous (i.e. compatibility) interrupts +	 * regardless of x2apic status.  Check just to be sure. +	 */ +	if (sts & DMA_GSTS_CFIS) +		WARN(1, KERN_WARNING +			"Compatibility-format IRQs enabled despite intr remapping;\n" +			"you are vulnerable to IRQ injection.\n"); +  	raw_spin_unlock_irqrestore(&iommu->register_lock, flags);  } @@ -526,20 +541,24 @@ static int __init intel_irq_remapping_supported(void)  static int __init intel_enable_irq_remapping(void)  {  	struct dmar_drhd_unit *drhd; +	bool x2apic_present;  	int setup = 0;  	int eim = 0; +	x2apic_present = x2apic_supported(); +  	if (parse_ioapics_under_ir() != 1) {  		printk(KERN_INFO "Not enable interrupt remapping\n"); -		return -1; +		goto error;  	} -	if (x2apic_supported()) { +	if (x2apic_present) {  		eim = !dmar_x2apic_optout(); -		WARN(!eim, KERN_WARNING -			   "Your BIOS is broken and requested that x2apic be disabled\n" -			   "This will leave your machine vulnerable to irq-injection attacks\n" -			   "Use 'intremap=no_x2apic_optout' to override BIOS request\n"); +		if (!eim) +			printk(KERN_WARNING +				"Your BIOS is broken and requested that x2apic be disabled.\n" +				"This will slightly decrease performance.\n" +				"Use 'intremap=no_x2apic_optout' to override BIOS request.\n");  	}  	for_each_drhd_unit(drhd) { @@ -578,7 +597,7 @@ static int __init intel_enable_irq_remapping(void)  		if (eim && !ecap_eim_support(iommu->ecap)) {  			printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "  			       " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); -			return -1; +			goto error;  		}  	} @@ -594,7 +613,7 @@ static int __init intel_enable_irq_remapping(void)  			printk(KERN_ERR "DRHD %Lx: failed to enable queued, "  			       " invalidation, ecap %Lx, ret %d\n",  			       drhd->reg_base_addr, iommu->ecap, ret); -			return -1; +			goto error;  		}  	} @@ -617,6 +636,14 @@ static int __init intel_enable_irq_remapping(void)  		goto error;  	irq_remapping_enabled = 1; + +	/* +	 * VT-d has a different layout for IO-APIC entries when +	 * interrupt remapping is enabled. So it needs a special routine +	 * to print IO-APIC entries for debugging purposes too. +	 */ +	x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries; +  	pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");  	return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; @@ -625,6 +652,11 @@ error:  	/*  	 * handle error condition gracefully here!  	 */ + +	if (x2apic_present) +		WARN(1, KERN_WARNING +			"Failed to enable irq remapping.  You are vulnerable to irq-injection attacks.\n"); +  	return -1;  }  |