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:
commit
346c1f8b52
@ -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
75
hw/debugexit.c
Normal 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)
|
@ -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
182
hw/pc-testdev.c
Normal 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
41
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user