xref: /illumos-gate/usr/src/cmd/bhyve/common/pci_virtio_9p.c (revision 5c4a5fe16715fb423db76577a6883b5bbecdbe45)
1*5c4a5fe1SAndy Fiddaman /*-
2*5c4a5fe1SAndy Fiddaman  * Copyright (c) 2015 iXsystems Inc.
3*5c4a5fe1SAndy Fiddaman  * Copyright (c) 2017-2018 Jakub Klama <jceel@FreeBSD.org>
4*5c4a5fe1SAndy Fiddaman  * All rights reserved.
5*5c4a5fe1SAndy Fiddaman  *
6*5c4a5fe1SAndy Fiddaman  * Redistribution and use in source and binary forms, with or without
7*5c4a5fe1SAndy Fiddaman  * modification, are permitted provided that the following conditions
8*5c4a5fe1SAndy Fiddaman  * are met:
9*5c4a5fe1SAndy Fiddaman  * 1. Redistributions of source code must retain the above copyright
10*5c4a5fe1SAndy Fiddaman  *    notice, this list of conditions and the following disclaimer
11*5c4a5fe1SAndy Fiddaman  *    in this position and unchanged.
12*5c4a5fe1SAndy Fiddaman  * 2. Redistributions in binary form must reproduce the above copyright
13*5c4a5fe1SAndy Fiddaman  *    notice, this list of conditions and the following disclaimer in the
14*5c4a5fe1SAndy Fiddaman  *    documentation and/or other materials provided with the distribution.
15*5c4a5fe1SAndy Fiddaman  *
16*5c4a5fe1SAndy Fiddaman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*5c4a5fe1SAndy Fiddaman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*5c4a5fe1SAndy Fiddaman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*5c4a5fe1SAndy Fiddaman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*5c4a5fe1SAndy Fiddaman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*5c4a5fe1SAndy Fiddaman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*5c4a5fe1SAndy Fiddaman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*5c4a5fe1SAndy Fiddaman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*5c4a5fe1SAndy Fiddaman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*5c4a5fe1SAndy Fiddaman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*5c4a5fe1SAndy Fiddaman  * SUCH DAMAGE.
27*5c4a5fe1SAndy Fiddaman  */
28*5c4a5fe1SAndy Fiddaman 
29*5c4a5fe1SAndy Fiddaman /*
30*5c4a5fe1SAndy Fiddaman  * VirtIO filesystem passthrough using 9p protocol.
31*5c4a5fe1SAndy Fiddaman  */
32*5c4a5fe1SAndy Fiddaman 
33*5c4a5fe1SAndy Fiddaman 
34*5c4a5fe1SAndy Fiddaman #include <sys/param.h>
35*5c4a5fe1SAndy Fiddaman #include <sys/linker_set.h>
36*5c4a5fe1SAndy Fiddaman #include <sys/uio.h>
37*5c4a5fe1SAndy Fiddaman #ifndef WITHOUT_CAPSICUM
38*5c4a5fe1SAndy Fiddaman #include <sys/capsicum.h>
39*5c4a5fe1SAndy Fiddaman #endif
40*5c4a5fe1SAndy Fiddaman 
41*5c4a5fe1SAndy Fiddaman #include <errno.h>
42*5c4a5fe1SAndy Fiddaman #include <fcntl.h>
43*5c4a5fe1SAndy Fiddaman #include <stdio.h>
44*5c4a5fe1SAndy Fiddaman #include <stdlib.h>
45*5c4a5fe1SAndy Fiddaman #include <string.h>
46*5c4a5fe1SAndy Fiddaman #include <unistd.h>
47*5c4a5fe1SAndy Fiddaman #include <assert.h>
48*5c4a5fe1SAndy Fiddaman #include <pthread.h>
49*5c4a5fe1SAndy Fiddaman 
50*5c4a5fe1SAndy Fiddaman #include <lib9p.h>
51*5c4a5fe1SAndy Fiddaman #include <backend/fs.h>
52*5c4a5fe1SAndy Fiddaman 
53*5c4a5fe1SAndy Fiddaman #include "bhyverun.h"
54*5c4a5fe1SAndy Fiddaman #include "config.h"
55*5c4a5fe1SAndy Fiddaman #include "debug.h"
56*5c4a5fe1SAndy Fiddaman #include "pci_emul.h"
57*5c4a5fe1SAndy Fiddaman #include "virtio.h"
58*5c4a5fe1SAndy Fiddaman 
59*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
60*5c4a5fe1SAndy Fiddaman #include "privileges.h"
61*5c4a5fe1SAndy Fiddaman #endif
62*5c4a5fe1SAndy Fiddaman 
63*5c4a5fe1SAndy Fiddaman #define	VT9P_MAX_IOV	128
64*5c4a5fe1SAndy Fiddaman #define VT9P_RINGSZ	256
65*5c4a5fe1SAndy Fiddaman #define	VT9P_MAXTAGSZ	256
66*5c4a5fe1SAndy Fiddaman #define	VT9P_CONFIGSPACESZ	(VT9P_MAXTAGSZ + sizeof(uint16_t))
67*5c4a5fe1SAndy Fiddaman 
68*5c4a5fe1SAndy Fiddaman static int pci_vt9p_debug;
69*5c4a5fe1SAndy Fiddaman #define DPRINTF(params) if (pci_vt9p_debug) printf params
70*5c4a5fe1SAndy Fiddaman #define WPRINTF(params) printf params
71*5c4a5fe1SAndy Fiddaman 
72*5c4a5fe1SAndy Fiddaman /*
73*5c4a5fe1SAndy Fiddaman  * Per-device softc
74*5c4a5fe1SAndy Fiddaman  */
75*5c4a5fe1SAndy Fiddaman struct pci_vt9p_softc {
76*5c4a5fe1SAndy Fiddaman 	struct virtio_softc      vsc_vs;
77*5c4a5fe1SAndy Fiddaman 	struct vqueue_info       vsc_vq;
78*5c4a5fe1SAndy Fiddaman 	pthread_mutex_t          vsc_mtx;
79*5c4a5fe1SAndy Fiddaman 	uint64_t                 vsc_cfg;
80*5c4a5fe1SAndy Fiddaman 	uint64_t                 vsc_features;
81*5c4a5fe1SAndy Fiddaman 	char *                   vsc_rootpath;
82*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_config * vsc_config;
83*5c4a5fe1SAndy Fiddaman 	struct l9p_backend *     vsc_fs_backend;
84*5c4a5fe1SAndy Fiddaman 	struct l9p_server *      vsc_server;
85*5c4a5fe1SAndy Fiddaman         struct l9p_connection *  vsc_conn;
86*5c4a5fe1SAndy Fiddaman };
87*5c4a5fe1SAndy Fiddaman 
88*5c4a5fe1SAndy Fiddaman struct pci_vt9p_request {
89*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_softc *	vsr_sc;
90*5c4a5fe1SAndy Fiddaman 	struct iovec *		vsr_iov;
91*5c4a5fe1SAndy Fiddaman 	size_t			vsr_niov;
92*5c4a5fe1SAndy Fiddaman 	size_t			vsr_respidx;
93*5c4a5fe1SAndy Fiddaman 	size_t			vsr_iolen;
94*5c4a5fe1SAndy Fiddaman 	uint16_t		vsr_idx;
95*5c4a5fe1SAndy Fiddaman };
96*5c4a5fe1SAndy Fiddaman 
97*5c4a5fe1SAndy Fiddaman struct pci_vt9p_config {
98*5c4a5fe1SAndy Fiddaman 	uint16_t tag_len;
99*5c4a5fe1SAndy Fiddaman #ifdef	__FreeBSD__
100*5c4a5fe1SAndy Fiddaman 	char tag[0];
101*5c4a5fe1SAndy Fiddaman #else
102*5c4a5fe1SAndy Fiddaman 	char tag[VT9P_MAXTAGSZ];
103*5c4a5fe1SAndy Fiddaman #endif
104*5c4a5fe1SAndy Fiddaman } __attribute__((packed));
105*5c4a5fe1SAndy Fiddaman 
106*5c4a5fe1SAndy Fiddaman static int pci_vt9p_send(struct l9p_request *, const struct iovec *,
107*5c4a5fe1SAndy Fiddaman     const size_t, const size_t, void *);
108*5c4a5fe1SAndy Fiddaman static void pci_vt9p_drop(struct l9p_request *, const struct iovec *, size_t,
109*5c4a5fe1SAndy Fiddaman     void *);
110*5c4a5fe1SAndy Fiddaman static void pci_vt9p_reset(void *);
111*5c4a5fe1SAndy Fiddaman static void pci_vt9p_notify(void *, struct vqueue_info *);
112*5c4a5fe1SAndy Fiddaman static int pci_vt9p_cfgread(void *, int, int, uint32_t *);
113*5c4a5fe1SAndy Fiddaman static void pci_vt9p_neg_features(void *, uint64_t);
114*5c4a5fe1SAndy Fiddaman 
115*5c4a5fe1SAndy Fiddaman static struct virtio_consts vt9p_vi_consts = {
116*5c4a5fe1SAndy Fiddaman 	.vc_name =	"vt9p",
117*5c4a5fe1SAndy Fiddaman 	.vc_nvq =	1,
118*5c4a5fe1SAndy Fiddaman 	.vc_cfgsize =	VT9P_CONFIGSPACESZ,
119*5c4a5fe1SAndy Fiddaman 	.vc_reset =	pci_vt9p_reset,
120*5c4a5fe1SAndy Fiddaman 	.vc_qnotify =	pci_vt9p_notify,
121*5c4a5fe1SAndy Fiddaman 	.vc_cfgread =	pci_vt9p_cfgread,
122*5c4a5fe1SAndy Fiddaman 	.vc_apply_features = pci_vt9p_neg_features,
123*5c4a5fe1SAndy Fiddaman 	.vc_hv_caps =	(1 << 0),
124*5c4a5fe1SAndy Fiddaman };
125*5c4a5fe1SAndy Fiddaman 
126*5c4a5fe1SAndy Fiddaman static void
pci_vt9p_reset(void * vsc)127*5c4a5fe1SAndy Fiddaman pci_vt9p_reset(void *vsc)
128*5c4a5fe1SAndy Fiddaman {
129*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_softc *sc;
130*5c4a5fe1SAndy Fiddaman 
131*5c4a5fe1SAndy Fiddaman 	sc = vsc;
132*5c4a5fe1SAndy Fiddaman 
133*5c4a5fe1SAndy Fiddaman 	DPRINTF(("vt9p: device reset requested !\n"));
134*5c4a5fe1SAndy Fiddaman 	vi_reset_dev(&sc->vsc_vs);
135*5c4a5fe1SAndy Fiddaman }
136*5c4a5fe1SAndy Fiddaman 
137*5c4a5fe1SAndy Fiddaman static void
pci_vt9p_neg_features(void * vsc,uint64_t negotiated_features)138*5c4a5fe1SAndy Fiddaman pci_vt9p_neg_features(void *vsc, uint64_t negotiated_features)
139*5c4a5fe1SAndy Fiddaman {
140*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_softc *sc = vsc;
141*5c4a5fe1SAndy Fiddaman 
142*5c4a5fe1SAndy Fiddaman 	sc->vsc_features = negotiated_features;
143*5c4a5fe1SAndy Fiddaman }
144*5c4a5fe1SAndy Fiddaman 
145*5c4a5fe1SAndy Fiddaman static int
pci_vt9p_cfgread(void * vsc,int offset,int size,uint32_t * retval)146*5c4a5fe1SAndy Fiddaman pci_vt9p_cfgread(void *vsc, int offset, int size, uint32_t *retval)
147*5c4a5fe1SAndy Fiddaman {
148*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_softc *sc = vsc;
149*5c4a5fe1SAndy Fiddaman 	void *ptr;
150*5c4a5fe1SAndy Fiddaman 
151*5c4a5fe1SAndy Fiddaman 	ptr = (uint8_t *)sc->vsc_config + offset;
152*5c4a5fe1SAndy Fiddaman 	memcpy(retval, ptr, size);
153*5c4a5fe1SAndy Fiddaman 	return (0);
154*5c4a5fe1SAndy Fiddaman }
155*5c4a5fe1SAndy Fiddaman 
156*5c4a5fe1SAndy Fiddaman static int
pci_vt9p_get_buffer(struct l9p_request * req,struct iovec * iov,size_t * niov,void * arg __unused)157*5c4a5fe1SAndy Fiddaman pci_vt9p_get_buffer(struct l9p_request *req, struct iovec *iov, size_t *niov,
158*5c4a5fe1SAndy Fiddaman     void *arg __unused)
159*5c4a5fe1SAndy Fiddaman {
160*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_request *preq = req->lr_aux;
161*5c4a5fe1SAndy Fiddaman 	size_t n = preq->vsr_niov - preq->vsr_respidx;
162*5c4a5fe1SAndy Fiddaman 
163*5c4a5fe1SAndy Fiddaman 	memcpy(iov, preq->vsr_iov + preq->vsr_respidx,
164*5c4a5fe1SAndy Fiddaman 	    n * sizeof(struct iovec));
165*5c4a5fe1SAndy Fiddaman 	*niov = n;
166*5c4a5fe1SAndy Fiddaman 	return (0);
167*5c4a5fe1SAndy Fiddaman }
168*5c4a5fe1SAndy Fiddaman 
169*5c4a5fe1SAndy Fiddaman static int
pci_vt9p_send(struct l9p_request * req,const struct iovec * iov __unused,const size_t niov __unused,const size_t iolen,void * arg __unused)170*5c4a5fe1SAndy Fiddaman pci_vt9p_send(struct l9p_request *req, const struct iovec *iov __unused,
171*5c4a5fe1SAndy Fiddaman     const size_t niov __unused, const size_t iolen, void *arg __unused)
172*5c4a5fe1SAndy Fiddaman {
173*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_request *preq = req->lr_aux;
174*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_softc *sc = preq->vsr_sc;
175*5c4a5fe1SAndy Fiddaman 
176*5c4a5fe1SAndy Fiddaman 	preq->vsr_iolen = iolen;
177*5c4a5fe1SAndy Fiddaman 
178*5c4a5fe1SAndy Fiddaman 	pthread_mutex_lock(&sc->vsc_mtx);
179*5c4a5fe1SAndy Fiddaman 	vq_relchain(&sc->vsc_vq, preq->vsr_idx, preq->vsr_iolen);
180*5c4a5fe1SAndy Fiddaman 	vq_endchains(&sc->vsc_vq, 1);
181*5c4a5fe1SAndy Fiddaman 	pthread_mutex_unlock(&sc->vsc_mtx);
182*5c4a5fe1SAndy Fiddaman 	free(preq);
183*5c4a5fe1SAndy Fiddaman 	return (0);
184*5c4a5fe1SAndy Fiddaman }
185*5c4a5fe1SAndy Fiddaman 
186*5c4a5fe1SAndy Fiddaman static void
pci_vt9p_drop(struct l9p_request * req,const struct iovec * iov __unused,size_t niov __unused,void * arg __unused)187*5c4a5fe1SAndy Fiddaman pci_vt9p_drop(struct l9p_request *req, const struct iovec *iov __unused,
188*5c4a5fe1SAndy Fiddaman     size_t niov __unused, void *arg __unused)
189*5c4a5fe1SAndy Fiddaman {
190*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_request *preq = req->lr_aux;
191*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_softc *sc = preq->vsr_sc;
192*5c4a5fe1SAndy Fiddaman 
193*5c4a5fe1SAndy Fiddaman 	pthread_mutex_lock(&sc->vsc_mtx);
194*5c4a5fe1SAndy Fiddaman 	vq_relchain(&sc->vsc_vq, preq->vsr_idx, 0);
195*5c4a5fe1SAndy Fiddaman 	vq_endchains(&sc->vsc_vq, 1);
196*5c4a5fe1SAndy Fiddaman 	pthread_mutex_unlock(&sc->vsc_mtx);
197*5c4a5fe1SAndy Fiddaman 	free(preq);
198*5c4a5fe1SAndy Fiddaman }
199*5c4a5fe1SAndy Fiddaman 
200*5c4a5fe1SAndy Fiddaman static void
pci_vt9p_notify(void * vsc,struct vqueue_info * vq)201*5c4a5fe1SAndy Fiddaman pci_vt9p_notify(void *vsc, struct vqueue_info *vq)
202*5c4a5fe1SAndy Fiddaman {
203*5c4a5fe1SAndy Fiddaman 	struct iovec iov[VT9P_MAX_IOV];
204*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_softc *sc;
205*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_request *preq;
206*5c4a5fe1SAndy Fiddaman 	struct vi_req req;
207*5c4a5fe1SAndy Fiddaman 	int n;
208*5c4a5fe1SAndy Fiddaman 
209*5c4a5fe1SAndy Fiddaman 	sc = vsc;
210*5c4a5fe1SAndy Fiddaman 
211*5c4a5fe1SAndy Fiddaman 	while (vq_has_descs(vq)) {
212*5c4a5fe1SAndy Fiddaman 		n = vq_getchain(vq, iov, VT9P_MAX_IOV, &req);
213*5c4a5fe1SAndy Fiddaman 		assert(n >= 1 && n <= VT9P_MAX_IOV);
214*5c4a5fe1SAndy Fiddaman 		preq = calloc(1, sizeof(struct pci_vt9p_request));
215*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
216*5c4a5fe1SAndy Fiddaman 		if (preq == NULL) {
217*5c4a5fe1SAndy Fiddaman 			EPRINTLN("virtio-9p: allocation failure: %s",
218*5c4a5fe1SAndy Fiddaman 			    strerror(errno));
219*5c4a5fe1SAndy Fiddaman 			break;
220*5c4a5fe1SAndy Fiddaman 		}
221*5c4a5fe1SAndy Fiddaman #endif
222*5c4a5fe1SAndy Fiddaman 		preq->vsr_sc = sc;
223*5c4a5fe1SAndy Fiddaman 		preq->vsr_idx = req.idx;
224*5c4a5fe1SAndy Fiddaman 		preq->vsr_iov = iov;
225*5c4a5fe1SAndy Fiddaman 		preq->vsr_niov = n;
226*5c4a5fe1SAndy Fiddaman 		preq->vsr_respidx = req.readable;
227*5c4a5fe1SAndy Fiddaman 
228*5c4a5fe1SAndy Fiddaman 		for (int i = 0; i < n; i++) {
229*5c4a5fe1SAndy Fiddaman 			DPRINTF(("vt9p: vt9p_notify(): desc%d base=%p, "
230*5c4a5fe1SAndy Fiddaman 			    "len=%zu\r\n", i, iov[i].iov_base,
231*5c4a5fe1SAndy Fiddaman 			    iov[i].iov_len));
232*5c4a5fe1SAndy Fiddaman 		}
233*5c4a5fe1SAndy Fiddaman 
234*5c4a5fe1SAndy Fiddaman 		l9p_connection_recv(sc->vsc_conn, iov, preq->vsr_respidx, preq);
235*5c4a5fe1SAndy Fiddaman 	}
236*5c4a5fe1SAndy Fiddaman }
237*5c4a5fe1SAndy Fiddaman 
238*5c4a5fe1SAndy Fiddaman static int
pci_vt9p_legacy_config(nvlist_t * nvl,const char * opts)239*5c4a5fe1SAndy Fiddaman pci_vt9p_legacy_config(nvlist_t *nvl, const char *opts)
240*5c4a5fe1SAndy Fiddaman {
241*5c4a5fe1SAndy Fiddaman 	char *sharename = NULL, *tofree, *token, *tokens;
242*5c4a5fe1SAndy Fiddaman 
243*5c4a5fe1SAndy Fiddaman 	if (opts == NULL)
244*5c4a5fe1SAndy Fiddaman 		return (0);
245*5c4a5fe1SAndy Fiddaman 
246*5c4a5fe1SAndy Fiddaman 	tokens = tofree = strdup(opts);
247*5c4a5fe1SAndy Fiddaman 	while ((token = strsep(&tokens, ",")) != NULL) {
248*5c4a5fe1SAndy Fiddaman 		if (strchr(token, '=') != NULL) {
249*5c4a5fe1SAndy Fiddaman 			if (sharename != NULL) {
250*5c4a5fe1SAndy Fiddaman 				EPRINTLN(
251*5c4a5fe1SAndy Fiddaman 			    "virtio-9p: more than one share name given");
252*5c4a5fe1SAndy Fiddaman 				return (-1);
253*5c4a5fe1SAndy Fiddaman 			}
254*5c4a5fe1SAndy Fiddaman 
255*5c4a5fe1SAndy Fiddaman 			sharename = strsep(&token, "=");
256*5c4a5fe1SAndy Fiddaman 			set_config_value_node(nvl, "sharename", sharename);
257*5c4a5fe1SAndy Fiddaman 			set_config_value_node(nvl, "path", token);
258*5c4a5fe1SAndy Fiddaman 		} else
259*5c4a5fe1SAndy Fiddaman 			set_config_bool_node(nvl, token, true);
260*5c4a5fe1SAndy Fiddaman 	}
261*5c4a5fe1SAndy Fiddaman 	free(tofree);
262*5c4a5fe1SAndy Fiddaman 
263*5c4a5fe1SAndy Fiddaman 	return (0);
264*5c4a5fe1SAndy Fiddaman }
265*5c4a5fe1SAndy Fiddaman 
266*5c4a5fe1SAndy Fiddaman static int
pci_vt9p_init(struct pci_devinst * pi,nvlist_t * nvl)267*5c4a5fe1SAndy Fiddaman pci_vt9p_init(struct pci_devinst *pi, nvlist_t *nvl)
268*5c4a5fe1SAndy Fiddaman {
269*5c4a5fe1SAndy Fiddaman 	struct pci_vt9p_softc *sc;
270*5c4a5fe1SAndy Fiddaman 	const char *value;
271*5c4a5fe1SAndy Fiddaman 	const char *sharename;
272*5c4a5fe1SAndy Fiddaman 	int rootfd;
273*5c4a5fe1SAndy Fiddaman 	bool ro;
274*5c4a5fe1SAndy Fiddaman #ifndef WITHOUT_CAPSICUM
275*5c4a5fe1SAndy Fiddaman 	cap_rights_t rootcap;
276*5c4a5fe1SAndy Fiddaman #endif
277*5c4a5fe1SAndy Fiddaman 
278*5c4a5fe1SAndy Fiddaman 	ro = get_config_bool_node_default(nvl, "ro", false);
279*5c4a5fe1SAndy Fiddaman 
280*5c4a5fe1SAndy Fiddaman #ifndef __FreeBSD__
281*5c4a5fe1SAndy Fiddaman 	illumos_priv_add_min(PRIV_FILE_DAC_READ, "vt9p");
282*5c4a5fe1SAndy Fiddaman 	illumos_priv_add_min(PRIV_FILE_DAC_SEARCH, "vt9p");
283*5c4a5fe1SAndy Fiddaman 
284*5c4a5fe1SAndy Fiddaman 	if (!ro) {
285*5c4a5fe1SAndy Fiddaman 		illumos_priv_add_min(PRIV_FILE_CHOWN, "vt9p");
286*5c4a5fe1SAndy Fiddaman 		illumos_priv_add_min(PRIV_FILE_CHOWN_SELF, "vt9p");
287*5c4a5fe1SAndy Fiddaman 		illumos_priv_add_min(PRIV_FILE_WRITE, "vt9p");
288*5c4a5fe1SAndy Fiddaman 		illumos_priv_add_min(PRIV_FILE_DAC_WRITE, "vt9p");
289*5c4a5fe1SAndy Fiddaman 		illumos_priv_add_min(PRIV_FILE_OWNER, "vt9p");
290*5c4a5fe1SAndy Fiddaman 		illumos_priv_add_min(PRIV_FILE_LINK_ANY, "vt9p");
291*5c4a5fe1SAndy Fiddaman 	}
292*5c4a5fe1SAndy Fiddaman #endif
293*5c4a5fe1SAndy Fiddaman 
294*5c4a5fe1SAndy Fiddaman 	value = get_config_value_node(nvl, "path");
295*5c4a5fe1SAndy Fiddaman 	if (value == NULL) {
296*5c4a5fe1SAndy Fiddaman 		EPRINTLN("virtio-9p: path required");
297*5c4a5fe1SAndy Fiddaman 		return (1);
298*5c4a5fe1SAndy Fiddaman 	}
299*5c4a5fe1SAndy Fiddaman 	rootfd = open(value, O_DIRECTORY);
300*5c4a5fe1SAndy Fiddaman 	if (rootfd < 0) {
301*5c4a5fe1SAndy Fiddaman 		EPRINTLN("virtio-9p: failed to open '%s': %s", value,
302*5c4a5fe1SAndy Fiddaman 		    strerror(errno));
303*5c4a5fe1SAndy Fiddaman 		return (-1);
304*5c4a5fe1SAndy Fiddaman 	}
305*5c4a5fe1SAndy Fiddaman 
306*5c4a5fe1SAndy Fiddaman 	sharename = get_config_value_node(nvl, "sharename");
307*5c4a5fe1SAndy Fiddaman 	if (sharename == NULL) {
308*5c4a5fe1SAndy Fiddaman 		EPRINTLN("virtio-9p: share name required");
309*5c4a5fe1SAndy Fiddaman 		return (1);
310*5c4a5fe1SAndy Fiddaman 	}
311*5c4a5fe1SAndy Fiddaman 	if (strlen(sharename) > VT9P_MAXTAGSZ) {
312*5c4a5fe1SAndy Fiddaman 		EPRINTLN("virtio-9p: share name too long");
313*5c4a5fe1SAndy Fiddaman 		return (1);
314*5c4a5fe1SAndy Fiddaman 	}
315*5c4a5fe1SAndy Fiddaman 
316*5c4a5fe1SAndy Fiddaman 	sc = calloc(1, sizeof(struct pci_vt9p_softc));
317*5c4a5fe1SAndy Fiddaman #ifdef	__FreeBSD__
318*5c4a5fe1SAndy Fiddaman 	sc->vsc_config = calloc(1, sizeof(struct pci_vt9p_config) +
319*5c4a5fe1SAndy Fiddaman 	    VT9P_MAXTAGSZ);
320*5c4a5fe1SAndy Fiddaman #else
321*5c4a5fe1SAndy Fiddaman 	if (sc == NULL) {
322*5c4a5fe1SAndy Fiddaman 		EPRINTLN("virtio-9p: soft state allocation failure: %s",
323*5c4a5fe1SAndy Fiddaman 		    strerror(errno));
324*5c4a5fe1SAndy Fiddaman 		return (1);
325*5c4a5fe1SAndy Fiddaman 	}
326*5c4a5fe1SAndy Fiddaman 	sc->vsc_config = calloc(1, sizeof(struct pci_vt9p_config));
327*5c4a5fe1SAndy Fiddaman 	if (sc == NULL) {
328*5c4a5fe1SAndy Fiddaman 		EPRINTLN("virtio-9p: vsc_config allocation failure: %s",
329*5c4a5fe1SAndy Fiddaman 		    strerror(errno));
330*5c4a5fe1SAndy Fiddaman 		return (1);
331*5c4a5fe1SAndy Fiddaman 	}
332*5c4a5fe1SAndy Fiddaman #endif
333*5c4a5fe1SAndy Fiddaman 
334*5c4a5fe1SAndy Fiddaman 	pthread_mutex_init(&sc->vsc_mtx, NULL);
335*5c4a5fe1SAndy Fiddaman 
336*5c4a5fe1SAndy Fiddaman #ifndef WITHOUT_CAPSICUM
337*5c4a5fe1SAndy Fiddaman 	cap_rights_init(&rootcap,
338*5c4a5fe1SAndy Fiddaman 	    CAP_LOOKUP, CAP_ACL_CHECK, CAP_ACL_DELETE, CAP_ACL_GET,
339*5c4a5fe1SAndy Fiddaman 	    CAP_ACL_SET, CAP_READ, CAP_WRITE, CAP_SEEK, CAP_FSTAT,
340*5c4a5fe1SAndy Fiddaman 	    CAP_CREATE, CAP_FCHMODAT, CAP_FCHOWNAT, CAP_FTRUNCATE,
341*5c4a5fe1SAndy Fiddaman 	    CAP_LINKAT_SOURCE, CAP_LINKAT_TARGET, CAP_MKDIRAT, CAP_MKNODAT,
342*5c4a5fe1SAndy Fiddaman 	    CAP_PREAD, CAP_PWRITE, CAP_RENAMEAT_SOURCE, CAP_RENAMEAT_TARGET,
343*5c4a5fe1SAndy Fiddaman 	    CAP_SEEK, CAP_SYMLINKAT, CAP_UNLINKAT, CAP_EXTATTR_DELETE,
344*5c4a5fe1SAndy Fiddaman 	    CAP_EXTATTR_GET, CAP_EXTATTR_LIST, CAP_EXTATTR_SET,
345*5c4a5fe1SAndy Fiddaman 	    CAP_FUTIMES, CAP_FSTATFS, CAP_FSYNC, CAP_FPATHCONF);
346*5c4a5fe1SAndy Fiddaman 
347*5c4a5fe1SAndy Fiddaman 	if (cap_rights_limit(rootfd, &rootcap) != 0)
348*5c4a5fe1SAndy Fiddaman 		return (1);
349*5c4a5fe1SAndy Fiddaman #endif
350*5c4a5fe1SAndy Fiddaman 
351*5c4a5fe1SAndy Fiddaman 	sc->vsc_config->tag_len = (uint16_t)strlen(sharename);
352*5c4a5fe1SAndy Fiddaman 	memcpy(sc->vsc_config->tag, sharename, sc->vsc_config->tag_len);
353*5c4a5fe1SAndy Fiddaman 
354*5c4a5fe1SAndy Fiddaman 	if (l9p_backend_fs_init(&sc->vsc_fs_backend, rootfd, ro) != 0) {
355*5c4a5fe1SAndy Fiddaman 		errno = ENXIO;
356*5c4a5fe1SAndy Fiddaman 		return (1);
357*5c4a5fe1SAndy Fiddaman 	}
358*5c4a5fe1SAndy Fiddaman 
359*5c4a5fe1SAndy Fiddaman 	if (l9p_server_init(&sc->vsc_server, sc->vsc_fs_backend) != 0) {
360*5c4a5fe1SAndy Fiddaman 		errno = ENXIO;
361*5c4a5fe1SAndy Fiddaman 		return (1);
362*5c4a5fe1SAndy Fiddaman 	}
363*5c4a5fe1SAndy Fiddaman 
364*5c4a5fe1SAndy Fiddaman 	if (l9p_connection_init(sc->vsc_server, &sc->vsc_conn) != 0) {
365*5c4a5fe1SAndy Fiddaman 		errno = EIO;
366*5c4a5fe1SAndy Fiddaman 		return (1);
367*5c4a5fe1SAndy Fiddaman 	}
368*5c4a5fe1SAndy Fiddaman 
369*5c4a5fe1SAndy Fiddaman 	sc->vsc_conn->lc_msize = L9P_MAX_IOV * PAGE_SIZE;
370*5c4a5fe1SAndy Fiddaman 	sc->vsc_conn->lc_lt.lt_get_response_buffer = pci_vt9p_get_buffer;
371*5c4a5fe1SAndy Fiddaman 	sc->vsc_conn->lc_lt.lt_send_response = pci_vt9p_send;
372*5c4a5fe1SAndy Fiddaman 	sc->vsc_conn->lc_lt.lt_drop_response = pci_vt9p_drop;
373*5c4a5fe1SAndy Fiddaman 
374*5c4a5fe1SAndy Fiddaman 	vi_softc_linkup(&sc->vsc_vs, &vt9p_vi_consts, sc, pi, &sc->vsc_vq);
375*5c4a5fe1SAndy Fiddaman 	sc->vsc_vs.vs_mtx = &sc->vsc_mtx;
376*5c4a5fe1SAndy Fiddaman 	sc->vsc_vq.vq_qsize = VT9P_RINGSZ;
377*5c4a5fe1SAndy Fiddaman 
378*5c4a5fe1SAndy Fiddaman 	/* initialize config space */
379*5c4a5fe1SAndy Fiddaman 	pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_9P);
380*5c4a5fe1SAndy Fiddaman 	pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
381*5c4a5fe1SAndy Fiddaman 	pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);
382*5c4a5fe1SAndy Fiddaman 	pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_ID_9P);
383*5c4a5fe1SAndy Fiddaman 	pci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);
384*5c4a5fe1SAndy Fiddaman 
385*5c4a5fe1SAndy Fiddaman 	if (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))
386*5c4a5fe1SAndy Fiddaman 		return (1);
387*5c4a5fe1SAndy Fiddaman 	vi_set_io_bar(&sc->vsc_vs, 0);
388*5c4a5fe1SAndy Fiddaman 
389*5c4a5fe1SAndy Fiddaman 	return (0);
390*5c4a5fe1SAndy Fiddaman }
391*5c4a5fe1SAndy Fiddaman 
392*5c4a5fe1SAndy Fiddaman static const struct pci_devemu pci_de_v9p = {
393*5c4a5fe1SAndy Fiddaman 	.pe_emu =	"virtio-9p",
394*5c4a5fe1SAndy Fiddaman 	.pe_legacy_config = pci_vt9p_legacy_config,
395*5c4a5fe1SAndy Fiddaman 	.pe_init =	pci_vt9p_init,
396*5c4a5fe1SAndy Fiddaman 	.pe_barwrite =	vi_pci_write,
397*5c4a5fe1SAndy Fiddaman 	.pe_barread =	vi_pci_read
398*5c4a5fe1SAndy Fiddaman };
399*5c4a5fe1SAndy Fiddaman PCI_EMUL_SET(pci_de_v9p);
400