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