win-pvdrivers

annotate xenpci/xenbus.c @ 464:4f1c7b79948b

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