virtio-serial-bus.c 28.7 KB
Newer Older
1 2 3
/*
 * A bus for connecting virtio serial and console ports
 *
4
 * Copyright (C) 2009, 2010 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15
 *
 * Author(s):
 *  Amit Shah <amit.shah@redhat.com>
 *
 * Some earlier parts are:
 *  Copyright IBM, Corp. 2008
 * authored by
 *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
16 17 18
 *
 * Contributions after 2012-01-13 are licensed under the terms of the
 * GNU GPL, version 2 or (at your option) any later version.
19 20
 */

21
#include "qemu/iov.h"
22
#include "monitor/monitor.h"
23
#include "qemu/queue.h"
24
#include "hw/sysbus.h"
A
Amit Shah 已提交
25
#include "trace.h"
P
Paolo Bonzini 已提交
26
#include "hw/virtio/virtio-serial.h"
27 28 29 30 31

static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
{
    VirtIOSerialPort *port;

32 33 34 35
    if (id == VIRTIO_CONSOLE_BAD_ID) {
        return NULL;
    }

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
    QTAILQ_FOREACH(port, &vser->ports, next) {
        if (port->id == id)
            return port;
    }
    return NULL;
}

static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
{
    VirtIOSerialPort *port;

    QTAILQ_FOREACH(port, &vser->ports, next) {
        if (port->ivq == vq || port->ovq == vq)
            return port;
    }
    return NULL;
}

54 55 56 57 58
static bool use_multiport(VirtIOSerial *vser)
{
    return vser->vdev.guest_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
}

59 60 61 62 63
static size_t write_to_port(VirtIOSerialPort *port,
                            const uint8_t *buf, size_t size)
{
    VirtQueueElement elem;
    VirtQueue *vq;
64
    size_t offset;
65 66 67 68 69 70

    vq = port->ivq;
    if (!virtio_queue_ready(vq)) {
        return 0;
    }

71
    offset = 0;
72
    while (offset < size) {
73
        size_t len;
74 75 76 77 78

        if (!virtqueue_pop(vq, &elem)) {
            break;
        }

79 80
        len = iov_from_buf(elem.in_sg, elem.in_num, 0,
                           buf + offset, size - offset);
81
        offset += len;
82 83 84 85 86 87 88 89

        virtqueue_push(vq, &elem, len);
    }

    virtio_notify(&port->vser->vdev, vq);
    return offset;
}

90
static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
91 92 93
{
    VirtQueueElement elem;

94 95 96
    if (!virtio_queue_ready(vq)) {
        return;
    }
97 98 99 100 101 102
    while (virtqueue_pop(vq, &elem)) {
        virtqueue_push(vq, &elem, 0);
    }
    virtio_notify(vdev, vq);
}

103
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
104
                                 VirtIODevice *vdev)
105
{
106
    VirtIOSerialPortClass *vsc;
107

108
    assert(port);
109
    assert(virtio_queue_ready(vq));
110

111
    vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
112

113
    while (!port->throttled) {
114
        unsigned int i;
115

116 117 118 119 120 121 122 123
        /* Pop an elem only if we haven't left off a previous one mid-way */
        if (!port->elem.out_num) {
            if (!virtqueue_pop(vq, &port->elem)) {
                break;
            }
            port->iov_idx = 0;
            port->iov_offset = 0;
        }
124

125 126 127 128 129
        for (i = port->iov_idx; i < port->elem.out_num; i++) {
            size_t buf_size;
            ssize_t ret;

            buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
130
            ret = vsc->have_data(port,
131 132 133
                                  port->elem.out_sg[i].iov_base
                                  + port->iov_offset,
                                  buf_size);
134
            if (port->throttled) {
135 136 137 138 139 140 141
                port->iov_idx = i;
                if (ret > 0) {
                    port->iov_offset += ret;
                }
                break;
            }
            port->iov_offset = 0;
142
        }
143 144 145 146 147
        if (port->throttled) {
            break;
        }
        virtqueue_push(vq, &port->elem, 0);
        port->elem.out_num = 0;
148 149 150 151
    }
    virtio_notify(vdev, vq);
}

