sd: Use ERRP_GUARD()
[qemu.git] / hw / char / sclpconsole-lm.c
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
28 #define SIZE_BUFFER 4096
29 #define NEWLINE "\n"
30
31 typedef struct OprtnsCommand {
32 EventBufferHeader header;
33 MDMSU message_unit;
34 char data[];
35 } QEMU_PACKED OprtnsCommand;
36
37 /* max size for line-mode data in 4K SCCB page */
38 #define SIZE_CONSOLE_BUFFER (SCCB_DATA_LEN - sizeof(OprtnsCommand))
39
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;
48
49 #define TYPE_SCLPLM_CONSOLE "sclplmconsole"
50 #define SCLPLM_CONSOLE(obj) \
51 OBJECT_CHECK(SCLPConsoleLM, (obj), TYPE_SCLPLM_CONSOLE)
52
53 /*
54 * Character layer call-back functions
55 *
56 * Allow 1 character at a time
57 *
58 * Accumulate bytes from character layer in console buffer,
59 * event_pending is set when a newline character is encountered
60 *
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.
64 */
65
66 static int chr_can_read(void *opaque)
67 {
68 SCLPConsoleLM *scon = opaque;
69
70 if (scon->event.event_pending) {
71 return 0;
72 }
73 return 1;
74 }
75
76 static void chr_read(void *opaque, const uint8_t *buf, int size)
77 {
78 SCLPConsoleLM *scon = opaque;
79
80 assert(size == 1);
81
82 if (*buf == '\r' || *buf == '\n') {
83 scon->event.event_pending = true;
84 sclp_service_interrupt(0);
85 return;
86 }
87 if (scon->length == SIZE_CONSOLE_BUFFER) {
88 /* Eat the character, but still process CR and LF. */
89 return;
90 }
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);
97 }
98 }
99
100 /* functions to be called by event facility */
101
102 static bool can_handle_event(uint8_t type)
103 {
104 return type == SCLP_EVENT_MESSAGE || type == SCLP_EVENT_PMSGCMD;
105 }
106
107 static sccb_mask_t send_mask(void)
108 {
109 return SCLP_EVENT_MASK_OP_CMD | SCLP_EVENT_MASK_PMSGCMD;
110 }
111
112 static sccb_mask_t receive_mask(void)
113 {
114 return SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_PMSGCMD;
115 }
116
117 /*
118 * Triggered by SCLP's read_event_data
119 * - convert ASCII byte stream to EBCDIC and
120 * - copy converted data into provided (SCLP) buffer
121 */
122 static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
123 int avail)
124 {
125 int len;
126
127 SCLPConsoleLM *cons = SCLPLM_CONSOLE(event);
128
129 len = cons->length;
130 /* data need to fit into provided SCLP buffer */
131 if (len > avail) {
132 return 1;
133 }
134
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;
142 }
143
144 static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
145 int *slen)
146 {
147 int avail, rc;
148 size_t src_len;
149 uint8_t *to;
150 OprtnsCommand *oc = (OprtnsCommand *) evt_buf_hdr;
151
152 if (!event->event_pending) {
153 /* no data pending */
154 return 0;
155 }
156
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;
163 }
164
165 oc->message_unit.mdmsu.gds_id = GDS_ID_MDSMU;
166 oc->message_unit.mdmsu.length = cpu_to_be16(sizeof(struct MDMSU));
167
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));
171
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)));
175
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)));
179
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);
183
184 oc->header.length = cpu_to_be16(sizeof(OprtnsCommand) + src_len);
185 oc->header.type = SCLP_EVENT_OPRTNS_COMMAND;
186 *slen = avail - src_len;
187
188 return 1;
189 }
190
191 /*
192 * Triggered by SCLP's write_event_data
193 * - write console data to character layer
194 * returns < 0 if an error occurred
195 */
196 static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
197 {
198 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
199
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;
203 }
204
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);
208 }
209
210 static int process_mdb(SCLPEvent *event, MDBO *mdbo)
211 {
212 int rc;
213 int len;
214 uint8_t buffer[SIZE_BUFFER];
215
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);
221
222 assert(len <= SIZE_BUFFER);
223
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;
229 }
230 return write_console_data(event, buffer, len);
231 }
232
233 static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
234 {
235 int len;
236 int written;
237 int errors = 0;
238 MDBO *mdbo;
239 SclpMsg *data = (SclpMsg *) ebh;
240 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
241
242 len = be16_to_cpu(data->mdb.header.length);
243 if (len < sizeof(data->mdb.header)) {
244 return SCLP_RC_INCONSISTENT_LENGTHS;
245 }
246 len -= sizeof(data->mdb.header);
247
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;
254 }
255 len -= be16_to_cpu(mdbo->length);
256 mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
257 }
258
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++;
270 }
271 break;
272 default: /* ignore */
273 break;
274 }
275 len -= be16_to_cpu(mdbo->length);
276 mdbo = (void *) mdbo + be16_to_cpu(mdbo->length);
277 }
278 if (errors) {
279 scon->write_errors += errors;
280 }
281 data->header.flags = SCLP_EVENT_BUFFER_ACCEPTED;
282
283 return SCLP_RC_NORMAL_COMPLETION;
284 }
285
286 /* functions for live migration */
287
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()
298 }
299 };
300
301 /* qemu object creation and initialization functions */
302
303 /* tell character layer our call-back functions */
304
305 static int console_init(SCLPEvent *event)
306 {
307 static bool console_available;
308
309 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
310
311 if (console_available) {
312 error_report("Multiple line-mode operator consoles are not supported");
313 return -1;
314 }
315 console_available = true;
316
317 qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
318 chr_read, NULL, NULL, scon, NULL, true);
319
320 return 0;
321 }
322
323 static void console_reset(DeviceState *dev)
324 {
325 SCLPEvent *event = SCLP_EVENT(dev);
326 SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);
327
328 event->event_pending = false;
329 scon->length = 0;
330 scon->write_errors = 0;
331 }
332
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(),
338 };
339
340 static void console_class_init(ObjectClass *klass, void *data)
341 {
342 DeviceClass *dc = DEVICE_CLASS(klass);
343 SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
344
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);
355 }
356
357 static const TypeInfo sclp_console_info = {
358 .name = "sclplmconsole",
359 .parent = TYPE_SCLP_EVENT,
360 .instance_size = sizeof(SCLPConsoleLM),
361 .class_init = console_class_init,
362 .class_size = sizeof(SCLPEventClass),
363 };
364
365 static void register_types(void)
366 {
367 type_register_static(&sclp_console_info);
368 }
369
370 type_init(register_types)