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 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); 195 196 if (!scon->chr) { 197 /* If there's no backend, we can just say we consumed all data. */ 198 return len; 199 } 200 201 /* XXX this blocks entire thread. Rewrite to use 202 * qemu_chr_fe_write and background I/O callbacks */ 203 return qemu_chr_fe_write_all(scon->chr, buf, len); 204 } 205 206 static int process_mdb(SCLPEvent *event, MDBO *mdbo) 207 { 208 int rc; 209 int len; 210 uint8_t buffer[SIZE_BUFFER]; 211 212 len = be16_to_cpu(mdbo->length); 213 len -= sizeof(mdbo->length) + sizeof(mdbo->type) 214 + sizeof(mdbo->mto.line_type_flags) 215 + sizeof(mdbo->mto.alarm_control) 216 + sizeof(mdbo->mto._reserved); 217 218 assert(len <= SIZE_BUFFER); 219 220 /* convert EBCDIC SCLP contents to ASCII console message */ 221 ascii_put(buffer, mdbo->mto.message, len); 222 rc = write_console_data(event, (uint8_t *)NEWLINE, 1); 223 if (rc < 0) { 224 return rc; 225 } 226 return write_console_data(event, buffer, len); 227 } 228 229 static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh) 230 { 231 int len; 232 int written; 233 int errors = 0; 234 MDBO *mdbo; 235 SclpMsg *data = (SclpMsg *) ebh; 236 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); 237 238 len = be16_to_cpu(data->mdb.header.length); 239 if (len < sizeof(data->mdb.header)) { 240 return SCLP_RC_INCONSISTENT_LENGTHS; 241 } 242 len -= sizeof(data->mdb.header); 243 244 /* first check message buffers */ 245 mdbo = data->mdb.mdbo; 246 while (len > 0) { 247 if (be16_to_cpu(mdbo->length) > len 248 || be16_to_cpu(mdbo->length) == 0) { 249 return SCLP_RC_INCONSISTENT_LENGTHS; 250 } 251 len -= be16_to_cpu(mdbo->length); 252 mdbo = (void *) mdbo + be16_to_cpu(mdbo->length); 253 } 254 255 /* then execute */ 256 len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header); 257 mdbo = data->mdb.mdbo; 258 while (len > 0) { 259 switch (be16_to_cpu(mdbo->type)) { 260 case MESSAGE_TEXT: 261 /* message text object */ 262 written = process_mdb(event, mdbo); 263 if (written < 0) { 264 /* character layer error */ 265 errors++; 266 } 267 break; 268 default: /* ignore */ 269 break; 270 } 271 len -= be16_to_cpu(mdbo->length); 272 mdbo = (void *) mdbo + be16_to_cpu(mdbo->length); 273 } 274 if (errors) { 275 scon->write_errors += errors; 276 } 277 data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED; 278 279 return SCLP_RC_NORMAL_COMPLETION; 280 } 281 282 /* functions for live migration */ 283 284 static const VMStateDescription vmstate_sclplmconsole = { 285 .name = "sclplmconsole", 286 .version_id = 0, 287 .minimum_version_id = 0, 288 .fields = (VMStateField[]) { 289 VMSTATE_BOOL(event.event_pending, SCLPConsoleLM), 290 VMSTATE_UINT32(write_errors, SCLPConsoleLM), 291 VMSTATE_UINT32(length, SCLPConsoleLM), 292 VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER), 293 VMSTATE_END_OF_LIST() 294 } 295 }; 296 297 /* qemu object creation and initialization functions */ 298 299 /* tell character layer our call-back functions */ 300 301 static int console_init(SCLPEvent *event) 302 { 303 static bool console_available; 304 305 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); 306 307 if (console_available) { 308 error_report("Multiple line-mode operator consoles are not supported"); 309 return -1; 310 } 311 console_available = true; 312 313 if (scon->chr) { 314 qemu_chr_add_handlers(scon->chr, chr_can_read, chr_read, NULL, scon); 315 } 316 317 return 0; 318 } 319 320 static int console_exit(SCLPEvent *event) 321 { 322 return 0; 323 } 324 325 static void console_reset(DeviceState *dev) 326 { 327 SCLPEvent *event = SCLP_EVENT(dev); 328 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); 329 330 event->event_pending = false; 331 scon->length = 0; 332 scon->write_errors = 0; 333 } 334 335 static Property console_properties[] = { 336 DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr), 337 DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0), 338 DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true), 339 DEFINE_PROP_END_OF_LIST(), 340 }; 341 342 static void console_class_init(ObjectClass *klass, void *data) 343 { 344 DeviceClass *dc = DEVICE_CLASS(klass); 345 SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); 346 347 dc->props = console_properties; 348 dc->reset = console_reset; 349 dc->vmsd = &vmstate_sclplmconsole; 350 ec->init = console_init; 351 ec->exit = console_exit; 352 ec->get_send_mask = send_mask; 353 ec->get_receive_mask = receive_mask; 354 ec->can_handle_event = can_handle_event; 355 ec->read_event_data = read_event_data; 356 ec->write_event_data = write_event_data; 357 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 358 } 359 360 static const TypeInfo sclp_console_info = { 361 .name = "sclplmconsole", 362 .parent = TYPE_SCLP_EVENT, 363 .instance_size = sizeof(SCLPConsoleLM), 364 .class_init = console_class_init, 365 .class_size = sizeof(SCLPEventClass), 366 }; 367 368 static void register_types(void) 369 { 370 type_register_static(&sclp_console_info); 371 } 372 373 type_init(register_types) 374