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 15130c57c0SHeinz Graalfs #include <hw/qdev.h> 161de7afc9SPaolo Bonzini #include "qemu/thread.h" 17b4a42f81SPaolo Bonzini #include "qemu/error-report.h" 18130c57c0SHeinz Graalfs 1983c9f4caSPaolo Bonzini #include "hw/s390x/sclp.h" 2083c9f4caSPaolo Bonzini #include "hw/s390x/event-facility.h" 21dccfcd0eSPaolo Bonzini #include "sysemu/char.h" 22130c57c0SHeinz Graalfs 23130c57c0SHeinz Graalfs typedef struct ASCIIConsoleData { 24130c57c0SHeinz Graalfs EventBufferHeader ebh; 25130c57c0SHeinz Graalfs char data[0]; 26130c57c0SHeinz Graalfs } QEMU_PACKED ASCIIConsoleData; 27130c57c0SHeinz Graalfs 28130c57c0SHeinz Graalfs /* max size for ASCII data in 4K SCCB page */ 29130c57c0SHeinz Graalfs #define SIZE_BUFFER_VT220 4080 30130c57c0SHeinz Graalfs 31130c57c0SHeinz Graalfs typedef struct SCLPConsole { 32130c57c0SHeinz Graalfs SCLPEvent event; 33130c57c0SHeinz Graalfs CharDriverState *chr; 34130c57c0SHeinz Graalfs /* io vector */ 35130c57c0SHeinz Graalfs uint8_t *iov; /* iov buffer pointer */ 36130c57c0SHeinz Graalfs uint8_t *iov_sclp; /* pointer to SCLP read offset */ 37130c57c0SHeinz Graalfs uint8_t *iov_bs; /* pointer byte stream read offset */ 38130c57c0SHeinz Graalfs uint32_t iov_data_len; /* length of byte stream in buffer */ 39130c57c0SHeinz Graalfs uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */ 40130c57c0SHeinz Graalfs qemu_irq irq_read_vt220; 41130c57c0SHeinz Graalfs } SCLPConsole; 42130c57c0SHeinz Graalfs 43130c57c0SHeinz Graalfs /* character layer call-back functions */ 44130c57c0SHeinz Graalfs 45130c57c0SHeinz Graalfs /* Return number of bytes that fit into iov buffer */ 46130c57c0SHeinz Graalfs static int chr_can_read(void *opaque) 47130c57c0SHeinz Graalfs { 48130c57c0SHeinz Graalfs SCLPConsole *scon = opaque; 49130c57c0SHeinz Graalfs 50760794f7SChristian Borntraeger return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0; 51130c57c0SHeinz Graalfs } 52130c57c0SHeinz Graalfs 53130c57c0SHeinz Graalfs /* Receive n bytes from character layer, save in iov buffer, 54130c57c0SHeinz Graalfs * and set event pending */ 55130c57c0SHeinz Graalfs static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf, 56130c57c0SHeinz Graalfs int size) 57130c57c0SHeinz Graalfs { 58130c57c0SHeinz Graalfs assert(scon->iov); 59130c57c0SHeinz Graalfs 60130c57c0SHeinz Graalfs /* read data must fit into current buffer */ 61130c57c0SHeinz Graalfs assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len); 62130c57c0SHeinz Graalfs 63130c57c0SHeinz Graalfs /* put byte-stream from character layer into buffer */ 64130c57c0SHeinz Graalfs memcpy(scon->iov_bs, buf, size); 65130c57c0SHeinz Graalfs scon->iov_data_len += size; 66130c57c0SHeinz Graalfs scon->iov_sclp_rest += size; 67130c57c0SHeinz Graalfs scon->iov_bs += size; 68130c57c0SHeinz Graalfs scon->event.event_pending = true; 69130c57c0SHeinz Graalfs } 70130c57c0SHeinz Graalfs 71130c57c0SHeinz Graalfs /* Send data from a char device over to the guest */ 72130c57c0SHeinz Graalfs static void chr_read(void *opaque, const uint8_t *buf, int size) 73130c57c0SHeinz Graalfs { 74130c57c0SHeinz Graalfs SCLPConsole *scon = opaque; 75130c57c0SHeinz Graalfs 76130c57c0SHeinz Graalfs assert(scon); 77130c57c0SHeinz Graalfs 78130c57c0SHeinz Graalfs receive_from_chr_layer(scon, buf, size); 79130c57c0SHeinz Graalfs /* trigger SCLP read operation */ 80130c57c0SHeinz Graalfs qemu_irq_raise(scon->irq_read_vt220); 81130c57c0SHeinz Graalfs } 82130c57c0SHeinz Graalfs 83130c57c0SHeinz Graalfs static void chr_event(void *opaque, int event) 84130c57c0SHeinz Graalfs { 85130c57c0SHeinz Graalfs SCLPConsole *scon = opaque; 86130c57c0SHeinz Graalfs 87130c57c0SHeinz Graalfs switch (event) { 88130c57c0SHeinz Graalfs case CHR_EVENT_OPENED: 89130c57c0SHeinz Graalfs if (!scon->iov) { 90130c57c0SHeinz Graalfs scon->iov = g_malloc0(SIZE_BUFFER_VT220); 91130c57c0SHeinz Graalfs scon->iov_sclp = scon->iov; 92130c57c0SHeinz Graalfs scon->iov_bs = scon->iov; 93130c57c0SHeinz Graalfs scon->iov_data_len = 0; 94130c57c0SHeinz Graalfs scon->iov_sclp_rest = 0; 95130c57c0SHeinz Graalfs } 96130c57c0SHeinz Graalfs break; 97130c57c0SHeinz Graalfs case CHR_EVENT_CLOSED: 98130c57c0SHeinz Graalfs if (scon->iov) { 99130c57c0SHeinz Graalfs g_free(scon->iov); 100130c57c0SHeinz Graalfs scon->iov = NULL; 101130c57c0SHeinz Graalfs } 102130c57c0SHeinz Graalfs break; 103130c57c0SHeinz Graalfs } 104130c57c0SHeinz Graalfs } 105130c57c0SHeinz Graalfs 106130c57c0SHeinz Graalfs /* functions to be called by event facility */ 107130c57c0SHeinz Graalfs 108130c57c0SHeinz Graalfs static int event_type(void) 109130c57c0SHeinz Graalfs { 110130c57c0SHeinz Graalfs return SCLP_EVENT_ASCII_CONSOLE_DATA; 111130c57c0SHeinz Graalfs } 112130c57c0SHeinz Graalfs 113130c57c0SHeinz Graalfs static unsigned int send_mask(void) 114130c57c0SHeinz Graalfs { 115130c57c0SHeinz Graalfs return SCLP_EVENT_MASK_MSG_ASCII; 116130c57c0SHeinz Graalfs } 117130c57c0SHeinz Graalfs 118130c57c0SHeinz Graalfs static unsigned int receive_mask(void) 119130c57c0SHeinz Graalfs { 120130c57c0SHeinz Graalfs return SCLP_EVENT_MASK_MSG_ASCII; 121130c57c0SHeinz Graalfs } 122130c57c0SHeinz Graalfs 123130c57c0SHeinz Graalfs /* triggered by SCLP's read_event_data - 124130c57c0SHeinz Graalfs * copy console data byte-stream into provided (SCLP) buffer 125130c57c0SHeinz Graalfs */ 126130c57c0SHeinz Graalfs static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, 127130c57c0SHeinz Graalfs int avail) 128130c57c0SHeinz Graalfs { 129130c57c0SHeinz Graalfs SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event); 130130c57c0SHeinz Graalfs 131130c57c0SHeinz Graalfs /* first byte is hex 0 saying an ascii string follows */ 132130c57c0SHeinz Graalfs *buf++ = '\0'; 133130c57c0SHeinz Graalfs avail--; 134130c57c0SHeinz Graalfs /* if all data fit into provided SCLP buffer */ 135130c57c0SHeinz Graalfs if (avail >= cons->iov_sclp_rest) { 136130c57c0SHeinz Graalfs /* copy character byte-stream to SCLP buffer */ 137130c57c0SHeinz Graalfs memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest); 138130c57c0SHeinz Graalfs *size = cons->iov_sclp_rest + 1; 139130c57c0SHeinz Graalfs cons->iov_sclp = cons->iov; 140130c57c0SHeinz Graalfs cons->iov_bs = cons->iov; 141130c57c0SHeinz Graalfs cons->iov_data_len = 0; 142130c57c0SHeinz Graalfs cons->iov_sclp_rest = 0; 143130c57c0SHeinz Graalfs event->event_pending = false; 144130c57c0SHeinz Graalfs /* data provided and no more data pending */ 145130c57c0SHeinz Graalfs } else { 146130c57c0SHeinz Graalfs /* if provided buffer is too small, just copy part */ 147130c57c0SHeinz Graalfs memcpy(buf, cons->iov_sclp, avail); 148130c57c0SHeinz Graalfs *size = avail + 1; 149130c57c0SHeinz Graalfs cons->iov_sclp_rest -= avail; 150130c57c0SHeinz Graalfs cons->iov_sclp += avail; 151130c57c0SHeinz Graalfs /* more data pending */ 152130c57c0SHeinz Graalfs } 153130c57c0SHeinz Graalfs } 154130c57c0SHeinz Graalfs 155130c57c0SHeinz Graalfs static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, 156130c57c0SHeinz Graalfs int *slen) 157130c57c0SHeinz Graalfs { 158130c57c0SHeinz Graalfs int avail; 159130c57c0SHeinz Graalfs size_t src_len; 160130c57c0SHeinz Graalfs uint8_t *to; 161130c57c0SHeinz Graalfs ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; 162130c57c0SHeinz Graalfs 163130c57c0SHeinz Graalfs if (!event->event_pending) { 164130c57c0SHeinz Graalfs /* no data pending */ 165130c57c0SHeinz Graalfs return 0; 166130c57c0SHeinz Graalfs } 167130c57c0SHeinz Graalfs 168130c57c0SHeinz Graalfs to = (uint8_t *)&acd->data; 169130c57c0SHeinz Graalfs avail = *slen - sizeof(ASCIIConsoleData); 170130c57c0SHeinz Graalfs get_console_data(event, to, &src_len, avail); 171130c57c0SHeinz Graalfs 172130c57c0SHeinz Graalfs acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len); 173130c57c0SHeinz Graalfs acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 174130c57c0SHeinz Graalfs acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; 175130c57c0SHeinz Graalfs *slen = avail - src_len; 176130c57c0SHeinz Graalfs 177130c57c0SHeinz Graalfs return 1; 178130c57c0SHeinz Graalfs } 179130c57c0SHeinz Graalfs 180130c57c0SHeinz Graalfs /* triggered by SCLP's write_event_data 1818367a14fSStefan Weil * - write console data to character layer 1828367a14fSStefan Weil * returns < 0 if an error occurred 183130c57c0SHeinz Graalfs */ 184130c57c0SHeinz Graalfs static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, 185130c57c0SHeinz Graalfs size_t len) 186130c57c0SHeinz Graalfs { 187130c57c0SHeinz Graalfs SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); 188130c57c0SHeinz Graalfs 189130c57c0SHeinz Graalfs if (!scon->chr) { 190130c57c0SHeinz Graalfs /* If there's no backend, we can just say we consumed all data. */ 191130c57c0SHeinz Graalfs return len; 192130c57c0SHeinz Graalfs } 193130c57c0SHeinz Graalfs 194*2e142114SHeinz Graalfs return qemu_chr_fe_write_all(scon->chr, buf, len); 195130c57c0SHeinz Graalfs } 196130c57c0SHeinz Graalfs 197130c57c0SHeinz Graalfs static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr) 198130c57c0SHeinz Graalfs { 199130c57c0SHeinz Graalfs int rc; 200130c57c0SHeinz Graalfs int length; 201130c57c0SHeinz Graalfs ssize_t written; 202130c57c0SHeinz Graalfs ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; 203130c57c0SHeinz Graalfs 204130c57c0SHeinz Graalfs length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader); 205130c57c0SHeinz Graalfs written = write_console_data(event, (uint8_t *)acd->data, length); 206130c57c0SHeinz Graalfs 207130c57c0SHeinz Graalfs rc = SCLP_RC_NORMAL_COMPLETION; 208130c57c0SHeinz Graalfs /* set event buffer accepted flag */ 209130c57c0SHeinz Graalfs evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED; 210130c57c0SHeinz Graalfs 211130c57c0SHeinz Graalfs /* written will be zero if a pty is not connected - don't treat as error */ 212130c57c0SHeinz Graalfs if (written < 0) { 213130c57c0SHeinz Graalfs /* event buffer not accepted due to error in character layer */ 214130c57c0SHeinz Graalfs evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED); 215130c57c0SHeinz Graalfs rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK; 216130c57c0SHeinz Graalfs } 217130c57c0SHeinz Graalfs 218130c57c0SHeinz Graalfs return rc; 219130c57c0SHeinz Graalfs } 220130c57c0SHeinz Graalfs 2219944d320SPaolo Bonzini static void trigger_ascii_console_data(void *opaque, int n, int level) 222130c57c0SHeinz Graalfs { 223130c57c0SHeinz Graalfs sclp_service_interrupt(0); 224130c57c0SHeinz Graalfs } 225130c57c0SHeinz Graalfs 226130c57c0SHeinz Graalfs /* qemu object creation and initialization functions */ 227130c57c0SHeinz Graalfs 228130c57c0SHeinz Graalfs /* tell character layer our call-back functions */ 229130c57c0SHeinz Graalfs static int console_init(SCLPEvent *event) 230130c57c0SHeinz Graalfs { 231130c57c0SHeinz Graalfs static bool console_available; 232130c57c0SHeinz Graalfs 233130c57c0SHeinz Graalfs SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event); 234130c57c0SHeinz Graalfs 235130c57c0SHeinz Graalfs if (console_available) { 236130c57c0SHeinz Graalfs error_report("Multiple VT220 operator consoles are not supported"); 237130c57c0SHeinz Graalfs return -1; 238130c57c0SHeinz Graalfs } 239130c57c0SHeinz Graalfs console_available = true; 240130c57c0SHeinz Graalfs event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA; 241130c57c0SHeinz Graalfs if (scon->chr) { 242130c57c0SHeinz Graalfs qemu_chr_add_handlers(scon->chr, chr_can_read, 243130c57c0SHeinz Graalfs chr_read, chr_event, scon); 244130c57c0SHeinz Graalfs } 245130c57c0SHeinz Graalfs scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data, 246130c57c0SHeinz Graalfs NULL, 1); 247130c57c0SHeinz Graalfs 248130c57c0SHeinz Graalfs return 0; 249130c57c0SHeinz Graalfs } 250130c57c0SHeinz Graalfs 251130c57c0SHeinz Graalfs static int console_exit(SCLPEvent *event) 252130c57c0SHeinz Graalfs { 253130c57c0SHeinz Graalfs return 0; 254130c57c0SHeinz Graalfs } 255130c57c0SHeinz Graalfs 256130c57c0SHeinz Graalfs static Property console_properties[] = { 257130c57c0SHeinz Graalfs DEFINE_PROP_CHR("chardev", SCLPConsole, chr), 258130c57c0SHeinz Graalfs DEFINE_PROP_END_OF_LIST(), 259130c57c0SHeinz Graalfs }; 260130c57c0SHeinz Graalfs 261130c57c0SHeinz Graalfs static void console_class_init(ObjectClass *klass, void *data) 262130c57c0SHeinz Graalfs { 263130c57c0SHeinz Graalfs DeviceClass *dc = DEVICE_CLASS(klass); 264130c57c0SHeinz Graalfs SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); 265130c57c0SHeinz Graalfs 266130c57c0SHeinz Graalfs dc->props = console_properties; 267130c57c0SHeinz Graalfs ec->init = console_init; 268130c57c0SHeinz Graalfs ec->exit = console_exit; 269130c57c0SHeinz Graalfs ec->get_send_mask = send_mask; 270130c57c0SHeinz Graalfs ec->get_receive_mask = receive_mask; 271130c57c0SHeinz Graalfs ec->event_type = event_type; 272130c57c0SHeinz Graalfs ec->read_event_data = read_event_data; 273130c57c0SHeinz Graalfs ec->write_event_data = write_event_data; 274130c57c0SHeinz Graalfs } 275130c57c0SHeinz Graalfs 2768c43a6f0SAndreas Färber static const TypeInfo sclp_console_info = { 277130c57c0SHeinz Graalfs .name = "sclpconsole", 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