qemu/hw/misc/pvpanic.c
<<
>>
Prefs
   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 "sysemu/sysemu.h"
  17#include "qemu/log.h"
  18
  19#include "hw/nvram/fw_cfg.h"
  20#include "hw/misc/pvpanic.h"
  21
  22/* The bit of supported pv event */
  23#define PVPANIC_F_PANICKED      0
  24
  25/* The pv event value */
  26#define PVPANIC_PANICKED        (1 << PVPANIC_F_PANICKED)
  27
  28#define ISA_PVPANIC_DEVICE(obj)    \
  29    OBJECT_CHECK(PVPanicState, (obj), TYPE_PVPANIC)
  30
  31static void handle_event(int event)
  32{
  33    static bool logged;
  34
  35    if (event & ~PVPANIC_PANICKED && !logged) {
  36        qemu_log_mask(LOG_GUEST_ERROR, "pvpanic: unknown event %#x.\n", event);
  37        logged = true;
  38    }
  39
  40    if (event & PVPANIC_PANICKED) {
  41        qemu_system_guest_panicked(NULL);
  42        return;
  43    }
  44}
  45
  46#include "hw/isa/isa.h"
  47
  48typedef struct PVPanicState {
  49    ISADevice parent_obj;
  50
  51    MemoryRegion io;
  52    uint16_t ioport;
  53} PVPanicState;
  54
  55/* return supported events on read */
  56static uint64_t pvpanic_ioport_read(void *opaque, hwaddr addr, unsigned size)
  57{
  58    return PVPANIC_PANICKED;
  59}
  60
  61static void pvpanic_ioport_write(void *opaque, hwaddr addr, uint64_t val,
  62                                 unsigned size)
  63{
  64    handle_event(val);
  65}
  66
  67static const MemoryRegionOps pvpanic_ops = {
  68    .read = pvpanic_ioport_read,
  69    .write = pvpanic_ioport_write,
  70    .impl = {
  71        .min_access_size = 1,
  72        .max_access_size = 1,
  73    },
  74};
  75
  76static void pvpanic_isa_initfn(Object *obj)
  77{
  78    PVPanicState *s = ISA_PVPANIC_DEVICE(obj);
  79
  80    memory_region_init_io(&s->io, OBJECT(s), &pvpanic_ops, s, "pvpanic", 1);
  81}
  82
  83static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
  84{
  85    ISADevice *d = ISA_DEVICE(dev);
  86    PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
  87    FWCfgState *fw_cfg = fw_cfg_find();
  88    uint16_t *pvpanic_port;
  89
  90    if (!fw_cfg) {
  91        return;
  92    }
  93
  94    pvpanic_port = g_malloc(sizeof(*pvpanic_port));
  95    *pvpanic_port = cpu_to_le16(s->ioport);
  96    fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
  97                    sizeof(*pvpanic_port));
  98
  99    isa_register_ioport(d, &s->io, s->ioport);
 100}
 101
 102#define PVPANIC_IOPORT_PROP "ioport"
 103
 104uint16_t pvpanic_port(void)
 105{
 106    Object *o = object_resolve_path_type("", TYPE_PVPANIC, NULL);
 107    if (!o) {
 108        return 0;
 109    }
 110    return object_property_get_uint(o, PVPANIC_IOPORT_PROP, NULL);
 111}
 112
 113static Property pvpanic_isa_properties[] = {
 114    DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicState, ioport, 0x505),
 115    DEFINE_PROP_END_OF_LIST(),
 116};
 117
 118static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
 119{
 120    DeviceClass *dc = DEVICE_CLASS(klass);
 121
 122    dc->realize = pvpanic_isa_realizefn;
 123    dc->props = pvpanic_isa_properties;
 124    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 125}
 126
 127static TypeInfo pvpanic_isa_info = {
 128    .name          = TYPE_PVPANIC,
 129    .parent        = TYPE_ISA_DEVICE,
 130    .instance_size = sizeof(PVPanicState),
 131    .instance_init = pvpanic_isa_initfn,
 132    .class_init    = pvpanic_isa_class_init,
 133};
 134
 135static void pvpanic_register_types(void)
 136{
 137    type_register_static(&pvpanic_isa_info);
 138}
 139
 140type_init(pvpanic_register_types)
 141