]> Git Repo - qemu.git/blob - hw/virtio-serial-bus.c
virtio-serial: don't crash on invalid input
[qemu.git] / hw / virtio-serial-bus.c
1 /*
2  * A bus for connecting virtio serial and console ports
3  *
4  * Copyright (C) 2009, 2010 Red Hat, Inc.
5  *
6  * Author(s):
7  *  Amit Shah <[email protected]>
8  *
9  * Some earlier parts are:
10  *  Copyright IBM, Corp. 2008
11  * authored by
12  *  Christian Ehrhardt <[email protected]>
13  *
14  * This work is licensed under the terms of the GNU GPL, version 2.  See
15  * the COPYING file in the top-level directory.
16  */
17
18 #include "iov.h"
19 #include "monitor.h"
20 #include "qemu-queue.h"
21 #include "sysbus.h"
22 #include "virtio-serial.h"
23
24 /* The virtio-serial bus on top of which the ports will ride as devices */
25 struct VirtIOSerialBus {
26     BusState qbus;
27
28     /* This is the parent device that provides the bus for ports. */
29     VirtIOSerial *vser;
30
31     /* The maximum number of ports that can ride on top of this bus */
32     uint32_t max_nr_ports;
33 };
34
35 struct VirtIOSerial {
36     VirtIODevice vdev;
37
38     VirtQueue *c_ivq, *c_ovq;
39     /* Arrays of ivqs and ovqs: one per port */
40     VirtQueue **ivqs, **ovqs;
41
42     VirtIOSerialBus *bus;
43
44     DeviceState *qdev;
45
46     QTAILQ_HEAD(, VirtIOSerialPort) ports;
47
48     /* bitmap for identifying active ports */
49     uint32_t *ports_map;
50
51     struct virtio_console_config config;
52 };
53
54 static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
55 {
56     VirtIOSerialPort *port;
57
58     if (id == VIRTIO_CONSOLE_BAD_ID) {
59         return NULL;
60     }
61
62     QTAILQ_FOREACH(port, &vser->ports, next) {
63         if (port->id == id)
64             return port;
65     }
66     return NULL;
67 }
68
69 static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
70 {
71     VirtIOSerialPort *port;
72
73     QTAILQ_FOREACH(port, &vser->ports, next) {
74         if (port->ivq == vq || port->ovq == vq)
75             return port;
76     }
77     return NULL;
78 }
79
80 static bool use_multiport(VirtIOSerial *vser)
81 {
82     return vser->vdev.guest_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
83 }
84
85 static size_t write_to_port(VirtIOSerialPort *port,
86                             const uint8_t *buf, size_t size)
87 {
88     VirtQueueElement elem;
89     VirtQueue *vq;
90     size_t offset;
91
92     vq = port->ivq;
93     if (!virtio_queue_ready(vq)) {
94         return 0;
95     }
96
97     offset = 0;
98     while (offset < size) {
99         size_t len;
100
101         if (!virtqueue_pop(vq, &elem)) {
102             break;
103         }
104
105         len = iov_from_buf(elem.in_sg, elem.in_num,
106                            buf + offset, size - offset);
107         offset += len;
108
109         virtqueue_push(vq, &elem, len);
110     }
111
112     virtio_notify(&port->vser->vdev, vq);
113     return offset;
114 }
115
116 static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
117 {
118     VirtQueueElement elem;
119
120     if (!virtio_queue_ready(vq)) {
121         return;
122     }
123     while (virtqueue_pop(vq, &elem)) {
124         virtqueue_push(vq, &elem, 0);
125     }
126     virtio_notify(vdev, vq);
127 }
128
129 static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
130                                  VirtIODevice *vdev)
131 {
132     assert(port);
133     assert(virtio_queue_ready(vq));
134
135     while (!port->throttled) {
136         unsigned int i;
137
138         /* Pop an elem only if we haven't left off a previous one mid-way */
139         if (!port->elem.out_num) {
140             if (!virtqueue_pop(vq, &port->elem)) {
141                 break;
142             }
143             port->iov_idx = 0;
144             port->iov_offset = 0;
145         }
146
147         for (i = port->iov_idx; i < port->elem.out_num; i++) {
148             size_t buf_size;
149             ssize_t ret;
150
151             buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
152             ret = port->info->have_data(port,
153                                         port->elem.out_sg[i].iov_base
154                                           + port->iov_offset,
155                                         buf_size);
156             if (ret < 0 && ret != -EAGAIN) {
157                 /* We don't handle any other type of errors here */
158                 abort();
159             }
160             if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) {
161                 virtio_serial_throttle_port(port, true);
162                 port->iov_idx = i;
163                 if (ret > 0) {
164                     port->iov_offset += ret;
165                 }
166                 break;
167             }
168             port->iov_offset = 0;
169         }
170         if (port->throttled) {
171             break;
172         }
173         virtqueue_push(vq, &port->elem, 0);
174         port->elem.out_num = 0;
175     }
176     virtio_notify(vdev, vq);
177 }
178
179 static void flush_queued_data(VirtIOSerialPort *port)
180 {
181     assert(port);
182
183     if (!virtio_queue_ready(port->ovq)) {
184         return;
185     }
186     do_flush_queued_data(port, port->ovq, &port->vser->vdev);
187 }
188
189 static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
190 {
191     VirtQueueElement elem;
192     VirtQueue *vq;
193     struct virtio_console_control *cpkt;
194
195     vq = port->vser->c_ivq;
196     if (!virtio_queue_ready(vq)) {
197         return 0;
198     }
199     if (!virtqueue_pop(vq, &elem)) {
200         return 0;
201     }
202
203     cpkt = (struct virtio_console_control *)buf;
204     stl_p(&cpkt->id, port->id);
205     memcpy(elem.in_sg[0].iov_base, buf, len);
206
207     virtqueue_push(vq, &elem, len);
208     virtio_notify(&port->vser->vdev, vq);
209     return len;
210 }
211
212 static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
213                                  uint16_t value)
214 {
215     struct virtio_console_control cpkt;
216
217     stw_p(&cpkt.event, event);
218     stw_p(&cpkt.value, value);
219
220     return send_control_msg(port, &cpkt, sizeof(cpkt));
221 }
222
223 /* Functions for use inside qemu to open and read from/write to ports */
224 int virtio_serial_open(VirtIOSerialPort *port)
225 {
226     /* Don't allow opening an already-open port */
227     if (port->host_connected) {
228         return 0;
229     }
230     /* Send port open notification to the guest */
231     port->host_connected = true;
232     send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
233
234     return 0;
235 }
236
237 int virtio_serial_close(VirtIOSerialPort *port)
238 {
239     port->host_connected = false;
240     /*
241      * If there's any data the guest sent which the app didn't
242      * consume, reset the throttling flag and discard the data.
243      */
244     port->throttled = false;
245     discard_vq_data(port->ovq, &port->vser->vdev);
246
247     send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
248
249     return 0;
250 }
251
252 /* Individual ports/apps call this function to write to the guest. */
253 ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
254                             size_t size)
255 {
256     if (!port || !port->host_connected || !port->guest_connected) {
257         return 0;
258     }
259     return write_to_port(port, buf, size);
260 }
261
262 /*
263  * Readiness of the guest to accept data on a port.
264  * Returns max. data the guest can receive
265  */
266 size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
267 {
268     VirtQueue *vq = port->ivq;
269
270     if (!virtio_queue_ready(vq) ||
271         !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
272         virtio_queue_empty(vq)) {
273         return 0;
274     }
275     if (use_multiport(port->vser) && !port->guest_connected) {
276         return 0;
277     }
278
279     if (virtqueue_avail_bytes(vq, 4096, 0)) {
280         return 4096;
281     }
282     if (virtqueue_avail_bytes(vq, 1, 0)) {
283         return 1;
284     }
285     return 0;
286 }
287
288 void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
289 {
290     if (!port) {
291         return;
292     }
293
294     port->throttled = throttle;
295     if (throttle) {
296         return;
297     }
298
299     flush_queued_data(port);
300 }
301
302 /* Guest wants to notify us of some event */
303 static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
304 {
305     struct VirtIOSerialPort *port;
306     struct virtio_console_control cpkt, *gcpkt;
307     uint8_t *buffer;
308     size_t buffer_len;
309
310     gcpkt = buf;
311
312     if (len < sizeof(cpkt)) {
313         /* The guest sent an invalid control packet */
314         return;
315     }
316
317     cpkt.event = lduw_p(&gcpkt->event);
318     cpkt.value = lduw_p(&gcpkt->value);
319
320     port = find_port_by_id(vser, ldl_p(&gcpkt->id));
321     if (!port && cpkt.event != VIRTIO_CONSOLE_DEVICE_READY)
322         return;
323
324     switch(cpkt.event) {
325     case VIRTIO_CONSOLE_DEVICE_READY:
326         if (!cpkt.value) {
327             error_report("virtio-serial-bus: Guest failure in adding device %s\n",
328                          vser->bus->qbus.name);
329             break;
330         }
331         /*
332          * The device is up, we can now tell the device about all the
333          * ports we have here.
334          */
335         QTAILQ_FOREACH(port, &vser->ports, next) {
336             send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1);
337         }
338         break;
339
340     case VIRTIO_CONSOLE_PORT_READY:
341         if (!cpkt.value) {
342             error_report("virtio-serial-bus: Guest failure in adding port %u for device %s\n",
343                          port->id, vser->bus->qbus.name);
344             break;
345         }
346         /*
347          * Now that we know the guest asked for the port name, we're
348          * sure the guest has initialised whatever state is necessary
349          * for this port. Now's a good time to let the guest know if
350          * this port is a console port so that the guest can hook it
351          * up to hvc.
352          */
353         if (port->is_console) {
354             send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
355         }
356
357         if (port->name) {
358             stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
359             stw_p(&cpkt.value, 1);
360
361             buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
362             buffer = qemu_malloc(buffer_len);
363
364             memcpy(buffer, &cpkt, sizeof(cpkt));
365             memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
366             buffer[buffer_len - 1] = 0;
367
368             send_control_msg(port, buffer, buffer_len);
369             qemu_free(buffer);
370         }
371
372         if (port->host_connected) {
373             send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
374         }
375
376         /*
377          * When the guest has asked us for this information it means
378          * the guest is all setup and has its virtqueues
379          * initialised. If some app is interested in knowing about
380          * this event, let it know.
381          */
382         if (port->info->guest_ready) {
383             port->info->guest_ready(port);
384         }
385         break;
386
387     case VIRTIO_CONSOLE_PORT_OPEN:
388         port->guest_connected = cpkt.value;
389         if (cpkt.value && port->info->guest_open) {
390             /* Send the guest opened notification if an app is interested */
391             port->info->guest_open(port);
392         }
393
394         if (!cpkt.value && port->info->guest_close) {
395             /* Send the guest closed notification if an app is interested */
396             port->info->guest_close(port);
397         }
398         break;
399     }
400 }
401
402 static void control_in(VirtIODevice *vdev, VirtQueue *vq)
403 {
404 }
405
406 static void control_out(VirtIODevice *vdev, VirtQueue *vq)
407 {
408     VirtQueueElement elem;
409     VirtIOSerial *vser;
410     uint8_t *buf;
411     size_t len;
412
413     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
414
415     len = 0;
416     buf = NULL;
417     while (virtqueue_pop(vq, &elem)) {
418         size_t cur_len, copied;
419
420         cur_len = iov_size(elem.out_sg, elem.out_num);
421         /*
422          * Allocate a new buf only if we didn't have one previously or
423          * if the size of the buf differs
424          */
425         if (cur_len > len) {
426             qemu_free(buf);
427
428             buf = qemu_malloc(cur_len);
429             len = cur_len;
430         }
431         copied = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, len);
432
433         handle_control_message(vser, buf, copied);
434         virtqueue_push(vq, &elem, 0);
435     }
436     qemu_free(buf);
437     virtio_notify(vdev, vq);
438 }
439
440 /* Guest wrote something to some port. */
441 static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
442 {
443     VirtIOSerial *vser;
444     VirtIOSerialPort *port;
445
446     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
447     port = find_port_by_vq(vser, vq);
448
449     if (!port || !port->host_connected || !port->info->have_data) {
450         discard_vq_data(vq, vdev);
451         return;
452     }
453
454     if (!port->throttled) {
455         do_flush_queued_data(port, vq, vdev);
456         return;
457     }
458 }
459
460 static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
461 {
462 }
463
464 static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
465 {
466     VirtIOSerial *vser;
467
468     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
469
470     if (vser->bus->max_nr_ports > 1) {
471         features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
472     }
473     return features;
474 }
475
476 /* Guest requested config info */
477 static void get_config(VirtIODevice *vdev, uint8_t *config_data)
478 {
479     VirtIOSerial *vser;
480
481     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
482     memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
483 }
484
485 static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
486 {
487     struct virtio_console_config config;
488
489     memcpy(&config, config_data, sizeof(config));
490 }
491
492 static void virtio_serial_save(QEMUFile *f, void *opaque)
493 {
494     VirtIOSerial *s = opaque;
495     VirtIOSerialPort *port;
496     uint32_t nr_active_ports;
497     unsigned int i;
498
499     /* The virtio device */
500     virtio_save(&s->vdev, f);
501
502     /* The config space */
503     qemu_put_be16s(f, &s->config.cols);
504     qemu_put_be16s(f, &s->config.rows);
505
506     qemu_put_be32s(f, &s->config.max_nr_ports);
507
508     /* The ports map */
509
510     for (i = 0; i < (s->config.max_nr_ports + 31) / 32; i++) {
511         qemu_put_be32s(f, &s->ports_map[i]);
512     }
513
514     /* Ports */
515
516     nr_active_ports = 0;
517     QTAILQ_FOREACH(port, &s->ports, next) {
518         nr_active_ports++;
519     }
520
521     qemu_put_be32s(f, &nr_active_ports);
522
523     /*
524      * Items in struct VirtIOSerialPort.
525      */
526     QTAILQ_FOREACH(port, &s->ports, next) {
527         uint32_t elem_popped;
528
529         qemu_put_be32s(f, &port->id);
530         qemu_put_byte(f, port->guest_connected);
531         qemu_put_byte(f, port->host_connected);
532
533         elem_popped = 0;
534         if (port->elem.out_num) {
535             elem_popped = 1;
536         }
537         qemu_put_be32s(f, &elem_popped);
538         if (elem_popped) {
539             qemu_put_be32s(f, &port->iov_idx);
540             qemu_put_be64s(f, &port->iov_offset);
541
542             qemu_put_buffer(f, (unsigned char *)&port->elem,
543                             sizeof(port->elem));
544         }
545     }
546 }
547
548 static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
549 {
550     VirtIOSerial *s = opaque;
551     VirtIOSerialPort *port;
552     uint32_t max_nr_ports, nr_active_ports, ports_map;
553     unsigned int i;
554
555     if (version_id > 3) {
556         return -EINVAL;
557     }
558
559     /* The virtio device */
560     virtio_load(&s->vdev, f);
561
562     if (version_id < 2) {
563         return 0;
564     }
565
566     /* The config space */
567     qemu_get_be16s(f, &s->config.cols);
568     qemu_get_be16s(f, &s->config.rows);
569
570     qemu_get_be32s(f, &max_nr_ports);
571     if (max_nr_ports > s->config.max_nr_ports) {
572         /* Source could have had more ports than us. Fail migration. */
573         return -EINVAL;
574     }
575
576     for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
577         qemu_get_be32s(f, &ports_map);
578
579         if (ports_map != s->ports_map[i]) {
580             /*
581              * Ports active on source and destination don't
582              * match. Fail migration.
583              */
584             return -EINVAL;
585         }
586     }
587
588     qemu_get_be32s(f, &nr_active_ports);
589
590     /* Items in struct VirtIOSerialPort */
591     for (i = 0; i < nr_active_ports; i++) {
592         uint32_t id;
593         bool host_connected;
594
595         id = qemu_get_be32(f);
596         port = find_port_by_id(s, id);
597         if (!port) {
598             return -EINVAL;
599         }
600
601         port->guest_connected = qemu_get_byte(f);
602         host_connected = qemu_get_byte(f);
603         if (host_connected != port->host_connected) {
604             /*
605              * We have to let the guest know of the host connection
606              * status change
607              */
608             send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
609                                port->host_connected);
610         }
611
612         if (version_id > 2) {
613             uint32_t elem_popped;
614
615             qemu_get_be32s(f, &elem_popped);
616             if (elem_popped) {
617                 qemu_get_be32s(f, &port->iov_idx);
618                 qemu_get_be64s(f, &port->iov_offset);
619
620                 qemu_get_buffer(f, (unsigned char *)&port->elem,
621                                 sizeof(port->elem));
622                 virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
623                                  port->elem.in_num, 1);
624                 virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
625                                  port->elem.out_num, 1);
626
627                 /*
628                  *  Port was throttled on source machine.  Let's
629                  *  unthrottle it here so data starts flowing again.
630                  */
631                 virtio_serial_throttle_port(port, false);
632             }
633         }
634     }
635     return 0;
636 }
637
638 static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
639
640 static struct BusInfo virtser_bus_info = {
641     .name      = "virtio-serial-bus",
642     .size      = sizeof(VirtIOSerialBus),
643     .print_dev = virtser_bus_dev_print,
644 };
645
646 static VirtIOSerialBus *virtser_bus_new(DeviceState *dev)
647 {
648     VirtIOSerialBus *bus;
649
650     bus = FROM_QBUS(VirtIOSerialBus, qbus_create(&virtser_bus_info, dev, NULL));
651     bus->qbus.allow_hotplug = 1;
652
653     return bus;
654 }
655
656 static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
657 {
658     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
659
660     monitor_printf(mon, "%*s dev-prop-int: id: %u\n",
661                    indent, "", port->id);
662     monitor_printf(mon, "%*s dev-prop-int: guest_connected: %d\n",
663                    indent, "", port->guest_connected);
664     monitor_printf(mon, "%*s dev-prop-int: host_connected: %d\n",
665                    indent, "", port->host_connected);
666     monitor_printf(mon, "%*s dev-prop-int: throttled: %d\n",
667                    indent, "", port->throttled);
668 }
669
670 /* This function is only used if a port id is not provided by the user */
671 static uint32_t find_free_port_id(VirtIOSerial *vser)
672 {
673     unsigned int i;
674
675     for (i = 0; i < (vser->config.max_nr_ports + 31) / 32; i++) {
676         uint32_t map, bit;
677
678         map = vser->ports_map[i];
679         bit = ffs(~map);
680         if (bit) {
681             return (bit - 1) + i * 32;
682         }
683     }
684     return VIRTIO_CONSOLE_BAD_ID;
685 }
686
687 static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
688 {
689     unsigned int i;
690
691     i = port_id / 32;
692     vser->ports_map[i] |= 1U << (port_id % 32);
693 }
694
695 static void add_port(VirtIOSerial *vser, uint32_t port_id)
696 {
697     mark_port_added(vser, port_id);
698
699     send_control_event(find_port_by_id(vser, port_id),
700                        VIRTIO_CONSOLE_PORT_ADD, 1);
701 }
702
703 static void remove_port(VirtIOSerial *vser, uint32_t port_id)
704 {
705     VirtIOSerialPort *port;
706     unsigned int i;
707
708     i = port_id / 32;
709     vser->ports_map[i] &= ~(1U << (port_id % 32));
710
711     port = find_port_by_id(vser, port_id);
712     /* Flush out any unconsumed buffers first */
713     discard_vq_data(port->ovq, &port->vser->vdev);
714
715     send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
716 }
717
718 static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
719 {
720     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
721     VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
722     VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
723     int ret;
724     bool plugging_port0;
725
726     port->vser = bus->vser;
727
728     /*
729      * Is the first console port we're seeing? If so, put it up at
730      * location 0. This is done for backward compatibility (old
731      * kernel, new qemu).
732      */
733     plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0);
734
735     if (find_port_by_id(port->vser, port->id)) {
736         error_report("virtio-serial-bus: A port already exists at id %u\n",
737                      port->id);
738         return -1;
739     }
740
741     if (port->id == VIRTIO_CONSOLE_BAD_ID) {
742         if (plugging_port0) {
743             port->id = 0;
744         } else {
745             port->id = find_free_port_id(port->vser);
746             if (port->id == VIRTIO_CONSOLE_BAD_ID) {
747                 error_report("virtio-serial-bus: Maximum port limit for this device reached\n");
748                 return -1;
749             }
750         }
751     }
752
753     if (port->id >= port->vser->config.max_nr_ports) {
754         error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u\n",
755                      port->vser->config.max_nr_ports - 1);
756         return -1;
757     }
758
759     port->info = info;
760     ret = info->init(port);
761     if (ret) {
762         return ret;
763     }
764
765     if (!use_multiport(port->vser)) {
766         /*
767          * Allow writes to guest in this case; we have no way of
768          * knowing if a guest port is connected.
769          */
770         port->guest_connected = true;
771     }
772
773     port->elem.out_num = 0;
774
775     QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
776     port->ivq = port->vser->ivqs[port->id];
777     port->ovq = port->vser->ovqs[port->id];
778
779     add_port(port->vser, port->id);
780
781     /* Send an update to the guest about this new port added */
782     virtio_notify_config(&port->vser->vdev);
783
784     return ret;
785 }
786
787 static int virtser_port_qdev_exit(DeviceState *qdev)
788 {
789     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
790     VirtIOSerial *vser = port->vser;
791
792     remove_port(port->vser, port->id);
793
794     QTAILQ_REMOVE(&vser->ports, port, next);
795
796     if (port->info->exit)
797         port->info->exit(port);
798
799     return 0;
800 }
801
802 void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
803 {
804     info->qdev.init = virtser_port_qdev_init;
805     info->qdev.bus_info = &virtser_bus_info;
806     info->qdev.exit = virtser_port_qdev_exit;
807     info->qdev.unplug = qdev_simple_unplug_cb;
808     qdev_register(&info->qdev);
809 }
810
811 VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
812 {
813     VirtIOSerial *vser;
814     VirtIODevice *vdev;
815     uint32_t i, max_supported_ports;
816
817     if (!conf->max_virtserial_ports)
818         return NULL;
819
820     /* Each port takes 2 queues, and one pair is for the control queue */
821     max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
822
823     if (conf->max_virtserial_ports > max_supported_ports) {
824         error_report("maximum ports supported: %u", max_supported_ports);
825         return NULL;
826     }
827
828     vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
829                               sizeof(struct virtio_console_config),
830                               sizeof(VirtIOSerial));
831
832     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
833
834     /* Spawn a new virtio-serial bus on which the ports will ride as devices */
835     vser->bus = virtser_bus_new(dev);
836     vser->bus->vser = vser;
837     QTAILQ_INIT(&vser->ports);
838
839     vser->bus->max_nr_ports = conf->max_virtserial_ports;
840     vser->ivqs = qemu_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
841     vser->ovqs = qemu_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
842
843     /* Add a queue for host to guest transfers for port 0 (backward compat) */
844     vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
845     /* Add a queue for guest to host transfers for port 0 (backward compat) */
846     vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
847
848     /* TODO: host to guest notifications can get dropped
849      * if the queue fills up. Implement queueing in host,
850      * this might also make it possible to reduce the control
851      * queue size: as guest preposts buffers there,
852      * this will save 4Kbyte of guest memory per entry. */
853
854     /* control queue: host to guest */
855     vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
856     /* control queue: guest to host */
857     vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
858
859     for (i = 1; i < vser->bus->max_nr_ports; i++) {
860         /* Add a per-port queue for host to guest transfers */
861         vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
862         /* Add a per-per queue for guest to host transfers */
863         vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
864     }
865
866     vser->config.max_nr_ports = conf->max_virtserial_ports;
867     vser->ports_map = qemu_mallocz(((conf->max_virtserial_ports + 31) / 32)
868         * sizeof(vser->ports_map[0]));
869     /*
870      * Reserve location 0 for a console port for backward compat
871      * (old kernel, new qemu)
872      */
873     mark_port_added(vser, 0);
874
875     vser->vdev.get_features = get_features;
876     vser->vdev.get_config = get_config;
877     vser->vdev.set_config = set_config;
878
879     vser->qdev = dev;
880
881     /*
882      * Register for the savevm section with the virtio-console name
883      * to preserve backward compat
884      */
885     register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
886                     virtio_serial_load, vser);
887
888     return vdev;
889 }
890
891 void virtio_serial_exit(VirtIODevice *vdev)
892 {
893     VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
894
895     unregister_savevm(vser->qdev, "virtio-console", vser);
896
897     qemu_free(vser->ivqs);
898     qemu_free(vser->ovqs);
899     qemu_free(vser->ports_map);
900
901     virtio_cleanup(vdev);
902 }
This page took 0.074108 seconds and 4 git commands to generate.