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" 67*154972afSPatrick Mooney #include "debug.h" 684c87aefeSPatrick Mooney #include "pci_emul.h" 694c87aefeSPatrick Mooney #include "virtio.h" 704c87aefeSPatrick Mooney #include "mevent.h" 714c87aefeSPatrick Mooney #include "sockstream.h" 724c87aefeSPatrick Mooney 734c87aefeSPatrick Mooney #define VTCON_RINGSZ 64 744c87aefeSPatrick Mooney #define VTCON_MAXPORTS 16 754c87aefeSPatrick Mooney #define VTCON_MAXQ (VTCON_MAXPORTS * 2 + 2) 764c87aefeSPatrick Mooney 774c87aefeSPatrick Mooney #define VTCON_DEVICE_READY 0 784c87aefeSPatrick Mooney #define VTCON_DEVICE_ADD 1 794c87aefeSPatrick Mooney #define VTCON_DEVICE_REMOVE 2 804c87aefeSPatrick Mooney #define VTCON_PORT_READY 3 814c87aefeSPatrick Mooney #define VTCON_CONSOLE_PORT 4 824c87aefeSPatrick Mooney #define VTCON_CONSOLE_RESIZE 5 834c87aefeSPatrick Mooney #define VTCON_PORT_OPEN 6 844c87aefeSPatrick Mooney #define VTCON_PORT_NAME 7 854c87aefeSPatrick Mooney 864c87aefeSPatrick Mooney #define VTCON_F_SIZE 0 874c87aefeSPatrick Mooney #define VTCON_F_MULTIPORT 1 884c87aefeSPatrick Mooney #define VTCON_F_EMERG_WRITE 2 894c87aefeSPatrick Mooney #define VTCON_S_HOSTCAPS \ 904c87aefeSPatrick Mooney (VTCON_F_SIZE | VTCON_F_MULTIPORT | VTCON_F_EMERG_WRITE) 914c87aefeSPatrick Mooney 924c87aefeSPatrick Mooney static int pci_vtcon_debug; 93*154972afSPatrick Mooney #define DPRINTF(params) if (pci_vtcon_debug) PRINTLN params 94*154972afSPatrick Mooney #define WPRINTF(params) PRINTLN params 954c87aefeSPatrick Mooney 964c87aefeSPatrick Mooney struct pci_vtcon_softc; 974c87aefeSPatrick Mooney struct pci_vtcon_port; 984c87aefeSPatrick Mooney struct pci_vtcon_config; 994c87aefeSPatrick Mooney typedef void (pci_vtcon_cb_t)(struct pci_vtcon_port *, void *, struct iovec *, 1004c87aefeSPatrick Mooney int); 1014c87aefeSPatrick Mooney 1024c87aefeSPatrick Mooney struct pci_vtcon_port { 1034c87aefeSPatrick Mooney struct pci_vtcon_softc * vsp_sc; 1044c87aefeSPatrick Mooney int vsp_id; 1054c87aefeSPatrick Mooney const char * vsp_name; 1064c87aefeSPatrick Mooney bool vsp_enabled; 1074c87aefeSPatrick Mooney bool vsp_console; 1084c87aefeSPatrick Mooney bool vsp_rx_ready; 1094c87aefeSPatrick Mooney bool vsp_open; 1104c87aefeSPatrick Mooney int vsp_rxq; 1114c87aefeSPatrick Mooney int vsp_txq; 1124c87aefeSPatrick Mooney void * vsp_arg; 1134c87aefeSPatrick Mooney pci_vtcon_cb_t * vsp_cb; 1144c87aefeSPatrick Mooney }; 1154c87aefeSPatrick Mooney 1164c87aefeSPatrick Mooney struct pci_vtcon_sock 1174c87aefeSPatrick Mooney { 1184c87aefeSPatrick Mooney struct pci_vtcon_port * vss_port; 1194c87aefeSPatrick Mooney const char * vss_path; 1204c87aefeSPatrick Mooney struct mevent * vss_server_evp; 1214c87aefeSPatrick Mooney struct mevent * vss_conn_evp; 1224c87aefeSPatrick Mooney int vss_server_fd; 1234c87aefeSPatrick Mooney int vss_conn_fd; 1244c87aefeSPatrick Mooney bool vss_open; 1254c87aefeSPatrick Mooney }; 1264c87aefeSPatrick Mooney 1274c87aefeSPatrick Mooney struct pci_vtcon_softc { 1284c87aefeSPatrick Mooney struct virtio_softc vsc_vs; 1294c87aefeSPatrick Mooney struct vqueue_info vsc_queues[VTCON_MAXQ]; 1304c87aefeSPatrick Mooney pthread_mutex_t vsc_mtx; 1314c87aefeSPatrick Mooney uint64_t vsc_cfg; 1324c87aefeSPatrick Mooney uint64_t vsc_features; 1334c87aefeSPatrick Mooney char * vsc_rootdir; 1344c87aefeSPatrick Mooney int vsc_kq; 1354c87aefeSPatrick Mooney int vsc_nports; 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 195*154972afSPatrick 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 * 2494c87aefeSPatrick Mooney pci_vtcon_port_add(struct pci_vtcon_softc *sc, const char *name, 2504c87aefeSPatrick Mooney pci_vtcon_cb_t *cb, void *arg) 2514c87aefeSPatrick Mooney { 2524c87aefeSPatrick Mooney struct pci_vtcon_port *port; 2534c87aefeSPatrick Mooney 2544c87aefeSPatrick Mooney if (sc->vsc_nports == VTCON_MAXPORTS) { 2554c87aefeSPatrick Mooney errno = EBUSY; 2564c87aefeSPatrick Mooney return (NULL); 2574c87aefeSPatrick Mooney } 2584c87aefeSPatrick Mooney 2594c87aefeSPatrick Mooney port = &sc->vsc_ports[sc->vsc_nports++]; 2604c87aefeSPatrick Mooney port->vsp_id = sc->vsc_nports - 1; 2614c87aefeSPatrick Mooney port->vsp_sc = sc; 2624c87aefeSPatrick Mooney port->vsp_name = name; 2634c87aefeSPatrick Mooney port->vsp_cb = cb; 2644c87aefeSPatrick Mooney port->vsp_arg = arg; 2654c87aefeSPatrick Mooney 2664c87aefeSPatrick Mooney if (port->vsp_id == 0) { 2674c87aefeSPatrick Mooney /* port0 */ 2684c87aefeSPatrick Mooney port->vsp_txq = 0; 2694c87aefeSPatrick Mooney port->vsp_rxq = 1; 2704c87aefeSPatrick Mooney } else { 2714c87aefeSPatrick Mooney port->vsp_txq = sc->vsc_nports * 2; 2724c87aefeSPatrick Mooney port->vsp_rxq = port->vsp_txq + 1; 2734c87aefeSPatrick Mooney } 2744c87aefeSPatrick Mooney 2754c87aefeSPatrick Mooney port->vsp_enabled = true; 2764c87aefeSPatrick Mooney return (port); 2774c87aefeSPatrick Mooney } 2784c87aefeSPatrick Mooney 2794c87aefeSPatrick Mooney static int 2804c87aefeSPatrick Mooney pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *name, 2814c87aefeSPatrick Mooney const char *path) 2824c87aefeSPatrick Mooney { 2834c87aefeSPatrick Mooney struct pci_vtcon_sock *sock; 2844c87aefeSPatrick Mooney #ifdef __FreeBSD__ 2854c87aefeSPatrick Mooney struct sockaddr_un sun; 2864c87aefeSPatrick Mooney char *pathcopy; 2874c87aefeSPatrick Mooney #else 2884c87aefeSPatrick Mooney /* Our compiler #defines 'sun' as '1'. Awesome. */ 2894c87aefeSPatrick Mooney struct sockaddr_un addr; 2904c87aefeSPatrick Mooney #endif 2914c87aefeSPatrick Mooney int s = -1, fd = -1, error = 0; 2924c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 2934c87aefeSPatrick Mooney cap_rights_t rights; 2944c87aefeSPatrick Mooney #endif 2954c87aefeSPatrick Mooney 2964c87aefeSPatrick Mooney sock = calloc(1, sizeof(struct pci_vtcon_sock)); 2974c87aefeSPatrick Mooney if (sock == NULL) { 2984c87aefeSPatrick Mooney error = -1; 2994c87aefeSPatrick Mooney goto out; 3004c87aefeSPatrick Mooney } 3014c87aefeSPatrick Mooney 3024c87aefeSPatrick Mooney s = socket(AF_UNIX, SOCK_STREAM, 0); 3034c87aefeSPatrick Mooney if (s < 0) { 3044c87aefeSPatrick Mooney error = -1; 3054c87aefeSPatrick Mooney goto out; 3064c87aefeSPatrick Mooney } 3074c87aefeSPatrick Mooney 3084c87aefeSPatrick Mooney #ifdef __FreeBSD__ 3094c87aefeSPatrick Mooney pathcopy = strdup(path); 3104c87aefeSPatrick Mooney if (pathcopy == NULL) { 3114c87aefeSPatrick Mooney error = -1; 3124c87aefeSPatrick Mooney goto out; 3134c87aefeSPatrick Mooney } 3144c87aefeSPatrick Mooney 3154c87aefeSPatrick Mooney fd = open(dirname(pathcopy), O_RDONLY | O_DIRECTORY); 3164c87aefeSPatrick Mooney if (fd < 0) { 3174c87aefeSPatrick Mooney free(pathcopy); 3184c87aefeSPatrick Mooney error = -1; 3194c87aefeSPatrick Mooney goto out; 3204c87aefeSPatrick Mooney } 3214c87aefeSPatrick Mooney 3224c87aefeSPatrick Mooney sun.sun_family = AF_UNIX; 3234c87aefeSPatrick Mooney sun.sun_len = sizeof(struct sockaddr_un); 3244c87aefeSPatrick Mooney strcpy(pathcopy, path); 3254c87aefeSPatrick Mooney strlcpy(sun.sun_path, basename(pathcopy), sizeof(sun.sun_path)); 3264c87aefeSPatrick Mooney free(pathcopy); 3274c87aefeSPatrick Mooney 3284c87aefeSPatrick Mooney if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0) { 3294c87aefeSPatrick Mooney error = -1; 3304c87aefeSPatrick Mooney goto out; 3314c87aefeSPatrick Mooney } 3324c87aefeSPatrick Mooney #else /* __FreeBSD__ */ 3334c87aefeSPatrick Mooney /* Do a simple bind rather than the FreeBSD bindat() */ 3344c87aefeSPatrick Mooney addr.sun_family = AF_UNIX; 3354c87aefeSPatrick Mooney (void) strlcpy(addr.sun_path, path, sizeof (addr.sun_path)); 3364c87aefeSPatrick Mooney if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { 3374c87aefeSPatrick Mooney error = -1; 3384c87aefeSPatrick Mooney goto out; 3394c87aefeSPatrick Mooney } 3404c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 3414c87aefeSPatrick Mooney 3424c87aefeSPatrick Mooney if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { 3434c87aefeSPatrick Mooney error = -1; 3444c87aefeSPatrick Mooney goto out; 3454c87aefeSPatrick Mooney } 3464c87aefeSPatrick Mooney 3474c87aefeSPatrick Mooney if (listen(s, 1) < 0) { 3484c87aefeSPatrick Mooney error = -1; 3494c87aefeSPatrick Mooney goto out; 3504c87aefeSPatrick Mooney } 3514c87aefeSPatrick Mooney 3524c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 3534c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE); 3544c87aefeSPatrick Mooney if (caph_rights_limit(s, &rights) == -1) 3554c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 3564c87aefeSPatrick Mooney #endif 3574c87aefeSPatrick Mooney 3584c87aefeSPatrick Mooney sock->vss_port = pci_vtcon_port_add(sc, name, pci_vtcon_sock_tx, sock); 3594c87aefeSPatrick Mooney if (sock->vss_port == NULL) { 3604c87aefeSPatrick Mooney error = -1; 3614c87aefeSPatrick Mooney goto out; 3624c87aefeSPatrick Mooney } 3634c87aefeSPatrick Mooney 3644c87aefeSPatrick Mooney sock->vss_open = false; 3654c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 3664c87aefeSPatrick Mooney sock->vss_server_fd = s; 3674c87aefeSPatrick Mooney sock->vss_server_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_accept, 3684c87aefeSPatrick Mooney sock); 3694c87aefeSPatrick Mooney 3704c87aefeSPatrick Mooney if (sock->vss_server_evp == NULL) { 3714c87aefeSPatrick Mooney error = -1; 3724c87aefeSPatrick Mooney goto out; 3734c87aefeSPatrick Mooney } 3744c87aefeSPatrick Mooney 3754c87aefeSPatrick Mooney out: 3764c87aefeSPatrick Mooney if (fd != -1) 3774c87aefeSPatrick Mooney close(fd); 3784c87aefeSPatrick Mooney 37984659b24SMichael Zeller if (error != 0) { 38084659b24SMichael Zeller if (s != -1) 3814c87aefeSPatrick Mooney close(s); 38284659b24SMichael Zeller free(sock); 38384659b24SMichael Zeller } 3844c87aefeSPatrick Mooney 3854c87aefeSPatrick Mooney return (error); 3864c87aefeSPatrick Mooney } 3874c87aefeSPatrick Mooney 3884c87aefeSPatrick Mooney static void 3894c87aefeSPatrick Mooney pci_vtcon_sock_accept(int fd __unused, enum ev_type t __unused, void *arg) 3904c87aefeSPatrick Mooney { 3914c87aefeSPatrick Mooney struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg; 3924c87aefeSPatrick Mooney int s; 3934c87aefeSPatrick Mooney 3944c87aefeSPatrick Mooney s = accept(sock->vss_server_fd, NULL, NULL); 3954c87aefeSPatrick Mooney if (s < 0) 3964c87aefeSPatrick Mooney return; 3974c87aefeSPatrick Mooney 3984c87aefeSPatrick Mooney if (sock->vss_open) { 3994c87aefeSPatrick Mooney close(s); 4004c87aefeSPatrick Mooney return; 4014c87aefeSPatrick Mooney } 4024c87aefeSPatrick Mooney 4034c87aefeSPatrick Mooney sock->vss_open = true; 4044c87aefeSPatrick Mooney sock->vss_conn_fd = s; 4054c87aefeSPatrick Mooney sock->vss_conn_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_rx, sock); 4064c87aefeSPatrick Mooney 4074c87aefeSPatrick Mooney pci_vtcon_open_port(sock->vss_port, true); 4084c87aefeSPatrick Mooney } 4094c87aefeSPatrick Mooney 4104c87aefeSPatrick Mooney static void 4114c87aefeSPatrick Mooney pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg) 4124c87aefeSPatrick Mooney { 4134c87aefeSPatrick Mooney struct pci_vtcon_port *port; 4144c87aefeSPatrick Mooney struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg; 4154c87aefeSPatrick Mooney struct vqueue_info *vq; 4164c87aefeSPatrick Mooney struct iovec iov; 4174c87aefeSPatrick Mooney static char dummybuf[2048]; 4184c87aefeSPatrick Mooney int len, n; 4194c87aefeSPatrick Mooney uint16_t idx; 4204c87aefeSPatrick Mooney 4214c87aefeSPatrick Mooney port = sock->vss_port; 4224c87aefeSPatrick Mooney vq = pci_vtcon_port_to_vq(port, true); 4234c87aefeSPatrick Mooney 4244c87aefeSPatrick Mooney if (!sock->vss_open || !port->vsp_rx_ready) { 4254c87aefeSPatrick Mooney len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf)); 4264c87aefeSPatrick Mooney if (len == 0) 4274c87aefeSPatrick Mooney goto close; 4284c87aefeSPatrick Mooney 4294c87aefeSPatrick Mooney return; 4304c87aefeSPatrick Mooney } 4314c87aefeSPatrick Mooney 4324c87aefeSPatrick Mooney if (!vq_has_descs(vq)) { 4334c87aefeSPatrick Mooney len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf)); 4344c87aefeSPatrick Mooney vq_endchains(vq, 1); 4354c87aefeSPatrick Mooney if (len == 0) 4364c87aefeSPatrick Mooney goto close; 4374c87aefeSPatrick Mooney 4384c87aefeSPatrick Mooney return; 4394c87aefeSPatrick Mooney } 4404c87aefeSPatrick Mooney 4414c87aefeSPatrick Mooney do { 4424c87aefeSPatrick Mooney n = vq_getchain(vq, &idx, &iov, 1, NULL); 4434c87aefeSPatrick Mooney len = readv(sock->vss_conn_fd, &iov, n); 4444c87aefeSPatrick Mooney 4454c87aefeSPatrick Mooney if (len == 0 || (len < 0 && errno == EWOULDBLOCK)) { 446*154972afSPatrick Mooney vq_retchains(vq, 1); 4474c87aefeSPatrick Mooney vq_endchains(vq, 0); 4484c87aefeSPatrick Mooney if (len == 0) 4494c87aefeSPatrick Mooney goto close; 4504c87aefeSPatrick Mooney 4514c87aefeSPatrick Mooney return; 4524c87aefeSPatrick Mooney } 4534c87aefeSPatrick Mooney 4544c87aefeSPatrick Mooney vq_relchain(vq, idx, len); 4554c87aefeSPatrick Mooney } while (vq_has_descs(vq)); 4564c87aefeSPatrick Mooney 4574c87aefeSPatrick Mooney vq_endchains(vq, 1); 4584c87aefeSPatrick Mooney 4594c87aefeSPatrick Mooney close: 4604c87aefeSPatrick Mooney mevent_delete_close(sock->vss_conn_evp); 4614c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 4624c87aefeSPatrick Mooney sock->vss_open = false; 4634c87aefeSPatrick Mooney } 4644c87aefeSPatrick Mooney 4654c87aefeSPatrick Mooney static void 4664c87aefeSPatrick Mooney pci_vtcon_sock_tx(struct pci_vtcon_port *port, void *arg, struct iovec *iov, 4674c87aefeSPatrick Mooney int niov) 4684c87aefeSPatrick Mooney { 4694c87aefeSPatrick Mooney struct pci_vtcon_sock *sock; 4704c87aefeSPatrick Mooney #ifdef __FreeBSD__ 4714c87aefeSPatrick Mooney int i, ret; 4724c87aefeSPatrick Mooney #else 4734c87aefeSPatrick Mooney int i, ret = 0; 4744c87aefeSPatrick Mooney #endif 4754c87aefeSPatrick Mooney 4764c87aefeSPatrick Mooney sock = (struct pci_vtcon_sock *)arg; 4774c87aefeSPatrick Mooney 4784c87aefeSPatrick Mooney if (sock->vss_conn_fd == -1) 4794c87aefeSPatrick Mooney return; 4804c87aefeSPatrick Mooney 4814c87aefeSPatrick Mooney for (i = 0; i < niov; i++) { 4824c87aefeSPatrick Mooney ret = stream_write(sock->vss_conn_fd, iov[i].iov_base, 4834c87aefeSPatrick Mooney iov[i].iov_len); 4844c87aefeSPatrick Mooney if (ret <= 0) 4854c87aefeSPatrick Mooney break; 4864c87aefeSPatrick Mooney } 4874c87aefeSPatrick Mooney 4884c87aefeSPatrick Mooney if (ret <= 0) { 4894c87aefeSPatrick Mooney mevent_delete_close(sock->vss_conn_evp); 4904c87aefeSPatrick Mooney sock->vss_conn_fd = -1; 4914c87aefeSPatrick Mooney sock->vss_open = false; 4924c87aefeSPatrick Mooney } 4934c87aefeSPatrick Mooney } 4944c87aefeSPatrick Mooney 4954c87aefeSPatrick Mooney static void 4964c87aefeSPatrick Mooney pci_vtcon_control_tx(struct pci_vtcon_port *port, void *arg, struct iovec *iov, 4974c87aefeSPatrick Mooney int niov) 4984c87aefeSPatrick Mooney { 4994c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 5004c87aefeSPatrick Mooney struct pci_vtcon_port *tmp; 5014c87aefeSPatrick Mooney struct pci_vtcon_control resp, *ctrl; 5024c87aefeSPatrick Mooney int i; 5034c87aefeSPatrick Mooney 5044c87aefeSPatrick Mooney assert(niov == 1); 5054c87aefeSPatrick Mooney 5064c87aefeSPatrick Mooney sc = port->vsp_sc; 5074c87aefeSPatrick Mooney ctrl = (struct pci_vtcon_control *)iov->iov_base; 5084c87aefeSPatrick Mooney 5094c87aefeSPatrick Mooney switch (ctrl->event) { 5104c87aefeSPatrick Mooney case VTCON_DEVICE_READY: 5114c87aefeSPatrick Mooney sc->vsc_ready = true; 5124c87aefeSPatrick Mooney /* set port ready events for registered ports */ 5134c87aefeSPatrick Mooney for (i = 0; i < VTCON_MAXPORTS; i++) { 5144c87aefeSPatrick Mooney tmp = &sc->vsc_ports[i]; 5154c87aefeSPatrick Mooney if (tmp->vsp_enabled) 5164c87aefeSPatrick Mooney pci_vtcon_announce_port(tmp); 5174c87aefeSPatrick Mooney 5184c87aefeSPatrick Mooney if (tmp->vsp_open) 5194c87aefeSPatrick Mooney pci_vtcon_open_port(tmp, true); 5204c87aefeSPatrick Mooney } 5214c87aefeSPatrick Mooney break; 5224c87aefeSPatrick Mooney 5234c87aefeSPatrick Mooney case VTCON_PORT_READY: 5244c87aefeSPatrick Mooney if (ctrl->id >= sc->vsc_nports) { 525*154972afSPatrick Mooney WPRINTF(("VTCON_PORT_READY event for unknown port %d", 5264c87aefeSPatrick Mooney ctrl->id)); 5274c87aefeSPatrick Mooney return; 5284c87aefeSPatrick Mooney } 5294c87aefeSPatrick Mooney 5304c87aefeSPatrick Mooney tmp = &sc->vsc_ports[ctrl->id]; 5314c87aefeSPatrick Mooney if (tmp->vsp_console) { 5324c87aefeSPatrick Mooney resp.event = VTCON_CONSOLE_PORT; 5334c87aefeSPatrick Mooney resp.id = ctrl->id; 5344c87aefeSPatrick Mooney resp.value = 1; 5354c87aefeSPatrick Mooney pci_vtcon_control_send(sc, &resp, NULL, 0); 5364c87aefeSPatrick Mooney } 5374c87aefeSPatrick Mooney break; 5384c87aefeSPatrick Mooney } 5394c87aefeSPatrick Mooney } 5404c87aefeSPatrick Mooney 5414c87aefeSPatrick Mooney static void 5424c87aefeSPatrick Mooney pci_vtcon_announce_port(struct pci_vtcon_port *port) 5434c87aefeSPatrick Mooney { 5444c87aefeSPatrick Mooney struct pci_vtcon_control event; 5454c87aefeSPatrick Mooney 5464c87aefeSPatrick Mooney event.id = port->vsp_id; 5474c87aefeSPatrick Mooney event.event = VTCON_DEVICE_ADD; 5484c87aefeSPatrick Mooney event.value = 1; 5494c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0); 5504c87aefeSPatrick Mooney 5514c87aefeSPatrick Mooney event.event = VTCON_PORT_NAME; 5524c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, port->vsp_name, 5534c87aefeSPatrick Mooney strlen(port->vsp_name)); 5544c87aefeSPatrick Mooney } 5554c87aefeSPatrick Mooney 5564c87aefeSPatrick Mooney static void 5574c87aefeSPatrick Mooney pci_vtcon_open_port(struct pci_vtcon_port *port, bool open) 5584c87aefeSPatrick Mooney { 5594c87aefeSPatrick Mooney struct pci_vtcon_control event; 5604c87aefeSPatrick Mooney 5614c87aefeSPatrick Mooney if (!port->vsp_sc->vsc_ready) { 5624c87aefeSPatrick Mooney port->vsp_open = true; 5634c87aefeSPatrick Mooney return; 5644c87aefeSPatrick Mooney } 5654c87aefeSPatrick Mooney 5664c87aefeSPatrick Mooney event.id = port->vsp_id; 5674c87aefeSPatrick Mooney event.event = VTCON_PORT_OPEN; 5684c87aefeSPatrick Mooney event.value = (int)open; 5694c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0); 5704c87aefeSPatrick Mooney } 5714c87aefeSPatrick Mooney 5724c87aefeSPatrick Mooney static void 5734c87aefeSPatrick Mooney pci_vtcon_control_send(struct pci_vtcon_softc *sc, 5744c87aefeSPatrick Mooney struct pci_vtcon_control *ctrl, const void *payload, size_t len) 5754c87aefeSPatrick Mooney { 5764c87aefeSPatrick Mooney struct vqueue_info *vq; 5774c87aefeSPatrick Mooney struct iovec iov; 5784c87aefeSPatrick Mooney uint16_t idx; 5794c87aefeSPatrick Mooney int n; 5804c87aefeSPatrick Mooney 5814c87aefeSPatrick Mooney vq = pci_vtcon_port_to_vq(&sc->vsc_control_port, true); 5824c87aefeSPatrick Mooney 5834c87aefeSPatrick Mooney if (!vq_has_descs(vq)) 5844c87aefeSPatrick Mooney return; 5854c87aefeSPatrick Mooney 5864c87aefeSPatrick Mooney n = vq_getchain(vq, &idx, &iov, 1, NULL); 5874c87aefeSPatrick Mooney 5884c87aefeSPatrick Mooney assert(n == 1); 5894c87aefeSPatrick Mooney 5904c87aefeSPatrick Mooney memcpy(iov.iov_base, ctrl, sizeof(struct pci_vtcon_control)); 5914c87aefeSPatrick Mooney if (payload != NULL && len > 0) 5924c87aefeSPatrick Mooney memcpy(iov.iov_base + sizeof(struct pci_vtcon_control), 5934c87aefeSPatrick Mooney payload, len); 5944c87aefeSPatrick Mooney 5954c87aefeSPatrick Mooney vq_relchain(vq, idx, sizeof(struct pci_vtcon_control) + len); 5964c87aefeSPatrick Mooney vq_endchains(vq, 1); 5974c87aefeSPatrick Mooney } 5984c87aefeSPatrick Mooney 5994c87aefeSPatrick Mooney 6004c87aefeSPatrick Mooney static void 6014c87aefeSPatrick Mooney pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq) 6024c87aefeSPatrick Mooney { 6034c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 6044c87aefeSPatrick Mooney struct pci_vtcon_port *port; 6054c87aefeSPatrick Mooney struct iovec iov[1]; 6064c87aefeSPatrick Mooney uint16_t idx, n; 6074c87aefeSPatrick Mooney uint16_t flags[8]; 6084c87aefeSPatrick Mooney 6094c87aefeSPatrick Mooney sc = vsc; 6104c87aefeSPatrick Mooney port = pci_vtcon_vq_to_port(sc, vq); 6114c87aefeSPatrick Mooney 6124c87aefeSPatrick Mooney while (vq_has_descs(vq)) { 6134c87aefeSPatrick Mooney n = vq_getchain(vq, &idx, iov, 1, flags); 6144c87aefeSPatrick Mooney assert(n >= 1); 6154c87aefeSPatrick Mooney if (port != NULL) 6164c87aefeSPatrick Mooney port->vsp_cb(port, port->vsp_arg, iov, 1); 6174c87aefeSPatrick Mooney 6184c87aefeSPatrick Mooney /* 6194c87aefeSPatrick Mooney * Release this chain and handle more 6204c87aefeSPatrick Mooney */ 6214c87aefeSPatrick Mooney vq_relchain(vq, idx, 0); 6224c87aefeSPatrick Mooney } 6234c87aefeSPatrick Mooney vq_endchains(vq, 1); /* Generate interrupt if appropriate. */ 6244c87aefeSPatrick Mooney } 6254c87aefeSPatrick Mooney 6264c87aefeSPatrick Mooney static void 6274c87aefeSPatrick Mooney pci_vtcon_notify_rx(void *vsc, struct vqueue_info *vq) 6284c87aefeSPatrick Mooney { 6294c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 6304c87aefeSPatrick Mooney struct pci_vtcon_port *port; 6314c87aefeSPatrick Mooney 6324c87aefeSPatrick Mooney sc = vsc; 6334c87aefeSPatrick Mooney port = pci_vtcon_vq_to_port(sc, vq); 6344c87aefeSPatrick Mooney 6354c87aefeSPatrick Mooney if (!port->vsp_rx_ready) { 6364c87aefeSPatrick Mooney port->vsp_rx_ready = 1; 63784659b24SMichael Zeller vq_kick_disable(vq); 6384c87aefeSPatrick Mooney } 6394c87aefeSPatrick Mooney } 6404c87aefeSPatrick Mooney 6414c87aefeSPatrick Mooney static int 6424c87aefeSPatrick Mooney pci_vtcon_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 6434c87aefeSPatrick Mooney { 6444c87aefeSPatrick Mooney struct pci_vtcon_softc *sc; 6454c87aefeSPatrick Mooney char *portname = NULL; 6464c87aefeSPatrick Mooney char *portpath = NULL; 6474c87aefeSPatrick Mooney char *opt; 6484c87aefeSPatrick Mooney int i; 6494c87aefeSPatrick Mooney 6504c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct pci_vtcon_softc)); 6514c87aefeSPatrick Mooney sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config)); 6524c87aefeSPatrick Mooney sc->vsc_config->max_nr_ports = VTCON_MAXPORTS; 6534c87aefeSPatrick Mooney sc->vsc_config->cols = 80; 6544c87aefeSPatrick Mooney sc->vsc_config->rows = 25; 6554c87aefeSPatrick Mooney 6564c87aefeSPatrick Mooney vi_softc_linkup(&sc->vsc_vs, &vtcon_vi_consts, sc, pi, sc->vsc_queues); 6574c87aefeSPatrick Mooney sc->vsc_vs.vs_mtx = &sc->vsc_mtx; 6584c87aefeSPatrick Mooney 6594c87aefeSPatrick Mooney for (i = 0; i < VTCON_MAXQ; i++) { 6604c87aefeSPatrick Mooney sc->vsc_queues[i].vq_qsize = VTCON_RINGSZ; 6614c87aefeSPatrick Mooney sc->vsc_queues[i].vq_notify = i % 2 == 0 6624c87aefeSPatrick Mooney ? pci_vtcon_notify_rx 6634c87aefeSPatrick Mooney : pci_vtcon_notify_tx; 6644c87aefeSPatrick Mooney } 6654c87aefeSPatrick Mooney 6664c87aefeSPatrick Mooney /* initialize config space */ 6674c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_CONSOLE); 6684c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 6694c87aefeSPatrick Mooney pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM); 6704c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_CONSOLE); 6714c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR); 6724c87aefeSPatrick Mooney 6734c87aefeSPatrick Mooney if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix())) 6744c87aefeSPatrick Mooney return (1); 6754c87aefeSPatrick Mooney vi_set_io_bar(&sc->vsc_vs, 0); 6764c87aefeSPatrick Mooney 6774c87aefeSPatrick Mooney /* create control port */ 6784c87aefeSPatrick Mooney sc->vsc_control_port.vsp_sc = sc; 6794c87aefeSPatrick Mooney sc->vsc_control_port.vsp_txq = 2; 6804c87aefeSPatrick Mooney sc->vsc_control_port.vsp_rxq = 3; 6814c87aefeSPatrick Mooney sc->vsc_control_port.vsp_cb = pci_vtcon_control_tx; 6824c87aefeSPatrick Mooney sc->vsc_control_port.vsp_enabled = true; 6834c87aefeSPatrick Mooney 6844c87aefeSPatrick Mooney while ((opt = strsep(&opts, ",")) != NULL) { 6854c87aefeSPatrick Mooney portname = strsep(&opt, "="); 6864c87aefeSPatrick Mooney portpath = opt; 6874c87aefeSPatrick Mooney 6884c87aefeSPatrick Mooney /* create port */ 6894c87aefeSPatrick Mooney if (pci_vtcon_sock_add(sc, portname, portpath) < 0) { 690*154972afSPatrick Mooney EPRINTLN("cannot create port %s: %s", 6914c87aefeSPatrick Mooney portname, strerror(errno)); 6924c87aefeSPatrick Mooney return (1); 6934c87aefeSPatrick Mooney } 6944c87aefeSPatrick Mooney } 6954c87aefeSPatrick Mooney 6964c87aefeSPatrick Mooney return (0); 6974c87aefeSPatrick Mooney } 6984c87aefeSPatrick Mooney 6994c87aefeSPatrick Mooney struct pci_devemu pci_de_vcon = { 7004c87aefeSPatrick Mooney .pe_emu = "virtio-console", 7014c87aefeSPatrick Mooney .pe_init = pci_vtcon_init, 7024c87aefeSPatrick Mooney .pe_barwrite = vi_pci_write, 7034c87aefeSPatrick Mooney .pe_barread = vi_pci_read 7044c87aefeSPatrick Mooney }; 7054c87aefeSPatrick Mooney PCI_EMUL_SET(pci_de_vcon); 706