]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
tools/configs: Describe PCI capabilities in config files
authorJan Kiszka <jan.kiszka@siemens.com>
Sun, 20 Jul 2014 09:45:37 +0000 (11:45 +0200)
committerJan Kiszka <jan.kiszka@siemens.com>
Mon, 28 Jul 2014 04:35:56 +0000 (06:35 +0200)
Instead of parsing the PCI config spaces in the hypervisor, offload this
to the configuration generator. It will produce a (logically) linked
list of capabilities per device, their ID, start and length. Each
capability can furthermore be marked as writable by the cell.

Note that identical capability lists shared between multiple devices
will automatically folded into a single one. The user can duplicate and
customize them individually in a manual post-processing step.

Configurations are updated for QEMU, the H87i and the pci-demo cell.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
configs/h87i.c
configs/pci-demo.c
configs/qemu-vm.c
hypervisor/include/jailhouse/cell-config.h
tools/jailhouse-config-create
tools/root-cell-config.c.tmpl

index 3aeb8418fb1fb9e9826880a211d670a7f3c95526..a9ba9a7ae4d951978bb408063bb3c0265f85cc37 100644 (file)
@@ -24,6 +24,7 @@ struct {
        struct jailhouse_irqchip irqchips[1];
        __u8 pio_bitmap[0x2000];
        struct jailhouse_pci_device pci_devices[13];
+       struct jailhouse_pci_capability pci_caps[27];
 } __attribute__((packed)) config = {
        .header = {
                .hypervisor_memory = {
@@ -45,6 +46,7 @@ struct {
                        .num_irqchips = ARRAY_SIZE(config.irqchips),
                        .pio_bitmap_size = ARRAY_SIZE(config.pio_bitmap),
                        .num_pci_devices = ARRAY_SIZE(config.pci_devices),
+                       .num_pci_caps = ARRAY_SIZE(config.pci_caps),
                },
        },
 
@@ -130,83 +132,299 @@ struct {
        },
 
        .pci_devices = {
+               /* PCIDevice: 00:00.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
-                       .devfn = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
+                       .devfn = 0x0,
+                       .caps_start = 0,
+                       .num_caps = 1,
                },
+               /* PCIDevice: 00:01.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_BRIDGE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
-                       .devfn = 0x08,
+                       .domain = 0x0,
+                       .bus = 0x0,
+                       .devfn = 0x8,
+                       .caps_start = 1,
+                       .num_caps = 4,
                },
+               /* PCIDevice: 00:02.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0x10,
+                       .caps_start = 5,
+                       .num_caps = 3,
                },
+               /* PCIDevice: 00:03.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0x18,
+                       .caps_start = 8,
+                       .num_caps = 3,
                },
+               /* PCIDevice: 00:14.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xa0,
+                       .caps_start = 11,
+                       .num_caps = 2,
                },
+               /* PCIDevice: 00:16.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xb0,
+                       .caps_start = 13,
+                       .num_caps = 2,
                },
+               /* PCIDevice: 00:19.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xc8,
+                       .caps_start = 15,
+                       .num_caps = 3,
                },
+               /* PCIDevice: 00:1a.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xd0,
+                       .caps_start = 18,
+                       .num_caps = 3,
                },
+               /* PCIDevice: 00:1b.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xd8,
+                       .caps_start = 21,
+                       .num_caps = 3,
                },
+               /* PCIDevice: 00:1d.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xe8,
+                       .caps_start = 18,
+                       .num_caps = 3,
                },
+               /* PCIDevice: 00:1f.0 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xf8,
+                       .caps_start = 0,
+                       .num_caps = 1,
                },
+               /* PCIDevice: 00:1f.2 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xfa,
+                       .caps_start = 24,
+                       .num_caps = 3,
                },
+               /* PCIDevice: 00:1f.3 */
                {
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
-                       .domain = 0x0000,
-                       .bus = 0x00,
+                       .domain = 0x0,
+                       .bus = 0x0,
                        .devfn = 0xfb,
+                       .caps_start = 0,
+                       .num_caps = 0,
+               },
+       },
+
+       .pci_caps = {
+               /* PCIDevice: 00:00.0 */
+               /* PCIDevice: 00:1f.0 */
+               {
+                       .id = 0x9,
+                       .start = 0xe0,
+                       .len = 2,
+                       .flags = 0,
+               },
+               /* PCIDevice: 00:01.0 */
+               {
+                       .id = 0xd,
+                       .start = 0x88,
+                       .len = 2,
+                       .flags = 0,
+               },
+               {
+                       .id = 0x1,
+                       .start = 0x80,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x5,
+                       .start = 0x90,
+                       .len = 10,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x10,
+                       .start = 0xa0,
+                       .len = 2,
+                       .flags = 0,
+               },
+               /* PCIDevice: 00:02.0 */
+               {
+                       .id = 0x5,
+                       .start = 0x90,
+                       .len = 10,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x1,
+                       .start = 0xd0,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x13,
+                       .start = 0xa4,
+                       .len = 2,
+                       .flags = 0,
+               },
+               /* PCIDevice: 00:03.0 */
+               {
+                       .id = 0x1,
+                       .start = 0x50,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x5,
+                       .start = 0x60,
+                       .len = 10,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x10,
+                       .start = 0x70,
+                       .len = 2,
+                       .flags = 0,
+               },
+               /* PCIDevice: 00:14.0 */
+               {
+                       .id = 0x1,
+                       .start = 0x70,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x5,
+                       .start = 0x80,
+                       .len = 14,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               /* PCIDevice: 00:16.0 */
+               {
+                       .id = 0x1,
+                       .start = 0x50,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x5,
+                       .start = 0x8c,
+                       .len = 14,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               /* PCIDevice: 00:19.0 */
+               {
+                       .id = 0x1,
+                       .start = 0xc8,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x5,
+                       .start = 0xd0,
+                       .len = 14,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x13,
+                       .start = 0xe0,
+                       .len = 2,
+                       .flags = 0,
+               },
+               /* PCIDevice: 00:1a.0 */
+               /* PCIDevice: 00:1d.0 */
+               {
+                       .id = 0x1,
+                       .start = 0x50,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0xa,
+                       .start = 0x58,
+                       .len = 2,
+                       .flags = 0,
+               },
+               {
+                       .id = 0x13,
+                       .start = 0x98,
+                       .len = 2,
+                       .flags = 0,
+               },
+               /* PCIDevice: 00:1b.0 */
+               {
+                       .id = 0x1,
+                       .start = 0x50,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x5,
+                       .start = 0x60,
+                       .len = 14,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x10,
+                       .start = 0x70,
+                       .len = 2,
+                       .flags = 0,
+               },
+               /* PCIDevice: 00:1f.2 */
+               {
+                       .id = 0x5,
+                       .start = 0x80,
+                       .len = 10,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x1,
+                       .start = 0x70,
+                       .len = 8,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               {
+                       .id = 0x12,
+                       .start = 0xa8,
+                       .len = 2,
+                       .flags = 0,
                },
        },
 };
index b0ca65f0a47f1ac613a945cd5e4c914ea2cccfae..2d20434be28d37600fa1f79af923e0ef89fc402e 100644 (file)
@@ -24,6 +24,7 @@ struct {
        struct jailhouse_memory mem_regions[3];
        __u8 pio_bitmap[0x2000];
        struct jailhouse_pci_device pci_devices[1];
+       struct jailhouse_pci_capability pci_caps[1];
 } __attribute__((packed)) config = {
        .cell = {
                .name = "pci-demo",
@@ -34,6 +35,7 @@ struct {
                .num_irqchips = 0,
                .pio_bitmap_size = ARRAY_SIZE(config.pio_bitmap),
                .num_pci_devices = ARRAY_SIZE(config.pci_devices),
+               .num_pci_caps = ARRAY_SIZE(config.pci_caps),
        },
 
        .cpus = {
@@ -76,6 +78,17 @@ struct {
                        .domain = 0x0000,
                        .bus = 0x00,
                        .devfn = 0xd8,
+                       .caps_start = 0,
+                       .num_caps = 1,
+               },
+       },
+
+       .pci_caps = {
+               { /* Intel HDA @00:1b.0 */
+                       .id = 0x5,
+                       .start = 0x50,
+                       .len = 14,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
                },
        },
 };
index e0201e65beaa0b04d611a6db885bee737380e03e..19cf503ea38169888248688647631a3540aea951 100644 (file)
@@ -28,6 +28,7 @@ struct {
        struct jailhouse_irqchip irqchips[1];
        __u8 pio_bitmap[0x2000];
        struct jailhouse_pci_device pci_devices[9];
+       struct jailhouse_pci_capability pci_caps[3];
 } __attribute__((packed)) config = {
        .header = {
                .hypervisor_memory = {
@@ -49,6 +50,7 @@ struct {
                        .num_irqchips = ARRAY_SIZE(config.irqchips),
                        .pio_bitmap_size = ARRAY_SIZE(config.pio_bitmap),
                        .num_pci_devices = ARRAY_SIZE(config.pci_devices),
+                       .num_pci_caps = ARRAY_SIZE(config.pci_caps),
                },
        },
 
@@ -150,12 +152,16 @@ struct {
                        .domain = 0x0000,
                        .bus = 0x00,
                        .devfn = 0x18,
+                       .caps_start = 0, /* for q35 */
+                       .num_caps = 1,
                },
                { /* 440fx: virtio-9p-pci */
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
                        .domain = 0x0000,
                        .bus = 0x00,
                        .devfn = 0x20,
+                       .caps_start = 0,
+                       .num_caps = 1,
                },
                { /* q35: ISA bridge */
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
@@ -168,6 +174,8 @@ struct {
                        .domain = 0x0000,
                        .bus = 0x00,
                        .devfn = 0xfa,
+                       .caps_start = 2,
+                       .num_caps = 2,
                },
                { /* q35: SMBus */
                        .type = JAILHOUSE_PCI_TYPE_DEVICE,
@@ -176,4 +184,25 @@ struct {
                        .devfn = 0xfb,
                },
        },
+
+       .pci_caps = {
+               { /* virtio-9p-pci */
+                       .id = 0x11,
+                       .start = 0x40,
+                       .len = 12,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+               { /* AHCI */
+                       .id = 0x12,
+                       .start = 0xa8,
+                       .len = 2,
+                       .flags = 0,
+               },
+               {
+                       .id = 0x5,
+                       .start = 0x50,
+                       .len = 14,
+                       .flags = JAILHOUSE_PCICAPS_WRITE,
+               },
+       },
 };
index 7cfaadaebc35f05d22e9ccb55537abd6baff8636..41dde1d06a6df34f734e3e493aeae899c3fe36fb 100644 (file)
@@ -26,6 +26,7 @@ struct jailhouse_cell_desc {
        __u32 num_irqchips;
        __u32 pio_bitmap_size;
        __u32 num_pci_devices;
+       __u32 num_pci_caps;
 } __attribute__((packed));
 
 #define JAILHOUSE_MEM_READ             0x0001
@@ -63,6 +64,17 @@ struct jailhouse_pci_device {
        __u16 domain;
        __u8 bus;
        __u8 devfn;
+       __u16 caps_start;
+       __u16 num_caps;
+} __attribute__((packed));
+
+#define JAILHOUSE_PCICAPS_WRITE                0x0001
+
+struct jailhouse_pci_capability {
+       __u16 id;
+       __u16 start;
+       __u16 len;
+       __u16 flags;
 } __attribute__((packed));
 
 struct jailhouse_system {
@@ -84,7 +96,8 @@ jailhouse_cell_config_size(struct jailhouse_cell_desc *cell)
                cell->num_memory_regions * sizeof(struct jailhouse_memory) +
                cell->num_irqchips * sizeof(struct jailhouse_irqchip) +
                cell->pio_bitmap_size +
-               cell->num_pci_devices * sizeof(struct jailhouse_pci_device);
+               cell->num_pci_devices * sizeof(struct jailhouse_pci_device) +
+               cell->num_pci_caps * sizeof(struct jailhouse_pci_capability);
 }
 
 static inline __u32
@@ -131,4 +144,12 @@ jailhouse_cell_pci_devices(const struct jailhouse_cell_desc *cell)
                 cell->pio_bitmap_size);
 }
 
+static inline const struct jailhouse_pci_capability *
+jailhouse_cell_pci_caps(const struct jailhouse_cell_desc *cell)
+{
+       return (const struct jailhouse_pci_capability *)
+               ((void *)jailhouse_cell_pci_devices(cell) +
+                cell->num_pci_devices * sizeof(struct jailhouse_pci_device));
+}
+
 #endif /* !_JAILHOUSE_CELL_CONFIG_H */
index 4a26c086b2910fa4d47f227094183b3c442d3f95..5f8fbbb29e60200a5f5486ab1085cf32e0103153 100755 (executable)
@@ -56,13 +56,73 @@ options = parser.parse_args()
 inputs = {'files': set(), 'files_opt': set(), 'dirs': set()}
 
 
+class PCICapability:
+    def __init__(self, id, start, len, flags):
+        self.id = id
+        self.start = start
+        self.len = len
+        self.flags = flags
+        self.comments = []
+
+    def __eq__(self, other):
+        return self.id == other.id and self.start == other.start and \
+            self.len == other.len and self.flags == other.flags
+
+    RD = '0'
+    RW = 'JAILHOUSE_PCICAPS_WRITE'
+
+    @staticmethod
+    def parse_pcicaps(dir):
+        caps = []
+        f = input_open(dir + '/config', 'rb')
+        f.seek(0x06)
+        (status,) = struct.unpack('<H', f.read(2))
+        # capability list supported?
+        if (status & (1 << 4)) == 0:
+            f.close()
+            return caps
+        # walk capability list
+        f.seek(0x34)
+        (next,) = struct.unpack('B', f.read(1))
+        while next != 0:
+            cap = next
+            f.seek(cap)
+            (id, next) = struct.unpack('<BB', f.read(2))
+            if id == 0x01:  # Power Management
+                # this cap can be handed out completely
+                len = 8
+                flags = PCICapability.RW
+            elif id == 0x05:  # MSI
+                # access will be moderated by hypervisor
+                len = 10
+                (msgctl,) = struct.unpack('<H', f.read(2))
+                if (msgctl & (1 << 7)) != 0:  # 64-bit support
+                    len += 4
+                if (msgctl & (1 << 8)) != 0:  # per-vector masking support
+                    len += 10
+                flags = PCICapability.RW
+            elif id == 0x11:  # MSI-X
+                # access will be moderated by hypervisor
+                len = 12
+                flags = PCICapability.RW
+            else:
+                # unknown/unhandled cap, mark its existence
+                len = 2
+                flags = PCICapability.RD
+            caps.append(PCICapability(id, cap, len, flags))
+        return caps
+
+
 class PCIDevice:
-    def __init__(self, type, domain, bus, dev, fn):
+    def __init__(self, type, domain, bus, dev, fn, caps):
         self.type = type
         self.domain = domain
         self.bus = bus
         self.dev = dev
         self.fn = fn
+        self.caps = caps
+        self.caps_start = 0
+        self.num_caps = 0
 
     def __str__(self):
         return 'PCIDevice: %02x:%02x.%x' % (self.bus, self.dev, self.fn)
@@ -72,7 +132,8 @@ class PCIDevice:
 
     @staticmethod
     def parse_pcidevice_sysfsdir(basedir, dir):
-        dclass = input_readline(basedir + '/' + dir + '/class')
+        dpath = basedir + '/' + dir
+        dclass = input_readline(dpath + '/class')
         if re.match(r'0x0604..', dclass):
             type = 'JAILHOUSE_PCI_TYPE_BRIDGE'
         else:
@@ -81,7 +142,9 @@ class PCIDevice:
         domain = int(a[0], 16)
         bus = int(a[1], 16)
         df = a[2].split('.')
-        return PCIDevice(type, domain, bus, int(df[0], 16), int(df[1], 16))
+        caps = PCICapability.parse_pcicaps(dpath)
+        return PCIDevice(type, domain, bus, int(df[0], 16), int(df[1], 16),
+                         caps)
 
 
 class MemRegion:
@@ -161,13 +224,30 @@ def parse_iomem():
 
 def parse_pcidevices():
     devices = []
+    caps = []
     basedir = '/sys/bus/pci/devices'
-    list = input_listdir(basedir, ['*/class'])
+    list = input_listdir(basedir, ['*/class', '*/config'])
     for dir in list:
         d = PCIDevice.parse_pcidevice_sysfsdir(basedir, dir)
         if d is not None:
+            if len(d.caps) > 0:
+                duplicate = False
+                # look for duplicate capability patterns
+                for d2 in devices:
+                    if d2.caps == d.caps:
+                        # reused existing capability list, but record all users
+                        d2.caps[0].comments.append(str(d))
+                        d.caps_start = d2.caps_start
+                        d.num_caps = d2.num_caps
+                        duplicate = True
+                        break
+                if not duplicate:
+                    d.caps[0].comments.append(str(d))
+                    d.caps_start = len(caps)
+                    d.num_caps = len(d.caps)
+                    caps.extend(d.caps)
             devices.append(d)
-    return devices
+    return (devices, caps)
 
 
 def kmg_multiply(value, kmg):
@@ -332,7 +412,7 @@ def parse_ioports():
     return pm_timer_base
 
 
-pcidevices = parse_pcidevices()
+(pcidevices, pcicaps) = parse_pcidevices()
 
 product = [input_readline('/sys/class/dmi/id/sys_vendor',
                           True).rstrip(),
@@ -400,6 +480,7 @@ else:
                         confmem=confmem,
                         product=product,
                         pcidevices=pcidevices,
+                        pcicaps=pcicaps,
                         cpucount=cpucount,
                         ioapic_id=ioapic_id,
                         pm_timer_base=pm_timer_base))
index 455da63f1986b4bdbb1d5f734264d4b0fee7afb3..952f0f77e9e78808866d9f2151969abe0b835bc4 100644 (file)
@@ -25,6 +25,7 @@ struct {
        struct jailhouse_irqchip irqchips[1];
        __u8 pio_bitmap[0x2000];
        struct jailhouse_pci_device pci_devices[${len(pcidevices)}];
+       struct jailhouse_pci_capability pci_caps[${len(pcicaps)}];
 } __attribute__((packed)) config = {
        .header = {
                .hypervisor_memory = {
@@ -45,6 +46,7 @@ struct {
                        .num_irqchips = ARRAY_SIZE(config.irqchips),
                        .pio_bitmap_size = ARRAY_SIZE(config.pio_bitmap),
                        .num_pci_devices = ARRAY_SIZE(config.pci_devices),
+                       .num_pci_caps = ARRAY_SIZE(config.pci_caps),
                },
        },
 
@@ -101,6 +103,22 @@ struct {
                        .domain = ${hex(d.domain)},
                        .bus = ${hex(d.bus)},
                        .devfn = ${hex(d.devfn())},
+                       .caps_start = ${d.caps_start},
+                       .num_caps = ${d.num_caps},
+               },
+               % endfor
+       },
+
+       .pci_caps = {
+               % for c in pcicaps:
+               % for comment in c.comments:
+               /* ${comment} */
+               % endfor
+               {
+                       .id = ${hex(c.id)},
+                       .start = ${hex(c.start)},
+                       .len = ${c.len},
+                       .flags = ${c.flags},
                },
                % endfor
        },