copy-on-read: Support compressed writes
[qemu.git] / hw / char / sclpconsole-lm.c
blob5848b4e9c5486da8794fdf2e72af8513951e7296
1 /*
2 * SCLP event types
3 * Operations Command - Line Mode input
4 * Message - Line Mode output
6 * Copyright IBM, Corp. 2013
8 * Authors:
9 * Heinz Graalfs <graalfs@linux.vnet.ibm.com>
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.
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"
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"
28 #define SIZE_BUFFER 4096
29 #define NEWLINE "\n"
31 typedef struct OprtnsCommand {
32 EventBufferHeader header;
33 MDMSU message_unit;
34 char data[];
35 } QEMU_PACKED OprtnsCommand;
37 /* max size for line-mode data in 4K SCCB page */
38 #define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand))
40 typedef struct SCLPConsoleLM {
41 SCLPEvent event;
42 CharBackend chr;
43 bool echo; /* immediate echo of input if true */
44 uint32_t write_errors; /* errors writing to char layer */
45 uint32_t length; /* length of byte stream in buffer */
46 uint8_t buf[SIZE_CONSOLE_BUFFER];
47 } SCLPConsoleLM;
49 #define TYPE_SCLPLM_CONSOLE "sclplmconsole"
50 #define SCLPLM_CONSOLE(obj) \
51 OBJECT_CHECK(SCLPConsoleLM, (obj), TYPE_SCLPLM_CONSOLE)
54 * Character layer call-back functions
56 * Allow 1 character at a time
58 * Accumulate bytes from character layer in console buffer,
59 * event_pending is set when a newline character is encountered
61 * The maximum command line length is limited by the maximum
62 * space available in an SCCB. Line mode console input is sent
63 * truncated to the guest in case it doesn't fit into the SCCB.
66 static int chr_can_read(void *opaque)
68 SCLPConsoleLM *scon = opaque;
70 if (scon->event.event_pending) {
71 return 0;
73 return 1;
76 static void chr_read(void *opaque, const uint8_t *buf, int size)
78 SCLPConsoleLM *scon = opaque;
80 assert(size == 1);
82 if (*buf == '\r' || *buf == '\n') {
83 scon->event.event_pending = true;
84 sclp_service_interrupt(0);
85 return;
87 if (scon->length == SIZE_CONSOLE_BUFFER) {
88 /* Eat the character, but still process CR and LF. */
89 return;
91 scon->buf[scon->length] = *buf;
92 scon->length += 1;
93 if (scon->echo) {
94 /* XXX this blocks entire thread. Rewrite to use
95 * qemu_chr_fe_write and background I/O callbacks */
96 qemu_chr_fe_write_all(&scon->chr, buf, size);
100 /* functions to be called by event facility */
102 static bool can_handle_event(uint8_t type)
104 return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD;
107 static sccb_mask_t send_mask(void)
109 return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD;
112 static sccb_mask_t receive_mask(void)
114 return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD;
118 * Triggered by SCLP's read_event_data
119 * - convert ASCII byte stream to EBCDIC and
120 * - copy converted data into provided (SCLP) buffer
122 static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
123 int avail)
125 int len;
127 SCLPConsoleLM *cons = SCLPLM_CONSOLE(event);
129 len = cons->length;
130 /* data need to fit into provided SCLP buffer */
131 if (len > avail) {
132 return 1;
135 ebcdic_put(buf, (char *)&cons->buf, len);
136 *size = len;
137 cons->length = 0;
138 /* data provided and no more data pending */
139 event->event_pending = false;
140 qemu_notify_event();
141 return 0;
144 static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
145 int *slen)
147 int avail, rc;
148 size_t src_len;
149 uint8_t *to;
150 OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr;
152 if (!event->event_pending) {
153 /* no data pending */
154 return 0;
157 to = (uint8_t *)&oc->data;
158 avail = *slen - sizeof(OprtnsCommand);
159 rc = get_console_data(event, to, &src_len, avail);
160 if (rc) {
161 /* data didn't fit, try next SCCB */
162 return 1;
165 oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU;
166 oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU));
168 oc->message_unit.cpmsu.gds_id = GDS_ID_CPMSU;
169 oc->message_unit.cpmsu.length =
170 cpu_to_be16(sizeof(struct MDMSU) - sizeof(GdsVector));
172 oc->message_unit.text_command.gds_id = GDS_ID_TEXTCMD;
173 oc->message_unit.text_command.length =
174 cpu_to_be16(sizeof(struct MDMSU) - (2 * sizeof(GdsVector)));
176 oc->message_unit.self_def_text_message.key = GDS_KEY_SELFDEFTEXTMSG;
177 oc->message_unit.self_def_text_message.length =
178 cpu_to_be16(sizeof(struct MDMSU) - (3 * sizeof(GdsVector)));
180 oc->message_unit.text_message.key = GDS_KEY_TEXTMSG;
181 oc->message_unit.text_message.length =
182 cpu_to_be16(sizeof(GdsSubvector) + src_len);
184 oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len);
185 oc->header.type = SCLP_EVENT_OPRTNS_COMMAND;
186 *slen = avail - src_len;
188 return 1;
192 * Triggered by SCLP's write_event_data
193 * - write console data to character layer
194 * returns < 0 if an error occurred
196 static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
198 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
200 if (!qemu_chr_fe_backend_connected(&scon->chr)) {
201 /* If there's no backend, we can just say we consumed all data. */
202 return len;
205 /* XXX this blocks entire thread. Rewrite to use
206 * qemu_chr_fe_write and background I/O callbacks */
207 return qemu_chr_fe_write_all(&scon->chr, buf, len);
210 static int process_mdb(SCLPEvent *event, MDBO *mdbo)
212 int rc;
213 int len;
214 uint8_t buffer[SIZE_BUFFER];
216 len = be16_to_cpu(mdbo->length);
217 len -= sizeof(mdbo->length) + sizeof(mdbo->type)
218 + sizeof(mdbo->mto.line_type_flags)
219 + sizeof(mdbo->mto.alarm_control)
220 + sizeof(mdbo->mto._reserved);
222 assert(len <= SIZE_BUFFER);
224 /* convert EBCDIC SCLP contents to ASCII console message */
225 ascii_put(buffer, mdbo->mto.message, len);
226 rc = write_console_data(event, (uint8_t *)NEWLINE, 1);
227 if (rc < 0) {
228 return rc;
230 return write_console_data(event, buffer, len);
233 static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
235 int len;
236 int written;
237 int errors = 0;
238 MDBO *mdbo;
239 SclpMsg *data = (SclpMsg *) ebh;
240 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
242 len = be16_to_cpu(data->mdb.header.length);
243 if (len < sizeof(data->mdb.header)) {
244 return SCLP_RC_INCONSISTENT_LENGTHS;
246 len -= sizeof(data->mdb.header);
248 /* first check message buffers */
249 mdbo = data->mdb.mdbo;
250 while (len > 0) {
251 if (be16_to_cpu(mdbo->length) > len
252 || be16_to_cpu(mdbo->length) == 0) {
253 return SCLP_RC_INCONSISTENT_LENGTHS;
255 len -= be16_to_cpu(mdbo->length);
256 mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
259 /* then execute */
260 len = be16_to_cpu(data->mdb.header.length) - sizeof(data->mdb.header);
261 mdbo = data->mdb.mdbo;
262 while (len > 0) {
263 switch (be16_to_cpu(mdbo->type)) {
264 case MESSAGE_TEXT:
265 /* message text object */
266 written = process_mdb(event, mdbo);
267 if (written < 0) {
268 /* character layer error */
269 errors++;
271 break;
272 default: /* ignore */
273 break;
275 len -= be16_to_cpu(mdbo->length);
276 mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
278 if (errors) {
279 scon->write_errors += errors;
281 data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED;
283 return SCLP_RC_NORMAL_COMPLETION;
286 /* functions for live migration */
288 static const VMStateDescription vmstate_sclplmconsole = {
289 .name = "sclplmconsole",
290 .version_id = 0,
291 .minimum_version_id = 0,
292 .fields = (VMStateField[]) {
293 VMSTATE_BOOL(event.event_pending, SCLPConsoleLM),
294 VMSTATE_UINT32(write_errors, SCLPConsoleLM),
295 VMSTATE_UINT32(length, SCLPConsoleLM),
296 VMSTATE_UINT8_ARRAY(buf, SCLPConsoleLM, SIZE_CONSOLE_BUFFER),
297 VMSTATE_END_OF_LIST()
301 /* qemu object creation and initialization functions */
303 /* tell character layer our call-back functions */
305 static int console_init(SCLPEvent *event)
307 static bool console_available;
309 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
311 if (console_available) {
312 error_report("Multiple line-mode operator consoles are not supported");
313 return -1;
315 console_available = true;
317 qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
318 chr_read, NULL, NULL, scon, NULL, true);
320 return 0;
323 static void console_reset(DeviceState *dev)
325 SCLPEvent *event = SCLP_EVENT(dev);
326 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
328 event->event_pending = false;
329 scon->length = 0;
330 scon->write_errors = 0;
333 static Property console_properties[] = {
334 DEFINE_PROP_CHR("chardev", SCLPConsoleLM, chr),
335 DEFINE_PROP_UINT32("write_errors", SCLPConsoleLM, write_errors, 0),
336 DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true),
337 DEFINE_PROP_END_OF_LIST(),
340 static void console_class_init(ObjectClass *klass, void *data)
342 DeviceClass *dc = DEVICE_CLASS(klass);
343 SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
345 device_class_set_props(dc, console_properties);
346 dc->reset = console_reset;
347 dc->vmsd = &vmstate_sclplmconsole;
348 ec->init = console_init;
349 ec->get_send_mask = send_mask;
350 ec->get_receive_mask = receive_mask;
351 ec->can_handle_event = can_handle_event;
352 ec->read_event_data = read_event_data;
353 ec->write_event_data = write_event_data;
354 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
357 static const TypeInfo sclp_console_info = {
358 .name = TYPE_SCLPLM_CONSOLE,
359 .parent = TYPE_SCLP_EVENT,
360 .instance_size = sizeof(SCLPConsoleLM),
361 .class_init = console_class_init,
362 .class_size = sizeof(SCLPEventClass),
365 static void register_types(void)
367 type_register_static(&sclp_console_info);
370 type_init(register_types)