152
static void flush_queued_data(VirtIOSerialPort *port)
153
{
154
    assert(port);
155

156 157 158
    if (!virtio_queue_ready(port->ovq)) {
        return;
    }
159
    do_flush_queued_data(port, port->ovq, &port->vser->vdev);
160 161
}

162
static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len)
163 164 165 166
{
    VirtQueueElement elem;
    VirtQueue *vq;

167
    vq = vser->c_ivq;
168 169 170 171 172 173 174 175 176 177
    if (!virtio_queue_ready(vq)) {
        return 0;
    }
    if (!virtqueue_pop(vq, &elem)) {
        return 0;
    }

    memcpy(elem.in_sg[0].iov_base, buf, len);

    virtqueue_push(vq, &elem, len);
178
    virtio_notify(&vser->vdev, vq);
179 180 181
    return len;
}

182 183
static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id,
                                 uint16_t event, uint16_t value)
184 185 186
{
    struct virtio_console_control cpkt;

187
    stl_p(&cpkt.id, port_id);
188 189 190
    stw_p(&cpkt.event, event);
    stw_p(&cpkt.value, value);

191 192
    trace_virtio_serial_send_control_event(port_id, event, value);
    return send_control_msg(vser, &cpkt, sizeof(cpkt));
193 194 195 196 197
}

/* Functions for use inside qemu to open and read from/write to ports */
int virtio_serial_open(VirtIOSerialPort *port)
{
198 199 200 201 202 203
    /* Don't allow opening an already-open port */
    if (port->host_connected) {
        return 0;
    }
    /* Send port open notification to the guest */
    port->host_connected = true;
204
    send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1);
205

206 207 208 209 210
    return 0;
}

int virtio_serial_close(VirtIOSerialPort *port)
{
211
    port->host_connected = false;
212 213 214 215 216
    /*
     * If there's any data the guest sent which the app didn't
     * consume, reset the throttling flag and discard the data.
     */
    port->throttled = false;
217
    discard_vq_data(port->ovq, &port->vser->vdev);
218

219
    send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0);
220

221 222 223 224 225 226 227
    return 0;
}

/* Individual ports/apps call this function to write to the guest. */
ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
                            size_t size)
{
228 229 230
    if (!port || !port->host_connected || !port->guest_connected) {
        return 0;
    }
231 232 233 234 235 236 237 238 239 240
    return write_to_port(port, buf, size);
}

/*
 * Readiness of the guest to accept data on a port.
 * Returns max. data the guest can receive
 */
size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
{
    VirtQueue *vq = port->ivq;
241
    unsigned int bytes;
242 243 244 245 246 247

    if (!virtio_queue_ready(vq) ||
        !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
        virtio_queue_empty(vq)) {
        return 0;
    }
248 249 250
    if (use_multiport(port->vser) && !port->guest_connected) {
        return 0;
    }
251
    virtqueue_get_avail_bytes(vq, &bytes, NULL, 4096, 0);
252
    return bytes;
253 254
}

255 256 257 258 259 260 261
static void flush_queued_data_bh(void *opaque)
{
    VirtIOSerialPort *port = opaque;

    flush_queued_data(port);
}

262 263 264 265 266 267
void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
{
    if (!port) {
        return;
    }

A
Amit Shah 已提交
268
    trace_virtio_serial_throttle_port(port->id, throttle);
269 270 271 272
    port->throttled = throttle;
    if (throttle) {
        return;
    }
273
    qemu_bh_schedule(port->bh);
274 275
}

