win-pvdrivers

annotate xenpci/xenbus.c @ 398:e7292fd9e55a

Fixup xenpci for mingw build with DBG enabled.

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