From d43445fabc7bf43facad2c89d9565e834a2ce12a Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sat, 20 Feb 2016 19:09:49 +0100 Subject: [PATCH] core, configs, tools: Prepare for variable IOMMU register set sizes Introduce a size field to struct jailhouse_iommu and fill it via the config generator. The information can be retrieved from the ACPI tables for AMD. On Intel, we need to study the Linux mappings, thus we need to demand that DMAR is enabled now while retrieving system information. Based on patches by Valentine Sinitsyn. Signed-off-by: Jan Kiszka --- configs/f2a88xm-hd3.c | 1 + configs/h87i.c | 2 + configs/qemu-vm.c | 1 + hypervisor/include/jailhouse/cell-config.h | 1 + tools/jailhouse-config-create | 84 ++++++++++++++++------ tools/root-cell-config.c.tmpl | 5 +- 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/configs/f2a88xm-hd3.c b/configs/f2a88xm-hd3.c index 825452a..d11ebd8 100644 --- a/configs/f2a88xm-hd3.c +++ b/configs/f2a88xm-hd3.c @@ -47,6 +47,7 @@ struct { .iommu_units = { { .base = 0xfeb80000, + .size = 0x80000, }, }, }, diff --git a/configs/h87i.c b/configs/h87i.c index 2015729..5869fb1 100644 --- a/configs/h87i.c +++ b/configs/h87i.c @@ -42,9 +42,11 @@ struct { .iommu_units = { { .base = 0xfed90000, + .size = 0x1000, }, { .base = 0xfed91000, + .size = 0x1000, }, }, }, diff --git a/configs/qemu-vm.c b/configs/qemu-vm.c index 1d7481e..64b9a25 100644 --- a/configs/qemu-vm.c +++ b/configs/qemu-vm.c @@ -56,6 +56,7 @@ struct { .iommu_units = { { .base = 0xfed90000, + .size = 0x1000, }, }, }, diff --git a/hypervisor/include/jailhouse/cell-config.h b/hypervisor/include/jailhouse/cell-config.h index 84ffa5c..b21bf60 100644 --- a/hypervisor/include/jailhouse/cell-config.h +++ b/hypervisor/include/jailhouse/cell-config.h @@ -141,6 +141,7 @@ struct jailhouse_pci_capability { struct jailhouse_iommu { __u64 base; + __u32 size; } __attribute__((packed)); #define JAILHOUSE_SYSTEM_SIGNATURE "JAILSYST" diff --git a/tools/jailhouse-config-create b/tools/jailhouse-config-create index 935a5c1..b7207fb 100755 --- a/tools/jailhouse-config-create +++ b/tools/jailhouse-config-create @@ -2,7 +2,13 @@ # # Jailhouse, a Linux-based partitioning hypervisor # -# Copyright (c) Siemens AG, 2014 +# Copyright (c) Siemens AG, 2014-2016 +# Copyright (c) Valentine Sinitsyn, 2014-2015 +# +# Authors: +# Henning Schild +# Jan Kiszka +# Valentine Sinitsyn # # This work is licensed under the terms of the GNU GPL, version 2. See # the COPYING file in the top-level directory. @@ -532,8 +538,7 @@ class IOMemRegionTree: # blacklisted on all levels if ( (s.find('PCI MMCONFIG') >= 0) or - (s.find('APIC') >= 0) or # covers both APIC and IOAPIC - (s.find('dmar') >= 0) + (s.find('APIC') >= 0) # covers both APIC and IOAPIC ): continue @@ -553,6 +558,12 @@ class IOMemRegionTree: return regions +class IOMMUConfig(object): + def __init__(self, props): + self.base_addr = props['base_addr'] + self.mmio_size = props['mmio_size'] + + def parse_iomem(pcidevices): regions = IOMemRegionTree.parse_iomem_tree( IOMemRegionTree.parse_iomem_file()) @@ -561,6 +572,7 @@ def parse_iomem(pcidevices): add_rom_region = False ret = [] + dmar_regions = [] for r in regions: append_r = True # filter the list for MSI-X pages @@ -580,6 +592,10 @@ def parse_iomem(pcidevices): if (r.start >= rom_region.start and r.stop <= rom_region.stop): add_rom_region = True append_r = False + # filter out and save DMAR regions + if r.typestr.find('dmar') >= 0: + dmar_regions.append(r) + append_r = False if append_r: ret.append(r) @@ -592,7 +608,7 @@ def parse_iomem(pcidevices): if (ret[0].typestr == 'System RAM' and ret[0].start == 0x1000): ret[0].start = 0 - return ret + return ret, dmar_regions def parse_pcidevices(): @@ -704,7 +720,7 @@ def parse_dmar_devscope(f): # parsing of DMAR ACPI Table # see Intel VT-d Spec chapter 8 -def parse_dmar(pcidevices, ioapics): +def parse_dmar(pcidevices, ioapics, dmar_regions): f = input_open('/sys/firmware/acpi/tables/DMAR', 'rb') signature = f.read(4) if signature != b'DMAR': @@ -729,7 +745,20 @@ def parse_dmar(pcidevices, ioapics): if len(units) >= 8: raise RuntimeError('Too many DMAR units. ' 'Raise JAILHOUSE_MAX_IOMMU_UNITS.') - units.append(base) + size = 0 + for r in dmar_regions: + if base == r.start: + size = r.size() + if size == 0: + raise RuntimeError('DMAR region size cannot be identified.\n' + 'Target Linux must run with Intel IOMMU ' + 'enabled.') + if size > 0x3000: + raise RuntimeError('Unexpectedly large DMAR region.') + units.append(IOMMUConfig({ + 'base_addr': base, + 'mmio_size': size + })) if flags & 1: for d in pcidevices: if d.iommu is None: @@ -825,19 +854,21 @@ def parse_ivrs(pcidevices, ioapics): regions = [] # BDF of devices that are permitted outside IOMMU: root complex iommu_skiplist = set([0x0]) + ivhd_blocks = 0 while length > 0: (block_type, block_length) = struct.unpack(' 1: + raise RuntimeError('Jailhouse doesn\'t support more than one ' + 'AMD IOMMU per PCI function.') # IVHD block - (iommu_id, base_addr, pci_seg) = \ - struct.unpack(' 0: @@ -908,9 +949,9 @@ def parse_ivrs(pcidevices, ioapics): elif type in [0x20, 0x21, 0x22]: # IVMD block + ivmd_fields = struct.unpack('