276
/* Guest wants to notify us of some event */
277
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
278 279
{
    struct VirtIOSerialPort *port;
280
    VirtIOSerialPortClass *vsc;
281
    struct virtio_console_control cpkt, *gcpkt;
282 283
    uint8_t *buffer;
    size_t buffer_len;
284 285 286

    gcpkt = buf;

287 288 289 290 291
    if (len < sizeof(cpkt)) {
        /* The guest sent an invalid control packet */
        return;
    }

292 293 294
    cpkt.event = lduw_p(&gcpkt->event);
    cpkt.value = lduw_p(&gcpkt->value);

A
Amit Shah 已提交
295 296
    trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);

297
    if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
298
        if (!cpkt.value) {
299
            error_report("virtio-serial-bus: Guest failure in adding device %s",
300
                         vser->bus.qbus.name);
301
            return;
302
        }
303 304 305 306 307
        /*
         * The device is up, we can now tell the device about all the
         * ports we have here.
         */
        QTAILQ_FOREACH(port, &vser->ports, next) {
308
            send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_ADD, 1);
309
        }
310 311
        return;
    }
312

313 314
    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
    if (!port) {
315
        error_report("virtio-serial-bus: Unexpected port id %u for device %s",
316 317 318 319
                     ldl_p(&gcpkt->id), vser->bus.qbus.name);
        return;
    }

A
Amit Shah 已提交
320 321
    trace_virtio_serial_handle_control_message_port(port->id);

322
    vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
323 324

    switch(cpkt.event) {
325
    case VIRTIO_CONSOLE_PORT_READY:
326
        if (!cpkt.value) {
327
            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s",
328
                         port->id, vser->bus.qbus.name);
329 330
            break;
        }
331 332 333 334 335 336 337
        /*
         * Now that we know the guest asked for the port name, we're
         * sure the guest has initialised whatever state is necessary
         * for this port. Now's a good time to let the guest know if
         * this port is a console port so that the guest can hook it
         * up to hvc.
         */
338
        if (vsc->is_console) {
339
            send_control_event(vser, port->id, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
340
        }
341

342
        if (port->name) {
343
            stl_p(&cpkt.id, port->id);
344 345 346 347
            stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
            stw_p(&cpkt.value, 1);

            buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
348
            buffer = g_malloc(buffer_len);
349 350 351 352 353

            memcpy(buffer, &cpkt, sizeof(cpkt));
            memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
            buffer[buffer_len - 1] = 0;

354
            send_control_msg(vser, buffer, buffer_len);
355
            g_free(buffer);
356 357
        }

358
        if (port->host_connected) {
359
            send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1);
360 361
        }

362 363 364 365 366 367
        /*
         * When the guest has asked us for this information it means
         * the guest is all setup and has its virtqueues
         * initialised. If some app is interested in knowing about
         * this event, let it know.
         */
368 369
        if (vsc->guest_ready) {
            vsc->guest_ready(port);
370 371
        }
        break;
372 373 374

    case VIRTIO_CONSOLE_PORT_OPEN:
        port->guest_connected = cpkt.value;
375
        if (vsc->set_guest_connected) {
376
            /* Send the guest opened notification if an app is interested */
377
            vsc->set_guest_connected(port, cpkt.value);
378 379
        }
        break;
380 381 382 383 384 385 386 387 388 389 390
    }
}

static void control_in(VirtIODevice *vdev, VirtQueue *vq)
{
}

static void control_out(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtQueueElement elem;
    VirtIOSerial *vser;
391 392
    uint8_t *buf;
    size_t len;
393 394 395

    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);

396 397
    len = 0;
    buf = NULL;
398
    while (virtqueue_pop(vq, &elem)) {
399
        size_t cur_len;
400 401 402 403 404 405 406

        cur_len = iov_size(elem.out_sg, elem.out_num);
        /*
         * Allocate a new buf only if we didn't have one previously or
         * if the size of the buf differs
         */
        if (cur_len > len) {
407
            g_free(buf);
408

409
            buf = g_malloc(cur_len);
410 411
            len = cur_len;
        }
412
        iov_to_buf(elem.out_sg, elem.out_num, 0, buf, cur_len);
413

414
        handle_control_message(vser, buf, cur_len);
415
        virtqueue_push(vq, &elem, 0);
416
    }
