From af11ad7ad76f58d743cda370eaaed8ed810b05bb Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 18 Jul 2014 10:21:40 +0200 Subject: [PATCH] inmates: Add PCI demo using an Intel HDA This demonstrates the setup of a PCI device including MSI. Signed-off-by: Jan Kiszka --- configs/pci-demo.c | 81 +++++++++++++++++++++++++++++++++ inmates/demos/x86/Makefile | 7 ++- inmates/demos/x86/pci-demo.c | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 configs/pci-demo.c create mode 100644 inmates/demos/x86/pci-demo.c diff --git a/configs/pci-demo.c b/configs/pci-demo.c new file mode 100644 index 0000000..b0ca65f --- /dev/null +++ b/configs/pci-demo.c @@ -0,0 +1,81 @@ +/* + * 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 + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include + +#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, + }, + }, +}; diff --git a/inmates/demos/x86/Makefile b/inmates/demos/x86/Makefile index 7794b87..4e82d75 100644 --- a/inmates/demos/x86/Makefile +++ b/inmates/demos/x86/Makefile @@ -14,7 +14,8 @@ include $(INMATES_LIB)/Makefile.lib 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 @@ -31,4 +32,8 @@ $(eval $(call DECLARE_32_BIT,32-bit-demo)) 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))) diff --git a/inmates/demos/x86/pci-demo.c b/inmates/demos/x86/pci-demo.c new file mode 100644 index 0000000..195f154 --- /dev/null +++ b/inmates/demos/x86/pci-demo.c @@ -0,0 +1,86 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2014 + * + * Authors: + * Jan Kiszka + * + * 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 + +#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"); +} -- 2.39.2