win-pvdrivers

annotate xenpci/xenbus.c @ 529:6a2d1517e10c

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