417
    g_free(buf);
418 419 420 421 422 423 424
    virtio_notify(vdev, vq);
}

/* Guest wrote something to some port. */
static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOSerial *vser;
425
    VirtIOSerialPort *port;
426 427

    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
428
    port = find_port_by_vq(vser, vq);
429

430
    if (!port || !port->host_connected) {
431 432 433
        discard_vq_data(vq, vdev);
        return;
    }
434 435 436

    if (!port->throttled) {
        do_flush_queued_data(port, vq, vdev);
437 438
        return;
    }
439 440 441 442 443 444 445 446
}

static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
{
}

static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
{
447 448 449 450
    VirtIOSerial *vser;

    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);

451
    if (vser->bus.max_nr_ports > 1) {
452 453
        features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
    }
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
    return features;
}

/* Guest requested config info */
static void get_config(VirtIODevice *vdev, uint8_t *config_data)
{
    VirtIOSerial *vser;

    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
}

static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
{
    struct virtio_console_config config;

    memcpy(&config, config_data, sizeof(config));
}

473 474 475 476 477 478 479 480 481
static void guest_reset(VirtIOSerial *vser)
{
    VirtIOSerialPort *port;
    VirtIOSerialPortClass *vsc;

    QTAILQ_FOREACH(port, &vser->ports, next) {
        vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
        if (port->guest_connected) {
            port->guest_connected = false;
482 483 484
            if (vsc->set_guest_connected) {
                vsc->set_guest_connected(port, false);
            }
485 486 487 488
        }
    }
}

489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
static void set_status(VirtIODevice *vdev, uint8_t status)
{
    VirtIOSerial *vser;
    VirtIOSerialPort *port;

    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
    port = find_port_by_id(vser, 0);

    if (port && !use_multiport(port->vser)
        && (status & VIRTIO_CONFIG_S_DRIVER_OK)) {
        /*
         * Non-multiport guests won't be able to tell us guest
         * open/close status.  Such guests can only have a port at id
         * 0, so set guest_connected for such ports as soon as guest
         * is up.
         */
        port->guest_connected = true;
    }
507 508 509 510 511 512 513 514 515 516 517
    if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
        guest_reset(vser);
    }
}

static void vser_reset(VirtIODevice *vdev)
{
    VirtIOSerial *vser;

    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
    guest_reset(vser);
518 519
}

520 521 522
static void virtio_serial_save(QEMUFile *f, void *opaque)
{
    VirtIOSerial *s = opaque;
523 524
    VirtIOSerialPort *port;
    uint32_t nr_active_ports;
525
    unsigned int i, max_nr_ports;
526 527 528 529 530 531 532

    /* The virtio device */
    virtio_save(&s->vdev, f);

    /* The config space */
    qemu_put_be16s(f, &s->config.cols);
    qemu_put_be16s(f, &s->config.rows);
533

534 535 536
    qemu_put_be32s(f, &s->config.max_nr_ports);

    /* The ports map */
537 538
    max_nr_ports = tswap32(s->config.max_nr_ports);
    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
539 540
        qemu_put_be32s(f, &s->ports_map[i]);
    }
541

542
    /* Ports */
543

544
    nr_active_ports = 0;
545
    QTAILQ_FOREACH(port, &s->ports, next) {
546
        nr_active_ports++;
547
    }
548 549 550 551 552 553 554

    qemu_put_be32s(f, &nr_active_ports);

    /*
     * Items in struct VirtIOSerialPort.
     */
    QTAILQ_FOREACH(port, &s->ports, next) {
555 556
        uint32_t elem_popped;

557 558
        qemu_put_be32s(f, &port->id);
        qemu_put_byte(f, port->guest_connected);
559
        qemu_put_byte(f, port->host_connected);
560 561 562 563 564 565 566 567 568 569 570 571 572

	elem_popped = 0;
        if (port->elem.out_num) {
            elem_popped = 1;
        }
        qemu_put_be32s(f, &elem_popped);
        if (elem_popped) {
            qemu_put_be32s(f, &port->iov_idx);
            qemu_put_be64s(f, &port->iov_offset);

            qemu_put_buffer(f, (unsigned char *)&port->elem,
                            sizeof(port->elem));
        }
573
    }
