From 49e40428789966cd1142aba40d7f2bbce2f6ed66 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 20 Aug 2014 09:08:01 +0200 Subject: [PATCH] core/configs/tools: Report IOMMU association of devices via config file We will need this information for emulating VT-d for the root cell: Add an iommu field to the PCI device config structure and encode the unit number in the id field of the IOAPIC's irqchip structure. The config generator fills the fields according to the DMAR ACPI table. However, we do not yet understand all exotic forms of Device Scope structures. If it turns out that there are PCI devices without any IOMMU association, refuse to generate a config file - such systems are unsupported (with the temporary exception of AMD platforms). Update the h87i config accordingly. QEMU currently only exposes a single DMAR unit, thus the implicit zero-initialization is fine. As the IOMMU number is only used in the context of the root cell, ioapic-demo and pci-demo require no updates as well. Signed-off-by: Jan Kiszka --- configs/h87i.c | 15 ++++++++++- configs/ioapic-demo.c | 1 + hypervisor/arch/x86/include/asm/cell.h | 1 + hypervisor/arch/x86/ioapic.c | 3 ++- hypervisor/include/jailhouse/cell-config.h | 3 ++- tools/jailhouse-config-create | 30 ++++++++++++++++++---- tools/root-cell-config.c.tmpl | 1 + 7 files changed, 46 insertions(+), 8 deletions(-) diff --git a/configs/h87i.c b/configs/h87i.c index 2b74999..27fcc2f 100644 --- a/configs/h87i.c +++ b/configs/h87i.c @@ -117,7 +117,7 @@ struct { .irqchips = { /* IOAPIC */ { .address = 0xfec00000, - .id = 0xf0f8, + .id = 0x1f0f8, .pin_bitmap = 0xffffff, }, }, @@ -139,6 +139,7 @@ struct { /* PCIDevice: 00:00.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0x0, .caps_start = 0, @@ -147,6 +148,7 @@ struct { /* PCIDevice: 00:01.0 */ { .type = JAILHOUSE_PCI_TYPE_BRIDGE, + .iommu = 1, .domain = 0x0, .bdf = 0x8, .caps_start = 1, @@ -156,6 +158,7 @@ struct { /* PCIDevice: 00:02.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 0, .domain = 0x0, .bdf = 0x10, .caps_start = 5, @@ -165,6 +168,7 @@ struct { /* PCIDevice: 00:03.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0x18, .caps_start = 8, @@ -174,6 +178,7 @@ struct { /* PCIDevice: 00:14.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xa0, .caps_start = 11, @@ -184,6 +189,7 @@ struct { /* PCIDevice: 00:16.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xb0, .caps_start = 13, @@ -194,6 +200,7 @@ struct { /* PCIDevice: 00:19.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xc8, .caps_start = 15, @@ -204,6 +211,7 @@ struct { /* PCIDevice: 00:1a.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xd0, .caps_start = 18, @@ -212,6 +220,7 @@ struct { /* PCIDevice: 00:1b.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xd8, .caps_start = 21, @@ -222,6 +231,7 @@ struct { /* PCIDevice: 00:1d.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xe8, .caps_start = 18, @@ -230,6 +240,7 @@ struct { /* PCIDevice: 00:1f.0 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xf8, .caps_start = 0, @@ -238,6 +249,7 @@ struct { /* PCIDevice: 00:1f.2 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xfa, .caps_start = 24, @@ -247,6 +259,7 @@ struct { /* PCIDevice: 00:1f.3 */ { .type = JAILHOUSE_PCI_TYPE_DEVICE, + .iommu = 1, .domain = 0x0, .bdf = 0xfb, .caps_start = 0, diff --git a/configs/ioapic-demo.c b/configs/ioapic-demo.c index 35f534f..1a4315e 100644 --- a/configs/ioapic-demo.c +++ b/configs/ioapic-demo.c @@ -59,6 +59,7 @@ struct { .irqchips = { /* IOAPIC */ { .address = 0xfec00000, + .id = 0xff01, .pin_bitmap = 0x000200, /* ACPI IRQ */ }, }, diff --git a/hypervisor/arch/x86/include/asm/cell.h b/hypervisor/arch/x86/include/asm/cell.h index ba18d70..70afb25 100644 --- a/hypervisor/arch/x86/include/asm/cell.h +++ b/hypervisor/arch/x86/include/asm/cell.h @@ -55,6 +55,7 @@ struct cell { u32 ioapic_index_reg_val; u16 ioapic_id; + u8 ioapic_iommu; u64 ioapic_pin_bitmap; union { diff --git a/hypervisor/arch/x86/ioapic.c b/hypervisor/arch/x86/ioapic.c index acd179c..a0b77dd 100644 --- a/hypervisor/arch/x86/ioapic.c +++ b/hypervisor/arch/x86/ioapic.c @@ -212,7 +212,8 @@ void ioapic_cell_init(struct cell *cell) ioapic_find_config(cell->config); if (irqchip) { - cell->ioapic_id = irqchip->id; + cell->ioapic_id = (u16)irqchip->id; + cell->ioapic_iommu = (u8)(irqchip->id >> 16); cell->ioapic_pin_bitmap = irqchip->pin_bitmap; if (cell != &root_cell) { diff --git a/hypervisor/include/jailhouse/cell-config.h b/hypervisor/include/jailhouse/cell-config.h index b01d6b5..d0b0341 100644 --- a/hypervisor/include/jailhouse/cell-config.h +++ b/hypervisor/include/jailhouse/cell-config.h @@ -60,7 +60,8 @@ struct jailhouse_irqchip { #define JAILHOUSE_PCI_TYPE_BRIDGE 0x02 struct jailhouse_pci_device { - __u16 type; + __u8 type; + __u8 iommu; __u16 domain; __u16 bdf; __u16 caps_start; diff --git a/tools/jailhouse-config-create b/tools/jailhouse-config-create index 6474534..7aedd5c 100755 --- a/tools/jailhouse-config-create +++ b/tools/jailhouse-config-create @@ -184,6 +184,7 @@ class PCICapability: class PCIDevice: def __init__(self, type, domain, bus, dev, fn, caps): self.type = type + self.iommu = None self.domain = domain self.bus = bus self.dev = dev @@ -473,7 +474,7 @@ def parse_dmar_devscope(f): # parsing of DMAR ACPI Table # see Intel VT-d Spec chapter 8 -def parse_dmar(): +def parse_dmar(pcidevices): f = input_open('/sys/firmware/acpi/tables/DMAR', 'rb', True) if get_cpu_vendor() == 'AuthenticAMD': print('WARNING: AMD IOMMU support is not implemented yet') @@ -498,22 +499,34 @@ def parse_dmar(): # DMA Remapping Hardware Unit Definition if struct_type == 0: - (segment, base) = struct.unpack('= 8: raise RuntimeError('Too many DMAR units. ' 'Raise JAILHOUSE_MAX_DMAR_UNITS.') units.append(base) + if flags & 1: + for d in pcidevices: + if d.iommu == None: + d.iommu = len(units) - 1 offset += 16 - offset while offset < struct_len: (scope_type, scope_len, bus, dev, fn) =\ parse_dmar_devscope(f) - if scope_type == 3: + if scope_type == 1: + for d in pcidevices: + if d.bus == bus and d.dev == dev and d.fn == fn: + d.iommu = len(units) - 1 + elif scope_type == 2: + raise RuntimeError('Unsupported DMAR Device Scope type') + elif scope_type == 3: if ioapic_id != 0: raise RuntimeError('We do not support more ' 'than 1 IOAPIC') - ioapic_id = (bus << 8) | (dev << 3) | fn + # encode the DMAR unit number into the device ID + ioapic_id = ((len(units) - 1) << 16) | \ + (bus << 8) | (dev << 3) | fn offset += scope_len # Reserved Memory Region Reporting Structure @@ -613,9 +626,16 @@ total = hvmem[1] + inmatemem mmconfig = MMConfig.parse() -(dmar_units, ioapic_id, rmrr_regs) = parse_dmar() +(dmar_units, ioapic_id, rmrr_regs) = parse_dmar(pcidevices) regions += rmrr_regs +for d in pcidevices: + if get_cpu_vendor() == 'AuthenticAMD': + d.iommu = 0 # temporary workaround + if d.iommu == None: + raise RuntimeError('PCI device %02x:%02x.%x outside the scope of an ' + 'IOMMU' % (d.bus, d.dev, d.fn)) + # kernel does not have memmap region, pick one if ourmem is None: ourmem = alloc_mem(regions, total) diff --git a/tools/root-cell-config.c.tmpl b/tools/root-cell-config.c.tmpl index fb34462..f111dbb 100644 --- a/tools/root-cell-config.c.tmpl +++ b/tools/root-cell-config.c.tmpl @@ -107,6 +107,7 @@ struct { /* ${str(d)} */ { .type = ${d.type}, + .iommu = ${d.iommu}, .domain = ${hex(d.domain)}, .bdf = ${hex(d.bdf())}, .caps_start = ${d.caps_start}, -- 2.39.2