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