xref: /openbmc/qemu/hw/misc/virt_ctrl.c (revision 2e1cacfb)
1 /*
2  * SPDX-License-Identifier: GPL-2.0-or-later
3  *
4  * Virt system Controller
5  */
6 
7 #include "qemu/osdep.h"
8 #include "hw/qdev-properties.h"
9 #include "hw/sysbus.h"
10 #include "migration/vmstate.h"
11 #include "qemu/log.h"
12 #include "trace.h"
13 #include "sysemu/runstate.h"
14 #include "hw/misc/virt_ctrl.h"
15 
16 enum {
17     REG_FEATURES = 0x00,
18     REG_CMD      = 0x04,
19 };
20 
21 #define FEAT_POWER_CTRL 0x00000001
22 
23 enum {
24     CMD_NOOP,
25     CMD_RESET,
26     CMD_HALT,
27     CMD_PANIC,
28 };
29 
30 static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size)
31 {
32     VirtCtrlState *s = opaque;
33     uint64_t value = 0;
34 
35     switch (addr) {
36     case REG_FEATURES:
37         value = FEAT_POWER_CTRL;
38         break;
39     default:
40         qemu_log_mask(LOG_UNIMP,
41                       "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
42                       __func__, addr);
43         break;
44     }
45 
46     trace_virt_ctrl_write(s, addr, size, value);
47 
48     return value;
49 }
50 
51 static void virt_ctrl_write(void *opaque, hwaddr addr, uint64_t value,
52                             unsigned size)
53 {
54     VirtCtrlState *s = opaque;
55 
56     trace_virt_ctrl_write(s, addr, size, value);
57 
58     switch (addr) {
59     case REG_CMD:
60         switch (value) {
61         case CMD_NOOP:
62             break;
63         case CMD_RESET:
64             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
65             break;
66         case CMD_HALT:
67             qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
68             break;
69         case CMD_PANIC:
70             qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC);
71             break;
72         }
73         break;
74     default:
75         qemu_log_mask(LOG_UNIMP,
76                       "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
77                       __func__, addr);
78         break;
79     }
80 }
81 
82 static const MemoryRegionOps virt_ctrl_ops = {
83     .read = virt_ctrl_read,
84     .write = virt_ctrl_write,
85     .endianness = DEVICE_NATIVE_ENDIAN,
86     .valid.max_access_size = 4,
87     .impl.max_access_size = 4,
88 };
89 
90 static void virt_ctrl_reset(DeviceState *dev)
91 {
92     VirtCtrlState *s = VIRT_CTRL(dev);
93 
94     trace_virt_ctrl_reset(s);
95 }
96 
97 static void virt_ctrl_realize(DeviceState *dev, Error **errp)
98 {
99     VirtCtrlState *s = VIRT_CTRL(dev);
100 
101     trace_virt_ctrl_instance_init(s);
102 
103     memory_region_init_io(&s->iomem, OBJECT(s), &virt_ctrl_ops, s,
104                           "virt-ctrl", 0x100);
105 }
106 
107 static const VMStateDescription vmstate_virt_ctrl = {
108     .name = "virt-ctrl",
109     .version_id = 1,
110     .minimum_version_id = 1,
111     .fields = (const VMStateField[]) {
112         VMSTATE_UINT32(irq_enabled, VirtCtrlState),
113         VMSTATE_END_OF_LIST()
114     }
115 };
116 
117 static void virt_ctrl_instance_init(Object *obj)
118 {
119     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
120     VirtCtrlState *s = VIRT_CTRL(obj);
121 
122     trace_virt_ctrl_instance_init(s);
123 
124     sysbus_init_mmio(dev, &s->iomem);
125     sysbus_init_irq(dev, &s->irq);
126 }
127 
128 static void virt_ctrl_class_init(ObjectClass *oc, void *data)
129 {
130     DeviceClass *dc = DEVICE_CLASS(oc);
131 
132     device_class_set_legacy_reset(dc, virt_ctrl_reset);
133     dc->realize = virt_ctrl_realize;
134     dc->vmsd = &vmstate_virt_ctrl;
135 }
136 
137 static const TypeInfo virt_ctrl_info = {
138     .name = TYPE_VIRT_CTRL,
139     .parent = TYPE_SYS_BUS_DEVICE,
140     .class_init = virt_ctrl_class_init,
141     .instance_init = virt_ctrl_instance_init,
142     .instance_size = sizeof(VirtCtrlState),
143 };
144 
145 static void virt_ctrl_register_types(void)
146 {
147     type_register_static(&virt_ctrl_info);
148 }
149 
150 type_init(virt_ctrl_register_types)
151