win-pvdrivers

annotate xenpci/xenbus.c @ 538:e75bb8d68370

Lots more changes...
author James Harper <james.harper@bendigoit.com.au>
date Tue Mar 03 09:51:24 2009 +1100 (2009-03-03)
parents 1d39de3ab8d6
children f905eb3f0545
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@272 289 ASSERT(KeGetCurrentIrql() < DISPATCH_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@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@342 316
james@409 317 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_ReadThread, NULL);
james@409 318 ZwClose(thread_handle);
james@409 319 if (!NT_SUCCESS(status))
james@409 320 {
james@409 321 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_ReadThread) = %08x\n", status));
james@409 322 return status;
james@409 323 }
james@409 324
james@409 325 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
james@409 326 if (!NT_SUCCESS(status))
james@409 327 {
james@409 328 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
james@409 329 return status;
james@409 330 }
james@409 331 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_WatchThread, NULL);
james@409 332 ZwClose(thread_handle);
james@409 333 if (!NT_SUCCESS(status))
james@409 334 {
james@409 335 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_WatchThread) = %08x\n", status));
james@409 336 }
james@409 337
james@409 338 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 339
james@0 340 return STATUS_SUCCESS;
james@0 341 }
james@0 342
james@406 343 char *
james@406 344 XenBus_SendRemWatch(
james@406 345 PVOID context,
james@406 346 xenbus_transaction_t xbt,
james@504 347 char *path,
james@504 348 int index)
james@406 349 {
james@406 350 struct xsd_sockmsg *rep;
james@406 351 char *msg;
james@406 352 char Token[20];
james@406 353 struct write_req req[2];
james@406 354
james@406 355 req[0].data = path;
james@406 356 req[0].len = (ULONG)strlen(path) + 1;
james@406 357
james@406 358 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
james@406 359 req[1].data = Token;
james@406 360 req[1].len = (ULONG)strlen(Token) + 1;
james@406 361
james@504 362 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
james@406 363
james@406 364 msg = errmsg(rep);
james@406 365 if (msg)
james@406 366 return msg;
james@406 367
james@406 368 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@406 369
james@406 370 return NULL;
james@406 371 }
james@406 372
james@35 373 NTSTATUS
james@390 374 XenBus_StopThreads(PXENPCI_DEVICE_DATA xpdd)
james@35 375 {
james@409 376 NTSTATUS status;
andy@56 377 //KWAIT_BLOCK WaitBlockArray[2];
james@406 378 int i;
james@409 379 LARGE_INTEGER timeout;
james@35 380
james@406 381 FUNCTION_ENTER();
james@406 382
james@272 383 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 384
james@406 385 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@406 386 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@406 387 if (xpdd->XenBus_WatchEntries[i].Active)
james@406 388 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@406 389 }
james@406 390
andy@38 391 xpdd->XenBus_ShuttingDown = TRUE;
james@406 392 KeMemoryBarrier();
james@35 393
james@385 394 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
james@385 395 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
james@409 396
james@409 397 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 398 while ((status = KeWaitForSingleObject(xpdd->XenBus_ReadThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
james@409 399 {
james@409 400 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 401 }
james@409 402 ObDereferenceObject(xpdd->XenBus_ReadThread);
james@409 403 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 404 while ((status = KeWaitForSingleObject(xpdd->XenBus_WatchThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
james@409 405 {
james@409 406 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
james@409 407 }
james@409 408 ObDereferenceObject(xpdd->XenBus_WatchThread);
james@406 409
andy@38 410 xpdd->XenBus_ShuttingDown = FALSE;
james@35 411
james@406 412 FUNCTION_EXIT();
james@35 413
james@0 414 return STATUS_SUCCESS;
james@0 415 }
james@0 416
james@0 417 char *
andy@13 418 XenBus_List(
andy@13 419 PVOID Context,
andy@13 420 xenbus_transaction_t xbt,
james@504 421 char *pre,
andy@13 422 char ***contents)
james@0 423 {
james@258 424 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 425 struct xsd_sockmsg *reply, *repmsg;
james@145 426 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
james@0 427 ULONG nr_elems, x, i;
james@0 428 char **res;
james@0 429 char *msg;
james@0 430
james@134 431 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 432
james@272 433 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 434
james@504 435 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
james@0 436 msg = errmsg(repmsg);
andy@15 437 if (msg)
andy@15 438 {
james@0 439 *contents = NULL;
james@134 440 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 441 return msg;
james@0 442 }
james@0 443 reply = repmsg + 1;
james@0 444 for (x = nr_elems = 0; x < repmsg->len; x++)
andy@15 445 {
james@0 446 nr_elems += (((char *)reply)[x] == 0);
andy@15 447 }
andy@15 448 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
andy@15 449 XENPCI_POOL_TAG);
andy@15 450 for (x = i = 0; i < nr_elems; i++)
andy@15 451 {
james@145 452 int l = (int)strlen((char *)reply + x);
james@0 453 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
james@0 454 memcpy(res[i], (char *)reply + x, l + 1);
james@0 455 x += l + 1;
james@0 456 }
james@0 457 res[i] = NULL;
james@0 458 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
james@0 459 *contents = res;
james@134 460 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 461 return NULL;
james@0 462 }
james@0 463
andy@328 464 static DDKAPI void
andy@15 465 XenBus_ReadThreadProc(PVOID StartContext)
james@0 466 {
james@0 467 int NewWriteIndex;
james@0 468 struct xsd_sockmsg msg;
james@0 469 char *payload;
james@0 470 char *path, *token;
james@258 471 PXENPCI_DEVICE_DATA xpdd = StartContext;
james@0 472
james@0 473 for(;;)
james@0 474 {
andy@15 475 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
james@536 476 //KdPrint((__DRIVER_NAME " +++ thread woken\n"));
andy@38 477 if (xpdd->XenBus_ShuttingDown)
james@35 478 {
james@35 479 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
james@35 480 PsTerminateSystemThread(0);
james@35 481 }
andy@15 482 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
james@0 483 {
james@536 484 //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 485 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
james@0 486 {
james@523 487 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
james@0 488 break;
james@0 489 }
james@0 490 KeMemoryBarrier();
andy@15 491 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
andy@15 492 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
andy@15 493 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
james@0 494 {
james@523 495 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
james@0 496 break;
james@0 497 }
james@0 498
andy@20 499 if (msg.type != XS_WATCH_EVENT)
andy@20 500 {
james@504 501 xpdd->xb_reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@20 502 memcpy_from_ring(xpdd->xen_store_interface->rsp,
james@504 503 xpdd->xb_reply,
andy@20 504 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
andy@20 505 msg.len + sizeof(msg));
andy@20 506 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@523 507 //KdPrint((__DRIVER_NAME " +++ Setting event\n"));
james@504 508 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
andy@20 509 }
andy@20 510 else // a watch: add to watch ring and signal watch thread
james@0 511 {
james@0 512 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@15 513 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
andy@15 514 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
andy@15 515 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@0 516 path = payload + sizeof(msg);
james@0 517 token = path + strlen(path) + 1;
james@0 518
andy@15 519 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
andy@15 520 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
james@0 521 {
andy@15 522 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
andy@15 523 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
andy@15 524 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
james@0 525 }
james@0 526 else
james@0 527 {
james@536 528 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
james@0 529 // drop the message on the floor
james@0 530 continue;
james@0 531 }
james@0 532
james@0 533 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
james@385 534 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
james@0 535 }
james@0 536 }
james@0 537 }
james@0 538 }
james@0 539
andy@328 540 static DDKAPI void
james@0 541 XenBus_WatchThreadProc(PVOID StartContext)
james@0 542 {
james@0 543 int index;
james@0 544 PXENBUS_WATCH_ENTRY entry;
james@258 545 PXENPCI_DEVICE_DATA xpdd = StartContext;
james@0 546
james@0 547 for(;;)
james@0 548 {
andy@37 549 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
james@504 550 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
andy@38 551 if (xpdd->XenBus_ShuttingDown)
james@35 552 {
james@35 553 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
james@504 554 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@35 555 PsTerminateSystemThread(0);
james@409 556 KdPrint((__DRIVER_NAME " WatchThreadProc still running... wtf?\n"));
james@35 557 }
andy@38 558 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
james@0 559 {
james@536 560 //KdPrint((__DRIVER_NAME " +++ watch triggered\n"));
andy@15 561 xpdd->XenBus_WatchRingReadIndex =
andy@15 562 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
andy@15 563 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
james@0 564
andy@15 565 entry = &xpdd->XenBus_WatchEntries[index];
james@128 566 if (!entry->Active || !entry->ServiceRoutine)
james@0 567 {
james@138 568 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
james@0 569 continue;
james@0 570 }
james@0 571 entry->Count++;
andy@15 572 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
james@0 573 }
james@504 574 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 575 }
james@0 576 }
james@0 577
james@404 578 /*
james@404 579 Called at PASSIVE_LEVEL
james@404 580 */
james@279 581 static char *
james@279 582 XenBus_SendAddWatch(
james@279 583 PVOID Context,
james@279 584 xenbus_transaction_t xbt,
james@504 585 char *Path,
james@279 586 int slot)
james@279 587 {
james@279 588 PXENPCI_DEVICE_DATA xpdd = Context;
james@279 589 struct xsd_sockmsg *rep;
james@279 590 char *msg;
james@279 591 char Token[20];
james@279 592 struct write_req req[2];
james@279 593
james@279 594 req[0].data = Path;
james@279 595 req[0].len = (ULONG)strlen(Path) + 1;
james@279 596
james@279 597 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
james@279 598 req[1].data = Token;
james@279 599 req[1].len = (ULONG)strlen(Token) + 1;
james@279 600
james@504 601 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
james@404 602
james@279 603 msg = errmsg(rep);
james@283 604 if (!msg)
james@283 605 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@279 606
james@279 607 return msg;
james@279 608 }
james@279 609
james@342 610 /* called at PASSIVE_LEVEL */
james@390 611 NTSTATUS
james@409 612 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
james@409 613 {
james@409 614 int i;
james@409 615
james@409 616 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@409 617 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@409 618 if (xpdd->XenBus_WatchEntries[i].Active)
james@409 619 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@409 620 }
james@409 621
james@409 622 // need to synchronise with readthread here too to ensure that it won't do anything silly
james@409 623
james@409 624 return STATUS_SUCCESS;
james@409 625 }
james@409 626
james@409 627 /* called at PASSIVE_LEVEL */
james@409 628 NTSTATUS
james@279 629 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
james@279 630 {
james@390 631 NTSTATUS status;
james@279 632 int i;
james@341 633
andy@398 634 FUNCTION_ENTER();
james@342 635
james@390 636 status = XenBus_Connect(xpdd);
james@390 637 if (!NT_SUCCESS(status))
james@390 638 {
james@390 639 return status;
james@390 640 }
james@536 641 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
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@536 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@538 734 if (xpdd->XenBus_WatchEntries[i].Active
james@538 735 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
andy@15 736 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
andy@15 737 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
james@409 738 {
james@409 739 KdPrint((__DRIVER_NAME " Match\n"));
james@0 740 break;
james@409 741 }
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
james@0 826 char *
andy@15 827 XenBus_Printf(
andy@15 828 PVOID Context,
andy@15 829 xenbus_transaction_t xbt,
james@504 830 char *path,
james@504 831 char *fmt,
andy@15 832 ...)
james@0 833 {
james@258 834 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 835 va_list ap;
andy@101 836 char buf[512];
james@95 837 char *retval;
james@95 838
james@134 839 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 840 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 841
james@0 842 va_start(ap, fmt);
james@0 843 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
james@0 844 va_end(ap);
james@258 845 retval = XenBus_Write(xpdd, xbt, path, buf);
james@95 846
james@134 847 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 848
james@95 849 return retval;
andy@37 850 }