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 = { 176*59d65d31SAndy Fiddaman .vc_name = "vtcon", 177*59d65d31SAndy Fiddaman .vc_nvq = VTCON_MAXQ, 178*59d65d31SAndy Fiddaman .vc_cfgsize = sizeof(struct pci_vtcon_config), 179*59d65d31SAndy Fiddaman .vc_reset = pci_vtcon_reset, 180*59d65d31SAndy Fiddaman .vc_cfgread = pci_vtcon_cfgread, 181*59d65d31SAndy Fiddaman .vc_cfgwrite = pci_vtcon_cfgwrite, 182*59d65d31SAndy Fiddaman .vc_apply_features = pci_vtcon_neg_features, 183*59d65d31SAndy Fiddaman .vc_hv_caps = VTCON_S_HOSTCAPS, 1844c87aefeSPatrick Mooney }; 1854c87aefeSPatrick Mooney 1864c87aefeSPatrick Mooney static void 1874c87aefeSPatrick Mooney pci_vtcon_reset(void *vsc) 1884c87aefeSPatrick Mooney { 1894c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 1904c87aefeSPatrick Mooney 1914c87aefeSPatrick Mooney sc = vsc; 1924c87aefeSPatrick Mooney 193154972afSPatrick Mooney DPRINTF(("vtcon: device reset requested!")); 1944c87aefeSPatrick Mooney vi_reset_dev(&sc->vsc_vs); 1954c87aefeSPatrick Mooney } 1964c87aefeSPatrick Mooney 1974c87aefeSPatrick Mooney static void 1984c87aefeSPatrick Mooney pci_vtcon_neg_features(void *vsc, uint64_t negotiated_features) 1994c87aefeSPatrick Mooney { 2004c87aefeSPatrick Mooney struct pci_vtcon_softc *sc = vsc; 2014c87aefeSPatrick Mooney 2024c87aefeSPatrick Mooney sc->vsc_features = negotiated_features; 2034c87aefeSPatrick Mooney } 2044c87aefeSPatrick Mooney 2054c87aefeSPatrick Mooney static int 2064c87aefeSPatrick Mooney pci_vtcon_cfgread(void *vsc, int offset, int size, uint32_t *retval) 2074c87aefeSPatrick Mooney { 2084c87aefeSPatrick Mooney struct pci_vtcon_softc *sc = vsc; 2094c87aefeSPatrick Mooney void *ptr; 2104c87aefeSPatrick Mooney 2114c87aefeSPatrick Mooney ptr = (uint8_t *)sc->vsc_config + offset; 2124c87aefeSPatrick Mooney memcpy(retval, ptr, size); 2134c87aefeSPatrick Mooney return (0); 2144c87aefeSPatrick Mooney } 2154c87aefeSPatrick Mooney 2164c87aefeSPatrick Mooney static int 217*59d65d31SAndy Fiddaman pci_vtcon_cfgwrite(void *vsc __unused, int offset __unused, int size __unused, 218*59d65d31SAndy Fiddaman uint32_t val __unused) 2194c87aefeSPatrick Mooney { 2204c87aefeSPatrick Mooney return (0); 2214c87aefeSPatrick Mooney } 2224c87aefeSPatrick Mooney 2234c87aefeSPatrick Mooney static inline struct pci_vtcon_port * 2244c87aefeSPatrick Mooney pci_vtcon_vq_to_port(struct pci_vtcon_softc *sc, struct vqueue_info *vq) 2254c87aefeSPatrick Mooney { 2264c87aefeSPatrick Mooney uint16_t num = vq->vq_num; 2274c87aefeSPatrick Mooney 2284c87aefeSPatrick Mooney if (num == 0 || num == 1) 2294c87aefeSPatrick Mooney return (&sc->vsc_ports[0]); 2304c87aefeSPatrick Mooney 2314c87aefeSPatrick Mooney if (num == 2 || num == 3) 2324c87aefeSPatrick Mooney return (&sc->vsc_control_port); 2334c87aefeSPatrick Mooney 2344c87aefeSPatrick Mooney return (&sc->vsc_ports[(num / 2) - 1]); 2354c87aefeSPatrick Mooney } 2364c87aefeSPatrick Mooney 2374c87aefeSPatrick Mooney static inline struct vqueue_info * 2384c87aefeSPatrick Mooney pci_vtcon_port_to_vq(struct pci_vtcon_port *port, bool tx_queue) 2394c87aefeSPatrick Mooney { 2404c87aefeSPatrick Mooney int qnum; 2414c87aefeSPatrick Mooney 2424c87aefeSPatrick Mooney qnum = tx_queue ? port->vsp_txq : port->vsp_rxq; 2434c87aefeSPatrick Mooney return (&port->vsp_sc->vsc_queues[qnum]); 2444c87aefeSPatrick Mooney } 2454c87aefeSPatrick Mooney 2464c87aefeSPatrick Mooney static struct pci_vtcon_port * 2472b948146SAndy Fiddaman pci_vtcon_port_add(struct pci_vtcon_softc *sc, int port_id, const char *name, 2484c87aefeSPatrick Mooney pci_vtcon_cb_t *cb, void *arg) 2494c87aefeSPatrick Mooney { 2504c87aefeSPatrick Mooney struct pci_vtcon_port *port; 2514c87aefeSPatrick Mooney 2522b948146SAndy Fiddaman port = &sc->vsc_ports[port_id]; 2532b948146SAndy Fiddaman if (port->vsp_enabled) { 2544c87aefeSPatrick Mooney errno = EBUSY; 2554c87aefeSPatrick Mooney return (NULL); 2564c87aefeSPatrick Mooney } 2572b948146SAndy Fiddaman port->vsp_id = port_id; 2584c87aefeSPatrick Mooney port->vsp_sc = sc; 2594c87aefeSPatrick Mooney port->vsp_name = name; 2604c87aefeSPatrick Mooney port->vsp_cb = cb; 2614c87aefeSPatrick Mooney port->vsp_arg = arg; 2624c87aefeSPatrick Mooney 2634c87aefeSPatrick Mooney if (port->vsp_id == 0) { 2644c87aefeSPatrick Mooney /* port0 */ 2654c87aefeSPatrick Mooney port->vsp_txq = 0; 2664c87aefeSPatrick Mooney port->vsp_rxq = 1; 2674c87aefeSPatrick Mooney } else { 2682b948146SAndy Fiddaman port->vsp_txq = (port_id + 1) * 2; 2694c87aefeSPatrick Mooney port->vsp_rxq = port->vsp_txq + 1; 2704c87aefeSPatrick Mooney } 2714c87aefeSPatrick Mooney 2724c87aefeSPatrick Mooney port->vsp_enabled = true; 2734c87aefeSPatrick Mooney return (port); 2744c87aefeSPatrick Mooney } 2754c87aefeSPatrick Mooney 2764c87aefeSPatrick Mooney static int 2772b948146SAndy Fiddaman pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *port_name, 2782b948146SAndy Fiddaman const nvlist_t *nvl) 2794c87aefeSPatrick Mooney { 280*59d65d31SAndy Fiddaman struct pci_vtcon_sock *sock = NULL; 2814c87aefeSPatrick Mooney #ifdef __FreeBSD__ 2824c87aefeSPatrick Mooney struct sockaddr_un sun; 2834c87aefeSPatrick Mooney #else 2844c87aefeSPatrick Mooney /* Our compiler #defines 'sun' as '1'. Awesome. */ 2854c87aefeSPatrick Mooney struct sockaddr_un addr; 2864c87aefeSPatrick Mooney #endif 2872b948146SAndy Fiddaman const char *name, *path; 2882b948146SAndy Fiddaman char *cp, *pathcopy; 2892b948146SAndy Fiddaman long port; 2904c87aefeSPatrick Mooney int s = -1, fd = -1, error = 0; 2914c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 2924c87aefeSPatrick Mooney cap_rights_t rights; 2934c87aefeSPatrick Mooney #endif 2944c87aefeSPatrick Mooney 2952b948146SAndy Fiddaman port = strtol(port_name, &cp, 0); 2962b948146SAndy Fiddaman if (*cp != '\0' || port < 0 || port >= VTCON_MAXPORTS) { 2972b948146SAndy Fiddaman EPRINTLN("vtcon: Invalid port %s", port_name); 2982b948146SAndy Fiddaman error = -1; 2992b948146SAndy Fiddaman goto out; 3002b948146SAndy Fiddaman } 3012b948146SAndy Fiddaman 3022b948146SAndy Fiddaman path = get_config_value_node(nvl, "path"); 3032b948146SAndy Fiddaman if (path == NULL) { 3042b948146SAndy Fiddaman EPRINTLN("vtcon: required path missing for port %ld", port); 3052b948146SAndy Fiddaman error = -1; 3062b948146SAndy Fiddaman goto out; 3072b948146SAndy Fiddaman } 3082b948146SAndy Fiddaman 3094c87aefeSPatrick Mooney sock = calloc(1, sizeof(struct pci_vtcon_sock)); 3104c87aefeSPatrick Mooney if (sock == NULL) { 3114c87aefeSPatrick Mooney error = -1; 3124c87aefeSPatrick Mooney goto out; 3134c87aefeSPatrick Mooney } 3144c87aefeSPatrick Mooney 3154c87aefeSPatrick Mooney s = socket(AF_UNIX, SOCK_STREAM, 0); 3164c87aefeSPatrick Mooney if (s < 0) { 3174c87aefeSPatrick Mooney error = -1; 3184c87aefeSPatrick Mooney goto out; 3194c87aefeSPatrick Mooney } 3204c87aefeSPatrick Mooney 3214c87aefeSPatrick Mooney #ifdef __FreeBSD__ 3224c87aefeSPatrick Mooney pathcopy = strdup(path); 3234c87aefeSPatrick Mooney if (pathcopy == NULL) { 3244c87aefeSPatrick Mooney error = -1; 3254c87aefeSPatrick Mooney goto out; 3264c87aefeSPatrick Mooney } 3274c87aefeSPatrick Mooney 3284c87aefeSPatrick Mooney fd = open(dirname(pathcopy), O_RDONLY | O_DIRECTORY); 3294c87aefeSPatrick Mooney if (fd < 0) { 3304c87aefeSPatrick Mooney free(pathcopy); 3314c87aefeSPatrick Mooney error = -1; 3324c87aefeSPatrick Mooney goto out; 3334c87aefeSPatrick Mooney } 3344c87aefeSPatrick Mooney 3354c87aefeSPatrick Mooney sun.sun_family = AF_UNIX; 3364c87aefeSPatrick Mooney sun.sun_len = sizeof(struct sockaddr_un); 3374c87aefeSPatrick Mooney strcpy(pathcopy, path); 3384c87aefeSPatrick Mooney strlcpy(sun.sun_path, basename(pathcopy), sizeof(sun.sun_path)); 3394c87aefeSPatrick Mooney free(pathcopy); 3404c87aefeSPatrick Mooney 3414c87aefeSPatrick Mooney if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0) { 3424c87aefeSPatrick Mooney error = -1; 3434c87aefeSPatrick Mooney goto out; 3444c87aefeSPatrick Mooney } 3454c87aefeSPatrick Mooney #else /* __FreeBSD__ */ 3464c87aefeSPatrick Mooney /* Do a simple bind rather than the FreeBSD bindat() */ 3472b948146SAndy Fiddaman pathcopy = (char *)path; 3484c87aefeSPatrick Mooney addr.sun_family = AF_UNIX; 3492b948146SAndy Fiddaman (void) strlcpy(addr.sun_path, pathcopy, sizeof (addr.sun_path)); 3504c87aefeSPatrick Mooney if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { 3514c87aefeSPatrick Mooney error = -1; 3524c87aefeSPatrick Mooney goto out; 3534c87aefeSPatrick Mooney } 3544c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 3554c87aefeSPatrick Mooney 3564c87aefeSPatrick Mooney if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { 3574c87aefeSPatrick Mooney error = -1; 3584c87aefeSPatrick Mooney goto out; 3594c87aefeSPatrick Mooney } 3604c87aefeSPatrick Mooney 3614c87aefeSPatrick Mooney if (listen(s, 1) < 0) { 3624c87aefeSPatrick Mooney error = -1; 3634c87aefeSPatrick Mooney goto out; 3644c87aefeSPatrick Mooney } 3654c87aefeSPatrick Mooney 3664c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 3674c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE); 3684c87aefeSPatrick Mooney if (caph_rights_limit(s, &rights) == -1) 3694c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 3704c87aefeSPatrick Mooney #endif 3714c87aefeSPatrick Mooney 3722b948146SAndy Fiddaman name = get_config_value_node(nvl, "name"); 3732b948146SAndy Fiddaman if (name == NULL) { 3742b948146SAndy Fiddaman EPRINTLN("vtcon: required name missing for port %ld", port); 3752b948146SAndy Fiddaman error = -1; 3762b948146SAndy Fiddaman goto out; 3772b948146SAndy Fiddaman } 3782b948146SAndy Fiddaman sock->vss_port = pci_vtcon_port_add(sc, port, name, pci_vtcon_sock_tx, sock); 3794c87aefeSPatrick Mooney if (sock->vss_port == NULL) { 3804c87aefeSPatrick Mooney error = -1; 3814c87aefeSPatrick Mooney goto out; 3824c87aefeSPatrick Mooney } 3834c87aefeSPatrick Mooney 3844c87aefeSPatrick Mooney sock->vss_open = false; 3854c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 3864c87aefeSPatrick Mooney sock->vss_server_fd = s; 3874c87aefeSPatrick Mooney sock->vss_server_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_accept, 3884c87aefeSPatrick Mooney sock); 3894c87aefeSPatrick Mooney 3904c87aefeSPatrick Mooney if (sock->vss_server_evp == NULL) { 3914c87aefeSPatrick Mooney error = -1; 3924c87aefeSPatrick Mooney goto out; 3934c87aefeSPatrick Mooney } 3944c87aefeSPatrick Mooney 3954c87aefeSPatrick Mooney out: 3964c87aefeSPatrick Mooney if (fd != -1) 3974c87aefeSPatrick Mooney close(fd); 3984c87aefeSPatrick Mooney 39984659b24SMichael Zeller if (error != 0) { 40084659b24SMichael Zeller if (s != -1) 4014c87aefeSPatrick Mooney close(s); 40284659b24SMichael Zeller free(sock); 40384659b24SMichael Zeller } 4044c87aefeSPatrick Mooney 4054c87aefeSPatrick Mooney return (error); 4064c87aefeSPatrick Mooney } 4074c87aefeSPatrick Mooney 4084c87aefeSPatrick Mooney static void 4094c87aefeSPatrick Mooney pci_vtcon_sock_accept(int fd __unused, enum ev_type t __unused, void *arg) 4104c87aefeSPatrick Mooney { 4114c87aefeSPatrick Mooney struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg; 4124c87aefeSPatrick Mooney int s; 4134c87aefeSPatrick Mooney 4144c87aefeSPatrick Mooney s = accept(sock->vss_server_fd, NULL, NULL); 4154c87aefeSPatrick Mooney if (s < 0) 4164c87aefeSPatrick Mooney return; 4174c87aefeSPatrick Mooney 4184c87aefeSPatrick Mooney if (sock->vss_open) { 4194c87aefeSPatrick Mooney close(s); 4204c87aefeSPatrick Mooney return; 4214c87aefeSPatrick Mooney } 4224c87aefeSPatrick Mooney 4234c87aefeSPatrick Mooney sock->vss_open = true; 4244c87aefeSPatrick Mooney sock->vss_conn_fd = s; 4254c87aefeSPatrick Mooney sock->vss_conn_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_rx, sock); 4264c87aefeSPatrick Mooney 4274c87aefeSPatrick Mooney pci_vtcon_open_port(sock->vss_port, true); 4284c87aefeSPatrick Mooney } 4294c87aefeSPatrick Mooney 4304c87aefeSPatrick Mooney static void 4314c87aefeSPatrick Mooney pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg) 4324c87aefeSPatrick Mooney { 4334c87aefeSPatrick Mooney struct pci_vtcon_port *port; 4344c87aefeSPatrick Mooney struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg; 4354c87aefeSPatrick Mooney struct vqueue_info *vq; 436b0de25cbSAndy Fiddaman struct vi_req req; 4374c87aefeSPatrick Mooney struct iovec iov; 4384c87aefeSPatrick Mooney static char dummybuf[2048]; 4394c87aefeSPatrick Mooney int len, n; 4404c87aefeSPatrick Mooney 4414c87aefeSPatrick Mooney port = sock->vss_port; 4424c87aefeSPatrick Mooney vq = pci_vtcon_port_to_vq(port, true); 4434c87aefeSPatrick Mooney 4444c87aefeSPatrick Mooney if (!sock->vss_open || !port->vsp_rx_ready) { 4454c87aefeSPatrick Mooney len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf)); 4464c87aefeSPatrick Mooney if (len == 0) 4474c87aefeSPatrick Mooney goto close; 4484c87aefeSPatrick Mooney 4494c87aefeSPatrick Mooney return; 4504c87aefeSPatrick Mooney } 4514c87aefeSPatrick Mooney 4524c87aefeSPatrick Mooney if (!vq_has_descs(vq)) { 4534c87aefeSPatrick Mooney len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf)); 4544c87aefeSPatrick Mooney vq_endchains(vq, 1); 4554c87aefeSPatrick Mooney if (len == 0) 4564c87aefeSPatrick Mooney goto close; 4574c87aefeSPatrick Mooney 4584c87aefeSPatrick Mooney return; 4594c87aefeSPatrick Mooney } 4604c87aefeSPatrick Mooney 4614c87aefeSPatrick Mooney do { 462b0de25cbSAndy Fiddaman n = vq_getchain(vq, &iov, 1, &req); 463b0de25cbSAndy Fiddaman assert(n == 1); 4644c87aefeSPatrick Mooney len = readv(sock->vss_conn_fd, &iov, n); 4654c87aefeSPatrick Mooney 4664c87aefeSPatrick Mooney if (len == 0 || (len < 0 && errno == EWOULDBLOCK)) { 467154972afSPatrick Mooney vq_retchains(vq, 1); 4684c87aefeSPatrick Mooney vq_endchains(vq, 0); 4694c87aefeSPatrick Mooney if (len == 0) 4704c87aefeSPatrick Mooney goto close; 4714c87aefeSPatrick Mooney 4724c87aefeSPatrick Mooney return; 4734c87aefeSPatrick Mooney } 4744c87aefeSPatrick Mooney 475b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, len); 4764c87aefeSPatrick Mooney } while (vq_has_descs(vq)); 4774c87aefeSPatrick Mooney 4784c87aefeSPatrick Mooney vq_endchains(vq, 1); 4794c87aefeSPatrick Mooney 4804c87aefeSPatrick Mooney close: 4814c87aefeSPatrick Mooney mevent_delete_close(sock->vss_conn_evp); 4824c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 4834c87aefeSPatrick Mooney sock->vss_open = false; 4844c87aefeSPatrick Mooney } 4854c87aefeSPatrick Mooney 4864c87aefeSPatrick Mooney static void 487*59d65d31SAndy Fiddaman pci_vtcon_sock_tx(struct pci_vtcon_port *port __unused, void *arg __unused, 488*59d65d31SAndy Fiddaman struct iovec *iov, int niov) 4894c87aefeSPatrick Mooney { 4904c87aefeSPatrick Mooney struct pci_vtcon_sock *sock; 4914c87aefeSPatrick Mooney int i, ret; 4922b948146SAndy Fiddaman 4932b948146SAndy Fiddaman #ifndef __FreeBSD__ 4942b948146SAndy Fiddaman ret = 0; 4954c87aefeSPatrick Mooney #endif 4964c87aefeSPatrick Mooney 4974c87aefeSPatrick Mooney sock = (struct pci_vtcon_sock *)arg; 4984c87aefeSPatrick Mooney 4994c87aefeSPatrick Mooney if (sock->vss_conn_fd == -1) 5004c87aefeSPatrick Mooney return; 5014c87aefeSPatrick Mooney 5024c87aefeSPatrick Mooney for (i = 0; i < niov; i++) { 5034c87aefeSPatrick Mooney ret = stream_write(sock->vss_conn_fd, iov[i].iov_base, 5044c87aefeSPatrick Mooney iov[i].iov_len); 5054c87aefeSPatrick Mooney if (ret <= 0) 5064c87aefeSPatrick Mooney break; 5074c87aefeSPatrick Mooney } 5084c87aefeSPatrick Mooney 5094c87aefeSPatrick Mooney if (ret <= 0) { 5104c87aefeSPatrick Mooney mevent_delete_close(sock->vss_conn_evp); 5114c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 5124c87aefeSPatrick Mooney sock->vss_open = false; 5134c87aefeSPatrick Mooney } 5144c87aefeSPatrick Mooney } 5154c87aefeSPatrick Mooney 5164c87aefeSPatrick Mooney static void 517*59d65d31SAndy Fiddaman pci_vtcon_control_tx(struct pci_vtcon_port *port, void *arg __unused, 518*59d65d31SAndy Fiddaman struct iovec *iov, int niov) 5194c87aefeSPatrick Mooney { 5204c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 5214c87aefeSPatrick Mooney struct pci_vtcon_port *tmp; 5224c87aefeSPatrick Mooney struct pci_vtcon_control resp, *ctrl; 5234c87aefeSPatrick Mooney int i; 5244c87aefeSPatrick Mooney 5254c87aefeSPatrick Mooney assert(niov == 1); 5264c87aefeSPatrick Mooney 5274c87aefeSPatrick Mooney sc = port->vsp_sc; 5284c87aefeSPatrick Mooney ctrl = (struct pci_vtcon_control *)iov->iov_base; 5294c87aefeSPatrick Mooney 5304c87aefeSPatrick Mooney switch (ctrl->event) { 5314c87aefeSPatrick Mooney case VTCON_DEVICE_READY: 5324c87aefeSPatrick Mooney sc->vsc_ready = true; 5334c87aefeSPatrick Mooney /* set port ready events for registered ports */ 5344c87aefeSPatrick Mooney for (i = 0; i < VTCON_MAXPORTS; i++) { 5354c87aefeSPatrick Mooney tmp = &sc->vsc_ports[i]; 5364c87aefeSPatrick Mooney if (tmp->vsp_enabled) 5374c87aefeSPatrick Mooney pci_vtcon_announce_port(tmp); 5384c87aefeSPatrick Mooney 5394c87aefeSPatrick Mooney if (tmp->vsp_open) 5404c87aefeSPatrick Mooney pci_vtcon_open_port(tmp, true); 5414c87aefeSPatrick Mooney } 5424c87aefeSPatrick Mooney break; 5434c87aefeSPatrick Mooney 5444c87aefeSPatrick Mooney case VTCON_PORT_READY: 5452b948146SAndy Fiddaman tmp = &sc->vsc_ports[ctrl->id]; 5462b948146SAndy Fiddaman if (ctrl->id >= VTCON_MAXPORTS || !tmp->vsp_enabled) { 547154972afSPatrick Mooney WPRINTF(("VTCON_PORT_READY event for unknown port %d", 5484c87aefeSPatrick Mooney ctrl->id)); 5494c87aefeSPatrick Mooney return; 5504c87aefeSPatrick Mooney } 5514c87aefeSPatrick Mooney 5524c87aefeSPatrick Mooney if (tmp->vsp_console) { 5534c87aefeSPatrick Mooney resp.event = VTCON_CONSOLE_PORT; 5544c87aefeSPatrick Mooney resp.id = ctrl->id; 5554c87aefeSPatrick Mooney resp.value = 1; 5564c87aefeSPatrick Mooney pci_vtcon_control_send(sc, &resp, NULL, 0); 5574c87aefeSPatrick Mooney } 5584c87aefeSPatrick Mooney break; 5594c87aefeSPatrick Mooney } 5604c87aefeSPatrick Mooney } 5614c87aefeSPatrick Mooney 5624c87aefeSPatrick Mooney static void 5634c87aefeSPatrick Mooney pci_vtcon_announce_port(struct pci_vtcon_port *port) 5644c87aefeSPatrick Mooney { 5654c87aefeSPatrick Mooney struct pci_vtcon_control event; 5664c87aefeSPatrick Mooney 5674c87aefeSPatrick Mooney event.id = port->vsp_id; 5684c87aefeSPatrick Mooney event.event = VTCON_DEVICE_ADD; 5694c87aefeSPatrick Mooney event.value = 1; 5704c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0); 5714c87aefeSPatrick Mooney 5724c87aefeSPatrick Mooney event.event = VTCON_PORT_NAME; 5734c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, port->vsp_name, 5744c87aefeSPatrick Mooney strlen(port->vsp_name)); 5754c87aefeSPatrick Mooney } 5764c87aefeSPatrick Mooney 5774c87aefeSPatrick Mooney static void 5784c87aefeSPatrick Mooney pci_vtcon_open_port(struct pci_vtcon_port *port, bool open) 5794c87aefeSPatrick Mooney { 5804c87aefeSPatrick Mooney struct pci_vtcon_control event; 5814c87aefeSPatrick Mooney 5824c87aefeSPatrick Mooney if (!port->vsp_sc->vsc_ready) { 5834c87aefeSPatrick Mooney port->vsp_open = true; 5844c87aefeSPatrick Mooney return; 5854c87aefeSPatrick Mooney } 5864c87aefeSPatrick Mooney 5874c87aefeSPatrick Mooney event.id = port->vsp_id; 5884c87aefeSPatrick Mooney event.event = VTCON_PORT_OPEN; 5894c87aefeSPatrick Mooney event.value = (int)open; 5904c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0); 5914c87aefeSPatrick Mooney } 5924c87aefeSPatrick Mooney 5934c87aefeSPatrick Mooney static void 5944c87aefeSPatrick Mooney pci_vtcon_control_send(struct pci_vtcon_softc *sc, 5954c87aefeSPatrick Mooney struct pci_vtcon_control *ctrl, const void *payload, size_t len) 5964c87aefeSPatrick Mooney { 5974c87aefeSPatrick Mooney struct vqueue_info *vq; 598b0de25cbSAndy Fiddaman struct vi_req req; 5994c87aefeSPatrick Mooney struct iovec iov; 6004c87aefeSPatrick Mooney int n; 6014c87aefeSPatrick Mooney 6024c87aefeSPatrick Mooney vq = pci_vtcon_port_to_vq(&sc->vsc_control_port, true); 6034c87aefeSPatrick Mooney 6044c87aefeSPatrick Mooney if (!vq_has_descs(vq)) 6054c87aefeSPatrick Mooney return; 6064c87aefeSPatrick Mooney 607b0de25cbSAndy Fiddaman n = vq_getchain(vq, &iov, 1, &req); 6084c87aefeSPatrick Mooney assert(n == 1); 6094c87aefeSPatrick Mooney 6104c87aefeSPatrick Mooney memcpy(iov.iov_base, ctrl, sizeof(struct pci_vtcon_control)); 6114c87aefeSPatrick Mooney if (payload != NULL && len > 0) 612*59d65d31SAndy Fiddaman memcpy((uint8_t *)iov.iov_base + 613*59d65d31SAndy Fiddaman sizeof(struct pci_vtcon_control), payload, len); 6144c87aefeSPatrick Mooney 615b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, sizeof(struct pci_vtcon_control) + len); 6164c87aefeSPatrick Mooney vq_endchains(vq, 1); 6174c87aefeSPatrick Mooney } 6184c87aefeSPatrick Mooney 6194c87aefeSPatrick Mooney 6204c87aefeSPatrick Mooney static void 6214c87aefeSPatrick Mooney pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq) 6224c87aefeSPatrick Mooney { 6234c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 6244c87aefeSPatrick Mooney struct pci_vtcon_port *port; 6254c87aefeSPatrick Mooney struct iovec iov[1]; 626b0de25cbSAndy Fiddaman struct vi_req req; 627b0de25cbSAndy Fiddaman int n; 6284c87aefeSPatrick Mooney 6294c87aefeSPatrick Mooney sc = vsc; 6304c87aefeSPatrick Mooney port = pci_vtcon_vq_to_port(sc, vq); 6314c87aefeSPatrick Mooney 6324c87aefeSPatrick Mooney while (vq_has_descs(vq)) { 633b0de25cbSAndy Fiddaman n = vq_getchain(vq, iov, 1, &req); 634b0de25cbSAndy Fiddaman assert(n == 1); 6354c87aefeSPatrick Mooney if (port != NULL) 6364c87aefeSPatrick Mooney port->vsp_cb(port, port->vsp_arg, iov, 1); 6374c87aefeSPatrick Mooney 6384c87aefeSPatrick Mooney /* 6394c87aefeSPatrick Mooney * Release this chain and handle more 6404c87aefeSPatrick Mooney */ 641b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, 0); 6424c87aefeSPatrick Mooney } 6434c87aefeSPatrick Mooney vq_endchains(vq, 1); /* Generate interrupt if appropriate. */ 6444c87aefeSPatrick Mooney } 6454c87aefeSPatrick Mooney 6464c87aefeSPatrick Mooney static void 6474c87aefeSPatrick Mooney pci_vtcon_notify_rx(void *vsc, struct vqueue_info *vq) 6484c87aefeSPatrick Mooney { 6494c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 6504c87aefeSPatrick Mooney struct pci_vtcon_port *port; 6514c87aefeSPatrick Mooney 6524c87aefeSPatrick Mooney sc = vsc; 6534c87aefeSPatrick Mooney port = pci_vtcon_vq_to_port(sc, vq); 6544c87aefeSPatrick Mooney 6554c87aefeSPatrick Mooney if (!port->vsp_rx_ready) { 6564c87aefeSPatrick Mooney port->vsp_rx_ready = 1; 65784659b24SMichael Zeller vq_kick_disable(vq); 6584c87aefeSPatrick Mooney } 6594c87aefeSPatrick Mooney } 6604c87aefeSPatrick Mooney 6612b948146SAndy Fiddaman /* 6622b948146SAndy Fiddaman * Each console device has a "port" node which contains nodes for 6632b948146SAndy Fiddaman * each port. Ports are numbered starting at 0. 6642b948146SAndy Fiddaman */ 6654c87aefeSPatrick Mooney static int 6662b948146SAndy Fiddaman pci_vtcon_legacy_config_port(nvlist_t *nvl, int port, char *opt) 6672b948146SAndy Fiddaman { 6682b948146SAndy Fiddaman char *name, *path; 6692b948146SAndy Fiddaman char node_name[sizeof("XX")]; 6702b948146SAndy Fiddaman nvlist_t *port_nvl; 6712b948146SAndy Fiddaman 6722b948146SAndy Fiddaman name = strsep(&opt, "="); 6732b948146SAndy Fiddaman path = opt; 6742b948146SAndy Fiddaman if (path == NULL) { 6752b948146SAndy Fiddaman EPRINTLN("vtcon: port %s requires a path", name); 6762b948146SAndy Fiddaman return (-1); 6772b948146SAndy Fiddaman } 6782b948146SAndy Fiddaman if (port >= VTCON_MAXPORTS) { 6792b948146SAndy Fiddaman EPRINTLN("vtcon: too many ports"); 6802b948146SAndy Fiddaman return (-1); 6812b948146SAndy Fiddaman } 6822b948146SAndy Fiddaman snprintf(node_name, sizeof(node_name), "%d", port); 6832b948146SAndy Fiddaman port_nvl = create_relative_config_node(nvl, node_name); 6842b948146SAndy Fiddaman set_config_value_node(port_nvl, "name", name); 6852b948146SAndy Fiddaman set_config_value_node(port_nvl, "path", path); 6862b948146SAndy Fiddaman return (0); 6872b948146SAndy Fiddaman } 6882b948146SAndy Fiddaman 6892b948146SAndy Fiddaman static int 6902b948146SAndy Fiddaman pci_vtcon_legacy_config(nvlist_t *nvl, const char *opts) 6912b948146SAndy Fiddaman { 6922b948146SAndy Fiddaman char *opt, *str, *tofree; 6932b948146SAndy Fiddaman nvlist_t *ports_nvl; 6942b948146SAndy Fiddaman int error, port; 6952b948146SAndy Fiddaman 6962b948146SAndy Fiddaman ports_nvl = create_relative_config_node(nvl, "port"); 6972b948146SAndy Fiddaman tofree = str = strdup(opts); 6982b948146SAndy Fiddaman error = 0; 6992b948146SAndy Fiddaman port = 0; 7002b948146SAndy Fiddaman while ((opt = strsep(&str, ",")) != NULL) { 7012b948146SAndy Fiddaman error = pci_vtcon_legacy_config_port(ports_nvl, port, opt); 7022b948146SAndy Fiddaman if (error) 7032b948146SAndy Fiddaman break; 7042b948146SAndy Fiddaman port++; 7052b948146SAndy Fiddaman } 7062b948146SAndy Fiddaman free(tofree); 7072b948146SAndy Fiddaman return (error); 7082b948146SAndy Fiddaman } 7092b948146SAndy Fiddaman 7102b948146SAndy Fiddaman static int 711*59d65d31SAndy Fiddaman pci_vtcon_init(struct vmctx *ctx __unused, struct pci_devinst *pi, 712*59d65d31SAndy Fiddaman nvlist_t *nvl) 7134c87aefeSPatrick Mooney { 7144c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 7152b948146SAndy Fiddaman nvlist_t *ports_nvl; 7164c87aefeSPatrick Mooney int i; 7174c87aefeSPatrick Mooney 7184c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct pci_vtcon_softc)); 7194c87aefeSPatrick Mooney sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config)); 7204c87aefeSPatrick Mooney sc->vsc_config->max_nr_ports = VTCON_MAXPORTS; 7214c87aefeSPatrick Mooney sc->vsc_config->cols = 80; 7224c87aefeSPatrick Mooney sc->vsc_config->rows = 25; 7234c87aefeSPatrick Mooney 7247bb0eb34SAndy Fiddaman pthread_mutex_init(&sc->vsc_mtx, NULL); 7257bb0eb34SAndy Fiddaman 7264c87aefeSPatrick Mooney vi_softc_linkup(&sc->vsc_vs, &vtcon_vi_consts, sc, pi, sc->vsc_queues); 7274c87aefeSPatrick Mooney sc->vsc_vs.vs_mtx = &sc->vsc_mtx; 7284c87aefeSPatrick Mooney 7294c87aefeSPatrick Mooney for (i = 0; i < VTCON_MAXQ; i++) { 7304c87aefeSPatrick Mooney sc->vsc_queues[i].vq_qsize = VTCON_RINGSZ; 7314c87aefeSPatrick Mooney sc->vsc_queues[i].vq_notify = i % 2 == 0 7324c87aefeSPatrick Mooney ? pci_vtcon_notify_rx 7334c87aefeSPatrick Mooney : pci_vtcon_notify_tx; 7344c87aefeSPatrick Mooney } 7354c87aefeSPatrick Mooney 7364c87aefeSPatrick Mooney /* initialize config space */ 7374c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_CONSOLE); 7384c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 7394c87aefeSPatrick Mooney pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM); 7402b948146SAndy Fiddaman pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_CONSOLE); 7414c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); 7424c87aefeSPatrick Mooney 7434c87aefeSPatrick Mooney if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) 7444c87aefeSPatrick Mooney return (1); 7454c87aefeSPatrick Mooney vi_set_io_bar(&sc->vsc_vs, 0); 7464c87aefeSPatrick Mooney 7474c87aefeSPatrick Mooney /* create control port */ 7484c87aefeSPatrick Mooney sc->vsc_control_port.vsp_sc = sc; 7494c87aefeSPatrick Mooney sc->vsc_control_port.vsp_txq = 2; 7504c87aefeSPatrick Mooney sc->vsc_control_port.vsp_rxq = 3; 7514c87aefeSPatrick Mooney sc->vsc_control_port.vsp_cb = pci_vtcon_control_tx; 7524c87aefeSPatrick Mooney sc->vsc_control_port.vsp_enabled = true; 7534c87aefeSPatrick Mooney 7542b948146SAndy Fiddaman ports_nvl = find_relative_config_node(nvl, "port"); 7552b948146SAndy Fiddaman if (ports_nvl != NULL) { 7562b948146SAndy Fiddaman const char *name; 7572b948146SAndy Fiddaman void *cookie; 7582b948146SAndy Fiddaman int type; 7594c87aefeSPatrick Mooney 7602b948146SAndy Fiddaman cookie = NULL; 7612b948146SAndy Fiddaman while ((name = nvlist_next(ports_nvl, &type, &cookie)) != 7622b948146SAndy Fiddaman NULL) { 7632b948146SAndy Fiddaman if (type != NV_TYPE_NVLIST) 7642b948146SAndy Fiddaman continue; 7652b948146SAndy Fiddaman 7662b948146SAndy Fiddaman if (pci_vtcon_sock_add(sc, name, 7672b948146SAndy Fiddaman nvlist_get_nvlist(ports_nvl, name)) < 0) { 768154972afSPatrick Mooney EPRINTLN("cannot create port %s: %s", 7692b948146SAndy Fiddaman name, strerror(errno)); 7704c87aefeSPatrick Mooney return (1); 7714c87aefeSPatrick Mooney } 7724c87aefeSPatrick Mooney } 7732b948146SAndy Fiddaman } 7744c87aefeSPatrick Mooney 7754c87aefeSPatrick Mooney return (0); 7764c87aefeSPatrick Mooney } 7774c87aefeSPatrick Mooney 7784f3f3e9aSAndy Fiddaman static const struct pci_devemu pci_de_vcon = { 7794c87aefeSPatrick Mooney .pe_emu = "virtio-console", 7804c87aefeSPatrick Mooney .pe_init = pci_vtcon_init, 7814c87aefeSPatrick Mooney .pe_barwrite = vi_pci_write, 7824f3f3e9aSAndy Fiddaman .pe_barread = vi_pci_read, 7834f3f3e9aSAndy Fiddaman .pe_legacy_config = pci_vtcon_legacy_config, 7844c87aefeSPatrick Mooney }; 7854c87aefeSPatrick Mooney PCI_EMUL_SET(pci_de_vcon); 786