win-pvdrivers

annotate xenpci/xenbus.c @ 512:6031f074c2f0

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