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