2 * A bus for connecting virtio serial and console ports
4 * Copyright (C) 2009 Red Hat, Inc.
7 * Amit Shah <amit.shah@redhat.com>
9 * Some earlier parts are:
10 * Copyright IBM, Corp. 2008
12 * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
14 * This work is licensed under the terms of the GNU GPL, version 2. See
15 * the COPYING file in the top-level directory.
19 #include "qemu-queue.h"
21 #include "virtio-serial.h"
23 /* The virtio-serial bus on top of which the ports will ride as devices */
24 struct VirtIOSerialBus
{
27 /* This is the parent device that provides the bus for ports. */
30 /* The maximum number of ports that can ride on top of this bus */
31 uint32_t max_nr_ports
;
37 VirtQueue
*c_ivq
, *c_ovq
;
38 /* Arrays of ivqs and ovqs: one per port */
39 VirtQueue
**ivqs
, **ovqs
;
43 QTAILQ_HEAD(, VirtIOSerialPort
) ports
;
44 struct virtio_console_config config
;
47 static VirtIOSerialPort
*find_port_by_id(VirtIOSerial
*vser
, uint32_t id
)
49 VirtIOSerialPort
*port
;
51 QTAILQ_FOREACH(port
, &vser
->ports
, next
) {
58 static VirtIOSerialPort
*find_port_by_vq(VirtIOSerial
*vser
, VirtQueue
*vq
)
60 VirtIOSerialPort
*port
;
62 QTAILQ_FOREACH(port
, &vser
->ports
, next
) {
63 if (port
->ivq
== vq
|| port
->ovq
== vq
)
69 static size_t write_to_port(VirtIOSerialPort
*port
,
70 const uint8_t *buf
, size_t size
)
72 VirtQueueElement elem
;
78 if (!virtio_queue_ready(vq
)) {
85 while (offset
< size
) {
88 if (!virtqueue_pop(vq
, &elem
)) {
92 for (i
= 0; offset
< size
&& i
< elem
.in_num
; i
++) {
93 len
= MIN(elem
.in_sg
[i
].iov_len
, size
- offset
);
95 memcpy(elem
.in_sg
[i
].iov_base
, buf
+ offset
, len
);
98 virtqueue_push(vq
, &elem
, len
);
101 virtio_notify(&port
->vser
->vdev
, vq
);
105 static size_t send_control_msg(VirtIOSerialPort
*port
, void *buf
, size_t len
)
107 VirtQueueElement elem
;
109 struct virtio_console_control
*cpkt
;
111 vq
= port
->vser
->c_ivq
;
112 if (!virtio_queue_ready(vq
)) {
115 if (!virtqueue_pop(vq
, &elem
)) {
119 cpkt
= (struct virtio_console_control
*)buf
;
120 stl_p(&cpkt
->id
, port
->id
);
121 memcpy(elem
.in_sg
[0].iov_base
, buf
, len
);
123 virtqueue_push(vq
, &elem
, len
);
124 virtio_notify(&port
->vser
->vdev
, vq
);
128 static size_t send_control_event(VirtIOSerialPort
*port
, uint16_t event
,
131 struct virtio_console_control cpkt
;
133 stw_p(&cpkt
.event
, event
);
134 stw_p(&cpkt
.value
, value
);
136 return send_control_msg(port
, &cpkt
, sizeof(cpkt
));
139 /* Functions for use inside qemu to open and read from/write to ports */
140 int virtio_serial_open(VirtIOSerialPort
*port
)
145 int virtio_serial_close(VirtIOSerialPort
*port
)
150 /* Individual ports/apps call this function to write to the guest. */
151 ssize_t
virtio_serial_write(VirtIOSerialPort
*port
, const uint8_t *buf
,
154 return write_to_port(port
, buf
, size
);
158 * Readiness of the guest to accept data on a port.
159 * Returns max. data the guest can receive
161 size_t virtio_serial_guest_ready(VirtIOSerialPort
*port
)
163 VirtQueue
*vq
= port
->ivq
;
165 if (!virtio_queue_ready(vq
) ||
166 !(port
->vser
->vdev
.status
& VIRTIO_CONFIG_S_DRIVER_OK
) ||
167 virtio_queue_empty(vq
)) {
171 if (virtqueue_avail_bytes(vq
, 4096, 0)) {
174 if (virtqueue_avail_bytes(vq
, 1, 0)) {
180 /* Guest wants to notify us of some event */
181 static void handle_control_message(VirtIOSerial
*vser
, void *buf
)
183 struct VirtIOSerialPort
*port
;
184 struct virtio_console_control cpkt
, *gcpkt
;
187 port
= find_port_by_id(vser
, ldl_p(&gcpkt
->id
));
191 cpkt
.event
= lduw_p(&gcpkt
->event
);
192 cpkt
.value
= lduw_p(&gcpkt
->value
);
195 case VIRTIO_CONSOLE_PORT_READY
:
197 * Now that we know the guest asked for the port name, we're
198 * sure the guest has initialised whatever state is necessary
199 * for this port. Now's a good time to let the guest know if
200 * this port is a console port so that the guest can hook it
203 if (port
->is_console
) {
204 send_control_event(port
, VIRTIO_CONSOLE_CONSOLE_PORT
, 1);
207 * When the guest has asked us for this information it means
208 * the guest is all setup and has its virtqueues
209 * initialised. If some app is interested in knowing about
210 * this event, let it know.
212 if (port
->info
->guest_ready
) {
213 port
->info
->guest_ready(port
);
219 static void control_in(VirtIODevice
*vdev
, VirtQueue
*vq
)
223 static void control_out(VirtIODevice
*vdev
, VirtQueue
*vq
)
225 VirtQueueElement elem
;
228 vser
= DO_UPCAST(VirtIOSerial
, vdev
, vdev
);
230 while (virtqueue_pop(vq
, &elem
)) {
231 handle_control_message(vser
, elem
.out_sg
[0].iov_base
);
232 virtqueue_push(vq
, &elem
, elem
.out_sg
[0].iov_len
);
234 virtio_notify(vdev
, vq
);
237 /* Guest wrote something to some port. */
238 static void handle_output(VirtIODevice
*vdev
, VirtQueue
*vq
)
241 VirtQueueElement elem
;
243 vser
= DO_UPCAST(VirtIOSerial
, vdev
, vdev
);
245 while (virtqueue_pop(vq
, &elem
)) {
246 VirtIOSerialPort
*port
;
249 port
= find_port_by_vq(vser
, vq
);
256 * A port may not have any handler registered for consuming the
257 * data that the guest sends or it may not have a chardev associated
258 * with it. Just ignore the data in that case.
260 if (!port
->info
->have_data
) {
265 /* The guest always sends only one sg */
266 ret
= port
->info
->have_data(port
, elem
.out_sg
[0].iov_base
,
267 elem
.out_sg
[0].iov_len
);
270 virtqueue_push(vq
, &elem
, ret
);
272 virtio_notify(vdev
, vq
);
275 static void handle_input(VirtIODevice
*vdev
, VirtQueue
*vq
)
279 static uint32_t get_features(VirtIODevice
*vdev
, uint32_t features
)
281 features
|= (1 << VIRTIO_CONSOLE_F_MULTIPORT
);
286 /* Guest requested config info */
287 static void get_config(VirtIODevice
*vdev
, uint8_t *config_data
)
291 vser
= DO_UPCAST(VirtIOSerial
, vdev
, vdev
);
292 memcpy(config_data
, &vser
->config
, sizeof(struct virtio_console_config
));
295 static void set_config(VirtIODevice
*vdev
, const uint8_t *config_data
)
297 struct virtio_console_config config
;
299 memcpy(&config
, config_data
, sizeof(config
));
302 static void virtio_serial_save(QEMUFile
*f
, void *opaque
)
304 VirtIOSerial
*s
= opaque
;
306 /* The virtio device */
307 virtio_save(&s
->vdev
, f
);
309 /* The config space */
310 qemu_put_be16s(f
, &s
->config
.cols
);
311 qemu_put_be16s(f
, &s
->config
.rows
);
312 qemu_put_be32s(f
, &s
->config
.nr_ports
);
315 static int virtio_serial_load(QEMUFile
*f
, void *opaque
, int version_id
)
317 VirtIOSerial
*s
= opaque
;
319 if (version_id
> 2) {
322 /* The virtio device */
323 virtio_load(&s
->vdev
, f
);
325 if (version_id
< 2) {
329 /* The config space */
330 qemu_get_be16s(f
, &s
->config
.cols
);
331 qemu_get_be16s(f
, &s
->config
.rows
);
332 s
->config
.nr_ports
= qemu_get_be32(f
);
337 static void virtser_bus_dev_print(Monitor
*mon
, DeviceState
*qdev
, int indent
);
339 static struct BusInfo virtser_bus_info
= {
340 .name
= "virtio-serial-bus",
341 .size
= sizeof(VirtIOSerialBus
),
342 .print_dev
= virtser_bus_dev_print
,
345 static VirtIOSerialBus
*virtser_bus_new(DeviceState
*dev
)
347 VirtIOSerialBus
*bus
;
349 bus
= FROM_QBUS(VirtIOSerialBus
, qbus_create(&virtser_bus_info
, dev
,
350 "virtio-serial-bus"));
351 bus
->qbus
.allow_hotplug
= 1;
356 static void virtser_bus_dev_print(Monitor
*mon
, DeviceState
*qdev
, int indent
)
358 VirtIOSerialDevice
*dev
= DO_UPCAST(VirtIOSerialDevice
, qdev
, qdev
);
359 VirtIOSerialPort
*port
= DO_UPCAST(VirtIOSerialPort
, dev
, &dev
->qdev
);
361 monitor_printf(mon
, "%*s dev-prop-int: id: %u\n",
362 indent
, "", port
->id
);
365 static int virtser_port_qdev_init(DeviceState
*qdev
, DeviceInfo
*base
)
367 VirtIOSerialDevice
*dev
= DO_UPCAST(VirtIOSerialDevice
, qdev
, qdev
);
368 VirtIOSerialPortInfo
*info
= DO_UPCAST(VirtIOSerialPortInfo
, qdev
, base
);
369 VirtIOSerialPort
*port
= DO_UPCAST(VirtIOSerialPort
, dev
, &dev
->qdev
);
370 VirtIOSerialBus
*bus
= DO_UPCAST(VirtIOSerialBus
, qbus
, qdev
->parent_bus
);
374 port
->vser
= bus
->vser
;
377 * Is the first console port we're seeing? If so, put it up at
378 * location 0. This is done for backward compatibility (old
381 plugging_port0
= port
->is_console
&& !find_port_by_id(port
->vser
, 0);
383 if (port
->vser
->config
.nr_ports
== bus
->max_nr_ports
&& !plugging_port0
) {
384 qemu_error("virtio-serial-bus: Maximum device limit reached\n");
389 ret
= info
->init(dev
);
394 port
->id
= plugging_port0
? 0 : port
->vser
->config
.nr_ports
++;
396 QTAILQ_INSERT_TAIL(&port
->vser
->ports
, port
, next
);
397 port
->ivq
= port
->vser
->ivqs
[port
->id
];
398 port
->ovq
= port
->vser
->ovqs
[port
->id
];
400 /* Send an update to the guest about this new port added */
401 virtio_notify_config(&port
->vser
->vdev
);
406 static int virtser_port_qdev_exit(DeviceState
*qdev
)
408 VirtIOSerialDevice
*dev
= DO_UPCAST(VirtIOSerialDevice
, qdev
, qdev
);
409 VirtIOSerialPort
*port
= DO_UPCAST(VirtIOSerialPort
, dev
, &dev
->qdev
);
410 VirtIOSerial
*vser
= port
->vser
;
413 * Don't decrement nr_ports here; thus we keep a linearly
414 * increasing port id. Not utilising an id again saves us a couple
417 * - Not having to bother about sending the port id to the guest
418 * kernel on hotplug or on addition of new ports; the guest can
419 * also linearly increment the port number. This is preferable
420 * because the config space won't have the need to store a
423 * - Extra state to be stored for all the "holes" that got created
424 * so that we keep filling in the ids from the least available
427 * When such a functionality is desired, a control message to add
428 * a port can be introduced.
430 QTAILQ_REMOVE(&vser
->ports
, port
, next
);
432 if (port
->info
->exit
)
433 port
->info
->exit(dev
);
438 void virtio_serial_port_qdev_register(VirtIOSerialPortInfo
*info
)
440 info
->qdev
.init
= virtser_port_qdev_init
;
441 info
->qdev
.bus_info
= &virtser_bus_info
;
442 info
->qdev
.exit
= virtser_port_qdev_exit
;
443 info
->qdev
.unplug
= qdev_simple_unplug_cb
;
444 qdev_register(&info
->qdev
);
447 VirtIODevice
*virtio_serial_init(DeviceState
*dev
, uint32_t max_nr_ports
)
456 vdev
= virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE
,
457 sizeof(struct virtio_console_config
),
458 sizeof(VirtIOSerial
));
460 vser
= DO_UPCAST(VirtIOSerial
, vdev
, vdev
);
462 /* Spawn a new virtio-serial bus on which the ports will ride as devices */
463 vser
->bus
= virtser_bus_new(dev
);
464 vser
->bus
->vser
= vser
;
465 QTAILQ_INIT(&vser
->ports
);
467 vser
->bus
->max_nr_ports
= max_nr_ports
;
468 vser
->ivqs
= qemu_malloc(max_nr_ports
* sizeof(VirtQueue
*));
469 vser
->ovqs
= qemu_malloc(max_nr_ports
* sizeof(VirtQueue
*));
471 /* Add a queue for host to guest transfers for port 0 (backward compat) */
472 vser
->ivqs
[0] = virtio_add_queue(vdev
, 128, handle_input
);
473 /* Add a queue for guest to host transfers for port 0 (backward compat) */
474 vser
->ovqs
[0] = virtio_add_queue(vdev
, 128, handle_output
);
476 /* control queue: host to guest */
477 vser
->c_ivq
= virtio_add_queue(vdev
, 16, control_in
);
478 /* control queue: guest to host */
479 vser
->c_ovq
= virtio_add_queue(vdev
, 16, control_out
);
481 for (i
= 1; i
< vser
->bus
->max_nr_ports
; i
++) {
482 /* Add a per-port queue for host to guest transfers */
483 vser
->ivqs
[i
] = virtio_add_queue(vdev
, 128, handle_input
);
484 /* Add a per-per queue for guest to host transfers */
485 vser
->ovqs
[i
] = virtio_add_queue(vdev
, 128, handle_output
);
488 vser
->config
.max_nr_ports
= max_nr_ports
;
490 * Reserve location 0 for a console port for backward compat
491 * (old kernel, new qemu)
493 vser
->config
.nr_ports
= 1;
495 vser
->vdev
.get_features
= get_features
;
496 vser
->vdev
.get_config
= get_config
;
497 vser
->vdev
.set_config
= set_config
;
500 * Register for the savevm section with the virtio-console name
501 * to preserve backward compat
503 register_savevm("virtio-console", -1, 2, virtio_serial_save
,
504 virtio_serial_load
, vser
);