win-pvdrivers

annotate xenpci/xenbus.c @ 264:91d40c6c314f

implement possible fix for bug 5812
author Andy Grover <andy.grover@oracle.com>
date Fri May 02 17:28:27 2008 -0700 (2008-05-02)
parents 58d13f9f8ef3
children 3673f1f07746
rev   line source
james@0 1 /*
james@0 2 PV Drivers for Windows Xen HVM Domains
james@0 3 Copyright (C) 2007 James Harper
james@0 4
james@0 5 This program is free software; you can redistribute it and/or
james@0 6 modify it under the terms of the GNU General Public License
james@0 7 as published by the Free Software Foundation; either version 2
james@0 8 of the License, or (at your option) any later version.
james@0 9
james@0 10 This program is distributed in the hope that it will be useful,
james@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@0 13 GNU General Public License for more details.
james@0 14
james@0 15 You should have received a copy of the GNU General Public License
james@0 16 along with this program; if not, write to the Free Software
james@0 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@0 18 */
james@0 19
james@0 20 #include "xenpci.h"
james@0 21 #include "io/xs_wire.h"
james@0 22 #include <stdlib.h>
james@0 23
james@0 24 #pragma warning( disable : 4204 )
james@0 25 #pragma warning( disable : 4221 )
james@0 26
andy@15 27 struct write_req {
andy@15 28 const void *data;
andy@15 29 unsigned len;
james@0 30 };
james@0 31
james@0 32 static void
james@0 33 XenBus_ReadThreadProc(PVOID StartContext);
james@0 34 static void
james@0 35 XenBus_WatchThreadProc(PVOID StartContext);
james@0 36 static BOOLEAN
james@0 37 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext);
james@0 38
andy@15 39 static int allocate_xenbus_id(WDFDEVICE Device)
james@0 40 {
andy@15 41 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
andy@15 42
james@0 43 static int probe;
james@0 44 int o_probe;
james@0 45
james@134 46 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 47
james@0 48 for (;;)
james@0 49 {
james@0 50 // spin_lock(&req_lock);
andy@15 51 if (xpdd->nr_live_reqs < NR_XB_REQS)
james@0 52 break;
james@0 53 // spin_unlock(&req_lock);
james@0 54 // wait_event(req_wq, (nr_live_reqs < NR_REQS));
james@0 55 }
james@0 56
james@0 57 o_probe = probe;
james@0 58
james@0 59 for (;;)
james@0 60 {
andy@15 61 if (!xpdd->req_info[o_probe].In_Use)
james@0 62 break;
andy@15 63 o_probe = (o_probe + 1) % NR_XB_REQS;
james@0 64 // BUG_ON(o_probe == probe);
james@0 65 }
andy@15 66 xpdd->nr_live_reqs++;
andy@15 67 xpdd->req_info[o_probe].In_Use = 1;
andy@15 68 probe = (o_probe + 1) % NR_XB_REQS;
james@0 69 //spin_unlock(&req_lock);
james@0 70 //init_waitqueue_head(&req_info[o_probe].waitq);
andy@15 71 KeInitializeEvent(&xpdd->req_info[o_probe].WaitEvent, SynchronizationEvent, FALSE);
james@0 72
james@134 73 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 74
james@0 75 return o_probe;
james@0 76 }
james@0 77
andy@15 78 static void release_xenbus_id(WDFDEVICE Device, int id)
james@0 79 {
andy@15 80 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
andy@15 81
james@0 82 // BUG_ON(!req_info[id].in_use);
james@0 83 // spin_lock(&req_lock);
andy@15 84 xpdd->req_info[id].In_Use = 0;
andy@15 85 xpdd->nr_live_reqs--;
andy@15 86 xpdd->req_info[id].In_Use = 0;
james@0 87 // if (nr_live_reqs == NR_REQS - 1)
james@0 88 // wake_up(&req_wq);
james@0 89 // spin_unlock(&req_lock);
james@0 90 }
james@0 91
james@157 92 // This routine free's the rep structure if there was an error!!!
james@0 93 static char *errmsg(struct xsd_sockmsg *rep)
james@0 94 {
james@0 95 char *res;
andy@15 96
james@0 97 if (!rep) {
james@0 98 char msg[] = "No reply";
james@0 99 size_t len = strlen(msg) + 1;
james@0 100 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
james@0 101 }
james@0 102 if (rep->type != XS_ERROR)
james@0 103 return NULL;
james@0 104 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
james@0 105 memcpy(res, rep + 1, rep->len);
james@0 106 res[rep->len] = 0;
james@0 107 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 108 return res;
james@0 109 }
james@0 110
james@0 111 static void memcpy_from_ring(const void *Ring,
james@0 112 void *Dest,
james@0 113 int off,
james@0 114 int len)
james@0 115 {
james@0 116 int c1, c2;
james@0 117 const char *ring = Ring;
james@0 118 char *dest = Dest;
james@0 119 c1 = min(len, XENSTORE_RING_SIZE - off);
james@0 120 c2 = len - c1;
james@0 121 memcpy(dest, ring + off, c1);
james@0 122 memcpy(dest + c1, ring, c2);
james@0 123 }
james@0 124
andy@15 125 static void xb_write(
andy@13 126 WDFDEVICE Device,
andy@13 127 int type,
andy@13 128 int req_id,
andy@13 129 xenbus_transaction_t trans_id,
andy@13 130 const struct write_req *req,
andy@13 131 int nr_reqs)
james@0 132 {
andy@15 133 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
james@0 134 XENSTORE_RING_IDX prod;
james@0 135 int r;
james@0 136 size_t len = 0;
james@0 137 const struct write_req *cur_req;
james@0 138 size_t req_off;
james@0 139 size_t total_off;
james@0 140 size_t this_chunk;
james@0 141 struct xsd_sockmsg m = {type, req_id, trans_id };
james@0 142 struct write_req header_req = { &m, sizeof(m) };
james@0 143
james@134 144 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 145
james@0 146 for (r = 0; r < nr_reqs; r++)
james@145 147 len += (size_t)req[r].len;
james@145 148 m.len = (ULONG)len;
james@0 149 len += sizeof(m);
james@0 150
james@0 151 cur_req = &header_req;
james@0 152
james@0 153 // BUG_ON(len > XENSTORE_RING_SIZE);
james@0 154 /* Wait for the ring to drain to the point where we can send the
james@0 155 message. */
andy@15 156 prod = xpdd->xen_store_interface->req_prod;
james@0 157
james@0 158 //KdPrint((__DRIVER_NAME " prod = %08x\n", prod));
james@0 159
andy@15 160 if (prod + len - xpdd->xen_store_interface->req_cons > XENSTORE_RING_SIZE)
james@0 161 {
james@0 162 /* Wait for there to be space on the ring */
james@0 163 //KdPrint((__DRIVER_NAME " prod %d, len %d, cons %d, size %d; waiting.\n", prod, len, xen_store_interface->req_cons, XENSTORE_RING_SIZE));
james@0 164 // wait_event(xb_waitq, xen_store_interface->req_prod + len - xen_store_interface->req_cons <= XENSTORE_RING_SIZE);
james@0 165 //KdPrint((__DRIVER_NAME " Back from wait.\n"));
andy@15 166 prod = xpdd->xen_store_interface->req_prod;
james@0 167 }
james@0 168
james@0 169 /* We're now guaranteed to be able to send the message without
james@0 170 overflowing the ring. Do so. */
james@0 171
james@0 172 total_off = 0;
james@0 173 req_off = 0;
james@0 174
james@0 175 while (total_off < len)
james@0 176 {
james@0 177 this_chunk = min(cur_req->len - req_off,XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
andy@15 178 memcpy((char *)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), (char *)cur_req->data + req_off, this_chunk);
james@145 179 prod += (XENSTORE_RING_IDX)this_chunk;
james@0 180 req_off += this_chunk;
james@0 181 total_off += this_chunk;
james@0 182 if (req_off == cur_req->len)
james@0 183 {
james@0 184 req_off = 0;
james@0 185 if (cur_req == &header_req)
james@0 186 cur_req = req;
james@0 187 else
james@0 188 cur_req++;
james@0 189 }
james@0 190 }
james@0 191
james@0 192 //KdPrint((__DRIVER_NAME " Complete main loop of xb_write.\n"));
james@0 193
james@0 194 // BUG_ON(req_off != 0);
james@0 195 // BUG_ON(total_off != len);
james@0 196 // BUG_ON(prod > xen_store_interface->req_cons + XENSTORE_RING_SIZE);
james@0 197
james@0 198 /* Remote must see entire message before updating indexes */
james@0 199 //_WriteBarrier();
james@0 200 KeMemoryBarrier();
james@0 201
james@145 202 xpdd->xen_store_interface->req_prod += (XENSTORE_RING_IDX)len;
james@0 203
james@0 204 //KdPrint((__DRIVER_NAME " prod = %08x\n", xen_store_interface->req_prod));
james@0 205
james@0 206 /* Send evtchn to notify remote */
andy@15 207 EvtChn_Notify(Device, xpdd->xen_store_evtchn);
james@0 208
james@134 209 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 210 }
james@0 211
james@0 212 static struct xsd_sockmsg *
andy@13 213 xenbus_msg_reply(
andy@13 214 WDFDEVICE Device,
andy@13 215 int type,
andy@13 216 xenbus_transaction_t trans,
andy@13 217 struct write_req *io,
andy@13 218 int nr_reqs)
james@0 219 {
andy@15 220 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
james@0 221 int id;
james@0 222
james@134 223 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 224
andy@15 225 id = allocate_xenbus_id(Device);
andy@94 226
james@96 227 xb_write(Device, type, id, trans, io, nr_reqs);
james@95 228
andy@15 229 KeWaitForSingleObject(&xpdd->req_info[id].WaitEvent, Executive, KernelMode, FALSE, NULL);
james@95 230
james@96 231 release_xenbus_id(Device, id);
james@0 232
james@134 233 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@96 234
andy@94 235 return xpdd->req_info[id].Reply;
james@0 236 }
james@0 237
james@0 238 char *
andy@15 239 XenBus_Read(
andy@13 240 PVOID Context,
andy@13 241 xenbus_transaction_t xbt,
andy@13 242 const char *path,
andy@13 243 char **value)
james@0 244 {
andy@13 245 WDFDEVICE Device = Context;
james@145 246 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
andy@13 247 struct xsd_sockmsg *rep;
andy@13 248 char *res;
andy@13 249 char *msg;
james@0 250
james@134 251 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 252
andy@13 253 rep = xenbus_msg_reply(Device, XS_READ, xbt, req, ARRAY_SIZE(req));
andy@13 254 msg = errmsg(rep);
andy@13 255 if (msg) {
andy@13 256 *value = NULL;
andy@13 257 return msg;
andy@13 258 }
andy@13 259 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
andy@13 260 memcpy(res, rep + 1, rep->len);
andy@13 261 res[rep->len] = 0;
andy@13 262 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
andy@13 263 *value = res;
james@95 264
james@134 265 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 266
andy@13 267 return NULL;
james@0 268 }
james@0 269
james@0 270 char *
andy@13 271 XenBus_Write(
andy@13 272 PVOID Context,
andy@13 273 xenbus_transaction_t xbt,
andy@13 274 const char *path,
andy@13 275 const char *value)
james@0 276 {
andy@13 277 WDFDEVICE Device = Context;
andy@13 278 struct write_req req[] = {
james@145 279 {path, (ULONG)strlen(path) + 1},
andy@264 280 {value, (ULONG)strlen(value)},
andy@13 281 };
andy@13 282 struct xsd_sockmsg *rep;
andy@13 283 char *msg;
james@0 284
james@134 285 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 286
andy@13 287 rep = xenbus_msg_reply(Device, XS_WRITE, xbt, req, ARRAY_SIZE(req));
andy@13 288 msg = errmsg(rep);
andy@13 289 if (msg)
andy@13 290 return msg;
andy@13 291 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 292
james@134 293 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 294
andy@13 295 return NULL;
james@0 296 }
james@0 297
james@0 298 NTSTATUS
andy@13 299 XenBus_Init(WDFDEVICE Device)
james@0 300 {
andy@37 301 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
james@35 302 NTSTATUS Status;
james@35 303 int i;
andy@37 304
james@95 305 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@35 306
james@128 307 KeInitializeSpinLock(&xpdd->WatchLock);
james@128 308
andy@15 309 xpdd->xen_store_evtchn = EvtChn_GetXenStorePort(Device);
andy@15 310 xpdd->xen_store_interface = EvtChn_GetXenStoreRingAddr(Device);
james@0 311
james@35 312 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@128 313 {
andy@38 314 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 315 xpdd->XenBus_WatchEntries[i].Running = 0;
james@128 316 KeInitializeEvent(&xpdd->XenBus_WatchEntries[i].CompleteEvent, SynchronizationEvent, FALSE);
james@128 317 }
james@0 318
andy@15 319 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
andy@15 320 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
andy@38 321 xpdd->XenBus_ShuttingDown = FALSE;
james@0 322
andy@41 323 Status = PsCreateSystemThread(&xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, Device);
andy@101 324 if (!NT_SUCCESS(Status))
andy@101 325 {
andy@101 326 KdPrint((__DRIVER_NAME " Could not start read thread\n"));
andy@101 327 return STATUS_UNSUCCESSFUL;
andy@101 328 }
james@35 329
andy@41 330 Status = PsCreateSystemThread(&xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, Device);
andy@101 331 if (!NT_SUCCESS(Status))
andy@101 332 {
andy@101 333 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
andy@101 334 return STATUS_UNSUCCESSFUL;
andy@101 335 }
james@35 336
james@95 337 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 338
james@0 339 return STATUS_SUCCESS;
james@0 340 }
james@0 341
james@0 342 NTSTATUS
andy@13 343 XenBus_Start(WDFDEVICE Device)
james@0 344 {
andy@38 345 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
andy@38 346
james@95 347 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 348
andy@89 349 EvtChn_BindDpc(Device, xpdd->xen_store_evtchn, XenBus_Interrupt, Device);
james@0 350
james@95 351 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 352
james@0 353 return STATUS_SUCCESS;
james@0 354 }
james@0 355
james@0 356 NTSTATUS
andy@13 357 XenBus_Stop(WDFDEVICE Device)
james@0 358 {
andy@15 359 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
james@0 360 int i;
james@0 361
james@95 362 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@35 363
james@0 364 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@0 365 {
andy@38 366 if (xpdd->XenBus_WatchEntries[i].Active)
andy@38 367 XenBus_RemWatch(Device, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path,
andy@38 368 xpdd->XenBus_WatchEntries[i].ServiceRoutine,
andy@38 369 xpdd->XenBus_WatchEntries[i].ServiceContext);
james@0 370 }
james@0 371
andy@15 372 EvtChn_Unbind(Device, xpdd->xen_store_evtchn);
james@0 373
james@95 374 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@35 375
james@35 376 return STATUS_SUCCESS;
james@35 377 }
james@35 378
james@35 379 NTSTATUS
andy@37 380 XenBus_Close(WDFDEVICE Device)
james@35 381 {
andy@38 382 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
andy@56 383 //KWAIT_BLOCK WaitBlockArray[2];
james@35 384 PVOID WaitArray[2];
james@35 385
andy@38 386 xpdd->XenBus_ShuttingDown = TRUE;
james@35 387
andy@38 388 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
andy@38 389 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
andy@38 390 ObReferenceObjectByHandle(xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[0], NULL);
andy@38 391 ObReferenceObjectByHandle(xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[1], NULL);
james@48 392 KeWaitForSingleObject(WaitArray[0], Executive, KernelMode, FALSE, NULL);
james@48 393 KeWaitForSingleObject(WaitArray[1], Executive, KernelMode, FALSE, NULL);
andy@38 394 xpdd->XenBus_ShuttingDown = FALSE;
james@35 395
andy@15 396 ZwClose(xpdd->XenBus_WatchThreadHandle);
andy@15 397 ZwClose(xpdd->XenBus_ReadThreadHandle);
james@0 398
james@95 399 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@35 400
james@0 401 return STATUS_SUCCESS;
james@0 402 }
james@0 403
james@0 404 char *
andy@13 405 XenBus_List(
andy@13 406 PVOID Context,
andy@13 407 xenbus_transaction_t xbt,
andy@13 408 const char *pre,
andy@13 409 char ***contents)
james@0 410 {
andy@13 411 WDFDEVICE Device = Context;
james@0 412 struct xsd_sockmsg *reply, *repmsg;
james@145 413 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
james@0 414 ULONG nr_elems, x, i;
james@0 415 char **res;
james@0 416 char *msg;
james@0 417
james@134 418 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 419
andy@13 420 repmsg = xenbus_msg_reply(Device, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
james@0 421 msg = errmsg(repmsg);
andy@15 422 if (msg)
andy@15 423 {
james@0 424 *contents = NULL;
james@134 425 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 426 return msg;
james@0 427 }
james@0 428 reply = repmsg + 1;
james@0 429 for (x = nr_elems = 0; x < repmsg->len; x++)
andy@15 430 {
james@0 431 nr_elems += (((char *)reply)[x] == 0);
andy@15 432 }
andy@15 433 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
andy@15 434 XENPCI_POOL_TAG);
andy@15 435 for (x = i = 0; i < nr_elems; i++)
andy@15 436 {
james@145 437 int l = (int)strlen((char *)reply + x);
james@0 438 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
james@0 439 memcpy(res[i], (char *)reply + x, l + 1);
james@0 440 x += l + 1;
james@0 441 }
james@0 442 res[i] = NULL;
james@0 443 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
james@0 444 *contents = res;
james@134 445 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 446 return NULL;
james@0 447 }
james@0 448
andy@15 449 static void
andy@15 450 XenBus_ReadThreadProc(PVOID StartContext)
james@0 451 {
james@0 452 int NewWriteIndex;
james@0 453 struct xsd_sockmsg msg;
james@0 454 char *payload;
james@0 455 char *path, *token;
andy@15 456 WDFDEVICE Device = StartContext;
andy@15 457 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
james@0 458
james@0 459 for(;;)
james@0 460 {
andy@15 461 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
andy@38 462 if (xpdd->XenBus_ShuttingDown)
james@35 463 {
james@35 464 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
james@35 465 PsTerminateSystemThread(0);
james@35 466 }
james@0 467 //KdPrint((__DRIVER_NAME " ReadThread Woken (Count = %d)\n", ReadThreadWaitCount++));
andy@15 468 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
james@0 469 {
james@0 470 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
andy@15 471 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
james@0 472 {
james@0 473 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
james@0 474 break;
james@0 475 }
james@0 476 //_ReadBarrier();
james@0 477 KeMemoryBarrier();
andy@15 478 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
andy@15 479 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
andy@15 480 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
james@0 481 {
james@0 482 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
james@0 483 break;
james@0 484 }
james@0 485
andy@20 486 if (msg.type != XS_WATCH_EVENT)
andy@20 487 {
andy@20 488 xpdd->req_info[msg.req_id].Reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@20 489 memcpy_from_ring(xpdd->xen_store_interface->rsp,
andy@20 490 xpdd->req_info[msg.req_id].Reply,
andy@20 491 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
andy@20 492 msg.len + sizeof(msg));
andy@20 493 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
andy@20 494 KeSetEvent(&xpdd->req_info[msg.req_id].WaitEvent, 1, FALSE);
andy@20 495 }
andy@20 496 else // a watch: add to watch ring and signal watch thread
james@0 497 {
james@0 498 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@15 499 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
andy@15 500 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
andy@15 501 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@0 502 path = payload + sizeof(msg);
james@0 503 token = path + strlen(path) + 1;
james@0 504
andy@15 505 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
andy@15 506 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
james@0 507 {
andy@15 508 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
andy@15 509 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
andy@15 510 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
james@0 511 }
james@0 512 else
james@0 513 {
james@0 514 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
james@0 515 // drop the message on the floor
james@0 516 continue;
james@0 517 }
james@0 518
james@0 519 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
james@0 520 //KdPrint((__DRIVER_NAME " +++ Watch Path = %s Token = %s\n", path, token));
andy@15 521 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
james@0 522 }
james@0 523 }
james@0 524 }
james@0 525 }
james@0 526
james@0 527 static void
james@0 528 XenBus_WatchThreadProc(PVOID StartContext)
james@0 529 {
james@0 530 int index;
james@0 531 PXENBUS_WATCH_ENTRY entry;
andy@15 532 WDFDEVICE Device = StartContext;
andy@15 533 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
james@128 534 KIRQL OldIrql;
james@0 535
james@0 536 for(;;)
james@0 537 {
andy@37 538 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
andy@38 539 if (xpdd->XenBus_ShuttingDown)
james@35 540 {
james@35 541 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
james@35 542 PsTerminateSystemThread(0);
james@35 543 }
andy@38 544 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
james@0 545 {
andy@15 546 xpdd->XenBus_WatchRingReadIndex =
andy@15 547 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
andy@15 548 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
james@0 549
andy@15 550 entry = &xpdd->XenBus_WatchEntries[index];
james@128 551 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
james@128 552 if (!entry->Active || !entry->ServiceRoutine)
james@0 553 {
james@128 554 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@138 555 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
james@0 556 continue;
james@0 557 }
james@138 558 KdPrint((__DRIVER_NAME " --- About to call watch\n"));
james@138 559 if (entry->RemovePending)
james@138 560 {
james@138 561 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@138 562 KdPrint((__DRIVER_NAME " Not calling watch - remove is pending\n"));
james@138 563 continue;
james@138 564 }
james@128 565 entry->Running = 1;
james@128 566 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@0 567 entry->Count++;
james@138 568 KdPrint((__DRIVER_NAME " --- for %s\n", xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path));
andy@15 569 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
james@128 570 entry->Running = 0;
james@128 571 KeSetEvent(&entry->CompleteEvent, 1, FALSE);
james@0 572 }
james@0 573 }
james@0 574 }
james@0 575
james@0 576 char *
andy@15 577 XenBus_AddWatch(
andy@13 578 PVOID Context,
andy@13 579 xenbus_transaction_t xbt,
andy@13 580 const char *Path,
andy@13 581 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 582 PVOID ServiceContext)
james@0 583 {
andy@13 584 WDFDEVICE Device = Context;
andy@15 585 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
james@0 586 struct xsd_sockmsg *rep;
james@0 587 char *msg;
james@0 588 int i;
james@0 589 char Token[20];
james@0 590 struct write_req req[2];
andy@94 591 PXENBUS_WATCH_ENTRY w_entry;
james@128 592 KIRQL OldIrql;
james@0 593
james@153 594 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 595
andy@94 596 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
james@0 597
james@128 598 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
james@128 599
james@0 600 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
andy@15 601 if (xpdd->XenBus_WatchEntries[i].Active == 0)
james@0 602 break;
james@0 603
james@0 604 if (i == MAX_WATCH_ENTRIES)
james@0 605 {
james@0 606 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
james@128 607 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@0 608 return NULL;
james@0 609 }
james@0 610
andy@94 611 /* must init watchentry before starting watch */
james@128 612
andy@94 613 w_entry = &xpdd->XenBus_WatchEntries[i];
andy@94 614 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
andy@94 615 w_entry->ServiceRoutine = ServiceRoutine;
andy@94 616 w_entry->ServiceContext = ServiceContext;
andy@94 617 w_entry->Count = 0;
andy@94 618 w_entry->Active = 1;
andy@94 619
james@128 620 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@128 621
james@0 622 req[0].data = Path;
james@145 623 req[0].len = (ULONG)strlen(Path) + 1;
james@0 624
james@0 625 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
james@0 626 req[1].data = Token;
james@145 627 req[1].len = (ULONG)strlen(Token) + 1;
james@0 628
andy@93 629 rep = xenbus_msg_reply(Device, XS_WATCH, xbt, req, ARRAY_SIZE(req));
andy@93 630
andy@93 631 msg = errmsg(rep);
andy@93 632 if (msg)
andy@93 633 {
andy@93 634 xpdd->XenBus_WatchEntries[i].Active = 0;
james@96 635 KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
andy@93 636 return msg;
andy@93 637 }
james@157 638 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
andy@93 639
james@153 640 KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
james@0 641
james@0 642 return NULL;
james@0 643 }
james@0 644
james@0 645 char *
andy@13 646 XenBus_RemWatch(
andy@13 647 PVOID Context,
andy@13 648 xenbus_transaction_t xbt,
andy@13 649 const char *Path,
andy@13 650 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 651 PVOID ServiceContext)
james@0 652 {
andy@13 653 WDFDEVICE Device = Context;
andy@15 654 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
james@0 655 struct xsd_sockmsg *rep;
james@0 656 char *msg;
james@0 657 int i;
james@0 658 char Token[20];
james@0 659 struct write_req req[2];
james@128 660 KIRQL OldIrql;
james@0 661
james@138 662 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 663
james@128 664 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
james@128 665
james@0 666 // check that Path < 128 chars
james@0 667
james@0 668 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
andy@15 669 if (xpdd->XenBus_WatchEntries[i].Active == 1
andy@15 670 && strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) == 0
andy@15 671 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
andy@15 672 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
james@0 673 break;
james@0 674 }
james@0 675
james@0 676 if (i == MAX_WATCH_ENTRIES)
james@0 677 {
james@128 678 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@0 679 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
james@0 680 return NULL;
james@0 681 }
james@0 682
james@138 683 if (xpdd->XenBus_WatchEntries[i].RemovePending)
james@128 684 {
james@132 685 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@138 686 KdPrint((__DRIVER_NAME " Remove already pending - can't remove\n"));
james@138 687 return NULL;
james@138 688 }
james@138 689 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@138 690
james@138 691 while (xpdd->XenBus_WatchEntries[i].Running)
james@128 692 KeWaitForSingleObject(&xpdd->XenBus_WatchEntries[i].CompleteEvent, Executive, KernelMode, FALSE, NULL);
james@138 693
james@138 694 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
james@128 695
james@128 696 xpdd->XenBus_WatchEntries[i].Active = 0;
james@138 697 xpdd->XenBus_WatchEntries[i].RemovePending = 0;
james@128 698 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
james@128 699
james@128 700 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
james@128 701
james@0 702 req[0].data = Path;
james@145 703 req[0].len = (ULONG)strlen(Path) + 1;
james@0 704
james@0 705 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
james@0 706 req[1].data = Token;
james@145 707 req[1].len = (ULONG)strlen(Token) + 1;
james@0 708
andy@13 709 rep = xenbus_msg_reply(Device, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
james@0 710
james@0 711 msg = errmsg(rep);
james@0 712 if (msg)
james@128 713 {
james@0 714 return msg;
james@128 715 }
james@0 716
james@0 717 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 718
james@138 719 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 720
james@0 721 return NULL;
james@0 722 }
james@0 723
james@0 724
james@0 725 char *
andy@13 726 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
james@0 727 {
andy@13 728 WDFDEVICE Device = Context;
james@0 729 /* xenstored becomes angry if you send a length 0 message, so just
james@0 730 shove a nul terminator on the end */
james@0 731 struct write_req req = { "", 1};
james@0 732 struct xsd_sockmsg *rep;
james@0 733 char *err;
james@0 734
james@134 735 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 736
andy@13 737 rep = xenbus_msg_reply(Device, XS_TRANSACTION_START, 0, &req, 1);
james@0 738 err = errmsg(rep);
james@0 739 if (err)
james@0 740 return err;
james@0 741 *xbt = atoi((char *)(rep + 1));
james@0 742 //sscanf((char *)(rep + 1), "%u", xbt);
james@0 743 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 744
james@134 745 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 746
james@0 747 return NULL;
james@0 748 }
james@0 749
james@0 750 char *
andy@15 751 XenBus_EndTransaction(
andy@15 752 PVOID Context,
andy@15 753 xenbus_transaction_t t,
andy@15 754 int abort,
andy@15 755 int *retry)
james@0 756 {
andy@13 757 WDFDEVICE Device = Context;
james@0 758 struct xsd_sockmsg *rep;
james@0 759 struct write_req req;
james@0 760 char *err;
james@0 761
james@134 762 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 763
james@0 764 *retry = 0;
james@0 765
james@0 766 req.data = abort ? "F" : "T";
james@0 767 req.len = 2;
andy@13 768 rep = xenbus_msg_reply(Device, XS_TRANSACTION_END, t, &req, 1);
james@0 769 err = errmsg(rep);
james@0 770 if (err) {
james@0 771 if (!strcmp(err, "EAGAIN")) {
james@0 772 *retry = 1;
james@0 773 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
james@0 774 return NULL;
james@0 775 } else {
james@0 776 return err;
james@0 777 }
james@0 778 }
james@0 779 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 780
james@134 781 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 782
james@0 783 return NULL;
james@0 784 }
james@0 785
james@0 786 static BOOLEAN
james@0 787 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext)
james@0 788 {
andy@15 789 WDFDEVICE Device = ServiceContext;
andy@15 790 PXENPCI_DEVICE_DATA xpdd = GetDeviceData(Device);
andy@15 791
james@0 792 UNREFERENCED_PARAMETER(Interrupt);
james@0 793
james@134 794 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 795
andy@15 796 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
james@0 797
james@134 798 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 799
james@0 800 return TRUE;
james@0 801 }
james@0 802
james@0 803 char *
andy@15 804 XenBus_Printf(
andy@15 805 PVOID Context,
andy@15 806 xenbus_transaction_t xbt,
andy@15 807 const char *path,
andy@15 808 const char *fmt,
andy@15 809 ...)
james@0 810 {
andy@13 811 WDFDEVICE Device = Context;
james@0 812 va_list ap;
andy@101 813 char buf[512];
james@95 814 char *retval;
james@95 815
james@134 816 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 817
james@0 818 va_start(ap, fmt);
james@0 819 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
james@0 820 va_end(ap);
james@95 821 retval = XenBus_Write(Device, xbt, path, buf);
james@95 822
james@134 823 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 824
james@95 825 return retval;
andy@37 826 }