win-pvdrivers

annotate xenpci/xenbus.c @ 134:f3f156c524ee

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