xref: /qemu/hw/misc/pvpanic.c (revision bc3e6a0d6c8ab6cd7cd4b576ed567756f1dcabd2)
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 
93db895a1eSAndreas Färber     memory_region_init_io(&s->io, &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);
100eec3d2adSHu Tao 
101db895a1eSAndreas Färber     isa_register_ioport(d, &s->io, s->ioport);
102*bc3e6a0dSMichael S. Tsirkin }
103eec3d2adSHu Tao 
104*bc3e6a0dSMichael S. Tsirkin static void pvpanic_fw_cfg(ISADevice *dev, FWCfgState *fw_cfg)
105*bc3e6a0dSMichael S. Tsirkin {
106*bc3e6a0dSMichael S. Tsirkin     PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
107*bc3e6a0dSMichael S. Tsirkin 
10810a584b2SHu Tao     fw_cfg_add_file(fw_cfg, "etc/pvpanic-port",
10910a584b2SHu Tao                     g_memdup(&s->ioport, sizeof(s->ioport)),
11010a584b2SHu Tao                     sizeof(s->ioport));
111eec3d2adSHu Tao }
112eec3d2adSHu Tao 
113*bc3e6a0dSMichael S. Tsirkin void pvpanic_init(ISABus *bus)
1143ab135f3SHu Tao {
115*bc3e6a0dSMichael S. Tsirkin     ISADevice *dev;
116*bc3e6a0dSMichael S. Tsirkin     FWCfgState *fw_cfg = fw_cfg_find();
117*bc3e6a0dSMichael S. Tsirkin     if (!fw_cfg) {
118*bc3e6a0dSMichael S. Tsirkin         return;
119*bc3e6a0dSMichael S. Tsirkin     }
120*bc3e6a0dSMichael S. Tsirkin     dev = isa_create_simple (bus, TYPE_ISA_PVPANIC_DEVICE);
121*bc3e6a0dSMichael S. Tsirkin     pvpanic_fw_cfg(dev, fw_cfg);
1223ab135f3SHu Tao }
1233ab135f3SHu Tao 
124eec3d2adSHu Tao static Property pvpanic_isa_properties[] = {
125eec3d2adSHu Tao     DEFINE_PROP_UINT16("ioport", PVPanicState, ioport, 0x505),
126eec3d2adSHu Tao     DEFINE_PROP_END_OF_LIST(),
127eec3d2adSHu Tao };
128eec3d2adSHu Tao 
129eec3d2adSHu Tao static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
130eec3d2adSHu Tao {
131eec3d2adSHu Tao     DeviceClass *dc = DEVICE_CLASS(klass);
132eec3d2adSHu Tao 
133db895a1eSAndreas Färber     dc->realize = pvpanic_isa_realizefn;
134eec3d2adSHu Tao     dc->no_user = 1;
135eec3d2adSHu Tao     dc->props = pvpanic_isa_properties;
136eec3d2adSHu Tao }
137eec3d2adSHu Tao 
138eec3d2adSHu Tao static TypeInfo pvpanic_isa_info = {
139eec3d2adSHu Tao     .name          = TYPE_ISA_PVPANIC_DEVICE,
140eec3d2adSHu Tao     .parent        = TYPE_ISA_DEVICE,
141eec3d2adSHu Tao     .instance_size = sizeof(PVPanicState),
142db895a1eSAndreas Färber     .instance_init = pvpanic_isa_initfn,
143eec3d2adSHu Tao     .class_init    = pvpanic_isa_class_init,
144eec3d2adSHu Tao };
145eec3d2adSHu Tao 
146eec3d2adSHu Tao static void pvpanic_register_types(void)
147eec3d2adSHu Tao {
148eec3d2adSHu Tao     type_register_static(&pvpanic_isa_info);
149eec3d2adSHu Tao }
150eec3d2adSHu Tao 
151eec3d2adSHu Tao type_init(pvpanic_register_types)
152