diff options
Diffstat (limited to 'hw/misc/virt_ctrl.c')
-rw-r--r-- | hw/misc/virt_ctrl.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/hw/misc/virt_ctrl.c b/hw/misc/virt_ctrl.c new file mode 100644 index 0000000000..2ea01bd7a1 --- /dev/null +++ b/hw/misc/virt_ctrl.c @@ -0,0 +1,151 @@ +/* + * SPDX-License-Identifer: GPL-2.0-or-later + * + * Virt system Controller + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "trace.h" +#include "sysemu/runstate.h" +#include "hw/misc/virt_ctrl.h" + +enum { + REG_FEATURES = 0x00, + REG_CMD = 0x04, +}; + +#define FEAT_POWER_CTRL 0x00000001 + +enum { + CMD_NOOP, + CMD_RESET, + CMD_HALT, + CMD_PANIC, +}; + +static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size) +{ + VirtCtrlState *s = opaque; + uint64_t value = 0; + + switch (addr) { + case REG_FEATURES: + value = FEAT_POWER_CTRL; + break; + default: + qemu_log_mask(LOG_UNIMP, + "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n", + __func__, addr); + break; + } + + trace_virt_ctrl_write(s, addr, size, value); + + return value; +} + +static void virt_ctrl_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ + VirtCtrlState *s = opaque; + + trace_virt_ctrl_write(s, addr, size, value); + + switch (addr) { + case REG_CMD: + switch (value) { + case CMD_NOOP: + break; + case CMD_RESET: + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + break; + case CMD_HALT: + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); + break; + case CMD_PANIC: + qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC); + break; + } + break; + default: + qemu_log_mask(LOG_UNIMP, + "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n", + __func__, addr); + break; + } +} + +static const MemoryRegionOps virt_ctrl_ops = { + .read = virt_ctrl_read, + .write = virt_ctrl_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.max_access_size = 4, + .impl.max_access_size = 4, +}; + +static void virt_ctrl_reset(DeviceState *dev) +{ + VirtCtrlState *s = VIRT_CTRL(dev); + + trace_virt_ctrl_reset(s); +} + +static void virt_ctrl_realize(DeviceState *dev, Error **errp) +{ + VirtCtrlState *s = VIRT_CTRL(dev); + + trace_virt_ctrl_instance_init(s); + + memory_region_init_io(&s->iomem, OBJECT(s), &virt_ctrl_ops, s, + "virt-ctrl", 0x100); +} + +static const VMStateDescription vmstate_virt_ctrl = { + .name = "virt-ctrl", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(irq_enabled, VirtCtrlState), + VMSTATE_END_OF_LIST() + } +}; + +static void virt_ctrl_instance_init(Object *obj) +{ + SysBusDevice *dev = SYS_BUS_DEVICE(obj); + VirtCtrlState *s = VIRT_CTRL(obj); + + trace_virt_ctrl_instance_init(s); + + sysbus_init_mmio(dev, &s->iomem); + sysbus_init_irq(dev, &s->irq); +} + +static void virt_ctrl_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->reset = virt_ctrl_reset; + dc->realize = virt_ctrl_realize; + dc->vmsd = &vmstate_virt_ctrl; +} + +static const TypeInfo virt_ctrl_info = { + .name = TYPE_VIRT_CTRL, + .parent = TYPE_SYS_BUS_DEVICE, + .class_init = virt_ctrl_class_init, + .instance_init = virt_ctrl_instance_init, + .instance_size = sizeof(VirtCtrlState), +}; + +static void virt_ctrl_register_types(void) +{ + type_register_static(&virt_ctrl_info); +} + +type_init(virt_ctrl_register_types) |