1 /* $NetBSD: xenbus_dev.c,v 1.7 2007/11/27 11:37:27 pooka Exp $ */
5 * Driver giving user-space access to the kernel's xenbus connection
8 * Copyright (c) 2005, Christian Limpach
9 * Copyright (c) 2005, Rusty Russell, IBM Corporation
11 * This file may be distributed separately from the Linux kernel, or
12 * incorporated into other software packages, subject to the following license:
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.7 2007/11/27 11:37:27 pooka Exp $");
38 #include <sys/types.h>
40 #include <sys/errno.h>
41 #include <sys/malloc.h>
42 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/dirent.h>
48 #include <sys/vnode.h>
49 #include <miscfs/specfs/specdev.h>
50 #include <miscfs/kernfs/kernfs.h>
52 #include <xen/kernfs_machdep.h>
54 #include <xen/hypervisor.h>
55 #include <xen/xenbus.h>
56 #include "xenbus_comms.h"
58 static int xenbus_dev_read(void *);
59 static int xenbus_dev_write(void *);
60 static int xenbus_dev_open(void *);
61 static int xenbus_dev_close(void *);
62 static int xsd_port_read(void *);
64 struct xenbus_dev_transaction
{
65 SLIST_ENTRY(xenbus_dev_transaction
) trans_next
;
66 struct xenbus_transaction
*handle
;
69 #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
70 #define PRIVCMD_MODE (S_IRUSR | S_IWUSR)
71 static const struct kernfs_fileop xenbus_fileops
[] = {
72 { .kf_fileop
= KERNFS_FILEOP_OPEN
, .kf_vop
= xenbus_dev_open
},
73 { .kf_fileop
= KERNFS_FILEOP_CLOSE
, .kf_vop
= xenbus_dev_close
},
74 { .kf_fileop
= KERNFS_FILEOP_READ
, .kf_vop
= xenbus_dev_read
},
75 { .kf_fileop
= KERNFS_FILEOP_WRITE
, .kf_vop
= xenbus_dev_write
},
78 #define XSD_MODE (S_IRUSR)
79 static const struct kernfs_fileop xsd_port_fileops
[] = {
80 { .kf_fileop
= KERNFS_FILEOP_READ
, .kf_vop
= xsd_port_read
},
84 xenbus_kernfs_init(void)
89 kfst
= KERNFS_ALLOCTYPE(xenbus_fileops
);
90 KERNFS_ALLOCENTRY(dkt
, M_TEMP
, M_WAITOK
);
91 KERNFS_INITENTRY(dkt
, DT_REG
, "xenbus", NULL
, kfst
, VREG
,
93 kernfs_addentry(kernxen_pkt
, dkt
);
95 kfst
= KERNFS_ALLOCTYPE(xsd_port_fileops
);
96 KERNFS_ALLOCENTRY(dkt
, M_TEMP
, M_WAITOK
);
97 KERNFS_INITENTRY(dkt
, DT_REG
, "xsd_port", NULL
, kfst
, VREG
, XSD_MODE
);
98 kernfs_addentry(kernxen_pkt
, dkt
);
101 struct xenbus_dev_data
{
102 #define BUFFER_SIZE (PAGE_SIZE)
103 #define MASK_READ_IDX(idx) ((idx)&(BUFFER_SIZE-1))
104 /* In-progress transaction. */
105 SLIST_HEAD(, xenbus_dev_transaction
) transactions
;
107 /* Partial request. */
110 struct xsd_sockmsg msg
;
111 char buffer
[BUFFER_SIZE
];
114 /* Response queue. */
115 char read_buffer
[BUFFER_SIZE
];
116 unsigned int read_cons
, read_prod
;
120 xenbus_dev_read(void *v
)
122 struct vop_read_args
/* {
126 struct ucred *a_cred;
128 struct kernfs_node
*kfs
= VTOKERN(ap
->a_vp
);
129 struct uio
*uio
= ap
->a_uio
;
130 struct xenbus_dev_data
*u
= kfs
->kfs_v
;
135 while (u
->read_prod
== u
->read_cons
) {
136 err
= tsleep(u
, PRIBIO
| PCATCH
, "xbrd", 0);
140 offset
= uio
->uio_offset
;
142 if (u
->read_cons
> u
->read_prod
) {
143 err
= uiomove(&u
->read_buffer
[MASK_READ_IDX(u
->read_cons
)],
144 0U - u
->read_cons
, uio
);
147 u
->read_cons
+= (uio
->uio_offset
- offset
);
148 offset
= uio
->uio_offset
;
150 err
= uiomove(&u
->read_buffer
[MASK_READ_IDX(u
->read_cons
)],
151 u
->read_prod
- u
->read_cons
, uio
);
153 u
->read_cons
+= (uio
->uio_offset
- offset
);
161 queue_reply(struct xenbus_dev_data
*u
,
162 char *data
, unsigned int len
)
166 for (i
= 0; i
< len
; i
++, u
->read_prod
++)
167 u
->read_buffer
[MASK_READ_IDX(u
->read_prod
)] = data
[i
];
169 KASSERT((u
->read_prod
- u
->read_cons
) <= sizeof(u
->read_buffer
));
175 xenbus_dev_write(void *v
)
177 struct vop_write_args
/* {
181 struct ucred *a_cred;
183 struct kernfs_node
*kfs
= VTOKERN(ap
->a_vp
);
184 struct uio
*uio
= ap
->a_uio
;
186 struct xenbus_dev_data
*u
= kfs
->kfs_v
;
187 struct xenbus_dev_transaction
*trans
;
192 if (uio
->uio_offset
< 0)
194 size
= uio
->uio_resid
;
196 if ((size
+ u
->len
) > sizeof(u
->u
.buffer
))
199 err
= uiomove(u
->u
.buffer
+ u
->len
, sizeof(u
->u
.buffer
) - u
->len
, uio
);
204 if (u
->len
< (sizeof(u
->u
.msg
) + u
->u
.msg
.len
))
207 switch (u
->u
.msg
.type
) {
208 case XS_TRANSACTION_START
:
209 case XS_TRANSACTION_END
:
214 case XS_GET_DOMAIN_PATH
:
219 err
= xenbus_dev_request_and_reply(&u
->u
.msg
, &reply
);
221 if (u
->u
.msg
.type
== XS_TRANSACTION_START
) {
222 trans
= malloc(sizeof(*trans
), M_DEVBUF
,
224 trans
->handle
= (struct xenbus_transaction
*)
225 strtoul(reply
, NULL
, 0);
226 SLIST_INSERT_HEAD(&u
->transactions
,
228 } else if (u
->u
.msg
.type
== XS_TRANSACTION_END
) {
229 SLIST_FOREACH(trans
, &u
->transactions
,
231 if ((unsigned long)trans
->handle
==
232 (unsigned long)u
->u
.msg
.tx_id
)
235 KASSERT(trans
!= NULL
);
236 SLIST_REMOVE(&u
->transactions
, trans
,
237 xenbus_dev_transaction
, trans_next
);
238 free(trans
, M_DEVBUF
);
240 queue_reply(u
, (char *)&u
->u
.msg
, sizeof(u
->u
.msg
));
241 queue_reply(u
, (char *)reply
, u
->u
.msg
.len
);
242 free(reply
, M_DEVBUF
);
259 xenbus_dev_open(void *v
)
261 struct vop_open_args
/* {
264 struct ucred *a_cred;
266 struct kernfs_node
*kfs
= VTOKERN(ap
->a_vp
);
268 struct xenbus_dev_data
*u
;
270 if (xen_start_info
.store_evtchn
== 0)
273 u
= malloc(sizeof(*u
), M_DEVBUF
, M_WAITOK
);
277 memset(u
, 0, sizeof(*u
));
278 SLIST_INIT(&u
->transactions
);
286 xenbus_dev_close(void *v
)
288 struct vop_close_args
/* {
291 struct ucred *a_cred;
293 struct kernfs_node
*kfs
= VTOKERN(ap
->a_vp
);
295 struct xenbus_dev_data
*u
= kfs
->kfs_v
;
296 struct xenbus_dev_transaction
*trans
;
298 while (!SLIST_EMPTY(&u
->transactions
)) {
299 trans
= SLIST_FIRST(&u
->transactions
);
300 xenbus_transaction_end(trans
->handle
, 1);
301 SLIST_REMOVE_HEAD(&u
->transactions
, trans_next
);
302 free(trans
, M_DEVBUF
);
311 #define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */
314 xsd_port_read(void *v
)
316 struct vop_read_args
/* {
320 struct ucred *a_cred;
322 struct uio
*uio
= ap
->a_uio
;
325 char strbuf
[LD_STRLEN
], *bf
;
327 off
= (int)uio
->uio_offset
;
331 len
= snprintf(strbuf
, sizeof(strbuf
), "%ld\n",
332 (long)xen_start_info
.store_evtchn
);
340 error
= uiomove(bf
, len
, uio
);
346 * c-file-style: "linux"
347 * indent-tabs-mode: t