This demonstrates the setup of a PCI device including MSI.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
--- /dev/null
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Minimal configuration for PCI demo inmate:
+ * 1 CPU, 1 MB RAM, 1 serial port, 1 Intel HDA PCI device
+ *
+ * Copyright (c) Siemens AG, 2014
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@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];
+} __attribute__((packed)) config = {
+ .cell = {
+ .name = "pci-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),
+ },
+
+ .cpus = {
+ 0x4,
+ },
+
+ .mem_regions = {
+ /* RAM */ {
+ .phys_start = 0x3be00000,
+ .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,
+ },
+ /* HDA BAR0 */ {
+ .phys_start = 0xfebf0000,
+ .virt_start = 0xfebf0000,
+ .size = 0x00004000,
+ .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE,
+ },
+ },
+
+ .pio_bitmap = {
+ [ 0/8 ... 0x2f7/8] = -1,
+ [ 0x2f8/8 ... 0x2ff/8] = 0, /* serial2 */
+ [ 0x300/8 ... 0xdfff/8] = -1,
+ [0xe000/8 ... 0xe007/8] = 0, /* OXPCIe952 serial2 */
+ [0xe008/8 ... 0xffff/8] = -1,
+ },
+
+ .pci_devices = {
+ { /* Intel HDA @00:1b.0 */
+ .type = JAILHOUSE_PCI_TYPE_DEVICE,
+ .domain = 0x0000,
+ .bus = 0x00,
+ .devfn = 0xd8,
+ },
+ },
+};
LIBDIR := ../../lib/x86
-INMATES := tiny-demo.bin apic-demo.bin ioapic-demo.bin 32-bit-demo.bin
+INMATES := tiny-demo.bin apic-demo.bin ioapic-demo.bin 32-bit-demo.bin \
+ pci-demo.bin
tiny-demo-y := tiny-demo.o \
$(LIBDIR)/header.o $(LIBDIR)/printk.o $(LIBDIR)/timing.o
32-bit-demo-y := 32-bit-demo.o \
$(LIBDIR)/header-32.o $(LIBDIR)/printk-32.o
+pci-demo-y := pci-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)))
--- /dev/null
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) Siemens AG, 2014
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ *
+ * Append "-device intel-hda,addr=1b.0 -device hda-output" to the QEMU command
+ * line for testing in the virtual machine. Adjust configs/pci-demo.c for real
+ * machines as needed.
+ */
+
+#include <inmate.h>
+
+#ifdef CONFIG_UART_OXPCIE952
+#define UART_BASE 0xe000
+#else
+#define UART_BASE 0x2f8
+#endif
+
+#define IRQ_VECTOR 32
+
+#define HDA_GCTL 0x08
+#define HDA_WAKEEN 0x0c
+#define HDA_STATESTS 0x0e
+#define HDA_INTCTL 0x20
+
+static void *hdbar;
+
+static void irq_handler(void)
+{
+ u16 statests = mmio_read16(hdbar + HDA_STATESTS);
+
+ printk("HDA MSI received (STATESTS: %04x)\n", statests);
+ mmio_write16(hdbar + HDA_STATESTS, statests);
+}
+
+void inmate_main(void)
+{
+ u64 bar;
+ int bdf;
+
+ printk_uart_base = UART_BASE;
+
+ int_init();
+ int_set_handler(IRQ_VECTOR, irq_handler);
+
+ bdf = pci_find_device(PCI_ID_ANY, PCI_ID_ANY);
+ if (bdf < 0) {
+ printk("No device found!\n");
+ return;
+ }
+ printk("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);
+
+ bar = pci_read_config(bdf, PCI_CFG_BAR, 4);
+ if ((bar & 0x6) == 0x4)
+ bar |= (u64)pci_read_config(bdf, PCI_CFG_BAR + 4, 4) << 32;
+ hdbar = (void *)(bar & ~0xfUL);
+ map_range(hdbar, PAGE_SIZE, MAP_UNCACHED);
+ printk("HDBAR at %p\n", hdbar);
+
+ pci_msi_set_vector(bdf, IRQ_VECTOR);
+
+ pci_write_config(bdf, PCI_CFG_COMMAND,
+ PCI_CMD_MEM | PCI_CMD_MASTER, 2);
+
+ asm volatile("sti");
+
+ mmio_write16(hdbar + HDA_GCTL, 0);
+ delay_us(7000);
+ mmio_write16(hdbar + HDA_GCTL, 1);
+
+ mmio_write16(hdbar + HDA_WAKEEN, 0x0f);
+ mmio_write32(hdbar + HDA_INTCTL, (1 << 31) | (1 << 30));
+
+ while (1)
+ asm volatile("hlt");
+}