xref: /openbmc/qemu/hw/i386/port92.c (revision 990d2c18)
1 /*
2  * QEMU I/O port 0x92 (System Control Port A, to handle Fast Gate A20)
3  *
4  * Copyright (c) 2003-2004 Fabrice Bellard
5  *
6  * SPDX-License-Identifier: MIT
7  */
8 
9 #include "qemu/osdep.h"
10 #include "sysemu/runstate.h"
11 #include "migration/vmstate.h"
12 #include "hw/irq.h"
13 #include "hw/isa/isa.h"
14 #include "hw/i386/pc.h"
15 #include "trace.h"
16 #include "qom/object.h"
17 
18 OBJECT_DECLARE_SIMPLE_TYPE(Port92State, PORT92)
19 
20 struct Port92State {
21     ISADevice parent_obj;
22 
23     MemoryRegion io;
24     uint8_t outport;
25     qemu_irq a20_out;
26 };
27 
28 static void port92_write(void *opaque, hwaddr addr, uint64_t val,
29                          unsigned size)
30 {
31     Port92State *s = opaque;
32     int oldval = s->outport;
33 
34     trace_port92_write(val);
35     s->outport = val;
36     qemu_set_irq(s->a20_out, (val >> 1) & 1);
37     if ((val & 1) && !(oldval & 1)) {
38         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
39     }
40 }
41 
42 static uint64_t port92_read(void *opaque, hwaddr addr,
43                             unsigned size)
44 {
45     Port92State *s = opaque;
46     uint32_t ret;
47 
48     ret = s->outport;
49     trace_port92_read(ret);
50 
51     return ret;
52 }
53 
54 static const VMStateDescription vmstate_port92_isa = {
55     .name = "port92",
56     .version_id = 1,
57     .minimum_version_id = 1,
58     .fields = (const VMStateField[]) {
59         VMSTATE_UINT8(outport, Port92State),
60         VMSTATE_END_OF_LIST()
61     }
62 };
63 
64 static void port92_reset(DeviceState *d)
65 {
66     Port92State *s = PORT92(d);
67 
68     s->outport &= ~1;
69 }
70 
71 static const MemoryRegionOps port92_ops = {
72     .read = port92_read,
73     .write = port92_write,
74     .impl = {
75         .min_access_size = 1,
76         .max_access_size = 1,
77     },
78     .endianness = DEVICE_LITTLE_ENDIAN,
79 };
80 
81 static void port92_initfn(Object *obj)
82 {
83     Port92State *s = PORT92(obj);
84 
85     memory_region_init_io(&s->io, OBJECT(s), &port92_ops, s, "port92", 1);
86 
87     s->outport = 0;
88 
89     qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, PORT92_A20_LINE, 1);
90 }
91 
92 static void port92_realizefn(DeviceState *dev, Error **errp)
93 {
94     ISADevice *isadev = ISA_DEVICE(dev);
95     Port92State *s = PORT92(dev);
96 
97     isa_register_ioport(isadev, &s->io, 0x92);
98 }
99 
100 static void port92_class_initfn(ObjectClass *klass, void *data)
101 {
102     DeviceClass *dc = DEVICE_CLASS(klass);
103 
104     dc->realize = port92_realizefn;
105     device_class_set_legacy_reset(dc, port92_reset);
106     dc->vmsd = &vmstate_port92_isa;
107     /*
108      * Reason: unlike ordinary ISA devices, this one needs additional
109      * wiring: its A20 output line needs to be wired up with
110      * qdev_connect_gpio_out_named().
111      */
112     dc->user_creatable = false;
113 }
114 
115 static const TypeInfo port92_info = {
116     .name          = TYPE_PORT92,
117     .parent        = TYPE_ISA_DEVICE,
118     .instance_size = sizeof(Port92State),
119     .instance_init = port92_initfn,
120     .class_init    = port92_class_initfn,
121 };
122 
123 static void port92_register_types(void)
124 {
125     type_register_static(&port92_info);
126 }
127 
128 type_init(port92_register_types)
129