win-pvdrivers

view xenpci/xenbus.c @ 390:46b6fa5bb7ad

Put synchronisation code into xenbus. We also now kill the xenbus threads before suspend and start them again on resume, to avoid any chance of a race.
author James Harper <james.harper@bendigoit.com.au>
date Mon Jul 14 23:04:23 2008 +1000 (2008-07-14)
parents e556065b2f1a
children e7292fd9e55a fdb7f8853695
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenpci.h"
21 #include "io/xs_wire.h"
22 #include <stdlib.h>
24 #pragma warning( disable : 4204 )
25 #pragma warning( disable : 4221 )
27 struct write_req {
28 const void *data;
29 unsigned len;
30 };
32 static DDKAPI void
33 XenBus_ReadThreadProc(PVOID StartContext);
34 static DDKAPI void
35 XenBus_WatchThreadProc(PVOID StartContext);
36 static DDKAPI BOOLEAN
37 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext);
39 static int allocate_xenbus_id(PXENPCI_DEVICE_DATA xpdd)
40 {
41 static int probe;
42 int o_probe;
43 KIRQL old_irql;
45 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
47 for (;;)
48 {
49 KeAcquireSpinLock(&xpdd->xenbus_id_lock, &old_irql);
50 if (xpdd->nr_live_reqs < NR_XB_REQS)
51 break;
52 KeReleaseSpinLock(&xpdd->xenbus_id_lock, old_irql);
53 KeWaitForSingleObject(&xpdd->xenbus_id_event, Executive, KernelMode, FALSE, NULL);
54 }
56 o_probe = probe;
58 for (;;)
59 {
60 if (!xpdd->req_info[o_probe].In_Use)
61 break;
62 o_probe = (o_probe + 1) % NR_XB_REQS;
63 ASSERT(o_probe != probe);
64 }
65 xpdd->nr_live_reqs++;
66 xpdd->req_info[o_probe].In_Use = 1;
67 probe = (o_probe + 1) % NR_XB_REQS;
68 KeReleaseSpinLock(&xpdd->xenbus_id_lock, old_irql);
69 KeInitializeEvent(&xpdd->req_info[o_probe].WaitEvent, SynchronizationEvent, FALSE);
71 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
73 return o_probe;
74 }
76 static void release_xenbus_id(PXENPCI_DEVICE_DATA xpdd, int id)
77 {
78 KIRQL old_irql;
80 ASSERT(xpdd->req_info[id].In_Use);
81 KeAcquireSpinLock(&xpdd->xenbus_id_lock, &old_irql);
82 xpdd->req_info[id].In_Use = 0;
83 xpdd->nr_live_reqs--;
84 xpdd->req_info[id].In_Use = 0;
85 if (xpdd->nr_live_reqs == NR_XB_REQS - 1)
86 KeSetEvent(&xpdd->xenbus_id_event, IO_NO_INCREMENT, FALSE);
87 KeReleaseSpinLock(&xpdd->xenbus_id_lock, old_irql);
88 }
90 // This routine free's the rep structure if there was an error!!!
91 static char *errmsg(struct xsd_sockmsg *rep)
92 {
93 char *res;
95 if (!rep) {
96 char msg[] = "No reply";
97 size_t len = strlen(msg) + 1;
98 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
99 }
100 if (rep->type != XS_ERROR)
101 return NULL;
102 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
103 memcpy(res, rep + 1, rep->len);
104 res[rep->len] = 0;
105 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
106 return res;
107 }
109 static void memcpy_from_ring(const void *Ring,
110 void *Dest,
111 int off,
112 int len)
113 {
114 int c1, c2;
115 const char *ring = Ring;
116 char *dest = Dest;
117 c1 = min(len, XENSTORE_RING_SIZE - off);
118 c2 = len - c1;
119 memcpy(dest, ring + off, c1);
120 memcpy(dest + c1, ring, c2);
121 }
123 static void xb_write(
124 PXENPCI_DEVICE_DATA xpdd,
125 int type,
126 int req_id,
127 xenbus_transaction_t trans_id,
128 const struct write_req *req,
129 int nr_reqs)
130 {
131 XENSTORE_RING_IDX prod;
132 int r;
133 size_t len = 0;
134 const struct write_req *cur_req;
135 size_t req_off;
136 size_t total_off;
137 size_t this_chunk;
138 struct xsd_sockmsg m = {type, req_id, trans_id };
139 struct write_req header_req = { &m, sizeof(m) };
141 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
143 for (r = 0; r < nr_reqs; r++)
144 len += (size_t)req[r].len;
145 m.len = (ULONG)len;
146 len += sizeof(m);
148 cur_req = &header_req;
150 ASSERT(len <= XENSTORE_RING_SIZE);
151 /* Wait for the ring to drain to the point where we can send the
152 message. */
153 prod = xpdd->xen_store_interface->req_prod;
155 while (prod + len - xpdd->xen_store_interface->req_cons > XENSTORE_RING_SIZE)
156 {
157 /* Wait for there to be space on the ring */
158 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
159 prod = xpdd->xen_store_interface->req_prod;
160 }
162 /* We're now guaranteed to be able to send the message without
163 overflowing the ring. Do so. */
165 total_off = 0;
166 req_off = 0;
168 while (total_off < len)
169 {
170 this_chunk = min(cur_req->len - req_off,XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
171 memcpy((char *)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), (char *)cur_req->data + req_off, this_chunk);
172 prod += (XENSTORE_RING_IDX)this_chunk;
173 req_off += this_chunk;
174 total_off += this_chunk;
175 if (req_off == cur_req->len)
176 {
177 req_off = 0;
178 if (cur_req == &header_req)
179 cur_req = req;
180 else
181 cur_req++;
182 }
183 }
185 /* Remote must see entire message before updating indexes */
186 KeMemoryBarrier();
188 xpdd->xen_store_interface->req_prod += (XENSTORE_RING_IDX)len;
190 /* Send evtchn to notify remote */
191 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn);
193 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
194 }
196 static struct xsd_sockmsg *
197 xenbus_msg_reply(
198 PXENPCI_DEVICE_DATA xpdd,
199 int type,
200 xenbus_transaction_t trans,
201 struct write_req *io,
202 int nr_reqs)
203 {
204 int id;
206 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
208 id = allocate_xenbus_id(xpdd);
210 xb_write(xpdd, type, id, trans, io, nr_reqs);
212 KeWaitForSingleObject(&xpdd->req_info[id].WaitEvent, Executive, KernelMode, FALSE, NULL);
214 release_xenbus_id(xpdd, id);
216 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
218 return xpdd->req_info[id].Reply;
219 }
221 char *
222 XenBus_Read(
223 PVOID Context,
224 xenbus_transaction_t xbt,
225 const char *path,
226 char **value)
227 {
228 PXENPCI_DEVICE_DATA xpdd = Context;
229 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
230 struct xsd_sockmsg *rep;
231 char *res;
232 char *msg;
234 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
236 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
238 rep = xenbus_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
239 msg = errmsg(rep);
240 if (msg) {
241 *value = NULL;
242 return msg;
243 }
244 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
245 memcpy(res, rep + 1, rep->len);
246 res[rep->len] = 0;
247 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
248 *value = res;
250 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
252 return NULL;
253 }
255 char *
256 XenBus_Write(
257 PVOID Context,
258 xenbus_transaction_t xbt,
259 const char *path,
260 const char *value)
261 {
262 PXENPCI_DEVICE_DATA xpdd = Context;
263 struct write_req req[] = {
264 {path, (ULONG)strlen(path) + 1},
265 {value, (ULONG)strlen(value)},
266 };
267 struct xsd_sockmsg *rep;
268 char *msg;
270 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
272 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
274 rep = xenbus_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
275 msg = errmsg(rep);
276 if (msg)
277 return msg;
278 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
280 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
282 return NULL;
283 }
285 NTSTATUS
286 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
287 {
288 PHYSICAL_ADDRESS pa_xen_store_interface;
289 xen_ulong_t xen_store_mfn;
290 NTSTATUS status;
292 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
293 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
294 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
295 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
297 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Interrupt, xpdd);
299 xpdd->XenBus_ShuttingDown = FALSE;
300 KeMemoryBarrier();
302 status = PsCreateSystemThread(&xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, xpdd);
303 if (!NT_SUCCESS(status))
304 {
305 KdPrint((__DRIVER_NAME " Could not start read thread\n"));
306 return status;
307 }
309 status = PsCreateSystemThread(&xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
310 if (!NT_SUCCESS(status))
311 {
312 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
313 return status;
314 }
316 return STATUS_SUCCESS;
317 }
319 NTSTATUS
320 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
321 {
322 NTSTATUS status;
323 int i;
325 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
327 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
329 KeInitializeSpinLock(&xpdd->WatchLock);
331 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
332 {
333 xpdd->XenBus_WatchEntries[i].Active = 0;
334 xpdd->XenBus_WatchEntries[i].Running = 0;
335 KeInitializeEvent(&xpdd->XenBus_WatchEntries[i].CompleteEvent, SynchronizationEvent, FALSE);
336 }
338 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
339 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
340 KeInitializeEvent(&xpdd->xenbus_id_event, SynchronizationEvent, FALSE);
341 KeInitializeSpinLock(&xpdd->xenbus_id_lock);
342 xpdd->XenBus_ShuttingDown = FALSE;
344 status = XenBus_Connect(xpdd);
345 if (!NT_SUCCESS(status))
346 {
347 return status;
348 }
350 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
352 return STATUS_SUCCESS;
353 }
355 #if 0
356 NTSTATUS
357 XenBus_Stop(PXENPCI_DEVICE_DATA xpdd)
358 {
359 int i;
361 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
363 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
364 {
365 if (xpdd->XenBus_WatchEntries[i].Active)
366 XenBus_RemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path,
367 xpdd->XenBus_WatchEntries[i].ServiceRoutine,
368 xpdd->XenBus_WatchEntries[i].ServiceContext);
369 }
371 EvtChn_Unbind(xpdd, xpdd->xen_store_evtchn);
373 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
375 return STATUS_SUCCESS;
376 }
377 #endif
379 NTSTATUS
380 XenBus_StopThreads(PXENPCI_DEVICE_DATA xpdd)
381 {
382 //KWAIT_BLOCK WaitBlockArray[2];
383 PVOID WaitArray[2];
385 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
387 xpdd->XenBus_ShuttingDown = TRUE;
389 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
390 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
391 ObReferenceObjectByHandle(xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[0], NULL);
392 ObReferenceObjectByHandle(xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[1], NULL);
393 KeWaitForSingleObject(WaitArray[0], Executive, KernelMode, FALSE, NULL);
394 KeWaitForSingleObject(WaitArray[1], Executive, KernelMode, FALSE, NULL);
395 xpdd->XenBus_ShuttingDown = FALSE;
397 ZwClose(xpdd->XenBus_WatchThreadHandle);
398 ZwClose(xpdd->XenBus_ReadThreadHandle);
400 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
402 return STATUS_SUCCESS;
403 }
405 char *
406 XenBus_List(
407 PVOID Context,
408 xenbus_transaction_t xbt,
409 const char *pre,
410 char ***contents)
411 {
412 PXENPCI_DEVICE_DATA xpdd = Context;
413 struct xsd_sockmsg *reply, *repmsg;
414 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
415 ULONG nr_elems, x, i;
416 char **res;
417 char *msg;
419 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
421 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
423 repmsg = xenbus_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
424 msg = errmsg(repmsg);
425 if (msg)
426 {
427 *contents = NULL;
428 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
429 return msg;
430 }
431 reply = repmsg + 1;
432 for (x = nr_elems = 0; x < repmsg->len; x++)
433 {
434 nr_elems += (((char *)reply)[x] == 0);
435 }
436 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
437 XENPCI_POOL_TAG);
438 for (x = i = 0; i < nr_elems; i++)
439 {
440 int l = (int)strlen((char *)reply + x);
441 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
442 memcpy(res[i], (char *)reply + x, l + 1);
443 x += l + 1;
444 }
445 res[i] = NULL;
446 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
447 *contents = res;
448 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
449 return NULL;
450 }
452 static DDKAPI void
453 XenBus_ReadThreadProc(PVOID StartContext)
454 {
455 int NewWriteIndex;
456 struct xsd_sockmsg msg;
457 char *payload;
458 char *path, *token;
459 PXENPCI_DEVICE_DATA xpdd = StartContext;
461 for(;;)
462 {
463 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
464 if (xpdd->XenBus_ShuttingDown)
465 {
466 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
467 PsTerminateSystemThread(0);
468 }
469 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
470 {
471 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
472 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
473 {
474 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
475 break;
476 }
477 KeMemoryBarrier();
478 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
479 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
480 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
481 {
482 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
483 break;
484 }
486 if (msg.type != XS_WATCH_EVENT)
487 {
488 xpdd->req_info[msg.req_id].Reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
489 memcpy_from_ring(xpdd->xen_store_interface->rsp,
490 xpdd->req_info[msg.req_id].Reply,
491 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
492 msg.len + sizeof(msg));
493 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
494 KeSetEvent(&xpdd->req_info[msg.req_id].WaitEvent, IO_NO_INCREMENT, FALSE);
495 }
496 else // a watch: add to watch ring and signal watch thread
497 {
498 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
499 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
500 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
501 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
502 path = payload + sizeof(msg);
503 token = path + strlen(path) + 1;
505 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
506 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
507 {
508 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
509 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
510 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
511 }
512 else
513 {
514 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
515 // drop the message on the floor
516 continue;
517 }
519 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
520 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
521 }
522 }
523 }
524 }
526 static DDKAPI void
527 XenBus_WatchThreadProc(PVOID StartContext)
528 {
529 int index;
530 PXENBUS_WATCH_ENTRY entry;
531 PXENPCI_DEVICE_DATA xpdd = StartContext;
532 KIRQL OldIrql;
534 for(;;)
535 {
536 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
537 if (xpdd->XenBus_ShuttingDown)
538 {
539 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
540 PsTerminateSystemThread(0);
541 }
542 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
543 {
544 xpdd->XenBus_WatchRingReadIndex =
545 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
546 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
548 entry = &xpdd->XenBus_WatchEntries[index];
549 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
550 if (!entry->Active || !entry->ServiceRoutine)
551 {
552 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
553 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
554 continue;
555 }
556 if (entry->RemovePending)
557 {
558 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
559 KdPrint((__DRIVER_NAME " Not calling watch - remove is pending\n"));
560 continue;
561 }
562 entry->Running = 1;
563 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
564 entry->Count++;
565 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
566 entry->Running = 0;
567 KeSetEvent(&entry->CompleteEvent, IO_NO_INCREMENT, FALSE);
568 }
569 }
570 }
572 static char *
573 XenBus_SendAddWatch(
574 PVOID Context,
575 xenbus_transaction_t xbt,
576 const char *Path,
577 int slot)
578 {
579 PXENPCI_DEVICE_DATA xpdd = Context;
580 struct xsd_sockmsg *rep;
581 char *msg;
582 char Token[20];
583 struct write_req req[2];
585 req[0].data = Path;
586 req[0].len = (ULONG)strlen(Path) + 1;
588 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
589 req[1].data = Token;
590 req[1].len = (ULONG)strlen(Token) + 1;
592 rep = xenbus_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
593 msg = errmsg(rep);
594 if (!msg)
595 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
597 return msg;
598 }
600 /* called at PASSIVE_LEVEL */
601 NTSTATUS
602 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
603 {
604 NTSTATUS status;
605 int i;
607 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
609 status = XenBus_Connect(xpdd);
610 if (!NT_SUCCESS(status))
611 {
612 return status;
613 }
615 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
616 {
617 if (xpdd->XenBus_WatchEntries[i].Active)
618 {
619 KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
620 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
621 }
622 }
623 KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
625 return STATUS_SUCCESS;
626 }
628 char *
629 XenBus_AddWatch(
630 PVOID Context,
631 xenbus_transaction_t xbt,
632 const char *Path,
633 PXENBUS_WATCH_CALLBACK ServiceRoutine,
634 PVOID ServiceContext)
635 {
636 PXENPCI_DEVICE_DATA xpdd = Context;
637 char *msg;
638 int i;
639 PXENBUS_WATCH_ENTRY w_entry;
640 KIRQL OldIrql;
642 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
644 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
646 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
648 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
650 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
651 if (xpdd->XenBus_WatchEntries[i].Active == 0)
652 break;
654 if (i == MAX_WATCH_ENTRIES)
655 {
656 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
657 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
658 return NULL;
659 }
661 /* must init watchentry before starting watch */
663 w_entry = &xpdd->XenBus_WatchEntries[i];
664 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
665 w_entry->ServiceRoutine = ServiceRoutine;
666 w_entry->ServiceContext = ServiceContext;
667 w_entry->Count = 0;
668 w_entry->Active = 1;
670 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
672 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
674 if (msg)
675 {
676 xpdd->XenBus_WatchEntries[i].Active = 0;
677 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
678 return msg;
679 }
681 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
683 return NULL;
684 }
686 char *
687 XenBus_RemWatch(
688 PVOID Context,
689 xenbus_transaction_t xbt,
690 const char *Path,
691 PXENBUS_WATCH_CALLBACK ServiceRoutine,
692 PVOID ServiceContext)
693 {
694 PXENPCI_DEVICE_DATA xpdd = Context;
695 struct xsd_sockmsg *rep;
696 char *msg;
697 int i;
698 char Token[20];
699 struct write_req req[2];
700 KIRQL OldIrql;
702 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
703 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
705 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
707 // check that Path < 128 chars
709 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
710 if (xpdd->XenBus_WatchEntries[i].Active == 1
711 && strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) == 0
712 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
713 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
714 break;
715 }
717 if (i == MAX_WATCH_ENTRIES)
718 {
719 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
720 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
721 return NULL;
722 }
724 if (xpdd->XenBus_WatchEntries[i].RemovePending)
725 {
726 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
727 KdPrint((__DRIVER_NAME " Remove already pending - can't remove\n"));
728 return NULL;
729 }
730 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
732 while (xpdd->XenBus_WatchEntries[i].Running)
733 KeWaitForSingleObject(&xpdd->XenBus_WatchEntries[i].CompleteEvent, Executive, KernelMode, FALSE, NULL);
735 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
737 xpdd->XenBus_WatchEntries[i].Active = 0;
738 xpdd->XenBus_WatchEntries[i].RemovePending = 0;
739 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
741 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
743 req[0].data = Path;
744 req[0].len = (ULONG)strlen(Path) + 1;
746 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
747 req[1].data = Token;
748 req[1].len = (ULONG)strlen(Token) + 1;
750 rep = xenbus_msg_reply(xpdd, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
752 msg = errmsg(rep);
753 if (msg)
754 {
755 return msg;
756 }
758 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
760 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
762 return NULL;
763 }
766 char *
767 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
768 {
769 PXENPCI_DEVICE_DATA xpdd = Context;
770 /* xenstored becomes angry if you send a length 0 message, so just
771 shove a nul terminator on the end */
772 struct write_req req = { "", 1};
773 struct xsd_sockmsg *rep;
774 char *err;
776 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
777 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
779 rep = xenbus_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
780 err = errmsg(rep);
781 if (err)
782 return err;
783 *xbt = atoi((char *)(rep + 1));
784 //sscanf((char *)(rep + 1), "%u", xbt);
785 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
787 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
789 return NULL;
790 }
792 char *
793 XenBus_EndTransaction(
794 PVOID Context,
795 xenbus_transaction_t t,
796 int abort,
797 int *retry)
798 {
799 PXENPCI_DEVICE_DATA xpdd = Context;
800 struct xsd_sockmsg *rep;
801 struct write_req req;
802 char *err;
804 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
806 *retry = 0;
808 req.data = abort ? "F" : "T";
809 req.len = 2;
810 rep = xenbus_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
811 err = errmsg(rep);
812 if (err) {
813 if (!strcmp(err, "EAGAIN")) {
814 *retry = 1;
815 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
816 return NULL;
817 } else {
818 return err;
819 }
820 }
821 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
823 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
825 return NULL;
826 }
828 static DDKAPI BOOLEAN
829 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext)
830 {
831 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
833 UNREFERENCED_PARAMETER(Interrupt);
835 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
837 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
839 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
841 return TRUE;
842 }
844 char *
845 XenBus_Printf(
846 PVOID Context,
847 xenbus_transaction_t xbt,
848 const char *path,
849 const char *fmt,
850 ...)
851 {
852 PXENPCI_DEVICE_DATA xpdd = Context;
853 va_list ap;
854 char buf[512];
855 char *retval;
857 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
858 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
860 va_start(ap, fmt);
861 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
862 va_end(ap);
863 retval = XenBus_Write(xpdd, xbt, path, buf);
865 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
867 return retval;
868 }