aboutsummaryrefslogtreecommitdiff
path: root/hw/misc/virt_ctrl.c
blob: e75d1e7e17b334f8c37c75d67bfb88c2b8c16890 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * Virt system Controller
 */

#include "qemu/osdep.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "trace.h"
#include "sysemu/runstate.h"
#include "hw/misc/virt_ctrl.h"

enum {
    REG_FEATURES = 0x00,
    REG_CMD      = 0x04,
};

#define FEAT_POWER_CTRL 0x00000001

enum {
    CMD_NOOP,
    CMD_RESET,
    CMD_HALT,
    CMD_PANIC,
};

static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size)
{
    VirtCtrlState *s = opaque;
    uint64_t value = 0;

    switch (addr) {
    case REG_FEATURES:
        value = FEAT_POWER_CTRL;
        break;
    default:
        qemu_log_mask(LOG_UNIMP,
                      "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
                      __func__, addr);
        break;
    }

    trace_virt_ctrl_write(s, addr, size, value);

    return value;
}

static void virt_ctrl_write(void *opaque, hwaddr addr, uint64_t value,
                            unsigned size)
{
    VirtCtrlState *s = opaque;

    trace_virt_ctrl_write(s, addr, size, value);

    switch (addr) {
    case REG_CMD:
        switch (value) {
        case CMD_NOOP:
            break;
        case CMD_RESET:
            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
            break;
        case CMD_HALT:
            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
            break;
        case CMD_PANIC:
            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC);
            break;
        }
        break;
    default:
        qemu_log_mask(LOG_UNIMP,
                      "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
                      __func__, addr);
        break;
    }
}

static const MemoryRegionOps virt_ctrl_ops = {
    .read = virt_ctrl_read,
    .write = virt_ctrl_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .valid.max_access_size = 4,
    .impl.max_access_size = 4,
};

static void virt_ctrl_reset(DeviceState *dev)
{
    VirtCtrlState *s = VIRT_CTRL(dev);

    trace_virt_ctrl_reset(s);
}

static void virt_ctrl_realize(DeviceState *dev, Error **errp)
{
    VirtCtrlState *s = VIRT_CTRL(dev);

    trace_virt_ctrl_instance_init(s);

    memory_region_init_io(&s->iomem, OBJECT(s), &virt_ctrl_ops, s,
                          "virt-ctrl", 0x100);
}

static const VMStateDescription vmstate_virt_ctrl = {
    .name = "virt-ctrl",
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32(irq_enabled, VirtCtrlState),
        VMSTATE_END_OF_LIST()
    }
};

static void virt_ctrl_instance_init(Object *obj)
{
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
    VirtCtrlState *s = VIRT_CTRL(obj);

    trace_virt_ctrl_instance_init(s);

    sysbus_init_mmio(dev, &s->iomem);
    sysbus_init_irq(dev, &s->irq);
}

static void virt_ctrl_class_init(ObjectClass *oc, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(oc);

    dc->reset = virt_ctrl_reset;
    dc->realize = virt_ctrl_realize;
    dc->vmsd = &vmstate_virt_ctrl;
}

static const TypeInfo virt_ctrl_info = {
    .name = TYPE_VIRT_CTRL,
    .parent = TYPE_SYS_BUS_DEVICE,
    .class_init = virt_ctrl_class_init,
    .instance_init = virt_ctrl_instance_init,
    .instance_size = sizeof(VirtCtrlState),
};

static void virt_ctrl_register_types(void)
{
    type_register_static(&virt_ctrl_info);
}

type_init(virt_ctrl_register_types)