xref: /qemu/hw/char/sclpconsole.c (revision cb335bebe1f5eadd0188215a9703c3fd90cfe84e)
1130c57c0SHeinz Graalfs /*
2130c57c0SHeinz Graalfs  * SCLP event type
3130c57c0SHeinz Graalfs  *    Ascii Console Data (VT220 Console)
4130c57c0SHeinz Graalfs  *
5130c57c0SHeinz Graalfs  * Copyright IBM, Corp. 2012
6130c57c0SHeinz Graalfs  *
7130c57c0SHeinz Graalfs  * Authors:
8130c57c0SHeinz Graalfs  *  Heinz Graalfs <graalfs@de.ibm.com>
9130c57c0SHeinz Graalfs  *
10130c57c0SHeinz Graalfs  * This work is licensed under the terms of the GNU GPL, version 2 or (at your
11130c57c0SHeinz Graalfs  * option) any later version.  See the COPYING file in the top-level directory.
12130c57c0SHeinz Graalfs  *
13130c57c0SHeinz Graalfs  */
14130c57c0SHeinz Graalfs 
15130c57c0SHeinz Graalfs #include <hw/qdev.h>
161de7afc9SPaolo Bonzini #include "qemu/thread.h"
17b4a42f81SPaolo Bonzini #include "qemu/error-report.h"
18130c57c0SHeinz Graalfs 
1983c9f4caSPaolo Bonzini #include "hw/s390x/sclp.h"
2083c9f4caSPaolo Bonzini #include "hw/s390x/event-facility.h"
21dccfcd0eSPaolo Bonzini #include "sysemu/char.h"
22130c57c0SHeinz Graalfs 
23130c57c0SHeinz Graalfs typedef struct ASCIIConsoleData {
24130c57c0SHeinz Graalfs     EventBufferHeader ebh;
25130c57c0SHeinz Graalfs     char data[0];
26130c57c0SHeinz Graalfs } QEMU_PACKED ASCIIConsoleData;
27130c57c0SHeinz Graalfs 
28130c57c0SHeinz Graalfs /* max size for ASCII data in 4K SCCB page */
29130c57c0SHeinz Graalfs #define SIZE_BUFFER_VT220 4080
30130c57c0SHeinz Graalfs 
31130c57c0SHeinz Graalfs typedef struct SCLPConsole {
32130c57c0SHeinz Graalfs     SCLPEvent event;
33130c57c0SHeinz Graalfs     CharDriverState *chr;
34ea9ad3e9SHeinz Graalfs     uint8_t iov[SIZE_BUFFER_VT220];
35ea9ad3e9SHeinz Graalfs     uint32_t iov_sclp;      /* offset in buf for SCLP read operation       */
36ea9ad3e9SHeinz Graalfs     uint32_t iov_bs;        /* offset in buf for char layer read operation */
37130c57c0SHeinz Graalfs     uint32_t iov_data_len;  /* length of byte stream in buffer             */
38130c57c0SHeinz Graalfs     uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP     */
39130c57c0SHeinz Graalfs     qemu_irq irq_read_vt220;
40130c57c0SHeinz Graalfs } SCLPConsole;
41130c57c0SHeinz Graalfs 
42130c57c0SHeinz Graalfs /* character layer call-back functions */
43130c57c0SHeinz Graalfs 
44130c57c0SHeinz Graalfs /* Return number of bytes that fit into iov buffer */
45130c57c0SHeinz Graalfs static int chr_can_read(void *opaque)
46130c57c0SHeinz Graalfs {
47130c57c0SHeinz Graalfs     SCLPConsole *scon = opaque;
48130c57c0SHeinz Graalfs 
49ea9ad3e9SHeinz Graalfs     return SIZE_BUFFER_VT220 - scon->iov_data_len;
50130c57c0SHeinz Graalfs }
51130c57c0SHeinz Graalfs 
52130c57c0SHeinz Graalfs /* Receive n bytes from character layer, save in iov buffer,
53130c57c0SHeinz Graalfs  * and set event pending */
54130c57c0SHeinz Graalfs static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
55130c57c0SHeinz Graalfs                                    int size)
56130c57c0SHeinz Graalfs {
57130c57c0SHeinz Graalfs     /* read data must fit into current buffer */
58130c57c0SHeinz Graalfs     assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
59130c57c0SHeinz Graalfs 
60130c57c0SHeinz Graalfs     /* put byte-stream from character layer into buffer */
61ea9ad3e9SHeinz Graalfs     memcpy(&scon->iov[scon->iov_bs], buf, size);
62130c57c0SHeinz Graalfs     scon->iov_data_len += size;
63130c57c0SHeinz Graalfs     scon->iov_sclp_rest += size;
64130c57c0SHeinz Graalfs     scon->iov_bs += size;
65130c57c0SHeinz Graalfs     scon->event.event_pending = true;
66130c57c0SHeinz Graalfs }
67130c57c0SHeinz Graalfs 
68130c57c0SHeinz Graalfs /* Send data from a char device over to the guest */
69130c57c0SHeinz Graalfs static void chr_read(void *opaque, const uint8_t *buf, int size)
70130c57c0SHeinz Graalfs {
71130c57c0SHeinz Graalfs     SCLPConsole *scon = opaque;
72130c57c0SHeinz Graalfs 
73130c57c0SHeinz Graalfs     assert(scon);
74130c57c0SHeinz Graalfs 
75130c57c0SHeinz Graalfs     receive_from_chr_layer(scon, buf, size);
76130c57c0SHeinz Graalfs     /* trigger SCLP read operation */
77130c57c0SHeinz Graalfs     qemu_irq_raise(scon->irq_read_vt220);
78130c57c0SHeinz Graalfs }
79130c57c0SHeinz Graalfs 
80130c57c0SHeinz Graalfs /* functions to be called by event facility */
81130c57c0SHeinz Graalfs 
82130c57c0SHeinz Graalfs static int event_type(void)
83130c57c0SHeinz Graalfs {
84130c57c0SHeinz Graalfs     return SCLP_EVENT_ASCII_CONSOLE_DATA;
85130c57c0SHeinz Graalfs }
86130c57c0SHeinz Graalfs 
87130c57c0SHeinz Graalfs static unsigned int send_mask(void)
88130c57c0SHeinz Graalfs {
89130c57c0SHeinz Graalfs     return SCLP_EVENT_MASK_MSG_ASCII;
90130c57c0SHeinz Graalfs }
91130c57c0SHeinz Graalfs 
92130c57c0SHeinz Graalfs static unsigned int receive_mask(void)
93130c57c0SHeinz Graalfs {
94130c57c0SHeinz Graalfs     return SCLP_EVENT_MASK_MSG_ASCII;
95130c57c0SHeinz Graalfs }
96130c57c0SHeinz Graalfs 
97130c57c0SHeinz Graalfs /* triggered by SCLP's read_event_data -
98130c57c0SHeinz Graalfs  * copy console data byte-stream into provided (SCLP) buffer
99130c57c0SHeinz Graalfs  */
100130c57c0SHeinz Graalfs static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
101130c57c0SHeinz Graalfs                              int avail)
102130c57c0SHeinz Graalfs {
103130c57c0SHeinz Graalfs     SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
104130c57c0SHeinz Graalfs 
105130c57c0SHeinz Graalfs     /* first byte is hex 0 saying an ascii string follows */
106130c57c0SHeinz Graalfs     *buf++ = '\0';
107130c57c0SHeinz Graalfs     avail--;
108130c57c0SHeinz Graalfs     /* if all data fit into provided SCLP buffer */
109130c57c0SHeinz Graalfs     if (avail >= cons->iov_sclp_rest) {
110130c57c0SHeinz Graalfs         /* copy character byte-stream to SCLP buffer */
111ea9ad3e9SHeinz Graalfs         memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest);
112130c57c0SHeinz Graalfs         *size = cons->iov_sclp_rest + 1;
113ea9ad3e9SHeinz Graalfs         cons->iov_sclp = 0;
114ea9ad3e9SHeinz Graalfs         cons->iov_bs = 0;
115130c57c0SHeinz Graalfs         cons->iov_data_len = 0;
116130c57c0SHeinz Graalfs         cons->iov_sclp_rest = 0;
117130c57c0SHeinz Graalfs         event->event_pending = false;
118130c57c0SHeinz Graalfs         /* data provided and no more data pending */
119130c57c0SHeinz Graalfs     } else {
120130c57c0SHeinz Graalfs         /* if provided buffer is too small, just copy part */
121ea9ad3e9SHeinz Graalfs         memcpy(buf, &cons->iov[cons->iov_sclp], avail);
122130c57c0SHeinz Graalfs         *size = avail + 1;
123130c57c0SHeinz Graalfs         cons->iov_sclp_rest -= avail;
124130c57c0SHeinz Graalfs         cons->iov_sclp += avail;
125130c57c0SHeinz Graalfs         /* more data pending */
126130c57c0SHeinz Graalfs     }
127130c57c0SHeinz Graalfs }
128130c57c0SHeinz Graalfs 
129130c57c0SHeinz Graalfs static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
130130c57c0SHeinz Graalfs                            int *slen)
131130c57c0SHeinz Graalfs {
132130c57c0SHeinz Graalfs     int avail;
133130c57c0SHeinz Graalfs     size_t src_len;
134130c57c0SHeinz Graalfs     uint8_t *to;
135130c57c0SHeinz Graalfs     ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
136130c57c0SHeinz Graalfs 
137130c57c0SHeinz Graalfs     if (!event->event_pending) {
138130c57c0SHeinz Graalfs         /* no data pending */
139130c57c0SHeinz Graalfs         return 0;
140130c57c0SHeinz Graalfs     }
141130c57c0SHeinz Graalfs 
142130c57c0SHeinz Graalfs     to = (uint8_t *)&acd->data;
143130c57c0SHeinz Graalfs     avail = *slen - sizeof(ASCIIConsoleData);
144130c57c0SHeinz Graalfs     get_console_data(event, to, &src_len, avail);
145130c57c0SHeinz Graalfs 
146130c57c0SHeinz Graalfs     acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
147130c57c0SHeinz Graalfs     acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
148130c57c0SHeinz Graalfs     acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
149130c57c0SHeinz Graalfs     *slen = avail - src_len;
150130c57c0SHeinz Graalfs 
151130c57c0SHeinz Graalfs     return 1;
152130c57c0SHeinz Graalfs }
153130c57c0SHeinz Graalfs 
154130c57c0SHeinz Graalfs /* triggered by SCLP's write_event_data
1558367a14fSStefan Weil  *  - write console data to character layer
1568367a14fSStefan Weil  *  returns < 0 if an error occurred
157130c57c0SHeinz Graalfs  */
158130c57c0SHeinz Graalfs static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
159130c57c0SHeinz Graalfs                                   size_t len)
160130c57c0SHeinz Graalfs {
161130c57c0SHeinz Graalfs     SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
162130c57c0SHeinz Graalfs 
163130c57c0SHeinz Graalfs     if (!scon->chr) {
164130c57c0SHeinz Graalfs         /* If there's no backend, we can just say we consumed all data. */
165130c57c0SHeinz Graalfs         return len;
166130c57c0SHeinz Graalfs     }
167130c57c0SHeinz Graalfs 
1682e142114SHeinz Graalfs     return qemu_chr_fe_write_all(scon->chr, buf, len);
169130c57c0SHeinz Graalfs }
170130c57c0SHeinz Graalfs 
171130c57c0SHeinz Graalfs static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
172130c57c0SHeinz Graalfs {
173130c57c0SHeinz Graalfs     int rc;
174130c57c0SHeinz Graalfs     int length;
175130c57c0SHeinz Graalfs     ssize_t written;
176130c57c0SHeinz Graalfs     ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
177130c57c0SHeinz Graalfs 
178130c57c0SHeinz Graalfs     length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
179130c57c0SHeinz Graalfs     written = write_console_data(event, (uint8_t *)acd->data, length);
180130c57c0SHeinz Graalfs 
181130c57c0SHeinz Graalfs     rc = SCLP_RC_NORMAL_COMPLETION;
182130c57c0SHeinz Graalfs     /* set event buffer accepted flag */
183130c57c0SHeinz Graalfs     evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
184130c57c0SHeinz Graalfs 
185130c57c0SHeinz Graalfs     /* written will be zero if a pty is not connected - don't treat as error */
186130c57c0SHeinz Graalfs     if (written < 0) {
187130c57c0SHeinz Graalfs         /* event buffer not accepted due to error in character layer */
188130c57c0SHeinz Graalfs         evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
189130c57c0SHeinz Graalfs         rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
190130c57c0SHeinz Graalfs     }
191130c57c0SHeinz Graalfs 
192130c57c0SHeinz Graalfs     return rc;
193130c57c0SHeinz Graalfs }
194130c57c0SHeinz Graalfs 
1959944d320SPaolo Bonzini static void trigger_ascii_console_data(void *opaque, int n, int level)
196130c57c0SHeinz Graalfs {
197130c57c0SHeinz Graalfs     sclp_service_interrupt(0);
198130c57c0SHeinz Graalfs }
199130c57c0SHeinz Graalfs 
200*cb335bebSHeinz Graalfs static const VMStateDescription vmstate_sclpconsole = {
201*cb335bebSHeinz Graalfs     .name = "sclpconsole",
202*cb335bebSHeinz Graalfs     .version_id = 0,
203*cb335bebSHeinz Graalfs     .minimum_version_id = 0,
204*cb335bebSHeinz Graalfs     .minimum_version_id_old = 0,
205*cb335bebSHeinz Graalfs     .fields      = (VMStateField[]) {
206*cb335bebSHeinz Graalfs         VMSTATE_BOOL(event.event_pending, SCLPConsole),
207*cb335bebSHeinz Graalfs         VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
208*cb335bebSHeinz Graalfs         VMSTATE_UINT32(iov_sclp, SCLPConsole),
209*cb335bebSHeinz Graalfs         VMSTATE_UINT32(iov_bs, SCLPConsole),
210*cb335bebSHeinz Graalfs         VMSTATE_UINT32(iov_data_len, SCLPConsole),
211*cb335bebSHeinz Graalfs         VMSTATE_UINT32(iov_sclp_rest, SCLPConsole),
212*cb335bebSHeinz Graalfs         VMSTATE_END_OF_LIST()
213*cb335bebSHeinz Graalfs      }
214*cb335bebSHeinz Graalfs };
215*cb335bebSHeinz Graalfs 
216130c57c0SHeinz Graalfs /* qemu object creation and initialization functions */
217130c57c0SHeinz Graalfs 
218130c57c0SHeinz Graalfs /* tell character layer our call-back functions */
219*cb335bebSHeinz Graalfs 
220130c57c0SHeinz Graalfs static int console_init(SCLPEvent *event)
221130c57c0SHeinz Graalfs {
222130c57c0SHeinz Graalfs     static bool console_available;
223130c57c0SHeinz Graalfs 
224130c57c0SHeinz Graalfs     SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
225130c57c0SHeinz Graalfs 
226130c57c0SHeinz Graalfs     if (console_available) {
227130c57c0SHeinz Graalfs         error_report("Multiple VT220 operator consoles are not supported");
228130c57c0SHeinz Graalfs         return -1;
229130c57c0SHeinz Graalfs     }
230130c57c0SHeinz Graalfs     console_available = true;
231ea9ad3e9SHeinz Graalfs     scon->iov_sclp = 0;
232ea9ad3e9SHeinz Graalfs     scon->iov_bs = 0;
233ea9ad3e9SHeinz Graalfs     scon->iov_data_len = 0;
234ea9ad3e9SHeinz Graalfs     scon->iov_sclp_rest = 0;
235130c57c0SHeinz Graalfs     event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
236130c57c0SHeinz Graalfs     if (scon->chr) {
237130c57c0SHeinz Graalfs         qemu_chr_add_handlers(scon->chr, chr_can_read,
238ea9ad3e9SHeinz Graalfs                               chr_read, NULL, scon);
239130c57c0SHeinz Graalfs     }
240130c57c0SHeinz Graalfs     scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
241130c57c0SHeinz Graalfs                                                NULL, 1);
242130c57c0SHeinz Graalfs 
243130c57c0SHeinz Graalfs     return 0;
244130c57c0SHeinz Graalfs }
245130c57c0SHeinz Graalfs 
246130c57c0SHeinz Graalfs static int console_exit(SCLPEvent *event)
247130c57c0SHeinz Graalfs {
248130c57c0SHeinz Graalfs     return 0;
249130c57c0SHeinz Graalfs }
250130c57c0SHeinz Graalfs 
251130c57c0SHeinz Graalfs static Property console_properties[] = {
252130c57c0SHeinz Graalfs     DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
253130c57c0SHeinz Graalfs     DEFINE_PROP_END_OF_LIST(),
254130c57c0SHeinz Graalfs };
255130c57c0SHeinz Graalfs 
256130c57c0SHeinz Graalfs static void console_class_init(ObjectClass *klass, void *data)
257130c57c0SHeinz Graalfs {
258130c57c0SHeinz Graalfs     DeviceClass *dc = DEVICE_CLASS(klass);
259130c57c0SHeinz Graalfs     SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
260130c57c0SHeinz Graalfs 
261130c57c0SHeinz Graalfs     dc->props = console_properties;
262*cb335bebSHeinz Graalfs     dc->vmsd = &vmstate_sclpconsole;
263130c57c0SHeinz Graalfs     ec->init = console_init;
264130c57c0SHeinz Graalfs     ec->exit = console_exit;
265130c57c0SHeinz Graalfs     ec->get_send_mask = send_mask;
266130c57c0SHeinz Graalfs     ec->get_receive_mask = receive_mask;
267130c57c0SHeinz Graalfs     ec->event_type = event_type;
268130c57c0SHeinz Graalfs     ec->read_event_data = read_event_data;
269130c57c0SHeinz Graalfs     ec->write_event_data = write_event_data;
270130c57c0SHeinz Graalfs }
271130c57c0SHeinz Graalfs 
2728c43a6f0SAndreas Färber static const TypeInfo sclp_console_info = {
273130c57c0SHeinz Graalfs     .name          = "sclpconsole",
274130c57c0SHeinz Graalfs     .parent        = TYPE_SCLP_EVENT,
275130c57c0SHeinz Graalfs     .instance_size = sizeof(SCLPConsole),
276130c57c0SHeinz Graalfs     .class_init    = console_class_init,
277130c57c0SHeinz Graalfs     .class_size    = sizeof(SCLPEventClass),
278130c57c0SHeinz Graalfs };
279130c57c0SHeinz Graalfs 
280130c57c0SHeinz Graalfs static void register_types(void)
281130c57c0SHeinz Graalfs {
282130c57c0SHeinz Graalfs     type_register_static(&sclp_console_info);
283130c57c0SHeinz Graalfs }
284130c57c0SHeinz Graalfs 
285130c57c0SHeinz Graalfs type_init(register_types)
286