qemu

Форк
0
/
sclpconsole.c 
289 строк · 8.1 Кб
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/qdev-properties-system.h"
24
#include "hw/s390x/event-facility.h"
25
#include "chardev/char-fe.h"
26
#include "qom/object.h"
27

28
typedef struct ASCIIConsoleData {
29
    EventBufferHeader ebh;
30
    char data[];
31
} QEMU_PACKED ASCIIConsoleData;
32

33
/* max size for ASCII data in 4K SCCB page */
34
#define SIZE_BUFFER_VT220 4080
35

36
struct SCLPConsole {
37
    SCLPEvent event;
38
    CharBackend chr;
39
    uint8_t iov[SIZE_BUFFER_VT220];
40
    uint32_t iov_sclp;      /* offset in buf for SCLP read operation       */
41
    uint32_t iov_bs;        /* offset in buf for char layer read operation */
42
    uint32_t iov_data_len;  /* length of byte stream in buffer             */
43
    uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP     */
44
    bool notify;            /* qemu_notify_event() req'd if true           */
45
};
46
typedef struct SCLPConsole SCLPConsole;
47

48
#define TYPE_SCLP_CONSOLE "sclpconsole"
49
DECLARE_INSTANCE_CHECKER(SCLPConsole, SCLP_CONSOLE,
50
                         TYPE_SCLP_CONSOLE)
51

52
/* character layer call-back functions */
53

54
/* Return number of bytes that fit into iov buffer */
55
static int chr_can_read(void *opaque)
56
{
57
    SCLPConsole *scon = opaque;
58
    int avail = SIZE_BUFFER_VT220 - scon->iov_data_len;
59

60
    if (avail == 0) {
61
        scon->notify = true;
62
    }
63
    return avail;
64
}
65

66
/* Send data from a char device over to the guest */
67
static void chr_read(void *opaque, const uint8_t *buf, int size)
68
{
69
    SCLPConsole *scon = opaque;
70

71
    assert(scon);
72
    /* read data must fit into current buffer */
73
    assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
74

75
    /* put byte-stream from character layer into buffer */
76
    memcpy(&scon->iov[scon->iov_bs], buf, size);
77
    scon->iov_data_len += size;
78
    scon->iov_sclp_rest += size;
79
    scon->iov_bs += size;
80
    scon->event.event_pending = true;
81
    sclp_service_interrupt(0);
82
}
83

84
/* functions to be called by event facility */
85

86
static bool can_handle_event(uint8_t type)
87
{
88
    return type == SCLP_EVENT_ASCII_CONSOLE_DATA;
89
}
90

91
static sccb_mask_t send_mask(void)
92
{
93
    return SCLP_EVENT_MASK_MSG_ASCII;
94
}
95

96
static sccb_mask_t receive_mask(void)
97
{
98
    return SCLP_EVENT_MASK_MSG_ASCII;
99
}
100

101
/* triggered by SCLP's read_event_data -
102
 * copy console data byte-stream into provided (SCLP) buffer
103
 */
104
static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
105
                             int avail)
106
{
107
    SCLPConsole *cons = SCLP_CONSOLE(event);
108

109
    /* first byte is hex 0 saying an ascii string follows */
110
    *buf++ = '\0';
111
    avail--;
112
    /* if all data fit into provided SCLP buffer */
113
    if (avail >= cons->iov_sclp_rest) {
114
        /* copy character byte-stream to SCLP buffer */
115
        memcpy(buf, &cons->iov[cons->iov_sclp], cons->iov_sclp_rest);
116
        *size = cons->iov_sclp_rest + 1;
117
        cons->iov_sclp = 0;
118
        cons->iov_bs = 0;
119
        cons->iov_data_len = 0;
120
        cons->iov_sclp_rest = 0;
121
        event->event_pending = false;
122
        /* data provided and no more data pending */
123
    } else {
124
        /* if provided buffer is too small, just copy part */
125
        memcpy(buf, &cons->iov[cons->iov_sclp], avail);
126
        *size = avail + 1;
127
        cons->iov_sclp_rest -= avail;
128
        cons->iov_sclp += avail;
129
        /* more data pending */
130
    }
131
    if (cons->notify) {
132
        cons->notify = false;
133
        qemu_notify_event();
134
    }
135
}
136

137
static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
138
                           int *slen)
