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