574 575
}

576 577
static void virtio_serial_post_load_timer_cb(void *opaque)
{
578
    uint32_t i;
579 580 581
    VirtIOSerial *s = opaque;
    VirtIOSerialPort *port;
    uint8_t host_connected;
582
    VirtIOSerialPortClass *vsc;
583

584 585 586 587 588 589
    if (!s->post_load) {
        return;
    }
    for (i = 0 ; i < s->post_load->nr_active_ports; ++i) {
        port = s->post_load->connected[i].port;
        host_connected = s->post_load->connected[i].host_connected;
590 591 592 593 594
        if (host_connected != port->host_connected) {
            /*
             * We have to let the guest know of the host connection
             * status change
             */
595
            send_control_event(s, port->id, VIRTIO_CONSOLE_PORT_OPEN,
596 597
                               port->host_connected);
        }
598 599 600 601
        vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
        if (vsc->set_guest_connected) {
            vsc->set_guest_connected(port, port->guest_connected);
        }
602
    }
603 604 605 606
    g_free(s->post_load->connected);
    qemu_free_timer(s->post_load->timer);
    g_free(s->post_load);
    s->post_load = NULL;
607 608
}

609 610 611 612 613
static int fetch_active_ports_list(QEMUFile *f, int version_id,
                                   VirtIOSerial *s, uint32_t nr_active_ports)
{
    uint32_t i;

614 615 616 617 618 619 620 621
    s->post_load = g_malloc0(sizeof(*s->post_load));
    s->post_load->nr_active_ports = nr_active_ports;
    s->post_load->connected =
        g_malloc0(sizeof(*s->post_load->connected) * nr_active_ports);

    s->post_load->timer = qemu_new_timer_ns(vm_clock,
                                            virtio_serial_post_load_timer_cb,
                                            s);
622 623 624 625 626 627 628 629 630 631 632 633 634

    /* Items in struct VirtIOSerialPort */
    for (i = 0; i < nr_active_ports; i++) {
        VirtIOSerialPort *port;
        uint32_t id;

        id = qemu_get_be32(f);
        port = find_port_by_id(s, id);
        if (!port) {
            return -EINVAL;
        }

        port->guest_connected = qemu_get_byte(f);
635 636
        s->post_load->connected[i].port = port;
        s->post_load->connected[i].host_connected = qemu_get_byte(f);
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660

        if (version_id > 2) {
            uint32_t elem_popped;

            qemu_get_be32s(f, &elem_popped);
            if (elem_popped) {
                qemu_get_be32s(f, &port->iov_idx);
                qemu_get_be64s(f, &port->iov_offset);

                qemu_get_buffer(f, (unsigned char *)&port->elem,
                                sizeof(port->elem));
                virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
                                 port->elem.in_num, 1);
                virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
                                 port->elem.out_num, 1);

                /*
                 *  Port was throttled on source machine.  Let's
                 *  unthrottle it here so data starts flowing again.
                 */
                virtio_serial_throttle_port(port, false);
            }
        }
    }
661
    qemu_mod_timer(s->post_load->timer, 1);
662 663 664
    return 0;
}

