On x86, we unfortunately need to parse the guest instruction that triggered an MMIO access interception. This parser started to be small and simple - and then real life bit. It already passed the point where we should have added systematic tests.
This is the hypervisor-located building block for such tests. The test creates a MMIO target page right after the Communication Page. Write accesses to the virtual registers 0xff8..0xfff are stored per cell, read accesses reproduce that written value. The virtual registers are backed by the Communication Page of the same cell at the same address, thus create a second channel to validate accesses. This test device is optional, configured in during build time by setting CONFIG_TEST_DEVICE in config.h and during runtime by adding JAILHOUSE_CELL_TEST_DEVICE to the cell's config flags. Signed-off-by: Jan Kiszka <[email protected]> --- Changes in v2: - include range check simplification as suggested by Henning hypervisor/arch/x86/Kbuild | 4 +- hypervisor/arch/x86/test-device.c | 104 ++++++++++++++++++++++++++++++++++++++ include/jailhouse/cell-config.h | 1 + 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 hypervisor/arch/x86/test-device.c diff --git a/hypervisor/arch/x86/Kbuild b/hypervisor/arch/x86/Kbuild index 476f9c1cc..8ab8d5636 100644 --- a/hypervisor/arch/x86/Kbuild +++ b/hypervisor/arch/x86/Kbuild @@ -26,9 +26,11 @@ common-objs-y := apic.o dbg-write.o entry.o setup.o control.o mmio.o iommu.o \ paging.o pci.o i8042.o vcpu.o vga.o ivshmem.o # units initialization order as defined by linking order: -# iommu, ioapic, [cat], <generic units> +# iommu, ioapic, [test-device], [cat], <generic units> common-objs-y += ioapic.o +common-objs-$(CONFIG_TEST_DEVICE) += test-device.o + built-in-amd-y := svm.o amd_iommu.o svm-vmexit.o $(common-objs-y) built-in-intel-y := vmx.o vtd.o vmx-vmexit.o $(common-objs-y) cat.o diff --git a/hypervisor/arch/x86/test-device.c b/hypervisor/arch/x86/test-device.c new file mode 100644 index 000000000..1ce8eda19 --- /dev/null +++ b/hypervisor/arch/x86/test-device.c @@ -0,0 +1,104 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Siemens AG, 2018 + * + * Authors: + * Jan Kiszka <[email protected]> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include <jailhouse/control.h> +#include <jailhouse/mmio.h> +#include <jailhouse/printk.h> +#include <jailhouse/unit.h> + +static unsigned int testdev_mmio_count_regions(struct cell *cell) +{ + return cell->config->flags & JAILHOUSE_CELL_TEST_DEVICE ? 1 : 0; +} + +static enum mmio_result testdev_handle_mmio_access(void *arg, + struct mmio_access *mmio) +{ + void *test_reg = &this_cell()->comm_page.padding[mmio->address]; + + if (mmio->address < 0xff8 || mmio->address > 0x1000 - mmio->size) + goto invalid_access; + + switch (mmio->size) { + case 1: + if (mmio->is_write) + *(u8 *)test_reg = mmio->value; + else + mmio->value = *(u8 *)test_reg; + break; + case 2: + if (mmio->is_write) + *(u16 *)test_reg = mmio->value; + else + mmio->value = *(u16 *)test_reg; + break; + case 4: + if (mmio->is_write) + *(u32 *)test_reg = mmio->value; + else + mmio->value = *(u32 *)test_reg; + break; + case 8: + if (mmio->is_write) + *(u64 *)test_reg = mmio->value; + else + mmio->value = *(u64 *)test_reg; + break; + } + return MMIO_HANDLED; + +invalid_access: + printk("testdev: invalid %s, register %lx, size %d\n", + mmio->is_write ? "write" : "read", mmio->address, mmio->size); + return MMIO_ERROR; +} + +static unsigned long testdev_get_mmio_base(struct cell *cell) +{ + const struct jailhouse_memory *mem; + unsigned int n; + + for_each_mem_region(mem, cell->config, n) + if (mem->flags & JAILHOUSE_MEM_COMM_REGION) + return mem->virt_start + PAGE_SIZE; + + return INVALID_PHYS_ADDR; +} + +static int testdev_cell_init(struct cell *cell) +{ + unsigned long comm_base; + + if (cell->config->flags & JAILHOUSE_CELL_TEST_DEVICE) { + comm_base = testdev_get_mmio_base(cell); + if (comm_base == INVALID_PHYS_ADDR) + return trace_error(-EINVAL); + + mmio_region_register(cell, comm_base, PAGE_SIZE, + testdev_handle_mmio_access, NULL); + } + return 0; +} + +static void testdev_cell_exit(struct cell *cell) +{ + if (cell->config->flags & JAILHOUSE_CELL_TEST_DEVICE) + mmio_region_unregister(cell, testdev_get_mmio_base(cell)); +} + +static int testdev_init(void) +{ + return 0; +} + +DEFINE_UNIT_SHUTDOWN_STUB(testdev); +DEFINE_UNIT(testdev, "Test device"); diff --git a/include/jailhouse/cell-config.h b/include/jailhouse/cell-config.h index 15ed7cdd5..1d0ae2e59 100644 --- a/include/jailhouse/cell-config.h +++ b/include/jailhouse/cell-config.h @@ -49,6 +49,7 @@ #define JAILHOUSE_CELL_PASSIVE_COMMREG 0x00000001 #define JAILHOUSE_CELL_DEBUG_CONSOLE 0x00000002 +#define JAILHOUSE_CELL_TEST_DEVICE 0x00000004 #define JAILHOUSE_CELL_DESC_SIGNATURE "JHCELL" -- 2.13.6 -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
