14c87aefeSPatrick Mooney /*-
2*32640292SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
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
394c87aefeSPatrick Mooney #include <sys/param.h>
404c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
414c87aefeSPatrick Mooney #include <sys/capsicum.h>
424c87aefeSPatrick Mooney #endif
434c87aefeSPatrick Mooney #include <sys/linker_set.h>
444c87aefeSPatrick Mooney #include <sys/uio.h>
454c87aefeSPatrick Mooney #include <sys/types.h>
464c87aefeSPatrick Mooney #include <sys/socket.h>
474c87aefeSPatrick Mooney #include <sys/un.h>
484c87aefeSPatrick Mooney
494c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
504c87aefeSPatrick Mooney #include <capsicum_helpers.h>
514c87aefeSPatrick Mooney #endif
524c87aefeSPatrick Mooney #include <err.h>
534c87aefeSPatrick Mooney #include <errno.h>
544c87aefeSPatrick Mooney #include <fcntl.h>
554c87aefeSPatrick Mooney #include <stdio.h>
564c87aefeSPatrick Mooney #include <stdlib.h>
574c87aefeSPatrick Mooney #include <stdbool.h>
584c87aefeSPatrick Mooney #include <string.h>
594c87aefeSPatrick Mooney #include <unistd.h>
604c87aefeSPatrick Mooney #include <assert.h>
614c87aefeSPatrick Mooney #include <pthread.h>
624c87aefeSPatrick Mooney #include <libgen.h>
634c87aefeSPatrick Mooney #include <sysexits.h>
644c87aefeSPatrick Mooney
654c87aefeSPatrick Mooney #include "bhyverun.h"
662b948146SAndy Fiddaman #include "config.h"
67154972afSPatrick 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;
93154972afSPatrick Mooney #define DPRINTF(params) if (pci_vtcon_debug) PRINTLN params
94154972afSPatrick 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 bool vsc_ready;
1364c87aefeSPatrick Mooney struct pci_vtcon_port vsc_control_port;
1374c87aefeSPatrick Mooney struct pci_vtcon_port vsc_ports[VTCON_MAXPORTS];
1384c87aefeSPatrick Mooney struct pci_vtcon_config *vsc_config;
1394c87aefeSPatrick Mooney };
1404c87aefeSPatrick Mooney
1414c87aefeSPatrick Mooney struct pci_vtcon_config {
1424c87aefeSPatrick Mooney uint16_t cols;
1434c87aefeSPatrick Mooney uint16_t rows;
1444c87aefeSPatrick Mooney uint32_t max_nr_ports;
1454c87aefeSPatrick Mooney uint32_t emerg_wr;
1464c87aefeSPatrick Mooney } __attribute__((packed));
1474c87aefeSPatrick Mooney
1484c87aefeSPatrick Mooney struct pci_vtcon_control {
1494c87aefeSPatrick Mooney uint32_t id;
1504c87aefeSPatrick Mooney uint16_t event;
1514c87aefeSPatrick Mooney uint16_t value;
1524c87aefeSPatrick Mooney } __attribute__((packed));
1534c87aefeSPatrick Mooney
1544c87aefeSPatrick Mooney struct pci_vtcon_console_resize {
1554c87aefeSPatrick Mooney uint16_t cols;
1564c87aefeSPatrick Mooney uint16_t rows;
1574c87aefeSPatrick Mooney } __attribute__((packed));
1584c87aefeSPatrick Mooney
1594c87aefeSPatrick Mooney static void pci_vtcon_reset(void *);
1604c87aefeSPatrick Mooney static void pci_vtcon_notify_rx(void *, struct vqueue_info *);
1614c87aefeSPatrick Mooney static void pci_vtcon_notify_tx(void *, struct vqueue_info *);
1624c87aefeSPatrick Mooney static int pci_vtcon_cfgread(void *, int, int, uint32_t *);
1634c87aefeSPatrick Mooney static int pci_vtcon_cfgwrite(void *, int, int, uint32_t);
1644c87aefeSPatrick Mooney static void pci_vtcon_neg_features(void *, uint64_t);
1654c87aefeSPatrick Mooney static void pci_vtcon_sock_accept(int, enum ev_type, void *);
1664c87aefeSPatrick Mooney static void pci_vtcon_sock_rx(int, enum ev_type, void *);
1674c87aefeSPatrick Mooney static void pci_vtcon_sock_tx(struct pci_vtcon_port *, void *, struct iovec *,
1684c87aefeSPatrick Mooney int);
1694c87aefeSPatrick Mooney static void pci_vtcon_control_send(struct pci_vtcon_softc *,
1704c87aefeSPatrick Mooney struct pci_vtcon_control *, const void *, size_t);
1714c87aefeSPatrick Mooney static void pci_vtcon_announce_port(struct pci_vtcon_port *);
1724c87aefeSPatrick Mooney static void pci_vtcon_open_port(struct pci_vtcon_port *, bool);
1734c87aefeSPatrick Mooney
1744c87aefeSPatrick Mooney static struct virtio_consts vtcon_vi_consts = {
17559d65d31SAndy Fiddaman .vc_name = "vtcon",
17659d65d31SAndy Fiddaman .vc_nvq = VTCON_MAXQ,
17759d65d31SAndy Fiddaman .vc_cfgsize = sizeof(struct pci_vtcon_config),
17859d65d31SAndy Fiddaman .vc_reset = pci_vtcon_reset,
17959d65d31SAndy Fiddaman .vc_cfgread = pci_vtcon_cfgread,
18059d65d31SAndy Fiddaman .vc_cfgwrite = pci_vtcon_cfgwrite,
18159d65d31SAndy Fiddaman .vc_apply_features = pci_vtcon_neg_features,
18259d65d31SAndy Fiddaman .vc_hv_caps = VTCON_S_HOSTCAPS,
1834c87aefeSPatrick Mooney };
1844c87aefeSPatrick Mooney
1854c87aefeSPatrick Mooney static void
pci_vtcon_reset(void * vsc)1864c87aefeSPatrick Mooney pci_vtcon_reset(void *vsc)
1874c87aefeSPatrick Mooney {
1884c87aefeSPatrick Mooney struct pci_vtcon_softc *sc;
1894c87aefeSPatrick Mooney
1904c87aefeSPatrick Mooney sc = vsc;
1914c87aefeSPatrick Mooney
192154972afSPatrick Mooney DPRINTF(("vtcon: device reset requested!"));
1934c87aefeSPatrick Mooney vi_reset_dev(&sc->vsc_vs);
1944c87aefeSPatrick Mooney }
1954c87aefeSPatrick Mooney
1964c87aefeSPatrick Mooney static void
pci_vtcon_neg_features(void * vsc,uint64_t negotiated_features)1974c87aefeSPatrick Mooney pci_vtcon_neg_features(void *vsc, uint64_t negotiated_features)
1984c87aefeSPatrick Mooney {
1994c87aefeSPatrick Mooney struct pci_vtcon_softc *sc = vsc;
2004c87aefeSPatrick Mooney
2014c87aefeSPatrick Mooney sc->vsc_features = negotiated_features;
2024c87aefeSPatrick Mooney }
2034c87aefeSPatrick Mooney
2044c87aefeSPatrick Mooney static int
pci_vtcon_cfgread(void * vsc,int offset,int size,uint32_t * retval)2054c87aefeSPatrick Mooney pci_vtcon_cfgread(void *vsc, int offset, int size, uint32_t *retval)
2064c87aefeSPatrick Mooney {
2074c87aefeSPatrick Mooney struct pci_vtcon_softc *sc = vsc;
2084c87aefeSPatrick Mooney void *ptr;
2094c87aefeSPatrick Mooney
2104c87aefeSPatrick Mooney ptr = (uint8_t *)sc->vsc_config + offset;
2114c87aefeSPatrick Mooney memcpy(retval, ptr, size);
2124c87aefeSPatrick Mooney return (0);
2134c87aefeSPatrick Mooney }
2144c87aefeSPatrick Mooney
2154c87aefeSPatrick Mooney static int
pci_vtcon_cfgwrite(void * vsc __unused,int offset __unused,int size __unused,uint32_t val __unused)21659d65d31SAndy Fiddaman pci_vtcon_cfgwrite(void *vsc __unused, int offset __unused, int size __unused,
21759d65d31SAndy Fiddaman uint32_t val __unused)
2184c87aefeSPatrick Mooney {
2194c87aefeSPatrick Mooney return (0);
2204c87aefeSPatrick Mooney }
2214c87aefeSPatrick Mooney
2224c87aefeSPatrick Mooney static inline struct pci_vtcon_port *
pci_vtcon_vq_to_port(struct pci_vtcon_softc * sc,struct vqueue_info * vq)2234c87aefeSPatrick Mooney pci_vtcon_vq_to_port(struct pci_vtcon_softc *sc, struct vqueue_info *vq)
2244c87aefeSPatrick Mooney {
2254c87aefeSPatrick Mooney uint16_t num = vq->vq_num;
2264c87aefeSPatrick Mooney
2274c87aefeSPatrick Mooney if (num == 0 || num == 1)
2284c87aefeSPatrick Mooney return (&sc->vsc_ports[0]);
2294c87aefeSPatrick Mooney
2304c87aefeSPatrick Mooney if (num == 2 || num == 3)
2314c87aefeSPatrick Mooney return (&sc->vsc_control_port);
2324c87aefeSPatrick Mooney
2334c87aefeSPatrick Mooney return (&sc->vsc_ports[(num / 2) - 1]);
2344c87aefeSPatrick Mooney }
2354c87aefeSPatrick Mooney
2364c87aefeSPatrick Mooney static inline struct vqueue_info *
pci_vtcon_port_to_vq(struct pci_vtcon_port * port,bool tx_queue)2374c87aefeSPatrick Mooney pci_vtcon_port_to_vq(struct pci_vtcon_port *port, bool tx_queue)
2384c87aefeSPatrick Mooney {
2394c87aefeSPatrick Mooney int qnum;
2404c87aefeSPatrick Mooney
2414c87aefeSPatrick Mooney qnum = tx_queue ? port->vsp_txq : port->vsp_rxq;
2424c87aefeSPatrick Mooney return (&port->vsp_sc->vsc_queues[qnum]);
2434c87aefeSPatrick Mooney }
2444c87aefeSPatrick Mooney
2454c87aefeSPatrick Mooney static struct pci_vtcon_port *
pci_vtcon_port_add(struct pci_vtcon_softc * sc,int port_id,const char * name,pci_vtcon_cb_t * cb,void * arg)2462b948146SAndy Fiddaman pci_vtcon_port_add(struct pci_vtcon_softc *sc, int port_id, const char *name,
2474c87aefeSPatrick Mooney pci_vtcon_cb_t *cb, void *arg)
2484c87aefeSPatrick Mooney {
2494c87aefeSPatrick Mooney struct pci_vtcon_port *port;
2504c87aefeSPatrick Mooney
2512b948146SAndy Fiddaman port = &sc->vsc_ports[port_id];
2522b948146SAndy Fiddaman if (port->vsp_enabled) {
2534c87aefeSPatrick Mooney errno = EBUSY;
2544c87aefeSPatrick Mooney return (NULL);
2554c87aefeSPatrick Mooney }
2562b948146SAndy Fiddaman port->vsp_id = port_id;
2574c87aefeSPatrick Mooney port->vsp_sc = sc;
2584c87aefeSPatrick Mooney port->vsp_name = name;
2594c87aefeSPatrick Mooney port->vsp_cb = cb;
2604c87aefeSPatrick Mooney port->vsp_arg = arg;
2614c87aefeSPatrick Mooney
2624c87aefeSPatrick Mooney if (port->vsp_id == 0) {
2634c87aefeSPatrick Mooney /* port0 */
2644c87aefeSPatrick Mooney port->vsp_txq = 0;
2654c87aefeSPatrick Mooney port->vsp_rxq = 1;
2664c87aefeSPatrick Mooney } else {
2672b948146SAndy Fiddaman port->vsp_txq = (port_id + 1) * 2;
2684c87aefeSPatrick Mooney port->vsp_rxq = port->vsp_txq + 1;
2694c87aefeSPatrick Mooney }
2704c87aefeSPatrick Mooney
2714c87aefeSPatrick Mooney port->vsp_enabled = true;
2724c87aefeSPatrick Mooney return (port);
2734c87aefeSPatrick Mooney }
2744c87aefeSPatrick Mooney
2754c87aefeSPatrick Mooney static int
pci_vtcon_sock_add(struct pci_vtcon_softc * sc,const char * port_name,const nvlist_t * nvl)2762b948146SAndy Fiddaman pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *port_name,
2772b948146SAndy Fiddaman const nvlist_t *nvl)
2784c87aefeSPatrick Mooney {
27959d65d31SAndy Fiddaman struct pci_vtcon_sock *sock = NULL;
2804c87aefeSPatrick Mooney #ifdef __FreeBSD__
2814c87aefeSPatrick Mooney struct sockaddr_un sun;
2824c87aefeSPatrick Mooney #else
2834c87aefeSPatrick Mooney /* Our compiler #defines 'sun' as '1'. Awesome. */
2844c87aefeSPatrick Mooney struct sockaddr_un addr;
2854c87aefeSPatrick Mooney #endif
2862b948146SAndy Fiddaman const char *name, *path;
2872b948146SAndy Fiddaman char *cp, *pathcopy;
2882b948146SAndy Fiddaman long port;
2894c87aefeSPatrick Mooney int s = -1, fd = -1, error = 0;
2904c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
2914c87aefeSPatrick Mooney cap_rights_t rights;
2924c87aefeSPatrick Mooney #endif
2934c87aefeSPatrick Mooney
2942b948146SAndy Fiddaman port = strtol(port_name, &cp, 0);
2952b948146SAndy Fiddaman if (*cp != '\0' || port < 0 || port >= VTCON_MAXPORTS) {
2962b948146SAndy Fiddaman EPRINTLN("vtcon: Invalid port %s", port_name);
2972b948146SAndy Fiddaman error = -1;
2982b948146SAndy Fiddaman goto out;
2992b948146SAndy Fiddaman }
3002b948146SAndy Fiddaman
3012b948146SAndy Fiddaman path = get_config_value_node(nvl, "path");
3022b948146SAndy Fiddaman if (path == NULL) {
3032b948146SAndy Fiddaman EPRINTLN("vtcon: required path missing for port %ld", port);
3042b948146SAndy Fiddaman error = -1;
3052b948146SAndy Fiddaman goto out;
3062b948146SAndy Fiddaman }
3072b948146SAndy Fiddaman
3084c87aefeSPatrick Mooney sock = calloc(1, sizeof(struct pci_vtcon_sock));
3094c87aefeSPatrick Mooney if (sock == NULL) {
3104c87aefeSPatrick Mooney error = -1;
3114c87aefeSPatrick Mooney goto out;
3124c87aefeSPatrick Mooney }
3134c87aefeSPatrick Mooney
3144c87aefeSPatrick Mooney s = socket(AF_UNIX, SOCK_STREAM, 0);
3154c87aefeSPatrick Mooney if (s < 0) {
3164c87aefeSPatrick Mooney error = -1;
3174c87aefeSPatrick Mooney goto out;
3184c87aefeSPatrick Mooney }
3194c87aefeSPatrick Mooney
3204c87aefeSPatrick Mooney #ifdef __FreeBSD__
3214c87aefeSPatrick Mooney pathcopy = strdup(path);
3224c87aefeSPatrick Mooney if (pathcopy == NULL) {
3234c87aefeSPatrick Mooney error = -1;
3244c87aefeSPatrick Mooney goto out;
3254c87aefeSPatrick Mooney }
3264c87aefeSPatrick Mooney
3274c87aefeSPatrick Mooney fd = open(dirname(pathcopy), O_RDONLY | O_DIRECTORY);
3284c87aefeSPatrick Mooney if (fd < 0) {
3294c87aefeSPatrick Mooney free(pathcopy);
3304c87aefeSPatrick Mooney error = -1;
3314c87aefeSPatrick Mooney goto out;
3324c87aefeSPatrick Mooney }
3334c87aefeSPatrick Mooney
3344c87aefeSPatrick Mooney sun.sun_family = AF_UNIX;
3354c87aefeSPatrick Mooney sun.sun_len = sizeof(struct sockaddr_un);
3364c87aefeSPatrick Mooney strcpy(pathcopy, path);
3374c87aefeSPatrick Mooney strlcpy(sun.sun_path, basename(pathcopy), sizeof(sun.sun_path));
3384c87aefeSPatrick Mooney free(pathcopy);
3394c87aefeSPatrick Mooney
3404c87aefeSPatrick Mooney if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0) {
3414c87aefeSPatrick Mooney error = -1;
3424c87aefeSPatrick Mooney goto out;
3434c87aefeSPatrick Mooney }
3444c87aefeSPatrick Mooney #else /* __FreeBSD__ */
3454c87aefeSPatrick Mooney /* Do a simple bind rather than the FreeBSD bindat() */
3462b948146SAndy Fiddaman pathcopy = (char *)path;
3474c87aefeSPatrick Mooney addr.sun_family = AF_UNIX;
3482b948146SAndy Fiddaman (void) strlcpy(addr.sun_path, pathcopy, sizeof (addr.sun_path));
3494c87aefeSPatrick Mooney if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
3504c87aefeSPatrick Mooney error = -1;
3514c87aefeSPatrick Mooney goto out;
3524c87aefeSPatrick Mooney }
3534c87aefeSPatrick Mooney #endif /* __FreeBSD__ */
3544c87aefeSPatrick Mooney
3554c87aefeSPatrick Mooney if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
3564c87aefeSPatrick Mooney error = -1;
3574c87aefeSPatrick Mooney goto out;
3584c87aefeSPatrick Mooney }
3594c87aefeSPatrick Mooney
3604c87aefeSPatrick Mooney if (listen(s, 1) < 0) {
3614c87aefeSPatrick Mooney error = -1;
3624c87aefeSPatrick Mooney goto out;
3634c87aefeSPatrick Mooney }
3644c87aefeSPatrick Mooney
3654c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
3664c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE);
3674c87aefeSPatrick Mooney if (caph_rights_limit(s, &rights) == -1)
3684c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox");
3694c87aefeSPatrick Mooney #endif
3704c87aefeSPatrick Mooney
3712b948146SAndy Fiddaman name = get_config_value_node(nvl, "name");
3722b948146SAndy Fiddaman if (name == NULL) {
3732b948146SAndy Fiddaman EPRINTLN("vtcon: required name missing for port %ld", port);
3742b948146SAndy Fiddaman error = -1;
3752b948146SAndy Fiddaman goto out;
3762b948146SAndy Fiddaman }
3772b948146SAndy Fiddaman sock->vss_port = pci_vtcon_port_add(sc, port, name, pci_vtcon_sock_tx, sock);
3784c87aefeSPatrick Mooney if (sock->vss_port == NULL) {
3794c87aefeSPatrick Mooney error = -1;
3804c87aefeSPatrick Mooney goto out;
3814c87aefeSPatrick Mooney }
3824c87aefeSPatrick Mooney
3834c87aefeSPatrick Mooney sock->vss_open = false;
3844c87aefeSPatrick Mooney sock->vss_conn_fd = -1;
3854c87aefeSPatrick Mooney sock->vss_server_fd = s;
3864c87aefeSPatrick Mooney sock->vss_server_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_accept,
3874c87aefeSPatrick Mooney sock);
3884c87aefeSPatrick Mooney
3894c87aefeSPatrick Mooney if (sock->vss_server_evp == NULL) {
3904c87aefeSPatrick Mooney error = -1;
3914c87aefeSPatrick Mooney goto out;
3924c87aefeSPatrick Mooney }
3934c87aefeSPatrick Mooney
3944c87aefeSPatrick Mooney out:
3954c87aefeSPatrick Mooney if (fd != -1)
3964c87aefeSPatrick Mooney close(fd);
3974c87aefeSPatrick Mooney
39884659b24SMichael Zeller if (error != 0) {
39984659b24SMichael Zeller if (s != -1)
40084659b24SMichael Zeller close(s);
40184659b24SMichael Zeller free(sock);
40284659b24SMichael Zeller }
4034c87aefeSPatrick Mooney
4044c87aefeSPatrick Mooney return (error);
4054c87aefeSPatrick Mooney }
4064c87aefeSPatrick Mooney
4074c87aefeSPatrick Mooney static void
pci_vtcon_sock_accept(int fd __unused,enum ev_type t __unused,void * arg)4084c87aefeSPatrick Mooney pci_vtcon_sock_accept(int fd __unused, enum ev_type t __unused, void *arg)
4094c87aefeSPatrick Mooney {
4104c87aefeSPatrick Mooney struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg;
4114c87aefeSPatrick Mooney int s;
4124c87aefeSPatrick Mooney
4134c87aefeSPatrick Mooney s = accept(sock->vss_server_fd, NULL, NULL);
4144c87aefeSPatrick Mooney if (s < 0)
4154c87aefeSPatrick Mooney return;
4164c87aefeSPatrick Mooney
4174c87aefeSPatrick Mooney if (sock->vss_open) {
4184c87aefeSPatrick Mooney close(s);
4194c87aefeSPatrick Mooney return;
4204c87aefeSPatrick Mooney }
4214c87aefeSPatrick Mooney
4224c87aefeSPatrick Mooney sock->vss_open = true;
4234c87aefeSPatrick Mooney sock->vss_conn_fd = s;
4244c87aefeSPatrick Mooney sock->vss_conn_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_rx, sock);
4254c87aefeSPatrick Mooney
4264c87aefeSPatrick Mooney pci_vtcon_open_port(sock->vss_port, true);
4274c87aefeSPatrick Mooney }
4284c87aefeSPatrick Mooney
4294c87aefeSPatrick Mooney static void
pci_vtcon_sock_rx(int fd __unused,enum ev_type t __unused,void * arg)4304c87aefeSPatrick Mooney pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg)
4314c87aefeSPatrick Mooney {
4324c87aefeSPatrick Mooney struct pci_vtcon_port *port;
4334c87aefeSPatrick Mooney struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg;
4344c87aefeSPatrick Mooney struct vqueue_info *vq;
435b0de25cbSAndy Fiddaman struct vi_req req;
4364c87aefeSPatrick Mooney struct iovec iov;
4374c87aefeSPatrick Mooney static char dummybuf[2048];
4384c87aefeSPatrick Mooney int len, n;
4394c87aefeSPatrick Mooney
4404c87aefeSPatrick Mooney port = sock->vss_port;
4414c87aefeSPatrick Mooney vq = pci_vtcon_port_to_vq(port, true);
4424c87aefeSPatrick Mooney
4434c87aefeSPatrick Mooney if (!sock->vss_open || !port->vsp_rx_ready) {
4444c87aefeSPatrick Mooney len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf));
4454c87aefeSPatrick Mooney if (len == 0)
4464c87aefeSPatrick Mooney goto close;
4474c87aefeSPatrick Mooney
4484c87aefeSPatrick Mooney return;
4494c87aefeSPatrick Mooney }
4504c87aefeSPatrick Mooney
4514c87aefeSPatrick Mooney if (!vq_has_descs(vq)) {
4524c87aefeSPatrick Mooney len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf));
4534c87aefeSPatrick Mooney vq_endchains(vq, 1);
4544c87aefeSPatrick Mooney if (len == 0)
4554c87aefeSPatrick Mooney goto close;
4564c87aefeSPatrick Mooney
4574c87aefeSPatrick Mooney return;
4584c87aefeSPatrick Mooney }
4594c87aefeSPatrick Mooney
4604c87aefeSPatrick Mooney do {
461b0de25cbSAndy Fiddaman n = vq_getchain(vq, &iov, 1, &req);
462b0de25cbSAndy Fiddaman assert(n == 1);
4634c87aefeSPatrick Mooney len = readv(sock->vss_conn_fd, &iov, n);
4644c87aefeSPatrick Mooney
4654c87aefeSPatrick Mooney if (len == 0 || (len < 0 && errno == EWOULDBLOCK)) {
466154972afSPatrick Mooney vq_retchains(vq, 1);
4674c87aefeSPatrick Mooney vq_endchains(vq, 0);
4684c87aefeSPatrick Mooney if (len == 0)
4694c87aefeSPatrick Mooney goto close;
4704c87aefeSPatrick Mooney
4714c87aefeSPatrick Mooney return;
4724c87aefeSPatrick Mooney }
4734c87aefeSPatrick Mooney
474b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, len);
4754c87aefeSPatrick Mooney } while (vq_has_descs(vq));
4764c87aefeSPatrick Mooney
4774c87aefeSPatrick Mooney vq_endchains(vq, 1);
4784c87aefeSPatrick Mooney
4794c87aefeSPatrick Mooney close:
4804c87aefeSPatrick Mooney mevent_delete_close(sock->vss_conn_evp);
4814c87aefeSPatrick Mooney sock->vss_conn_fd = -1;
4824c87aefeSPatrick Mooney sock->vss_open = false;
4834c87aefeSPatrick Mooney }
4844c87aefeSPatrick Mooney
4854c87aefeSPatrick Mooney static void
pci_vtcon_sock_tx(struct pci_vtcon_port * port __unused,void * arg __unused,struct iovec * iov,int niov)48659d65d31SAndy Fiddaman pci_vtcon_sock_tx(struct pci_vtcon_port *port __unused, void *arg __unused,
48759d65d31SAndy Fiddaman struct iovec *iov, int niov)
4884c87aefeSPatrick Mooney {
4894c87aefeSPatrick Mooney struct pci_vtcon_sock *sock;
4904c87aefeSPatrick Mooney int i, ret;
4912b948146SAndy Fiddaman
4922b948146SAndy Fiddaman #ifndef __FreeBSD__
4932b948146SAndy Fiddaman ret = 0;
4944c87aefeSPatrick Mooney #endif
4954c87aefeSPatrick Mooney
4964c87aefeSPatrick Mooney sock = (struct pci_vtcon_sock *)arg;
4974c87aefeSPatrick Mooney
4984c87aefeSPatrick Mooney if (sock->vss_conn_fd == -1)
4994c87aefeSPatrick Mooney return;
5004c87aefeSPatrick Mooney
5014c87aefeSPatrick Mooney for (i = 0; i < niov; i++) {
5024c87aefeSPatrick Mooney ret = stream_write(sock->vss_conn_fd, iov[i].iov_base,
5034c87aefeSPatrick Mooney iov[i].iov_len);
5044c87aefeSPatrick Mooney if (ret <= 0)
5054c87aefeSPatrick Mooney break;
5064c87aefeSPatrick Mooney }
5074c87aefeSPatrick Mooney
5084c87aefeSPatrick Mooney if (ret <= 0) {
5094c87aefeSPatrick Mooney mevent_delete_close(sock->vss_conn_evp);
5104c87aefeSPatrick Mooney sock->vss_conn_fd = -1;
5114c87aefeSPatrick Mooney sock->vss_open = false;
5124c87aefeSPatrick Mooney }
5134c87aefeSPatrick Mooney }
5144c87aefeSPatrick Mooney
5154c87aefeSPatrick Mooney static void
pci_vtcon_control_tx(struct pci_vtcon_port * port,void * arg __unused,struct iovec * iov,int niov)51659d65d31SAndy Fiddaman pci_vtcon_control_tx(struct pci_vtcon_port *port, void *arg __unused,
51759d65d31SAndy Fiddaman struct iovec *iov, int niov)
5184c87aefeSPatrick Mooney {
5194c87aefeSPatrick Mooney struct pci_vtcon_softc *sc;
5204c87aefeSPatrick Mooney struct pci_vtcon_port *tmp;
5214c87aefeSPatrick Mooney struct pci_vtcon_control resp, *ctrl;
5224c87aefeSPatrick Mooney int i;
5234c87aefeSPatrick Mooney
5244c87aefeSPatrick Mooney assert(niov == 1);
5254c87aefeSPatrick Mooney
5264c87aefeSPatrick Mooney sc = port->vsp_sc;
5274c87aefeSPatrick Mooney ctrl = (struct pci_vtcon_control *)iov->iov_base;
5284c87aefeSPatrick Mooney
5294c87aefeSPatrick Mooney switch (ctrl->event) {
5304c87aefeSPatrick Mooney case VTCON_DEVICE_READY:
5314c87aefeSPatrick Mooney sc->vsc_ready = true;
5324c87aefeSPatrick Mooney /* set port ready events for registered ports */
5334c87aefeSPatrick Mooney for (i = 0; i < VTCON_MAXPORTS; i++) {
5344c87aefeSPatrick Mooney tmp = &sc->vsc_ports[i];
5354c87aefeSPatrick Mooney if (tmp->vsp_enabled)
5364c87aefeSPatrick Mooney pci_vtcon_announce_port(tmp);
5374c87aefeSPatrick Mooney
5384c87aefeSPatrick Mooney if (tmp->vsp_open)
5394c87aefeSPatrick Mooney pci_vtcon_open_port(tmp, true);
5404c87aefeSPatrick Mooney }
5414c87aefeSPatrick Mooney break;
5424c87aefeSPatrick Mooney
5434c87aefeSPatrick Mooney case VTCON_PORT_READY:
5442b948146SAndy Fiddaman tmp = &sc->vsc_ports[ctrl->id];
5452b948146SAndy Fiddaman if (ctrl->id >= VTCON_MAXPORTS || !tmp->vsp_enabled) {
546154972afSPatrick Mooney WPRINTF(("VTCON_PORT_READY event for unknown port %d",
5474c87aefeSPatrick Mooney ctrl->id));
5484c87aefeSPatrick Mooney return;
5494c87aefeSPatrick Mooney }
5504c87aefeSPatrick Mooney
5514c87aefeSPatrick Mooney if (tmp->vsp_console) {
5524c87aefeSPatrick Mooney resp.event = VTCON_CONSOLE_PORT;
5534c87aefeSPatrick Mooney resp.id = ctrl->id;
5544c87aefeSPatrick Mooney resp.value = 1;
5554c87aefeSPatrick Mooney pci_vtcon_control_send(sc, &resp, NULL, 0);
5564c87aefeSPatrick Mooney }
5574c87aefeSPatrick Mooney break;
5584c87aefeSPatrick Mooney }
5594c87aefeSPatrick Mooney }
5604c87aefeSPatrick Mooney
5614c87aefeSPatrick Mooney static void
pci_vtcon_announce_port(struct pci_vtcon_port * port)5624c87aefeSPatrick Mooney pci_vtcon_announce_port(struct pci_vtcon_port *port)
5634c87aefeSPatrick Mooney {
5644c87aefeSPatrick Mooney struct pci_vtcon_control event;
5654c87aefeSPatrick Mooney
5664c87aefeSPatrick Mooney event.id = port->vsp_id;
5674c87aefeSPatrick Mooney event.event = VTCON_DEVICE_ADD;
5684c87aefeSPatrick Mooney event.value = 1;
5694c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0);
5704c87aefeSPatrick Mooney
5714c87aefeSPatrick Mooney event.event = VTCON_PORT_NAME;
5724c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, port->vsp_name,
5734c87aefeSPatrick Mooney strlen(port->vsp_name));
5744c87aefeSPatrick Mooney }
5754c87aefeSPatrick Mooney
5764c87aefeSPatrick Mooney static void
pci_vtcon_open_port(struct pci_vtcon_port * port,bool open)5774c87aefeSPatrick Mooney pci_vtcon_open_port(struct pci_vtcon_port *port, bool open)
5784c87aefeSPatrick Mooney {
5794c87aefeSPatrick Mooney struct pci_vtcon_control event;
5804c87aefeSPatrick Mooney
5814c87aefeSPatrick Mooney if (!port->vsp_sc->vsc_ready) {
5824c87aefeSPatrick Mooney port->vsp_open = true;
5834c87aefeSPatrick Mooney return;
5844c87aefeSPatrick Mooney }
5854c87aefeSPatrick Mooney
5864c87aefeSPatrick Mooney event.id = port->vsp_id;
5874c87aefeSPatrick Mooney event.event = VTCON_PORT_OPEN;
5884c87aefeSPatrick Mooney event.value = (int)open;
5894c87aefeSPatrick Mooney pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0);
5904c87aefeSPatrick Mooney }
5914c87aefeSPatrick Mooney
5924c87aefeSPatrick Mooney static void
pci_vtcon_control_send(struct pci_vtcon_softc * sc,struct pci_vtcon_control * ctrl,const void * payload,size_t len)5934c87aefeSPatrick Mooney pci_vtcon_control_send(struct pci_vtcon_softc *sc,
5944c87aefeSPatrick Mooney struct pci_vtcon_control *ctrl, const void *payload, size_t len)
5954c87aefeSPatrick Mooney {
5964c87aefeSPatrick Mooney struct vqueue_info *vq;
597b0de25cbSAndy Fiddaman struct vi_req req;
5984c87aefeSPatrick Mooney struct iovec iov;
5994c87aefeSPatrick Mooney int n;
6004c87aefeSPatrick Mooney
6014c87aefeSPatrick Mooney vq = pci_vtcon_port_to_vq(&sc->vsc_control_port, true);
6024c87aefeSPatrick Mooney
6034c87aefeSPatrick Mooney if (!vq_has_descs(vq))
6044c87aefeSPatrick Mooney return;
6054c87aefeSPatrick Mooney
606b0de25cbSAndy Fiddaman n = vq_getchain(vq, &iov, 1, &req);
6074c87aefeSPatrick Mooney assert(n == 1);
6084c87aefeSPatrick Mooney
6094c87aefeSPatrick Mooney memcpy(iov.iov_base, ctrl, sizeof(struct pci_vtcon_control));
6104c87aefeSPatrick Mooney if (payload != NULL && len > 0)
61159d65d31SAndy Fiddaman memcpy((uint8_t *)iov.iov_base +
61259d65d31SAndy Fiddaman sizeof(struct pci_vtcon_control), payload, len);
6134c87aefeSPatrick Mooney
614b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, sizeof(struct pci_vtcon_control) + len);
6154c87aefeSPatrick Mooney vq_endchains(vq, 1);
6164c87aefeSPatrick Mooney }
6176dc98349SAndy Fiddaman
6184c87aefeSPatrick Mooney
6194c87aefeSPatrick Mooney static void
pci_vtcon_notify_tx(void * vsc,struct vqueue_info * vq)6204c87aefeSPatrick Mooney pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq)
6214c87aefeSPatrick Mooney {
6224c87aefeSPatrick Mooney struct pci_vtcon_softc *sc;
6234c87aefeSPatrick Mooney struct pci_vtcon_port *port;
6244c87aefeSPatrick Mooney struct iovec iov[1];
625b0de25cbSAndy Fiddaman struct vi_req req;
626b0de25cbSAndy Fiddaman int n;
6274c87aefeSPatrick Mooney
6284c87aefeSPatrick Mooney sc = vsc;
6294c87aefeSPatrick Mooney port = pci_vtcon_vq_to_port(sc, vq);
6304c87aefeSPatrick Mooney
6314c87aefeSPatrick Mooney while (vq_has_descs(vq)) {
632b0de25cbSAndy Fiddaman n = vq_getchain(vq, iov, 1, &req);
633b0de25cbSAndy Fiddaman assert(n == 1);
6344c87aefeSPatrick Mooney if (port != NULL)
6354c87aefeSPatrick Mooney port->vsp_cb(port, port->vsp_arg, iov, 1);
6364c87aefeSPatrick Mooney
6374c87aefeSPatrick Mooney /*
6384c87aefeSPatrick Mooney * Release this chain and handle more
6394c87aefeSPatrick Mooney */
640b0de25cbSAndy Fiddaman vq_relchain(vq, req.idx, 0);
6414c87aefeSPatrick Mooney }
6424c87aefeSPatrick Mooney vq_endchains(vq, 1); /* Generate interrupt if appropriate. */
6434c87aefeSPatrick Mooney }
6444c87aefeSPatrick Mooney
6454c87aefeSPatrick Mooney static void
pci_vtcon_notify_rx(void * vsc,struct vqueue_info * vq)6464c87aefeSPatrick Mooney pci_vtcon_notify_rx(void *vsc, struct vqueue_info *vq)
6474c87aefeSPatrick Mooney {
6484c87aefeSPatrick Mooney struct pci_vtcon_softc *sc;
6494c87aefeSPatrick Mooney struct pci_vtcon_port *port;
6504c87aefeSPatrick Mooney
6514c87aefeSPatrick Mooney sc = vsc;
6524c87aefeSPatrick Mooney port = pci_vtcon_vq_to_port(sc, vq);
6534c87aefeSPatrick Mooney
6544c87aefeSPatrick Mooney if (!port->vsp_rx_ready) {
6554c87aefeSPatrick Mooney port->vsp_rx_ready = 1;
65684659b24SMichael Zeller vq_kick_disable(vq);
6574c87aefeSPatrick Mooney }
6584c87aefeSPatrick Mooney }
6594c87aefeSPatrick Mooney
6602b948146SAndy Fiddaman /*
6612b948146SAndy Fiddaman * Each console device has a "port" node which contains nodes for
6622b948146SAndy Fiddaman * each port. Ports are numbered starting at 0.
6632b948146SAndy Fiddaman */
6642b948146SAndy Fiddaman static int
pci_vtcon_legacy_config_port(nvlist_t * nvl,int port,char * opt)6652b948146SAndy Fiddaman pci_vtcon_legacy_config_port(nvlist_t *nvl, int port, char *opt)
6662b948146SAndy Fiddaman {
6672b948146SAndy Fiddaman char *name, *path;
6682b948146SAndy Fiddaman char node_name[sizeof("XX")];
6692b948146SAndy Fiddaman nvlist_t *port_nvl;
6702b948146SAndy Fiddaman
6712b948146SAndy Fiddaman name = strsep(&opt, "=");
6722b948146SAndy Fiddaman path = opt;
6732b948146SAndy Fiddaman if (path == NULL) {
6742b948146SAndy Fiddaman EPRINTLN("vtcon: port %s requires a path", name);
6752b948146SAndy Fiddaman return (-1);
6762b948146SAndy Fiddaman }
6772b948146SAndy Fiddaman if (port >= VTCON_MAXPORTS) {
6782b948146SAndy Fiddaman EPRINTLN("vtcon: too many ports");
6792b948146SAndy Fiddaman return (-1);
6802b948146SAndy Fiddaman }
6812b948146SAndy Fiddaman snprintf(node_name, sizeof(node_name), "%d", port);
6822b948146SAndy Fiddaman port_nvl = create_relative_config_node(nvl, node_name);
6832b948146SAndy Fiddaman set_config_value_node(port_nvl, "name", name);
6842b948146SAndy Fiddaman set_config_value_node(port_nvl, "path", path);
6852b948146SAndy Fiddaman return (0);
6862b948146SAndy Fiddaman }
6872b948146SAndy Fiddaman
6884c87aefeSPatrick Mooney static int
pci_vtcon_legacy_config(nvlist_t * nvl,const char * opts)6892b948146SAndy Fiddaman pci_vtcon_legacy_config(nvlist_t *nvl, const char *opts)
6902b948146SAndy Fiddaman {
6912b948146SAndy Fiddaman char *opt, *str, *tofree;
6922b948146SAndy Fiddaman nvlist_t *ports_nvl;
6932b948146SAndy Fiddaman int error, port;
6942b948146SAndy Fiddaman
6952b948146SAndy Fiddaman ports_nvl = create_relative_config_node(nvl, "port");
6962b948146SAndy Fiddaman tofree = str = strdup(opts);
6972b948146SAndy Fiddaman error = 0;
6982b948146SAndy Fiddaman port = 0;
6992b948146SAndy Fiddaman while ((opt = strsep(&str, ",")) != NULL) {
7002b948146SAndy Fiddaman error = pci_vtcon_legacy_config_port(ports_nvl, port, opt);
7012b948146SAndy Fiddaman if (error)
7022b948146SAndy Fiddaman break;
7032b948146SAndy Fiddaman port++;
7042b948146SAndy Fiddaman }
7052b948146SAndy Fiddaman free(tofree);
7062b948146SAndy Fiddaman return (error);
7072b948146SAndy Fiddaman }
7082b948146SAndy Fiddaman
7092b948146SAndy Fiddaman static int
pci_vtcon_init(struct pci_devinst * pi,nvlist_t * nvl)710*32640292SAndy Fiddaman pci_vtcon_init(struct pci_devinst *pi, nvlist_t *nvl)
7114c87aefeSPatrick Mooney {
7124c87aefeSPatrick Mooney struct pci_vtcon_softc *sc;
7132b948146SAndy Fiddaman nvlist_t *ports_nvl;
7142b948146SAndy Fiddaman int i;
7154c87aefeSPatrick Mooney
7164c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct pci_vtcon_softc));
7174c87aefeSPatrick Mooney sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config));
7184c87aefeSPatrick Mooney sc->vsc_config->max_nr_ports = VTCON_MAXPORTS;
7194c87aefeSPatrick Mooney sc->vsc_config->cols = 80;
7206dc98349SAndy Fiddaman sc->vsc_config->rows = 25;
7214c87aefeSPatrick Mooney
7227bb0eb34SAndy Fiddaman pthread_mutex_init(&sc->vsc_mtx, NULL);
7237bb0eb34SAndy Fiddaman
7244c87aefeSPatrick Mooney vi_softc_linkup(&sc->vsc_vs, &vtcon_vi_consts, sc, pi, sc->vsc_queues);
7254c87aefeSPatrick Mooney sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
7264c87aefeSPatrick Mooney
7274c87aefeSPatrick Mooney for (i = 0; i < VTCON_MAXQ; i++) {
7284c87aefeSPatrick Mooney sc->vsc_queues[i].vq_qsize = VTCON_RINGSZ;
7294c87aefeSPatrick Mooney sc->vsc_queues[i].vq_notify = i % 2 == 0
7304c87aefeSPatrick Mooney ? pci_vtcon_notify_rx
7314c87aefeSPatrick Mooney : pci_vtcon_notify_tx;
7324c87aefeSPatrick Mooney }
7334c87aefeSPatrick Mooney
7344c87aefeSPatrick Mooney /* initialize config space */
7354c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_CONSOLE);
7364c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
7374c87aefeSPatrick Mooney pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM);
7382b948146SAndy Fiddaman pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_CONSOLE);
7394c87aefeSPatrick Mooney pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
7404c87aefeSPatrick Mooney
7414c87aefeSPatrick Mooney if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
7424c87aefeSPatrick Mooney return (1);
7434c87aefeSPatrick Mooney vi_set_io_bar(&sc->vsc_vs, 0);
7444c87aefeSPatrick Mooney
7454c87aefeSPatrick Mooney /* create control port */
7464c87aefeSPatrick Mooney sc->vsc_control_port.vsp_sc = sc;
7474c87aefeSPatrick Mooney sc->vsc_control_port.vsp_txq = 2;
7484c87aefeSPatrick Mooney sc->vsc_control_port.vsp_rxq = 3;
7494c87aefeSPatrick Mooney sc->vsc_control_port.vsp_cb = pci_vtcon_control_tx;
7504c87aefeSPatrick Mooney sc->vsc_control_port.vsp_enabled = true;
7514c87aefeSPatrick Mooney
7522b948146SAndy Fiddaman ports_nvl = find_relative_config_node(nvl, "port");
7532b948146SAndy Fiddaman if (ports_nvl != NULL) {
7542b948146SAndy Fiddaman const char *name;
7552b948146SAndy Fiddaman void *cookie;
7562b948146SAndy Fiddaman int type;
7572b948146SAndy Fiddaman
7582b948146SAndy Fiddaman cookie = NULL;
7592b948146SAndy Fiddaman while ((name = nvlist_next(ports_nvl, &type, &cookie)) !=
7602b948146SAndy Fiddaman NULL) {
7612b948146SAndy Fiddaman if (type != NV_TYPE_NVLIST)
7622b948146SAndy Fiddaman continue;
7632b948146SAndy Fiddaman
7642b948146SAndy Fiddaman if (pci_vtcon_sock_add(sc, name,
7652b948146SAndy Fiddaman nvlist_get_nvlist(ports_nvl, name)) < 0) {
7662b948146SAndy Fiddaman EPRINTLN("cannot create port %s: %s",
7672b948146SAndy Fiddaman name, strerror(errno));
7682b948146SAndy Fiddaman return (1);
7692b948146SAndy Fiddaman }
7704c87aefeSPatrick Mooney }
7714c87aefeSPatrick Mooney }
7724c87aefeSPatrick Mooney
7734c87aefeSPatrick Mooney return (0);
7744c87aefeSPatrick Mooney }
7754c87aefeSPatrick Mooney
7764f3f3e9aSAndy Fiddaman static const struct pci_devemu pci_de_vcon = {
7774c87aefeSPatrick Mooney .pe_emu = "virtio-console",
7784c87aefeSPatrick Mooney .pe_init = pci_vtcon_init,
7794c87aefeSPatrick Mooney .pe_barwrite = vi_pci_write,
7804f3f3e9aSAndy Fiddaman .pe_barread = vi_pci_read,
7814f3f3e9aSAndy Fiddaman .pe_legacy_config = pci_vtcon_legacy_config,
7824c87aefeSPatrick Mooney };
7834c87aefeSPatrick Mooney PCI_EMUL_SET(pci_de_vcon);
784