665 666 667
static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
{
    VirtIOSerial *s = opaque;
668
    uint32_t max_nr_ports, nr_active_ports, ports_map;
669
    unsigned int i;
670
    int ret;
671

672
    if (version_id > 3) {
673 674
        return -EINVAL;
    }
675

676
    /* The virtio device */
677 678 679 680
    ret = virtio_load(&s->vdev, f);
    if (ret) {
        return ret;
    }
681 682 683 684 685 686 687 688

    if (version_id < 2) {
        return 0;
    }

    /* The config space */
    qemu_get_be16s(f, &s->config.cols);
    qemu_get_be16s(f, &s->config.rows);
689

690
    qemu_get_be32s(f, &max_nr_ports);
691 692
    tswap32s(&max_nr_ports);
    if (max_nr_ports > tswap32(s->config.max_nr_ports)) {
693
        /* Source could have had more ports than us. Fail migration. */
694 695
        return -EINVAL;
    }
696

697
    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
698
        qemu_get_be32s(f, &ports_map);
699

700
        if (ports_map != s->ports_map[i]) {
701 702 703 704 705 706
            /*
             * Ports active on source and destination don't
             * match. Fail migration.
             */
            return -EINVAL;
        }
707 708
    }

709 710
    qemu_get_be32s(f, &nr_active_ports);

711 712 713 714
    if (nr_active_ports) {
        ret = fetch_active_ports_list(f, version_id, s, nr_active_ports);
        if (ret) {
            return ret;
715
        }
716
    }
717 718 719 720 721
    return 0;
}

static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);

722 723 724 725 726 727
static Property virtser_props[] = {
    DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
    DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
    DEFINE_PROP_END_OF_LIST()
};

728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
#define TYPE_VIRTIO_SERIAL_BUS "virtio-serial-bus"
#define VIRTIO_SERIAL_BUS(obj) \
      OBJECT_CHECK(VirtIOSerialBus, (obj), TYPE_VIRTIO_SERIAL_BUS)

static void virtser_bus_class_init(ObjectClass *klass, void *data)
{
    BusClass *k = BUS_CLASS(klass);
    k->print_dev = virtser_bus_dev_print;
}

static const TypeInfo virtser_bus_info = {
    .name = TYPE_VIRTIO_SERIAL_BUS,
    .parent = TYPE_BUS,
    .instance_size = sizeof(VirtIOSerialBus),
    .class_init = virtser_bus_class_init,
743 744 745 746
};

static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
747
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
748

749 750 751 752 753
    monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n",
                   indent, "", port->id,
                   port->guest_connected ? "on" : "off",
                   port->host_connected ? "on" : "off",
                   port->throttled ? "on" : "off");
754 755
}

756 757 758
/* This function is only used if a port id is not provided by the user */
static uint32_t find_free_port_id(VirtIOSerial *vser)
{
759
    unsigned int i, max_nr_ports;
760

761 762
    max_nr_ports = tswap32(vser->config.max_nr_ports);
    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
        uint32_t map, bit;

        map = vser->ports_map[i];
        bit = ffs(~map);
        if (bit) {
            return (bit - 1) + i * 32;
        }
    }
    return VIRTIO_CONSOLE_BAD_ID;
}

static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
{
    unsigned int i;

    i = port_id / 32;
    vser->ports_map[i] |= 1U << (port_id % 32);
}

static void add_port(VirtIOSerial *vser, uint32_t port_id)
{
    mark_port_added(vser, port_id);
785
    send_control_event(vser, port_id, VIRTIO_CONSOLE_PORT_ADD, 1);
786 787 788 789
}

static void remove_port(VirtIOSerial *vser, uint32_t port_id)
{
790
    VirtIOSerialPort *port;
791 792 793 794 795
    unsigned int i;

    i = port_id / 32;
    vser->ports_map[i] &= ~(1U << (port_id % 32));

796
    port = find_port_by_id(vser, port_id);
797 798 799 800 801 802
    /*
     * This function is only called from qdev's unplug callback; if we
     * get a NULL port here, we're in trouble.
     */
    assert(port);

803
    /* Flush out any unconsumed buffers first */
804
    discard_vq_data(port->ovq, &port->vser->vdev);
805

806
    send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1);
807 808
}

