xref: /qemu/hw/misc/pvpanic.c (revision 3ab135f3462af4c523a4b5969f9d6c67b2ac427a)
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"
22*3ab135f3SHu 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 
89eec3d2adSHu Tao static int pvpanic_isa_initfn(ISADevice *dev)
90eec3d2adSHu Tao {
91eec3d2adSHu Tao     PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
9210a584b2SHu Tao     static bool port_configured;
9310a584b2SHu Tao     void *fw_cfg;
94eec3d2adSHu Tao 
95eec3d2adSHu Tao     memory_region_init_io(&s->io, &pvpanic_ops, s, "pvpanic", 1);
96eec3d2adSHu Tao     isa_register_ioport(dev, &s->io, s->ioport);
97eec3d2adSHu Tao 
9810a584b2SHu Tao     if (!port_configured) {
9910a584b2SHu Tao         fw_cfg = object_resolve_path("/machine/fw_cfg", NULL);
10010a584b2SHu Tao         if (fw_cfg) {
10110a584b2SHu Tao             fw_cfg_add_file(fw_cfg, "etc/pvpanic-port",
10210a584b2SHu Tao                             g_memdup(&s->ioport, sizeof(s->ioport)),
10310a584b2SHu Tao                             sizeof(s->ioport));
10410a584b2SHu Tao             port_configured = true;
10510a584b2SHu Tao         }
10610a584b2SHu Tao     }
10710a584b2SHu Tao 
108eec3d2adSHu Tao     return 0;
109eec3d2adSHu Tao }
110eec3d2adSHu Tao 
111*3ab135f3SHu Tao int pvpanic_init(ISABus *bus)
112*3ab135f3SHu Tao {
113*3ab135f3SHu Tao     isa_create_simple(bus, TYPE_ISA_PVPANIC_DEVICE);
114*3ab135f3SHu Tao     return 0;
115*3ab135f3SHu Tao }
116*3ab135f3SHu Tao 
117eec3d2adSHu Tao static Property pvpanic_isa_properties[] = {
118eec3d2adSHu Tao     DEFINE_PROP_UINT16("ioport", PVPanicState, ioport, 0x505),
119eec3d2adSHu Tao     DEFINE_PROP_END_OF_LIST(),
120eec3d2adSHu Tao };
121eec3d2adSHu Tao 
122eec3d2adSHu Tao static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
123eec3d2adSHu Tao {
124eec3d2adSHu Tao     DeviceClass *dc = DEVICE_CLASS(klass);
125eec3d2adSHu Tao     ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
126eec3d2adSHu Tao 
127eec3d2adSHu Tao     ic->init = pvpanic_isa_initfn;
128eec3d2adSHu Tao     dc->no_user = 1;
129eec3d2adSHu Tao     dc->props = pvpanic_isa_properties;
130eec3d2adSHu Tao }
131eec3d2adSHu Tao 
132eec3d2adSHu Tao static TypeInfo pvpanic_isa_info = {
133eec3d2adSHu Tao     .name          = TYPE_ISA_PVPANIC_DEVICE,
134eec3d2adSHu Tao     .parent        = TYPE_ISA_DEVICE,
135eec3d2adSHu Tao     .instance_size = sizeof(PVPanicState),
136eec3d2adSHu Tao     .class_init    = pvpanic_isa_class_init,
137eec3d2adSHu Tao };
138eec3d2adSHu Tao 
139eec3d2adSHu Tao static void pvpanic_register_types(void)
140eec3d2adSHu Tao {
141eec3d2adSHu Tao     type_register_static(&pvpanic_isa_info);
142eec3d2adSHu Tao }
143eec3d2adSHu Tao 
144eec3d2adSHu Tao type_init(pvpanic_register_types)
145