1130c57c0SHeinz Graalfs /* 2130c57c0SHeinz Graalfs * SCLP event type 3130c57c0SHeinz Graalfs * Ascii Console Data (VT220 Console) 4130c57c0SHeinz Graalfs * 5130c57c0SHeinz Graalfs * Copyright IBM, Corp. 2012 6130c57c0SHeinz Graalfs * 7130c57c0SHeinz Graalfs * Authors: 8130c57c0SHeinz Graalfs * Heinz Graalfs <graalfs@de.ibm.com> 9130c57c0SHeinz Graalfs * 10130c57c0SHeinz Graalfs * This work is licensed under the terms of the GNU GPL, version 2 or (at your 11130c57c0SHeinz Graalfs * option) any later version. See the COPYING file in the top-level directory. 12130c57c0SHeinz Graalfs * 13130c57c0SHeinz Graalfs */ 14130c57c0SHeinz Graalfs 159615495aSPeter Maydell #include "qemu/osdep.h" 161de7afc9SPaolo Bonzini #include "qemu/thread.h" 17b4a42f81SPaolo Bonzini #include "qemu/error-report.h" 180b8fa32fSMarkus Armbruster #include "qemu/module.h" 19130c57c0SHeinz Graalfs 2083c9f4caSPaolo Bonzini #include "hw/s390x/sclp.h" 21d6454270SMarkus Armbruster #include "migration/vmstate.h" 22a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 23ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h" 2483c9f4caSPaolo Bonzini #include "hw/s390x/event-facility.h" 254d43a603SMarc-André Lureau #include "chardev/char-fe.h" 26db1015e9SEduardo Habkost #include "qom/object.h" 27130c57c0SHeinz Graalfs 28130c57c0SHeinz Graalfs typedef struct ASCIIConsoleData { 29130c57c0SHeinz Graalfs EventBufferHeader ebh; 30880a7817SPhilippe Mathieu-Daudé char data[]; 31130c57c0SHeinz Graalfs } QEMU_PACKED ASCIIConsoleData; 32130c57c0SHeinz Graalfs 33130c57c0SHeinz Graalfs /* max size for ASCII data in 4K SCCB page */ 34130c57c0SHeinz Graalfs #define SIZE_BUFFER_VT220 4080 35130c57c0SHeinz Graalfs 36db1015e9SEduardo Habkost struct SCLPConsole { 37130c57c0SHeinz Graalfs SCLPEvent event; 38becdfa00SMarc-André Lureau CharBackend chr; 39ea9ad3e9SHeinz Graalfs uint8_t iov[SIZE_BUFFER_VT220]; 40ea9ad3e9SHeinz Graalfs uint32_t iov_sclp; /* offset in buf for SCLP read operation */ 41ea9ad3e9SHeinz Graalfs uint32_t iov_bs; /* offset in buf for char layer read operation */ 42130c57c0SHeinz Graalfs uint32_t iov_data_len; /* length of byte stream in buffer */ 43130c57c0SHeinz Graalfs uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */ 44bb3e9e1fSHeinz Graalfs bool notify; /* qemu_notify_event() req'd if true */ 45db1015e9SEduardo Habkost }; 46db1015e9SEduardo Habkost typedef struct SCLPConsole SCLPConsole; 47130c57c0SHeinz Graalfs 483f6ec642Sxiaoqiang zhao #define TYPE_SCLP_CONSOLE "sclpconsole" 498110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(SCLPConsole, SCLP_CONSOLE, 508110fa1dSEduardo Habkost TYPE_SCLP_CONSOLE) 513f6ec642Sxiaoqiang zhao 52130c57c0SHeinz Graalfs /* character layer call-back functions */ 53130c57c0SHeinz Graalfs 54130c57c0SHeinz Graalfs /* Return number of bytes that fit into iov buffer */ 55130c57c0SHeinz Graalfs static int chr_can_read(void *opaque) 56130c57c0SHeinz Graalfs { 57130c57c0SHeinz Graalfs SCLPConsole *scon = opaque; 58bb3e9e1fSHeinz Graalfs int avail = SIZE_BUFFER_VT220 - scon->iov_data_len; 59130c57c0SHeinz Graalfs 60bb3e9e1fSHeinz Graalfs if (avail == 0) { 61bb3e9e1fSHeinz Graalfs scon->notify = true; 62bb3e9e1fSHeinz Graalfs } 63bb3e9e1fSHeinz Graalfs return avail; 64130c57c0SHeinz Graalfs } 65130c57c0SHeinz Graalfs 66b074e622SChristian Borntraeger /* Send data from a char device over to the guest */ 67b074e622SChristian Borntraeger static void chr_read(void *opaque, const uint8_t *buf, int size) 68130c57c0SHeinz Graalfs { 69b074e622SChristian Borntraeger SCLPConsole *scon = opaque; 70b074e622SChristian Borntraeger 71b074e622SChristian Borntraeger assert(scon); 72130c57c0SHeinz Graalfs /* read data must fit into current buffer */ 73130c57c0SHeinz Graalfs assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len); 74130c57c0SHeinz Graalfs 75130c57c0SHeinz Graalfs /* put byte-stream from character layer into buffer */ 76ea9ad3e9SHeinz Graalfs memcpy(&scon->iov[scon->iov_bs], buf, size); 77130c57c0SHeinz Graalfs scon->iov_data_len += size; 78130c57c0SHeinz Graalfs scon->iov_sclp_rest += size; 79130c57c0SHeinz Graalfs scon->iov_bs += size; 80130c57c0SHeinz Graalfs scon->event.event_pending = true; 81b074e622SChristian Borntraeger sclp_service_interrupt(0); 82130c57c0SHeinz Graalfs } 83130c57c0SHeinz Graalfs 84130c57c0SHeinz Graalfs /* functions to be called by event facility */ 85130c57c0SHeinz Graalfs 86c3d9f24aSChristian Borntraeger static bool can_handle_event(uint8_t type) 87130c57c0SHeinz Graalfs { 88c3d9f24aSChristian Borntraeger return type == SCLP_EVENT_ASCII_CONSOLE_DATA; 89130c57c0SHeinz Graalfs } 90130c57c0SHeinz Graalfs 911ffed98fSClaudio Imbrenda static sccb_mask_t send_mask(void) 92130c57c0SHeinz Graalfs { 93130c57c0SHeinz Graalfs return SCLP_EVENT_MASK_MSG_ASCII; 94130c57c0SHeinz Graalfs } 95130c57c0SHeinz Graalfs 961ffed98fSClaudio Imbrenda static sccb_mask_t receive_mask(void) 97130c57c0SHeinz Graalfs { 98130c57c0SHeinz Graalfs return SCLP_EVENT_MASK_MSG_ASCII; 99130c57c0SHeinz Graalfs } 100130c57c0SHeinz Graalfs 101130c57c0SHeinz Graalfs /* triggered by SCLP's read_event_data - 102130c57c0SHeinz Graalfs * copy console data byte-stream into provided (SCLP) buffer 103130c57c0SHeinz Graalfs */ 104130c57c0SHeinz Graalfs static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, 105130c57c0SHeinz Graalfs int avail) 106130c57c0SHeinz Graalfs { 1073f6ec642Sxiaoqiang zhao SCLPConsole *cons = SCLP_CONSOLE(event); 108130c57c0SHeinz Graalfs 109130c57c0SHeinz Graalfs /* first byte is hex 0 saying an ascii string follows */ 110130c57c0SHeinz Graalfs *buf++ = '\0'; 111130c57c0SHeinz Graalfs avail--; 112130c57c0SHeinz Graalfs /* if all data fit into provided SCLP buffer */ 113130c57c0SHeinz Graalfs if (avail >= cons->iov_sclp_rest) { 114130c57c0SHeinz Graalfs /* copy character byte-stream to SCLP buffer */ 115ea9ad3e9SHeinz Graalfs memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest); 116130c57c0SHeinz Graalfs *size = cons->iov_sclp_rest + 1; 117ea9ad3e9SHeinz Graalfs cons->iov_sclp = 0; 118ea9ad3e9SHeinz Graalfs cons->iov_bs = 0; 119130c57c0SHeinz Graalfs cons->iov_data_len = 0; 120130c57c0SHeinz Graalfs cons->iov_sclp_rest = 0; 121130c57c0SHeinz Graalfs event->event_pending = false; 122130c57c0SHeinz Graalfs /* data provided and no more data pending */ 123130c57c0SHeinz Graalfs } else { 124130c57c0SHeinz Graalfs /* if provided buffer is too small, just copy part */ 125ea9ad3e9SHeinz Graalfs memcpy(buf, &cons->iov[cons->iov_sclp], avail); 126130c57c0SHeinz Graalfs *size = avail + 1; 127130c57c0SHeinz Graalfs cons->iov_sclp_rest -= avail; 128130c57c0SHeinz Graalfs cons->iov_sclp += avail; 129130c57c0SHeinz Graalfs /* more data pending */ 130130c57c0SHeinz Graalfs } 131bb3e9e1fSHeinz Graalfs if (cons->notify) { 132bb3e9e1fSHeinz Graalfs cons->notify = false; 133bb3e9e1fSHeinz Graalfs qemu_notify_event(); 134bb3e9e1fSHeinz Graalfs } 135130c57c0SHeinz Graalfs } 136130c57c0SHeinz Graalfs 137130c57c0SHeinz Graalfs static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, 138130c57c0SHeinz Graalfs int *slen) 139130c57c0SHeinz Graalfs { 140130c57c0SHeinz Graalfs int avail; 141130c57c0SHeinz Graalfs size_t src_len; 142130c57c0SHeinz Graalfs uint8_t *to; 143130c57c0SHeinz Graalfs ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; 144130c57c0SHeinz Graalfs 145130c57c0SHeinz Graalfs if (!event->event_pending) { 146130c57c0SHeinz Graalfs /* no data pending */ 147130c57c0SHeinz Graalfs return 0; 148130c57c0SHeinz Graalfs } 149130c57c0SHeinz Graalfs 150130c57c0SHeinz Graalfs to = (uint8_t *)&acd->data; 151130c57c0SHeinz Graalfs avail = *slen - sizeof(ASCIIConsoleData); 152130c57c0SHeinz Graalfs get_console_data(event, to, &src_len, avail); 153130c57c0SHeinz Graalfs 154130c57c0SHeinz Graalfs acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len); 155130c57c0SHeinz Graalfs acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 156130c57c0SHeinz Graalfs acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; 157130c57c0SHeinz Graalfs *slen = avail - src_len; 158130c57c0SHeinz Graalfs 159130c57c0SHeinz Graalfs return 1; 160130c57c0SHeinz Graalfs } 161130c57c0SHeinz Graalfs 162130c57c0SHeinz Graalfs /* triggered by SCLP's write_event_data 1638367a14fSStefan Weil * - write console data to character layer 1648367a14fSStefan Weil * returns < 0 if an error occurred 165130c57c0SHeinz Graalfs */ 166130c57c0SHeinz Graalfs static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, 167130c57c0SHeinz Graalfs size_t len) 168130c57c0SHeinz Graalfs { 1693f6ec642Sxiaoqiang zhao SCLPConsole *scon = SCLP_CONSOLE(event); 170130c57c0SHeinz Graalfs 17130650701SAnton Nefedov if (!qemu_chr_fe_backend_connected(&scon->chr)) { 172130c57c0SHeinz Graalfs /* If there's no backend, we can just say we consumed all data. */ 173130c57c0SHeinz Graalfs return len; 174130c57c0SHeinz Graalfs } 175130c57c0SHeinz Graalfs 1766ab3fc32SDaniel P. Berrange /* XXX this blocks entire thread. Rewrite to use 1776ab3fc32SDaniel P. Berrange * qemu_chr_fe_write and background I/O callbacks */ 1785345fdb4SMarc-André Lureau return qemu_chr_fe_write_all(&scon->chr, buf, len); 179130c57c0SHeinz Graalfs } 180130c57c0SHeinz Graalfs 181130c57c0SHeinz Graalfs static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr) 182130c57c0SHeinz Graalfs { 183130c57c0SHeinz Graalfs int rc; 184130c57c0SHeinz Graalfs int length; 185130c57c0SHeinz Graalfs ssize_t written; 186130c57c0SHeinz Graalfs ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; 187130c57c0SHeinz Graalfs 188130c57c0SHeinz Graalfs length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader); 189130c57c0SHeinz Graalfs written = write_console_data(event, (uint8_t *)acd->data, length); 190130c57c0SHeinz Graalfs 191130c57c0SHeinz Graalfs rc = SCLP_RC_NORMAL_COMPLETION; 192130c57c0SHeinz Graalfs /* set event buffer accepted flag */ 193130c57c0SHeinz Graalfs evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED; 194130c57c0SHeinz Graalfs 195130c57c0SHeinz Graalfs /* written will be zero if a pty is not connected - don't treat as error */ 196130c57c0SHeinz Graalfs if (written < 0) { 197130c57c0SHeinz Graalfs /* event buffer not accepted due to error in character layer */ 198130c57c0SHeinz Graalfs evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED); 199130c57c0SHeinz Graalfs rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK; 200130c57c0SHeinz Graalfs } 201130c57c0SHeinz Graalfs 202130c57c0SHeinz Graalfs return rc; 203130c57c0SHeinz Graalfs } 204130c57c0SHeinz Graalfs 205cb335bebSHeinz Graalfs static const VMStateDescription vmstate_sclpconsole = { 206cb335bebSHeinz Graalfs .name = "sclpconsole", 207cb335bebSHeinz Graalfs .version_id = 0, 208cb335bebSHeinz Graalfs .minimum_version_id = 0, 2092f6cab05SRichard Henderson .fields = (const VMStateField[]) { 210cb335bebSHeinz Graalfs VMSTATE_BOOL(event.event_pending, SCLPConsole), 211cb335bebSHeinz Graalfs VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220), 212cb335bebSHeinz Graalfs VMSTATE_UINT32(iov_sclp, SCLPConsole), 213cb335bebSHeinz Graalfs VMSTATE_UINT32(iov_bs, SCLPConsole), 214cb335bebSHeinz Graalfs VMSTATE_UINT32(iov_data_len, SCLPConsole), 215cb335bebSHeinz Graalfs VMSTATE_UINT32(iov_sclp_rest, SCLPConsole), 216cb335bebSHeinz Graalfs VMSTATE_END_OF_LIST() 217cb335bebSHeinz Graalfs } 218cb335bebSHeinz Graalfs }; 219cb335bebSHeinz Graalfs 220130c57c0SHeinz Graalfs /* qemu object creation and initialization functions */ 221130c57c0SHeinz Graalfs 222130c57c0SHeinz Graalfs /* tell character layer our call-back functions */ 223cb335bebSHeinz Graalfs 224130c57c0SHeinz Graalfs static int console_init(SCLPEvent *event) 225130c57c0SHeinz Graalfs { 226130c57c0SHeinz Graalfs static bool console_available; 227130c57c0SHeinz Graalfs 2283f6ec642Sxiaoqiang zhao SCLPConsole *scon = SCLP_CONSOLE(event); 229130c57c0SHeinz Graalfs 230130c57c0SHeinz Graalfs if (console_available) { 231130c57c0SHeinz Graalfs error_report("Multiple VT220 operator consoles are not supported"); 232130c57c0SHeinz Graalfs return -1; 233130c57c0SHeinz Graalfs } 234130c57c0SHeinz Graalfs console_available = true; 2355345fdb4SMarc-André Lureau qemu_chr_fe_set_handlers(&scon->chr, chr_can_read, 23681517ba3SAnton Nefedov chr_read, NULL, NULL, scon, NULL, true); 237130c57c0SHeinz Graalfs 238130c57c0SHeinz Graalfs return 0; 239130c57c0SHeinz Graalfs } 240130c57c0SHeinz Graalfs 2413af6de32SHeinz Graalfs static void console_reset(DeviceState *dev) 2423af6de32SHeinz Graalfs { 2433af6de32SHeinz Graalfs SCLPEvent *event = SCLP_EVENT(dev); 2443f6ec642Sxiaoqiang zhao SCLPConsole *scon = SCLP_CONSOLE(event); 2453af6de32SHeinz Graalfs 2463af6de32SHeinz Graalfs event->event_pending = false; 2473af6de32SHeinz Graalfs scon->iov_sclp = 0; 2483af6de32SHeinz Graalfs scon->iov_bs = 0; 2493af6de32SHeinz Graalfs scon->iov_data_len = 0; 2503af6de32SHeinz Graalfs scon->iov_sclp_rest = 0; 251bb3e9e1fSHeinz Graalfs scon->notify = false; 2523af6de32SHeinz Graalfs } 2533af6de32SHeinz Graalfs 254130c57c0SHeinz Graalfs static Property console_properties[] = { 255130c57c0SHeinz Graalfs DEFINE_PROP_CHR("chardev", SCLPConsole, chr), 256130c57c0SHeinz Graalfs DEFINE_PROP_END_OF_LIST(), 257130c57c0SHeinz Graalfs }; 258130c57c0SHeinz Graalfs 259130c57c0SHeinz Graalfs static void console_class_init(ObjectClass *klass, void *data) 260130c57c0SHeinz Graalfs { 261130c57c0SHeinz Graalfs DeviceClass *dc = DEVICE_CLASS(klass); 262130c57c0SHeinz Graalfs SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); 263130c57c0SHeinz Graalfs 2644f67d30bSMarc-André Lureau device_class_set_props(dc, console_properties); 265*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, console_reset); 266cb335bebSHeinz Graalfs dc->vmsd = &vmstate_sclpconsole; 267130c57c0SHeinz Graalfs ec->init = console_init; 268130c57c0SHeinz Graalfs ec->get_send_mask = send_mask; 269130c57c0SHeinz Graalfs ec->get_receive_mask = receive_mask; 270c3d9f24aSChristian Borntraeger ec->can_handle_event = can_handle_event; 271130c57c0SHeinz Graalfs ec->read_event_data = read_event_data; 272130c57c0SHeinz Graalfs ec->write_event_data = write_event_data; 273183f6b8dSCornelia Huck set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 274130c57c0SHeinz Graalfs } 275130c57c0SHeinz Graalfs 2768c43a6f0SAndreas Färber static const TypeInfo sclp_console_info = { 2771a3bae79SEduardo Habkost .name = TYPE_SCLP_CONSOLE, 278130c57c0SHeinz Graalfs .parent = TYPE_SCLP_EVENT, 279130c57c0SHeinz Graalfs .instance_size = sizeof(SCLPConsole), 280130c57c0SHeinz Graalfs .class_init = console_class_init, 281130c57c0SHeinz Graalfs .class_size = sizeof(SCLPEventClass), 282130c57c0SHeinz Graalfs }; 283130c57c0SHeinz Graalfs 284130c57c0SHeinz Graalfs static void register_types(void) 285130c57c0SHeinz Graalfs { 286130c57c0SHeinz Graalfs type_register_static(&sclp_console_info); 287130c57c0SHeinz Graalfs } 288130c57c0SHeinz Graalfs 289130c57c0SHeinz Graalfs type_init(register_types) 290