1 /* $NetBSD: xenbus_dev.c,v 1.8 2009/03/16 06:17:39 cegger Exp $ */ 2 /* 3 * xenbus_dev.c 4 * 5 * Driver giving user-space access to the kernel's xenbus connection 6 * to xenstore. 7 * 8 * Copyright (c) 2005, Christian Limpach 9 * Copyright (c) 2005, Rusty Russell, IBM Corporation 10 * 11 * This file may be distributed separately from the Linux kernel, or 12 * incorporated into other software packages, subject to the following license: 13 * 14 * Permission is hereby granted, free of charge, to any person obtaining a copy 15 * of this source file (the "Software"), to deal in the Software without 16 * restriction, including without limitation the rights to use, copy, modify, 17 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 18 * and to permit persons to whom the Software is furnished to do so, subject to 19 * the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be included in 22 * all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 30 * IN THE SOFTWARE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: xenbus_dev.c,v 1.8 2009/03/16 06:17:39 cegger Exp $"); 35 36 #include "opt_xen.h" 37 38 #include <sys/types.h> 39 #include <sys/null.h> 40 #include <sys/errno.h> 41 #include <sys/malloc.h> 42 #include <sys/param.h> 43 #include <sys/proc.h> 44 #include <sys/systm.h> 45 #include <sys/dirent.h> 46 #include <sys/stat.h> 47 #include <sys/tree.h> 48 #include <sys/vnode.h> 49 #include <miscfs/specfs/specdev.h> 50 #include <miscfs/kernfs/kernfs.h> 51 52 #include <xen/kernfs_machdep.h> 53 54 #include <xen/hypervisor.h> 55 #include <xen/xenbus.h> 56 #include "xenbus_comms.h" 57 58 static int xenbus_dev_read(void *); 59 static int xenbus_dev_write(void *); 60 static int xenbus_dev_open(void *); 61 static int xenbus_dev_close(void *); 62 static int xsd_port_read(void *); 63 64 struct xenbus_dev_transaction { 65 SLIST_ENTRY(xenbus_dev_transaction) trans_next; 66 struct xenbus_transaction *handle; 67 }; 68 69 #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 70 #define PRIVCMD_MODE (S_IRUSR | S_IWUSR) 71 static const struct kernfs_fileop xenbus_fileops[] = { 72 { .kf_fileop = KERNFS_FILEOP_OPEN, .kf_vop = xenbus_dev_open }, 73 { .kf_fileop = KERNFS_FILEOP_CLOSE, .kf_vop = xenbus_dev_close }, 74 { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xenbus_dev_read }, 75 { .kf_fileop = KERNFS_FILEOP_WRITE, .kf_vop = xenbus_dev_write }, 76 }; 77 78 #define XSD_MODE (S_IRUSR) 79 static const struct kernfs_fileop xsd_port_fileops[] = { 80 { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xsd_port_read }, 81 }; 82 83 void 84 xenbus_kernfs_init(void) 85 { 86 kernfs_entry_t *dkt; 87 kfstype kfst; 88 89 kfst = KERNFS_ALLOCTYPE(xenbus_fileops); 90 KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK); 91 KERNFS_INITENTRY(dkt, DT_REG, "xenbus", NULL, kfst, VREG, 92 PRIVCMD_MODE); 93 kernfs_addentry(kernxen_pkt, dkt); 94 95 kfst = KERNFS_ALLOCTYPE(xsd_port_fileops); 96 KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK); 97 KERNFS_INITENTRY(dkt, DT_REG, "xsd_port", NULL, kfst, VREG, XSD_MODE); 98 kernfs_addentry(kernxen_pkt, dkt); 99 } 100 101 struct xenbus_dev_data { 102 #define BUFFER_SIZE (PAGE_SIZE) 103 #define MASK_READ_IDX(idx) ((idx)&(BUFFER_SIZE-1)) 104 /* In-progress transaction. */ 105 SLIST_HEAD(, xenbus_dev_transaction) transactions; 106 107 /* Partial request. */ 108 unsigned int len; 109 union { 110 struct xsd_sockmsg msg; 111 char buffer[BUFFER_SIZE]; 112 } u; 113 114 /* Response queue. */ 115 char read_buffer[BUFFER_SIZE]; 116 unsigned int read_cons, read_prod; 117 }; 118 119 static int 120 xenbus_dev_read(void *v) 121 { 122 struct vop_read_args /* { 123 struct vnode *a_vp; 124 struct uio *a_uio; 125 int a_ioflag; 126 struct ucred *a_cred; 127 } */ *ap = v; 128 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 129 struct uio *uio = ap->a_uio; 130 struct xenbus_dev_data *u = kfs->kfs_v; 131 int err; 132 off_t offset; 133 int s = spltty(); 134 135 while (u->read_prod == u->read_cons) { 136 err = tsleep(u, PRIBIO | PCATCH, "xbrd", 0); 137 if (err) 138 goto end; 139 } 140 offset = uio->uio_offset; 141 142 if (u->read_cons > u->read_prod) { 143 err = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 144 0U - u->read_cons, uio); 145 if (err) 146 goto end; 147 u->read_cons += (uio->uio_offset - offset); 148 offset = uio->uio_offset; 149 } 150 err = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 151 u->read_prod - u->read_cons, uio); 152 if (err == 0) 153 u->read_cons += (uio->uio_offset - offset); 154 155 end: 156 splx(s); 157 return err; 158 } 159 160 static void 161 queue_reply(struct xenbus_dev_data *u, 162 char *data, unsigned int len) 163 { 164 int i; 165 166 for (i = 0; i < len; i++, u->read_prod++) 167 u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; 168 169 KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer)); 170 171 wakeup(&u); 172 } 173 174 static int 175 xenbus_dev_write(void *v) 176 { 177 struct vop_write_args /* { 178 struct vnode *a_vp; 179 struct uio *a_uio; 180 int a_ioflag; 181 struct ucred *a_cred; 182 } */ *ap = v; 183 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 184 struct uio *uio = ap->a_uio; 185 186 struct xenbus_dev_data *u = kfs->kfs_v; 187 struct xenbus_dev_transaction *trans; 188 void *reply; 189 int err; 190 size_t size; 191 192 if (uio->uio_offset < 0) 193 return EINVAL; 194 size = uio->uio_resid; 195 196 if ((size + u->len) > sizeof(u->u.buffer)) 197 return EINVAL; 198 199 err = uiomove(u->u.buffer + u->len, sizeof(u->u.buffer) - u->len, uio); 200 if (err) 201 return err; 202 203 u->len += size; 204 if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) 205 return 0; 206 207 switch (u->u.msg.type) { 208 case XS_TRANSACTION_START: 209 case XS_TRANSACTION_END: 210 case XS_DIRECTORY: 211 case XS_READ: 212 case XS_GET_PERMS: 213 case XS_RELEASE: 214 case XS_GET_DOMAIN_PATH: 215 case XS_WRITE: 216 case XS_MKDIR: 217 case XS_RM: 218 case XS_SET_PERMS: 219 err = xenbus_dev_request_and_reply(&u->u.msg, &reply); 220 if (err == 0) { 221 if (u->u.msg.type == XS_TRANSACTION_START) { 222 trans = malloc(sizeof(*trans), M_DEVBUF, 223 M_WAITOK); 224 trans->handle = (struct xenbus_transaction *) 225 strtoul(reply, NULL, 0); 226 SLIST_INSERT_HEAD(&u->transactions, 227 trans, trans_next); 228 } else if (u->u.msg.type == XS_TRANSACTION_END) { 229 SLIST_FOREACH(trans, &u->transactions, 230 trans_next) { 231 if ((unsigned long)trans->handle == 232 (unsigned long)u->u.msg.tx_id) 233 break; 234 } 235 KASSERT(trans != NULL); 236 SLIST_REMOVE(&u->transactions, trans, 237 xenbus_dev_transaction, trans_next); 238 free(trans, M_DEVBUF); 239 } 240 queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 241 queue_reply(u, (char *)reply, u->u.msg.len); 242 free(reply, M_DEVBUF); 243 } 244 break; 245 246 default: 247 err = EINVAL; 248 break; 249 } 250 251 if (err == 0) { 252 u->len = 0; 253 } 254 255 return err; 256 } 257 258 static int 259 xenbus_dev_open(void *v) 260 { 261 struct vop_open_args /* { 262 struct vnode *a_vp; 263 int a_mode; 264 struct ucred *a_cred; 265 } */ *ap = v; 266 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 267 268 struct xenbus_dev_data *u; 269 270 if (xen_start_info.store_evtchn == 0) 271 return ENOENT; 272 273 u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK); 274 if (u == NULL) 275 return ENOMEM; 276 277 memset(u, 0, sizeof(*u)); 278 SLIST_INIT(&u->transactions); 279 280 kfs->kfs_v = u; 281 282 return 0; 283 } 284 285 static int 286 xenbus_dev_close(void *v) 287 { 288 struct vop_close_args /* { 289 struct vnode *a_vp; 290 int a_fflag; 291 struct ucred *a_cred; 292 } */ *ap = v; 293 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 294 295 struct xenbus_dev_data *u = kfs->kfs_v; 296 struct xenbus_dev_transaction *trans; 297 298 while (!SLIST_EMPTY(&u->transactions)) { 299 trans = SLIST_FIRST(&u->transactions); 300 xenbus_transaction_end(trans->handle, 1); 301 SLIST_REMOVE_HEAD(&u->transactions, trans_next); 302 free(trans, M_DEVBUF); 303 } 304 305 free(u, M_DEVBUF); 306 kfs->kfs_v = NULL; 307 308 return 0; 309 } 310 311 #define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */ 312 313 static int 314 xsd_port_read(void *v) 315 { 316 struct vop_read_args /* { 317 struct vnode *a_vp; 318 struct uio *a_uio; 319 int a_ioflag; 320 struct ucred *a_cred; 321 } */ *ap = v; 322 struct uio *uio = ap->a_uio; 323 int off, error; 324 size_t len; 325 char strbuf[LD_STRLEN], *bf; 326 327 off = (int)uio->uio_offset; 328 if (off < 0) 329 return EINVAL; 330 331 len = snprintf(strbuf, sizeof(strbuf), "%ld\n", 332 (long)xen_start_info.store_evtchn); 333 if (off >= len) { 334 bf = strbuf; 335 len = 0; 336 } else { 337 bf = &strbuf[off]; 338 len -= off; 339 } 340 error = uiomove(bf, len, uio); 341 return error; 342 } 343 344 /* 345 * Local variables: 346 * c-file-style: "linux" 347 * indent-tabs-mode: t 348 * c-indent-level: 8 349 * c-basic-offset: 8 350 * tab-width: 8 351 * End: 352 */ 353