]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/xen/xenbus/xenbus_dev.c
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
[FreeBSD/FreeBSD.git] / 6 / sys / xen / xenbus / xenbus_dev.c
1 /*
2  * xenbus_dev.c
3  * 
4  * Driver giving user-space access to the kernel's xenbus connection
5  * to xenstore.
6  * 
7  * Copyright (c) 2005, Christian Limpach
8  * Copyright (c) 2005, Rusty Russell, IBM Corporation
9  * 
10  * This file may be distributed separately from the Linux kernel, or
11  * incorporated into other software packages, subject to the following license:
12  * 
13  * Permission is hereby granted, free of charge, to any person obtaining a copy
14  * of this source file (the "Software"), to deal in the Software without
15  * restriction, including without limitation the rights to use, copy, modify,
16  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17  * and to permit persons to whom the Software is furnished to do so, subject to
18  * the following conditions:
19  * 
20  * The above copyright notice and this permission notice shall be included in
21  * all copies or substantial portions of the Software.
22  * 
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29  * IN THE SOFTWARE.
30  */
31
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/types.h>
37 #include <sys/cdefs.h>
38 #include <sys/errno.h>
39 #include <sys/uio.h>
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/proc.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/conf.h>
46
47
48 #include <machine/xen/xen-os.h>
49 #include <machine/xen/hypervisor.h>
50 #include <machine/xen/xenbus.h>
51 #include <machine/xen/hypervisor.h>
52 #include <xen/xenbus/xenbus_comms.h>
53
54
55
56
57 #define kmalloc(size, unused) malloc(size, M_DEVBUF, M_WAITOK)
58 #define BUG_ON        PANIC_IF
59 #define semaphore     sema
60 #define rw_semaphore  sema
61 #define DEFINE_SPINLOCK(lock) struct mtx lock
62 #define DECLARE_MUTEX(lock) struct sema lock
63 #define u32           uint32_t
64 #define simple_strtoul strtoul
65
66 struct xenbus_dev_transaction {
67         LIST_ENTRY(xenbus_dev_transaction) list;
68         struct xenbus_transaction handle;
69 };
70
71 struct xenbus_dev_data {
72         /* In-progress transaction. */
73         LIST_HEAD(xdd_list_head, xenbus_dev_transaction) transactions;
74
75         /* Partial request. */
76         unsigned int len;
77         union {
78                 struct xsd_sockmsg msg;
79                 char buffer[PAGE_SIZE];
80         } u;
81
82         /* Response queue. */
83 #define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
84         char read_buffer[PAGE_SIZE];
85         unsigned int read_cons, read_prod;
86         int read_waitq;
87 };
88 #if 0
89 static struct proc_dir_entry *xenbus_dev_intf;
90 #endif
91 static int 
92 xenbus_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
93 {
94         int i = 0;
95         struct xenbus_dev_data *u = dev->si_drv1;
96
97         if (wait_event_interruptible(&u->read_waitq,
98                                      u->read_prod != u->read_cons))
99                 return EINTR;
100
101         for (i = 0; i < uio->uio_iov[0].iov_len; i++) {
102                 if (u->read_cons == u->read_prod)
103                         break;
104                 copyout(&u->read_buffer[MASK_READ_IDX(u->read_cons)], (char *)uio->uio_iov[0].iov_base+i, 1);
105                 u->read_cons++;
106                 uio->uio_resid--;
107         }
108         return 0;
109 }
110
111 static void queue_reply(struct xenbus_dev_data *u,
112                         char *data, unsigned int len)
113 {
114         int i;
115
116         for (i = 0; i < len; i++, u->read_prod++)
117                 u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
118
119         BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer));
120
121         wakeup(&u->read_waitq);
122 }
123
124 static int 
125 xenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
126 {
127         int err = 0;
128         struct xenbus_dev_data *u = dev->si_drv1;
129         struct xenbus_dev_transaction *trans;
130         void *reply;
131         int len = uio->uio_iov[0].iov_len;
132
133         if ((len + u->len) > sizeof(u->u.buffer))
134                 return EINVAL;
135
136         if (copyin(u->u.buffer + u->len, uio->uio_iov[0].iov_base, len) != 0)
137                 return EFAULT;
138
139         u->len += len;
140         if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
141                 return len;
142
143         switch (u->u.msg.type) {
144         case XS_TRANSACTION_START:
145         case XS_TRANSACTION_END:
146         case XS_DIRECTORY:
147         case XS_READ:
148         case XS_GET_PERMS:
149         case XS_RELEASE:
150         case XS_GET_DOMAIN_PATH:
151         case XS_WRITE:
152         case XS_MKDIR:
153         case XS_RM:
154         case XS_SET_PERMS:
155                 reply = xenbus_dev_request_and_reply(&u->u.msg);
156                 if (IS_ERR(reply)) {
157                         err = PTR_ERR(reply);
158                 } else {
159                         if (u->u.msg.type == XS_TRANSACTION_START) {
160                                 trans = kmalloc(sizeof(*trans), GFP_KERNEL);
161                                 trans->handle.id = simple_strtoul(reply, NULL, 0);
162                                 LIST_INSERT_HEAD(&u->transactions, trans, list);
163                         } else if (u->u.msg.type == XS_TRANSACTION_END) {
164                                 LIST_FOREACH(trans, &u->transactions,
165                                              list)
166                                         if (trans->handle.id ==
167                                             u->u.msg.tx_id)
168                                                 break;
169 #if 0 /* XXX does this mean the list is empty? */
170                                 BUG_ON(&trans->list == &u->transactions);
171 #endif
172                                 LIST_REMOVE(trans, list);
173                                 kfree(trans);
174                         }
175                         queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
176                         queue_reply(u, (char *)reply, u->u.msg.len);
177                         kfree(reply);
178                 }
179                 break;
180
181         default:
182                 err = EINVAL;
183                 break;
184         }
185
186         if (err == 0) {
187                 u->len = 0;
188                 err = len;
189         }
190
191         return err;
192 }
193
194 static int xenbus_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
195 {
196         struct xenbus_dev_data *u;
197
198         if (xen_start_info->store_evtchn == 0)
199                 return ENOENT;
200 #if 0 /* XXX figure out if equiv needed */
201         nonseekable_open(inode, filp);
202 #endif
203         u = kmalloc(sizeof(*u), GFP_KERNEL);
204         if (u == NULL)
205                 return ENOMEM;
206
207         memset(u, 0, sizeof(*u));
208         LIST_INIT(&u->transactions);
209
210         dev->si_drv1 = u;
211
212         return 0;
213 }
214
215 static int xenbus_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
216 {
217         struct xenbus_dev_data *u = dev->si_drv1;
218         struct xenbus_dev_transaction *trans, *tmp;
219
220         LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) {
221                 xenbus_transaction_end(trans->handle, 1);
222                 LIST_REMOVE(trans, list);
223                 kfree(trans);
224         }
225
226         kfree(u);
227         return 0;
228 }
229
230 static struct cdevsw xenbus_dev_cdevsw = {
231         .d_version = D_VERSION, 
232         .d_read = xenbus_dev_read,
233         .d_write = xenbus_dev_write,
234         .d_open = xenbus_dev_open,
235         .d_close = xenbus_dev_close,
236         .d_name = "xenbus_dev",
237 };
238
239 static int
240 xenbus_dev_sysinit(void)
241 {
242         make_dev(&xenbus_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, "xenbus");
243
244         return 0;
245 }
246 SYSINIT(xenbus_dev_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, xenbus_dev_sysinit, NULL);
247 /* SYSINIT NEEDED XXX */
248
249
250
251 /*
252  * Local variables:
253  *  c-file-style: "linux"
254  *  indent-tabs-mode: t
255  *  c-indent-level: 8
256  *  c-basic-offset: 8
257  *  tab-width: 8
258  * End:
259  */