1 /* $NetBSD: xenbus_dev.c,v 1.5 2006/05/07 21:49:56 bouyer 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.5 2006/05/07 21:49:56 bouyer 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 #include <machine/kernfs_machdep.h> 52 53 #include <machine/hypervisor.h> 54 #include <machine/xenbus.h> 55 #include "xenbus_comms.h" 56 57 static int xenbus_dev_read(void *); 58 static int xenbus_dev_write(void *); 59 static int xenbus_dev_open(void *); 60 static int xenbus_dev_close(void *); 61 static int xsd_port_read(void *); 62 63 struct xenbus_dev_transaction { 64 SLIST_ENTRY(xenbus_dev_transaction) trans_next; 65 struct xenbus_transaction *handle; 66 }; 67 68 #define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) 69 #define PRIVCMD_MODE (S_IRUSR | S_IWUSR) 70 static const struct kernfs_fileop xenbus_fileops[] = { 71 { .kf_fileop = KERNFS_FILEOP_OPEN, .kf_vop = xenbus_dev_open }, 72 { .kf_fileop = KERNFS_FILEOP_CLOSE, .kf_vop = xenbus_dev_close }, 73 { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xenbus_dev_read }, 74 { .kf_fileop = KERNFS_FILEOP_WRITE, .kf_vop = xenbus_dev_write }, 75 }; 76 77 #define XSD_MODE (S_IRUSR) 78 static const struct kernfs_fileop xsd_port_fileops[] = { 79 { .kf_fileop = KERNFS_FILEOP_READ, .kf_vop = xsd_port_read }, 80 }; 81 82 void 83 xenbus_kernfs_init() 84 { 85 kernfs_entry_t *dkt; 86 kfstype kfst; 87 88 kfst = KERNFS_ALLOCTYPE(xenbus_fileops); 89 KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK); 90 KERNFS_INITENTRY(dkt, DT_REG, "xenbus", NULL, kfst, VREG, 91 PRIVCMD_MODE); 92 kernfs_addentry(kernxen_pkt, dkt); 93 94 kfst = KERNFS_ALLOCTYPE(xsd_port_fileops); 95 KERNFS_ALLOCENTRY(dkt, M_TEMP, M_WAITOK); 96 KERNFS_INITENTRY(dkt, DT_REG, "xsd_port", NULL, kfst, VREG, XSD_MODE); 97 kernfs_addentry(kernxen_pkt, dkt); 98 } 99 100 struct xenbus_dev_data { 101 #define BUFFER_SIZE (PAGE_SIZE) 102 #define MASK_READ_IDX(idx) ((idx)&(BUFFER_SIZE-1)) 103 /* In-progress transaction. */ 104 SLIST_HEAD(, xenbus_dev_transaction) transactions; 105 106 /* Partial request. */ 107 unsigned int len; 108 union { 109 struct xsd_sockmsg msg; 110 char buffer[BUFFER_SIZE]; 111 } u; 112 113 /* Response queue. */ 114 char read_buffer[BUFFER_SIZE]; 115 unsigned int read_cons, read_prod; 116 }; 117 118 static int 119 xenbus_dev_read(void *v) 120 { 121 struct vop_read_args /* { 122 struct vnode *a_vp; 123 struct uio *a_uio; 124 int a_ioflag; 125 struct ucred *a_cred; 126 } */ *ap = v; 127 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 128 struct uio *uio = ap->a_uio; 129 struct xenbus_dev_data *u = kfs->kfs_v; 130 int err; 131 off_t offset; 132 int s = spltty(); 133 134 while (u->read_prod == u->read_cons) { 135 err = tsleep(u, PRIBIO | PCATCH, "xbrd", 0); 136 if (err) 137 goto end; 138 } 139 offset = uio->uio_offset; 140 141 if (u->read_cons > u->read_prod) { 142 err = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 143 0U - u->read_cons, uio); 144 if (err) 145 goto end; 146 u->read_cons += (uio->uio_offset - offset); 147 offset = uio->uio_offset; 148 } 149 err = uiomove(&u->read_buffer[MASK_READ_IDX(u->read_cons)], 150 u->read_prod - u->read_cons, uio); 151 if (err == 0) 152 u->read_cons += (uio->uio_offset - offset); 153 154 end: 155 splx(s); 156 return err; 157 } 158 159 static void 160 queue_reply(struct xenbus_dev_data *u, 161 char *data, unsigned int len) 162 { 163 int i; 164 165 for (i = 0; i < len; i++, u->read_prod++) 166 u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i]; 167 168 KASSERT((u->read_prod - u->read_cons) <= sizeof(u->read_buffer)); 169 170 wakeup(&u); 171 } 172 173 static int 174 xenbus_dev_write(void *v) 175 { 176 struct vop_write_args /* { 177 struct vnode *a_vp; 178 struct uio *a_uio; 179 int a_ioflag; 180 struct ucred *a_cred; 181 } */ *ap = v; 182 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 183 struct uio *uio = ap->a_uio; 184 185 struct xenbus_dev_data *u = kfs->kfs_v; 186 struct xenbus_dev_transaction *trans; 187 void *reply; 188 int err; 189 size_t size; 190 191 if (uio->uio_offset < 0) 192 return EINVAL; 193 size = uio->uio_resid; 194 195 if ((size + u->len) > sizeof(u->u.buffer)) 196 return EINVAL; 197 198 err = uiomove(u->u.buffer + u->len, sizeof(u->u.buffer) - u->len, uio); 199 if (err) 200 return err; 201 202 u->len += size; 203 if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) 204 return 0; 205 206 switch (u->u.msg.type) { 207 case XS_TRANSACTION_START: 208 case XS_TRANSACTION_END: 209 case XS_DIRECTORY: 210 case XS_READ: 211 case XS_GET_PERMS: 212 case XS_RELEASE: 213 case XS_GET_DOMAIN_PATH: 214 case XS_WRITE: 215 case XS_MKDIR: 216 case XS_RM: 217 case XS_SET_PERMS: 218 err = xenbus_dev_request_and_reply(&u->u.msg, &reply); 219 if (err == 0) { 220 if (u->u.msg.type == XS_TRANSACTION_START) { 221 trans = malloc(sizeof(*trans), M_DEVBUF, 222 M_WAITOK); 223 trans->handle = (struct xenbus_transaction *) 224 strtoul(reply, NULL, 0); 225 SLIST_INSERT_HEAD(&u->transactions, 226 trans, trans_next); 227 } else if (u->u.msg.type == XS_TRANSACTION_END) { 228 SLIST_FOREACH(trans, &u->transactions, 229 trans_next) { 230 if ((unsigned long)trans->handle == 231 (unsigned long)u->u.msg.tx_id) 232 break; 233 } 234 KASSERT(trans != NULL); 235 SLIST_REMOVE(&u->transactions, trans, 236 xenbus_dev_transaction, trans_next); 237 free(trans, M_DEVBUF); 238 } 239 queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); 240 queue_reply(u, (char *)reply, u->u.msg.len); 241 free(reply, M_DEVBUF); 242 } 243 break; 244 245 default: 246 err = EINVAL; 247 break; 248 } 249 250 if (err == 0) { 251 u->len = 0; 252 } 253 254 return err; 255 } 256 257 static int 258 xenbus_dev_open(void *v) 259 { 260 struct vop_open_args /* { 261 struct vnode *a_vp; 262 int a_mode; 263 struct ucred *a_cred; 264 struct lwp *a_l; 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 struct lwp *a_l; 293 } */ *ap = v; 294 struct kernfs_node *kfs = VTOKERN(ap->a_vp); 295 296 struct xenbus_dev_data *u = kfs->kfs_v; 297 struct xenbus_dev_transaction *trans; 298 299 while (!SLIST_EMPTY(&u->transactions)) { 300 trans = SLIST_FIRST(&u->transactions); 301 xenbus_transaction_end(trans->handle, 1); 302 SLIST_REMOVE_HEAD(&u->transactions, trans_next); 303 free(trans, M_DEVBUF); 304 } 305 306 free(u, M_DEVBUF); 307 kfs->kfs_v = NULL; 308 309 return 0; 310 } 311 312 #define LD_STRLEN 21 /* a 64bit integer needs 20 digits in base10 */ 313 314 static int 315 xsd_port_read(void *v) 316 { 317 struct vop_read_args /* { 318 struct vnode *a_vp; 319 struct uio *a_uio; 320 int a_ioflag; 321 struct ucred *a_cred; 322 } */ *ap = v; 323 struct uio *uio = ap->a_uio; 324 int off, error; 325 size_t len; 326 char strbuf[LD_STRLEN], *bf; 327 328 off = (int)uio->uio_offset; 329 if (off < 0) 330 return EINVAL; 331 332 len = snprintf(strbuf, sizeof(strbuf), "%ld\n", 333 (long)xen_start_info.store_evtchn); 334 if (off >= len) { 335 bf = strbuf; 336 len = 0; 337 } else { 338 bf = &strbuf[off]; 339 len -= off; 340 } 341 error = uiomove(bf, len, uio); 342 return error; 343 } 344 345 /* 346 * Local variables: 347 * c-file-style: "linux" 348 * indent-tabs-mode: t 349 * c-indent-level: 8 350 * c-basic-offset: 8 351 * tab-width: 8 352 * End: 353 */ 354