qemu/hw/char/sclpconsole.c
<<
>>
Prefs
   1/*
   2 * SCLP event type
   3 *    Ascii Console Data (VT220 Console)
   4 *
   5 * Copyright IBM, Corp. 2012
   6 *
   7 * Authors:
   8 *  Heinz Graalfs <graalfs@de.ibm.com>
   9 *
  10 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
  11 * option) any later version.  See the COPYING file in the top-level directory.
  12 *
  13 */
  14
  15#include "qemu/osdep.h"
  16#include <hw/qdev.h>
  17#include "qemu/thread.h"
  18#include "qemu/error-report.h"
  19
  20#include "hw/s390x/sclp.h"
  21#include "hw/s390x/event-facility.h"
  22#include "sysemu/char.h"
  23
  24typedef struct ASCIIConsoleData {
  25    EventBufferHeader ebh;
  26    char data[0];
  27} QEMU_PACKED ASCIIConsoleData;
  28
  29/* max size for ASCII data in 4K SCCB page */
  30#define SIZE_BUFFER_VT220 4080
  31
  32typedef struct SCLPConsole {
  33    SCLPEvent event;
  34    CharDriverState *chr;
  35    uint8_t iov[SIZE_BUFFER_VT220];
  36    uint32_t iov_sclp;      /* offset in buf for SCLP read operation       */
  37    uint32_t iov_bs;        /* offset in buf for char layer read operation */
  38    uint32_t iov_data_len;  /* length of byte stream in buffer             */
  39    uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP     */
  40    bool notify;            /* qemu_notify_event() req'd if true           */
  41} SCLPConsole;
  42
  43#define TYPE_SCLP_CONSOLE "sclpconsole"
  44#define SCLP_CONSOLE(obj) \
  45    OBJECT_CHECK(SCLPConsole, (obj), TYPE_SCLP_CONSOLE)
  46
  47/* character layer call-back functions */
  48
  49/* Return number of bytes that fit into iov buffer */
  50static int chr_can_read(void *opaque)
  51{
  52    SCLPConsole *scon = opaque;
  53    int avail = SIZE_BUFFER_VT220 - scon->iov_data_len;
  54
  55    if (avail == 0) {
  56        scon->notify = true;
  57    }
  58    return avail;
  59}
  60
  61/* Send data from a char device over to the guest */
  62static void chr_read(void *opaque, const uint8_t *buf, int size)
  63{
  64    SCLPConsole *scon = opaque;
  65
  66    assert(scon);
  67    /* read data must fit into current buffer */
  68    assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
  69
  70    /* put byte-stream from character layer into buffer */
  71    memcpy(&scon->iov[scon->iov_bs], buf, size);
  72    scon->iov_data_len += size;
  73    scon->iov_sclp_rest += size;
  74    scon->iov_bs += size;
  75    scon->event.event_pending = true;
  76    sclp_service_interrupt(0);
  77}
  78
  79/* functions to be called by event facility */
  80
  81static bool can_handle_event(uint8_t type)
  82{
  83    return type == SCLP_EVENT_ASCII_CONSOLE_DATA;
  84}
  85
  86static unsigned int send_mask(void)
  87{
  88    return SCLP_EVENT_MASK_MSG_ASCII;
  89}
  90
  91static unsigned int receive_mask(void)
  92{
  93    return SCLP_EVENT_MASK_MSG_ASCII;
  94}
  95
  96/* triggered by SCLP's read_event_data -
  97 * copy console data byte-stream into provided (SCLP) buffer
  98 */
  99static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
 100                             int avail)
 101{
 102    SCLPConsole *cons = SCLP_CONSOLE(event);
 103
 104    /* first byte is hex 0 saying an ascii string follows */
 105    *buf++ = '\0';
 106    avail--;
 107    /* if all data fit into provided SCLP buffer */
 108    if (avail >= cons->iov_sclp_rest) {
 109        /* copy character byte-stream to SCLP buffer */
 110        memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest);
 111        *size = cons->iov_sclp_rest + 1;
 112        cons->iov_sclp = 0;
 113        cons->iov_bs = 0;
 114        cons->iov_data_len = 0;
 115        cons->iov_sclp_rest = 0;
 116        event->event_pending = false;
 117        /* data provided and no more data pending */
 118    } else {
 119        /* if provided buffer is too small, just copy part */
 120        memcpy(buf, &cons->iov[cons->iov_sclp], avail);
 121        *size = avail + 1;
 122        cons->iov_sclp_rest -= avail;
 123        cons->iov_sclp += avail;
 124        /* more data pending */
 125    }
 126    if (cons->notify) {
 127        cons->notify = false;
 128        qemu_notify_event();
 129    }
 130}
 131
 132static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
 133                           int *slen)
 134{
 135    int avail;
 136    size_t src_len;
 137    uint8_t *to;
 138    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
 139
 140    if (!event->event_pending) {
 141        /* no data pending */
 142        return 0;
 143    }
 144
 145    to = (uint8_t *)&acd->data;
 146    avail = *slen - sizeof(ASCIIConsoleData);
 147    get_console_data(event, to, &src_len, avail);
 148
 149    acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
 150    acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
 151    acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
 152    *slen = avail - src_len;
 153
 154    return 1;
 155}
 156
 157/* triggered by SCLP's write_event_data
 158 *  - write console data to character layer
 159 *  returns < 0 if an error occurred
 160 */
 161static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
 162                                  size_t len)
 163{
 164    SCLPConsole *scon = SCLP_CONSOLE(event);
 165
 166    if (!scon->chr) {
 167        /* If there's no backend, we can just say we consumed all data. */
 168        return len;
 169    }
 170
 171    return qemu_chr_fe_write_all(scon->chr, buf, len);
 172}
 173
 174static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
 175{
 176    int rc;
 177    int length;
 178    ssize_t written;
 179    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
 180
 181    length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
 182    written = write_console_data(event, (uint8_t *)acd->data, length);
 183
 184    rc = SCLP_RC_NORMAL_COMPLETION;
 185    /* set event buffer accepted flag */
 186    evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
 187
 188    /* written will be zero if a pty is not connected - don't treat as error */
 189    if (written < 0) {
 190        /* event buffer not accepted due to error in character layer */
 191        evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
 192        rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
 193    }
 194
 195    return rc;
 196}
 197
 198static const VMStateDescription vmstate_sclpconsole = {
 199    .name = "sclpconsole",
 200    .version_id = 0,
 201    .minimum_version_id = 0,
 202    .fields = (VMStateField[]) {
 203        VMSTATE_BOOL(event.event_pending, SCLPConsole),
 204        VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
 205        VMSTATE_UINT32(iov_sclp, SCLPConsole),
 206        VMSTATE_UINT32(iov_bs, SCLPConsole),
 207        VMSTATE_UINT32(iov_data_len, SCLPConsole),
 208        VMSTATE_UINT32(iov_sclp_rest, SCLPConsole),
 209        VMSTATE_END_OF_LIST()
 210     }
 211};
 212
 213/* qemu object creation and initialization functions */
 214
 215/* tell character layer our call-back functions */
 216
 217static int console_init(SCLPEvent *event)
 218{
 219    static bool console_available;
 220
 221    SCLPConsole *scon = SCLP_CONSOLE(event);
 222
 223    if (console_available) {
 224        error_report("Multiple VT220 operator consoles are not supported");
 225        return -1;
 226    }
 227    console_available = true;
 228    if (scon->chr) {
 229        qemu_chr_add_handlers(scon->chr, chr_can_read,
 230                              chr_read, NULL, scon);
 231    }
 232
 233    return 0;
 234}
 235
 236static void console_reset(DeviceState *dev)
 237{
 238   SCLPEvent *event = SCLP_EVENT(dev);
 239   SCLPConsole *scon = SCLP_CONSOLE(event);
 240
 241   event->event_pending = false;
 242   scon->iov_sclp = 0;
 243   scon->iov_bs = 0;
 244   scon->iov_data_len = 0;
 245   scon->iov_sclp_rest = 0;
 246   scon->notify = false;
 247}
 248
 249static int console_exit(SCLPEvent *event)
 250{
 251    return 0;
 252}
 253
 254static Property console_properties[] = {
 255    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
 256    DEFINE_PROP_END_OF_LIST(),
 257};
 258
 259static void console_class_init(ObjectClass *klass, void *data)
 260{
 261    DeviceClass *dc = DEVICE_CLASS(klass);
 262    SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
 263
 264    dc->props = console_properties;
 265    dc->reset = console_reset;
 266    dc->vmsd = &vmstate_sclpconsole;
 267    ec->init = console_init;
 268    ec->exit = console_exit;
 269    ec->get_send_mask = send_mask;
 270    ec->get_receive_mask = receive_mask;
 271    ec->can_handle_event = can_handle_event;
 272    ec->read_event_data = read_event_data;
 273    ec->write_event_data = write_event_data;
 274    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
 275}
 276
 277static const TypeInfo sclp_console_info = {
 278    .name          = "sclpconsole",
 279    .parent        = TYPE_SCLP_EVENT,
 280    .instance_size = sizeof(SCLPConsole),
 281    .class_init    = console_class_init,
 282    .class_size    = sizeof(SCLPEventClass),
 283};
 284
 285static void register_types(void)
 286{
 287    type_register_static(&sclp_console_info);
 288}
 289
 290type_init(register_types)
 291