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