qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

prep_systemio.c (9693B)


      1 /*
      2  * QEMU PReP System I/O emulation
      3  *
      4  * Copyright (c) 2017 Hervé Poussineau
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "qemu/log.h"
     27 #include "hw/irq.h"
     28 #include "hw/isa/isa.h"
     29 #include "hw/qdev-properties.h"
     30 #include "migration/vmstate.h"
     31 #include "exec/address-spaces.h"
     32 #include "qom/object.h"
     33 #include "qemu/error-report.h" /* for error_report() */
     34 #include "qemu/module.h"
     35 #include "sysemu/runstate.h"
     36 #include "cpu.h"
     37 #include "trace.h"
     38 
     39 #define TYPE_PREP_SYSTEMIO "prep-systemio"
     40 OBJECT_DECLARE_SIMPLE_TYPE(PrepSystemIoState, PREP_SYSTEMIO)
     41 
     42 /* Bit as defined in PowerPC Reference Plaform v1.1, sect. 6.1.5, p. 132 */
     43 #define PREP_BIT(n) (1 << (7 - (n)))
     44 
     45 struct PrepSystemIoState {
     46     ISADevice parent_obj;
     47     MemoryRegion ppc_parity_mem;
     48 
     49     qemu_irq non_contiguous_io_map_irq;
     50     uint8_t sreset; /* 0x0092 */
     51     uint8_t equipment; /* 0x080c */
     52     uint8_t system_control; /* 0x081c */
     53     uint8_t iomap_type; /* 0x0850 */
     54     uint8_t ibm_planar_id; /* 0x0852 */
     55     qemu_irq softreset_irq;
     56     PortioList portio;
     57 };
     58 
     59 /* PORT 0092 -- Special Port 92 (Read/Write) */
     60 
     61 enum {
     62     PORT0092_SOFTRESET  = PREP_BIT(7),
     63     PORT0092_LE_MODE    = PREP_BIT(6),
     64 };
     65 
     66 static void prep_port0092_write(void *opaque, uint32_t addr, uint32_t val)
     67 {
     68     PrepSystemIoState *s = opaque;
     69 
     70     trace_prep_systemio_write(addr, val);
     71 
     72     s->sreset = val & PORT0092_SOFTRESET;
     73     qemu_set_irq(s->softreset_irq, s->sreset);
     74 
     75     if ((val & PORT0092_LE_MODE) != 0) {
     76         /* XXX Not supported yet */
     77         error_report("little-endian mode not supported");
     78         vm_stop(RUN_STATE_PAUSED);
     79     } else {
     80         /* Nothing to do */
     81     }
     82 }
     83 
     84 static uint32_t prep_port0092_read(void *opaque, uint32_t addr)
     85 {
     86     PrepSystemIoState *s = opaque;
     87     trace_prep_systemio_read(addr, s->sreset);
     88     return s->sreset;
     89 }
     90 
     91 /* PORT 0808 -- Hardfile Light Register (Write Only) */
     92 
     93 enum {
     94     PORT0808_HARDFILE_LIGHT_ON  = PREP_BIT(7),
     95 };
     96 
     97 static void prep_port0808_write(void *opaque, uint32_t addr, uint32_t val)
     98 {
     99     trace_prep_systemio_write(addr, val);
    100 }
    101 
    102 /* PORT 0810 -- Password Protect 1 Register (Write Only) */
    103 
    104 /* reset by port 0x4D in the SIO */
    105 static void prep_port0810_write(void *opaque, uint32_t addr, uint32_t val)
    106 {
    107     trace_prep_systemio_write(addr, val);
    108 }
    109 
    110 /* PORT 0812 -- Password Protect 2 Register (Write Only) */
    111 
    112 /* reset by port 0x4D in the SIO */
    113 static void prep_port0812_write(void *opaque, uint32_t addr, uint32_t val)
    114 {
    115     trace_prep_systemio_write(addr, val);
    116 }
    117 
    118 /* PORT 0814 -- L2 Invalidate Register (Write Only) */
    119 
    120 static void prep_port0814_write(void *opaque, uint32_t addr, uint32_t val)
    121 {
    122     trace_prep_systemio_write(addr, val);
    123 }
    124 
    125 /* PORT 0818 -- Reserved for Keylock (Read Only) */
    126 
    127 enum {
    128     PORT0818_KEYLOCK_SIGNAL_HIGH    = PREP_BIT(7),
    129 };
    130 
    131 static uint32_t prep_port0818_read(void *opaque, uint32_t addr)
    132 {
    133     uint32_t val = 0;
    134     trace_prep_systemio_read(addr, val);
    135     return val;
    136 }
    137 
    138 /* PORT 080C -- Equipment */
    139 
    140 enum {
    141     PORT080C_SCSIFUSE               = PREP_BIT(1),
    142     PORT080C_L2_COPYBACK            = PREP_BIT(4),
    143     PORT080C_L2_256                 = PREP_BIT(5),
    144     PORT080C_UPGRADE_CPU            = PREP_BIT(6),
    145     PORT080C_L2                     = PREP_BIT(7),
    146 };
    147 
    148 static uint32_t prep_port080c_read(void *opaque, uint32_t addr)
    149 {
    150     PrepSystemIoState *s = opaque;
    151     trace_prep_systemio_read(addr, s->equipment);
    152     return s->equipment;
    153 }
    154 
    155 /* PORT 081C -- System Control Register (Read/Write) */
    156 
    157 enum {
    158     PORT081C_FLOPPY_MOTOR_INHIBIT   = PREP_BIT(3),
    159     PORT081C_MASK_TEA               = PREP_BIT(2),
    160     PORT081C_L2_UPDATE_INHIBIT      = PREP_BIT(1),
    161     PORT081C_L2_CACHEMISS_INHIBIT   = PREP_BIT(0),
    162 };
    163 
    164 static void prep_port081c_write(void *opaque, uint32_t addr, uint32_t val)
    165 {
    166     static const uint8_t mask = PORT081C_FLOPPY_MOTOR_INHIBIT |
    167                                 PORT081C_MASK_TEA |
    168                                 PORT081C_L2_UPDATE_INHIBIT |
    169                                 PORT081C_L2_CACHEMISS_INHIBIT;
    170     PrepSystemIoState *s = opaque;
    171     trace_prep_systemio_write(addr, val);
    172     s->system_control = val & mask;
    173 }
    174 
    175 static uint32_t prep_port081c_read(void *opaque, uint32_t addr)
    176 {
    177     PrepSystemIoState *s = opaque;
    178     trace_prep_systemio_read(addr, s->system_control);
    179     return s->system_control;
    180 }
    181 
    182 /* System Board Identification */
    183 
    184 static uint32_t prep_port0852_read(void *opaque, uint32_t addr)
    185 {
    186     PrepSystemIoState *s = opaque;
    187     trace_prep_systemio_read(addr, s->ibm_planar_id);
    188     return s->ibm_planar_id;
    189 }
    190 
    191 /* PORT 0850 -- I/O Map Type Register (Read/Write) */
    192 
    193 enum {
    194     PORT0850_IOMAP_NONCONTIGUOUS    = PREP_BIT(7),
    195 };
    196 
    197 static uint32_t prep_port0850_read(void *opaque, uint32_t addr)
    198 {
    199     PrepSystemIoState *s = opaque;
    200     trace_prep_systemio_read(addr, s->iomap_type);
    201     return s->iomap_type;
    202 }
    203 
    204 static void prep_port0850_write(void *opaque, uint32_t addr, uint32_t val)
    205 {
    206     PrepSystemIoState *s = opaque;
    207 
    208     trace_prep_systemio_write(addr, val);
    209     qemu_set_irq(s->non_contiguous_io_map_irq,
    210                  val & PORT0850_IOMAP_NONCONTIGUOUS);
    211     s->iomap_type = val & PORT0850_IOMAP_NONCONTIGUOUS;
    212 }
    213 
    214 static const MemoryRegionPortio ppc_io800_port_list[] = {
    215     { 0x092, 1, 1, .read = prep_port0092_read,
    216                    .write = prep_port0092_write, },
    217     { 0x808, 1, 1, .write = prep_port0808_write, },
    218     { 0x80c, 1, 1, .read = prep_port080c_read, },
    219     { 0x810, 1, 1, .write = prep_port0810_write, },
    220     { 0x812, 1, 1, .write = prep_port0812_write, },
    221     { 0x814, 1, 1, .write = prep_port0814_write, },
    222     { 0x818, 1, 1, .read = prep_port0818_read },
    223     { 0x81c, 1, 1, .read = prep_port081c_read,
    224                    .write = prep_port081c_write, },
    225     { 0x850, 1, 1, .read = prep_port0850_read,
    226                    .write = prep_port0850_write, },
    227     { 0x852, 1, 1, .read = prep_port0852_read, },
    228     PORTIO_END_OF_LIST()
    229 };
    230 
    231 static uint64_t ppc_parity_error_readl(void *opaque, hwaddr addr,
    232                                        unsigned int size)
    233 {
    234     uint32_t val = 0;
    235     trace_prep_systemio_read((unsigned int)addr, val);
    236     return val;
    237 }
    238 
    239 static void ppc_parity_error_writel(void *opaque, hwaddr addr,
    240                                     uint64_t data, unsigned size)
    241 {
    242     qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid access\n", __func__);
    243 }
    244 
    245 static const MemoryRegionOps ppc_parity_error_ops = {
    246     .read = ppc_parity_error_readl,
    247     .write = ppc_parity_error_writel,
    248     .valid = {
    249         .min_access_size = 4,
    250         .max_access_size = 4,
    251     },
    252 };
    253 
    254 static void prep_systemio_realize(DeviceState *dev, Error **errp)
    255 {
    256     ISADevice *isa = ISA_DEVICE(dev);
    257     PrepSystemIoState *s = PREP_SYSTEMIO(dev);
    258     PowerPCCPU *cpu;
    259 
    260     qdev_init_gpio_out(dev, &s->non_contiguous_io_map_irq, 1);
    261     s->iomap_type = PORT0850_IOMAP_NONCONTIGUOUS;
    262     qemu_set_irq(s->non_contiguous_io_map_irq,
    263                  s->iomap_type & PORT0850_IOMAP_NONCONTIGUOUS);
    264     cpu = POWERPC_CPU(first_cpu);
    265     s->softreset_irq = qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_HRESET);
    266 
    267     isa_register_portio_list(isa, &s->portio, 0x0, ppc_io800_port_list, s,
    268                              "systemio800");
    269 
    270     memory_region_init_io(&s->ppc_parity_mem, OBJECT(dev),
    271                           &ppc_parity_error_ops, s, "ppc-parity", 0x4);
    272     memory_region_add_subregion(get_system_memory(), 0xbfffeff0,
    273                                 &s->ppc_parity_mem);
    274 }
    275 
    276 static const VMStateDescription vmstate_prep_systemio = {
    277     .name = "prep_systemio",
    278     .version_id = 1,
    279     .minimum_version_id = 1,
    280     .fields = (VMStateField[]) {
    281         VMSTATE_UINT8(sreset, PrepSystemIoState),
    282         VMSTATE_UINT8(system_control, PrepSystemIoState),
    283         VMSTATE_UINT8(iomap_type, PrepSystemIoState),
    284         VMSTATE_END_OF_LIST()
    285     },
    286 };
    287 
    288 static Property prep_systemio_properties[] = {
    289     DEFINE_PROP_UINT8("ibm-planar-id", PrepSystemIoState, ibm_planar_id, 0),
    290     DEFINE_PROP_UINT8("equipment", PrepSystemIoState, equipment, 0),
    291     DEFINE_PROP_END_OF_LIST()
    292 };
    293 
    294 static void prep_systemio_class_initfn(ObjectClass *klass, void *data)
    295 {
    296     DeviceClass *dc = DEVICE_CLASS(klass);
    297 
    298     dc->realize = prep_systemio_realize;
    299     dc->vmsd = &vmstate_prep_systemio;
    300     device_class_set_props(dc, prep_systemio_properties);
    301 }
    302 
    303 static const TypeInfo prep_systemio800_info = {
    304     .name          = TYPE_PREP_SYSTEMIO,
    305     .parent        = TYPE_ISA_DEVICE,
    306     .instance_size = sizeof(PrepSystemIoState),
    307     .class_init    = prep_systemio_class_initfn,
    308 };
    309 
    310 static void prep_systemio_register_types(void)
    311 {
    312     type_register_static(&prep_systemio800_info);
    313 }
    314 
    315 type_init(prep_systemio_register_types)