xenbus_dev.c revision 1.10 1 1.10 msaitoh /* $NetBSD: xenbus_dev.c,v 1.10 2016/07/07 06:55:40 msaitoh Exp $ */
2 1.1 bouyer /*
3 1.1 bouyer * xenbus_dev.c
4 1.1 bouyer *
5 1.1 bouyer * Driver giving user-space access to the kernel's xenbus connection
6 1.1 bouyer * to xenstore.
7 1.1 bouyer *
8 1.1 bouyer * Copyright (c) 2005, Christian Limpach
9 1.1 bouyer * Copyright (c) 2005, Rusty Russell, IBM Corporation
10 1.1 bouyer *
11 1.1 bouyer * This file may be distributed separately from the Linux kernel, or
12 1.1 bouyer * incorporated into other software packages, subject to the following license:
13 1.1 bouyer *
14 1.1 bouyer * Permission is hereby granted, free of charge, to any person obtaining a copy
15 1.1 bouyer * of this source file (the "Software"), to deal in the Software without
16 1.1 bouyer * restriction, including without limitation the rights to use, copy, modify,
17 1.1 bouyer * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 1.1 bouyer * and to permit persons to whom the Software is furnished to do so, subject to
19 1.1 bouyer * the following conditions:
20 1.1 bouyer *
21 1.1 bouyer * The above copyright notice and this permission notice shall be included in
22 1.1 bouyer * all copies or substantial portions of the Software.
23 1.1 bouyer *
24 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 1.1 bouyer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 1.1 bouyer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 1.1 bouyer * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 1.1 bouyer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 1.1 bouyer * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 1.1 bouyer * IN THE SOFTWARE.
31 1.1 bouyer */
32 1.1 bouyer
33 1.2 bouyer #include <sys/cdefs.h>
34 1.10 msaitoh __KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.10 2016/07/07 06:55:40 msaitoh Exp $");
35 1.1 bouyer
36 1.2 bouyer #include "opt_xen.h"
37 1.2 bouyer
38 1.2 bouyer #include <sys/types.h>
39 1.2 bouyer #include <sys/null.h>
40 1.2 bouyer #include <sys/errno.h>
41 1.2 bouyer #include <sys/malloc.h>
42 1.2 bouyer #include <sys/param.h>
43 1.2 bouyer #include <sys/proc.h>
44 1.2 bouyer #include <sys/systm.h>
45 1.2 bouyer #include <sys/dirent.h>
46 1.2 bouyer #include <sys/stat.h>
47 1.2 bouyer #include <sys/tree.h>
48 1.2 bouyer #include <sys/vnode.h>
49 1.2 bouyer #include <miscfs/specfs/specdev.h>
50 1.2 bouyer #include <miscfs/kernfs/kernfs.h>
51 1.2 bouyer
52 1.6 bouyer #include <xen/kernfs_machdep.h>
53 1.6 bouyer
54 1.6 bouyer #include <xen/hypervisor.h>
55 1.6 bouyer #include <xen/xenbus.h>
56 1.1 bouyer #include "xenbus_comms.h"
57 1.1 bouyer
58 1.2 bouyer static int xenbus_dev_read(void *);
59 1.2 bouyer static int xenbus_dev_write(void *);
60 1.2 bouyer static int xenbus_dev_open(void *);
61 1.2 bouyer static int xenbus_dev_close(void *);
62 1.3 bouyer static int xsd_port_read(void *);
63 1.1 bouyer
64 1.1 bouyer struct xenbus_dev_transaction {
65 1.2 bouyer SLIST_ENTRY(xenbus_dev_transaction) trans_next;
66 1.1 bouyer struct xenbus_transaction *handle;
67 1.1 bouyer };
68 1.1 bouyer
69 1.2 bouyer #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
70 1.2 bouyer #define PRIVCMD_MODE (S_IRUSR | S_IWUSR)
71 1.2 bouyer static const struct kernfs_fileop xenbus_fileops[] = {
72 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_OPEN, .kf_vop = xenbus_dev_open },
73 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_CLOSE, .kf_vop = xenbus_dev_close },
74 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xenbus_dev_read },
75 1.2 bouyer { .kf_fileop = KERNFS_FILEOP_WRITE, .kf_vop = xenbus_dev_write },
76 1.2 bouyer };
77 1.2 bouyer
78 1.3 bouyer #define XSD_MODE (S_IRUSR)
79 1.3 bouyer static const struct kernfs_fileop xsd_port_fileops[] = {
80 1.3 bouyer { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xsd_port_read },
81 1.3 bouyer };
82 1.2 bouyer
83 1.2 bouyer void
84 1.8 cegger xenbus_kernfs_init(void)
85 1.2 bouyer {
86 1.2 bouyer kernfs_entry_t *dkt;
87 1.2 bouyer kfstype kfst;
88 1.2 bouyer
89 1.2 bouyer kfst = KERNFS_ALLOCTYPE(xenbus_fileops);
90 1.2 bouyer KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK);
91 1.2 bouyer KERNFS_INITENTRY(dkt, DT_REG, "xenbus", NULL, kfst, VREG,
92 1.2 bouyer PRIVCMD_MODE);
93 1.2 bouyer kernfs_addentry(kernxen_pkt, dkt);
94 1.3 bouyer
95 1.9 jym if (xendomain_is_dom0()) {
96 1.9 jym kfst = KERNFS_ALLOCTYPE(xsd_port_fileops);
97 1.9 jym KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK);
98 1.9 jym KERNFS_INITENTRY(dkt, DT_REG, "xsd_port", NULL,
99 1.9 jym kfst, VREG, XSD_MODE);
100 1.9 jym kernfs_addentry(kernxen_pkt, dkt);
101 1.9 jym }
102 1.2 bouyer }
103 1.2 bouyer
104 1.1 bouyer struct xenbus_dev_data {
105 1.2 bouyer #define BUFFER_SIZE (PAGE_SIZE)
106 1.2 bouyer #define MASK_READ_IDX(idx) ((idx)&(BUFFER_SIZE-1))
107 1.1 bouyer /* In-progress transaction. */
108 1.2 bouyer SLIST_HEAD(, xenbus_dev_transaction) transactions;
109 1.1 bouyer
110 1.1 bouyer /* Partial request. */
111 1.1 bouyer unsigned int len;
112 1.1 bouyer union {
113 1.1 bouyer struct xsd_sockmsg msg;
114 1.2 bouyer char buffer[BUFFER_SIZE];
115 1.1 bouyer } u;
116 1.1 bouyer
117 1.1 bouyer /* Response queue. */
118 1.2 bouyer char read_buffer[BUFFER_SIZE];
119 1.1 bouyer unsigned int read_cons, read_prod;
120 1.1 bouyer };
121 1.1 bouyer
122 1.2 bouyer static int
123 1.2 bouyer xenbus_dev_read(void *v)
124 1.1 bouyer {
125 1.2 bouyer struct vop_read_args /* {
126 1.2 bouyer struct vnode *a_vp;
127 1.2 bouyer struct uio *a_uio;
128 1.2 bouyer int a_ioflag;
129 1.2 bouyer struct ucred *a_cred;
130 1.2 bouyer } */ *ap = v;
131 1.2 bouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
132 1.2 bouyer struct uio *uio = ap->a_uio;
133 1.2 bouyer struct xenbus_dev_data *u = kfs->kfs_v;
134 1.2 bouyer int err;
135 1.2 bouyer off_t offset;
136 1.2 bouyer int s = spltty();
137 1.2 bouyer
138 1.2 bouyer while (u->read_prod == u->read_cons) {
139 1.2 bouyer err = tsleep(u, PRIBIO | PCATCH, "xbrd", 0);
140 1.2 bouyer if (err)
141 1.2 bouyer goto end;
142 1.2 bouyer }
143 1.5 bouyer offset = uio->uio_offset;
144 1.1 bouyer
145 1.2 bouyer if (u->read_cons > u->read_prod) {
146 1.2 bouyer err = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
147 1.2 bouyer 0U - u->read_cons, uio);
148 1.2 bouyer if (err)
149 1.2 bouyer goto end;
150 1.5 bouyer u->read_cons += (uio->uio_offset - offset);
151 1.2 bouyer offset = uio->uio_offset;
152 1.1 bouyer }
153 1.2 bouyer err = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
154 1.2 bouyer u->read_prod - u->read_cons, uio);
155 1.2 bouyer if (err == 0)
156 1.5 bouyer u->read_cons += (uio->uio_offset - offset);
157 1.1 bouyer
158 1.2 bouyer end:
159 1.2 bouyer splx(s);
160 1.2 bouyer return err;
161 1.1 bouyer }
162 1.1 bouyer
163 1.2 bouyer static void
164 1.2 bouyer queue_reply(struct xenbus_dev_data *u,
165 1.1 bouyer char *data, unsigned int len)
166 1.1 bouyer {
167 1.1 bouyer int i;
168 1.1 bouyer
169 1.1 bouyer for (i = 0; i < len; i++, u->read_prod++)
170 1.1 bouyer u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
171 1.1 bouyer
172 1.2 bouyer KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer));
173 1.1 bouyer
174 1.2 bouyer wakeup(&u);
175 1.1 bouyer }
176 1.1 bouyer
177 1.2 bouyer static int
178 1.2 bouyer xenbus_dev_write(void *v)
179 1.1 bouyer {
180 1.2 bouyer struct vop_write_args /* {
181 1.2 bouyer struct vnode *a_vp;
182 1.2 bouyer struct uio *a_uio;
183 1.2 bouyer int a_ioflag;
184 1.2 bouyer struct ucred *a_cred;
185 1.2 bouyer } */ *ap = v;
186 1.2 bouyer struct kernfs_node *kfs = VTOKERN(ap->a_vp);
187 1.2 bouyer struct uio *uio = ap->a_uio;
188 1.2 bouyer
189 1.2 bouyer struct xenbus_dev_data *u = kfs->kfs_v;
190 1.1 bouyer struct xenbus_dev_transaction *trans;
191 1.1 bouyer void *reply;
192 1.2 bouyer int err;
193 1.2 bouyer size_t size;
194 1.2 bouyer
195 1.2 bouyer if (uio->uio_offset < 0)
196 1.2 bouyer return EINVAL;
197 1.2 bouyer size = uio->uio_resid;
198 1.1 bouyer
199 1.2 bouyer if ((size + u->len) > sizeof(u->u.buffer))
200 1.2 bouyer return EINVAL;
201 1.1 bouyer
202 1.2 bouyer err = uiomove(u->u.buffer + u->len, sizeof(u->u.buffer) - u->len, uio);
203 1.2 bouyer if (err)
204 1.2 bouyer return err;
205 1.1 bouyer
206 1.2 bouyer u->len += size;
207 1.1 bouyer if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
208 1.2 bouyer return 0;
209 1.1 bouyer
210 1.1 bouyer switch (u->u.msg.type) {
211 1.1 bouyer case XS_TRANSACTION_START:
212 1.1 bouyer case XS_TRANSACTION_END:
213 1.1 bouyer case XS_DIRECTORY:
214 1.1 bouyer case XS_READ:
215 1.1 bouyer case XS_GET_PERMS:
216 1.1 bouyer case XS_RELEASE:
217 1.1 bouyer case XS_GET_DOMAIN_PATH:
218 1.1 bouyer case XS_WRITE:
219 1.1 bouyer case XS_MKDIR:
220 1.1 bouyer case XS_RM:
221 1.1 bouyer case XS_SET_PERMS:
222 1.2 bouyer err = xenbus_dev_request_and_reply(&u->u.msg, &reply);
223 1.2 bouyer if (err == 0) {
224 1.1 bouyer if (u->u.msg.type == XS_TRANSACTION_START) {
225 1.2 bouyer trans = malloc(sizeof(*trans), M_DEVBUF,
226 1.2 bouyer M_WAITOK);
227 1.1 bouyer trans->handle = (struct xenbus_transaction *)
228 1.2 bouyer strtoul(reply, NULL, 0);
229 1.2 bouyer SLIST_INSERT_HEAD(&u->transactions,
230 1.2 bouyer trans, trans_next);
231 1.1 bouyer } else if (u->u.msg.type == XS_TRANSACTION_END) {
232 1.2 bouyer SLIST_FOREACH(trans, &u->transactions,
233 1.2 bouyer trans_next) {
234 1.1 bouyer if ((unsigned long)trans->handle ==
235 1.1 bouyer (unsigned long)u->u.msg.tx_id)
236 1.1 bouyer break;
237 1.2 bouyer }
238 1.2 bouyer KASSERT(trans != NULL);
239 1.2 bouyer SLIST_REMOVE(&u->transactions, trans,
240 1.2 bouyer xenbus_dev_transaction, trans_next);
241 1.2 bouyer free(trans, M_DEVBUF);
242 1.1 bouyer }
243 1.1 bouyer queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
244 1.1 bouyer queue_reply(u, (char *)reply, u->u.msg.len);
245 1.2 bouyer free(reply, M_DEVBUF);
246 1.1 bouyer }
247 1.1 bouyer break;
248 1.1 bouyer
249 1.1 bouyer default:
250 1.2 bouyer err = EINVAL;
251 1.1 bouyer break;
252 1.1 bouyer }
253 1.1 bouyer
254 1.1 bouyer if (err == 0) {
255 1.1 bouyer u->len = 0;
256 1.1 bouyer }
257 1.1 bouyer
258 1.1 bouyer return err;
259 1.1 bouyer }
260 1.1 bouyer
261 1.2 bouyer static int
262 1.2 bouyer xenbus_dev_open(void *v)
263 1.1 bouyer {
264 1.2 bouyer struct vop_open_args /* {
265 1.2 bouyer struct vnode *a_vp;
266 1.2 bouyer int a_mode;
267 1.2 bouyer struct ucred *a_cred;
268 1.2 bouyer } */ *ap = v;
269 1.10 msaitoh struct kernfs_node *kfs = VTOKERN(ap->a_vp);
270 1.2 bouyer
271 1.1 bouyer struct xenbus_dev_data *u;
272 1.1 bouyer
273 1.2 bouyer if (xen_start_info.store_evtchn == 0)
274 1.2 bouyer return ENOENT;
275 1.1 bouyer
276 1.2 bouyer u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK);
277 1.1 bouyer if (u == NULL)
278 1.2 bouyer return ENOMEM;
279 1.1 bouyer
280 1.1 bouyer memset(u, 0, sizeof(*u));
281 1.2 bouyer SLIST_INIT(&u->transactions);
282 1.1 bouyer
283 1.2 bouyer kfs->kfs_v = u;
284 1.1 bouyer
285 1.1 bouyer return 0;
286 1.1 bouyer }
287 1.1 bouyer
288 1.2 bouyer static int
289 1.2 bouyer xenbus_dev_close(void *v)
290 1.1 bouyer {
291 1.2 bouyer struct vop_close_args /* {
292 1.2 bouyer struct vnode *a_vp;
293 1.2 bouyer int a_fflag;
294 1.2 bouyer struct ucred *a_cred;
295 1.2 bouyer } */ *ap = v;
296 1.10 msaitoh struct kernfs_node *kfs = VTOKERN(ap->a_vp);
297 1.1 bouyer
298 1.2 bouyer struct xenbus_dev_data *u = kfs->kfs_v;
299 1.2 bouyer struct xenbus_dev_transaction *trans;
300 1.2 bouyer
301 1.2 bouyer while (!SLIST_EMPTY(&u->transactions)) {
302 1.2 bouyer trans = SLIST_FIRST(&u->transactions);
303 1.1 bouyer xenbus_transaction_end(trans->handle, 1);
304 1.2 bouyer SLIST_REMOVE_HEAD(&u->transactions, trans_next);
305 1.2 bouyer free(trans, M_DEVBUF);
306 1.1 bouyer }
307 1.1 bouyer
308 1.2 bouyer free(u, M_DEVBUF);
309 1.2 bouyer kfs->kfs_v = NULL;
310 1.1 bouyer
311 1.1 bouyer return 0;
312 1.1 bouyer }
313 1.1 bouyer
314 1.3 bouyer #define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */
315 1.3 bouyer
316 1.3 bouyer static int
317 1.3 bouyer xsd_port_read(void *v)
318 1.3 bouyer {
319 1.3 bouyer struct vop_read_args /* {
320 1.3 bouyer struct vnode *a_vp;
321 1.3 bouyer struct uio *a_uio;
322 1.3 bouyer int a_ioflag;
323 1.3 bouyer struct ucred *a_cred;
324 1.3 bouyer } */ *ap = v;
325 1.3 bouyer struct uio *uio = ap->a_uio;
326 1.3 bouyer int off, error;
327 1.10 msaitoh size_t len;
328 1.3 bouyer char strbuf[LD_STRLEN], *bf;
329 1.3 bouyer
330 1.3 bouyer off = (int)uio->uio_offset;
331 1.3 bouyer if (off < 0)
332 1.3 bouyer return EINVAL;
333 1.3 bouyer
334 1.3 bouyer len = snprintf(strbuf, sizeof(strbuf), "%ld\n",
335 1.3 bouyer (long)xen_start_info.store_evtchn);
336 1.3 bouyer if (off >= len) {
337 1.3 bouyer bf = strbuf;
338 1.3 bouyer len = 0;
339 1.3 bouyer } else {
340 1.3 bouyer bf = &strbuf[off];
341 1.3 bouyer len -= off;
342 1.3 bouyer }
343 1.3 bouyer error = uiomove(bf, len, uio);
344 1.3 bouyer return error;
345 1.3 bouyer }
346 1.3 bouyer
347 1.1 bouyer /*
348 1.1 bouyer * Local variables:
349 1.1 bouyer * c-file-style: "linux"
350 1.1 bouyer * indent-tabs-mode: t
351 1.1 bouyer * c-indent-level: 8
352 1.1 bouyer * c-basic-offset: 8
353 1.1 bouyer * tab-width: 8
354 1.1 bouyer * End:
355 1.1 bouyer */
356