xref: /qemu/hw/misc/pvpanic.c (revision 10a584b2875a391d1036adac18955a892e56f5e3)
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 
21*10a584b2SHu Tao #include "hw/nvram/fw_cfg.h"
22*10a584b2SHu Tao 
23eec3d2adSHu Tao /* The bit of supported pv event */
24eec3d2adSHu Tao #define PVPANIC_F_PANICKED      0
25eec3d2adSHu Tao 
26eec3d2adSHu Tao /* The pv event value */
27eec3d2adSHu Tao #define PVPANIC_PANICKED        (1 << PVPANIC_F_PANICKED)
28eec3d2adSHu Tao 
29eec3d2adSHu Tao #define TYPE_ISA_PVPANIC_DEVICE    "pvpanic"
30eec3d2adSHu Tao #define ISA_PVPANIC_DEVICE(obj)    \
31eec3d2adSHu Tao     OBJECT_CHECK(PVPanicState, (obj), TYPE_ISA_PVPANIC_DEVICE)
32eec3d2adSHu Tao 
33eec3d2adSHu Tao static void panicked_mon_event(const char *action)
34eec3d2adSHu Tao {
35eec3d2adSHu Tao     QObject *data;
36eec3d2adSHu Tao 
37eec3d2adSHu Tao     data = qobject_from_jsonf("{ 'action': %s }", action);
38eec3d2adSHu Tao     monitor_protocol_event(QEVENT_GUEST_PANICKED, data);
39eec3d2adSHu Tao     qobject_decref(data);
40eec3d2adSHu Tao }
41eec3d2adSHu Tao 
42eec3d2adSHu Tao static void handle_event(int event)
43eec3d2adSHu Tao {
44eec3d2adSHu Tao     static bool logged;
45eec3d2adSHu Tao 
46eec3d2adSHu Tao     if (event & ~PVPANIC_PANICKED && !logged) {
47eec3d2adSHu Tao         qemu_log_mask(LOG_GUEST_ERROR, "pvpanic: unknown event %#x.\n", event);
48eec3d2adSHu Tao         logged = true;
49eec3d2adSHu Tao     }
50eec3d2adSHu Tao 
51eec3d2adSHu Tao     if (event & PVPANIC_PANICKED) {
52eec3d2adSHu Tao         panicked_mon_event("pause");
53eec3d2adSHu Tao         vm_stop(RUN_STATE_GUEST_PANICKED);
54eec3d2adSHu Tao         return;
55eec3d2adSHu Tao     }
56eec3d2adSHu Tao }
57eec3d2adSHu Tao 
58eec3d2adSHu Tao #include "hw/isa/isa.h"
59eec3d2adSHu Tao 
60eec3d2adSHu Tao typedef struct PVPanicState {
61eec3d2adSHu Tao     ISADevice parent_obj;
62eec3d2adSHu Tao 
63eec3d2adSHu Tao     MemoryRegion io;
64eec3d2adSHu Tao     uint16_t ioport;
65eec3d2adSHu Tao } PVPanicState;
66eec3d2adSHu Tao 
67eec3d2adSHu Tao /* return supported events on read */
68eec3d2adSHu Tao static uint64_t pvpanic_ioport_read(void *opaque, hwaddr addr, unsigned size)
69eec3d2adSHu Tao {
70eec3d2adSHu Tao     return PVPANIC_PANICKED;
71eec3d2adSHu Tao }
72eec3d2adSHu Tao 
73eec3d2adSHu Tao static void pvpanic_ioport_write(void *opaque, hwaddr addr, uint64_t val,
74eec3d2adSHu Tao                                  unsigned size)
75eec3d2adSHu Tao {
76eec3d2adSHu Tao     handle_event(val);
77eec3d2adSHu Tao }
78eec3d2adSHu Tao 
79eec3d2adSHu Tao static const MemoryRegionOps pvpanic_ops = {
80eec3d2adSHu Tao     .read = pvpanic_ioport_read,
81eec3d2adSHu Tao     .write = pvpanic_ioport_write,
82eec3d2adSHu Tao     .impl = {
83eec3d2adSHu Tao         .min_access_size = 1,
84eec3d2adSHu Tao         .max_access_size = 1,
85eec3d2adSHu Tao     },
86eec3d2adSHu Tao };
87eec3d2adSHu Tao 
88eec3d2adSHu Tao static int pvpanic_isa_initfn(ISADevice *dev)
89eec3d2adSHu Tao {
90eec3d2adSHu Tao     PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
91*10a584b2SHu Tao     static bool port_configured;
92*10a584b2SHu Tao     void *fw_cfg;
93eec3d2adSHu Tao 
94eec3d2adSHu Tao     memory_region_init_io(&s->io, &pvpanic_ops, s, "pvpanic", 1);
95eec3d2adSHu Tao     isa_register_ioport(dev, &s->io, s->ioport);
96eec3d2adSHu Tao 
97*10a584b2SHu Tao     if (!port_configured) {
98*10a584b2SHu Tao         fw_cfg = object_resolve_path("/machine/fw_cfg", NULL);
99*10a584b2SHu Tao         if (fw_cfg) {
100*10a584b2SHu Tao             fw_cfg_add_file(fw_cfg, "etc/pvpanic-port",
101*10a584b2SHu Tao                             g_memdup(&s->ioport, sizeof(s->ioport)),
102*10a584b2SHu Tao                             sizeof(s->ioport));
103*10a584b2SHu Tao             port_configured = true;
104*10a584b2SHu Tao         }
105*10a584b2SHu Tao     }
106*10a584b2SHu Tao 
107eec3d2adSHu Tao     return 0;
108eec3d2adSHu Tao }
109eec3d2adSHu Tao 
110eec3d2adSHu Tao static Property pvpanic_isa_properties[] = {
111eec3d2adSHu Tao     DEFINE_PROP_UINT16("ioport", PVPanicState, ioport, 0x505),
112eec3d2adSHu Tao     DEFINE_PROP_END_OF_LIST(),
113eec3d2adSHu Tao };
114eec3d2adSHu Tao 
115eec3d2adSHu Tao static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
116eec3d2adSHu Tao {
117eec3d2adSHu Tao     DeviceClass *dc = DEVICE_CLASS(klass);
118eec3d2adSHu Tao     ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
119eec3d2adSHu Tao 
120eec3d2adSHu Tao     ic->init = pvpanic_isa_initfn;
121eec3d2adSHu Tao     dc->no_user = 1;
122eec3d2adSHu Tao     dc->props = pvpanic_isa_properties;
123eec3d2adSHu Tao }
124eec3d2adSHu Tao 
125eec3d2adSHu Tao static TypeInfo pvpanic_isa_info = {
126eec3d2adSHu Tao     .name          = TYPE_ISA_PVPANIC_DEVICE,
127eec3d2adSHu Tao     .parent        = TYPE_ISA_DEVICE,
128eec3d2adSHu Tao     .instance_size = sizeof(PVPanicState),
129eec3d2adSHu Tao     .class_init    = pvpanic_isa_class_init,
130eec3d2adSHu Tao };
131eec3d2adSHu Tao 
132eec3d2adSHu Tao static void pvpanic_register_types(void)
133eec3d2adSHu Tao {
134eec3d2adSHu Tao     type_register_static(&pvpanic_isa_info);
135eec3d2adSHu Tao }
136eec3d2adSHu Tao 
137eec3d2adSHu Tao type_init(pvpanic_register_types)
138