A
Anthony Liguori 已提交
809
static int virtser_port_qdev_init(DeviceState *qdev)
810
{
811
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
812
    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
813
    VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
814
    int ret, max_nr_ports;
815 816 817
    bool plugging_port0;

    port->vser = bus->vser;
818
    port->bh = qemu_bh_new(flush_queued_data_bh, port);
819

820
    assert(vsc->have_data);
821

822 823 824 825 826
    /*
     * Is the first console port we're seeing? If so, put it up at
     * location 0. This is done for backward compatibility (old
     * kernel, new qemu).
     */
827
    plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0);
828

829
    if (find_port_by_id(port->vser, port->id)) {
830
        error_report("virtio-serial-bus: A port already exists at id %u",
831
                     port->id);
832 833 834
        return -1;
    }

835 836 837 838 839 840
    if (port->id == VIRTIO_CONSOLE_BAD_ID) {
        if (plugging_port0) {
            port->id = 0;
        } else {
            port->id = find_free_port_id(port->vser);
            if (port->id == VIRTIO_CONSOLE_BAD_ID) {
841
                error_report("virtio-serial-bus: Maximum port limit for this device reached");
842 843 844 845 846
                return -1;
            }
        }
    }

847 848
    max_nr_ports = tswap32(port->vser->config.max_nr_ports);
    if (port->id >= max_nr_ports) {
849
        error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u",
850
                     max_nr_ports - 1);
851 852 853
        return -1;
    }

854
    ret = vsc->init(port);
855 856 857 858
    if (ret) {
        return ret;
    }

859 860
    port->elem.out_num = 0;

861 862 863 864
    QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
    port->ivq = port->vser->ivqs[port->id];
    port->ovq = port->vser->ovqs[port->id];

865 866
    add_port(port->vser, port->id);

867 868 869 870 871 872 873 874
    /* Send an update to the guest about this new port added */
    virtio_notify_config(&port->vser->vdev);

    return ret;
}

static int virtser_port_qdev_exit(DeviceState *qdev)
{
875
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
876
    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
877 878
    VirtIOSerial *vser = port->vser;

879
    qemu_bh_delete(port->bh);
880
    remove_port(port->vser, port->id);
881

882 883
    QTAILQ_REMOVE(&vser->ports, port, next);

884 885
    if (vsc->exit) {
        vsc->exit(port);
886
    }
887 888 889
    return 0;
}

890
static int virtio_serial_device_init(VirtIODevice *vdev)
891
{
892 893
    DeviceState *qdev = DEVICE(vdev);
    VirtIOSerial *vser = VIRTIO_SERIAL(vdev);
894
    uint32_t i, max_supported_ports;
895

896 897 898
    if (!vser->serial.max_virtserial_ports) {
        return -1;
    }
899

900 901 902
    /* Each port takes 2 queues, and one pair is for the control queue */
    max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;

903
    if (vser->serial.max_virtserial_ports > max_supported_ports) {
904
        error_report("maximum ports supported: %u", max_supported_ports);
905
        return -1;
906 907
    }

908 909
    virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE,
                sizeof(struct virtio_console_config));
910 911

    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
912
    qbus_create_inplace(&vser->bus.qbus, TYPE_VIRTIO_SERIAL_BUS, qdev, NULL);
913 914
    vser->bus.qbus.allow_hotplug = 1;
    vser->bus.vser = vser;
915 916
    QTAILQ_INIT(&vser->ports);

917 918 919 920 921
    vser->bus.max_nr_ports = vser->serial.max_virtserial_ports;
    vser->ivqs = g_malloc(vser->serial.max_virtserial_ports
                          * sizeof(VirtQueue *));
    vser->ovqs = g_malloc(vser->serial.max_virtserial_ports
                          * sizeof(VirtQueue *));
922 923 924 925 926 927

    /* Add a queue for host to guest transfers for port 0 (backward compat) */
    vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
    /* Add a queue for guest to host transfers for port 0 (backward compat) */
    vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);

928 929 930 931 932 933
    /* TODO: host to guest notifications can get dropped
     * if the queue fills up. Implement queueing in host,
     * this might also make it possible to reduce the control
     * queue size: as guest preposts buffers there,
     * this will save 4Kbyte of guest memory per entry. */

