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