Commit cda2f6c7 authored by Keir Fraser's avatar Keir Fraser

vt-d: enhance the support of Interrupt Remapping EIM and x2APIC

1) Clear Interrupt Remapping(IR) unit's CFI (Compatibility Format
Interrupt) to enhance security;
2) Move the iommu_setup() ahead and put it before we begin to use
IOAPIC so we can make sure after we enable Interrupt Remapping, the
later IOAPIC (and MSI) initialization would setup IOAPIC RTEs (and
MSI) with remappable format;
3) Enable x2APIC only when all VT-d engines support IR with EIM
(Extended Interrupt Mode). EIM enables external devices to deliver
interrupts to logical processor with >8-bit APIC ID.
Signed-off-by: default avatarDexuan Cui <dexuan.cui@intel.com>
parent 1589882b
......@@ -630,6 +630,8 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus);
initialise_gdb(); /* could be moved earlier */
iommu_setup(); /* setup iommu if available */
do_initcalls();
sort_main_extable();
......
......@@ -848,6 +848,9 @@ void enable_x2apic(void)
{
u32 lo, hi;
if ( !iommu_supports_eim() )
return;
rdmsr(MSR_IA32_APICBASE, lo, hi);
if ( !(lo & MSR_IA32_APICBASE_EXTD) )
{
......@@ -858,7 +861,13 @@ void enable_x2apic(void)
else
printk("x2APIC mode enabled by BIOS.\n");
x2apic_enabled = 1;
if ( !x2apic_enabled )
{
x2apic_enabled = 1;
genapic = &apic_x2apic;
printk(KERN_INFO "Switched to APIC driver %s.\n",
genapic->name);
}
}
void __init init_apic_mappings(void)
......@@ -889,6 +898,8 @@ __next:
*/
if (boot_cpu_physical_apicid == -1U)
boot_cpu_physical_apicid = get_apic_id();
x86_cpu_to_apicid[0] = get_apic_id();
cpu_2_logical_apicid[0] = get_logical_apic_id();
init_ioapic_mappings();
}
......
......@@ -14,7 +14,6 @@
#include <asm/apicdef.h>
#include <asm/genapic.h>
extern struct genapic apic_x2apic;
extern struct genapic apic_summit;
extern struct genapic apic_bigsmp;
extern struct genapic apic_default;
......@@ -22,7 +21,6 @@ extern struct genapic apic_default;
struct genapic *genapic;
struct genapic *apic_probe[] __initdata = {
&apic_x2apic,
&apic_summit,
&apic_bigsmp,
&apic_default, /* must be last */
......
......@@ -904,11 +904,11 @@ void __init __start_xen(unsigned long mbi_p)
generic_apic_probe();
acpi_boot_init();
if ( x2apic_is_available() )
enable_x2apic();
acpi_boot_init();
init_cpu_to_node();
if ( smp_found_config )
......@@ -954,6 +954,8 @@ void __init __start_xen(unsigned long mbi_p)
if ( opt_nosmp )
max_cpus = 0;
iommu_setup(); /* setup iommu if available */
smp_prepare_cpus(max_cpus);
spin_debug_enable();
......
......@@ -260,7 +260,7 @@ int deassign_device(struct domain *d, u8 bus, u8 devfn)
return 0;
}
static int iommu_setup(void)
int iommu_setup(void)
{
int rc = -ENODEV;
......@@ -279,7 +279,6 @@ static int iommu_setup(void)
iommu_pv_enabled ? "en" : "dis");
return rc;
}
__initcall(iommu_setup);
int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn,
XEN_GUEST_HANDLE_64(uint32) buf, int max_sdevs)
......
......@@ -357,6 +357,7 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header;
void *dev_scope_start, *dev_scope_end;
struct acpi_drhd_unit *dmaru;
void *addr;
int ret = 0;
static int include_all = 0;
......@@ -371,6 +372,9 @@ acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
dprintk(XENLOG_INFO VTDPREFIX, "dmaru->address = %"PRIx64"\n",
dmaru->address);
addr = map_to_nocache_virt(0, drhd->address);
dmaru->ecap = dmar_readq(addr, DMAR_ECAP_REG);
dev_scope_start = (void *)(drhd + 1);
dev_scope_end = ((void *)drhd) + header->length;
ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
......
......@@ -50,6 +50,7 @@ struct acpi_drhd_unit {
struct dmar_scope scope; /* must be first member of struct */
struct list_head list;
u64 address; /* register base address of the unit */
u64 ecap;
u8 include_all:1;
struct iommu *iommu;
struct list_head ioapic_list;
......@@ -109,6 +110,8 @@ do { \
} \
} while (0)
void *map_to_nocache_virt(int nr_iommus, u64 maddr);
int vtd_hw_check(void);
void disable_pmr(struct iommu *iommu);
int is_usb_device(u8 bus, u8 devfn);
......
......@@ -121,6 +121,22 @@ static void set_ioapic_source_id(int apic_id, struct iremap_entry *ire)
apicid_to_bdf(apic_id));
}
int iommu_supports_eim(void)
{
struct acpi_drhd_unit *drhd;
if ( !iommu_enabled || !iommu_qinval || !iommu_intremap )
return 0;
for_each_drhd_unit ( drhd )
if ( !ecap_queued_inval(drhd->ecap) ||
!ecap_intr_remap(drhd->ecap) ||
!ecap_eim(drhd->ecap) )
return 0;
return 1;
}
static int remap_entry_to_ioapic_rte(
struct iommu *iommu, struct IO_xAPIC_route_entry *old_rte)
{
......@@ -635,10 +651,10 @@ int enable_intremap(struct iommu *iommu)
ir_ctrl->iremap_index = -1;
}
#if defined(ENABLED_EXTENDED_INTERRUPT_SUPPORT)
#ifdef CONFIG_X86
/* set extended interrupt mode bit */
ir_ctrl->iremap_maddr |=
ecap_ext_intr(iommu->ecap) ? (1 << IRTA_REG_EIME_SHIFT) : 0;
x2apic_enabled ? (1 << IRTA_REG_EIME_SHIFT) : 0;
#endif
spin_lock_irqsave(&iommu->register_lock, flags);
......@@ -659,13 +675,6 @@ int enable_intremap(struct iommu *iommu)
iommu_flush_iec_global(iommu);
spin_lock_irqsave(&iommu->register_lock, flags);
/* enable comaptiblity format interrupt pass through */
gcmd |= DMA_GCMD_CFI;
dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd);
IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
(sts & DMA_GSTS_CFIS), sts);
/* enable interrupt remapping hardware */
gcmd |= DMA_GCMD_IRE;
dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd);
......
......@@ -101,7 +101,7 @@
#define ecap_queued_inval(e) ((e >> 1) & 0x1)
#define ecap_dev_iotlb(e) ((e >> 2) & 0x1)
#define ecap_intr_remap(e) ((e >> 3) & 0x1)
#define ecap_ext_intr(e) ((e >> 4) & 0x1)
#define ecap_eim(e) ((e >> 4) & 0x1)
#define ecap_cache_hints(e) ((e >> 5) & 0x1)
#define ecap_pass_thru(e) ((e >> 6) & 0x1)
#define ecap_snp_ctl(e) ((e >> 7) & 0x1)
......
......@@ -100,7 +100,6 @@ struct msi_msg_remap_entry {
unsigned int get_cache_line_size(void);
void cacheline_flush(char *);
void flush_all_cache(void);
void *map_to_nocache_virt(int nr_iommus, u64 maddr);
u64 alloc_pgtable_maddr(struct acpi_drhd_unit *drhd, unsigned long npages);
void free_pgtable_maddr(u64 maddr);
void *map_vtd_domain_page(u64 maddr);
......
......@@ -49,6 +49,7 @@ struct genapic {
APICFUNC(acpi_madt_oem_check)
extern struct genapic *genapic;
extern struct genapic apic_x2apic;
void init_apic_ldr_flat(void);
void clustered_apic_check_flat(void);
......
......@@ -49,6 +49,7 @@ extern void zap_low_mappings(l2_pgentry_t *base);
#define MAX_APICID 256
extern u32 x86_cpu_to_apicid[];
extern u32 cpu_2_logical_apicid[];
#define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu]
......
......@@ -57,6 +57,9 @@ struct iommu {
struct intel_iommu *intel;
};
int iommu_setup(void);
int iommu_supports_eim(void);
int iommu_add_device(struct pci_dev *pdev);
int iommu_remove_device(struct pci_dev *pdev);
int iommu_domain_init(struct domain *d);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment