qemu/hw/s390x/event-facility.c
<<
>>
Prefs
   1/*
   2 * SCLP
   3 *    Event Facility
   4 *       handles SCLP event types
   5 *          - Signal Quiesce - system power down
   6 *          - ASCII Console Data - VT220 read and write
   7 *
   8 * Copyright IBM, Corp. 2012
   9 *
  10 * Authors:
  11 *  Heinz Graalfs <graalfs@de.ibm.com>
  12 *
  13 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
  14 * option) any later version.  See the COPYING file in the top-level directory.
  15 *
  16 */
  17
  18#include "sysemu/sysemu.h"
  19
  20#include "hw/s390x/sclp.h"
  21#include "hw/s390x/event-facility.h"
  22
  23typedef struct SCLPEventsBus {
  24    BusState qbus;
  25} SCLPEventsBus;
  26
  27struct SCLPEventFacility {
  28    SysBusDevice parent_obj;
  29    SCLPEventsBus sbus;
  30    /* guest' receive mask */
  31    unsigned int receive_mask;
  32};
  33
  34/* return true if any child has event pending set */
  35static bool event_pending(SCLPEventFacility *ef)
  36{
  37    BusChild *kid;
  38    SCLPEvent *event;
  39    SCLPEventClass *event_class;
  40
  41    QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
  42        DeviceState *qdev = kid->child;
  43        event = DO_UPCAST(SCLPEvent, qdev, qdev);
  44        event_class = SCLP_EVENT_GET_CLASS(event);
  45        if (event->event_pending &&
  46            event_class->get_send_mask() & ef->receive_mask) {
  47            return true;
  48        }
  49    }
  50    return false;
  51}
  52
  53static unsigned int get_host_send_mask(SCLPEventFacility *ef)
  54{
  55    unsigned int mask;
  56    BusChild *kid;
  57    SCLPEventClass *child;
  58
  59    mask = 0;
  60
  61    QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
  62        DeviceState *qdev = kid->child;
  63        child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev);
  64        mask |= child->get_send_mask();
  65    }
  66    return mask;
  67}
  68
  69static unsigned int get_host_receive_mask(SCLPEventFacility *ef)
  70{
  71    unsigned int mask;
  72    BusChild *kid;
  73    SCLPEventClass *child;
  74
  75    mask = 0;
  76
  77    QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
  78        DeviceState *qdev = kid->child;
  79        child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev);
  80        mask |= child->get_receive_mask();
  81    }
  82    return mask;
  83}
  84
  85static uint16_t write_event_length_check(SCCB *sccb)
  86{
  87    int slen;
  88    unsigned elen = 0;
  89    EventBufferHeader *event;
  90    WriteEventData *wed = (WriteEventData *) sccb;
  91
  92    event = (EventBufferHeader *) &wed->ebh;
  93    for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) {
  94        elen = be16_to_cpu(event->length);
  95        if (elen < sizeof(*event) || elen > slen) {
  96            return SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR;
  97        }
  98        event = (void *) event + elen;
  99    }
 100    if (slen) {
 101        return SCLP_RC_INCONSISTENT_LENGTHS;
 102    }
 103    return SCLP_RC_NORMAL_COMPLETION;
 104}
 105
 106static uint16_t handle_write_event_buf(SCLPEventFacility *ef,
 107                                       EventBufferHeader *event_buf, SCCB *sccb)
 108{
 109    uint16_t rc;
 110    BusChild *kid;
 111    SCLPEvent *event;
 112    SCLPEventClass *ec;
 113
 114    rc = SCLP_RC_INVALID_FUNCTION;
 115
 116    QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
 117        DeviceState *qdev = kid->child;
 118        event = (SCLPEvent *) qdev;
 119        ec = SCLP_EVENT_GET_CLASS(event);
 120
 121        if (ec->write_event_data &&
 122            ec->can_handle_event(event_buf->type)) {
 123            rc = ec->write_event_data(event, event_buf);
 124            break;
 125        }
 126    }
 127    return rc;
 128}
 129
 130static uint16_t handle_sccb_write_events(SCLPEventFacility *ef, SCCB *sccb)
 131{
 132    uint16_t rc;
 133    int slen;
 134    unsigned elen = 0;
 135    EventBufferHeader *event_buf;
 136    WriteEventData *wed = (WriteEventData *) sccb;
 137
 138    event_buf = &wed->ebh;
 139    rc = SCLP_RC_NORMAL_COMPLETION;
 140
 141    /* loop over all contained event buffers */
 142    for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) {
 143        elen = be16_to_cpu(event_buf->length);
 144
 145        /* in case of a previous error mark all trailing buffers
 146         * as not accepted */
 147        if (rc != SCLP_RC_NORMAL_COMPLETION) {
 148            event_buf->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
 149        } else {
 150            rc = handle_write_event_buf(ef, event_buf, sccb);
 151        }
 152        event_buf = (void *) event_buf + elen;
 153    }
 154    return rc;
 155}
 156
 157static void write_event_data(SCLPEventFacility *ef, SCCB *sccb)
 158{
 159    if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) {
 160        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
 161        goto out;
 162    }
 163    if (be16_to_cpu(sccb->h.length) < 8) {
 164        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
 165        goto out;
 166    }
 167    /* first do a sanity check of the write events */
 168    sccb->h.response_code = cpu_to_be16(write_event_length_check(sccb));
 169
 170    /* if no early error, then execute */
 171    if (sccb->h.response_code == be16_to_cpu(SCLP_RC_NORMAL_COMPLETION)) {
 172        sccb->h.response_code =
 173                cpu_to_be16(handle_sccb_write_events(ef, sccb));
 174    }
 175
 176out:
 177    return;
 178}
 179
 180static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb,
 181                                        unsigned int mask)
 182{
 183    uint16_t rc;
 184    int slen;
 185    unsigned elen;
 186    BusChild *kid;
 187    SCLPEvent *event;
 188    SCLPEventClass *ec;
 189    EventBufferHeader *event_buf;
 190    ReadEventData *red = (ReadEventData *) sccb;
 191
 192    event_buf = &red->ebh;
 193    event_buf->length = 0;
 194    slen = sizeof(sccb->data);
 195
 196    rc = SCLP_RC_NO_EVENT_BUFFERS_STORED;
 197
 198    QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
 199        DeviceState *qdev = kid->child;
 200        event = (SCLPEvent *) qdev;
 201        ec = SCLP_EVENT_GET_CLASS(event);
 202
 203        if (mask & ec->get_send_mask()) {
 204            if (ec->read_event_data(event, event_buf, &slen)) {
 205                elen = be16_to_cpu(event_buf->length);
 206                event_buf = (EventBufferHeader *) ((char *)event_buf + elen);
 207                rc = SCLP_RC_NORMAL_COMPLETION;
 208            }
 209        }
 210    }
 211
 212    if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
 213        /* architecture suggests to reset variable-length-response bit */
 214        sccb->h.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE;
 215        /* with a new length value */
 216        sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
 217    }
 218    return rc;
 219}
 220
 221static void read_event_data(SCLPEventFacility *ef, SCCB *sccb)
 222{
 223    unsigned int sclp_active_selection_mask;
 224    unsigned int sclp_cp_receive_mask;
 225
 226    ReadEventData *red = (ReadEventData *) sccb;
 227
 228    if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) {
 229        sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
 230        goto out;
 231    }
 232
 233    sclp_cp_receive_mask = ef->receive_mask;
 234
 235    /* get active selection mask */
 236    switch (sccb->h.function_code) {
 237    case SCLP_UNCONDITIONAL_READ:
 238        sclp_active_selection_mask = sclp_cp_receive_mask;
 239        break;
 240    case SCLP_SELECTIVE_READ:
 241        sclp_active_selection_mask = be32_to_cpu(red->mask);
 242        if (!sclp_cp_receive_mask ||
 243            (sclp_active_selection_mask & ~sclp_cp_receive_mask)) {
 244            sccb->h.response_code =
 245                    cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
 246            goto out;
 247        }
 248        break;
 249    default:
 250        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
 251        goto out;
 252    }
 253    sccb->h.response_code = cpu_to_be16(
 254            handle_sccb_read_events(ef, sccb, sclp_active_selection_mask));
 255
 256out:
 257    return;
 258}
 259
 260static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb)
 261{
 262    WriteEventMask *we_mask = (WriteEventMask *) sccb;
 263
 264    /* Attention: We assume that Linux uses 4-byte masks, what it actually
 265       does. Architecture allows for masks of variable size, though */
 266    if (be16_to_cpu(we_mask->mask_length) != 4) {
 267        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
 268        goto out;
 269    }
 270
 271    /* keep track of the guest's capability masks */
 272    ef->receive_mask = be32_to_cpu(we_mask->cp_receive_mask);
 273
 274    /* return the SCLP's capability masks to the guest */
 275    we_mask->send_mask = cpu_to_be32(get_host_send_mask(ef));
 276    we_mask->receive_mask = cpu_to_be32(get_host_receive_mask(ef));
 277
 278    sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
 279
 280out:
 281    return;
 282}
 283
 284/* qemu object creation and initialization functions */
 285
 286#define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus"
 287
 288static void sclp_events_bus_realize(BusState *bus, Error **errp)
 289{
 290    BusChild *kid;
 291
 292    /* TODO: recursive realization has to be done in common code */
 293    QTAILQ_FOREACH(kid, &bus->children, sibling) {
 294        DeviceState *dev = kid->child;
 295
 296        object_property_set_bool(OBJECT(dev), true, "realized", errp);
 297        if (*errp) {
 298            return;
 299        }
 300    }
 301}
 302
 303static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
 304{
 305    BusClass *bc = BUS_CLASS(klass);
 306
 307    bc->realize = sclp_events_bus_realize;
 308}
 309
 310static const TypeInfo sclp_events_bus_info = {
 311    .name = TYPE_SCLP_EVENTS_BUS,
 312    .parent = TYPE_BUS,
 313    .class_init = sclp_events_bus_class_init,
 314};
 315
 316static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
 317{
 318    switch (code & SCLP_CMD_CODE_MASK) {
 319    case SCLP_CMD_READ_EVENT_DATA:
 320        read_event_data(ef, sccb);
 321        break;
 322    case SCLP_CMD_WRITE_EVENT_DATA:
 323        write_event_data(ef, sccb);
 324        break;
 325    case SCLP_CMD_WRITE_EVENT_MASK:
 326        write_event_mask(ef, sccb);
 327        break;
 328    default:
 329        sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
 330        break;
 331    }
 332}
 333
 334static const VMStateDescription vmstate_event_facility = {
 335    .name = "vmstate-event-facility",
 336    .version_id = 0,
 337    .minimum_version_id = 0,
 338    .fields = (VMStateField[]) {
 339        VMSTATE_UINT32(receive_mask, SCLPEventFacility),
 340        VMSTATE_END_OF_LIST()
 341     }
 342};
 343
 344static void init_event_facility(Object *obj)
 345{
 346    SCLPEventFacility *event_facility = EVENT_FACILITY(obj);
 347    DeviceState *sdev = DEVICE(obj);
 348    Object *new;
 349
 350    /* Spawn a new bus for SCLP events */
 351    qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
 352                        TYPE_SCLP_EVENTS_BUS, sdev, NULL);
 353
 354    new = object_new(TYPE_SCLP_QUIESCE);
 355    object_property_add_child(obj, TYPE_SCLP_QUIESCE, new, NULL);
 356    object_unref(new);
 357    qdev_set_parent_bus(DEVICE(new), &event_facility->sbus.qbus);
 358
 359    new = object_new(TYPE_SCLP_CPU_HOTPLUG);
 360    object_property_add_child(obj, TYPE_SCLP_CPU_HOTPLUG, new, NULL);
 361    object_unref(new);
 362    qdev_set_parent_bus(DEVICE(new), &event_facility->sbus.qbus);
 363    /* the facility will automatically realize the devices via the bus */
 364}
 365
 366static void reset_event_facility(DeviceState *dev)
 367{
 368    SCLPEventFacility *sdev = EVENT_FACILITY(dev);
 369
 370    sdev->receive_mask = 0;
 371}
 372
 373static void init_event_facility_class(ObjectClass *klass, void *data)
 374{
 375    SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
 376    DeviceClass *dc = DEVICE_CLASS(sbdc);
 377    SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc);
 378
 379    dc->reset = reset_event_facility;
 380    dc->vmsd = &vmstate_event_facility;
 381    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 382    k->command_handler = command_handler;
 383    k->event_pending = event_pending;
 384}
 385
 386static const TypeInfo sclp_event_facility_info = {
 387    .name          = TYPE_SCLP_EVENT_FACILITY,
 388    .parent        = TYPE_SYS_BUS_DEVICE,
 389    .instance_init = init_event_facility,
 390    .instance_size = sizeof(SCLPEventFacility),
 391    .class_init    = init_event_facility_class,
 392    .class_size    = sizeof(SCLPEventFacilityClass),
 393};
 394
 395static void event_realize(DeviceState *qdev, Error **errp)
 396{
 397    SCLPEvent *event = SCLP_EVENT(qdev);
 398    SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
 399
 400    if (child->init) {
 401        int rc = child->init(event);
 402        if (rc < 0) {
 403            error_setg(errp, "SCLP event initialization failed.");
 404            return;
 405        }
 406    }
 407}
 408
 409static void event_unrealize(DeviceState *qdev, Error **errp)
 410{
 411    SCLPEvent *event = SCLP_EVENT(qdev);
 412    SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
 413    if (child->exit) {
 414        int rc = child->exit(event);
 415        if (rc < 0) {
 416            error_setg(errp, "SCLP event exit failed.");
 417            return;
 418        }
 419    }
 420}
 421
 422static void event_class_init(ObjectClass *klass, void *data)
 423{
 424    DeviceClass *dc = DEVICE_CLASS(klass);
 425
 426    dc->bus_type = TYPE_SCLP_EVENTS_BUS;
 427    dc->realize = event_realize;
 428    dc->unrealize = event_unrealize;
 429}
 430
 431static const TypeInfo sclp_event_type_info = {
 432    .name = TYPE_SCLP_EVENT,
 433    .parent = TYPE_DEVICE,
 434    .instance_size = sizeof(SCLPEvent),
 435    .class_init = event_class_init,
 436    .class_size = sizeof(SCLPEventClass),
 437    .abstract = true,
 438};
 439
 440static void register_types(void)
 441{
 442    type_register_static(&sclp_events_bus_info);
 443    type_register_static(&sclp_event_facility_info);
 444    type_register_static(&sclp_event_type_info);
 445}
 446
 447type_init(register_types)
 448