From e8ba1ce92d8cbc4e77efcaf040077d3901098e5f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Dec 2012 15:43:35 +0100 Subject: [PATCH 1/4] switch debugcon to memory api Also some QOM glue while being at it. Signed-off-by: Gerd Hoffmann --- hw/debugcon.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/hw/debugcon.c b/hw/debugcon.c index 14f83f1962..e8a855e33a 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -29,20 +29,27 @@ #include "isa.h" #include "pc.h" +#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" +#define ISA_DEBUGCON_DEVICE(obj) \ + OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE) + //#define DEBUG_DEBUGCON typedef struct DebugconState { + MemoryRegion io; CharDriverState *chr; uint32_t readback; } DebugconState; typedef struct ISADebugconState { - ISADevice dev; + ISADevice parent_obj; + uint32_t iobase; DebugconState state; } ISADebugconState; -static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) { DebugconState *s = opaque; unsigned char ch = val; @@ -55,7 +62,7 @@ static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val) } -static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr) +static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width) { DebugconState *s = opaque; @@ -66,6 +73,14 @@ static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr) return s->readback; } +static const MemoryRegionOps debugcon_ops = { + .read = debugcon_ioport_read, + .write = debugcon_ioport_write, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static void debugcon_init_core(DebugconState *s) { if (!s->chr) { @@ -78,12 +93,14 @@ static void debugcon_init_core(DebugconState *s) static int debugcon_isa_initfn(ISADevice *dev) { - ISADebugconState *isa = DO_UPCAST(ISADebugconState, dev, dev); + ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev); DebugconState *s = &isa->state; debugcon_init_core(s); - register_ioport_write(isa->iobase, 1, 1, debugcon_ioport_write, s); - register_ioport_read(isa->iobase, 1, 1, debugcon_ioport_read, s); + memory_region_init_io(&s->io, &debugcon_ops, s, + TYPE_ISA_DEBUGCON_DEVICE, 1); + memory_region_add_subregion(isa_address_space_io(dev), + isa->iobase, &s->io); return 0; } @@ -103,7 +120,7 @@ static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) } static TypeInfo debugcon_isa_info = { - .name = "isa-debugcon", + .name = TYPE_ISA_DEBUGCON_DEVICE, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISADebugconState), .class_init = debugcon_isa_class_initfn, From bb355b1859dde19fbb4f856c6d0b8f46733142d7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 12 Dec 2012 15:54:59 +0100 Subject: [PATCH 2/4] add isa-debug-exit device. When present it makes qemu exit on any write. Mapped to port 0x501 by default. Without this patch Anthony doesn't allow me to remove the bochs bios debug ports because his test suite uses this. Signed-off-by: Gerd Hoffmann --- hw/debugexit.c | 75 +++++++++++++++++++++++++++++++++++++++++++ hw/i386/Makefile.objs | 2 +- 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 hw/debugexit.c diff --git a/hw/debugexit.c b/hw/debugexit.c new file mode 100644 index 0000000000..90642eb37f --- /dev/null +++ b/hw/debugexit.c @@ -0,0 +1,75 @@ +/* + * debug exit port emulation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + */ + +#include "hw.h" +#include "isa.h" + +#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit" +#define ISA_DEBUG_EXIT_DEVICE(obj) \ + OBJECT_CHECK(ISADebugExitState, (obj), TYPE_ISA_DEBUG_EXIT_DEVICE) + +typedef struct ISADebugExitState { + ISADevice parent_obj; + + uint32_t iobase; + uint32_t iosize; + MemoryRegion io; +} ISADebugExitState; + +static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val, + unsigned width) +{ + exit((val << 1) | 1); +} + +static const MemoryRegionOps debug_exit_ops = { + .write = debug_exit_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int debug_exit_initfn(ISADevice *dev) +{ + ISADebugExitState *isa = ISA_DEBUG_EXIT_DEVICE(dev); + + memory_region_init_io(&isa->io, &debug_exit_ops, isa, + TYPE_ISA_DEBUG_EXIT_DEVICE, isa->iosize); + memory_region_add_subregion(isa_address_space_io(dev), + isa->iobase, &isa->io); + return 0; +} + +static Property debug_exit_properties[] = { + DEFINE_PROP_HEX32("iobase", ISADebugExitState, iobase, 0x501), + DEFINE_PROP_HEX32("iosize", ISADebugExitState, iosize, 0x02), + DEFINE_PROP_END_OF_LIST(), +}; + +static void debug_exit_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = debug_exit_initfn; + dc->props = debug_exit_properties; +} + +static TypeInfo debug_exit_info = { + .name = TYPE_ISA_DEBUG_EXIT_DEVICE, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISADebugExitState), + .class_init = debug_exit_class_initfn, +}; + +static void debug_exit_register_types(void) +{ + type_register_static(&debug_exit_info); +} + +type_init(debug_exit_register_types) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 257f3c1a91..2ba04db0a8 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -3,7 +3,7 @@ obj-y += apic_common.o apic.o kvmvapic.o obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o obj-y += vmport.o obj-y += pci/pci-hotplug.o smbios.o wdt_ib700.o -obj-y += debugcon.o multiboot.o +obj-y += debugcon.o debugexit.o multiboot.o obj-y += pc_piix.o obj-y += pc_sysfw.o obj-y += lpc_ich9.o q35.o pc_q35.o From ee0cc5415e6edc043bd84e855f7d0bf85bd97547 Mon Sep 17 00:00:00 2001 From: Lucas Meneghel Rodrigues Date: Thu, 13 Dec 2012 12:48:53 -0200 Subject: [PATCH 3/4] hw: Add test device for unittests execution Add a test device which supports the kvmctl ioports, so one can run the KVM unittest suite. Intended Usage: qemu-system-x86_64 -nographic \ -device pc-testdev \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ -kernel /path/to/kvm/unittests/msr.flat Where msr.flat is one of the KVM unittests, present on a separate repo, git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git [ kraxel: more memory api + qom fixes ] CC: Paolo Bonzini Signed-off-by: Alexander Graf Signed-off-by: Marcelo Tosatti Signed-off-by: Lucas Meneghel Rodrigues Signed-off-by: Gerd Hoffmann --- hw/i386/Makefile.objs | 1 + hw/pc-testdev.c | 182 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 hw/pc-testdev.c diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 2ba04db0a8..025803aa66 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -12,5 +12,6 @@ obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o obj-y += kvm/ obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o +obj-y += pc-testdev.o obj-y := $(addprefix ../,$(obj-y)) diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c new file mode 100644 index 0000000000..620c86c92a --- /dev/null +++ b/hw/pc-testdev.c @@ -0,0 +1,182 @@ +/* + * QEMU x86 ISA testdev + * + * Copyright (c) 2012 Avi Kivity, Gerd Hoffmann, Marcelo Tosatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * This device is used to test KVM features specific to the x86 port, such + * as emulation, power management, interrupt routing, among others. It's meant + * to be used like: + * + * qemu-system-x86_64 -device pc-testdev -serial stdio \ + * -device isa-debug-exit,iobase=0xf4,iosize=0x4 \ + * -kernel /home/lmr/Code/virt-test.git/kvm/unittests/msr.flat + * + * Where msr.flat is one of the KVM unittests, present on a separate repo, + * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git +*/ + +#include +#include "hw.h" +#include "qdev.h" +#include "isa.h" + +#define IOMEM_LEN 0x10000 + +typedef struct PCTestdev { + ISADevice parent_obj; + + MemoryRegion ioport; + MemoryRegion flush; + MemoryRegion irq; + MemoryRegion iomem; + uint32_t ioport_data; + char iomem_buf[IOMEM_LEN]; +} PCTestdev; + +#define TYPE_TESTDEV "pc-testdev" +#define TESTDEV(obj) \ + OBJECT_CHECK(struct PCTestdev, (obj), TYPE_TESTDEV) + +static void test_irq_line(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + struct PCTestdev *dev = opaque; + struct ISADevice *isa = ISA_DEVICE(dev); + + qemu_set_irq(isa_get_irq(isa, addr), !!data); +} + +static const MemoryRegionOps test_irq_ops = { + .write = test_irq_line, + .valid.min_access_size = 1, + .valid.max_access_size = 1, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + struct PCTestdev *dev = opaque; + dev->ioport_data = data; +} + +static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len) +{ + struct PCTestdev *dev = opaque; + return dev->ioport_data; +} + +static const MemoryRegionOps test_ioport_ops = { + .read = test_ioport_read, + .write = test_ioport_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void test_flush_page(void *opaque, hwaddr addr, uint64_t data, + unsigned len) +{ + hwaddr page = 4096; + void *a = cpu_physical_memory_map(data & ~0xffful, &page, 0); + + /* We might not be able to get the full page, only mprotect what we actually + have mapped */ + mprotect(a, page, PROT_NONE); + mprotect(a, page, PROT_READ|PROT_WRITE); + cpu_physical_memory_unmap(a, page, 0, 0); +} + +static const MemoryRegionOps test_flush_ops = { + .write = test_flush_page, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len) +{ + struct PCTestdev *dev = opaque; + uint64_t ret = 0; + memcpy(&ret, &dev->iomem_buf[addr], len); + ret = le64_to_cpu(ret); + + return ret; +} + +static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) +{ + struct PCTestdev *dev = opaque; + val = cpu_to_le64(val); + memcpy(&dev->iomem_buf[addr], &val, len); + dev->iomem_buf[addr] = val; +} + +static const MemoryRegionOps test_iomem_ops = { + .read = test_iomem_read, + .write = test_iomem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int init_test_device(ISADevice *isa) +{ + struct PCTestdev *dev = TESTDEV(isa); + MemoryRegion *mem = isa_address_space(isa); + MemoryRegion *io = isa_address_space_io(isa); + + memory_region_init_io(&dev->ioport, &test_ioport_ops, dev, + "pc-testdev-ioport", 4); + memory_region_init_io(&dev->flush, &test_flush_ops, dev, + "pc-testdev-flush-page", 4); + memory_region_init_io(&dev->irq, &test_irq_ops, dev, + "pc-testdev-irq-line", 24); + memory_region_init_io(&dev->iomem, &test_iomem_ops, dev, + "pc-testdev-iomem", IOMEM_LEN); + + memory_region_add_subregion(io, 0xe0, &dev->ioport); + memory_region_add_subregion(io, 0xe4, &dev->flush); + memory_region_add_subregion(io, 0x2000, &dev->irq); + memory_region_add_subregion(mem, 0xff000000, &dev->iomem); + + return 0; +} + +static void testdev_class_init(ObjectClass *klass, void *data) +{ + ISADeviceClass *k = ISA_DEVICE_CLASS(klass); + + k->init = init_test_device; +} + +static TypeInfo testdev_info = { + .name = TYPE_TESTDEV, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(struct PCTestdev), + .class_init = testdev_class_init, +}; + +static void testdev_register_types(void) +{ + type_register_static(&testdev_info); +} + +type_init(testdev_register_types) From 9ee59f341f9d7a95b3a87b7cac3f74bcdda395fb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 11 Dec 2012 09:59:55 +0100 Subject: [PATCH 4/4] pc: remove bochs bios debug ports Prehistoric leftover, zap it. We poweroff via acpi these days. And having a port (0x501,0x502) where any random guest write will make qemu exit -- with no way to turn it off -- is a bad joke anyway. Signed-off-by: Gerd Hoffmann --- hw/pc.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/hw/pc.c b/hw/pc.c index 71902e210b..4879e4f4fb 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -524,34 +524,6 @@ static void handle_a20_line_change(void *opaque, int irq, int level) cpu_x86_set_a20(cpu, level); } -/***********************************************************/ -/* Bochs BIOS debug ports */ - -static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) -{ - static const char shutdown_str[8] = "Shutdown"; - static int shutdown_index = 0; - - switch(addr) { - case 0x8900: - /* same as Bochs power off */ - if (val == shutdown_str[shutdown_index]) { - shutdown_index++; - if (shutdown_index == 8) { - shutdown_index = 0; - qemu_system_shutdown_request(); - } - } else { - shutdown_index = 0; - } - break; - - case 0x501: - case 0x502: - exit((val << 1) | 1); - } -} - int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) { int index = le32_to_cpu(e820_table.count); @@ -569,14 +541,6 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) return index; } -static const MemoryRegionPortio bochs_bios_portio_list[] = { - { 0x500, 1, 1, .write = bochs_bios_write, }, /* 0x500 */ - { 0x501, 1, 1, .write = bochs_bios_write, }, /* 0x501 */ - { 0x501, 2, 2, .write = bochs_bios_write, }, /* 0x501 */ - { 0x8900, 1, 1, .write = bochs_bios_write, }, /* 0x8900 */ - PORTIO_END_OF_LIST(), -}; - static void *bochs_bios_init(void) { void *fw_cfg; @@ -584,11 +548,6 @@ static void *bochs_bios_init(void) size_t smbios_len; uint64_t *numa_fw_cfg; int i, j; - PortioList *bochs_bios_port_list = g_new(PortioList, 1); - - portio_list_init(bochs_bios_port_list, bochs_bios_portio_list, - NULL, "bochs-bios"); - portio_list_add(bochs_bios_port_list, get_system_io(), 0x0); fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);