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