1 /* 2 * SCLP event type 3 * Ascii Console Data (VT220 Console) 4 * 5 * Copyright IBM, Corp. 2012 6 * 7 * Authors: 8 * Heinz Graalfs <graalfs@de.ibm.com> 9 * 10 * This work is licensed under the terms of the GNU GPL, version 2 or (at your 11 * option) any later version. See the COPYING file in the top-level directory. 12 * 13 */ 14 15 #include "qemu/osdep.h" 16 #include "qemu/thread.h" 17 #include "qemu/error-report.h" 18 #include "qemu/module.h" 19 20 #include "hw/s390x/sclp.h" 21 #include "migration/vmstate.h" 22 #include "hw/qdev-properties.h" 23 #include "hw/s390x/event-facility.h" 24 #include "chardev/char-fe.h" 25 #include "qom/object.h" 26 27 typedef struct ASCIIConsoleData { 28 EventBufferHeader ebh; 29 char data[]; 30 } QEMU_PACKED ASCIIConsoleData; 31 32 /* max size for ASCII data in 4K SCCB page */ 33 #define SIZE_BUFFER_VT220 4080 34 35 struct SCLPConsole { 36 SCLPEvent event; 37 CharBackend chr; 38 uint8_t iov[SIZE_BUFFER_VT220]; 39 uint32_t iov_sclp; /* offset in buf for SCLP read operation */ 40 uint32_t iov_bs; /* offset in buf for char layer read operation */ 41 uint32_t iov_data_len; /* length of byte stream in buffer */ 42 uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */ 43 bool notify; /* qemu_notify_event() req'd if true */ 44 }; 45 typedef struct SCLPConsole SCLPConsole; 46 47 #define TYPE_SCLP_CONSOLE "sclpconsole" 48 DECLARE_INSTANCE_CHECKER(SCLPConsole, SCLP_CONSOLE, 49 TYPE_SCLP_CONSOLE) 50 51 /* character layer call-back functions */ 52 53 /* Return number of bytes that fit into iov buffer */ 54 static int chr_can_read(void *opaque) 55 { 56 SCLPConsole *scon = opaque; 57 int avail = SIZE_BUFFER_VT220 - scon->iov_data_len; 58 59 if (avail == 0) { 60 scon->notify = true; 61 } 62 return avail; 63 } 64 65 /* Send data from a char device over to the guest */ 66 static void chr_read(void *opaque, const uint8_t *buf, int size) 67 { 68 SCLPConsole *scon = opaque; 69 70 assert(scon); 71 /* read data must fit into current buffer */ 72 assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len); 73 74 /* put byte-stream from character layer into buffer */ 75 memcpy(&scon->iov[scon->iov_bs], buf, size); 76 scon->iov_data_len += size; 77 scon->iov_sclp_rest += size; 78 scon->iov_bs += size; 79 scon->event.event_pending = true; 80 sclp_service_interrupt(0); 81 } 82 83 /* functions to be called by event facility */ 84 85 static bool can_handle_event(uint8_t type) 86 { 87 return type == SCLP_EVENT_ASCII_CONSOLE_DATA; 88 } 89 90 static sccb_mask_t send_mask(void) 91 { 92 return SCLP_EVENT_MASK_MSG_ASCII; 93 } 94 95 static sccb_mask_t receive_mask(void) 96 { 97 return SCLP_EVENT_MASK_MSG_ASCII; 98 } 99 100 /* triggered by SCLP's read_event_data - 101 * copy console data byte-stream into provided (SCLP) buffer 102 */ 103 static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size, 104 int avail) 105 { 106 SCLPConsole *cons = SCLP_CONSOLE(event); 107 108 /* first byte is hex 0 saying an ascii string follows */ 109 *buf++ = '\0'; 110 avail--; 111 /* if all data fit into provided SCLP buffer */ 112 if (avail >= cons->iov_sclp_rest) { 113 /* copy character byte-stream to SCLP buffer */ 114 memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest); 115 *size = cons->iov_sclp_rest + 1; 116 cons->iov_sclp = 0; 117 cons->iov_bs = 0; 118 cons->iov_data_len = 0; 119 cons->iov_sclp_rest = 0; 120 event->event_pending = false; 121 /* data provided and no more data pending */ 122 } else { 123 /* if provided buffer is too small, just copy part */ 124 memcpy(buf, &cons->iov[cons->iov_sclp], avail); 125 *size = avail + 1; 126 cons->iov_sclp_rest -= avail; 127 cons->iov_sclp += avail; 128 /* more data pending */ 129 } 130 if (cons->notify) { 131 cons->notify = false; 132 qemu_notify_event(); 133 } 134 } 135 136 static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, 137 int *slen) 138 { 139 int avail; 140 size_t src_len; 141 uint8_t *to; 142 ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; 143 144 if (!event->event_pending) { 145 /* no data pending */ 146 return 0; 147 } 148 149 to = (uint8_t *)&acd->data; 150 avail = *slen - sizeof(ASCIIConsoleData); 151 get_console_data(event, to, &src_len, avail); 152 153 acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len); 154 acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA; 155 acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; 156 *slen = avail - src_len; 157 158 return 1; 159 } 160 161 /* triggered by SCLP's write_event_data 162 * - write console data to character layer 163 * returns < 0 if an error occurred 164 */ 165 static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf, 166 size_t len) 167 { 168 SCLPConsole *scon = SCLP_CONSOLE(event); 169 170 if (!qemu_chr_fe_backend_connected(&scon->chr)) { 171 /* If there's no backend, we can just say we consumed all data. */ 172 return len; 173 } 174 175 /* XXX this blocks entire thread. Rewrite to use 176 * qemu_chr_fe_write and background I/O callbacks */ 177 return qemu_chr_fe_write_all(&scon->chr, buf, len); 178 } 179 180 static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr) 181 { 182 int rc; 183 int length; 184 ssize_t written; 185 ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr; 186 187 length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader); 188 written = write_console_data(event, (uint8_t *)acd->data, length); 189 190 rc = SCLP_RC_NORMAL_COMPLETION; 191 /* set event buffer accepted flag */ 192 evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED; 193 194 /* written will be zero if a pty is not connected - don't treat as error */ 195 if (written < 0) { 196 /* event buffer not accepted due to error in character layer */ 197 evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED); 198 rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK; 199 } 200 201 return rc; 202 } 203 204 static const VMStateDescription vmstate_sclpconsole = { 205 .name = "sclpconsole", 206 .version_id = 0, 207 .minimum_version_id = 0, 208 .fields = (VMStateField[]) { 209 VMSTATE_BOOL(event.event_pending, SCLPConsole), 210 VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220), 211 VMSTATE_UINT32(iov_sclp, SCLPConsole), 212 VMSTATE_UINT32(iov_bs, SCLPConsole), 213 VMSTATE_UINT32(iov_data_len, SCLPConsole), 214 VMSTATE_UINT32(iov_sclp_rest, SCLPConsole), 215 VMSTATE_END_OF_LIST() 216 } 217 }; 218 219 /* qemu object creation and initialization functions */ 220 221 /* tell character layer our call-back functions */ 222 223 static int console_init(SCLPEvent *event) 224 { 225 static bool console_available; 226 227 SCLPConsole *scon = SCLP_CONSOLE(event); 228 229 if (console_available) { 230 error_report("Multiple VT220 operator consoles are not supported"); 231 return -1; 232 } 233 console_available = true; 234 qemu_chr_fe_set_handlers(&scon->chr, chr_can_read, 235 chr_read, NULL, NULL, scon, NULL, true); 236 237 return 0; 238 } 239 240 static void console_reset(DeviceState *dev) 241 { 242 SCLPEvent *event = SCLP_EVENT(dev); 243 SCLPConsole *scon = SCLP_CONSOLE(event); 244 245 event->event_pending = false; 246 scon->iov_sclp = 0; 247 scon->iov_bs = 0; 248 scon->iov_data_len = 0; 249 scon->iov_sclp_rest = 0; 250 scon->notify = false; 251 } 252 253 static Property console_properties[] = { 254 DEFINE_PROP_CHR("chardev", SCLPConsole, chr), 255 DEFINE_PROP_END_OF_LIST(), 256 }; 257 258 static void console_class_init(ObjectClass *klass, void *data) 259 { 260 DeviceClass *dc = DEVICE_CLASS(klass); 261 SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); 262 263 device_class_set_props(dc, console_properties); 264 dc->reset = console_reset; 265 dc->vmsd = &vmstate_sclpconsole; 266 ec->init = console_init; 267 ec->get_send_mask = send_mask; 268 ec->get_receive_mask = receive_mask; 269 ec->can_handle_event = can_handle_event; 270 ec->read_event_data = read_event_data; 271 ec->write_event_data = write_event_data; 272 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 273 } 274 275 static const TypeInfo sclp_console_info = { 276 .name = TYPE_SCLP_CONSOLE, 277 .parent = TYPE_SCLP_EVENT, 278 .instance_size = sizeof(SCLPConsole), 279 .class_init = console_class_init, 280 .class_size = sizeof(SCLPEventClass), 281 }; 282 283 static void register_types(void) 284 { 285 type_register_static(&sclp_console_info); 286 } 287 288 type_init(register_types) 289