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 "qemu/thread.h" 18 #include "qemu/error-report.h" 19 #include "qemu/module.h" 20 #include "chardev/char-fe.h" 21 22 #include "hw/s390x/sclp.h" 23 #include "migration/vmstate.h" 24 #include "hw/s390x/event-facility.h" 25 #include "hw/qdev-properties.h" 26 #include "hw/s390x/ebcdic.h" 27 #include "qom/object.h" 28 29 #define SIZE_BUFFER 4096 30 #define NEWLINE "\n" 31 32 typedef struct OprtnsCommand { 33 EventBufferHeader header; 34 MDMSU message_unit; 35 char data[]; 36 } QEMU_PACKED OprtnsCommand; 37 38 /* max size for line-mode data in 4K SCCB page */ 39 #define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand)) 40 41 struct SCLPConsoleLM { 42 SCLPEvent event; 43 CharBackend chr; 44 bool echo; /* immediate echo of input if true */ 45 uint32_t write_errors; /* errors writing to char layer */ 46 uint32_t length; /* length of byte stream in buffer */ 47 uint8_t buf[SIZE_CONSOLE_BUFFER]; 48 }; 49 typedef struct SCLPConsoleLM SCLPConsoleLM; 50 51 #define TYPE_SCLPLM_CONSOLE "sclplmconsole" 52 DECLARE_INSTANCE_CHECKER(SCLPConsoleLM, SCLPLM_CONSOLE, 53 TYPE_SCLPLM_CONSOLE) 54 55 /* 56 * Character layer call-back functions 57 * 58 * Allow 1 character at a time 59 * 60 * Accumulate bytes from character layer in console buffer, 61 * event_pending is set when a newline character is encountered 62 * 63 * The maximum command line length is limited by the maximum 64 * space available in an SCCB. Line mode console input is sent 65 * truncated to the guest in case it doesn't fit into the SCCB. 66 */ 67 68 static int chr_can_read(void *opaque) 69 { 70 SCLPConsoleLM *scon = opaque; 71 72 if (scon->event.event_pending) { 73 return 0; 74 } 75 return 1; 76 } 77 78 static void chr_read(void *opaque, const uint8_t *buf, int size) 79 { 80 SCLPConsoleLM *scon = opaque; 81 82 assert(size == 1); 83 84 if (*buf == '\r' || *buf == '\n') { 85 scon->event.event_pending = true; 86 sclp_service_interrupt(0); 87 return; 88 } 89 if (scon->length == SIZE_CONSOLE_BUFFER) { 90 /* Eat the character, but still process CR and LF. */ 91 return; 92 } 93 scon->buf[scon->length] = *buf; 94 scon->length += 1; 95 if (scon->echo) { 96 /* XXX this blocks entire thread. Rewrite to use 97 * qemu_chr_fe_write and background I/O callbacks */ 98 qemu_chr_fe_write_all(&scon->chr, buf, size); 99 } 100 } 101 102 /* functions to be called by event facility */ 103 104 static bool can_handle_event(uint8_t type) 105 { 106 return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD; 107 } 108 109 static sccb_mask_t send_mask(void) 110 { 111 return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD; 112 } 113 114 static sccb_mask_t receive_mask(void) 115 { 116 return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD; 117 } 118 119 /* 120 * Triggered by SCLP's read_event_data 121 * - convert ASCII byte stream to EBCDIC and 122 * - copy converted data into provided (SCLP) buffer 123 */ 124 static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, 125 int avail) 126 { 127 int len; 128 129 SCLPConsoleLM *cons = SCLPLM_CONSOLE(event); 130 131 len = cons->length; 132 /* data need to fit into provided SCLP buffer */ 133 if (len > avail) { 134 return 1; 135 } 136 137 ebcdic_put(buf, (char *)&cons->buf, len); 138 *size = len; 139 cons->length = 0; 140 /* data provided and no more data pending */ 141 event->event_pending = false; 142 qemu_notify_event(); 143 return 0; 144 } 145 146 static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, 147 int *slen) 148 { 149 int avail, rc; 150 size_t src_len; 151 uint8_t *to; 152 OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr; 153 154 if (!event->event_pending) { 155 /* no data pending */ 156 return 0; 157 } 158 159 to = (uint8_t *)&oc->data; 160 avail = *slen - sizeof(OprtnsCommand); 161 rc = get_console_data(event, to, &src_len, avail); 162 if (rc) { 163 /* data didn't fit, try next SCCB */ 164 return 1; 165 } 166 167 oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU; 168 oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU)); 169 170 oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU; 171 oc->message_unit.cpmsu.length = 172 cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector)); 173 174 oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD; 175 oc->message_unit.text_command.length = 176 cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector))); 177 178 oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG; 179 oc->message_unit.self_def_text_message.length = 180 cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector))); 181 182 oc->message_unit.text_message.key = GDS_KEY_TEXTMSG; 183 oc->message_unit.text_message.length = 184 cpu_to_be16(sizeof(GdsSubvector) + src_len); 185 186 oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len); 187 oc->header.type = SCLP_EVENT_OPRTNS_COMMAND; 188 *slen = avail - src_len; 189 190 return 1; 191 } 192 193 /* 194 * Triggered by SCLP's write_event_data 195 * - write console data to character layer 196 * returns < 0 if an error occurred 197 */ 198 static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len) 199 { 200 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); 201 202 if (!qemu_chr_fe_backend_connected(&scon->chr)) { 203 /* If there's no backend, we can just say we consumed all data. */ 204 return len; 205 } 206 207 /* XXX this blocks entire thread. Rewrite to use 208 * qemu_chr_fe_write and background I/O callbacks */ 209 return qemu_chr_fe_write_all(&scon->chr, buf, len); 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 = SCLPLM_CONSOLE(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 .fields = (VMStateField[]) { 295 VMSTATE_BOOL(event.event_pending, SCLPConsoleLM), 296 VMSTATE_UINT32(write_errors, SCLPConsoleLM), 297 VMSTATE_UINT32(length, SCLPConsoleLM), 298 VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER), 299 VMSTATE_END_OF_LIST() 300 } 301 }; 302 303 /* qemu object creation and initialization functions */ 304 305 /* tell character layer our call-back functions */ 306 307 static int console_init(SCLPEvent *event) 308 { 309 static bool console_available; 310 311 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event); 312 313 if (console_available) { 314 error_report("Multiple line-mode operator consoles are not supported"); 315 return -1; 316 } 317 console_available = true; 318 319 qemu_chr_fe_set_handlers(&scon->chr, chr_can_read, 320 chr_read, NULL, NULL, scon, NULL, true); 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 device_class_set_props(dc, console_properties); 348 dc->reset = console_reset; 349 dc->vmsd = &vmstate_sclplmconsole; 350 ec->init = console_init; 351 ec->get_send_mask = send_mask; 352 ec->get_receive_mask = receive_mask; 353 ec->can_handle_event = can_handle_event; 354 ec->read_event_data = read_event_data; 355 ec->write_event_data = write_event_data; 356 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 357 } 358 359 static const TypeInfo sclp_console_info = { 360 .name = TYPE_SCLPLM_CONSOLE, 361 .parent = TYPE_SCLP_EVENT, 362 .instance_size = sizeof(SCLPConsoleLM), 363 .class_init = console_class_init, 364 .class_size = sizeof(SCLPEventClass), 365 }; 366 367 static void register_types(void) 368 { 369 type_register_static(&sclp_console_info); 370 } 371 372 type_init(register_types) 373