934
    /* control queue: host to guest */
935
    vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
936
    /* control queue: guest to host */
937
    vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
938

939
    for (i = 1; i < vser->bus.max_nr_ports; i++) {
940 941 942 943 944 945
        /* Add a per-port queue for host to guest transfers */
        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
        /* Add a per-per queue for guest to host transfers */
        vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
    }

946 947
    vser->config.max_nr_ports = tswap32(vser->serial.max_virtserial_ports);
    vser->ports_map = g_malloc0(((vser->serial.max_virtserial_ports + 31) / 32)
948
        * sizeof(vser->ports_map[0]));
949 950 951 952
    /*
     * Reserve location 0 for a console port for backward compat
     * (old kernel, new qemu)
     */
953
    mark_port_added(vser, 0);
954 955 956 957

    vser->vdev.get_features = get_features;
    vser->vdev.get_config = get_config;
    vser->vdev.set_config = set_config;
958
    vser->vdev.set_status = set_status;
959
    vser->vdev.reset = vser_reset;
960

961
    vser->qdev = qdev;
962

963 964
    vser->post_load = NULL;

965 966 967 968
    /*
     * Register for the savevm section with the virtio-console name
     * to preserve backward compat
     */
969
    register_savevm(qdev, "virtio-console", -1, 3, virtio_serial_save,
970 971
                    virtio_serial_load, vser);

972
    return 0;
973
}
974

975 976 977 978
static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *k = DEVICE_CLASS(klass);
    k->init = virtser_port_qdev_init;
979
    k->bus_type = TYPE_VIRTIO_SERIAL_BUS;
980 981
    k->exit = virtser_port_qdev_exit;
    k->unplug = qdev_simple_unplug_cb;
982
    k->props = virtser_props;
983 984
}

985
static const TypeInfo virtio_serial_port_type_info = {
986 987 988 989 990
    .name = TYPE_VIRTIO_SERIAL_PORT,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(VirtIOSerialPort),
    .abstract = true,
    .class_size = sizeof(VirtIOSerialPortClass),
991
    .class_init = virtio_serial_port_class_init,
992 993
};

994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
static int virtio_serial_device_exit(DeviceState *dev)
{
    VirtIOSerial *vser = VIRTIO_SERIAL(dev);
    VirtIODevice *vdev = VIRTIO_DEVICE(dev);

    unregister_savevm(dev, "virtio-console", vser);

    g_free(vser->ivqs);
    g_free(vser->ovqs);
    g_free(vser->ports_map);
    if (vser->post_load) {
        g_free(vser->post_load->connected);
        qemu_del_timer(vser->post_load->timer);
        qemu_free_timer(vser->post_load->timer);
        g_free(vser->post_load);
    }
    virtio_common_cleanup(vdev);
    return 0;
}

static Property virtio_serial_properties[] = {
    DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerial, serial),
    DEFINE_PROP_END_OF_LIST(),
};

static void virtio_serial_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
    dc->exit = virtio_serial_device_exit;
    dc->props = virtio_serial_properties;
    vdc->init = virtio_serial_device_init;
    vdc->get_features = get_features;
    vdc->get_config = get_config;
    vdc->set_config = set_config;
    vdc->set_status = set_status;
    vdc->reset = vser_reset;
}

static const TypeInfo virtio_device_info = {
    .name = TYPE_VIRTIO_SERIAL,
    .parent = TYPE_VIRTIO_DEVICE,
    .instance_size = sizeof(VirtIOSerial),
    .class_init = virtio_serial_class_init,
};

A
Andreas Färber 已提交
1040
static void virtio_serial_register_types(void)
1041
{
1042
    type_register_static(&virtser_bus_info);
1043
    type_register_static(&virtio_serial_port_type_info);
1044
    type_register_static(&virtio_device_info);
1045 1046
}

A
Andreas Färber 已提交
1047
type_init(virtio_serial_register_types)