1 /* 2 * SCLP event types 3 * Operations Command - Line Mode input 4 * Message - Line Mode output 5 * 6 * Copyright IBM, Corp. 2013 7 * 8 * Authors: 9 * Heinz Graalfs <graalfs@linux.vnet.ibm.com> 10 * 11 * This work is licensed under the terms of the GNU GPL, version 2 or (at your 12 * option) any later version. See the COPYING file in the top-level directory. 13 * 14 */ 15 16 #include "hw/qdev.h" 17 #include "qemu/thread.h" 18 #include "qemu/error-report.h" 19 #include "sysemu/char.h" 20 21 #include "hw/s390x/sclp.h" 22 #include "hw/s390x/event-facility.h" 23 #include "hw/s390x/ebcdic.h" 24 25 #define SIZE_BUFFER 4096 26 #define NEWLINE "\n" 27 28 typedef struct OprtnsCommand { 29 EventBufferHeader header; 30 MDMSU message_unit; 31 char data[0]; 32 } QEMU_PACKED OprtnsCommand; 33 34 /* max size for line-mode data in 4K SCCB page */ 35 #define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand)) 36 37 typedef struct SCLPConsoleLM { 38 SCLPEvent event; 39 CharDriverState *chr; 40 bool echo; /* immediate echo of input if true */ 41 uint32_t write_errors; /* errors writing to char layer */ 42 uint32_t length; /* length of byte stream in buffer */ 43 uint8_t buf[SIZE_CONSOLE_BUFFER]; 44 qemu_irq irq_console_read; 45 } SCLPConsoleLM; 46 47 /* 48 * Character layer call-back functions 49 * 50 * Allow 1 character at a time 51 * 52 * Accumulate bytes from character layer in console buffer, 53 * event_pending is set when a newline character is encountered 54 * 55 * The maximum command line length is limited by the maximum 56 * space available in an SCCB 57 */ 58 59 static int chr_can_read(void *opaque) 60 { 61 SCLPConsoleLM *scon = opaque; 62 63 if (scon->event.event_pending) { 64 return 0; 65 } else if (SIZE_CONSOLE_BUFFER - scon->length) { 66 return 1; 67 } 68 return 0; 69 } 70 71 static void receive_from_chr_layer(SCLPConsoleLM *scon, const uint8_t *buf, 72 int size) 73 { 74 assert(size == 1); 75 76 if (*buf == '\r' || *buf == '\n') { 77 scon->event.event_pending = true; 78 return; 79 } 80 scon->buf[scon->length] = *buf; 81 scon->length += 1; 82 if (scon->echo) { 83 qemu_chr_fe_write(scon->chr, buf, size); 84 } 85 } 86 87 /* 88 * Send data from a char device over to the guest 89 */ 90 static void chr_read(void *opaque, const uint8_t *buf, int size) 91 { 92 SCLPConsoleLM *scon = opaque; 93 94 receive_from_chr_layer(scon, buf, size); 95 if (scon->event.event_pending) { 96 /* trigger SCLP read operation */ 97 qemu_irq_raise(scon->irq_console_read); 98 } 99 } 100 101 /* functions to be called by event facility */ 102 103 static bool can_handle_event(uint8_t type) 104 { 105 return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD; 106 } 107 108 static unsigned int send_mask(void) 109 { 110 return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD; 111 } 112 113 static unsigned int receive_mask(void) 114 { 115 return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD; 116 } 117 118 /* 119 * Triggered by SCLP's read_event_data 120 * - convert ASCII byte stream to EBCDIC and 121 * - copy converted data into provided (SCLP) buffer 122 */ 123 static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, 124 int avail) 125 { 126 int len; 127 128 SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event); 129 130 len = cons->length; 131 /* data need to fit into provided SCLP buffer */ 132 if (len > avail) { 133 return 1; 134 } 135 136 ebcdic_put(buf, (char *)&cons->buf, len); 137 *size = len; 138 cons->length = 0; 139 /* data provided and no more data pending */ 140 event->event_pending = false; 141 return 0; 142 } 143 144 static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, 145 int *slen) 146 { 147 int avail, rc; 148 size_t src_len; 149 uint8_t *to; 150 OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr; 151 152 if (!event->event_pending) { 153 /* no data pending */ 154 return 0; 155 } 156 157 to = (uint8_t *)&oc->data; 158 avail = *slen - sizeof(OprtnsCommand); 159 rc = get_console_data(event, to, &src_len, avail); 160 if (rc) { 161 /* data didn't fit, try next SCCB */ 162 return 1; 163 } 164 165 oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU; 166 oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU)); 167 168 oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU; 169 oc->message_unit.cpmsu.length = 170 cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector)); 171 172 oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD; 173 oc->message_unit.text_command.length = 174 cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector))); 175 176 oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG; 177 oc->message_unit.self_def_text_message.length = 178 cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector))); 179 180 oc->message_unit.text_message.key = GDS_KEY_TEXTMSG; 181 oc->message_unit.text_message.length = 182 cpu_to_be16(sizeof(GdsSubvector) + src_len); 183 184 oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len); 185 oc->header.type = SCLP_EVENT_OPRTNS_COMMAND; 186 *slen = avail - src_len; 187 188 return 1; 189 } 190 191 /* 192 * Triggered by SCLP's write_event_data 193 * - write console data to character layer 194 * returns < 0 if an error occurred 195 */ 196 static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) 197 { 198 int ret = 0; 199 const uint8_t *buf_offset; 200 201 SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); 202 203 if (!scon->chr) { 204 /* If there's no backend, we can just say we consumed all data. */ 205 return len; 206 } 207 208 buf_offset = buf; 209 while (len > 0) { 210 ret = qemu_chr_fe_write(scon->chr, buf, len); 211 if (ret == 0) { 212 /* a pty doesn't seem to be connected - no error */ 213 len = 0; 214 } else if (ret == -EAGAIN || (ret > 0 && ret < len)) { 215 len -= ret; 216 buf_offset += ret; 217 } else { 218 len = 0; 219 } 220 } 221 222 return ret; 223 } 224 225 static int process_mdb(SCLPEvent *event, MDBO *mdbo) 226 { 227 int rc; 228 int len; 229 uint8_t buffer[SIZE_BUFFER]; 230 231 len = be16_to_cpu(mdbo->length); 232 len -= sizeof(mdbo->length) + sizeof(mdbo->type) 233 + sizeof(mdbo->mto.line_type_flags) 234 + sizeof(mdbo->mto.alarm_control) 235 + sizeof(mdbo->mto._reserved); 236 237 assert(len <= SIZE_BUFFER); 238 239 /* convert EBCDIC SCLP contents to ASCII console message */ 240 ascii_put(buffer, mdbo->mto.message, len); 241 rc = write_console_data(event, (uint8_t *)NEWLINE, 1); 242 if (rc < 0) { 243 return rc; 244 } 245 return write_console_data(event, buffer, len); 246 } 247 248 static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh) 249 { 250 int len; 251 int written; 252 int errors = 0; 253 MDBO *mdbo; 254 SclpMsg *data = (SclpMsg *) ebh; 255 SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); 256 257 len = be16_to_cpu(data->mdb.header.length); 258 if (len < sizeof(data->mdb.header)) { 259 return SCLP_RC_INCONSISTENT_LENGTHS; 260 } 261 len -= sizeof(data->mdb.header); 262 263 /* first check message buffers */ 264 mdbo = data->mdb.mdbo; 265 while (len > 0) { 266 if (be16_to_cpu(mdbo->length) > len 267 || be16_to_cpu(mdbo->length) == 0) { 268 return SCLP_RC_INCONSISTENT_LENGTHS; 269 } 270 len -= be16_to_cpu(mdbo->length); 271 mdbo = (void *) mdbo + be16_to_cpu(mdbo->length); 272 } 273 274 /* then execute */ 275 len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header); 276 mdbo = data->mdb.mdbo; 277 while (len > 0) { 278 switch (be16_to_cpu(mdbo->type)) { 279 case MESSAGE_TEXT: 280 /* message text object */ 281 written = process_mdb(event, mdbo); 282 if (written < 0) { 283 /* character layer error */ 284 errors++; 285 } 286 break; 287 default: /* ignore */ 288 break; 289 } 290 len -= be16_to_cpu(mdbo->length); 291 mdbo = (void *) mdbo + be16_to_cpu(mdbo->length); 292 } 293 if (errors) { 294 scon->write_errors += errors; 295 } 296 data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED; 297 298 return SCLP_RC_NORMAL_COMPLETION; 299 } 300 301 static void trigger_console_data(void *opaque, int n, int level) 302 { 303 sclp_service_interrupt(0); 304 } 305 306 /* functions for live migration */ 307 308 static const VMStateDescription vmstate_sclplmconsole = { 309 .name = "sclplmconsole", 310 .version_id = 0, 311 .minimum_version_id = 0, 312 .minimum_version_id_old = 0, 313 .fields = (VMStateField[]) { 314 VMSTATE_BOOL(event.event_pending, SCLPConsoleLM), 315 VMSTATE_UINT32(write_errors, SCLPConsoleLM), 316 VMSTATE_UINT32(length, SCLPConsoleLM), 317 VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER), 318 VMSTATE_END_OF_LIST() 319 } 320 }; 321 322 /* qemu object creation and initialization functions */ 323 324 /* tell character layer our call-back functions */ 325 326 static int console_init(SCLPEvent *event) 327 { 328 static bool console_available; 329 330 SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); 331 332 if (console_available) { 333 error_report("Multiple line-mode operator consoles are not supported"); 334 return -1; 335 } 336 console_available = true; 337 338 if (scon->chr) { 339 qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon); 340 } 341 scon->irq_console_read = *qemu_allocate_irqs(trigger_console_data, NULL, 1); 342 343 return 0; 344 } 345 346 static int console_exit(SCLPEvent *event) 347 { 348 return 0; 349 } 350 351 static void console_reset(DeviceState *dev) 352 { 353 SCLPEvent *event = SCLP_EVENT(dev); 354 SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event); 355 356 event->event_pending = false; 357 scon->length = 0; 358 scon->write_errors = 0; 359 } 360 361 static Property console_properties[] = { 362 DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr), 363 DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0), 364 DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true), 365 DEFINE_PROP_END_OF_LIST(), 366 }; 367 368 static void console_class_init(ObjectClass *klass, void *data) 369 { 370 DeviceClass *dc = DEVICE_CLASS(klass); 371 SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); 372 373 dc->props = console_properties; 374 dc->reset = console_reset; 375 dc->vmsd = &vmstate_sclplmconsole; 376 ec->init = console_init; 377 ec->exit = console_exit; 378 ec->get_send_mask = send_mask; 379 ec->get_receive_mask = receive_mask; 380 ec->can_handle_event = can_handle_event; 381 ec->read_event_data = read_event_data; 382 ec->write_event_data = write_event_data; 383 } 384 385 static const TypeInfo sclp_console_info = { 386 .name = "sclplmconsole", 387 .parent = TYPE_SCLP_EVENT, 388 .instance_size = sizeof(SCLPConsoleLM), 389 .class_init = console_class_init, 390 .class_size = sizeof(SCLPEventClass), 391 }; 392 393 static void register_types(void) 394 { 395 type_register_static(&sclp_console_info); 396 } 397 398 type_init(register_types) 399