xref: /openbmc/qemu/hw/misc/pvpanic.c (revision 2b37e9f8)
1  /*
2   * QEMU simulated pvpanic device.
3   *
4   * Copyright Fujitsu, Corp. 2013
5   *
6   * Authors:
7   *     Wen Congyang <wency@cn.fujitsu.com>
8   *     Hu Tao <hutao@cn.fujitsu.com>
9   *
10   * This work is licensed under the terms of the GNU GPL, version 2 or later.
11   * See the COPYING file in the top-level directory.
12   *
13   */
14  
15  #include "qemu/osdep.h"
16  #include "qemu/log.h"
17  #include "qemu/module.h"
18  #include "sysemu/runstate.h"
19  
20  #include "hw/nvram/fw_cfg.h"
21  #include "hw/qdev-properties.h"
22  #include "hw/misc/pvpanic.h"
23  #include "qom/object.h"
24  
25  /* The bit of supported pv event, TODO: include uapi header and remove this */
26  #define PVPANIC_F_PANICKED      0
27  #define PVPANIC_F_CRASHLOADED   1
28  
29  /* The pv event value */
30  #define PVPANIC_PANICKED        (1 << PVPANIC_F_PANICKED)
31  #define PVPANIC_CRASHLOADED     (1 << PVPANIC_F_CRASHLOADED)
32  
33  typedef struct PVPanicState PVPanicState;
34  DECLARE_INSTANCE_CHECKER(PVPanicState, ISA_PVPANIC_DEVICE,
35                           TYPE_PVPANIC)
36  
37  static void handle_event(int event)
38  {
39      static bool logged;
40  
41      if (event & ~(PVPANIC_PANICKED | PVPANIC_CRASHLOADED) && !logged) {
42          qemu_log_mask(LOG_GUEST_ERROR, "pvpanic: unknown event %#x.\n", event);
43          logged = true;
44      }
45  
46      if (event & PVPANIC_PANICKED) {
47          qemu_system_guest_panicked(NULL);
48          return;
49      }
50  
51      if (event & PVPANIC_CRASHLOADED) {
52          qemu_system_guest_crashloaded(NULL);
53          return;
54      }
55  }
56  
57  #include "hw/isa/isa.h"
58  
59  struct PVPanicState {
60      ISADevice parent_obj;
61  
62      MemoryRegion io;
63      uint16_t ioport;
64      uint8_t events;
65  };
66  
67  /* return supported events on read */
68  static uint64_t pvpanic_ioport_read(void *opaque, hwaddr addr, unsigned size)
69  {
70      PVPanicState *pvp = opaque;
71      return pvp->events;
72  }
73  
74  static void pvpanic_ioport_write(void *opaque, hwaddr addr, uint64_t val,
75                                   unsigned size)
76  {
77      handle_event(val);
78  }
79  
80  static const MemoryRegionOps pvpanic_ops = {
81      .read = pvpanic_ioport_read,
82      .write = pvpanic_ioport_write,
83      .impl = {
84          .min_access_size = 1,
85          .max_access_size = 1,
86      },
87  };
88  
89  static void pvpanic_isa_initfn(Object *obj)
90  {
91      PVPanicState *s = ISA_PVPANIC_DEVICE(obj);
92  
93      memory_region_init_io(&s->io, OBJECT(s), &pvpanic_ops, s, "pvpanic", 1);
94  }
95  
96  static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
97  {
98      ISADevice *d = ISA_DEVICE(dev);
99      PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
100      FWCfgState *fw_cfg = fw_cfg_find();
101      uint16_t *pvpanic_port;
102  
103      if (!fw_cfg) {
104          return;
105      }
106  
107      pvpanic_port = g_malloc(sizeof(*pvpanic_port));
108      *pvpanic_port = cpu_to_le16(s->ioport);
109      fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
110                      sizeof(*pvpanic_port));
111  
112      isa_register_ioport(d, &s->io, s->ioport);
113  }
114  
115  static Property pvpanic_isa_properties[] = {
116      DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicState, ioport, 0x505),
117      DEFINE_PROP_UINT8("events", PVPanicState, events, PVPANIC_PANICKED | PVPANIC_CRASHLOADED),
118      DEFINE_PROP_END_OF_LIST(),
119  };
120  
121  static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
122  {
123      DeviceClass *dc = DEVICE_CLASS(klass);
124  
125      dc->realize = pvpanic_isa_realizefn;
126      device_class_set_props(dc, pvpanic_isa_properties);
127      set_bit(DEVICE_CATEGORY_MISC, dc->categories);
128  }
129  
130  static TypeInfo pvpanic_isa_info = {
131      .name          = TYPE_PVPANIC,
132      .parent        = TYPE_ISA_DEVICE,
133      .instance_size = sizeof(PVPanicState),
134      .instance_init = pvpanic_isa_initfn,
135      .class_init    = pvpanic_isa_class_init,
136  };
137  
138  static void pvpanic_register_types(void)
139  {
140      type_register_static(&pvpanic_isa_info);
141  }
142  
143  type_init(pvpanic_register_types)
144