win-pvdrivers

annotate xenpci/xenbus.c @ 622:f905eb3f0545

Shut down threads properly on hibernate.
Added some debug to try and find where the hang happens when the verifier is enabled
Added the suspend event channel to allow triggering a suspend much earlier
author James Harper <james.harper@bendigoit.com.au>
date Wed Aug 05 19:09:55 2009 +1000 (2009-08-05)
parents e75bb8d68370
children 0b55299418ce
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 <stdlib.h>
james@0 22
james@0 23 #pragma warning( disable : 4204 )
james@0 24 #pragma warning( disable : 4221 )
james@0 25
andy@15 26 struct write_req {
james@504 27 void *data;
andy@15 28 unsigned len;
james@0 29 };
james@0 30
andy@328 31 static DDKAPI void
james@0 32 XenBus_ReadThreadProc(PVOID StartContext);
andy@328 33 static DDKAPI void
james@0 34 XenBus_WatchThreadProc(PVOID StartContext);
james@0 35
james@157 36 // This routine free's the rep structure if there was an error!!!
james@0 37 static char *errmsg(struct xsd_sockmsg *rep)
james@0 38 {
james@0 39 char *res;
andy@15 40
james@0 41 if (!rep) {
james@0 42 char msg[] = "No reply";
james@0 43 size_t len = strlen(msg) + 1;
james@0 44 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
james@0 45 }
james@0 46 if (rep->type != XS_ERROR)
james@0 47 return NULL;
james@0 48 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
james@0 49 memcpy(res, rep + 1, rep->len);
james@0 50 res[rep->len] = 0;
james@0 51 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 52 return res;
james@0 53 }
james@0 54
james@504 55 static void memcpy_from_ring(void *Ring,
james@0 56 void *Dest,
james@0 57 int off,
james@0 58 int len)
james@0 59 {
james@0 60 int c1, c2;
james@504 61 char *ring = Ring;
james@0 62 char *dest = Dest;
james@0 63 c1 = min(len, XENSTORE_RING_SIZE - off);
james@0 64 c2 = len - c1;
james@0 65 memcpy(dest, ring + off, c1);
james@0 66 memcpy(dest + c1, ring, c2);
james@0 67 }
james@0 68
james@404 69 /* called with xenbus_mutex held */
andy@15 70 static void xb_write(
james@258 71 PXENPCI_DEVICE_DATA xpdd,
james@504 72 PVOID data,
james@504 73 ULONG len
james@504 74 )
james@0 75 {
james@0 76 XENSTORE_RING_IDX prod;
james@504 77 ULONG copy_len;
james@504 78 PUCHAR ptr;
james@504 79 ULONG remaining;
james@504 80
james@523 81 //FUNCTION_ENTER();
james@523 82 //KdPrint((__DRIVER_NAME " len = %d\n", len));
james@0 83
james@390 84 ASSERT(len <= XENSTORE_RING_SIZE);
james@0 85 /* Wait for the ring to drain to the point where we can send the
james@0 86 message. */
andy@15 87 prod = xpdd->xen_store_interface->req_prod;
james@0 88
james@390 89 while (prod + len - xpdd->xen_store_interface->req_cons > XENSTORE_RING_SIZE)
james@0 90 {
james@0 91 /* Wait for there to be space on the ring */
james@504 92 /* not sure if I can wait here like this... */
james@390 93 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
andy@15 94 prod = xpdd->xen_store_interface->req_prod;
james@0 95 }
james@0 96
james@0 97 /* We're now guaranteed to be able to send the message without
james@0 98 overflowing the ring. Do so. */
james@0 99
james@504 100 ptr = data;
james@504 101 remaining = len;
james@504 102 while (remaining)
james@0 103 {
james@504 104 copy_len = min(remaining, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
james@523 105 //KdPrint((__DRIVER_NAME " copy_len = %d\n", copy_len));
james@504 106 memcpy((PUCHAR)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), ptr, copy_len);
james@504 107 prod += (XENSTORE_RING_IDX)copy_len;
james@504 108 ptr += copy_len;
james@504 109 remaining -= copy_len;
james@0 110 }
james@0 111 /* Remote must see entire message before updating indexes */
james@0 112 KeMemoryBarrier();
james@504 113 xpdd->xen_store_interface->req_prod = prod;
james@258 114 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn);
james@0 115
james@523 116 //FUNCTION_EXIT();
james@0 117 }
james@0 118
james@504 119 /* takes and releases xb_request_mutex */
james@0 120 static struct xsd_sockmsg *
james@504 121 xenbus_format_msg_reply(
james@258 122 PXENPCI_DEVICE_DATA xpdd,
andy@13 123 int type,
james@504 124 xenbus_transaction_t trans_id,
james@504 125 struct write_req *req,
andy@13 126 int nr_reqs)
james@0 127 {
james@504 128 struct xsd_sockmsg msg;
james@504 129 struct xsd_sockmsg *reply;
james@504 130 int i;
andy@94 131
james@529 132 //FUNCTION_ENTER();
james@504 133
james@504 134 msg.type = type;
james@504 135 msg.req_id = 0;
james@504 136 msg.tx_id = trans_id;
james@504 137 msg.len = 0;
james@504 138 for (i = 0; i < nr_reqs; i++)
james@515 139 msg.len += req[i].len;
james@95 140
james@504 141 ExAcquireFastMutex(&xpdd->xb_request_mutex);
james@504 142 xb_write(xpdd, &msg, sizeof(msg));
james@504 143 for (i = 0; i < nr_reqs; i++)
james@504 144 xb_write(xpdd, req[i].data, req[i].len);
james@0 145
james@523 146 //KdPrint((__DRIVER_NAME " waiting...\n"));
james@504 147 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
james@523 148 //KdPrint((__DRIVER_NAME " ...done waiting\n"));
james@504 149 reply = xpdd->xb_reply;
james@504 150 xpdd->xb_reply = NULL;
james@512 151 ExReleaseFastMutex(&xpdd->xb_request_mutex);
james@96 152
james@529 153 //FUNCTION_EXIT();
james@504 154
james@504 155 return reply;
james@504 156 }
james@504 157
james@504 158 /* takes and releases xb_request_mutex */
james@504 159 struct xsd_sockmsg *
james@504 160 XenBus_Raw(
james@504 161 PXENPCI_DEVICE_DATA xpdd,
james@504 162 struct xsd_sockmsg *msg)
james@504 163 {
james@504 164 struct xsd_sockmsg *reply;
james@536 165
james@536 166 FUNCTION_ENTER();
james@504 167
james@504 168 ExAcquireFastMutex(&xpdd->xb_request_mutex);
james@504 169 xb_write(xpdd, msg, sizeof(struct xsd_sockmsg) + msg->len);
james@504 170 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
james@504 171 reply = xpdd->xb_reply;
james@504 172 xpdd->xb_reply = NULL;
james@504 173 ExReleaseFastMutex(&xpdd->xb_request_mutex);
james@504 174
james@536 175 FUNCTION_EXIT();
james@536 176
james@504 177 return reply;
james@0 178 }
james@0 179
james@404 180 /*
james@404 181 Called at PASSIVE_LEVEL
james@404 182 */
james@0 183 char *
andy@15 184 XenBus_Read(
andy@13 185 PVOID Context,
andy@13 186 xenbus_transaction_t xbt,
james@504 187 char *path,
andy@13 188 char **value)
james@0 189 {
james@258 190 PXENPCI_DEVICE_DATA xpdd = Context;
james@145 191 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
andy@13 192 struct xsd_sockmsg *rep;
andy@13 193 char *res;
andy@13 194 char *msg;
james@0 195
james@342 196 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 197
james@272 198 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 199
james@504 200 rep = xenbus_format_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
andy@13 201 msg = errmsg(rep);
andy@13 202 if (msg) {
andy@13 203 *value = NULL;
andy@13 204 return msg;
andy@13 205 }
andy@13 206 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
andy@13 207 memcpy(res, rep + 1, rep->len);
andy@13 208 res[rep->len] = 0;
andy@13 209 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
andy@13 210 *value = res;
james@95 211
james@342 212 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 213
andy@13 214 return NULL;
james@0 215 }
james@0 216
james@404 217 /*
james@404 218 Called at PASSIVE_LEVEL
james@404 219 */
james@0 220 char *
andy@13 221 XenBus_Write(
andy@13 222 PVOID Context,
andy@13 223 xenbus_transaction_t xbt,
james@504 224 char *path,
james@504 225 char *value)
james@0 226 {
james@258 227 PXENPCI_DEVICE_DATA xpdd = Context;
andy@13 228 struct write_req req[] = {
james@145 229 {path, (ULONG)strlen(path) + 1},
andy@264 230 {value, (ULONG)strlen(value)},
andy@13 231 };
andy@13 232 struct xsd_sockmsg *rep;
andy@13 233 char *msg;
james@0 234
james@342 235 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 236
james@272 237 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 238
james@504 239 rep = xenbus_format_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
andy@13 240 msg = errmsg(rep);
andy@13 241 if (msg)
andy@13 242 return msg;
andy@13 243 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 244
james@342 245 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 246
andy@13 247 return NULL;
james@0 248 }
james@0 249
james@515 250 static VOID
james@515 251 XenBus_Dpc(PVOID ServiceContext)
james@515 252 {
james@515 253 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
james@515 254
james@536 255 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@515 256
james@515 257 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
james@515 258
james@536 259 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@515 260
james@515 261 return;
james@515 262 }
james@515 263
james@390 264 NTSTATUS
james@342 265 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
james@342 266 {
james@342 267 PHYSICAL_ADDRESS pa_xen_store_interface;
james@342 268 xen_ulong_t xen_store_mfn;
james@342 269
james@342 270 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
james@342 271 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
james@342 272 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
james@342 273 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
james@342 274
james@390 275 KeMemoryBarrier();
james@390 276
james@390 277 return STATUS_SUCCESS;
james@342 278 }
james@342 279
james@0 280 NTSTATUS
james@258 281 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
james@0 282 {
james@390 283 NTSTATUS status;
james@409 284 HANDLE thread_handle;
james@35 285 int i;
andy@37 286
james@409 287 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@35 288
james@622 289 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
james@35 290
james@504 291 ExInitializeFastMutex(&xpdd->xb_request_mutex);
james@504 292 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
james@128 293
james@35 294 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@128 295 {
andy@38 296 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 297 }
james@0 298
andy@15 299 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
andy@15 300 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
james@504 301 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
james@504 302
james@390 303 status = XenBus_Connect(xpdd);
james@390 304 if (!NT_SUCCESS(status))
andy@101 305 {
james@390 306 return status;
andy@101 307 }
james@536 308 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
james@409 309
james@622 310 KdPrint((__DRIVER_NAME " A\n"));
james@409 311 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, xpdd);
james@409 312 if (!NT_SUCCESS(status))
james@409 313 {
james@409 314 KdPrint((__DRIVER_NAME " Could not start read thread\n"));
james@409 315 return status;
james@409 316 }
james@622 317 KdPrint((__DRIVER_NAME " B\n"));
james@622 318 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_ReadThread, NULL);
james@622 319 KdPrint((__DRIVER_NAME " C\n"));
james@622 320 ZwClose(thread_handle);
james@342 321
james@622 322 KdPrint((__DRIVER_NAME " D\n"));
james@409 323 if (!NT_SUCCESS(status))
james@409 324 {
james@409 325 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_ReadThread) = %08x\n", status));
james@409 326 return status;
james@409 327 }
james@622 328 KdPrint((__DRIVER_NAME " E\n"));
james@409 329
james@409 330 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
james@622 331 KdPrint((__DRIVER_NAME " F\n"));
james@409 332 if (!NT_SUCCESS(status))
james@409 333 {
james@409 334 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
james@409 335 return status;
james@409 336 }
james@622 337 KdPrint((__DRIVER_NAME " G\n"));
james@409 338 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_WatchThread, NULL);
james@622 339 KdPrint((__DRIVER_NAME " H\n"));
james@409 340 ZwClose(thread_handle);
james@622 341 KdPrint((__DRIVER_NAME " I\n"));
james@409 342 if (!NT_SUCCESS(status))
james@409 343 {
james@409 344 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_WatchThread) = %08x\n", status));
james@409 345 }
james@409 346
james@409 347 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 348
james@0 349 return STATUS_SUCCESS;
james@0 350 }
james@0 351
james@406 352 char *
james@406 353 XenBus_SendRemWatch(
james@406 354 PVOID context,
james@406 355 xenbus_transaction_t xbt,
james@504 356 char *path,
james@504 357 int index)
james@406 358 {
james@406 359 struct xsd_sockmsg *rep;
james@406 360 char *msg;
james@406 361 char Token[20];
james@406 362 struct write_req req[2];
james@406 363
james@406 364 req[0].data = path;
james@406 365 req[0].len = (ULONG)strlen(path) + 1;
james@406 366
james@406 367 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
james@406 368 req[1].data = Token;
james@406 369 req[1].len = (ULONG)strlen(Token) + 1;
james@406 370
james@504 371 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
james@406 372
james@406 373 msg = errmsg(rep);
james@406 374 if (msg)
james@406 375 return msg;
james@406 376
james@406 377 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@406 378
james@406 379 return NULL;
james@406 380 }
james@406 381
james@35 382 NTSTATUS
james@622 383 XenBus_Halt(PXENPCI_DEVICE_DATA xpdd)
james@35 384 {
james@409 385 NTSTATUS status;
james@406 386 int i;
james@409 387 LARGE_INTEGER timeout;
james@35 388
james@406 389 FUNCTION_ENTER();
james@406 390
james@272 391 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 392
james@406 393 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@406 394 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@406 395 if (xpdd->XenBus_WatchEntries[i].Active)
james@406 396 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@406 397 }
james@406 398
andy@38 399 xpdd->XenBus_ShuttingDown = TRUE;
james@406 400 KeMemoryBarrier();
james@35 401
james@622 402 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
james@385 403 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
james@409 404
james@409 405 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@622 406 while ((status = KeWaitForSingleObject(xpdd->XenBus_WatchThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
james@622 407 {
james@622 408 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@622 409 KdPrint((__DRIVER_NAME " Waiting for XenBus_WatchThread to stop\n"));
james@622 410 }
james@622 411 ObDereferenceObject(xpdd->XenBus_WatchThread);
james@622 412
james@622 413 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 414 while ((status = KeWaitForSingleObject(xpdd->XenBus_ReadThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
james@409 415 {
james@409 416 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@622 417 KdPrint((__DRIVER_NAME " Waiting for XenBus_ReadThread to stop\n"));
james@409 418 }
james@409 419 ObDereferenceObject(xpdd->XenBus_ReadThread);
james@406 420
andy@38 421 xpdd->XenBus_ShuttingDown = FALSE;
james@35 422
james@406 423 FUNCTION_EXIT();
james@35 424
james@0 425 return STATUS_SUCCESS;
james@0 426 }
james@0 427
james@0 428 char *
andy@13 429 XenBus_List(
andy@13 430 PVOID Context,
andy@13 431 xenbus_transaction_t xbt,
james@504 432 char *pre,
andy@13 433 char ***contents)
james@0 434 {
james@258 435 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 436 struct xsd_sockmsg *reply, *repmsg;
james@145 437 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
james@0 438 ULONG nr_elems, x, i;
james@0 439 char **res;
james@0 440 char *msg;
james@0 441
james@134 442 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 443
james@272 444 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 445
james@504 446 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
james@0 447 msg = errmsg(repmsg);
andy@15 448 if (msg)
andy@15 449 {
james@0 450 *contents = NULL;
james@134 451 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 452 return msg;
james@0 453 }
james@0 454 reply = repmsg + 1;
james@0 455 for (x = nr_elems = 0; x < repmsg->len; x++)
andy@15 456 {
james@0 457 nr_elems += (((char *)reply)[x] == 0);
andy@15 458 }
andy@15 459 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
andy@15 460 XENPCI_POOL_TAG);
andy@15 461 for (x = i = 0; i < nr_elems; i++)
andy@15 462 {
james@145 463 int l = (int)strlen((char *)reply + x);
james@0 464 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
james@0 465 memcpy(res[i], (char *)reply + x, l + 1);
james@0 466 x += l + 1;
james@0 467 }
james@0 468 res[i] = NULL;
james@0 469 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
james@0 470 *contents = res;
james@134 471 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 472 return NULL;
james@0 473 }
james@0 474
andy@328 475 static DDKAPI void
andy@15 476 XenBus_ReadThreadProc(PVOID StartContext)
james@0 477 {
james@0 478 int NewWriteIndex;
james@0 479 struct xsd_sockmsg msg;
james@0 480 char *payload;
james@0 481 char *path, *token;
james@258 482 PXENPCI_DEVICE_DATA xpdd = StartContext;
james@0 483
james@622 484 FUNCTION_ENTER();
james@0 485 for(;;)
james@0 486 {
andy@15 487 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
james@536 488 //KdPrint((__DRIVER_NAME " +++ thread woken\n"));
andy@38 489 if (xpdd->XenBus_ShuttingDown)
james@35 490 {
james@35 491 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
james@35 492 PsTerminateSystemThread(0);
james@35 493 }
andy@15 494 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
james@0 495 {
james@536 496 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xpdd->xen_store_interface->rsp_cons, xpdd->xen_store_interface->rsp_prod));
andy@15 497 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
james@0 498 {
james@523 499 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
james@0 500 break;
james@0 501 }
james@0 502 KeMemoryBarrier();
andy@15 503 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
andy@15 504 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
andy@15 505 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
james@0 506 {
james@523 507 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
james@0 508 break;
james@0 509 }
james@0 510
andy@20 511 if (msg.type != XS_WATCH_EVENT)
andy@20 512 {
james@504 513 xpdd->xb_reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@20 514 memcpy_from_ring(xpdd->xen_store_interface->rsp,
james@504 515 xpdd->xb_reply,
andy@20 516 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
andy@20 517 msg.len + sizeof(msg));
andy@20 518 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@523 519 //KdPrint((__DRIVER_NAME " +++ Setting event\n"));
james@504 520 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
andy@20 521 }
andy@20 522 else // a watch: add to watch ring and signal watch thread
james@0 523 {
james@0 524 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@15 525 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
andy@15 526 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
andy@15 527 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@0 528 path = payload + sizeof(msg);
james@0 529 token = path + strlen(path) + 1;
james@0 530
andy@15 531 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
andy@15 532 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
james@0 533 {
andy@15 534 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
andy@15 535 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
andy@15 536 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
james@0 537 }
james@0 538 else
james@0 539 {
james@536 540 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
james@0 541 // drop the message on the floor
james@0 542 continue;
james@0 543 }
james@0 544
james@0 545 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
james@385 546 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
james@0 547 }
james@0 548 }
james@0 549 }
james@622 550 FUNCTION_EXIT();
james@0 551 }
james@0 552
andy@328 553 static DDKAPI void
james@0 554 XenBus_WatchThreadProc(PVOID StartContext)
james@0 555 {
james@0 556 int index;
james@0 557 PXENBUS_WATCH_ENTRY entry;
james@258 558 PXENPCI_DEVICE_DATA xpdd = StartContext;
james@0 559
james@0 560 for(;;)
james@0 561 {
andy@37 562 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
james@504 563 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
andy@38 564 if (xpdd->XenBus_ShuttingDown)
james@35 565 {
james@35 566 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
james@504 567 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@35 568 PsTerminateSystemThread(0);
james@409 569 KdPrint((__DRIVER_NAME " WatchThreadProc still running... wtf?\n"));
james@35 570 }
andy@38 571 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
james@0 572 {
james@536 573 //KdPrint((__DRIVER_NAME " +++ watch triggered\n"));
andy@15 574 xpdd->XenBus_WatchRingReadIndex =
andy@15 575 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
andy@15 576 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
james@0 577
andy@15 578 entry = &xpdd->XenBus_WatchEntries[index];
james@128 579 if (!entry->Active || !entry->ServiceRoutine)
james@0 580 {
james@138 581 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
james@0 582 continue;
james@0 583 }
james@0 584 entry->Count++;
andy@15 585 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
james@0 586 }
james@504 587 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 588 }
james@0 589 }
james@0 590
james@404 591 /*
james@404 592 Called at PASSIVE_LEVEL
james@404 593 */
james@279 594 static char *
james@279 595 XenBus_SendAddWatch(
james@279 596 PVOID Context,
james@279 597 xenbus_transaction_t xbt,
james@504 598 char *Path,
james@279 599 int slot)
james@279 600 {
james@279 601 PXENPCI_DEVICE_DATA xpdd = Context;
james@279 602 struct xsd_sockmsg *rep;
james@279 603 char *msg;
james@279 604 char Token[20];
james@279 605 struct write_req req[2];
james@279 606
james@279 607 req[0].data = Path;
james@279 608 req[0].len = (ULONG)strlen(Path) + 1;
james@279 609
james@279 610 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
james@279 611 req[1].data = Token;
james@279 612 req[1].len = (ULONG)strlen(Token) + 1;
james@279 613
james@504 614 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
james@404 615
james@279 616 msg = errmsg(rep);
james@283 617 if (!msg)
james@283 618 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@279 619
james@279 620 return msg;
james@279 621 }
james@279 622
james@342 623 /* called at PASSIVE_LEVEL */
james@390 624 NTSTATUS
james@409 625 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
james@409 626 {
james@409 627 int i;
james@409 628
james@409 629 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@409 630 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@409 631 if (xpdd->XenBus_WatchEntries[i].Active)
james@409 632 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@409 633 }
james@409 634
james@409 635 // need to synchronise with readthread here too to ensure that it won't do anything silly
james@622 636 MmUnmapIoSpace(xpdd->xen_store_interface, PAGE_SIZE);
james@622 637
james@409 638 return STATUS_SUCCESS;
james@409 639 }
james@409 640
james@409 641 /* called at PASSIVE_LEVEL */
james@409 642 NTSTATUS
james@279 643 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
james@279 644 {
james@390 645 NTSTATUS status;
james@279 646 int i;
james@341 647
andy@398 648 FUNCTION_ENTER();
james@342 649
james@390 650 status = XenBus_Connect(xpdd);
james@390 651 if (!NT_SUCCESS(status))
james@390 652 {
james@390 653 return status;
james@390 654 }
james@536 655 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
james@279 656
james@279 657 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@341 658 {
james@279 659 if (xpdd->XenBus_WatchEntries[i].Active)
james@341 660 {
james@536 661 //KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
james@279 662 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@341 663 }
james@341 664 }
andy@398 665 FUNCTION_EXIT();
james@390 666
james@390 667 return STATUS_SUCCESS;
james@279 668 }
james@279 669
james@0 670 char *
andy@15 671 XenBus_AddWatch(
andy@13 672 PVOID Context,
andy@13 673 xenbus_transaction_t xbt,
james@504 674 char *Path,
andy@13 675 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 676 PVOID ServiceContext)
james@0 677 {
james@258 678 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 679 char *msg;
james@0 680 int i;
andy@94 681 PXENBUS_WATCH_ENTRY w_entry;
james@0 682
james@267 683 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 684
james@272 685 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 686
andy@94 687 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
james@0 688
james@504 689 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 690
james@0 691 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
andy@15 692 if (xpdd->XenBus_WatchEntries[i].Active == 0)
james@0 693 break;
james@0 694
james@0 695 if (i == MAX_WATCH_ENTRIES)
james@0 696 {
james@0 697 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
james@504 698 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 699 return NULL;
james@0 700 }
james@0 701
andy@94 702 /* must init watchentry before starting watch */
james@128 703
andy@94 704 w_entry = &xpdd->XenBus_WatchEntries[i];
andy@94 705 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
andy@94 706 w_entry->ServiceRoutine = ServiceRoutine;
andy@94 707 w_entry->ServiceContext = ServiceContext;
andy@94 708 w_entry->Count = 0;
andy@94 709 w_entry->Active = 1;
andy@94 710
james@504 711 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@128 712
james@279 713 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
james@0 714
andy@93 715 if (msg)
andy@93 716 {
andy@93 717 xpdd->XenBus_WatchEntries[i].Active = 0;
james@341 718 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
andy@93 719 return msg;
andy@93 720 }
andy@93 721
james@341 722 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
james@0 723
james@0 724 return NULL;
james@0 725 }
james@0 726
james@0 727 char *
andy@13 728 XenBus_RemWatch(
andy@13 729 PVOID Context,
andy@13 730 xenbus_transaction_t xbt,
james@504 731 char *Path,
andy@13 732 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 733 PVOID ServiceContext)
james@0 734 {
james@258 735 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 736 char *msg;
james@0 737 int i;
james@0 738
james@267 739 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 740 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 741
james@504 742 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 743
james@0 744 // check that Path < 128 chars
james@0 745
james@409 746 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@409 747 {
james@538 748 if (xpdd->XenBus_WatchEntries[i].Active
james@538 749 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
andy@15 750 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
andy@15 751 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
james@409 752 {
james@409 753 KdPrint((__DRIVER_NAME " Match\n"));
james@0 754 break;
james@409 755 }
james@0 756 }
james@0 757
james@0 758 if (i == MAX_WATCH_ENTRIES)
james@0 759 {
james@504 760 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 761 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
james@0 762 return NULL;
james@0 763 }
james@0 764
james@128 765 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 766 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
james@128 767
james@504 768 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 769
james@406 770 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
james@406 771
james@267 772 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 773
james@406 774 return msg;
james@0 775 }
james@0 776
james@0 777
james@0 778 char *
andy@13 779 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
james@0 780 {
james@258 781 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 782 /* xenstored becomes angry if you send a length 0 message, so just
james@0 783 shove a nul terminator on the end */
james@0 784 struct write_req req = { "", 1};
james@0 785 struct xsd_sockmsg *rep;
james@0 786 char *err;
james@0 787
james@134 788 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 789 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@95 790
james@504 791 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
james@0 792 err = errmsg(rep);
james@0 793 if (err)
james@0 794 return err;
james@0 795 *xbt = atoi((char *)(rep + 1));
james@0 796 //sscanf((char *)(rep + 1), "%u", xbt);
james@0 797 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 798
james@134 799 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 800
james@0 801 return NULL;
james@0 802 }
james@0 803
james@0 804 char *
andy@15 805 XenBus_EndTransaction(
andy@15 806 PVOID Context,
andy@15 807 xenbus_transaction_t t,
andy@15 808 int abort,
andy@15 809 int *retry)
james@0 810 {
james@258 811 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 812 struct xsd_sockmsg *rep;
james@0 813 struct write_req req;
james@0 814 char *err;
james@0 815
james@134 816 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 817
james@0 818 *retry = 0;
james@0 819
james@0 820 req.data = abort ? "F" : "T";
james@0 821 req.len = 2;
james@504 822 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
james@0 823 err = errmsg(rep);
james@0 824 if (err) {
james@0 825 if (!strcmp(err, "EAGAIN")) {
james@0 826 *retry = 1;
james@0 827 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
james@0 828 return NULL;
james@0 829 } else {
james@0 830 return err;
james@0 831 }
james@0 832 }
james@0 833 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 834
james@134 835 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 836
james@0 837 return NULL;
james@0 838 }
james@0 839
james@0 840 char *
andy@15 841 XenBus_Printf(
andy@15 842 PVOID Context,
andy@15 843 xenbus_transaction_t xbt,
james@504 844 char *path,
james@504 845 char *fmt,
andy@15 846 ...)
james@0 847 {
james@258 848 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 849 va_list ap;
andy@101 850 char buf[512];
james@95 851 char *retval;
james@95 852
james@134 853 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 854 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 855
james@0 856 va_start(ap, fmt);
james@0 857 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
james@0 858 va_end(ap);
james@258 859 retval = XenBus_Write(xpdd, xbt, path, buf);
james@95 860
james@134 861 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 862
james@95 863 return retval;
andy@37 864 }