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