1181624Skmacy/*
2214077Sgibbs * xenstore_dev.c
3181624Skmacy *
4214077Sgibbs * Driver giving user-space access to the kernel's connection to the
5214077Sgibbs * XenStore service.
6181624Skmacy *
7181624Skmacy * Copyright (c) 2005, Christian Limpach
8181624Skmacy * Copyright (c) 2005, Rusty Russell, IBM Corporation
9181624Skmacy *
10181624Skmacy * This file may be distributed separately from the Linux kernel, or
11181624Skmacy * incorporated into other software packages, subject to the following license:
12181624Skmacy *
13181624Skmacy * Permission is hereby granted, free of charge, to any person obtaining a copy
14181624Skmacy * of this source file (the "Software"), to deal in the Software without
15181624Skmacy * restriction, including without limitation the rights to use, copy, modify,
16181624Skmacy * merge, publish, distribute, sublicense, and/or sell copies of the Software,
17181624Skmacy * and to permit persons to whom the Software is furnished to do so, subject to
18181624Skmacy * the following conditions:
19181624Skmacy *
20181624Skmacy * The above copyright notice and this permission notice shall be included in
21181624Skmacy * all copies or substantial portions of the Software.
22181624Skmacy *
23181624Skmacy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24181624Skmacy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25181624Skmacy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26181624Skmacy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27181624Skmacy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28181624Skmacy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
29181624Skmacy * IN THE SOFTWARE.
30181624Skmacy */
31181624Skmacy
32181624Skmacy
33181624Skmacy#include <sys/cdefs.h>
34181624Skmacy__FBSDID("$FreeBSD$");
35181624Skmacy
36181624Skmacy#include <sys/types.h>
37181624Skmacy#include <sys/cdefs.h>
38181624Skmacy#include <sys/errno.h>
39181624Skmacy#include <sys/uio.h>
40181624Skmacy#include <sys/param.h>
41181624Skmacy#include <sys/systm.h>
42181624Skmacy#include <sys/proc.h>
43181624Skmacy#include <sys/kernel.h>
44181624Skmacy#include <sys/malloc.h>
45181624Skmacy#include <sys/conf.h>
46272318Sroyger#include <sys/module.h>
47181624Skmacy
48255040Sgibbs#include <xen/xen-os.h>
49214077Sgibbs
50186557Skmacy#include <xen/hypervisor.h>
51214077Sgibbs#include <xen/xenstore/xenstorevar.h>
52214077Sgibbs#include <xen/xenstore/xenstore_internal.h>
53181624Skmacy
54214077Sgibbsstruct xs_dev_transaction {
55214077Sgibbs	LIST_ENTRY(xs_dev_transaction) list;
56214077Sgibbs	struct xs_transaction handle;
57181624Skmacy};
58181624Skmacy
59214077Sgibbsstruct xs_dev_data {
60181624Skmacy	/* In-progress transaction. */
61214077Sgibbs	LIST_HEAD(xdd_list_head, xs_dev_transaction) transactions;
62181624Skmacy
63181624Skmacy	/* Partial request. */
64181624Skmacy	unsigned int len;
65181624Skmacy	union {
66181624Skmacy		struct xsd_sockmsg msg;
67181624Skmacy		char buffer[PAGE_SIZE];
68181624Skmacy	} u;
69181624Skmacy
70181624Skmacy	/* Response queue. */
71181624Skmacy#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
72181624Skmacy	char read_buffer[PAGE_SIZE];
73181624Skmacy	unsigned int read_cons, read_prod;
74181624Skmacy};
75186557Skmacy
76181624Skmacystatic int
77214077Sgibbsxs_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
78181624Skmacy{
79186557Skmacy	int error;
80278844Sroyger	struct xs_dev_data *u;
81181624Skmacy
82278844Sroyger	error = devfs_get_cdevpriv((void **)&u);
83278844Sroyger	if (error != 0)
84278844Sroyger		return (error);
85278844Sroyger
86186557Skmacy	while (u->read_prod == u->read_cons) {
87214077Sgibbs		error = tsleep(u, PCATCH, "xsdread", hz/10);
88186557Skmacy		if (error && error != EWOULDBLOCK)
89186557Skmacy			return (error);
90186557Skmacy	}
91181624Skmacy
92186557Skmacy	while (uio->uio_resid > 0) {
93181624Skmacy		if (u->read_cons == u->read_prod)
94181624Skmacy			break;
95186557Skmacy		error = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)],
96186557Skmacy		    1, uio);
97186557Skmacy		if (error)
98186557Skmacy			return (error);
99181624Skmacy		u->read_cons++;
100181624Skmacy	}
101186557Skmacy	return (0);
102181624Skmacy}
103181624Skmacy
104186557Skmacystatic void
105214077Sgibbsxs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len)
106181624Skmacy{
107181624Skmacy	int i;
108181624Skmacy
109181624Skmacy	for (i = 0; i < len; i++, u->read_prod++)
110181624Skmacy		u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
111181624Skmacy
112186557Skmacy	KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer),
113186557Skmacy	    ("xenstore reply too big"));
114181624Skmacy
115186557Skmacy	wakeup(u);
116181624Skmacy}
117181624Skmacy
118181624Skmacystatic int
119214077Sgibbsxs_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
120181624Skmacy{
121186557Skmacy	int error;
122278844Sroyger	struct xs_dev_data *u;
123214077Sgibbs	struct xs_dev_transaction *trans;
124181624Skmacy	void *reply;
125186557Skmacy	int len = uio->uio_resid;
126181624Skmacy
127278844Sroyger	error = devfs_get_cdevpriv((void **)&u);
128278844Sroyger	if (error != 0)
129278844Sroyger		return (error);
130278844Sroyger
131181624Skmacy	if ((len + u->len) > sizeof(u->u.buffer))
132186557Skmacy		return (EINVAL);
133181624Skmacy
134186557Skmacy	error = uiomove(u->u.buffer + u->len, len, uio);
135186557Skmacy	if (error)
136186557Skmacy		return (error);
137181624Skmacy
138181624Skmacy	u->len += len;
139181624Skmacy	if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
140186557Skmacy		return (0);
141181624Skmacy
142181624Skmacy	switch (u->u.msg.type) {
143181624Skmacy	case XS_TRANSACTION_START:
144181624Skmacy	case XS_TRANSACTION_END:
145181624Skmacy	case XS_DIRECTORY:
146181624Skmacy	case XS_READ:
147181624Skmacy	case XS_GET_PERMS:
148181624Skmacy	case XS_RELEASE:
149181624Skmacy	case XS_GET_DOMAIN_PATH:
150181624Skmacy	case XS_WRITE:
151181624Skmacy	case XS_MKDIR:
152181624Skmacy	case XS_RM:
153181624Skmacy	case XS_SET_PERMS:
154214077Sgibbs		error = xs_dev_request_and_reply(&u->u.msg, &reply);
155186557Skmacy		if (!error) {
156181624Skmacy			if (u->u.msg.type == XS_TRANSACTION_START) {
157214077Sgibbs				trans = malloc(sizeof(*trans), M_XENSTORE,
158186557Skmacy				    M_WAITOK);
159186557Skmacy				trans->handle.id = strtoul(reply, NULL, 0);
160181624Skmacy				LIST_INSERT_HEAD(&u->transactions, trans, list);
161181624Skmacy			} else if (u->u.msg.type == XS_TRANSACTION_END) {
162186557Skmacy				LIST_FOREACH(trans, &u->transactions, list)
163186557Skmacy					if (trans->handle.id == u->u.msg.tx_id)
164181624Skmacy						break;
165181624Skmacy#if 0 /* XXX does this mean the list is empty? */
166181624Skmacy				BUG_ON(&trans->list == &u->transactions);
167181624Skmacy#endif
168181624Skmacy				LIST_REMOVE(trans, list);
169214077Sgibbs				free(trans, M_XENSTORE);
170181624Skmacy			}
171214077Sgibbs			xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
172214077Sgibbs			xs_queue_reply(u, (char *)reply, u->u.msg.len);
173214077Sgibbs			free(reply, M_XENSTORE);
174181624Skmacy		}
175181624Skmacy		break;
176181624Skmacy
177181624Skmacy	default:
178186557Skmacy		error = EINVAL;
179181624Skmacy		break;
180181624Skmacy	}
181181624Skmacy
182186557Skmacy	if (error == 0)
183181624Skmacy		u->len = 0;
184181624Skmacy
185186557Skmacy	return (error);
186181624Skmacy}
187181624Skmacy
188278844Sroygerstatic void
189278844Sroygerxs_dev_dtor(void *arg)
190181624Skmacy{
191278844Sroyger	struct xs_dev_data *u = arg;
192214077Sgibbs	struct xs_dev_transaction *trans, *tmp;
193181624Skmacy
194181624Skmacy	LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) {
195214077Sgibbs		xs_transaction_end(trans->handle, 1);
196181624Skmacy		LIST_REMOVE(trans, list);
197214077Sgibbs		free(trans, M_XENSTORE);
198181624Skmacy	}
199181624Skmacy
200214077Sgibbs	free(u, M_XENSTORE);
201181624Skmacy}
202181624Skmacy
203278844Sroygerstatic int
204278844Sroygerxs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
205278844Sroyger{
206278844Sroyger	struct xs_dev_data *u;
207278844Sroyger	int error;
208278844Sroyger
209278844Sroyger	u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO);
210278844Sroyger	LIST_INIT(&u->transactions);
211278844Sroyger	error = devfs_set_cdevpriv(u, xs_dev_dtor);
212278844Sroyger	if (error != 0)
213278844Sroyger		free(u, M_XENSTORE);
214278844Sroyger
215278844Sroyger	return (error);
216278844Sroyger}
217278844Sroyger
218214077Sgibbsstatic struct cdevsw xs_dev_cdevsw = {
219181624Skmacy	.d_version = D_VERSION,
220214077Sgibbs	.d_read = xs_dev_read,
221214077Sgibbs	.d_write = xs_dev_write,
222214077Sgibbs	.d_open = xs_dev_open,
223214077Sgibbs	.d_name = "xs_dev",
224181624Skmacy};
225181624Skmacy
226272318Sroyger/*------------------ Private Device Attachment Functions  --------------------*/
227272318Sroyger/**
228272318Sroyger * \brief Identify instances of this device type in the system.
229272318Sroyger *
230272318Sroyger * \param driver  The driver performing this identify action.
231272318Sroyger * \param parent  The NewBus parent device for any devices this method adds.
232272318Sroyger */
233272318Sroygerstatic void
234272318Sroygerxs_dev_identify(driver_t *driver __unused, device_t parent)
235181624Skmacy{
236272318Sroyger	/*
237272318Sroyger	 * A single device instance for our driver is always present
238272318Sroyger	 * in a system operating under Xen.
239272318Sroyger	 */
240272318Sroyger	BUS_ADD_CHILD(parent, 0, driver->name, 0);
241272318Sroyger}
242272318Sroyger
243272318Sroyger/**
244298955Spfg * \brief Probe for the existence of the Xenstore device
245272318Sroyger *
246272318Sroyger * \param dev  NewBus device_t for this instance.
247272318Sroyger *
248272318Sroyger * \return  Always returns 0 indicating success.
249272318Sroyger */
250272318Sroygerstatic int
251272318Sroygerxs_dev_probe(device_t dev)
252272318Sroyger{
253272318Sroyger
254272318Sroyger	device_set_desc(dev, "Xenstore user-space device");
255272318Sroyger	return (0);
256272318Sroyger}
257272318Sroyger
258272318Sroyger/**
259272318Sroyger * \brief Attach the Xenstore device.
260272318Sroyger *
261272318Sroyger * \param dev  NewBus device_t for this instance.
262272318Sroyger *
263272318Sroyger * \return  On success, 0. Otherwise an errno value indicating the
264272318Sroyger *          type of failure.
265272318Sroyger */
266272318Sroygerstatic int
267272318Sroygerxs_dev_attach(device_t dev)
268272318Sroyger{
269272318Sroyger	struct cdev *xs_cdev;
270272318Sroyger
271278844Sroyger	xs_cdev = make_dev_credf(MAKEDEV_ETERNAL, &xs_dev_cdevsw, 0, NULL,
272278844Sroyger	    UID_ROOT, GID_WHEEL, 0400, "xen/xenstore");
273272318Sroyger	if (xs_cdev == NULL)
274272318Sroyger		return (EINVAL);
275272318Sroyger
276272318Sroyger	return (0);
277181624Skmacy}
278272318Sroyger
279272318Sroyger/*-------------------- Private Device Attachment Data  -----------------------*/
280272318Sroygerstatic device_method_t xs_dev_methods[] = {
281272318Sroyger	/* Device interface */
282272318Sroyger	DEVMETHOD(device_identify,	xs_dev_identify),
283272318Sroyger	DEVMETHOD(device_probe,         xs_dev_probe),
284272318Sroyger	DEVMETHOD(device_attach,        xs_dev_attach),
285272318Sroyger
286272318Sroyger	DEVMETHOD_END
287272318Sroyger};
288272318Sroyger
289272318SroygerDEFINE_CLASS_0(xs_dev, xs_dev_driver, xs_dev_methods, 0);
290272318Sroygerdevclass_t xs_dev_devclass;
291272318Sroyger
292272318SroygerDRIVER_MODULE(xs_dev, xenstore, xs_dev_driver, xs_dev_devclass,
293272318Sroyger    NULL, NULL);
294