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