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