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