xref: /illumos-gate/usr/src/cmd/bhyve/pci_virtio_console.c (revision 4c87aefe8930bd07275b8dd2e96ea5f24d93a52e)
1*4c87aefeSPatrick Mooney /*-
2*4c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*4c87aefeSPatrick Mooney  *
4*4c87aefeSPatrick Mooney  * Copyright (c) 2016 iXsystems Inc.
5*4c87aefeSPatrick Mooney  * All rights reserved.
6*4c87aefeSPatrick Mooney  *
7*4c87aefeSPatrick Mooney  * This software was developed by Jakub Klama <jceel@FreeBSD.org>
8*4c87aefeSPatrick Mooney  * under sponsorship from iXsystems Inc.
9*4c87aefeSPatrick Mooney  *
10*4c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
11*4c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
12*4c87aefeSPatrick Mooney  * are met:
13*4c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
14*4c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer
15*4c87aefeSPatrick Mooney  *    in this position and unchanged.
16*4c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
17*4c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
18*4c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
19*4c87aefeSPatrick Mooney  *
20*4c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*4c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*4c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*4c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*4c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*4c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*4c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*4c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*4c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*4c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*4c87aefeSPatrick Mooney  * SUCH DAMAGE.
31*4c87aefeSPatrick Mooney  */
32*4c87aefeSPatrick Mooney 
33*4c87aefeSPatrick Mooney /*
34*4c87aefeSPatrick Mooney  * Copyright 2018 Joyent, Inc.
35*4c87aefeSPatrick Mooney  */
36*4c87aefeSPatrick Mooney 
37*4c87aefeSPatrick Mooney #include <sys/cdefs.h>
38*4c87aefeSPatrick Mooney __FBSDID("$FreeBSD$");
39*4c87aefeSPatrick Mooney 
40*4c87aefeSPatrick Mooney #include <sys/param.h>
41*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
42*4c87aefeSPatrick Mooney #include <sys/capsicum.h>
43*4c87aefeSPatrick Mooney #endif
44*4c87aefeSPatrick Mooney #include <sys/linker_set.h>
45*4c87aefeSPatrick Mooney #include <sys/uio.h>
46*4c87aefeSPatrick Mooney #include <sys/types.h>
47*4c87aefeSPatrick Mooney #include <sys/socket.h>
48*4c87aefeSPatrick Mooney #include <sys/un.h>
49*4c87aefeSPatrick Mooney 
50*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
51*4c87aefeSPatrick Mooney #include <capsicum_helpers.h>
52*4c87aefeSPatrick Mooney #endif
53*4c87aefeSPatrick Mooney #include <err.h>
54*4c87aefeSPatrick Mooney #include <errno.h>
55*4c87aefeSPatrick Mooney #include <fcntl.h>
56*4c87aefeSPatrick Mooney #include <stdio.h>
57*4c87aefeSPatrick Mooney #include <stdlib.h>
58*4c87aefeSPatrick Mooney #include <stdbool.h>
59*4c87aefeSPatrick Mooney #include <string.h>
60*4c87aefeSPatrick Mooney #include <unistd.h>
61*4c87aefeSPatrick Mooney #include <assert.h>
62*4c87aefeSPatrick Mooney #include <pthread.h>
63*4c87aefeSPatrick Mooney #include <libgen.h>
64*4c87aefeSPatrick Mooney #include <sysexits.h>
65*4c87aefeSPatrick Mooney 
66*4c87aefeSPatrick Mooney #include "bhyverun.h"
67*4c87aefeSPatrick Mooney #include "pci_emul.h"
68*4c87aefeSPatrick Mooney #include "virtio.h"
69*4c87aefeSPatrick Mooney #include "mevent.h"
70*4c87aefeSPatrick Mooney #include "sockstream.h"
71*4c87aefeSPatrick Mooney 
72*4c87aefeSPatrick Mooney #define	VTCON_RINGSZ	64
73*4c87aefeSPatrick Mooney #define	VTCON_MAXPORTS	16
74*4c87aefeSPatrick Mooney #define	VTCON_MAXQ	(VTCON_MAXPORTS * 2 + 2)
75*4c87aefeSPatrick Mooney 
76*4c87aefeSPatrick Mooney #define	VTCON_DEVICE_READY	0
77*4c87aefeSPatrick Mooney #define	VTCON_DEVICE_ADD	1
78*4c87aefeSPatrick Mooney #define	VTCON_DEVICE_REMOVE	2
79*4c87aefeSPatrick Mooney #define	VTCON_PORT_READY	3
80*4c87aefeSPatrick Mooney #define	VTCON_CONSOLE_PORT	4
81*4c87aefeSPatrick Mooney #define	VTCON_CONSOLE_RESIZE	5
82*4c87aefeSPatrick Mooney #define	VTCON_PORT_OPEN		6
83*4c87aefeSPatrick Mooney #define	VTCON_PORT_NAME		7
84*4c87aefeSPatrick Mooney 
85*4c87aefeSPatrick Mooney #define	VTCON_F_SIZE		0
86*4c87aefeSPatrick Mooney #define	VTCON_F_MULTIPORT	1
87*4c87aefeSPatrick Mooney #define	VTCON_F_EMERG_WRITE	2
88*4c87aefeSPatrick Mooney #define	VTCON_S_HOSTCAPS	\
89*4c87aefeSPatrick Mooney     (VTCON_F_SIZE | VTCON_F_MULTIPORT | VTCON_F_EMERG_WRITE)
90*4c87aefeSPatrick Mooney 
91*4c87aefeSPatrick Mooney static int pci_vtcon_debug;
92*4c87aefeSPatrick Mooney #define DPRINTF(params) if (pci_vtcon_debug) printf params
93*4c87aefeSPatrick Mooney #define WPRINTF(params) printf params
94*4c87aefeSPatrick Mooney 
95*4c87aefeSPatrick Mooney struct pci_vtcon_softc;
96*4c87aefeSPatrick Mooney struct pci_vtcon_port;
97*4c87aefeSPatrick Mooney struct pci_vtcon_config;
98*4c87aefeSPatrick Mooney typedef void (pci_vtcon_cb_t)(struct pci_vtcon_port *, void *, struct iovec *,
99*4c87aefeSPatrick Mooney     int);
100*4c87aefeSPatrick Mooney 
101*4c87aefeSPatrick Mooney struct pci_vtcon_port {
102*4c87aefeSPatrick Mooney 	struct pci_vtcon_softc * vsp_sc;
103*4c87aefeSPatrick Mooney 	int                      vsp_id;
104*4c87aefeSPatrick Mooney 	const char *             vsp_name;
105*4c87aefeSPatrick Mooney 	bool                     vsp_enabled;
106*4c87aefeSPatrick Mooney 	bool                     vsp_console;
107*4c87aefeSPatrick Mooney 	bool                     vsp_rx_ready;
108*4c87aefeSPatrick Mooney 	bool                     vsp_open;
109*4c87aefeSPatrick Mooney 	int                      vsp_rxq;
110*4c87aefeSPatrick Mooney 	int                      vsp_txq;
111*4c87aefeSPatrick Mooney 	void *                   vsp_arg;
112*4c87aefeSPatrick Mooney 	pci_vtcon_cb_t *         vsp_cb;
113*4c87aefeSPatrick Mooney };
114*4c87aefeSPatrick Mooney 
115*4c87aefeSPatrick Mooney struct pci_vtcon_sock
116*4c87aefeSPatrick Mooney {
117*4c87aefeSPatrick Mooney 	struct pci_vtcon_port *  vss_port;
118*4c87aefeSPatrick Mooney 	const char *             vss_path;
119*4c87aefeSPatrick Mooney 	struct mevent *          vss_server_evp;
120*4c87aefeSPatrick Mooney 	struct mevent *          vss_conn_evp;
121*4c87aefeSPatrick Mooney 	int                      vss_server_fd;
122*4c87aefeSPatrick Mooney 	int                      vss_conn_fd;
123*4c87aefeSPatrick Mooney 	bool                     vss_open;
124*4c87aefeSPatrick Mooney };
125*4c87aefeSPatrick Mooney 
126*4c87aefeSPatrick Mooney struct pci_vtcon_softc {
127*4c87aefeSPatrick Mooney 	struct virtio_softc      vsc_vs;
128*4c87aefeSPatrick Mooney 	struct vqueue_info       vsc_queues[VTCON_MAXQ];
129*4c87aefeSPatrick Mooney 	pthread_mutex_t          vsc_mtx;
130*4c87aefeSPatrick Mooney 	uint64_t                 vsc_cfg;
131*4c87aefeSPatrick Mooney 	uint64_t                 vsc_features;
132*4c87aefeSPatrick Mooney 	char *                   vsc_rootdir;
133*4c87aefeSPatrick Mooney 	int                      vsc_kq;
134*4c87aefeSPatrick Mooney 	int                      vsc_nports;
135*4c87aefeSPatrick Mooney 	bool                     vsc_ready;
136*4c87aefeSPatrick Mooney 	struct pci_vtcon_port    vsc_control_port;
137*4c87aefeSPatrick Mooney  	struct pci_vtcon_port    vsc_ports[VTCON_MAXPORTS];
138*4c87aefeSPatrick Mooney 	struct pci_vtcon_config *vsc_config;
139*4c87aefeSPatrick Mooney };
140*4c87aefeSPatrick Mooney 
141*4c87aefeSPatrick Mooney struct pci_vtcon_config {
142*4c87aefeSPatrick Mooney 	uint16_t cols;
143*4c87aefeSPatrick Mooney 	uint16_t rows;
144*4c87aefeSPatrick Mooney 	uint32_t max_nr_ports;
145*4c87aefeSPatrick Mooney 	uint32_t emerg_wr;
146*4c87aefeSPatrick Mooney } __attribute__((packed));
147*4c87aefeSPatrick Mooney 
148*4c87aefeSPatrick Mooney struct pci_vtcon_control {
149*4c87aefeSPatrick Mooney 	uint32_t id;
150*4c87aefeSPatrick Mooney 	uint16_t event;
151*4c87aefeSPatrick Mooney 	uint16_t value;
152*4c87aefeSPatrick Mooney } __attribute__((packed));
153*4c87aefeSPatrick Mooney 
154*4c87aefeSPatrick Mooney struct pci_vtcon_console_resize {
155*4c87aefeSPatrick Mooney 	uint16_t cols;
156*4c87aefeSPatrick Mooney 	uint16_t rows;
157*4c87aefeSPatrick Mooney } __attribute__((packed));
158*4c87aefeSPatrick Mooney 
159*4c87aefeSPatrick Mooney static void pci_vtcon_reset(void *);
160*4c87aefeSPatrick Mooney static void pci_vtcon_notify_rx(void *, struct vqueue_info *);
161*4c87aefeSPatrick Mooney static void pci_vtcon_notify_tx(void *, struct vqueue_info *);
162*4c87aefeSPatrick Mooney static int pci_vtcon_cfgread(void *, int, int, uint32_t *);
163*4c87aefeSPatrick Mooney static int pci_vtcon_cfgwrite(void *, int, int, uint32_t);
164*4c87aefeSPatrick Mooney static void pci_vtcon_neg_features(void *, uint64_t);
165*4c87aefeSPatrick Mooney static void pci_vtcon_sock_accept(int, enum ev_type,  void *);
166*4c87aefeSPatrick Mooney static void pci_vtcon_sock_rx(int, enum ev_type, void *);
167*4c87aefeSPatrick Mooney static void pci_vtcon_sock_tx(struct pci_vtcon_port *, void *, struct iovec *,
168*4c87aefeSPatrick Mooney     int);
169*4c87aefeSPatrick Mooney static void pci_vtcon_control_send(struct pci_vtcon_softc *,
170*4c87aefeSPatrick Mooney     struct pci_vtcon_control *, const void *, size_t);
171*4c87aefeSPatrick Mooney static void pci_vtcon_announce_port(struct pci_vtcon_port *);
172*4c87aefeSPatrick Mooney static void pci_vtcon_open_port(struct pci_vtcon_port *, bool);
173*4c87aefeSPatrick Mooney 
174*4c87aefeSPatrick Mooney static struct virtio_consts vtcon_vi_consts = {
175*4c87aefeSPatrick Mooney 	"vtcon",		/* our name */
176*4c87aefeSPatrick Mooney 	VTCON_MAXQ,		/* we support VTCON_MAXQ virtqueues */
177*4c87aefeSPatrick Mooney 	sizeof(struct pci_vtcon_config), /* config reg size */
178*4c87aefeSPatrick Mooney 	pci_vtcon_reset,	/* reset */
179*4c87aefeSPatrick Mooney 	NULL,			/* device-wide qnotify */
180*4c87aefeSPatrick Mooney 	pci_vtcon_cfgread,	/* read virtio config */
181*4c87aefeSPatrick Mooney 	pci_vtcon_cfgwrite,	/* write virtio config */
182*4c87aefeSPatrick Mooney 	pci_vtcon_neg_features,	/* apply negotiated features */
183*4c87aefeSPatrick Mooney 	VTCON_S_HOSTCAPS,	/* our capabilities */
184*4c87aefeSPatrick Mooney };
185*4c87aefeSPatrick Mooney 
186*4c87aefeSPatrick Mooney 
187*4c87aefeSPatrick Mooney static void
188*4c87aefeSPatrick Mooney pci_vtcon_reset(void *vsc)
189*4c87aefeSPatrick Mooney {
190*4c87aefeSPatrick Mooney 	struct pci_vtcon_softc *sc;
191*4c87aefeSPatrick Mooney 
192*4c87aefeSPatrick Mooney 	sc = vsc;
193*4c87aefeSPatrick Mooney 
194*4c87aefeSPatrick Mooney 	DPRINTF(("vtcon: device reset requested!\n"));
195*4c87aefeSPatrick Mooney 	vi_reset_dev(&sc->vsc_vs);
196*4c87aefeSPatrick Mooney }
197*4c87aefeSPatrick Mooney 
198*4c87aefeSPatrick Mooney static void
199*4c87aefeSPatrick Mooney pci_vtcon_neg_features(void *vsc, uint64_t negotiated_features)
200*4c87aefeSPatrick Mooney {
201*4c87aefeSPatrick Mooney 	struct pci_vtcon_softc *sc = vsc;
202*4c87aefeSPatrick Mooney 
203*4c87aefeSPatrick Mooney 	sc->vsc_features = negotiated_features;
204*4c87aefeSPatrick Mooney }
205*4c87aefeSPatrick Mooney 
206*4c87aefeSPatrick Mooney static int
207*4c87aefeSPatrick Mooney pci_vtcon_cfgread(void *vsc, int offset, int size, uint32_t *retval)
208*4c87aefeSPatrick Mooney {
209*4c87aefeSPatrick Mooney 	struct pci_vtcon_softc *sc = vsc;
210*4c87aefeSPatrick Mooney 	void *ptr;
211*4c87aefeSPatrick Mooney 
212*4c87aefeSPatrick Mooney 	ptr = (uint8_t *)sc->vsc_config + offset;
213*4c87aefeSPatrick Mooney 	memcpy(retval, ptr, size);
214*4c87aefeSPatrick Mooney 	return (0);
215*4c87aefeSPatrick Mooney }
216*4c87aefeSPatrick Mooney 
217*4c87aefeSPatrick Mooney static int
218*4c87aefeSPatrick Mooney pci_vtcon_cfgwrite(void *vsc, int offset, int size, uint32_t val)
219*4c87aefeSPatrick Mooney {
220*4c87aefeSPatrick Mooney 
221*4c87aefeSPatrick Mooney 	return (0);
222*4c87aefeSPatrick Mooney }
223*4c87aefeSPatrick Mooney 
224*4c87aefeSPatrick Mooney static inline struct pci_vtcon_port *
225*4c87aefeSPatrick Mooney pci_vtcon_vq_to_port(struct pci_vtcon_softc *sc, struct vqueue_info *vq)
226*4c87aefeSPatrick Mooney {
227*4c87aefeSPatrick Mooney 	uint16_t num = vq->vq_num;
228*4c87aefeSPatrick Mooney 
229*4c87aefeSPatrick Mooney 	if (num == 0 || num == 1)
230*4c87aefeSPatrick Mooney 		return (&sc->vsc_ports[0]);
231*4c87aefeSPatrick Mooney 
232*4c87aefeSPatrick Mooney 	if (num == 2 || num == 3)
233*4c87aefeSPatrick Mooney 		return (&sc->vsc_control_port);
234*4c87aefeSPatrick Mooney 
235*4c87aefeSPatrick Mooney 	return (&sc->vsc_ports[(num / 2) - 1]);
236*4c87aefeSPatrick Mooney }
237*4c87aefeSPatrick Mooney 
238*4c87aefeSPatrick Mooney static inline struct vqueue_info *
239*4c87aefeSPatrick Mooney pci_vtcon_port_to_vq(struct pci_vtcon_port *port, bool tx_queue)
240*4c87aefeSPatrick Mooney {
241*4c87aefeSPatrick Mooney 	int qnum;
242*4c87aefeSPatrick Mooney 
243*4c87aefeSPatrick Mooney 	qnum = tx_queue ? port->vsp_txq : port->vsp_rxq;
244*4c87aefeSPatrick Mooney 	return (&port->vsp_sc->vsc_queues[qnum]);
245*4c87aefeSPatrick Mooney }
246*4c87aefeSPatrick Mooney 
247*4c87aefeSPatrick Mooney static struct pci_vtcon_port *
248*4c87aefeSPatrick Mooney pci_vtcon_port_add(struct pci_vtcon_softc *sc, const char *name,
249*4c87aefeSPatrick Mooney     pci_vtcon_cb_t *cb, void *arg)
250*4c87aefeSPatrick Mooney {
251*4c87aefeSPatrick Mooney 	struct pci_vtcon_port *port;
252*4c87aefeSPatrick Mooney 
253*4c87aefeSPatrick Mooney 	if (sc->vsc_nports == VTCON_MAXPORTS) {
254*4c87aefeSPatrick Mooney 		errno = EBUSY;
255*4c87aefeSPatrick Mooney 		return (NULL);
256*4c87aefeSPatrick Mooney 	}
257*4c87aefeSPatrick Mooney 
258*4c87aefeSPatrick Mooney 	port = &sc->vsc_ports[sc->vsc_nports++];
259*4c87aefeSPatrick Mooney 	port->vsp_id = sc->vsc_nports - 1;
260*4c87aefeSPatrick Mooney 	port->vsp_sc = sc;
261*4c87aefeSPatrick Mooney 	port->vsp_name = name;
262*4c87aefeSPatrick Mooney 	port->vsp_cb = cb;
263*4c87aefeSPatrick Mooney 	port->vsp_arg = arg;
264*4c87aefeSPatrick Mooney 
265*4c87aefeSPatrick Mooney 	if (port->vsp_id == 0) {
266*4c87aefeSPatrick Mooney 		/* port0 */
267*4c87aefeSPatrick Mooney 		port->vsp_txq = 0;
268*4c87aefeSPatrick Mooney 		port->vsp_rxq = 1;
269*4c87aefeSPatrick Mooney 	} else {
270*4c87aefeSPatrick Mooney 		port->vsp_txq = sc->vsc_nports * 2;
271*4c87aefeSPatrick Mooney 		port->vsp_rxq = port->vsp_txq + 1;
272*4c87aefeSPatrick Mooney 	}
273*4c87aefeSPatrick Mooney 
274*4c87aefeSPatrick Mooney 	port->vsp_enabled = true;
275*4c87aefeSPatrick Mooney 	return (port);
276*4c87aefeSPatrick Mooney }
277*4c87aefeSPatrick Mooney 
278*4c87aefeSPatrick Mooney static int
279*4c87aefeSPatrick Mooney pci_vtcon_sock_add(struct pci_vtcon_softc *sc, const char *name,
280*4c87aefeSPatrick Mooney     const char *path)
281*4c87aefeSPatrick Mooney {
282*4c87aefeSPatrick Mooney 	struct pci_vtcon_sock *sock;
283*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
284*4c87aefeSPatrick Mooney 	struct sockaddr_un sun;
285*4c87aefeSPatrick Mooney 	char *pathcopy;
286*4c87aefeSPatrick Mooney #else
287*4c87aefeSPatrick Mooney 	/* Our compiler #defines 'sun' as '1'.  Awesome. */
288*4c87aefeSPatrick Mooney 	struct sockaddr_un addr;
289*4c87aefeSPatrick Mooney #endif
290*4c87aefeSPatrick Mooney 	int s = -1, fd = -1, error = 0;
291*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
292*4c87aefeSPatrick Mooney 	cap_rights_t rights;
293*4c87aefeSPatrick Mooney #endif
294*4c87aefeSPatrick Mooney 
295*4c87aefeSPatrick Mooney 	sock = calloc(1, sizeof(struct pci_vtcon_sock));
296*4c87aefeSPatrick Mooney 	if (sock == NULL) {
297*4c87aefeSPatrick Mooney 		error = -1;
298*4c87aefeSPatrick Mooney 		goto out;
299*4c87aefeSPatrick Mooney 	}
300*4c87aefeSPatrick Mooney 
301*4c87aefeSPatrick Mooney 	s = socket(AF_UNIX, SOCK_STREAM, 0);
302*4c87aefeSPatrick Mooney 	if (s < 0) {
303*4c87aefeSPatrick Mooney 		error = -1;
304*4c87aefeSPatrick Mooney 		goto out;
305*4c87aefeSPatrick Mooney 	}
306*4c87aefeSPatrick Mooney 
307*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
308*4c87aefeSPatrick Mooney 	pathcopy = strdup(path);
309*4c87aefeSPatrick Mooney 	if (pathcopy == NULL) {
310*4c87aefeSPatrick Mooney 		error = -1;
311*4c87aefeSPatrick Mooney 		goto out;
312*4c87aefeSPatrick Mooney 	}
313*4c87aefeSPatrick Mooney 
314*4c87aefeSPatrick Mooney 	fd = open(dirname(pathcopy), O_RDONLY | O_DIRECTORY);
315*4c87aefeSPatrick Mooney 	if (fd < 0) {
316*4c87aefeSPatrick Mooney 		free(pathcopy);
317*4c87aefeSPatrick Mooney 		error = -1;
318*4c87aefeSPatrick Mooney 		goto out;
319*4c87aefeSPatrick Mooney 	}
320*4c87aefeSPatrick Mooney 
321*4c87aefeSPatrick Mooney 	sun.sun_family = AF_UNIX;
322*4c87aefeSPatrick Mooney 	sun.sun_len = sizeof(struct sockaddr_un);
323*4c87aefeSPatrick Mooney 	strcpy(pathcopy, path);
324*4c87aefeSPatrick Mooney 	strlcpy(sun.sun_path, basename(pathcopy), sizeof(sun.sun_path));
325*4c87aefeSPatrick Mooney 	free(pathcopy);
326*4c87aefeSPatrick Mooney 
327*4c87aefeSPatrick Mooney 	if (bindat(fd, s, (struct sockaddr *)&sun, sun.sun_len) < 0) {
328*4c87aefeSPatrick Mooney 		error = -1;
329*4c87aefeSPatrick Mooney 		goto out;
330*4c87aefeSPatrick Mooney 	}
331*4c87aefeSPatrick Mooney #else /* __FreeBSD__ */
332*4c87aefeSPatrick Mooney 	/* Do a simple bind rather than the FreeBSD bindat() */
333*4c87aefeSPatrick Mooney 	addr.sun_family = AF_UNIX;
334*4c87aefeSPatrick Mooney 	(void) strlcpy(addr.sun_path, path, sizeof (addr.sun_path));
335*4c87aefeSPatrick Mooney 	if (bind(fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) {
336*4c87aefeSPatrick Mooney 		error = -1;
337*4c87aefeSPatrick Mooney 		goto out;
338*4c87aefeSPatrick Mooney 	}
339*4c87aefeSPatrick Mooney #endif /* __FreeBSD__ */
340*4c87aefeSPatrick Mooney 
341*4c87aefeSPatrick Mooney 	if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
342*4c87aefeSPatrick Mooney 		error = -1;
343*4c87aefeSPatrick Mooney 		goto out;
344*4c87aefeSPatrick Mooney 	}
345*4c87aefeSPatrick Mooney 
346*4c87aefeSPatrick Mooney 	if (listen(s, 1) < 0) {
347*4c87aefeSPatrick Mooney 		error = -1;
348*4c87aefeSPatrick Mooney 		goto out;
349*4c87aefeSPatrick Mooney 	}
350*4c87aefeSPatrick Mooney 
351*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM
352*4c87aefeSPatrick Mooney 	cap_rights_init(&rights, CAP_ACCEPT, CAP_EVENT, CAP_READ, CAP_WRITE);
353*4c87aefeSPatrick Mooney 	if (caph_rights_limit(s, &rights) == -1)
354*4c87aefeSPatrick Mooney 		errx(EX_OSERR, "Unable to apply rights for sandbox");
355*4c87aefeSPatrick Mooney #endif
356*4c87aefeSPatrick Mooney 
357*4c87aefeSPatrick Mooney 	sock->vss_port = pci_vtcon_port_add(sc, name, pci_vtcon_sock_tx, sock);
358*4c87aefeSPatrick Mooney 	if (sock->vss_port == NULL) {
359*4c87aefeSPatrick Mooney 		error = -1;
360*4c87aefeSPatrick Mooney 		goto out;
361*4c87aefeSPatrick Mooney 	}
362*4c87aefeSPatrick Mooney 
363*4c87aefeSPatrick Mooney 	sock->vss_open = false;
364*4c87aefeSPatrick Mooney 	sock->vss_conn_fd = -1;
365*4c87aefeSPatrick Mooney 	sock->vss_server_fd = s;
366*4c87aefeSPatrick Mooney 	sock->vss_server_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_accept,
367*4c87aefeSPatrick Mooney 	    sock);
368*4c87aefeSPatrick Mooney 
369*4c87aefeSPatrick Mooney 	if (sock->vss_server_evp == NULL) {
370*4c87aefeSPatrick Mooney 		error = -1;
371*4c87aefeSPatrick Mooney 		goto out;
372*4c87aefeSPatrick Mooney 	}
373*4c87aefeSPatrick Mooney 
374*4c87aefeSPatrick Mooney out:
375*4c87aefeSPatrick Mooney 	if (fd != -1)
376*4c87aefeSPatrick Mooney 		close(fd);
377*4c87aefeSPatrick Mooney 
378*4c87aefeSPatrick Mooney 	if (error != 0 && s != -1)
379*4c87aefeSPatrick Mooney 		close(s);
380*4c87aefeSPatrick Mooney 
381*4c87aefeSPatrick Mooney 	return (error);
382*4c87aefeSPatrick Mooney }
383*4c87aefeSPatrick Mooney 
384*4c87aefeSPatrick Mooney static void
385*4c87aefeSPatrick Mooney pci_vtcon_sock_accept(int fd __unused, enum ev_type t __unused, void *arg)
386*4c87aefeSPatrick Mooney {
387*4c87aefeSPatrick Mooney 	struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg;
388*4c87aefeSPatrick Mooney 	int s;
389*4c87aefeSPatrick Mooney 
390*4c87aefeSPatrick Mooney 	s = accept(sock->vss_server_fd, NULL, NULL);
391*4c87aefeSPatrick Mooney 	if (s < 0)
392*4c87aefeSPatrick Mooney 		return;
393*4c87aefeSPatrick Mooney 
394*4c87aefeSPatrick Mooney 	if (sock->vss_open) {
395*4c87aefeSPatrick Mooney 		close(s);
396*4c87aefeSPatrick Mooney 		return;
397*4c87aefeSPatrick Mooney 	}
398*4c87aefeSPatrick Mooney 
399*4c87aefeSPatrick Mooney 	sock->vss_open = true;
400*4c87aefeSPatrick Mooney 	sock->vss_conn_fd = s;
401*4c87aefeSPatrick Mooney 	sock->vss_conn_evp = mevent_add(s, EVF_READ, pci_vtcon_sock_rx, sock);
402*4c87aefeSPatrick Mooney 
403*4c87aefeSPatrick Mooney 	pci_vtcon_open_port(sock->vss_port, true);
404*4c87aefeSPatrick Mooney }
405*4c87aefeSPatrick Mooney 
406*4c87aefeSPatrick Mooney static void
407*4c87aefeSPatrick Mooney pci_vtcon_sock_rx(int fd __unused, enum ev_type t __unused, void *arg)
408*4c87aefeSPatrick Mooney {
409*4c87aefeSPatrick Mooney 	struct pci_vtcon_port *port;
410*4c87aefeSPatrick Mooney 	struct pci_vtcon_sock *sock = (struct pci_vtcon_sock *)arg;
411*4c87aefeSPatrick Mooney 	struct vqueue_info *vq;
412*4c87aefeSPatrick Mooney 	struct iovec iov;
413*4c87aefeSPatrick Mooney 	static char dummybuf[2048];
414*4c87aefeSPatrick Mooney 	int len, n;
415*4c87aefeSPatrick Mooney 	uint16_t idx;
416*4c87aefeSPatrick Mooney 
417*4c87aefeSPatrick Mooney 	port = sock->vss_port;
418*4c87aefeSPatrick Mooney 	vq = pci_vtcon_port_to_vq(port, true);
419*4c87aefeSPatrick Mooney 
420*4c87aefeSPatrick Mooney 	if (!sock->vss_open || !port->vsp_rx_ready) {
421*4c87aefeSPatrick Mooney 		len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf));
422*4c87aefeSPatrick Mooney 		if (len == 0)
423*4c87aefeSPatrick Mooney 			goto close;
424*4c87aefeSPatrick Mooney 
425*4c87aefeSPatrick Mooney 		return;
426*4c87aefeSPatrick Mooney 	}
427*4c87aefeSPatrick Mooney 
428*4c87aefeSPatrick Mooney 	if (!vq_has_descs(vq)) {
429*4c87aefeSPatrick Mooney 		len = read(sock->vss_conn_fd, dummybuf, sizeof(dummybuf));
430*4c87aefeSPatrick Mooney 		vq_endchains(vq, 1);
431*4c87aefeSPatrick Mooney 		if (len == 0)
432*4c87aefeSPatrick Mooney 			goto close;
433*4c87aefeSPatrick Mooney 
434*4c87aefeSPatrick Mooney 		return;
435*4c87aefeSPatrick Mooney 	}
436*4c87aefeSPatrick Mooney 
437*4c87aefeSPatrick Mooney 	do {
438*4c87aefeSPatrick Mooney 		n = vq_getchain(vq, &idx, &iov, 1, NULL);
439*4c87aefeSPatrick Mooney 		len = readv(sock->vss_conn_fd, &iov, n);
440*4c87aefeSPatrick Mooney 
441*4c87aefeSPatrick Mooney 		if (len == 0 || (len < 0 && errno == EWOULDBLOCK)) {
442*4c87aefeSPatrick Mooney 			vq_retchain(vq);
443*4c87aefeSPatrick Mooney 			vq_endchains(vq, 0);
444*4c87aefeSPatrick Mooney 			if (len == 0)
445*4c87aefeSPatrick Mooney 				goto close;
446*4c87aefeSPatrick Mooney 
447*4c87aefeSPatrick Mooney 			return;
448*4c87aefeSPatrick Mooney 		}
449*4c87aefeSPatrick Mooney 
450*4c87aefeSPatrick Mooney 		vq_relchain(vq, idx, len);
451*4c87aefeSPatrick Mooney 	} while (vq_has_descs(vq));
452*4c87aefeSPatrick Mooney 
453*4c87aefeSPatrick Mooney 	vq_endchains(vq, 1);
454*4c87aefeSPatrick Mooney 
455*4c87aefeSPatrick Mooney close:
456*4c87aefeSPatrick Mooney 	mevent_delete_close(sock->vss_conn_evp);
457*4c87aefeSPatrick Mooney 	sock->vss_conn_fd = -1;
458*4c87aefeSPatrick Mooney 	sock->vss_open = false;
459*4c87aefeSPatrick Mooney }
460*4c87aefeSPatrick Mooney 
461*4c87aefeSPatrick Mooney static void
462*4c87aefeSPatrick Mooney pci_vtcon_sock_tx(struct pci_vtcon_port *port, void *arg, struct iovec *iov,
463*4c87aefeSPatrick Mooney     int niov)
464*4c87aefeSPatrick Mooney {
465*4c87aefeSPatrick Mooney 	struct pci_vtcon_sock *sock;
466*4c87aefeSPatrick Mooney #ifdef __FreeBSD__
467*4c87aefeSPatrick Mooney 	int i, ret;
468*4c87aefeSPatrick Mooney #else
469*4c87aefeSPatrick Mooney 	int i, ret = 0;
470*4c87aefeSPatrick Mooney #endif
471*4c87aefeSPatrick Mooney 
472*4c87aefeSPatrick Mooney 	sock = (struct pci_vtcon_sock *)arg;
473*4c87aefeSPatrick Mooney 
474*4c87aefeSPatrick Mooney 	if (sock->vss_conn_fd == -1)
475*4c87aefeSPatrick Mooney 		return;
476*4c87aefeSPatrick Mooney 
477*4c87aefeSPatrick Mooney 	for (i = 0; i < niov; i++) {
478*4c87aefeSPatrick Mooney 		ret = stream_write(sock->vss_conn_fd, iov[i].iov_base,
479*4c87aefeSPatrick Mooney 		    iov[i].iov_len);
480*4c87aefeSPatrick Mooney 		if (ret <= 0)
481*4c87aefeSPatrick Mooney 			break;
482*4c87aefeSPatrick Mooney 	}
483*4c87aefeSPatrick Mooney 
484*4c87aefeSPatrick Mooney 	if (ret <= 0) {
485*4c87aefeSPatrick Mooney 		mevent_delete_close(sock->vss_conn_evp);
486*4c87aefeSPatrick Mooney 		sock->vss_conn_fd = -1;
487*4c87aefeSPatrick Mooney 		sock->vss_open = false;
488*4c87aefeSPatrick Mooney 	}
489*4c87aefeSPatrick Mooney }
490*4c87aefeSPatrick Mooney 
491*4c87aefeSPatrick Mooney static void
492*4c87aefeSPatrick Mooney pci_vtcon_control_tx(struct pci_vtcon_port *port, void *arg, struct iovec *iov,
493*4c87aefeSPatrick Mooney     int niov)
494*4c87aefeSPatrick Mooney {
495*4c87aefeSPatrick Mooney 	struct pci_vtcon_softc *sc;
496*4c87aefeSPatrick Mooney 	struct pci_vtcon_port *tmp;
497*4c87aefeSPatrick Mooney 	struct pci_vtcon_control resp, *ctrl;
498*4c87aefeSPatrick Mooney 	int i;
499*4c87aefeSPatrick Mooney 
500*4c87aefeSPatrick Mooney 	assert(niov == 1);
501*4c87aefeSPatrick Mooney 
502*4c87aefeSPatrick Mooney 	sc = port->vsp_sc;
503*4c87aefeSPatrick Mooney 	ctrl = (struct pci_vtcon_control *)iov->iov_base;
504*4c87aefeSPatrick Mooney 
505*4c87aefeSPatrick Mooney 	switch (ctrl->event) {
506*4c87aefeSPatrick Mooney 	case VTCON_DEVICE_READY:
507*4c87aefeSPatrick Mooney 		sc->vsc_ready = true;
508*4c87aefeSPatrick Mooney 		/* set port ready events for registered ports */
509*4c87aefeSPatrick Mooney 		for (i = 0; i < VTCON_MAXPORTS; i++) {
510*4c87aefeSPatrick Mooney 			tmp = &sc->vsc_ports[i];
511*4c87aefeSPatrick Mooney 			if (tmp->vsp_enabled)
512*4c87aefeSPatrick Mooney 				pci_vtcon_announce_port(tmp);
513*4c87aefeSPatrick Mooney 
514*4c87aefeSPatrick Mooney 			if (tmp->vsp_open)
515*4c87aefeSPatrick Mooney 				pci_vtcon_open_port(tmp, true);
516*4c87aefeSPatrick Mooney 		}
517*4c87aefeSPatrick Mooney 		break;
518*4c87aefeSPatrick Mooney 
519*4c87aefeSPatrick Mooney 	case VTCON_PORT_READY:
520*4c87aefeSPatrick Mooney 		if (ctrl->id >= sc->vsc_nports) {
521*4c87aefeSPatrick Mooney 			WPRINTF(("VTCON_PORT_READY event for unknown port %d\n",
522*4c87aefeSPatrick Mooney 			    ctrl->id));
523*4c87aefeSPatrick Mooney 			return;
524*4c87aefeSPatrick Mooney 		}
525*4c87aefeSPatrick Mooney 
526*4c87aefeSPatrick Mooney 		tmp = &sc->vsc_ports[ctrl->id];
527*4c87aefeSPatrick Mooney 		if (tmp->vsp_console) {
528*4c87aefeSPatrick Mooney 			resp.event = VTCON_CONSOLE_PORT;
529*4c87aefeSPatrick Mooney 			resp.id = ctrl->id;
530*4c87aefeSPatrick Mooney 			resp.value = 1;
531*4c87aefeSPatrick Mooney 			pci_vtcon_control_send(sc, &resp, NULL, 0);
532*4c87aefeSPatrick Mooney 		}
533*4c87aefeSPatrick Mooney 		break;
534*4c87aefeSPatrick Mooney 	}
535*4c87aefeSPatrick Mooney }
536*4c87aefeSPatrick Mooney 
537*4c87aefeSPatrick Mooney static void
538*4c87aefeSPatrick Mooney pci_vtcon_announce_port(struct pci_vtcon_port *port)
539*4c87aefeSPatrick Mooney {
540*4c87aefeSPatrick Mooney 	struct pci_vtcon_control event;
541*4c87aefeSPatrick Mooney 
542*4c87aefeSPatrick Mooney 	event.id = port->vsp_id;
543*4c87aefeSPatrick Mooney 	event.event = VTCON_DEVICE_ADD;
544*4c87aefeSPatrick Mooney 	event.value = 1;
545*4c87aefeSPatrick Mooney 	pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0);
546*4c87aefeSPatrick Mooney 
547*4c87aefeSPatrick Mooney 	event.event = VTCON_PORT_NAME;
548*4c87aefeSPatrick Mooney 	pci_vtcon_control_send(port->vsp_sc, &event, port->vsp_name,
549*4c87aefeSPatrick Mooney 	    strlen(port->vsp_name));
550*4c87aefeSPatrick Mooney }
551*4c87aefeSPatrick Mooney 
552*4c87aefeSPatrick Mooney static void
553*4c87aefeSPatrick Mooney pci_vtcon_open_port(struct pci_vtcon_port *port, bool open)
554*4c87aefeSPatrick Mooney {
555*4c87aefeSPatrick Mooney 	struct pci_vtcon_control event;
556*4c87aefeSPatrick Mooney 
557*4c87aefeSPatrick Mooney 	if (!port->vsp_sc->vsc_ready) {
558*4c87aefeSPatrick Mooney 		port->vsp_open = true;
559*4c87aefeSPatrick Mooney 		return;
560*4c87aefeSPatrick Mooney 	}
561*4c87aefeSPatrick Mooney 
562*4c87aefeSPatrick Mooney 	event.id = port->vsp_id;
563*4c87aefeSPatrick Mooney 	event.event = VTCON_PORT_OPEN;
564*4c87aefeSPatrick Mooney 	event.value = (int)open;
565*4c87aefeSPatrick Mooney 	pci_vtcon_control_send(port->vsp_sc, &event, NULL, 0);
566*4c87aefeSPatrick Mooney }
567*4c87aefeSPatrick Mooney 
568*4c87aefeSPatrick Mooney static void
569*4c87aefeSPatrick Mooney pci_vtcon_control_send(struct pci_vtcon_softc *sc,
570*4c87aefeSPatrick Mooney     struct pci_vtcon_control *ctrl, const void *payload, size_t len)
571*4c87aefeSPatrick Mooney {
572*4c87aefeSPatrick Mooney 	struct vqueue_info *vq;
573*4c87aefeSPatrick Mooney 	struct iovec iov;
574*4c87aefeSPatrick Mooney 	uint16_t idx;
575*4c87aefeSPatrick Mooney 	int n;
576*4c87aefeSPatrick Mooney 
577*4c87aefeSPatrick Mooney 	vq = pci_vtcon_port_to_vq(&sc->vsc_control_port, true);
578*4c87aefeSPatrick Mooney 
579*4c87aefeSPatrick Mooney 	if (!vq_has_descs(vq))
580*4c87aefeSPatrick Mooney 		return;
581*4c87aefeSPatrick Mooney 
582*4c87aefeSPatrick Mooney 	n = vq_getchain(vq, &idx, &iov, 1, NULL);
583*4c87aefeSPatrick Mooney 
584*4c87aefeSPatrick Mooney 	assert(n == 1);
585*4c87aefeSPatrick Mooney 
586*4c87aefeSPatrick Mooney 	memcpy(iov.iov_base, ctrl, sizeof(struct pci_vtcon_control));
587*4c87aefeSPatrick Mooney 	if (payload != NULL && len > 0)
588*4c87aefeSPatrick Mooney 		memcpy(iov.iov_base + sizeof(struct pci_vtcon_control),
589*4c87aefeSPatrick Mooney 		     payload, len);
590*4c87aefeSPatrick Mooney 
591*4c87aefeSPatrick Mooney 	vq_relchain(vq, idx, sizeof(struct pci_vtcon_control) + len);
592*4c87aefeSPatrick Mooney 	vq_endchains(vq, 1);
593*4c87aefeSPatrick Mooney }
594*4c87aefeSPatrick Mooney 
595*4c87aefeSPatrick Mooney 
596*4c87aefeSPatrick Mooney static void
597*4c87aefeSPatrick Mooney pci_vtcon_notify_tx(void *vsc, struct vqueue_info *vq)
598*4c87aefeSPatrick Mooney {
599*4c87aefeSPatrick Mooney 	struct pci_vtcon_softc *sc;
600*4c87aefeSPatrick Mooney 	struct pci_vtcon_port *port;
601*4c87aefeSPatrick Mooney 	struct iovec iov[1];
602*4c87aefeSPatrick Mooney 	uint16_t idx, n;
603*4c87aefeSPatrick Mooney 	uint16_t flags[8];
604*4c87aefeSPatrick Mooney 
605*4c87aefeSPatrick Mooney 	sc = vsc;
606*4c87aefeSPatrick Mooney 	port = pci_vtcon_vq_to_port(sc, vq);
607*4c87aefeSPatrick Mooney 
608*4c87aefeSPatrick Mooney 	while (vq_has_descs(vq)) {
609*4c87aefeSPatrick Mooney 		n = vq_getchain(vq, &idx, iov, 1, flags);
610*4c87aefeSPatrick Mooney 		assert(n >= 1);
611*4c87aefeSPatrick Mooney 		if (port != NULL)
612*4c87aefeSPatrick Mooney 			port->vsp_cb(port, port->vsp_arg, iov, 1);
613*4c87aefeSPatrick Mooney 
614*4c87aefeSPatrick Mooney 		/*
615*4c87aefeSPatrick Mooney 		 * Release this chain and handle more
616*4c87aefeSPatrick Mooney 		 */
617*4c87aefeSPatrick Mooney 		vq_relchain(vq, idx, 0);
618*4c87aefeSPatrick Mooney 	}
619*4c87aefeSPatrick Mooney 	vq_endchains(vq, 1);	/* Generate interrupt if appropriate. */
620*4c87aefeSPatrick Mooney }
621*4c87aefeSPatrick Mooney 
622*4c87aefeSPatrick Mooney static void
623*4c87aefeSPatrick Mooney pci_vtcon_notify_rx(void *vsc, struct vqueue_info *vq)
624*4c87aefeSPatrick Mooney {
625*4c87aefeSPatrick Mooney 	struct pci_vtcon_softc *sc;
626*4c87aefeSPatrick Mooney 	struct pci_vtcon_port *port;
627*4c87aefeSPatrick Mooney 
628*4c87aefeSPatrick Mooney 	sc = vsc;
629*4c87aefeSPatrick Mooney 	port = pci_vtcon_vq_to_port(sc, vq);
630*4c87aefeSPatrick Mooney 
631*4c87aefeSPatrick Mooney 	if (!port->vsp_rx_ready) {
632*4c87aefeSPatrick Mooney 		port->vsp_rx_ready = 1;
633*4c87aefeSPatrick Mooney 		vq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;
634*4c87aefeSPatrick Mooney 	}
635*4c87aefeSPatrick Mooney }
636*4c87aefeSPatrick Mooney 
637*4c87aefeSPatrick Mooney static int
638*4c87aefeSPatrick Mooney pci_vtcon_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
639*4c87aefeSPatrick Mooney {
640*4c87aefeSPatrick Mooney 	struct pci_vtcon_softc *sc;
641*4c87aefeSPatrick Mooney 	char *portname = NULL;
642*4c87aefeSPatrick Mooney 	char *portpath = NULL;
643*4c87aefeSPatrick Mooney 	char *opt;
644*4c87aefeSPatrick Mooney 	int i;
645*4c87aefeSPatrick Mooney 
646*4c87aefeSPatrick Mooney 	sc = calloc(1, sizeof(struct pci_vtcon_softc));
647*4c87aefeSPatrick Mooney 	sc->vsc_config = calloc(1, sizeof(struct pci_vtcon_config));
648*4c87aefeSPatrick Mooney 	sc->vsc_config->max_nr_ports = VTCON_MAXPORTS;
649*4c87aefeSPatrick Mooney 	sc->vsc_config->cols = 80;
650*4c87aefeSPatrick Mooney 	sc->vsc_config->rows = 25;
651*4c87aefeSPatrick Mooney 
652*4c87aefeSPatrick Mooney 	vi_softc_linkup(&sc->vsc_vs, &vtcon_vi_consts, sc, pi, sc->vsc_queues);
653*4c87aefeSPatrick Mooney 	sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
654*4c87aefeSPatrick Mooney 
655*4c87aefeSPatrick Mooney 	for (i = 0; i < VTCON_MAXQ; i++) {
656*4c87aefeSPatrick Mooney 		sc->vsc_queues[i].vq_qsize = VTCON_RINGSZ;
657*4c87aefeSPatrick Mooney 		sc->vsc_queues[i].vq_notify = i % 2 == 0
658*4c87aefeSPatrick Mooney 		    ? pci_vtcon_notify_rx
659*4c87aefeSPatrick Mooney 		    : pci_vtcon_notify_tx;
660*4c87aefeSPatrick Mooney 	}
661*4c87aefeSPatrick Mooney 
662*4c87aefeSPatrick Mooney 	/* initialize config space */
663*4c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_CONSOLE);
664*4c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
665*4c87aefeSPatrick Mooney 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM);
666*4c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_CONSOLE);
667*4c87aefeSPatrick Mooney 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
668*4c87aefeSPatrick Mooney 
669*4c87aefeSPatrick Mooney 	if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
670*4c87aefeSPatrick Mooney 		return (1);
671*4c87aefeSPatrick Mooney 	vi_set_io_bar(&sc->vsc_vs, 0);
672*4c87aefeSPatrick Mooney 
673*4c87aefeSPatrick Mooney 	/* create control port */
674*4c87aefeSPatrick Mooney 	sc->vsc_control_port.vsp_sc = sc;
675*4c87aefeSPatrick Mooney 	sc->vsc_control_port.vsp_txq = 2;
676*4c87aefeSPatrick Mooney 	sc->vsc_control_port.vsp_rxq = 3;
677*4c87aefeSPatrick Mooney 	sc->vsc_control_port.vsp_cb = pci_vtcon_control_tx;
678*4c87aefeSPatrick Mooney 	sc->vsc_control_port.vsp_enabled = true;
679*4c87aefeSPatrick Mooney 
680*4c87aefeSPatrick Mooney 	while ((opt = strsep(&opts, ",")) != NULL) {
681*4c87aefeSPatrick Mooney 		portname = strsep(&opt, "=");
682*4c87aefeSPatrick Mooney 		portpath = opt;
683*4c87aefeSPatrick Mooney 
684*4c87aefeSPatrick Mooney 		/* create port */
685*4c87aefeSPatrick Mooney 		if (pci_vtcon_sock_add(sc, portname, portpath) < 0) {
686*4c87aefeSPatrick Mooney 			fprintf(stderr, "cannot create port %s: %s\n",
687*4c87aefeSPatrick Mooney 			    portname, strerror(errno));
688*4c87aefeSPatrick Mooney 			return (1);
689*4c87aefeSPatrick Mooney 		}
690*4c87aefeSPatrick Mooney 	}
691*4c87aefeSPatrick Mooney 
692*4c87aefeSPatrick Mooney 	return (0);
693*4c87aefeSPatrick Mooney }
694*4c87aefeSPatrick Mooney 
695*4c87aefeSPatrick Mooney struct pci_devemu pci_de_vcon = {
696*4c87aefeSPatrick Mooney 	.pe_emu =	"virtio-console",
697*4c87aefeSPatrick Mooney 	.pe_init =	pci_vtcon_init,
698*4c87aefeSPatrick Mooney 	.pe_barwrite =	vi_pci_write,
699*4c87aefeSPatrick Mooney 	.pe_barread =	vi_pci_read
700*4c87aefeSPatrick Mooney };
701*4c87aefeSPatrick Mooney PCI_EMUL_SET(pci_de_vcon);
702