]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
inmates, configs: add ivshmem virtual PCI device demo code and config
authorHenning Schild <henning.schild@siemens.com>
Mon, 24 Nov 2014 17:54:17 +0000 (18:54 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Wed, 26 Nov 2014 21:04:00 +0000 (22:04 +0100)
New demo to demonstrate ivshmem virtual PCI devices for shared memory
inter-cell communication.

Signed-off-by: Henning Schild <henning.schild@siemens.com>
[Jan: adjusted region location]
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
configs/ivshmem-demo.c [new file with mode: 0644]
inmates/demos/x86/Makefile
inmates/demos/x86/ivshmem-demo.c [new file with mode: 0644]

diff --git a/configs/ivshmem-demo.c b/configs/ivshmem-demo.c
new file mode 100644 (file)
index 0000000..29dab4a
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) Siemens AG, 2013, 2014
+ *
+ * Authors:
+ *  Henning Schild <henning.schild@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <linux/types.h>
+#include <jailhouse/cell-config.h>
+
+#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
+
+struct {
+       struct jailhouse_cell_desc cell;
+       __u64 cpus[1];
+       struct jailhouse_memory mem_regions[3];
+       __u8 pio_bitmap[0x2000];
+       struct jailhouse_pci_device pci_devices[1];
+       struct jailhouse_pci_capability pci_caps[0];
+} __attribute__((packed)) config = {
+       .cell = {
+               .name = "ivshmem-demo",
+               .flags = JAILHOUSE_CELL_PASSIVE_COMMREG,
+
+               .cpu_set_size = sizeof(config.cpus),
+               .num_memory_regions = ARRAY_SIZE(config.mem_regions),
+               .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 = {
+               0b0100,
+       },
+
+       .mem_regions = {
+               /* RAM */ {
+                       .phys_start = 0x3f000000,
+                       .virt_start = 0,
+                       .size = 0x00100000,
+                       .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE |
+                               JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE,
+               },
+               /* communication region */ {
+                       .virt_start = 0x00100000,
+                       .size = 0x00001000,
+                       .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE |
+                               JAILHOUSE_MEM_COMM_REGION,
+               },
+               /* IVSHMEM shared memory region */
+               {
+                       .phys_start = 0x3f1ff000,
+                       .virt_start = 0x3f1ff000,
+                       .size = 0x1000,
+                       .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE |
+                               JAILHOUSE_MEM_ROOTSHARED,
+               },
+       },
+
+       .pio_bitmap = {
+               [     0/8 ...  0x3f7/8] = -1,
+               [ 0x3f8/8 ...  0x3ff/8] = 0, /* serial1 */
+               [ 0x400/8 ... 0xffff/8] = -1,
+       },
+
+       .pci_devices = {
+               {
+                       .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
+                       .domain = 0x0,
+                       .bdf = (0x0f<<3),
+                       .shmem_region = 2,
+                       .num_msix_vectors = 1,
+               },
+       },
+};
index 06f6bfd0fbdd40c1a1ad7d89d9bffd9a5d421165..2a96bd9848485c658cc9bef79d4fa20bc42fa286 100644 (file)
@@ -15,7 +15,7 @@ include $(INMATES_LIB)/Makefile.lib
 LIBDIR := ../../lib/x86
 
 INMATES := tiny-demo.bin apic-demo.bin ioapic-demo.bin 32-bit-demo.bin \
-       pci-demo.bin e1000-demo.bin
+       pci-demo.bin e1000-demo.bin ivshmem-demo.bin
 
 tiny-demo-y := tiny-demo.o \
        $(LIBDIR)/header.o $(LIBDIR)/printk.o $(LIBDIR)/timing.o
@@ -40,4 +40,8 @@ e1000-demo-y := e1000-demo.o \
        $(LIBDIR)/header.o $(LIBDIR)/printk.o $(LIBDIR)/mem.o \
        $(LIBDIR)/pci.o $(LIBDIR)/timing.o
 
+ivshmem-demo-y := ivshmem-demo.o \
+       $(LIBDIR)/header.o $(LIBDIR)/printk.o $(LIBDIR)/mem.o \
+       $(LIBDIR)/int.o $(LIBDIR)/pci.o $(LIBDIR)/timing.o
+
 $(eval $(call DECLARE_TARGETS,$(INMATES)))
diff --git a/inmates/demos/x86/ivshmem-demo.c b/inmates/demos/x86/ivshmem-demo.c
new file mode 100644 (file)
index 0000000..fe3c380
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) Siemens AG, 2014
+ *
+ * Authors:
+ *  Henning Schild <henning.schild@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+#include <inmate.h>
+
+#define VENDORID       0x1af4
+#define DEVICEID       0x1110
+
+#define IVSHMEM_CFG_SHMEM_PTR  0x40
+#define IVSHMEM_CFG_SHMEM_SZ   0x48
+
+#define IRQ_VECTOR     32
+
+#define MAX_NDEV       4
+#define UART_BASE      0x3F8
+
+static char str[32] = "Hello From IVSHMEM  ";
+static int ndevices;
+static int irq_counter;
+
+struct ivshmem_dev_data {
+       u16 bdf;
+       u32 *registers;
+       void *shmem;
+       u32 *msix_table;
+       u64 shmemsz;
+       u64 bar2sz;
+};
+
+static struct ivshmem_dev_data devs[MAX_NDEV];
+
+static u64 pci_cfg_read64(u16 bdf, unsigned int addr)
+{
+       u64 bar;
+
+       bar = ((u64)pci_read_config(bdf, addr + 4, 4) << 32) |
+             pci_read_config(bdf, addr, 4);
+       return bar;
+}
+
+static void pci_cfg_write64(u16 bdf, unsigned int addr, u64 val)
+{
+       pci_write_config(bdf, addr + 4, (u32)(val >> 32), 4);
+       pci_write_config(bdf, addr, (u32)val, 4);
+}
+
+static u64 get_bar_sz(u16 bdf, u8 barn)
+{
+       u64 bar, tmp;
+       u64 barsz;
+
+       bar = pci_cfg_read64(bdf, PCI_CFG_BAR + (8 * barn));
+       pci_cfg_write64(bdf, PCI_CFG_BAR + (8 * barn), 0xffffffffffffffff);
+       tmp = pci_cfg_read64(bdf, PCI_CFG_BAR + (8 * barn));
+       barsz = ~(tmp & ~(0xf)) + 1;
+       pci_cfg_write64(bdf, PCI_CFG_BAR + (8 * barn), bar);
+
+       return barsz;
+}
+
+static void map_shmem_and_bars(struct ivshmem_dev_data *d)
+{
+       int cap = pci_find_cap(d->bdf, PCI_CAP_MSIX);
+
+       if (cap < 0) {
+               printk("IVSHMEM ERROR: device is not MSI-X capable\n");
+               return;
+       }
+
+       d->shmemsz = pci_cfg_read64(d->bdf, IVSHMEM_CFG_SHMEM_SZ);
+       d->shmem = (void *)pci_cfg_read64(d->bdf, IVSHMEM_CFG_SHMEM_PTR);
+
+       printk("IVSHMEM: shmem is at %p\n", d->shmem);
+       d->registers = (u32 *)((u64)(d->shmem + d->shmemsz + PAGE_SIZE - 1)
+               & PAGE_MASK);
+       pci_cfg_write64(d->bdf, PCI_CFG_BAR, (u64)d->registers);
+       printk("IVSHMEM: bar0 is at %p\n", d->registers);
+       d->bar2sz = get_bar_sz(d->bdf, 2);
+       d->msix_table = (u32 *)((u64)d->registers + PAGE_SIZE);
+       pci_cfg_write64(d->bdf, PCI_CFG_BAR + 16, (u64)d->msix_table);
+       printk("IVSHMEM: bar2 is at %p\n", d->msix_table);
+
+       pci_write_config(d->bdf, PCI_CFG_COMMAND,
+                        (PCI_CMD_MEM | PCI_CMD_MASTER), 2);
+       map_range(d->shmem, d->shmemsz + PAGE_SIZE + d->bar2sz, MAP_UNCACHED);
+}
+
+static int get_ivpos(struct ivshmem_dev_data *d)
+{
+       return mmio_read32(d->registers + 2);
+}
+
+static void send_irq(struct ivshmem_dev_data *d)
+{
+       printk("IVSHMEM: %02x:%02x.%x sending IRQ\n",
+              d->bdf >> 8, (d->bdf >> 3) & 0x1f, d->bdf & 0x3);
+       mmio_write32(d->registers + 3, 1);
+}
+
+static void irq_handler(void)
+{
+       printk("IVSHMEM: got interrupt ... %d\n", irq_counter++);
+}
+
+void inmate_main(void)
+{
+       int i;
+       int bdf = 0;
+       struct ivshmem_dev_data *d;
+       volatile char *shmem;
+
+       printk_uart_base = UART_BASE;
+
+       pm_timer_init();
+       int_init();
+
+again:
+       bdf = pci_find_device(VENDORID, DEVICEID, bdf);
+       if (bdf != -1) {
+               printk("IVSHMEM: Found %04x:%04x at %02x:%02x.%x\n",
+                      pci_read_config(bdf, PCI_CFG_VENDOR_ID, 2),
+                      pci_read_config(bdf, PCI_CFG_DEVICE_ID, 2),
+                      bdf >> 8, (bdf >> 3) & 0x1f, bdf & 0x3);
+
+               ndevices++;
+               d = devs + ndevices - 1;
+               d->bdf = bdf;
+               map_shmem_and_bars(d);
+               printk("IVSHMEM: mapped the bars got position %d\n",
+                       get_ivpos(d));
+
+               memcpy(d->shmem, str, 32);
+
+               int_set_handler(IRQ_VECTOR + ndevices - 1, irq_handler);
+               pci_msix_set_vector(bdf, IRQ_VECTOR + ndevices - 1, 0);
+               bdf++;
+               if (ndevices < MAX_NDEV)
+                       goto again;
+       }
+
+       if (!ndevices) {
+               printk("IVSHMEM: No PCI devices found .. nothing to do.\n");
+               goto out;
+       }
+
+       asm volatile("sti");
+       while (1) {
+               for (i = 0; i < ndevices; i++) {
+                       d = devs + i;
+                       delay_us(1000*1000);
+                       shmem = d->shmem;
+                       shmem[19]++;
+                       send_irq(d);
+               }
+       }
+out:
+       asm volatile("hlt");
+}