14c87aefeSPatrick Mooney /*- 24c87aefeSPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 34c87aefeSPatrick Mooney * 44c87aefeSPatrick Mooney * Copyright (c) 2016 iXsystems Inc. 54c87aefeSPatrick Mooney * All rights reserved. 64c87aefeSPatrick Mooney * 74c87aefeSPatrick Mooney * This software was developed by Jakub Klama <jceel@FreeBSD.org> 84c87aefeSPatrick Mooney * under sponsorship from iXsystems Inc. 94c87aefeSPatrick Mooney * 104c87aefeSPatrick Mooney * Redistribution and use in source and binary forms, with or without 114c87aefeSPatrick Mooney * modification, are permitted provided that the following conditions 124c87aefeSPatrick Mooney * are met: 134c87aefeSPatrick Mooney * 1. Redistributions of source code must retain the above copyright 144c87aefeSPatrick Mooney * notice, this list of conditions and the following disclaimer 154c87aefeSPatrick Mooney * in this position and unchanged. 164c87aefeSPatrick Mooney * 2. Redistributions in binary form must reproduce the above copyright 174c87aefeSPatrick Mooney * notice, this list of conditions and the following disclaimer in the 184c87aefeSPatrick Mooney * documentation and/or other materials provided with the distribution. 194c87aefeSPatrick Mooney * 204c87aefeSPatrick Mooney * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214c87aefeSPatrick Mooney * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224c87aefeSPatrick Mooney * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234c87aefeSPatrick Mooney * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244c87aefeSPatrick Mooney * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254c87aefeSPatrick Mooney * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264c87aefeSPatrick Mooney * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274c87aefeSPatrick Mooney * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284c87aefeSPatrick Mooney * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294c87aefeSPatrick Mooney * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304c87aefeSPatrick Mooney * SUCH DAMAGE. 314c87aefeSPatrick Mooney */ 324c87aefeSPatrick Mooney 334c87aefeSPatrick Mooney /* 344c87aefeSPatrick Mooney * Copyright 2018 Joyent, Inc. 354c87aefeSPatrick Mooney */ 364c87aefeSPatrick Mooney 374c87aefeSPatrick Mooney #include <sys/cdefs.h> 384c87aefeSPatrick Mooney __FBSDID("$FreeBSD$"); 394c87aefeSPatrick Mooney 404c87aefeSPatrick Mooney #include <sys/param.h> 414c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 424c87aefeSPatrick Mooney #include <sys/capsicum.h> 434c87aefeSPatrick Mooney #endif 444c87aefeSPatrick Mooney #include <sys/linker_set.h> 454c87aefeSPatrick Mooney #include <sys/uio.h> 464c87aefeSPatrick Mooney #include <sys/types.h> 474c87aefeSPatrick Mooney #include <sys/socket.h> 484c87aefeSPatrick Mooney #include <sys/un.h> 494c87aefeSPatrick Mooney 504c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 514c87aefeSPatrick Mooney #include <capsicum_helpers.h> 524c87aefeSPatrick Mooney #endif 534c87aefeSPatrick Mooney #include <err.h> 544c87aefeSPatrick Mooney #include <errno.h> 554c87aefeSPatrick Mooney #include <fcntl.h> 564c87aefeSPatrick Mooney #include <stdio.h> 574c87aefeSPatrick Mooney #include <stdlib.h> 584c87aefeSPatrick Mooney #include <stdbool.h> 594c87aefeSPatrick Mooney #include <string.h> 604c87aefeSPatrick Mooney #include <unistd.h> 614c87aefeSPatrick Mooney #include <assert.h> 624c87aefeSPatrick Mooney #include <pthread.h> 634c87aefeSPatrick Mooney #include <libgen.h> 644c87aefeSPatrick Mooney #include <sysexits.h> 654c87aefeSPatrick Mooney 664c87aefeSPatrick Mooney #include "bhyverun.h" 672b948146SAndy Fiddaman #include "config.h" 68154972afSPatrick Mooney #include "debug.h" 694c87aefeSPatrick Mooney #include "pci_emul.h" 704c87aefeSPatrick Mooney #include "virtio.h" 714c87aefeSPatrick Mooney #include "mevent.h" 724c87aefeSPatrick Mooney #include "sockstream.h" 734c87aefeSPatrick Mooney 744c87aefeSPatrick Mooney #define VTCON_RINGSZ 64 754c87aefeSPatrick Mooney #define VTCON_MAXPORTS 16 764c87aefeSPatrick Mooney #define VTCON_MAXQ (VTCON_MAXPORTS * 2 + 2) 774c87aefeSPatrick Mooney 784c87aefeSPatrick Mooney #define VTCON_DEVICE_READY 0 794c87aefeSPatrick Mooney #define VTCON_DEVICE_ADD 1 804c87aefeSPatrick Mooney #define VTCON_DEVICE_REMOVE 2 814c87aefeSPatrick Mooney #define VTCON_PORT_READY 3 824c87aefeSPatrick Mooney #define VTCON_CONSOLE_PORT 4 834c87aefeSPatrick Mooney #define VTCON_CONSOLE_RESIZE 5 844c87aefeSPatrick Mooney #define VTCON_PORT_OPEN 6 854c87aefeSPatrick Mooney #define VTCON_PORT_NAME 7 864c87aefeSPatrick Mooney 874c87aefeSPatrick Mooney #define VTCON_F_SIZE 0 884c87aefeSPatrick Mooney #define VTCON_F_MULTIPORT 1 894c87aefeSPatrick Mooney #define VTCON_F_EMERG_WRITE 2 904c87aefeSPatrick Mooney #define VTCON_S_HOSTCAPS \ 914c87aefeSPatrick Mooney (VTCON_F_SIZE | VTCON_F_MULTIPORT | VTCON_F_EMERG_WRITE) 924c87aefeSPatrick Mooney 934c87aefeSPatrick Mooney static int pci_vtcon_debug; 94154972afSPatrick Mooney #define DPRINTF(params) if (pci_vtcon_debug) PRINTLN params 95154972afSPatrick Mooney #define WPRINTF(params) PRINTLN params 964c87aefeSPatrick Mooney 974c87aefeSPatrick Mooney struct pci_vtcon_softc; 984c87aefeSPatrick Mooney struct pci_vtcon_port; 994c87aefeSPatrick Mooney struct pci_vtcon_config; 1004c87aefeSPatrick Mooney typedef void (pci_vtcon_cb_t)(struct pci_vtcon_port *, void *, struct iovec *, 1014c87aefeSPatrick Mooney int); 1024c87aefeSPatrick Mooney 1034c87aefeSPatrick Mooney struct pci_vtcon_port { 1044c87aefeSPatrick Mooney struct pci_vtcon_softc * vsp_sc; 1054c87aefeSPatrick Mooney int vsp_id; 1064c87aefeSPatrick Mooney const char * vsp_name; 1074c87aefeSPatrick Mooney bool vsp_enabled; 1084c87aefeSPatrick Mooney bool vsp_console; 1094c87aefeSPatrick Mooney bool vsp_rx_ready; 1104c87aefeSPatrick Mooney bool vsp_open; 1114c87aefeSPatrick Mooney int vsp_rxq; 1124c87aefeSPatrick Mooney int vsp_txq; 1134c87aefeSPatrick Mooney void * vsp_arg; 1144c87aefeSPatrick Mooney pci_vtcon_cb_t * vsp_cb; 1154c87aefeSPatrick Mooney }; 1164c87aefeSPatrick Mooney 1174c87aefeSPatrick Mooney struct pci_vtcon_sock 1184c87aefeSPatrick Mooney { 1194c87aefeSPatrick Mooney struct pci_vtcon_port * vss_port; 1204c87aefeSPatrick Mooney const char * vss_path; 1214c87aefeSPatrick Mooney struct mevent * vss_server_evp; 1224c87aefeSPatrick Mooney struct mevent * vss_conn_evp; 1234c87aefeSPatrick Mooney int vss_server_fd; 1244c87aefeSPatrick Mooney int vss_conn_fd; 1254c87aefeSPatrick Mooney bool vss_open; 1264c87aefeSPatrick Mooney }; 1274c87aefeSPatrick Mooney 1284c87aefeSPatrick Mooney struct pci_vtcon_softc { 1294c87aefeSPatrick Mooney struct virtio_softc vsc_vs; 1304c87aefeSPatrick Mooney struct vqueue_info vsc_queues[VTCON_MAXQ]; 1314c87aefeSPatrick Mooney pthread_mutex_t vsc_mtx; 1324c87aefeSPatrick Mooney uint64_t vsc_cfg; 1334c87aefeSPatrick Mooney uint64_t vsc_features; 1344c87aefeSPatrick Mooney char * vsc_rootdir; 1354c87aefeSPatrick Mooney int vsc_kq; 1364c87aefeSPatrick Mooney bool vsc_ready; 1374c87aefeSPatrick Mooney struct pci_vtcon_port vsc_control_port; 1384c87aefeSPatrick Mooney struct pci_vtcon_port vsc_ports[VTCON_MAXPORTS]; 1394c87aefeSPatrick Mooney struct pci_vtcon_config *vsc_config; 1404c87aefeSPatrick Mooney }; 1414c87aefeSPatrick Mooney 1424c87aefeSPatrick Mooney struct pci_vtcon_config { 1434c87aefeSPatrick Mooney uint16_t cols; 1444c87aefeSPatrick Mooney uint16_t rows; 1454c87aefeSPatrick Mooney uint32_t max_nr_ports; 1464c87aefeSPatrick Mooney uint32_t emerg_wr; 1474c87aefeSPatrick Mooney } __attribute__((packed)); 1484c87aefeSPatrick Mooney 1494c87aefeSPatrick Mooney struct pci_vtcon_control { 1504c87aefeSPatrick Mooney uint32_t id; 1514c87aefeSPatrick Mooney uint16_t event; 1524c87aefeSPatrick Mooney uint16_t value; 1534c87aefeSPatrick Mooney } __attribute__((packed)); 1544c87aefeSPatrick Mooney 1554c87aefeSPatrick Mooney struct pci_vtcon_console_resize { 1564c87aefeSPatrick Mooney uint16_t cols; 1574c87aefeSPatrick Mooney uint16_t rows; 1584c87aefeSPatrick Mooney } __attribute__((packed)); 1594c87aefeSPatrick Mooney 1604c87aefeSPatrick Mooney static void pci_vtcon_reset(void *); 1614c87aefeSPatrick Mooney static void pci_vtcon_notify_rx(void *, struct vqueue_info *); 1624c87aefeSPatrick Mooney static void pci_vtcon_notify_tx(void *, struct vqueue_info *); 1634c87aefeSPatrick Mooney static int pci_vtcon_cfgread(void *, int, int, uint32_t *); 1644c87aefeSPatrick Mooney static int pci_vtcon_cfgwrite(void *, int, int, uint32_t); 1654c87aefeSPatrick Mooney static void pci_vtcon_neg_features(void *, uint64_t); 1664c87aefeSPatrick Mooney static void pci_vtcon_sock_accept(int, enum ev_type, void *); 1674c87aefeSPatrick Mooney static void pci_vtcon_sock_rx(int, enum ev_type, void *); 1684c87aefeSPatrick Mooney static void pci_vtcon_sock_tx(struct pci_vtcon_port *, void *, struct iovec *, 1694c87aefeSPatrick Mooney int); 1704c87aefeSPatrick Mooney static void pci_vtcon_control_send(struct pci_vtcon_softc *, 1714c87aefeSPatrick Mooney struct pci_vtcon_control *, const void *, size_t); 1724c87aefeSPatrick Mooney static void pci_vtcon_announce_port(struct pci_vtcon_port *); 1734c87aefeSPatrick Mooney static void pci_vtcon_open_port(struct pci_vtcon_port *, bool); 1744c87aefeSPatrick Mooney 1754c87aefeSPatrick Mooney static struct virtio_consts vtcon_vi_consts = { 1764c87aefeSPatrick Mooney "vtcon", /* our name */ 1774c87aefeSPatrick Mooney VTCON_MAXQ, /* we support VTCON_MAXQ virtqueues */ 1784c87aefeSPatrick Mooney sizeof(struct pci_vtcon_config), /* config reg size */ 1794c87aefeSPatrick Mooney pci_vtcon_reset, /* reset */ 1804c87aefeSPatrick Mooney NULL, /* device-wide qnotify */ 1814c87aefeSPatrick Mooney pci_vtcon_cfgread, /* read virtio config */ 1824c87aefeSPatrick Mooney pci_vtcon_cfgwrite, /* write virtio config */ 1834c87aefeSPatrick Mooney pci_vtcon_neg_features, /* apply negotiated features */ 1844c87aefeSPatrick Mooney VTCON_S_HOSTCAPS, /* our capabilities */ 1854c87aefeSPatrick Mooney }; 1864c87aefeSPatrick Mooney 1874c87aefeSPatrick Mooney 1884c87aefeSPatrick Mooney static void 1894c87aefeSPatrick Mooney pci_vtcon_reset(void *vsc) 1904c87aefeSPatrick Mooney { 1914c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 1924c87aefeSPatrick Mooney 1934c87aefeSPatrick Mooney sc = vsc; 1944c87aefeSPatrick Mooney 195154972afSPatrick Mooney DPRINTF(("vtcon: device reset requested!")); 1964c87aefeSPatrick Mooney vi_reset_dev(&sc->vsc_vs); 1974c87aefeSPatrick Mooney } 1984c87aefeSPatrick Mooney 1994c87aefeSPatrick Mooney static void 2004c87aefeSPatrick Mooney pci_vtcon_neg_features(void *vsc, uint64_t negotiated_features) 2014c87aefeSPatrick Mooney { 2024c87aefeSPatrick Mooney struct pci_vtcon_softc *sc = vsc; 2034c87aefeSPatrick Mooney 2044c87aefeSPatrick Mooney sc->vsc_features = negotiated_features; 2054c87aefeSPatrick Mooney } 2064c87aefeSPatrick Mooney 2074c87aefeSPatrick Mooney static int 2084c87aefeSPatrick Mooney pci_vtcon_cfgread(void *vsc, int offset, int size, uint32_t *retval) 2094c87aefeSPatrick Mooney { 2104c87aefeSPatrick Mooney struct pci_vtcon_softc *sc = vsc; 2114c87aefeSPatrick Mooney void *ptr; 2124c87aefeSPatrick Mooney 2134c87aefeSPatrick Mooney ptr = (uint8_t *)sc->vsc_config + offset; 2144c87aefeSPatrick Mooney memcpy(retval, ptr, size); 2154c87aefeSPatrick Mooney return (0); 2164c87aefeSPatrick Mooney } 2174c87aefeSPatrick Mooney 2184c87aefeSPatrick Mooney static int 2194c87aefeSPatrick Mooney pci_vtcon_cfgwrite(void *vsc, int offset, int size, uint32_t val) 2204c87aefeSPatrick Mooney { 2214c87aefeSPatrick Mooney 2224c87aefeSPatrick Mooney return (0); 2234c87aefeSPatrick Mooney } 2244c87aefeSPatrick Mooney 2254c87aefeSPatrick Mooney static inline struct pci_vtcon_port * 2264c87aefeSPatrick Mooney pci_vtcon_vq_to_port(struct pci_vtcon_softc *sc, struct vqueue_info *vq) 2274c87aefeSPatrick Mooney { 2284c87aefeSPatrick Mooney uint16_t num = vq->vq_num; 2294c87aefeSPatrick Mooney 2304c87aefeSPatrick Mooney if (num == 0 || num == 1) 2314c87aefeSPatrick Mooney return (&sc->vsc_ports[0]); 2324c87aefeSPatrick Mooney 2334c87aefeSPatrick Mooney if (num == 2 || num == 3) 2344c87aefeSPatrick Mooney return (&sc->vsc_control_port); 2354c87aefeSPatrick Mooney 2364c87aefeSPatrick Mooney return (&sc->vsc_ports[(num / 2) - 1]); 2374c87aefeSPatrick Mooney } 2384c87aefeSPatrick Mooney 2394c87aefeSPatrick Mooney static inline struct vqueue_info * 2404c87aefeSPatrick Mooney pci_vtcon_port_to_vq(struct pci_vtcon_port *port, bool tx_queue) 2414c87aefeSPatrick Mooney { 2424c87aefeSPatrick Mooney int qnum; 2434c87aefeSPatrick Mooney 2444c87aefeSPatrick Mooney qnum = tx_queue ? port->vsp_txq : port->vsp_rxq; 2454c87aefeSPatrick Mooney return (&port->vsp_sc->vsc_queues[qnum]); 2464c87aefeSPatrick Mooney } 2474c87aefeSPatrick Mooney 2484c87aefeSPatrick Mooney static struct pci_vtcon_port * 2492b948146SAndy Fiddaman pci_vtcon_port_add(struct pci_vtcon_softc *sc, int port_id, const char *name, 2504c87aefeSPatrick Mooney pci_vtcon_cb_t *cb, void *arg) 2514c87aefeSPatrick Mooney { 2524c87aefeSPatrick Mooney struct pci_vtcon_port *port; 2534c87aefeSPatrick Mooney 2542b948146SAndy Fiddaman port = &sc->vsc_ports[port_id]; 2552b948146SAndy Fiddaman if (port->vsp_enabled) { 2564c87aefeSPatrick Mooney errno = EBUSY; 2574c87aefeSPatrick Mooney return (NULL); 2584c87aefeSPatrick Mooney } 2592b948146SAndy Fiddaman port->vsp_id = port_id; 2604c87aefeSPatrick Mooney port->vsp_sc = sc; 2614c87aefeSPatrick Mooney port->vsp_name = name; 2624c87aefeSPatrick Mooney port->vsp_cb = cb; 2634c87aefeSPatrick Mooney port->vsp_arg = arg; 2644c87aefeSPatrick Mooney 2654c87aefeSPatrick Mooney if (port->vsp_id == 0) { 2664c87aefeSPatrick Mooney /* port0 */ 2674c87aefeSPatrick Mooney port->vsp_txq = 0; 2684c87aefeSPatrick Mooney port->vsp_rxq = 1; 2694c87aefeSPatrick Mooney } else { 2702b948146SAndy Fiddaman port->vsp_txq = (port_id + 1) * 2; 2714c87aefeSPatrick Mooney port->vsp_rxq = port->vsp_txq + 1; 2724c87aefeSPatrick Mooney } 2734c87aefeSPatrick Mooney 2744c87aefeSPatrick Mooney port->vsp_enabled = true; 2754c87aefeSPatrick Mooney return (port); 2764c87aefeSPatrick Mooney } 2774c87aefeSPatrick Mooney 2784c87aefeSPatrick Mooney static int 2792b948146SAndy Fiddaman pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *port_name, 2802b948146SAndy Fiddaman const nvlist_t *nvl) 2814c87aefeSPatrick Mooney { 2824c87aefeSPatrick Mooney #ifdef __FreeBSD__ 2832b948146SAndy Fiddaman struct pci_vtcon_sock *sock; 2844c87aefeSPatrick Mooney struct sockaddr_un sun; 2854c87aefeSPatrick Mooney #else 2862b948146SAndy Fiddaman struct pci_vtcon_sock *sock = NULL; 2874c87aefeSPatrick Mooney /* Our compiler #defines 'sun' as '1'. Awesome. */ 2884c87aefeSPatrick Mooney struct sockaddr_un addr; 2894c87aefeSPatrick Mooney #endif 2902b948146SAndy Fiddaman const char *name, *path; 2912b948146SAndy Fiddaman char *cp, *pathcopy; 2922b948146SAndy Fiddaman long port; 2934c87aefeSPatrick Mooney int s = -1, fd = -1, error = 0; 2944c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 2954c87aefeSPatrick Mooney cap_rights_t rights; 2964c87aefeSPatrick Mooney #endif 2974c87aefeSPatrick Mooney 2982b948146SAndy Fiddaman port = strtol(port_name, &cp, 0); 2992b948146SAndy Fiddaman if (*cp != '\0' || port < 0 || port >= VTCON_MAXPORTS) { 3002b948146SAndy Fiddaman EPRINTLN("vtcon: Invalid port %s", port_name); 3012b948146SAndy Fiddaman error = -1; 3022b948146SAndy Fiddaman goto out; 3032b948146SAndy Fiddaman } 3042b948146SAndy Fiddaman 3052b948146SAndy Fiddaman path = get_config_value_node(nvl, "path"); 3062b948146SAndy Fiddaman if (path == NULL) { 3072b948146SAndy Fiddaman EPRINTLN("vtcon: required path missing for port %ld", port); 3082b948146SAndy Fiddaman error = -1; 3092b948146SAndy Fiddaman goto out; 3102b948146SAndy Fiddaman } 3112b948146SAndy Fiddaman 3124c87aefeSPatrick Mooney sock = calloc(1, sizeof(struct pci_vtcon_sock)); 3134c87aefeSPatrick Mooney if (sock == NULL) { 3144c87aefeSPatrick Mooney error = -1; 3154c87aefeSPatrick Mooney goto out; 3164c87aefeSPatrick Mooney } 3174c87aefeSPatrick Mooney 3184c87aefeSPatrick Mooney s = socket(AF_UNIX, SOCK_STREAM, 0); 3194c87aefeSPatrick Mooney if (s < 0) { 3204c87aefeSPatrick Mooney error = -1; 3214c87aefeSPatrick Mooney goto out; 3224c87aefeSPatrick Mooney } 3234c87aefeSPatrick Mooney 3244c87aefeSPatrick Mooney #ifdef __FreeBSD__ 3254c87aefeSPatrick Mooney pathcopy = strdup(path); 3264c87aefeSPatrick Mooney if (pathcopy == NULL) { 3274c87aefeSPatrick Mooney error = -1; 3284c87aefeSPatrick Mooney goto out; 3294c87aefeSPatrick Mooney } 3304c87aefeSPatrick Mooney 3314c87aefeSPatrick Mooney fd = open(dirname(pathcopy), O_RDONLY | O_DIRECTORY); 3324c87aefeSPatrick Mooney if (fd < 0) { 3334c87aefeSPatrick Mooney free(pathcopy); 3344c87aefeSPatrick Mooney error = -1; 3354c87aefeSPatrick Mooney goto out; 3364c87aefeSPatrick Mooney } 3374c87aefeSPatrick Mooney 3384c87aefeSPatrick Mooney sun.sun_family = AF_UNIX; 3394c87aefeSPatrick Mooney sun.sun_len = sizeof(struct sockaddr_un); 3404c87aefeSPatrick Mooney strcpy(pathcopy, path); 3414c87aefeSPatrick Mooney strlcpy(sun.sun_path, basename(pathcopy), sizeof(sun.sun_path)); 3424c87aefeSPatrick Mooney free(pathcopy); 3434c87aefeSPatrick Mooney 3444c87aefeSPatrick Mooney if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0) { 3454c87aefeSPatrick Mooney error = -1; 3464c87aefeSPatrick Mooney goto out; 3474c87aefeSPatrick Mooney } 3484c87aefeSPatrick Mooney #else /* __FreeBSD__ */ 3494c87aefeSPatrick Mooney /* Do a simple bind rather than the FreeBSD bindat() */ 3502b948146SAndy Fiddaman pathcopy = (char *)path; 3514c87aefeSPatrick Mooney addr.sun_family = AF_UNIX; 3522b948146SAndy Fiddaman (void) strlcpy(addr.sun_path, pathcopy, sizeof (addr.sun_path)); 3534c87aefeSPatrick Mooney if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { 3544c87aefeSPatrick Mooney error = -1; 3554c87aefeSPatrick Mooney goto out; 3564c87aefeSPatrick Mooney } 3574c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 3584c87aefeSPatrick Mooney 3594c87aefeSPatrick Mooney if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { 3604c87aefeSPatrick Mooney error = -1; 3614c87aefeSPatrick Mooney goto out; 3624c87aefeSPatrick Mooney } 3634c87aefeSPatrick Mooney 3644c87aefeSPatrick Mooney if (listen(s, 1) < 0) { 3654c87aefeSPatrick Mooney error = -1; 3664c87aefeSPatrick Mooney goto out; 3674c87aefeSPatrick Mooney } 3684c87aefeSPatrick Mooney 3694c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 3704c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE); 3714c87aefeSPatrick Mooney if (caph_rights_limit(s, &rights) == -1) 3724c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 3734c87aefeSPatrick Mooney #endif 3744c87aefeSPatrick Mooney 3752b948146SAndy Fiddaman name = get_config_value_node(nvl, "name"); 3762b948146SAndy Fiddaman if (name == NULL) { 3772b948146SAndy Fiddaman EPRINTLN("vtcon: required name missing for port %ld", port); 3782b948146SAndy Fiddaman error = -1; 3792b948146SAndy Fiddaman goto out; 3802b948146SAndy Fiddaman } 3812b948146SAndy Fiddaman sock->vss_port = pci_vtcon_port_add(sc, port, name, pci_vtcon_sock_tx, sock); 3824c87aefeSPatrick Mooney if (sock->vss_port == NULL) { 3834c87aefeSPatrick Mooney error = -1; 3844c87aefeSPatrick Mooney goto out; 3854c87aefeSPatrick Mooney } 3864c87aefeSPatrick Mooney 3874c87aefeSPatrick Mooney sock->vss_open = false; 3884c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 3894c87aefeSPatrick Mooney sock->vss_server_fd = s; 3904c87aefeSPatrick Mooney sock->vss_server_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_accept, 3914c87aefeSPatrick Mooney sock); 3924c87aefeSPatrick Mooney 3934c87aefeSPatrick Mooney if (sock->vss_server_evp == NULL) { 3944c87aefeSPatrick Mooney error = -1; 3954c87aefeSPatrick Mooney goto out; 3964c87aefeSPatrick Mooney } 3974c87aefeSPatrick Mooney 3984c87aefeSPatrick Mooney out: 3994c87aefeSPatrick Mooney if (fd != -1) 4004c87aefeSPatrick Mooney close(fd); 4014c87aefeSPatrick Mooney 40284659b24SMichael Zeller if (error != 0) { 40384659b24SMichael Zeller if (s != -1) 4044c87aefeSPatrick Mooney close(s); 40584659b24SMichael Zeller free(sock); 40684659b24SMichael Zeller } 4074c87aefeSPatrick Mooney 4084c87aefeSPatrick Mooney return (error); 4094c87aefeSPatrick Mooney } 4104c87aefeSPatrick Mooney 4114c87aefeSPatrick Mooney static void 4124c87aefeSPatrick Mooney pci_vtcon_sock_accept(int fd __unused, enum ev_type t __unused, void *arg) 4134c87aefeSPatrick Mooney { 4144c87aefeSPatrick Mooney struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg; 4154c87aefeSPatrick Mooney int s; 4164c87aefeSPatrick Mooney 4174c87aefeSPatrick Mooney s = accept(sock->vss_server_fd, NULL, NULL); 4184c87aefeSPatrick Mooney if (s < 0) 4194c87aefeSPatrick Mooney return; 4204c87aefeSPatrick Mooney 4214c87aefeSPatrick Mooney if (sock->vss_open) { 4224c87aefeSPatrick Mooney close(s); 4234c87aefeSPatrick Mooney return; 4244c87aefeSPatrick Mooney } 4254c87aefeSPatrick Mooney 4264c87aefeSPatrick Mooney sock->vss_open = true; 4274c87aefeSPatrick Mooney sock->vss_conn_fd = s; 4284c87aefeSPatrick Mooney sock->vss_conn_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_rx, sock); 4294c87aefeSPatrick Mooney 4304c87aefeSPatrick Mooney pci_vtcon_open_port(sock->vss_port, true); 4314c87aefeSPatrick Mooney } 4324c87aefeSPatrick Mooney 4334c87aefeSPatrick Mooney static void 4344c87aefeSPatrick Mooney pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg) 4354c87aefeSPatrick Mooney { 4364c87aefeSPatrick Mooney struct pci_vtcon_port *port; 4374c87aefeSPatrick Mooney struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg; 4384c87aefeSPatrick Mooney struct vqueue_info *vq; 439*b0de25cbSAndy Fiddaman struct vi_req req; 4404c87aefeSPatrick Mooney struct iovec iov; 4414c87aefeSPatrick Mooney static char dummybuf[2048]; 4424c87aefeSPatrick Mooney int len, n; 4434c87aefeSPatrick Mooney 4444c87aefeSPatrick Mooney port = sock->vss_port; 4454c87aefeSPatrick Mooney vq = pci_vtcon_port_to_vq(port, true); 4464c87aefeSPatrick Mooney 4474c87aefeSPatrick Mooney if (!sock->vss_open || !port->vsp_rx_ready) { 4484c87aefeSPatrick Mooney len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf)); 4494c87aefeSPatrick Mooney if (len == 0) 4504c87aefeSPatrick Mooney goto close; 4514c87aefeSPatrick Mooney 4524c87aefeSPatrick Mooney return; 4534c87aefeSPatrick Mooney } 4544c87aefeSPatrick Mooney 4554c87aefeSPatrick Mooney if (!vq_has_descs(vq)) { 4564c87aefeSPatrick Mooney len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf)); 4574c87aefeSPatrick Mooney vq_endchains(vq, 1); 4584c87aefeSPatrick Mooney if (len == 0) 4594c87aefeSPatrick Mooney goto close; 4604c87aefeSPatrick Mooney 4614c87aefeSPatrick Mooney return; 4624c87aefeSPatrick Mooney } 4634c87aefeSPatrick Mooney 4644c87aefeSPatrick Mooney do { 465*b0de25cbSAndy Fiddaman n = vq_getchain(vq, &iov, 1, &req); 466*b0de25cbSAndy Fiddaman assert(n == 1); 4674c87aefeSPatrick Mooney len = readv(sock->vss_conn_fd, &iov, n); 4684c87aefeSPatrick Mooney 4694c87aefeSPatrick Mooney if (len == 0 || (len < 0 && errno == EWOULDBLOCK)) { 470154972afSPatrick Mooney vq_retchains(vq, 1); 4714c87aefeSPatrick Mooney vq_endchains(vq, 0); 4724c87aefeSPatrick Mooney if (len == 0) 4734c87aefeSPatrick Mooney goto close; 4744c87aefeSPatrick Mooney 4754c87aefeSPatrick Mooney return; 4764c87aefeSPatrick Mooney } 4774c87aefeSPatrick Mooney 478*b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, len); 4794c87aefeSPatrick Mooney } while (vq_has_descs(vq)); 4804c87aefeSPatrick Mooney 4814c87aefeSPatrick Mooney vq_endchains(vq, 1); 4824c87aefeSPatrick Mooney 4834c87aefeSPatrick Mooney close: 4844c87aefeSPatrick Mooney mevent_delete_close(sock->vss_conn_evp); 4854c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 4864c87aefeSPatrick Mooney sock->vss_open = false; 4874c87aefeSPatrick Mooney } 4884c87aefeSPatrick Mooney 4894c87aefeSPatrick Mooney static void 4904c87aefeSPatrick Mooney pci_vtcon_sock_tx(struct pci_vtcon_port *port, void *arg, struct iovec *iov, 4914c87aefeSPatrick Mooney int niov) 4924c87aefeSPatrick Mooney { 4934c87aefeSPatrick Mooney struct pci_vtcon_sock *sock; 4944c87aefeSPatrick Mooney int i, ret; 4952b948146SAndy Fiddaman 4962b948146SAndy Fiddaman #ifndef __FreeBSD__ 4972b948146SAndy Fiddaman ret = 0; 4984c87aefeSPatrick Mooney #endif 4994c87aefeSPatrick Mooney 5004c87aefeSPatrick Mooney sock = (struct pci_vtcon_sock *)arg; 5014c87aefeSPatrick Mooney 5024c87aefeSPatrick Mooney if (sock->vss_conn_fd == -1) 5034c87aefeSPatrick Mooney return; 5044c87aefeSPatrick Mooney 5054c87aefeSPatrick Mooney for (i = 0; i < niov; i++) { 5064c87aefeSPatrick Mooney ret = stream_write(sock->vss_conn_fd, iov[i].iov_base, 5074c87aefeSPatrick Mooney iov[i].iov_len); 5084c87aefeSPatrick Mooney if (ret <= 0) 5094c87aefeSPatrick Mooney break; 5104c87aefeSPatrick Mooney } 5114c87aefeSPatrick Mooney 5124c87aefeSPatrick Mooney if (ret <= 0) { 5134c87aefeSPatrick Mooney mevent_delete_close(sock->vss_conn_evp); 5144c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 5154c87aefeSPatrick Mooney sock->vss_open = false; 5164c87aefeSPatrick Mooney } 5174c87aefeSPatrick Mooney } 5184c87aefeSPatrick Mooney 5194c87aefeSPatrick Mooney static void 5204c87aefeSPatrick Mooney pci_vtcon_control_tx(struct pci_vtcon_port *port, void *arg, struct iovec *iov, 5214c87aefeSPatrick Mooney int niov) 5224c87aefeSPatrick Mooney { 5234c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 5244c87aefeSPatrick Mooney struct pci_vtcon_port *tmp; 5254c87aefeSPatrick Mooney struct pci_vtcon_control resp, *ctrl; 5264c87aefeSPatrick Mooney int i; 5274c87aefeSPatrick Mooney 5284c87aefeSPatrick Mooney assert(niov == 1); 5294c87aefeSPatrick Mooney 5304c87aefeSPatrick Mooney sc = port->vsp_sc; 5314c87aefeSPatrick Mooney ctrl = (struct pci_vtcon_control *)iov->iov_base; 5324c87aefeSPatrick Mooney 5334c87aefeSPatrick Mooney switch (ctrl->event) { 5344c87aefeSPatrick Mooney case VTCON_DEVICE_READY: 5354c87aefeSPatrick Mooney sc->vsc_ready = true; 5364c87aefeSPatrick Mooney /* set port ready events for registered ports */ 5374c87aefeSPatrick Mooney for (i = 0; i < VTCON_MAXPORTS; i++) { 5384c87aefeSPatrick Mooney tmp = &sc->vsc_ports[i]; 5394c87aefeSPatrick Mooney if (tmp->vsp_enabled) 5404c87aefeSPatrick Mooney pci_vtcon_announce_port(tmp); 5414c87aefeSPatrick Mooney 5424c87aefeSPatrick Mooney if (tmp->vsp_open) 5434c87aefeSPatrick Mooney pci_vtcon_open_port(tmp, true); 5444c87aefeSPatrick Mooney } 5454c87aefeSPatrick Mooney break; 5464c87aefeSPatrick Mooney 5474c87aefeSPatrick Mooney case VTCON_PORT_READY: 5482b948146SAndy Fiddaman tmp = &sc->vsc_ports[ctrl->id]; 5492b948146SAndy Fiddaman if (ctrl->id >= VTCON_MAXPORTS || !tmp->vsp_enabled) { 550154972afSPatrick Mooney WPRINTF(("VTCON_PORT_READY event for unknown port %d", 5514c87aefeSPatrick Mooney ctrl->id)); 5524c87aefeSPatrick Mooney return; 5534c87aefeSPatrick Mooney } 5544c87aefeSPatrick Mooney 5554c87aefeSPatrick Mooney if (tmp->vsp_console) { 5564c87aefeSPatrick Mooney resp.event = VTCON_CONSOLE_PORT; 5574c87aefeSPatrick Mooney resp.id = ctrl->id; 5584c87aefeSPatrick Mooney resp.value = 1; 5594c87aefeSPatrick Mooney pci_vtcon_control_send(sc, &resp, NULL, 0); 5604c87aefeSPatrick Mooney } 5614c87aefeSPatrick Mooney break; 5624c87aefeSPatrick Mooney } 5634c87aefeSPatrick Mooney } 5644c87aefeSPatrick Mooney 5654c87aefeSPatrick Mooney static void 5664c87aefeSPatrick Mooney pci_vtcon_announce_port(struct pci_vtcon_port *port) 5674c87aefeSPatrick Mooney { 5684c87aefeSPatrick Mooney struct pci_vtcon_control event; 5694c87aefeSPatrick Mooney 5704c87aefeSPatrick Mooney event.id = port->vsp_id; 5714c87aefeSPatrick Mooney event.event = VTCON_DEVICE_ADD; 5724c87aefeSPatrick Mooney event.value = 1; 5734c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0); 5744c87aefeSPatrick Mooney 5754c87aefeSPatrick Mooney event.event = VTCON_PORT_NAME; 5764c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, port->vsp_name, 5774c87aefeSPatrick Mooney strlen(port->vsp_name)); 5784c87aefeSPatrick Mooney } 5794c87aefeSPatrick Mooney 5804c87aefeSPatrick Mooney static void 5814c87aefeSPatrick Mooney pci_vtcon_open_port(struct pci_vtcon_port *port, bool open) 5824c87aefeSPatrick Mooney { 5834c87aefeSPatrick Mooney struct pci_vtcon_control event; 5844c87aefeSPatrick Mooney 5854c87aefeSPatrick Mooney if (!port->vsp_sc->vsc_ready) { 5864c87aefeSPatrick Mooney port->vsp_open = true; 5874c87aefeSPatrick Mooney return; 5884c87aefeSPatrick Mooney } 5894c87aefeSPatrick Mooney 5904c87aefeSPatrick Mooney event.id = port->vsp_id; 5914c87aefeSPatrick Mooney event.event = VTCON_PORT_OPEN; 5924c87aefeSPatrick Mooney event.value = (int)open; 5934c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0); 5944c87aefeSPatrick Mooney } 5954c87aefeSPatrick Mooney 5964c87aefeSPatrick Mooney static void 5974c87aefeSPatrick Mooney pci_vtcon_control_send(struct pci_vtcon_softc *sc, 5984c87aefeSPatrick Mooney struct pci_vtcon_control *ctrl, const void *payload, size_t len) 5994c87aefeSPatrick Mooney { 6004c87aefeSPatrick Mooney struct vqueue_info *vq; 601*b0de25cbSAndy Fiddaman struct vi_req req; 6024c87aefeSPatrick Mooney struct iovec iov; 6034c87aefeSPatrick Mooney int n; 6044c87aefeSPatrick Mooney 6054c87aefeSPatrick Mooney vq = pci_vtcon_port_to_vq(&sc->vsc_control_port, true); 6064c87aefeSPatrick Mooney 6074c87aefeSPatrick Mooney if (!vq_has_descs(vq)) 6084c87aefeSPatrick Mooney return; 6094c87aefeSPatrick Mooney 610*b0de25cbSAndy Fiddaman n = vq_getchain(vq, &iov, 1, &req); 6114c87aefeSPatrick Mooney assert(n == 1); 6124c87aefeSPatrick Mooney 6134c87aefeSPatrick Mooney memcpy(iov.iov_base, ctrl, sizeof(struct pci_vtcon_control)); 6144c87aefeSPatrick Mooney if (payload != NULL && len > 0) 6154c87aefeSPatrick Mooney memcpy(iov.iov_base + sizeof(struct pci_vtcon_control), 6164c87aefeSPatrick Mooney payload, len); 6174c87aefeSPatrick Mooney 618*b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, sizeof(struct pci_vtcon_control) + len); 6194c87aefeSPatrick Mooney vq_endchains(vq, 1); 6204c87aefeSPatrick Mooney } 6214c87aefeSPatrick Mooney 6224c87aefeSPatrick Mooney 6234c87aefeSPatrick Mooney static void 6244c87aefeSPatrick Mooney pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq) 6254c87aefeSPatrick Mooney { 6264c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 6274c87aefeSPatrick Mooney struct pci_vtcon_port *port; 6284c87aefeSPatrick Mooney struct iovec iov[1]; 629*b0de25cbSAndy Fiddaman struct vi_req req; 630*b0de25cbSAndy Fiddaman int n; 6314c87aefeSPatrick Mooney 6324c87aefeSPatrick Mooney sc = vsc; 6334c87aefeSPatrick Mooney port = pci_vtcon_vq_to_port(sc, vq); 6344c87aefeSPatrick Mooney 6354c87aefeSPatrick Mooney while (vq_has_descs(vq)) { 636*b0de25cbSAndy Fiddaman n = vq_getchain(vq, iov, 1, &req); 637*b0de25cbSAndy Fiddaman assert(n == 1); 6384c87aefeSPatrick Mooney if (port != NULL) 6394c87aefeSPatrick Mooney port->vsp_cb(port, port->vsp_arg, iov, 1); 6404c87aefeSPatrick Mooney 6414c87aefeSPatrick Mooney /* 6424c87aefeSPatrick Mooney * Release this chain and handle more 6434c87aefeSPatrick Mooney */ 644*b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, 0); 6454c87aefeSPatrick Mooney } 6464c87aefeSPatrick Mooney vq_endchains(vq, 1); /* Generate interrupt if appropriate. */ 6474c87aefeSPatrick Mooney } 6484c87aefeSPatrick Mooney 6494c87aefeSPatrick Mooney static void 6504c87aefeSPatrick Mooney pci_vtcon_notify_rx(void *vsc, struct vqueue_info *vq) 6514c87aefeSPatrick Mooney { 6524c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 6534c87aefeSPatrick Mooney struct pci_vtcon_port *port; 6544c87aefeSPatrick Mooney 6554c87aefeSPatrick Mooney sc = vsc; 6564c87aefeSPatrick Mooney port = pci_vtcon_vq_to_port(sc, vq); 6574c87aefeSPatrick Mooney 6584c87aefeSPatrick Mooney if (!port->vsp_rx_ready) { 6594c87aefeSPatrick Mooney port->vsp_rx_ready = 1; 66084659b24SMichael Zeller vq_kick_disable(vq); 6614c87aefeSPatrick Mooney } 6624c87aefeSPatrick Mooney } 6634c87aefeSPatrick Mooney 6642b948146SAndy Fiddaman #ifdef __FreeBSD__ 6652b948146SAndy Fiddaman /* 6662b948146SAndy Fiddaman * Each console device has a "port" node which contains nodes for 6672b948146SAndy Fiddaman * each port. Ports are numbered starting at 0. 6682b948146SAndy Fiddaman */ 6694c87aefeSPatrick Mooney static int 6702b948146SAndy Fiddaman pci_vtcon_legacy_config_port(nvlist_t *nvl, int port, char *opt) 6712b948146SAndy Fiddaman { 6722b948146SAndy Fiddaman char *name, *path; 6732b948146SAndy Fiddaman char node_name[sizeof("XX")]; 6742b948146SAndy Fiddaman nvlist_t *port_nvl; 6752b948146SAndy Fiddaman 6762b948146SAndy Fiddaman name = strsep(&opt, "="); 6772b948146SAndy Fiddaman path = opt; 6782b948146SAndy Fiddaman if (path == NULL) { 6792b948146SAndy Fiddaman EPRINTLN("vtcon: port %s requires a path", name); 6802b948146SAndy Fiddaman return (-1); 6812b948146SAndy Fiddaman } 6822b948146SAndy Fiddaman if (port >= VTCON_MAXPORTS) { 6832b948146SAndy Fiddaman EPRINTLN("vtcon: too many ports"); 6842b948146SAndy Fiddaman return (-1); 6852b948146SAndy Fiddaman } 6862b948146SAndy Fiddaman snprintf(node_name, sizeof(node_name), "%d", port); 6872b948146SAndy Fiddaman port_nvl = create_relative_config_node(nvl, node_name); 6882b948146SAndy Fiddaman set_config_value_node(port_nvl, "name", name); 6892b948146SAndy Fiddaman set_config_value_node(port_nvl, "path", path); 6902b948146SAndy Fiddaman return (0); 6912b948146SAndy Fiddaman } 6922b948146SAndy Fiddaman 6932b948146SAndy Fiddaman static int 6942b948146SAndy Fiddaman pci_vtcon_legacy_config(nvlist_t *nvl, const char *opts) 6952b948146SAndy Fiddaman { 6962b948146SAndy Fiddaman char *opt, *str, *tofree; 6972b948146SAndy Fiddaman nvlist_t *ports_nvl; 6982b948146SAndy Fiddaman int error, port; 6992b948146SAndy Fiddaman 7002b948146SAndy Fiddaman ports_nvl = create_relative_config_node(nvl, "port"); 7012b948146SAndy Fiddaman tofree = str = strdup(opts); 7022b948146SAndy Fiddaman error = 0; 7032b948146SAndy Fiddaman port = 0; 7042b948146SAndy Fiddaman while ((opt = strsep(&str, ",")) != NULL) { 7052b948146SAndy Fiddaman error = pci_vtcon_legacy_config_port(ports_nvl, port, opt); 7062b948146SAndy Fiddaman if (error) 7072b948146SAndy Fiddaman break; 7082b948146SAndy Fiddaman port++; 7092b948146SAndy Fiddaman } 7102b948146SAndy Fiddaman free(tofree); 7112b948146SAndy Fiddaman return (error); 7122b948146SAndy Fiddaman } 7132b948146SAndy Fiddaman #endif 7142b948146SAndy Fiddaman 7152b948146SAndy Fiddaman static int 7162b948146SAndy Fiddaman pci_vtcon_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) 7174c87aefeSPatrick Mooney { 7184c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 7192b948146SAndy Fiddaman nvlist_t *ports_nvl; 7204c87aefeSPatrick Mooney int i; 7214c87aefeSPatrick Mooney 7224c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct pci_vtcon_softc)); 7234c87aefeSPatrick Mooney sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config)); 7244c87aefeSPatrick Mooney sc->vsc_config->max_nr_ports = VTCON_MAXPORTS; 7254c87aefeSPatrick Mooney sc->vsc_config->cols = 80; 7264c87aefeSPatrick Mooney sc->vsc_config->rows = 25; 7274c87aefeSPatrick Mooney 7284c87aefeSPatrick Mooney vi_softc_linkup(&sc->vsc_vs, &vtcon_vi_consts, sc, pi, sc->vsc_queues); 7294c87aefeSPatrick Mooney sc->vsc_vs.vs_mtx = &sc->vsc_mtx; 7304c87aefeSPatrick Mooney 7314c87aefeSPatrick Mooney for (i = 0; i < VTCON_MAXQ; i++) { 7324c87aefeSPatrick Mooney sc->vsc_queues[i].vq_qsize = VTCON_RINGSZ; 7334c87aefeSPatrick Mooney sc->vsc_queues[i].vq_notify = i % 2 == 0 7344c87aefeSPatrick Mooney ? pci_vtcon_notify_rx 7354c87aefeSPatrick Mooney : pci_vtcon_notify_tx; 7364c87aefeSPatrick Mooney } 7374c87aefeSPatrick Mooney 7384c87aefeSPatrick Mooney /* initialize config space */ 7394c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_CONSOLE); 7404c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 7414c87aefeSPatrick Mooney pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM); 7422b948146SAndy Fiddaman pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_CONSOLE); 7434c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); 7444c87aefeSPatrick Mooney 7454c87aefeSPatrick Mooney if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) 7464c87aefeSPatrick Mooney return (1); 7474c87aefeSPatrick Mooney vi_set_io_bar(&sc->vsc_vs, 0); 7484c87aefeSPatrick Mooney 7494c87aefeSPatrick Mooney /* create control port */ 7504c87aefeSPatrick Mooney sc->vsc_control_port.vsp_sc = sc; 7514c87aefeSPatrick Mooney sc->vsc_control_port.vsp_txq = 2; 7524c87aefeSPatrick Mooney sc->vsc_control_port.vsp_rxq = 3; 7534c87aefeSPatrick Mooney sc->vsc_control_port.vsp_cb = pci_vtcon_control_tx; 7544c87aefeSPatrick Mooney sc->vsc_control_port.vsp_enabled = true; 7554c87aefeSPatrick Mooney 7562b948146SAndy Fiddaman ports_nvl = find_relative_config_node(nvl, "port"); 7572b948146SAndy Fiddaman if (ports_nvl != NULL) { 7582b948146SAndy Fiddaman const char *name; 7592b948146SAndy Fiddaman void *cookie; 7602b948146SAndy Fiddaman int type; 7614c87aefeSPatrick Mooney 7622b948146SAndy Fiddaman cookie = NULL; 7632b948146SAndy Fiddaman while ((name = nvlist_next(ports_nvl, &type, &cookie)) != 7642b948146SAndy Fiddaman NULL) { 7652b948146SAndy Fiddaman if (type != NV_TYPE_NVLIST) 7662b948146SAndy Fiddaman continue; 7672b948146SAndy Fiddaman 7682b948146SAndy Fiddaman if (pci_vtcon_sock_add(sc, name, 7692b948146SAndy Fiddaman nvlist_get_nvlist(ports_nvl, name)) < 0) { 770154972afSPatrick Mooney EPRINTLN("cannot create port %s: %s", 7712b948146SAndy Fiddaman name, strerror(errno)); 7724c87aefeSPatrick Mooney return (1); 7734c87aefeSPatrick Mooney } 7744c87aefeSPatrick Mooney } 7752b948146SAndy Fiddaman } 7764c87aefeSPatrick Mooney 7774c87aefeSPatrick Mooney return (0); 7784c87aefeSPatrick Mooney } 7794c87aefeSPatrick Mooney 7804c87aefeSPatrick Mooney struct pci_devemu pci_de_vcon = { 7814c87aefeSPatrick Mooney .pe_emu = "virtio-console", 7824c87aefeSPatrick Mooney .pe_init = pci_vtcon_init, 7834c87aefeSPatrick Mooney .pe_barwrite = vi_pci_write, 7844c87aefeSPatrick Mooney .pe_barread = vi_pci_read 7854c87aefeSPatrick Mooney }; 7864c87aefeSPatrick Mooney PCI_EMUL_SET(pci_de_vcon); 787