Merge remote-tracking branch 'kraxel/testdev.1' into staging

* kraxel/testdev.1:
  pc: remove bochs bios debug ports
  hw: Add test device for unittests execution
  add isa-debug-exit device.
  switch debugcon to memory api

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2013-01-04 13:25:07 -06:00
commit 346c1f8b52
5 changed files with 283 additions and 49 deletions

View file

@ -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,

75
hw/debugexit.c Normal file
View file

@ -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)

View file

@ -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
@ -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))

182
hw/pc-testdev.c Normal file
View file

@ -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 <sys/mman.h>
#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)

41
hw/pc.c
View file

@ -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);