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