xref: /qemu/hw/misc/pvpanic.c (revision 309cd62d6b2628b4f0e2850b42011077f40956c7)
1eec3d2adSHu Tao /*
2eec3d2adSHu Tao  * QEMU simulated pvpanic device.
3eec3d2adSHu Tao  *
4eec3d2adSHu Tao  * Copyright Fujitsu, Corp. 2013
5eec3d2adSHu Tao  *
6eec3d2adSHu Tao  * Authors:
7eec3d2adSHu Tao  *     Wen Congyang <wency@cn.fujitsu.com>
8eec3d2adSHu Tao  *     Hu Tao <hutao@cn.fujitsu.com>
9eec3d2adSHu Tao  *
10eec3d2adSHu Tao  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11eec3d2adSHu Tao  * See the COPYING file in the top-level directory.
12eec3d2adSHu Tao  *
13eec3d2adSHu Tao  */
14eec3d2adSHu Tao 
15eec3d2adSHu Tao #include "qapi/qmp/qobject.h"
16eec3d2adSHu Tao #include "qapi/qmp/qjson.h"
17eec3d2adSHu Tao #include "monitor/monitor.h"
18eec3d2adSHu Tao #include "sysemu/sysemu.h"
19eec3d2adSHu Tao #include "qemu/log.h"
20eec3d2adSHu Tao 
2110a584b2SHu Tao #include "hw/nvram/fw_cfg.h"
223ab135f3SHu Tao #include "hw/i386/pc.h"
2310a584b2SHu Tao 
24eec3d2adSHu Tao /* The bit of supported pv event */
25eec3d2adSHu Tao #define PVPANIC_F_PANICKED      0
26eec3d2adSHu Tao 
27eec3d2adSHu Tao /* The pv event value */
28eec3d2adSHu Tao #define PVPANIC_PANICKED        (1 << PVPANIC_F_PANICKED)
29eec3d2adSHu Tao 
30eec3d2adSHu Tao #define TYPE_ISA_PVPANIC_DEVICE    "pvpanic"
31eec3d2adSHu Tao #define ISA_PVPANIC_DEVICE(obj)    \
32eec3d2adSHu Tao     OBJECT_CHECK(PVPanicState, (obj), TYPE_ISA_PVPANIC_DEVICE)
33eec3d2adSHu Tao 
34eec3d2adSHu Tao static void panicked_mon_event(const char *action)
35eec3d2adSHu Tao {
36eec3d2adSHu Tao     QObject *data;
37eec3d2adSHu Tao 
38eec3d2adSHu Tao     data = qobject_from_jsonf("{ 'action': %s }", action);
39eec3d2adSHu Tao     monitor_protocol_event(QEVENT_GUEST_PANICKED, data);
40eec3d2adSHu Tao     qobject_decref(data);
41eec3d2adSHu Tao }
42eec3d2adSHu Tao 
43eec3d2adSHu Tao static void handle_event(int event)
44eec3d2adSHu Tao {
45eec3d2adSHu Tao     static bool logged;
46eec3d2adSHu Tao 
47eec3d2adSHu Tao     if (event & ~PVPANIC_PANICKED && !logged) {
48eec3d2adSHu Tao         qemu_log_mask(LOG_GUEST_ERROR, "pvpanic: unknown event %#x.\n", event);
49eec3d2adSHu Tao         logged = true;
50eec3d2adSHu Tao     }
51eec3d2adSHu Tao 
52eec3d2adSHu Tao     if (event & PVPANIC_PANICKED) {
53eec3d2adSHu Tao         panicked_mon_event("pause");
54eec3d2adSHu Tao         vm_stop(RUN_STATE_GUEST_PANICKED);
55eec3d2adSHu Tao         return;
56eec3d2adSHu Tao     }
57eec3d2adSHu Tao }
58eec3d2adSHu Tao 
59eec3d2adSHu Tao #include "hw/isa/isa.h"
60eec3d2adSHu Tao 
61eec3d2adSHu Tao typedef struct PVPanicState {
62eec3d2adSHu Tao     ISADevice parent_obj;
63eec3d2adSHu Tao 
64eec3d2adSHu Tao     MemoryRegion io;
65eec3d2adSHu Tao     uint16_t ioport;
66eec3d2adSHu Tao } PVPanicState;
67eec3d2adSHu Tao 
68eec3d2adSHu Tao /* return supported events on read */
69eec3d2adSHu Tao static uint64_t pvpanic_ioport_read(void *opaque, hwaddr addr, unsigned size)
70eec3d2adSHu Tao {
71eec3d2adSHu Tao     return PVPANIC_PANICKED;
72eec3d2adSHu Tao }
73eec3d2adSHu Tao 
74eec3d2adSHu Tao static void pvpanic_ioport_write(void *opaque, hwaddr addr, uint64_t val,
75eec3d2adSHu Tao                                  unsigned size)
76eec3d2adSHu Tao {
77eec3d2adSHu Tao     handle_event(val);
78eec3d2adSHu Tao }
79eec3d2adSHu Tao 
80eec3d2adSHu Tao static const MemoryRegionOps pvpanic_ops = {
81eec3d2adSHu Tao     .read = pvpanic_ioport_read,
82eec3d2adSHu Tao     .write = pvpanic_ioport_write,
83eec3d2adSHu Tao     .impl = {
84eec3d2adSHu Tao         .min_access_size = 1,
85eec3d2adSHu Tao         .max_access_size = 1,
86eec3d2adSHu Tao     },
87eec3d2adSHu Tao };
88eec3d2adSHu Tao 
89db895a1eSAndreas Färber static void pvpanic_isa_initfn(Object *obj)
90eec3d2adSHu Tao {
91db895a1eSAndreas Färber     PVPanicState *s = ISA_PVPANIC_DEVICE(obj);
92db895a1eSAndreas Färber 
933c161542SPaolo Bonzini     memory_region_init_io(&s->io, OBJECT(s), &pvpanic_ops, s, "pvpanic", 1);
94db895a1eSAndreas Färber }
95db895a1eSAndreas Färber 
96db895a1eSAndreas Färber static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
97db895a1eSAndreas Färber {
98db895a1eSAndreas Färber     ISADevice *d = ISA_DEVICE(dev);
99eec3d2adSHu Tao     PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
100a5d3f640SMarcel Apfelbaum     FWCfgState *fw_cfg = fw_cfg_find();
101a5d3f640SMarcel Apfelbaum     uint16_t *pvpanic_port;
102a5d3f640SMarcel Apfelbaum 
103a5d3f640SMarcel Apfelbaum     if (!fw_cfg) {
104a5d3f640SMarcel Apfelbaum         return;
105a5d3f640SMarcel Apfelbaum     }
106a5d3f640SMarcel Apfelbaum 
107a5d3f640SMarcel Apfelbaum     pvpanic_port = g_malloc(sizeof(*pvpanic_port));
108a5d3f640SMarcel Apfelbaum     *pvpanic_port = cpu_to_le16(s->ioport);
109a5d3f640SMarcel Apfelbaum     fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
110a5d3f640SMarcel Apfelbaum                     sizeof(*pvpanic_port));
111eec3d2adSHu Tao 
112db895a1eSAndreas Färber     isa_register_ioport(d, &s->io, s->ioport);
113eec3d2adSHu Tao }
114eec3d2adSHu Tao 
115bc3e6a0dSMichael S. Tsirkin void pvpanic_init(ISABus *bus)
1163ab135f3SHu Tao {
117a5d3f640SMarcel Apfelbaum     isa_create_simple(bus, TYPE_ISA_PVPANIC_DEVICE);
1183ab135f3SHu Tao }
1193ab135f3SHu Tao 
120*309cd62dSMichael S. Tsirkin #define PVPANIC_IOPORT_PROP "ioport"
121*309cd62dSMichael S. Tsirkin 
122*309cd62dSMichael S. Tsirkin uint16_t pvpanic_port(void)
123*309cd62dSMichael S. Tsirkin {
124*309cd62dSMichael S. Tsirkin     Object *o = object_resolve_path_type("", TYPE_ISA_PVPANIC_DEVICE, NULL);
125*309cd62dSMichael S. Tsirkin     if (!o) {
126*309cd62dSMichael S. Tsirkin         return 0;
127*309cd62dSMichael S. Tsirkin     }
128*309cd62dSMichael S. Tsirkin     return object_property_get_int(o, PVPANIC_IOPORT_PROP, NULL);
129*309cd62dSMichael S. Tsirkin }
130*309cd62dSMichael S. Tsirkin 
131eec3d2adSHu Tao static Property pvpanic_isa_properties[] = {
132*309cd62dSMichael S. Tsirkin     DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicState, ioport, 0x505),
133eec3d2adSHu Tao     DEFINE_PROP_END_OF_LIST(),
134eec3d2adSHu Tao };
135eec3d2adSHu Tao 
136eec3d2adSHu Tao static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
137eec3d2adSHu Tao {
138eec3d2adSHu Tao     DeviceClass *dc = DEVICE_CLASS(klass);
139eec3d2adSHu Tao 
140db895a1eSAndreas Färber     dc->realize = pvpanic_isa_realizefn;
141eec3d2adSHu Tao     dc->props = pvpanic_isa_properties;
142a5d3f640SMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
143eec3d2adSHu Tao }
144eec3d2adSHu Tao 
145eec3d2adSHu Tao static TypeInfo pvpanic_isa_info = {
146eec3d2adSHu Tao     .name          = TYPE_ISA_PVPANIC_DEVICE,
147eec3d2adSHu Tao     .parent        = TYPE_ISA_DEVICE,
148eec3d2adSHu Tao     .instance_size = sizeof(PVPanicState),
149db895a1eSAndreas Färber     .instance_init = pvpanic_isa_initfn,
150eec3d2adSHu Tao     .class_init    = pvpanic_isa_class_init,
151eec3d2adSHu Tao };
152eec3d2adSHu Tao 
153eec3d2adSHu Tao static void pvpanic_register_types(void)
154eec3d2adSHu Tao {
155eec3d2adSHu Tao     type_register_static(&pvpanic_isa_info);
156eec3d2adSHu Tao }
157eec3d2adSHu Tao 
158eec3d2adSHu Tao type_init(pvpanic_register_types)
159