win-pvdrivers

annotate xenpci/xenbus.c @ 385:e556065b2f1a

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