1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2016 iXsystems Inc. 5 * All rights reserved. 6 * 7 * This software was developed by Jakub Klama <jceel@FreeBSD.org> 8 * under sponsorship from iXsystems Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer 15 * in this position and unchanged. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright 2018 Joyent, Inc. 35 */ 36 37 38 #include <sys/param.h> 39 #ifndef WITHOUT_CAPSICUM 40 #include <sys/capsicum.h> 41 #endif 42 #include <sys/linker_set.h> 43 #include <sys/uio.h> 44 #include <sys/types.h> 45 #include <sys/socket.h> 46 #include <sys/un.h> 47 48 #ifndef WITHOUT_CAPSICUM 49 #include <capsicum_helpers.h> 50 #endif 51 #include <err.h> 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <stdbool.h> 57 #include <string.h> 58 #include <unistd.h> 59 #include <assert.h> 60 #include <pthread.h> 61 #include <libgen.h> 62 #include <sysexits.h> 63 64 #include "bhyverun.h" 65 #include "config.h" 66 #include "debug.h" 67 #include "pci_emul.h" 68 #include "virtio.h" 69 #include "mevent.h" 70 #include "sockstream.h" 71 72 #define VTCON_RINGSZ 64 73 #define VTCON_MAXPORTS 16 74 #define VTCON_MAXQ (VTCON_MAXPORTS * 2 + 2) 75 76 #define VTCON_DEVICE_READY 0 77 #define VTCON_DEVICE_ADD 1 78 #define VTCON_DEVICE_REMOVE 2 79 #define VTCON_PORT_READY 3 80 #define VTCON_CONSOLE_PORT 4 81 #define VTCON_CONSOLE_RESIZE 5 82 #define VTCON_PORT_OPEN 6 83 #define VTCON_PORT_NAME 7 84 85 #define VTCON_F_SIZE 0 86 #define VTCON_F_MULTIPORT 1 87 #define VTCON_F_EMERG_WRITE 2 88 #define VTCON_S_HOSTCAPS \ 89 (VTCON_F_SIZE | VTCON_F_MULTIPORT | VTCON_F_EMERG_WRITE) 90 91 static int pci_vtcon_debug; 92 #define DPRINTF(params) if (pci_vtcon_debug) PRINTLN params 93 #define WPRINTF(params) PRINTLN params 94 95 struct pci_vtcon_softc; 96 struct pci_vtcon_port; 97 struct pci_vtcon_config; 98 typedef void (pci_vtcon_cb_t)(struct pci_vtcon_port *, void *, struct iovec *, 99 int); 100 101 struct pci_vtcon_port { 102 struct pci_vtcon_softc * vsp_sc; 103 int vsp_id; 104 const char * vsp_name; 105 bool vsp_enabled; 106 bool vsp_console; 107 bool vsp_rx_ready; 108 bool vsp_open; 109 int vsp_rxq; 110 int vsp_txq; 111 void * vsp_arg; 112 pci_vtcon_cb_t * vsp_cb; 113 }; 114 115 struct pci_vtcon_sock 116 { 117 struct pci_vtcon_port * vss_port; 118 const char * vss_path; 119 struct mevent * vss_server_evp; 120 struct mevent * vss_conn_evp; 121 int vss_server_fd; 122 int vss_conn_fd; 123 bool vss_open; 124 }; 125 126 struct pci_vtcon_softc { 127 struct virtio_softc vsc_vs; 128 struct vqueue_info vsc_queues[VTCON_MAXQ]; 129 pthread_mutex_t vsc_mtx; 130 uint64_t vsc_cfg; 131 uint64_t vsc_features; 132 char * vsc_rootdir; 133 int vsc_kq; 134 bool vsc_ready; 135 struct pci_vtcon_port vsc_control_port; 136 struct pci_vtcon_port vsc_ports[VTCON_MAXPORTS]; 137 struct pci_vtcon_config *vsc_config; 138 }; 139 140 struct pci_vtcon_config { 141 uint16_t cols; 142 uint16_t rows; 143 uint32_t max_nr_ports; 144 uint32_t emerg_wr; 145 } __attribute__((packed)); 146 147 struct pci_vtcon_control { 148 uint32_t id; 149 uint16_t event; 150 uint16_t value; 151 } __attribute__((packed)); 152 153 struct pci_vtcon_console_resize { 154 uint16_t cols; 155 uint16_t rows; 156 } __attribute__((packed)); 157 158 static void pci_vtcon_reset(void *); 159 static void pci_vtcon_notify_rx(void *, struct vqueue_info *); 160 static void pci_vtcon_notify_tx(void *, struct vqueue_info *); 161 static int pci_vtcon_cfgread(void *, int, int, uint32_t *); 162 static int pci_vtcon_cfgwrite(void *, int, int, uint32_t); 163 static void pci_vtcon_neg_features(void *, uint64_t); 164 static void pci_vtcon_sock_accept(int, enum ev_type, void *); 165 static void pci_vtcon_sock_rx(int, enum ev_type, void *); 166 static void pci_vtcon_sock_tx(struct pci_vtcon_port *, void *, struct iovec *, 167 int); 168 static void pci_vtcon_control_send(struct pci_vtcon_softc *, 169 struct pci_vtcon_control *, const void *, size_t); 170 static void pci_vtcon_announce_port(struct pci_vtcon_port *); 171 static void pci_vtcon_open_port(struct pci_vtcon_port *, bool); 172 173 static struct virtio_consts vtcon_vi_consts = { 174 .vc_name = "vtcon", 175 .vc_nvq = VTCON_MAXQ, 176 .vc_cfgsize = sizeof(struct pci_vtcon_config), 177 .vc_reset = pci_vtcon_reset, 178 .vc_cfgread = pci_vtcon_cfgread, 179 .vc_cfgwrite = pci_vtcon_cfgwrite, 180 .vc_apply_features = pci_vtcon_neg_features, 181 .vc_hv_caps = VTCON_S_HOSTCAPS, 182 }; 183 184 static void 185 pci_vtcon_reset(void *vsc) 186 { 187 struct pci_vtcon_softc *sc; 188 189 sc = vsc; 190 191 DPRINTF(("vtcon: device reset requested!")); 192 vi_reset_dev(&sc->vsc_vs); 193 } 194 195 static void 196 pci_vtcon_neg_features(void *vsc, uint64_t negotiated_features) 197 { 198 struct pci_vtcon_softc *sc = vsc; 199 200 sc->vsc_features = negotiated_features; 201 } 202 203 static int 204 pci_vtcon_cfgread(void *vsc, int offset, int size, uint32_t *retval) 205 { 206 struct pci_vtcon_softc *sc = vsc; 207 void *ptr; 208 209 ptr = (uint8_t *)sc->vsc_config + offset; 210 memcpy(retval, ptr, size); 211 return (0); 212 } 213 214 static int 215 pci_vtcon_cfgwrite(void *vsc __unused, int offset __unused, int size __unused, 216 uint32_t val __unused) 217 { 218 return (0); 219 } 220 221 static inline struct pci_vtcon_port * 222 pci_vtcon_vq_to_port(struct pci_vtcon_softc *sc, struct vqueue_info *vq) 223 { 224 uint16_t num = vq->vq_num; 225 226 if (num == 0 || num == 1) 227 return (&sc->vsc_ports[0]); 228 229 if (num == 2 || num == 3) 230 return (&sc->vsc_control_port); 231 232 return (&sc->vsc_ports[(num / 2) - 1]); 233 } 234 235 static inline struct vqueue_info * 236 pci_vtcon_port_to_vq(struct pci_vtcon_port *port, bool tx_queue) 237 { 238 int qnum; 239 240 qnum = tx_queue ? port->vsp_txq : port->vsp_rxq; 241 return (&port->vsp_sc->vsc_queues[qnum]); 242 } 243 244 static struct pci_vtcon_port * 245 pci_vtcon_port_add(struct pci_vtcon_softc *sc, int port_id, const char *name, 246 pci_vtcon_cb_t *cb, void *arg) 247 { 248 struct pci_vtcon_port *port; 249 250 port = &sc->vsc_ports[port_id]; 251 if (port->vsp_enabled) { 252 errno = EBUSY; 253 return (NULL); 254 } 255 port->vsp_id = port_id; 256 port->vsp_sc = sc; 257 port->vsp_name = name; 258 port->vsp_cb = cb; 259 port->vsp_arg = arg; 260 261 if (port->vsp_id == 0) { 262 /* port0 */ 263 port->vsp_txq = 0; 264 port->vsp_rxq = 1; 265 } else { 266 port->vsp_txq = (port_id + 1) * 2; 267 port->vsp_rxq = port->vsp_txq + 1; 268 } 269 270 port->vsp_enabled = true; 271 return (port); 272 } 273 274 static int 275 pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *port_name, 276 const nvlist_t *nvl) 277 { 278 struct pci_vtcon_sock *sock = NULL; 279 #ifdef __FreeBSD__ 280 struct sockaddr_un sun; 281 #else 282 /* Our compiler #defines 'sun' as '1'. Awesome. */ 283 struct sockaddr_un addr; 284 #endif 285 const char *name, *path; 286 char *cp, *pathcopy; 287 long port; 288 int s = -1, fd = -1, error = 0; 289 #ifndef WITHOUT_CAPSICUM 290 cap_rights_t rights; 291 #endif 292 293 port = strtol(port_name, &cp, 0); 294 if (*cp != '\0' || port < 0 || port >= VTCON_MAXPORTS) { 295 EPRINTLN("vtcon: Invalid port %s", port_name); 296 error = -1; 297 goto out; 298 } 299 300 path = get_config_value_node(nvl, "path"); 301 if (path == NULL) { 302 EPRINTLN("vtcon: required path missing for port %ld", port); 303 error = -1; 304 goto out; 305 } 306 307 sock = calloc(1, sizeof(struct pci_vtcon_sock)); 308 if (sock == NULL) { 309 error = -1; 310 goto out; 311 } 312 313 s = socket(AF_UNIX, SOCK_STREAM, 0); 314 if (s < 0) { 315 error = -1; 316 goto out; 317 } 318 319 #ifdef __FreeBSD__ 320 pathcopy = strdup(path); 321 if (pathcopy == NULL) { 322 error = -1; 323 goto out; 324 } 325 326 fd = open(dirname(pathcopy), O_RDONLY | O_DIRECTORY); 327 if (fd < 0) { 328 free(pathcopy); 329 error = -1; 330 goto out; 331 } 332 333 sun.sun_family = AF_UNIX; 334 sun.sun_len = sizeof(struct sockaddr_un); 335 strcpy(pathcopy, path); 336 strlcpy(sun.sun_path, basename(pathcopy), sizeof(sun.sun_path)); 337 free(pathcopy); 338 339 if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0) { 340 error = -1; 341 goto out; 342 } 343 #else /* __FreeBSD__ */ 344 /* Do a simple bind rather than the FreeBSD bindat() */ 345 pathcopy = (char *)path; 346 addr.sun_family = AF_UNIX; 347 (void) strlcpy(addr.sun_path, pathcopy, sizeof (addr.sun_path)); 348 if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { 349 error = -1; 350 goto out; 351 } 352 #endif /* __FreeBSD__ */ 353 354 if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { 355 error = -1; 356 goto out; 357 } 358 359 if (listen(s, 1) < 0) { 360 error = -1; 361 goto out; 362 } 363 364 #ifndef WITHOUT_CAPSICUM 365 cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE); 366 if (caph_rights_limit(s, &rights) == -1) 367 errx(EX_OSERR, "Unable to apply rights for sandbox"); 368 #endif 369 370 name = get_config_value_node(nvl, "name"); 371 if (name == NULL) { 372 EPRINTLN("vtcon: required name missing for port %ld", port); 373 error = -1; 374 goto out; 375 } 376 sock->vss_port = pci_vtcon_port_add(sc, port, name, pci_vtcon_sock_tx, sock); 377 if (sock->vss_port == NULL) { 378 error = -1; 379 goto out; 380 } 381 382 sock->vss_open = false; 383 sock->vss_conn_fd = -1; 384 sock->vss_server_fd = s; 385 sock->vss_server_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_accept, 386 sock); 387 388 if (sock->vss_server_evp == NULL) { 389 error = -1; 390 goto out; 391 } 392 393 out: 394 if (fd != -1) 395 close(fd); 396 397 if (error != 0) { 398 if (s != -1) 399 close(s); 400 free(sock); 401 } 402 403 return (error); 404 } 405 406 static void 407 pci_vtcon_sock_accept(int fd __unused, enum ev_type t __unused, void *arg) 408 { 409 struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg; 410 int s; 411 412 s = accept(sock->vss_server_fd, NULL, NULL); 413 if (s < 0) 414 return; 415 416 if (sock->vss_open) { 417 close(s); 418 return; 419 } 420 421 sock->vss_open = true; 422 sock->vss_conn_fd = s; 423 sock->vss_conn_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_rx, sock); 424 425 pci_vtcon_open_port(sock->vss_port, true); 426 } 427 428 static void 429 pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg) 430 { 431 struct pci_vtcon_port *port; 432 struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg; 433 struct vqueue_info *vq; 434 struct vi_req req; 435 struct iovec iov; 436 static char dummybuf[2048]; 437 int len, n; 438 439 port = sock->vss_port; 440 vq = pci_vtcon_port_to_vq(port, true); 441 442 if (!sock->vss_open || !port->vsp_rx_ready) { 443 len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf)); 444 if (len == 0) 445 goto close; 446 447 return; 448 } 449 450 if (!vq_has_descs(vq)) { 451 len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf)); 452 vq_endchains(vq, 1); 453 if (len == 0) 454 goto close; 455 456 return; 457 } 458 459 do { 460 n = vq_getchain(vq, &iov, 1, &req); 461 assert(n == 1); 462 len = readv(sock->vss_conn_fd, &iov, n); 463 464 if (len == 0 || (len < 0 && errno == EWOULDBLOCK)) { 465 vq_retchains(vq, 1); 466 vq_endchains(vq, 0); 467 if (len == 0) 468 goto close; 469 470 return; 471 } 472 473 vq_relchain(vq, req.idx, len); 474 } while (vq_has_descs(vq)); 475 476 vq_endchains(vq, 1); 477 478 close: 479 mevent_delete_close(sock->vss_conn_evp); 480 sock->vss_conn_fd = -1; 481 sock->vss_open = false; 482 } 483 484 static void 485 pci_vtcon_sock_tx(struct pci_vtcon_port *port __unused, void *arg __unused, 486 struct iovec *iov, int niov) 487 { 488 struct pci_vtcon_sock *sock; 489 int i, ret; 490 491 #ifndef __FreeBSD__ 492 ret = 0; 493 #endif 494 495 sock = (struct pci_vtcon_sock *)arg; 496 497 if (sock->vss_conn_fd == -1) 498 return; 499 500 for (i = 0; i < niov; i++) { 501 ret = stream_write(sock->vss_conn_fd, iov[i].iov_base, 502 iov[i].iov_len); 503 if (ret <= 0) 504 break; 505 } 506 507 if (ret <= 0) { 508 mevent_delete_close(sock->vss_conn_evp); 509 sock->vss_conn_fd = -1; 510 sock->vss_open = false; 511 } 512 } 513 514 static void 515 pci_vtcon_control_tx(struct pci_vtcon_port *port, void *arg __unused, 516 struct iovec *iov, int niov) 517 { 518 struct pci_vtcon_softc *sc; 519 struct pci_vtcon_port *tmp; 520 struct pci_vtcon_control resp, *ctrl; 521 int i; 522 523 assert(niov == 1); 524 525 sc = port->vsp_sc; 526 ctrl = (struct pci_vtcon_control *)iov->iov_base; 527 528 switch (ctrl->event) { 529 case VTCON_DEVICE_READY: 530 sc->vsc_ready = true; 531 /* set port ready events for registered ports */ 532 for (i = 0; i < VTCON_MAXPORTS; i++) { 533 tmp = &sc->vsc_ports[i]; 534 if (tmp->vsp_enabled) 535 pci_vtcon_announce_port(tmp); 536 537 if (tmp->vsp_open) 538 pci_vtcon_open_port(tmp, true); 539 } 540 break; 541 542 case VTCON_PORT_READY: 543 tmp = &sc->vsc_ports[ctrl->id]; 544 if (ctrl->id >= VTCON_MAXPORTS || !tmp->vsp_enabled) { 545 WPRINTF(("VTCON_PORT_READY event for unknown port %d", 546 ctrl->id)); 547 return; 548 } 549 550 if (tmp->vsp_console) { 551 resp.event = VTCON_CONSOLE_PORT; 552 resp.id = ctrl->id; 553 resp.value = 1; 554 pci_vtcon_control_send(sc, &resp, NULL, 0); 555 } 556 break; 557 } 558 } 559 560 static void 561 pci_vtcon_announce_port(struct pci_vtcon_port *port) 562 { 563 struct pci_vtcon_control event; 564 565 event.id = port->vsp_id; 566 event.event = VTCON_DEVICE_ADD; 567 event.value = 1; 568 pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0); 569 570 event.event = VTCON_PORT_NAME; 571 pci_vtcon_control_send(port->vsp_sc, &event, port->vsp_name, 572 strlen(port->vsp_name)); 573 } 574 575 static void 576 pci_vtcon_open_port(struct pci_vtcon_port *port, bool open) 577 { 578 struct pci_vtcon_control event; 579 580 if (!port->vsp_sc->vsc_ready) { 581 port->vsp_open = true; 582 return; 583 } 584 585 event.id = port->vsp_id; 586 event.event = VTCON_PORT_OPEN; 587 event.value = (int)open; 588 pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0); 589 } 590 591 static void 592 pci_vtcon_control_send(struct pci_vtcon_softc *sc, 593 struct pci_vtcon_control *ctrl, const void *payload, size_t len) 594 { 595 struct vqueue_info *vq; 596 struct vi_req req; 597 struct iovec iov; 598 int n; 599 600 vq = pci_vtcon_port_to_vq(&sc->vsc_control_port, true); 601 602 if (!vq_has_descs(vq)) 603 return; 604 605 n = vq_getchain(vq, &iov, 1, &req); 606 assert(n == 1); 607 608 memcpy(iov.iov_base, ctrl, sizeof(struct pci_vtcon_control)); 609 if (payload != NULL && len > 0) 610 memcpy((uint8_t *)iov.iov_base + 611 sizeof(struct pci_vtcon_control), payload, len); 612 613 vq_relchain(vq, req.idx, sizeof(struct pci_vtcon_control) + len); 614 vq_endchains(vq, 1); 615 } 616 617 618 static void 619 pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq) 620 { 621 struct pci_vtcon_softc *sc; 622 struct pci_vtcon_port *port; 623 struct iovec iov[1]; 624 struct vi_req req; 625 int n; 626 627 sc = vsc; 628 port = pci_vtcon_vq_to_port(sc, vq); 629 630 while (vq_has_descs(vq)) { 631 n = vq_getchain(vq, iov, 1, &req); 632 assert(n == 1); 633 if (port != NULL) 634 port->vsp_cb(port, port->vsp_arg, iov, 1); 635 636 /* 637 * Release this chain and handle more 638 */ 639 vq_relchain(vq, req.idx, 0); 640 } 641 vq_endchains(vq, 1); /* Generate interrupt if appropriate. */ 642 } 643 644 static void 645 pci_vtcon_notify_rx(void *vsc, struct vqueue_info *vq) 646 { 647 struct pci_vtcon_softc *sc; 648 struct pci_vtcon_port *port; 649 650 sc = vsc; 651 port = pci_vtcon_vq_to_port(sc, vq); 652 653 if (!port->vsp_rx_ready) { 654 port->vsp_rx_ready = 1; 655 vq_kick_disable(vq); 656 } 657 } 658 659 /* 660 * Each console device has a "port" node which contains nodes for 661 * each port. Ports are numbered starting at 0. 662 */ 663 static int 664 pci_vtcon_legacy_config_port(nvlist_t *nvl, int port, char *opt) 665 { 666 char *name, *path; 667 char node_name[sizeof("XX")]; 668 nvlist_t *port_nvl; 669 670 name = strsep(&opt, "="); 671 path = opt; 672 if (path == NULL) { 673 EPRINTLN("vtcon: port %s requires a path", name); 674 return (-1); 675 } 676 if (port >= VTCON_MAXPORTS) { 677 EPRINTLN("vtcon: too many ports"); 678 return (-1); 679 } 680 snprintf(node_name, sizeof(node_name), "%d", port); 681 port_nvl = create_relative_config_node(nvl, node_name); 682 set_config_value_node(port_nvl, "name", name); 683 set_config_value_node(port_nvl, "path", path); 684 return (0); 685 } 686 687 static int 688 pci_vtcon_legacy_config(nvlist_t *nvl, const char *opts) 689 { 690 char *opt, *str, *tofree; 691 nvlist_t *ports_nvl; 692 int error, port; 693 694 ports_nvl = create_relative_config_node(nvl, "port"); 695 tofree = str = strdup(opts); 696 error = 0; 697 port = 0; 698 while ((opt = strsep(&str, ",")) != NULL) { 699 error = pci_vtcon_legacy_config_port(ports_nvl, port, opt); 700 if (error) 701 break; 702 port++; 703 } 704 free(tofree); 705 return (error); 706 } 707 708 static int 709 pci_vtcon_init(struct pci_devinst *pi, nvlist_t *nvl) 710 { 711 struct pci_vtcon_softc *sc; 712 nvlist_t *ports_nvl; 713 int i; 714 715 sc = calloc(1, sizeof(struct pci_vtcon_softc)); 716 sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config)); 717 sc->vsc_config->max_nr_ports = VTCON_MAXPORTS; 718 sc->vsc_config->cols = 80; 719 sc->vsc_config->rows = 25; 720 721 pthread_mutex_init(&sc->vsc_mtx, NULL); 722 723 vi_softc_linkup(&sc->vsc_vs, &vtcon_vi_consts, sc, pi, sc->vsc_queues); 724 sc->vsc_vs.vs_mtx = &sc->vsc_mtx; 725 726 for (i = 0; i < VTCON_MAXQ; i++) { 727 sc->vsc_queues[i].vq_qsize = VTCON_RINGSZ; 728 sc->vsc_queues[i].vq_notify = i % 2 == 0 729 ? pci_vtcon_notify_rx 730 : pci_vtcon_notify_tx; 731 } 732 733 /* initialize config space */ 734 pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_CONSOLE); 735 pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 736 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM); 737 pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_CONSOLE); 738 pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); 739 740 if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) 741 return (1); 742 vi_set_io_bar(&sc->vsc_vs, 0); 743 744 /* create control port */ 745 sc->vsc_control_port.vsp_sc = sc; 746 sc->vsc_control_port.vsp_txq = 2; 747 sc->vsc_control_port.vsp_rxq = 3; 748 sc->vsc_control_port.vsp_cb = pci_vtcon_control_tx; 749 sc->vsc_control_port.vsp_enabled = true; 750 751 ports_nvl = find_relative_config_node(nvl, "port"); 752 if (ports_nvl != NULL) { 753 const char *name; 754 void *cookie; 755 int type; 756 757 cookie = NULL; 758 while ((name = nvlist_next(ports_nvl, &type, &cookie)) != 759 NULL) { 760 if (type != NV_TYPE_NVLIST) 761 continue; 762 763 if (pci_vtcon_sock_add(sc, name, 764 nvlist_get_nvlist(ports_nvl, name)) < 0) { 765 EPRINTLN("cannot create port %s: %s", 766 name, strerror(errno)); 767 return (1); 768 } 769 } 770 } 771 772 return (0); 773 } 774 775 static const struct pci_devemu pci_de_vcon = { 776 .pe_emu = "virtio-console", 777 .pe_init = pci_vtcon_init, 778 .pe_barwrite = vi_pci_write, 779 .pe_barread = vi_pci_read, 780 .pe_legacy_config = pci_vtcon_legacy_config, 781 }; 782 PCI_EMUL_SET(pci_de_vcon); 783