win-pvdrivers

annotate xenpci/xenbus.c @ 523:331f861accf0

removed debugging kdprint's
author James Harper <james.harper@bendigoit.com.au>
date Fri Dec 26 23:18:55 2008 +1100 (2008-12-26)
parents 4e7d9cc9f816
children 6a2d1517e10c
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@504 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@504 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@504 165
james@504 166 ExAcquireFastMutex(&xpdd->xb_request_mutex);
james@504 167 xb_write(xpdd, msg, sizeof(struct xsd_sockmsg) + msg->len);
james@504 168 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
james@504 169 reply = xpdd->xb_reply;
james@504 170 xpdd->xb_reply = NULL;
james@504 171 ExReleaseFastMutex(&xpdd->xb_request_mutex);
james@504 172
james@504 173 return reply;
james@0 174 }
james@0 175
james@404 176 /*
james@404 177 Called at PASSIVE_LEVEL
james@404 178 */
james@0 179 char *
andy@15 180 XenBus_Read(
andy@13 181 PVOID Context,
andy@13 182 xenbus_transaction_t xbt,
james@504 183 char *path,
andy@13 184 char **value)
james@0 185 {
james@258 186 PXENPCI_DEVICE_DATA xpdd = Context;
james@145 187 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
andy@13 188 struct xsd_sockmsg *rep;
andy@13 189 char *res;
andy@13 190 char *msg;
james@0 191
james@342 192 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 193
james@272 194 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 195
james@504 196 rep = xenbus_format_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
andy@13 197 msg = errmsg(rep);
andy@13 198 if (msg) {
andy@13 199 *value = NULL;
andy@13 200 return msg;
andy@13 201 }
andy@13 202 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
andy@13 203 memcpy(res, rep + 1, rep->len);
andy@13 204 res[rep->len] = 0;
andy@13 205 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
andy@13 206 *value = res;
james@95 207
james@342 208 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 209
andy@13 210 return NULL;
james@0 211 }
james@0 212
james@404 213 /*
james@404 214 Called at PASSIVE_LEVEL
james@404 215 */
james@0 216 char *
andy@13 217 XenBus_Write(
andy@13 218 PVOID Context,
andy@13 219 xenbus_transaction_t xbt,
james@504 220 char *path,
james@504 221 char *value)
james@0 222 {
james@258 223 PXENPCI_DEVICE_DATA xpdd = Context;
andy@13 224 struct write_req req[] = {
james@145 225 {path, (ULONG)strlen(path) + 1},
andy@264 226 {value, (ULONG)strlen(value)},
andy@13 227 };
andy@13 228 struct xsd_sockmsg *rep;
andy@13 229 char *msg;
james@0 230
james@342 231 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 232
james@272 233 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 234
james@504 235 rep = xenbus_format_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
andy@13 236 msg = errmsg(rep);
andy@13 237 if (msg)
andy@13 238 return msg;
andy@13 239 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 240
james@342 241 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 242
andy@13 243 return NULL;
james@0 244 }
james@0 245
james@515 246 static VOID
james@515 247 XenBus_Dpc(PVOID ServiceContext)
james@515 248 {
james@515 249 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
james@515 250
james@515 251 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@515 252
james@515 253 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
james@515 254
james@515 255 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@515 256
james@515 257 return;
james@515 258 }
james@515 259
james@390 260 NTSTATUS
james@342 261 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
james@342 262 {
james@342 263 PHYSICAL_ADDRESS pa_xen_store_interface;
james@342 264 xen_ulong_t xen_store_mfn;
james@342 265
james@342 266 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
james@342 267 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
james@342 268 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
james@342 269 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
james@342 270
james@464 271 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
james@390 272
james@390 273 xpdd->XenBus_ShuttingDown = FALSE;
james@390 274 KeMemoryBarrier();
james@390 275
james@390 276 return STATUS_SUCCESS;
james@342 277 }
james@342 278
james@0 279 NTSTATUS
james@258 280 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
james@0 281 {
james@390 282 NTSTATUS status;
james@409 283 HANDLE thread_handle;
james@35 284 int i;
andy@37 285
james@409 286 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@35 287
james@272 288 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@35 289
james@504 290 ExInitializeFastMutex(&xpdd->xb_request_mutex);
james@504 291 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
james@128 292
james@35 293 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@128 294 {
andy@38 295 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 296 }
james@0 297
andy@15 298 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
andy@15 299 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
james@504 300 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
james@504 301
andy@38 302 xpdd->XenBus_ShuttingDown = FALSE;
james@0 303
james@390 304 status = XenBus_Connect(xpdd);
james@390 305 if (!NT_SUCCESS(status))
andy@101 306 {
james@390 307 return status;
andy@101 308 }
james@409 309
james@409 310 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, xpdd);
james@409 311 if (!NT_SUCCESS(status))
james@409 312 {
james@409 313 KdPrint((__DRIVER_NAME " Could not start read thread\n"));
james@409 314 return status;
james@409 315 }
james@409 316 KdPrint((__DRIVER_NAME " Started ReadThread\n"));
james@342 317
james@409 318 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_ReadThread, NULL);
james@409 319 ZwClose(thread_handle);
james@409 320 if (!NT_SUCCESS(status))
james@409 321 {
james@409 322 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_ReadThread) = %08x\n", status));
james@409 323 return status;
james@409 324 }
james@409 325
james@409 326 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
james@409 327 if (!NT_SUCCESS(status))
james@409 328 {
james@409 329 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
james@409 330 return status;
james@409 331 }
james@409 332 KdPrint((__DRIVER_NAME " Started WatchThread\n"));
james@409 333 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_WatchThread, NULL);
james@409 334 ZwClose(thread_handle);
james@409 335 if (!NT_SUCCESS(status))
james@409 336 {
james@409 337 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_WatchThread) = %08x\n", status));
james@409 338 }
james@409 339
james@409 340 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 341
james@0 342 return STATUS_SUCCESS;
james@0 343 }
james@0 344
james@406 345 char *
james@406 346 XenBus_SendRemWatch(
james@406 347 PVOID context,
james@406 348 xenbus_transaction_t xbt,
james@504 349 char *path,
james@504 350 int index)
james@406 351 {
james@406 352 struct xsd_sockmsg *rep;
james@406 353 char *msg;
james@406 354 char Token[20];
james@406 355 struct write_req req[2];
james@406 356
james@406 357 req[0].data = path;
james@406 358 req[0].len = (ULONG)strlen(path) + 1;
james@406 359
james@406 360 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
james@406 361 req[1].data = Token;
james@406 362 req[1].len = (ULONG)strlen(Token) + 1;
james@406 363
james@504 364 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
james@406 365
james@406 366 msg = errmsg(rep);
james@406 367 if (msg)
james@406 368 return msg;
james@406 369
james@406 370 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@406 371
james@406 372 return NULL;
james@406 373 }
james@406 374
james@35 375 NTSTATUS
james@390 376 XenBus_StopThreads(PXENPCI_DEVICE_DATA xpdd)
james@35 377 {
james@409 378 NTSTATUS status;
andy@56 379 //KWAIT_BLOCK WaitBlockArray[2];
james@406 380 int i;
james@409 381 LARGE_INTEGER timeout;
james@35 382
james@406 383 FUNCTION_ENTER();
james@406 384
james@272 385 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 386
james@406 387 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@406 388 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@406 389 if (xpdd->XenBus_WatchEntries[i].Active)
james@406 390 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@406 391 }
james@406 392
andy@38 393 xpdd->XenBus_ShuttingDown = TRUE;
james@406 394 KeMemoryBarrier();
james@35 395
james@385 396 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
james@385 397 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
james@409 398
james@409 399 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 400 while ((status = KeWaitForSingleObject(xpdd->XenBus_ReadThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
james@409 401 {
james@409 402 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 403 }
james@409 404 ObDereferenceObject(xpdd->XenBus_ReadThread);
james@409 405 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 406 while ((status = KeWaitForSingleObject(xpdd->XenBus_WatchThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
james@409 407 {
james@409 408 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 409 }
james@409 410 ObDereferenceObject(xpdd->XenBus_WatchThread);
james@406 411
andy@38 412 xpdd->XenBus_ShuttingDown = FALSE;
james@35 413
james@406 414 FUNCTION_EXIT();
james@35 415
james@0 416 return STATUS_SUCCESS;
james@0 417 }
james@0 418
james@0 419 char *
andy@13 420 XenBus_List(
andy@13 421 PVOID Context,
andy@13 422 xenbus_transaction_t xbt,
james@504 423 char *pre,
andy@13 424 char ***contents)
james@0 425 {
james@258 426 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 427 struct xsd_sockmsg *reply, *repmsg;
james@145 428 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
james@0 429 ULONG nr_elems, x, i;
james@0 430 char **res;
james@0 431 char *msg;
james@0 432
james@134 433 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 434
james@272 435 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 436
james@504 437 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
james@0 438 msg = errmsg(repmsg);
andy@15 439 if (msg)
andy@15 440 {
james@0 441 *contents = NULL;
james@134 442 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 443 return msg;
james@0 444 }
james@0 445 reply = repmsg + 1;
james@0 446 for (x = nr_elems = 0; x < repmsg->len; x++)
andy@15 447 {
james@0 448 nr_elems += (((char *)reply)[x] == 0);
andy@15 449 }
andy@15 450 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
andy@15 451 XENPCI_POOL_TAG);
andy@15 452 for (x = i = 0; i < nr_elems; i++)
andy@15 453 {
james@145 454 int l = (int)strlen((char *)reply + x);
james@0 455 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
james@0 456 memcpy(res[i], (char *)reply + x, l + 1);
james@0 457 x += l + 1;
james@0 458 }
james@0 459 res[i] = NULL;
james@0 460 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
james@0 461 *contents = res;
james@134 462 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 463 return NULL;
james@0 464 }
james@0 465
andy@328 466 static DDKAPI void
andy@15 467 XenBus_ReadThreadProc(PVOID StartContext)
james@0 468 {
james@0 469 int NewWriteIndex;
james@0 470 struct xsd_sockmsg msg;
james@0 471 char *payload;
james@0 472 char *path, *token;
james@258 473 PXENPCI_DEVICE_DATA xpdd = StartContext;
james@0 474
james@0 475 for(;;)
james@0 476 {
andy@15 477 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
james@523 478 //Print((__DRIVER_NAME " +++ thread woken\n"));
andy@38 479 if (xpdd->XenBus_ShuttingDown)
james@35 480 {
james@35 481 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
james@35 482 PsTerminateSystemThread(0);
james@35 483 }
andy@15 484 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
james@0 485 {
james@0 486 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
andy@15 487 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
james@0 488 {
james@523 489 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
james@0 490 break;
james@0 491 }
james@0 492 KeMemoryBarrier();
andy@15 493 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
andy@15 494 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
andy@15 495 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
james@0 496 {
james@523 497 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
james@0 498 break;
james@0 499 }
james@0 500
andy@20 501 if (msg.type != XS_WATCH_EVENT)
andy@20 502 {
james@504 503 xpdd->xb_reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@20 504 memcpy_from_ring(xpdd->xen_store_interface->rsp,
james@504 505 xpdd->xb_reply,
andy@20 506 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
andy@20 507 msg.len + sizeof(msg));
andy@20 508 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@523 509 //KdPrint((__DRIVER_NAME " +++ Setting event\n"));
james@504 510 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
andy@20 511 }
andy@20 512 else // a watch: add to watch ring and signal watch thread
james@0 513 {
james@0 514 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@15 515 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
andy@15 516 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
andy@15 517 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@0 518 path = payload + sizeof(msg);
james@0 519 token = path + strlen(path) + 1;
james@0 520
andy@15 521 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
andy@15 522 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
james@0 523 {
andy@15 524 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
andy@15 525 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
andy@15 526 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
james@0 527 }
james@0 528 else
james@0 529 {
james@523 530 //KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
james@0 531 // drop the message on the floor
james@0 532 continue;
james@0 533 }
james@0 534
james@0 535 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
james@385 536 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
james@0 537 }
james@0 538 }
james@0 539 }
james@0 540 }
james@0 541
andy@328 542 static DDKAPI void
james@0 543 XenBus_WatchThreadProc(PVOID StartContext)
james@0 544 {
james@0 545 int index;
james@0 546 PXENBUS_WATCH_ENTRY entry;
james@258 547 PXENPCI_DEVICE_DATA xpdd = StartContext;
james@0 548
james@0 549 for(;;)
james@0 550 {
andy@37 551 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
james@504 552 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
andy@38 553 if (xpdd->XenBus_ShuttingDown)
james@35 554 {
james@35 555 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
james@504 556 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@35 557 PsTerminateSystemThread(0);
james@409 558 KdPrint((__DRIVER_NAME " WatchThreadProc still running... wtf?\n"));
james@35 559 }
andy@38 560 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
james@0 561 {
andy@15 562 xpdd->XenBus_WatchRingReadIndex =
andy@15 563 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
andy@15 564 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
james@0 565
andy@15 566 entry = &xpdd->XenBus_WatchEntries[index];
james@128 567 if (!entry->Active || !entry->ServiceRoutine)
james@0 568 {
james@138 569 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
james@0 570 continue;
james@0 571 }
james@0 572 entry->Count++;
andy@15 573 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
james@0 574 }
james@504 575 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 576 }
james@0 577 }
james@0 578
james@404 579 /*
james@404 580 Called at PASSIVE_LEVEL
james@404 581 */
james@279 582 static char *
james@279 583 XenBus_SendAddWatch(
james@279 584 PVOID Context,
james@279 585 xenbus_transaction_t xbt,
james@504 586 char *Path,
james@279 587 int slot)
james@279 588 {
james@279 589 PXENPCI_DEVICE_DATA xpdd = Context;
james@279 590 struct xsd_sockmsg *rep;
james@279 591 char *msg;
james@279 592 char Token[20];
james@279 593 struct write_req req[2];
james@279 594
james@279 595 req[0].data = Path;
james@279 596 req[0].len = (ULONG)strlen(Path) + 1;
james@279 597
james@279 598 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
james@279 599 req[1].data = Token;
james@279 600 req[1].len = (ULONG)strlen(Token) + 1;
james@279 601
james@504 602 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
james@404 603
james@279 604 msg = errmsg(rep);
james@283 605 if (!msg)
james@283 606 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@279 607
james@279 608 return msg;
james@279 609 }
james@279 610
james@342 611 /* called at PASSIVE_LEVEL */
james@390 612 NTSTATUS
james@409 613 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
james@409 614 {
james@409 615 int i;
james@409 616
james@409 617 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@409 618 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@409 619 if (xpdd->XenBus_WatchEntries[i].Active)
james@409 620 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@409 621 }
james@409 622
james@409 623 // need to synchronise with readthread here too to ensure that it won't do anything silly
james@409 624
james@409 625 return STATUS_SUCCESS;
james@409 626 }
james@409 627
james@409 628 /* called at PASSIVE_LEVEL */
james@409 629 NTSTATUS
james@279 630 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
james@279 631 {
james@390 632 NTSTATUS status;
james@279 633 int i;
james@341 634
andy@398 635 FUNCTION_ENTER();
james@342 636
james@390 637 status = XenBus_Connect(xpdd);
james@390 638 if (!NT_SUCCESS(status))
james@390 639 {
james@390 640 return status;
james@390 641 }
james@279 642
james@279 643 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@341 644 {
james@279 645 if (xpdd->XenBus_WatchEntries[i].Active)
james@341 646 {
james@341 647 KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
james@279 648 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@341 649 }
james@341 650 }
andy@398 651 FUNCTION_EXIT();
james@390 652
james@390 653 return STATUS_SUCCESS;
james@279 654 }
james@279 655
james@0 656 char *
andy@15 657 XenBus_AddWatch(
andy@13 658 PVOID Context,
andy@13 659 xenbus_transaction_t xbt,
james@504 660 char *Path,
andy@13 661 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 662 PVOID ServiceContext)
james@0 663 {
james@258 664 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 665 char *msg;
james@0 666 int i;
andy@94 667 PXENBUS_WATCH_ENTRY w_entry;
james@0 668
james@267 669 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 670
james@272 671 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 672
andy@94 673 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
james@0 674
james@504 675 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 676
james@0 677 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
andy@15 678 if (xpdd->XenBus_WatchEntries[i].Active == 0)
james@0 679 break;
james@0 680
james@0 681 if (i == MAX_WATCH_ENTRIES)
james@0 682 {
james@0 683 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
james@504 684 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 685 return NULL;
james@0 686 }
james@0 687
andy@94 688 /* must init watchentry before starting watch */
james@128 689
andy@94 690 w_entry = &xpdd->XenBus_WatchEntries[i];
andy@94 691 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
andy@94 692 w_entry->ServiceRoutine = ServiceRoutine;
andy@94 693 w_entry->ServiceContext = ServiceContext;
andy@94 694 w_entry->Count = 0;
andy@94 695 w_entry->Active = 1;
andy@94 696
james@504 697 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@128 698
james@279 699 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
james@0 700
andy@93 701 if (msg)
andy@93 702 {
andy@93 703 xpdd->XenBus_WatchEntries[i].Active = 0;
james@341 704 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
andy@93 705 return msg;
andy@93 706 }
andy@93 707
james@341 708 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
james@0 709
james@0 710 return NULL;
james@0 711 }
james@0 712
james@0 713 char *
andy@13 714 XenBus_RemWatch(
andy@13 715 PVOID Context,
andy@13 716 xenbus_transaction_t xbt,
james@504 717 char *Path,
andy@13 718 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 719 PVOID ServiceContext)
james@0 720 {
james@258 721 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 722 char *msg;
james@0 723 int i;
james@0 724
james@267 725 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 726 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 727
james@504 728 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 729
james@0 730 // check that Path < 128 chars
james@0 731
james@409 732 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@409 733 {
james@409 734 #if 0
james@409 735 if (xpdd->XenBus_WatchEntries[i].Active)
james@409 736 {
james@409 737 KdPrint((__DRIVER_NAME " (%d == 1) = %d\n", xpdd->XenBus_WatchEntries[i].Active, xpdd->XenBus_WatchEntries[i].Active == 1));
james@409 738 KdPrint((__DRIVER_NAME " strcmp(%s, %s) = %d\n", xpdd->XenBus_WatchEntries[i].Path, Path, strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)));
james@409 739 KdPrint((__DRIVER_NAME " (%p == %p) = %d\n", xpdd->XenBus_WatchEntries[i].ServiceRoutine, ServiceRoutine, xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine));
james@409 740 KdPrint((__DRIVER_NAME " (%p == %p) = %d\n", xpdd->XenBus_WatchEntries[i].ServiceContext, ServiceContext, xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext));
james@409 741 #endif
andy@15 742 if (xpdd->XenBus_WatchEntries[i].Active == 1
andy@15 743 && strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) == 0
andy@15 744 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
andy@15 745 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
james@409 746 {
james@409 747 KdPrint((__DRIVER_NAME " Match\n"));
james@0 748 break;
james@409 749 }
james@409 750 #if 0
james@409 751 }
james@409 752 #endif
james@0 753 }
james@0 754
james@0 755 if (i == MAX_WATCH_ENTRIES)
james@0 756 {
james@504 757 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 758 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
james@0 759 return NULL;
james@0 760 }
james@0 761
james@128 762 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 763 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
james@128 764
james@504 765 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 766
james@406 767 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
james@406 768
james@267 769 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 770
james@406 771 return msg;
james@0 772 }
james@0 773
james@0 774
james@0 775 char *
andy@13 776 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
james@0 777 {
james@258 778 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 779 /* xenstored becomes angry if you send a length 0 message, so just
james@0 780 shove a nul terminator on the end */
james@0 781 struct write_req req = { "", 1};
james@0 782 struct xsd_sockmsg *rep;
james@0 783 char *err;
james@0 784
james@134 785 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 786 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@95 787
james@504 788 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
james@0 789 err = errmsg(rep);
james@0 790 if (err)
james@0 791 return err;
james@0 792 *xbt = atoi((char *)(rep + 1));
james@0 793 //sscanf((char *)(rep + 1), "%u", xbt);
james@0 794 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 795
james@134 796 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 797
james@0 798 return NULL;
james@0 799 }
james@0 800
james@0 801 char *
andy@15 802 XenBus_EndTransaction(
andy@15 803 PVOID Context,
andy@15 804 xenbus_transaction_t t,
andy@15 805 int abort,
andy@15 806 int *retry)
james@0 807 {
james@258 808 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 809 struct xsd_sockmsg *rep;
james@0 810 struct write_req req;
james@0 811 char *err;
james@0 812
james@134 813 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 814
james@0 815 *retry = 0;
james@0 816
james@0 817 req.data = abort ? "F" : "T";
james@0 818 req.len = 2;
james@504 819 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
james@0 820 err = errmsg(rep);
james@0 821 if (err) {
james@0 822 if (!strcmp(err, "EAGAIN")) {
james@0 823 *retry = 1;
james@0 824 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
james@0 825 return NULL;
james@0 826 } else {
james@0 827 return err;
james@0 828 }
james@0 829 }
james@0 830 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 831
james@134 832 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 833
james@0 834 return NULL;
james@0 835 }
james@0 836
james@0 837 char *
andy@15 838 XenBus_Printf(
andy@15 839 PVOID Context,
andy@15 840 xenbus_transaction_t xbt,
james@504 841 char *path,
james@504 842 char *fmt,
andy@15 843 ...)
james@0 844 {
james@258 845 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 846 va_list ap;
andy@101 847 char buf[512];
james@95 848 char *retval;
james@95 849
james@134 850 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 851 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 852
james@0 853 va_start(ap, fmt);
james@0 854 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
james@0 855 va_end(ap);
james@258 856 retval = XenBus_Write(xpdd, xbt, path, buf);
james@95 857
james@134 858 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 859
james@95 860 return retval;
andy@37 861 }