xenstore_dev.c revision 181889
1184610Salfred/*
2184610Salfred * xenbus_dev.c
3184610Salfred *
4184610Salfred * Driver giving user-space access to the kernel's xenbus connection
5184610Salfred * to xenstore.
6184610Salfred *
7188412Sthompsa * Copyright (c) 2005, Christian Limpach
8184610Salfred * Copyright (c) 2005, Rusty Russell, IBM Corporation
9184610Salfred *
10184610Salfred * This file may be distributed separately from the Linux kernel, or
11184610Salfred * incorporated into other software packages, subject to the following license:
12184610Salfred *
13184610Salfred * Permission is hereby granted, free of charge, to any person obtaining a copy
14184610Salfred * of this source file (the "Software"), to deal in the Software without
15184610Salfred * restriction, including without limitation the rights to use, copy, modify,
16184610Salfred * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17184610Salfred * and to permit persons to whom the Software is furnished to do so, subject to
18184610Salfred * the following conditions:
19184610Salfred *
20184610Salfred * The above copyright notice and this permission notice shall be included in
21184610Salfred * all copies or substantial portions of the Software.
22184610Salfred *
23184610Salfred * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24184610Salfred * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25184610Salfred * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26184610Salfred * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27184610Salfred * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28184610Salfred * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29184610Salfred * IN THE SOFTWARE.
30184610Salfred */
31184610Salfred
32184610Salfred
33184610Salfred#include <sys/cdefs.h>
34184610Salfred__FBSDID("$FreeBSD: head/sys/xen/xenbus/xenbus_dev.c 181889 2008-08-20 02:42:08Z kmacy $");
35184610Salfred
36184610Salfred#include <sys/types.h>
37184610Salfred#include <sys/cdefs.h>
38184610Salfred#include <sys/errno.h>
39184610Salfred#include <sys/uio.h>
40184610Salfred#include <sys/param.h>
41184610Salfred#include <sys/systm.h>
42184610Salfred#include <sys/proc.h>
43184610Salfred#include <sys/kernel.h>
44184610Salfred#include <sys/malloc.h>
45184610Salfred#include <sys/conf.h>
46188746Sthompsa
47188942Sthompsa
48188942Sthompsa#include <machine/xen/xen-os.h>
49188942Sthompsa#include <machine/xen/hypervisor.h>
50188942Sthompsa#include <machine/xen/xenbus.h>
51184610Salfred#include <machine/xen/hypervisor.h>
52184610Salfred#include <xen/xenbus/xenbus_comms.h>
53184610Salfred
54188942Sthompsa
55188942Sthompsa
56188942Sthompsa
57188942Sthompsa#define kmalloc(size, unused) malloc(size, M_DEVBUF, M_WAITOK)
58188942Sthompsa#define BUG_ON        PANIC_IF
59188942Sthompsa#define semaphore     sema
60188942Sthompsa#define rw_semaphore  sema
61188942Sthompsa#define DEFINE_SPINLOCK(lock) struct mtx lock
62188942Sthompsa#define DECLARE_MUTEX(lock) struct sema lock
63184610Salfred#define u32           uint32_t
64188942Sthompsa#define simple_strtoul strtoul
65188942Sthompsa
66184610Salfredstruct xenbus_dev_transaction {
67184610Salfred	LIST_ENTRY(xenbus_dev_transaction) list;
68184610Salfred	struct xenbus_transaction handle;
69184610Salfred};
70184610Salfred
71184610Salfredstruct xenbus_dev_data {
72188942Sthompsa	/* In-progress transaction. */
73184610Salfred	LIST_HEAD(xdd_list_head, xenbus_dev_transaction) transactions;
74193045Sthompsa
75193045Sthompsa	/* Partial request. */
76193045Sthompsa	unsigned int len;
77193045Sthompsa	union {
78184610Salfred		struct xsd_sockmsg msg;
79193045Sthompsa		char buffer[PAGE_SIZE];
80193045Sthompsa	} u;
81193045Sthompsa
82193045Sthompsa	/* Response queue. */
83193045Sthompsa#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
84193045Sthompsa	char read_buffer[PAGE_SIZE];
85188412Sthompsa	unsigned int read_cons, read_prod;
86185948Sthompsa	int read_waitq;
87184610Salfred};
88184610Salfred#if 0
89184610Salfredstatic struct proc_dir_entry *xenbus_dev_intf;
90184610Salfred#endif
91192502Sthompsastatic int
92192502Sthompsaxenbus_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
93188412Sthompsa{
94184610Salfred	int i = 0;
95184610Salfred	struct xenbus_dev_data *u = dev->si_drv1;
96192984Sthompsa
97184610Salfred	if (wait_event_interruptible(&u->read_waitq,
98190734Sthompsa				     u->read_prod != u->read_cons))
99184610Salfred		return EINTR;
100184610Salfred
101190734Sthompsa	for (i = 0; i < uio->uio_iov[0].iov_len; i++) {
102184610Salfred		if (u->read_cons == u->read_prod)
103190734Sthompsa			break;
104190734Sthompsa		copyout(&u->read_buffer[MASK_READ_IDX(u->read_cons)], (char *)uio->uio_iov[0].iov_base+i, 1);
105190734Sthompsa		u->read_cons++;
106190734Sthompsa		uio->uio_resid--;
107190734Sthompsa	}
108192499Sthompsa	return 0;
109184610Salfred}
110184610Salfred
111190734Sthompsastatic void queue_reply(struct xenbus_dev_data *u,
112184610Salfred			char *data, unsigned int len)
113184610Salfred{
114190734Sthompsa	int i;
115184610Salfred
116190734Sthompsa	for (i = 0; i < len; i++, u->read_prod++)
117190734Sthompsa		u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
118190734Sthompsa
119190734Sthompsa	BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer));
120190734Sthompsa
121192499Sthompsa	wakeup(&u->read_waitq);
122184610Salfred}
123184610Salfred
124190734Sthompsastatic int
125184610Salfredxenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
126184610Salfred{
127190734Sthompsa	int err = 0;
128184610Salfred	struct xenbus_dev_data *u = dev->si_drv1;
129190734Sthompsa	struct xenbus_dev_transaction *trans;
130190734Sthompsa	void *reply;
131190734Sthompsa	int len = uio->uio_iov[0].iov_len;
132190734Sthompsa
133190734Sthompsa	if ((len + u->len) > sizeof(u->u.buffer))
134184610Salfred		return EINVAL;
135190734Sthompsa
136190734Sthompsa	if (copyin(u->u.buffer + u->len, uio->uio_iov[0].iov_base, len) != 0)
137190734Sthompsa		return EFAULT;
138190734Sthompsa
139190734Sthompsa	u->len += len;
140190734Sthompsa	if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
141190734Sthompsa		return len;
142190734Sthompsa
143190734Sthompsa	switch (u->u.msg.type) {
144190734Sthompsa	case XS_TRANSACTION_START:
145190734Sthompsa	case XS_TRANSACTION_END:
146190734Sthompsa	case XS_DIRECTORY:
147184610Salfred	case XS_READ:
148184610Salfred	case XS_GET_PERMS:
149184610Salfred	case XS_RELEASE:
150184610Salfred	case XS_GET_DOMAIN_PATH:
151188942Sthompsa	case XS_WRITE:
152184610Salfred	case XS_MKDIR:
153184610Salfred	case XS_RM:
154184610Salfred	case XS_SET_PERMS:
155184610Salfred		reply = xenbus_dev_request_and_reply(&u->u.msg);
156184610Salfred		if (IS_ERR(reply)) {
157184610Salfred			err = PTR_ERR(reply);
158184610Salfred		} else {
159184610Salfred			if (u->u.msg.type == XS_TRANSACTION_START) {
160184610Salfred				trans = kmalloc(sizeof(*trans), GFP_KERNEL);
161184610Salfred				trans->handle.id = simple_strtoul(reply, NULL, 0);
162184610Salfred				LIST_INSERT_HEAD(&u->transactions, trans, list);
163184610Salfred			} else if (u->u.msg.type == XS_TRANSACTION_END) {
164184610Salfred				LIST_FOREACH(trans, &u->transactions,
165184610Salfred					     list)
166184610Salfred					if (trans->handle.id ==
167184610Salfred					    u->u.msg.tx_id)
168184610Salfred						break;
169184610Salfred#if 0 /* XXX does this mean the list is empty? */
170184610Salfred				BUG_ON(&trans->list == &u->transactions);
171189275Sthompsa#endif
172184610Salfred				LIST_REMOVE(trans, list);
173188942Sthompsa				kfree(trans);
174188942Sthompsa			}
175184610Salfred			queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
176184610Salfred			queue_reply(u, (char *)reply, u->u.msg.len);
177192984Sthompsa			kfree(reply);
178188412Sthompsa		}
179188412Sthompsa		break;
180188412Sthompsa
181188412Sthompsa	default:
182188412Sthompsa		err = EINVAL;
183188412Sthompsa		break;
184188412Sthompsa	}
185188412Sthompsa
186192984Sthompsa	if (err == 0) {
187184610Salfred		u->len = 0;
188184610Salfred		err = len;
189184610Salfred	}
190184610Salfred
191184610Salfred	return err;
192184610Salfred}
193184610Salfred
194184610Salfredstatic int xenbus_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
195184610Salfred{
196184610Salfred	struct xenbus_dev_data *u;
197184610Salfred
198184610Salfred	if (xen_start_info->store_evtchn == 0)
199184610Salfred		return ENOENT;
200184610Salfred#if 0 /* XXX figure out if equiv needed */
201184610Salfred	nonseekable_open(inode, filp);
202184610Salfred#endif
203184610Salfred	u = kmalloc(sizeof(*u), GFP_KERNEL);
204184610Salfred	if (u == NULL)
205184610Salfred		return ENOMEM;
206184610Salfred
207184610Salfred	memset(u, 0, sizeof(*u));
208192984Sthompsa	LIST_INIT(&u->transactions);
209184610Salfred
210184610Salfred        dev->si_drv1 = u;
211184610Salfred
212184610Salfred	return 0;
213188412Sthompsa}
214192984Sthompsa
215188412Sthompsastatic int xenbus_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
216188412Sthompsa{
217188412Sthompsa	struct xenbus_dev_data *u = dev->si_drv1;
218188412Sthompsa	struct xenbus_dev_transaction *trans, *tmp;
219188412Sthompsa
220184610Salfred	LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) {
221184610Salfred		xenbus_transaction_end(trans->handle, 1);
222184610Salfred		LIST_REMOVE(trans, list);
223184610Salfred		kfree(trans);
224192984Sthompsa	}
225192984Sthompsa
226192984Sthompsa	kfree(u);
227192984Sthompsa	return 0;
228192984Sthompsa}
229192984Sthompsa
230184610Salfredstatic struct cdevsw xenbus_dev_cdevsw = {
231184610Salfred	.d_version = D_VERSION,
232184610Salfred	.d_read = xenbus_dev_read,
233184610Salfred	.d_write = xenbus_dev_write,
234184610Salfred	.d_open = xenbus_dev_open,
235184610Salfred	.d_close = xenbus_dev_close,
236184610Salfred	.d_name = "xenbus_dev",
237184610Salfred};
238188412Sthompsa
239184610Salfredstatic int
240184610Salfredxenbus_dev_sysinit(void)
241184610Salfred{
242184610Salfred	make_dev(&xenbus_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, "xenbus");
243184610Salfred
244184610Salfred	return 0;
245184610Salfred}
246184610SalfredSYSINIT(xenbus_dev_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, xenbus_dev_sysinit, NULL);
247184610Salfred/* SYSINIT NEEDED XXX */
248184610Salfred
249184610Salfred
250184610Salfred
251184610Salfred/*
252184610Salfred * Local variables:
253184610Salfred *  c-file-style: "linux"
254184610Salfred *  indent-tabs-mode: t
255184610Salfred *  c-indent-level: 8
256184610Salfred *  c-basic-offset: 8
257184610Salfred *  tab-width: 8
258184610Salfred * End:
259184610Salfred */
260184610Salfred