win-pvdrivers

annotate xenpci/xenbus.c @ 515:4e7d9cc9f816

Refreshed the EVT_ACTION_TYPE_NORMAL code path. Updated prototypes.
Fixed compiler warning under amd64
author James Harper <james.harper@bendigoit.com.au>
date Thu Dec 25 17:49:31 2008 +1100 (2008-12-25)
parents 6031f074c2f0
children 331f861accf0
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@504 81 FUNCTION_ENTER();
james@504 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@504 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@504 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@504 146 KdPrint((__DRIVER_NAME " waiting...\n"));
james@504 147 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
james@504 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@504 478 KdPrint((__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@409 483 KdPrint((__DRIVER_NAME " ReadThreadProc still running... wtf?\n"));
james@35 484 }
andy@15 485 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
james@0 486 {
james@0 487 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
andy@15 488 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
james@0 489 {
james@504 490 KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
james@0 491 break;
james@0 492 }
james@0 493 KeMemoryBarrier();
andy@15 494 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
andy@15 495 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
andy@15 496 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
james@0 497 {
james@504 498 KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
james@0 499 break;
james@0 500 }
james@0 501
andy@20 502 if (msg.type != XS_WATCH_EVENT)
andy@20 503 {
james@504 504 xpdd->xb_reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@20 505 memcpy_from_ring(xpdd->xen_store_interface->rsp,
james@504 506 xpdd->xb_reply,
andy@20 507 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
andy@20 508 msg.len + sizeof(msg));
andy@20 509 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@504 510 KdPrint((__DRIVER_NAME " +++ Setting event\n"));
james@504 511 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
andy@20 512 }
andy@20 513 else // a watch: add to watch ring and signal watch thread
james@0 514 {
james@0 515 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
andy@15 516 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
andy@15 517 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
andy@15 518 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@0 519 path = payload + sizeof(msg);
james@0 520 token = path + strlen(path) + 1;
james@0 521
andy@15 522 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
andy@15 523 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
james@0 524 {
andy@15 525 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
andy@15 526 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
andy@15 527 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
james@0 528 }
james@0 529 else
james@0 530 {
james@0 531 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
james@0 532 // drop the message on the floor
james@0 533 continue;
james@0 534 }
james@0 535
james@0 536 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
james@385 537 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
james@0 538 }
james@0 539 }
james@0 540 }
james@0 541 }
james@0 542
andy@328 543 static DDKAPI void
james@0 544 XenBus_WatchThreadProc(PVOID StartContext)
james@0 545 {
james@0 546 int index;
james@0 547 PXENBUS_WATCH_ENTRY entry;
james@258 548 PXENPCI_DEVICE_DATA xpdd = StartContext;
james@0 549
james@0 550 for(;;)
james@0 551 {
andy@37 552 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
james@504 553 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
andy@38 554 if (xpdd->XenBus_ShuttingDown)
james@35 555 {
james@35 556 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
james@504 557 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@35 558 PsTerminateSystemThread(0);
james@409 559 KdPrint((__DRIVER_NAME " WatchThreadProc still running... wtf?\n"));
james@35 560 }
andy@38 561 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
james@0 562 {
andy@15 563 xpdd->XenBus_WatchRingReadIndex =
andy@15 564 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
andy@15 565 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
james@0 566
andy@15 567 entry = &xpdd->XenBus_WatchEntries[index];
james@128 568 if (!entry->Active || !entry->ServiceRoutine)
james@0 569 {
james@138 570 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
james@0 571 continue;
james@0 572 }
james@0 573 entry->Count++;
andy@15 574 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
james@0 575 }
james@504 576 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 577 }
james@0 578 }
james@0 579
james@404 580 /*
james@404 581 Called at PASSIVE_LEVEL
james@404 582 */
james@279 583 static char *
james@279 584 XenBus_SendAddWatch(
james@279 585 PVOID Context,
james@279 586 xenbus_transaction_t xbt,
james@504 587 char *Path,
james@279 588 int slot)
james@279 589 {
james@279 590 PXENPCI_DEVICE_DATA xpdd = Context;
james@279 591 struct xsd_sockmsg *rep;
james@279 592 char *msg;
james@279 593 char Token[20];
james@279 594 struct write_req req[2];
james@279 595
james@279 596 req[0].data = Path;
james@279 597 req[0].len = (ULONG)strlen(Path) + 1;
james@279 598
james@279 599 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
james@279 600 req[1].data = Token;
james@279 601 req[1].len = (ULONG)strlen(Token) + 1;
james@279 602
james@504 603 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
james@404 604
james@279 605 msg = errmsg(rep);
james@283 606 if (!msg)
james@283 607 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@279 608
james@279 609 return msg;
james@279 610 }
james@279 611
james@342 612 /* called at PASSIVE_LEVEL */
james@390 613 NTSTATUS
james@409 614 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
james@409 615 {
james@409 616 int i;
james@409 617
james@409 618 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@409 619 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@409 620 if (xpdd->XenBus_WatchEntries[i].Active)
james@409 621 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@409 622 }
james@409 623
james@409 624 // need to synchronise with readthread here too to ensure that it won't do anything silly
james@409 625
james@409 626 return STATUS_SUCCESS;
james@409 627 }
james@409 628
james@409 629 /* called at PASSIVE_LEVEL */
james@409 630 NTSTATUS
james@279 631 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
james@279 632 {
james@390 633 NTSTATUS status;
james@279 634 int i;
james@341 635
andy@398 636 FUNCTION_ENTER();
james@342 637
james@390 638 status = XenBus_Connect(xpdd);
james@390 639 if (!NT_SUCCESS(status))
james@390 640 {
james@390 641 return status;
james@390 642 }
james@279 643
james@279 644 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@341 645 {
james@279 646 if (xpdd->XenBus_WatchEntries[i].Active)
james@341 647 {
james@341 648 KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
james@279 649 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@341 650 }
james@341 651 }
andy@398 652 FUNCTION_EXIT();
james@390 653
james@390 654 return STATUS_SUCCESS;
james@279 655 }
james@279 656
james@0 657 char *
andy@15 658 XenBus_AddWatch(
andy@13 659 PVOID Context,
andy@13 660 xenbus_transaction_t xbt,
james@504 661 char *Path,
andy@13 662 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 663 PVOID ServiceContext)
james@0 664 {
james@258 665 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 666 char *msg;
james@0 667 int i;
andy@94 668 PXENBUS_WATCH_ENTRY w_entry;
james@0 669
james@267 670 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@0 671
james@272 672 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 673
andy@94 674 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
james@0 675
james@504 676 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 677
james@0 678 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
andy@15 679 if (xpdd->XenBus_WatchEntries[i].Active == 0)
james@0 680 break;
james@0 681
james@0 682 if (i == MAX_WATCH_ENTRIES)
james@0 683 {
james@0 684 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
james@504 685 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 686 return NULL;
james@0 687 }
james@0 688
andy@94 689 /* must init watchentry before starting watch */
james@128 690
andy@94 691 w_entry = &xpdd->XenBus_WatchEntries[i];
andy@94 692 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
andy@94 693 w_entry->ServiceRoutine = ServiceRoutine;
andy@94 694 w_entry->ServiceContext = ServiceContext;
andy@94 695 w_entry->Count = 0;
andy@94 696 w_entry->Active = 1;
andy@94 697
james@504 698 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@128 699
james@279 700 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
james@0 701
andy@93 702 if (msg)
andy@93 703 {
andy@93 704 xpdd->XenBus_WatchEntries[i].Active = 0;
james@341 705 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
andy@93 706 return msg;
andy@93 707 }
andy@93 708
james@341 709 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
james@0 710
james@0 711 return NULL;
james@0 712 }
james@0 713
james@0 714 char *
andy@13 715 XenBus_RemWatch(
andy@13 716 PVOID Context,
andy@13 717 xenbus_transaction_t xbt,
james@504 718 char *Path,
andy@13 719 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 720 PVOID ServiceContext)
james@0 721 {
james@258 722 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 723 char *msg;
james@0 724 int i;
james@0 725
james@267 726 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 727 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 728
james@504 729 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 730
james@0 731 // check that Path < 128 chars
james@0 732
james@409 733 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@409 734 {
james@409 735 #if 0
james@409 736 if (xpdd->XenBus_WatchEntries[i].Active)
james@409 737 {
james@409 738 KdPrint((__DRIVER_NAME " (%d == 1) = %d\n", xpdd->XenBus_WatchEntries[i].Active, xpdd->XenBus_WatchEntries[i].Active == 1));
james@409 739 KdPrint((__DRIVER_NAME " strcmp(%s, %s) = %d\n", xpdd->XenBus_WatchEntries[i].Path, Path, strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)));
james@409 740 KdPrint((__DRIVER_NAME " (%p == %p) = %d\n", xpdd->XenBus_WatchEntries[i].ServiceRoutine, ServiceRoutine, xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine));
james@409 741 KdPrint((__DRIVER_NAME " (%p == %p) = %d\n", xpdd->XenBus_WatchEntries[i].ServiceContext, ServiceContext, xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext));
james@409 742 #endif
andy@15 743 if (xpdd->XenBus_WatchEntries[i].Active == 1
andy@15 744 && strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) == 0
andy@15 745 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
andy@15 746 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
james@409 747 {
james@409 748 KdPrint((__DRIVER_NAME " Match\n"));
james@0 749 break;
james@409 750 }
james@409 751 #if 0
james@409 752 }
james@409 753 #endif
james@0 754 }
james@0 755
james@0 756 if (i == MAX_WATCH_ENTRIES)
james@0 757 {
james@504 758 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 759 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
james@0 760 return NULL;
james@0 761 }
james@0 762
james@128 763 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 764 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
james@128 765
james@504 766 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 767
james@406 768 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
james@406 769
james@267 770 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@0 771
james@406 772 return msg;
james@0 773 }
james@0 774
james@0 775
james@0 776 char *
andy@13 777 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
james@0 778 {
james@258 779 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 780 /* xenstored becomes angry if you send a length 0 message, so just
james@0 781 shove a nul terminator on the end */
james@0 782 struct write_req req = { "", 1};
james@0 783 struct xsd_sockmsg *rep;
james@0 784 char *err;
james@0 785
james@134 786 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 787 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@95 788
james@504 789 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
james@0 790 err = errmsg(rep);
james@0 791 if (err)
james@0 792 return err;
james@0 793 *xbt = atoi((char *)(rep + 1));
james@0 794 //sscanf((char *)(rep + 1), "%u", xbt);
james@0 795 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 796
james@134 797 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 798
james@0 799 return NULL;
james@0 800 }
james@0 801
james@0 802 char *
andy@15 803 XenBus_EndTransaction(
andy@15 804 PVOID Context,
andy@15 805 xenbus_transaction_t t,
andy@15 806 int abort,
andy@15 807 int *retry)
james@0 808 {
james@258 809 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 810 struct xsd_sockmsg *rep;
james@0 811 struct write_req req;
james@0 812 char *err;
james@0 813
james@134 814 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 815
james@0 816 *retry = 0;
james@0 817
james@0 818 req.data = abort ? "F" : "T";
james@0 819 req.len = 2;
james@504 820 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
james@0 821 err = errmsg(rep);
james@0 822 if (err) {
james@0 823 if (!strcmp(err, "EAGAIN")) {
james@0 824 *retry = 1;
james@0 825 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
james@0 826 return NULL;
james@0 827 } else {
james@0 828 return err;
james@0 829 }
james@0 830 }
james@0 831 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 832
james@134 833 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 834
james@0 835 return NULL;
james@0 836 }
james@0 837
james@0 838 char *
andy@15 839 XenBus_Printf(
andy@15 840 PVOID Context,
andy@15 841 xenbus_transaction_t xbt,
james@504 842 char *path,
james@504 843 char *fmt,
andy@15 844 ...)
james@0 845 {
james@258 846 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 847 va_list ap;
andy@101 848 char buf[512];
james@95 849 char *retval;
james@95 850
james@134 851 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@272 852 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 853
james@0 854 va_start(ap, fmt);
james@0 855 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
james@0 856 va_end(ap);
james@258 857 retval = XenBus_Write(xpdd, xbt, path, buf);
james@95 858
james@134 859 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 860
james@95 861 return retval;
andy@37 862 }