139
{
140
    int avail;
141
    size_t src_len;
142
    uint8_t *to;
143
    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
144

145
    if (!event->event_pending) {
146
        /* no data pending */
147
        return 0;
148
    }
149

150
    to = (uint8_t *)&acd->data;
151
    avail = *slen - sizeof(ASCIIConsoleData);
152
    get_console_data(event, to, &src_len, avail);
153

154
    acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
155
    acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
156
    acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
157
    *slen = avail - src_len;
158

159
    return 1;
160
}
161

162
/* triggered by SCLP's write_event_data
163
 *  - write console data to character layer
164
 *  returns < 0 if an error occurred
165
 */
166
static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
167
                                  size_t len)
168
{
169
    SCLPConsole *scon = SCLP_CONSOLE(event);
170

171
    if (!qemu_chr_fe_backend_connected(&scon->chr)) {
172
        /* If there's no backend, we can just say we consumed all data. */
173
        return len;
174
    }
175

176
    /* XXX this blocks entire thread. Rewrite to use
177
     * qemu_chr_fe_write and background I/O callbacks */
178
    return qemu_chr_fe_write_all(&scon->chr, buf, len);
179
}
180

181
static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
182
{
183
    int rc;
184
    int length;
185
    ssize_t written;
186
    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
187

188
    length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
189
    written = write_console_data(event, (uint8_t *)acd->data, length);
190

191
    rc = SCLP_RC_NORMAL_COMPLETION;
192
    /* set event buffer accepted flag */
193
    evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
194

195
    /* written will be zero if a pty is not connected - don't treat as error */
196
    if (written < 0) {
197
        /* event buffer not accepted due to error in character layer */
198
        evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
199
        rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
200
    }
201

202
    return rc;
203
}
204

205
static const VMStateDescription vmstate_sclpconsole = {
206
    .name = "sclpconsole",
207
    .version_id = 0,
208
    .minimum_version_id = 0,
209
    .fields = (const VMStateField[]) {
210
        VMSTATE_BOOL(event.event_pending, SCLPConsole),
211
        VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
212
        VMSTATE_UINT32(iov_sclp, SCLPConsole),
213
        VMSTATE_UINT32(iov_bs, SCLPConsole),
214
        VMSTATE_UINT32(iov_data_len, SCLPConsole),
215
        VMSTATE_UINT32(iov_sclp_rest, SCLPConsole),
216
        VMSTATE_END_OF_LIST()
217
     }
218
};
219

220
/* qemu object creation and initialization functions */
221

222
/* tell character layer our call-back functions */
223

224
static int console_init(SCLPEvent *event)
225
{
226
    static bool console_available;
227

228
    SCLPConsole *scon = SCLP_CONSOLE(event);
229

230
    if (console_available) {
231
        error_report("Multiple VT220 operator consoles are not supported");
232
        return -1;
233
    }
234
    console_available = true;
235
    qemu_chr_fe_set_handlers(&scon->chr, chr_can_read,
236
                             chr_read, NULL, NULL, scon, NULL, true);
237

238
    return 0;
239
}
240

241
static void console_reset(DeviceState *dev)
242
{
243
   SCLPEvent *event = SCLP_EVENT(dev);
244
   SCLPConsole *scon = SCLP_CONSOLE(event);
245

246
   event->event_pending = false;
247
   scon->iov_sclp = 0;
248
   scon->iov_bs = 0;
249
   scon->iov_data_len = 0;
250
   scon->iov_sclp_rest = 0;
251
   scon->notify = false;
252
}
253

254
static Property console_properties[] = {
255
    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
256
    DEFINE_PROP_END_OF_LIST(),
257
};
258

259
static void console_class_init(ObjectClass *klass, void *data)
260
{
261
    DeviceClass *dc = DEVICE_CLASS(klass);
262
    SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
263

264
    device_class_set_props(dc, console_properties);
265
    dc->reset = console_reset;
266
    dc->vmsd = &vmstate_sclpconsole;
267
    ec->init = console_init;
268
    ec->get_send_mask = send_mask;
269
    ec->get_receive_mask = receive_mask;
270
    ec->can_handle_event = can_handle_event;
271
    ec->read_event_data = read_event_data;
272
    ec->write_event_data = write_event_data;
273
    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
274
}
275

276
static const TypeInfo sclp_console_info = {
277
    .name          = TYPE_SCLP_CONSOLE,
278
    .parent        = TYPE_SCLP_EVENT,
279
    .instance_size = sizeof(SCLPConsole),
280
    .class_init    = console_class_init,
281
    .class_size    = sizeof(SCLPEventClass),
282
};
283

284
static void register_types(void)
285
{
286
    type_register_static(&sclp_console_info);
287
}
288

289
type_init(register_types)
290

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.