win-pvdrivers

view xenpci/xenbus.c @ 622:f905eb3f0545

Shut down threads properly on hibernate.
Added some debug to try and find where the hang happens when the verifier is enabled
Added the suspend event channel to allow triggering a suspend much earlier
author James Harper <james.harper@bendigoit.com.au>
date Wed Aug 05 19:09:55 2009 +1000 (2009-08-05)
parents e75bb8d68370
children 0b55299418ce
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 <stdlib.h>
23 #pragma warning( disable : 4204 )
24 #pragma warning( disable : 4221 )
26 struct write_req {
27 void *data;
28 unsigned len;
29 };
31 static DDKAPI void
32 XenBus_ReadThreadProc(PVOID StartContext);
33 static DDKAPI void
34 XenBus_WatchThreadProc(PVOID StartContext);
36 // This routine free's the rep structure if there was an error!!!
37 static char *errmsg(struct xsd_sockmsg *rep)
38 {
39 char *res;
41 if (!rep) {
42 char msg[] = "No reply";
43 size_t len = strlen(msg) + 1;
44 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
45 }
46 if (rep->type != XS_ERROR)
47 return NULL;
48 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
49 memcpy(res, rep + 1, rep->len);
50 res[rep->len] = 0;
51 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
52 return res;
53 }
55 static void memcpy_from_ring(void *Ring,
56 void *Dest,
57 int off,
58 int len)
59 {
60 int c1, c2;
61 char *ring = Ring;
62 char *dest = Dest;
63 c1 = min(len, XENSTORE_RING_SIZE - off);
64 c2 = len - c1;
65 memcpy(dest, ring + off, c1);
66 memcpy(dest + c1, ring, c2);
67 }
69 /* called with xenbus_mutex held */
70 static void xb_write(
71 PXENPCI_DEVICE_DATA xpdd,
72 PVOID data,
73 ULONG len
74 )
75 {
76 XENSTORE_RING_IDX prod;
77 ULONG copy_len;
78 PUCHAR ptr;
79 ULONG remaining;
81 //FUNCTION_ENTER();
82 //KdPrint((__DRIVER_NAME " len = %d\n", len));
84 ASSERT(len <= XENSTORE_RING_SIZE);
85 /* Wait for the ring to drain to the point where we can send the
86 message. */
87 prod = xpdd->xen_store_interface->req_prod;
89 while (prod + len - xpdd->xen_store_interface->req_cons > XENSTORE_RING_SIZE)
90 {
91 /* Wait for there to be space on the ring */
92 /* not sure if I can wait here like this... */
93 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
94 prod = xpdd->xen_store_interface->req_prod;
95 }
97 /* We're now guaranteed to be able to send the message without
98 overflowing the ring. Do so. */
100 ptr = data;
101 remaining = len;
102 while (remaining)
103 {
104 copy_len = min(remaining, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
105 //KdPrint((__DRIVER_NAME " copy_len = %d\n", copy_len));
106 memcpy((PUCHAR)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), ptr, copy_len);
107 prod += (XENSTORE_RING_IDX)copy_len;
108 ptr += copy_len;
109 remaining -= copy_len;
110 }
111 /* Remote must see entire message before updating indexes */
112 KeMemoryBarrier();
113 xpdd->xen_store_interface->req_prod = prod;
114 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn);
116 //FUNCTION_EXIT();
117 }
119 /* takes and releases xb_request_mutex */
120 static struct xsd_sockmsg *
121 xenbus_format_msg_reply(
122 PXENPCI_DEVICE_DATA xpdd,
123 int type,
124 xenbus_transaction_t trans_id,
125 struct write_req *req,
126 int nr_reqs)
127 {
128 struct xsd_sockmsg msg;
129 struct xsd_sockmsg *reply;
130 int i;
132 //FUNCTION_ENTER();
134 msg.type = type;
135 msg.req_id = 0;
136 msg.tx_id = trans_id;
137 msg.len = 0;
138 for (i = 0; i < nr_reqs; i++)
139 msg.len += req[i].len;
141 ExAcquireFastMutex(&xpdd->xb_request_mutex);
142 xb_write(xpdd, &msg, sizeof(msg));
143 for (i = 0; i < nr_reqs; i++)
144 xb_write(xpdd, req[i].data, req[i].len);
146 //KdPrint((__DRIVER_NAME " waiting...\n"));
147 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
148 //KdPrint((__DRIVER_NAME " ...done waiting\n"));
149 reply = xpdd->xb_reply;
150 xpdd->xb_reply = NULL;
151 ExReleaseFastMutex(&xpdd->xb_request_mutex);
153 //FUNCTION_EXIT();
155 return reply;
156 }
158 /* takes and releases xb_request_mutex */
159 struct xsd_sockmsg *
160 XenBus_Raw(
161 PXENPCI_DEVICE_DATA xpdd,
162 struct xsd_sockmsg *msg)
163 {
164 struct xsd_sockmsg *reply;
166 FUNCTION_ENTER();
168 ExAcquireFastMutex(&xpdd->xb_request_mutex);
169 xb_write(xpdd, msg, sizeof(struct xsd_sockmsg) + msg->len);
170 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
171 reply = xpdd->xb_reply;
172 xpdd->xb_reply = NULL;
173 ExReleaseFastMutex(&xpdd->xb_request_mutex);
175 FUNCTION_EXIT();
177 return reply;
178 }
180 /*
181 Called at PASSIVE_LEVEL
182 */
183 char *
184 XenBus_Read(
185 PVOID Context,
186 xenbus_transaction_t xbt,
187 char *path,
188 char **value)
189 {
190 PXENPCI_DEVICE_DATA xpdd = Context;
191 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
192 struct xsd_sockmsg *rep;
193 char *res;
194 char *msg;
196 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
198 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
200 rep = xenbus_format_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
201 msg = errmsg(rep);
202 if (msg) {
203 *value = NULL;
204 return msg;
205 }
206 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
207 memcpy(res, rep + 1, rep->len);
208 res[rep->len] = 0;
209 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
210 *value = res;
212 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
214 return NULL;
215 }
217 /*
218 Called at PASSIVE_LEVEL
219 */
220 char *
221 XenBus_Write(
222 PVOID Context,
223 xenbus_transaction_t xbt,
224 char *path,
225 char *value)
226 {
227 PXENPCI_DEVICE_DATA xpdd = Context;
228 struct write_req req[] = {
229 {path, (ULONG)strlen(path) + 1},
230 {value, (ULONG)strlen(value)},
231 };
232 struct xsd_sockmsg *rep;
233 char *msg;
235 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
237 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
239 rep = xenbus_format_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
240 msg = errmsg(rep);
241 if (msg)
242 return msg;
243 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
245 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
247 return NULL;
248 }
250 static VOID
251 XenBus_Dpc(PVOID ServiceContext)
252 {
253 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
255 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
257 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
259 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
261 return;
262 }
264 NTSTATUS
265 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
266 {
267 PHYSICAL_ADDRESS pa_xen_store_interface;
268 xen_ulong_t xen_store_mfn;
270 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
271 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
272 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
273 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
275 KeMemoryBarrier();
277 return STATUS_SUCCESS;
278 }
280 NTSTATUS
281 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
282 {
283 NTSTATUS status;
284 HANDLE thread_handle;
285 int i;
287 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
289 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
291 ExInitializeFastMutex(&xpdd->xb_request_mutex);
292 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
294 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
295 {
296 xpdd->XenBus_WatchEntries[i].Active = 0;
297 }
299 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
300 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
301 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
303 status = XenBus_Connect(xpdd);
304 if (!NT_SUCCESS(status))
305 {
306 return status;
307 }
308 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
310 KdPrint((__DRIVER_NAME " A\n"));
311 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, xpdd);
312 if (!NT_SUCCESS(status))
313 {
314 KdPrint((__DRIVER_NAME " Could not start read thread\n"));
315 return status;
316 }
317 KdPrint((__DRIVER_NAME " B\n"));
318 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_ReadThread, NULL);
319 KdPrint((__DRIVER_NAME " C\n"));
320 ZwClose(thread_handle);
322 KdPrint((__DRIVER_NAME " D\n"));
323 if (!NT_SUCCESS(status))
324 {
325 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_ReadThread) = %08x\n", status));
326 return status;
327 }
328 KdPrint((__DRIVER_NAME " E\n"));
330 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
331 KdPrint((__DRIVER_NAME " F\n"));
332 if (!NT_SUCCESS(status))
333 {
334 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
335 return status;
336 }
337 KdPrint((__DRIVER_NAME " G\n"));
338 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_WatchThread, NULL);
339 KdPrint((__DRIVER_NAME " H\n"));
340 ZwClose(thread_handle);
341 KdPrint((__DRIVER_NAME " I\n"));
342 if (!NT_SUCCESS(status))
343 {
344 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_WatchThread) = %08x\n", status));
345 }
347 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
349 return STATUS_SUCCESS;
350 }
352 char *
353 XenBus_SendRemWatch(
354 PVOID context,
355 xenbus_transaction_t xbt,
356 char *path,
357 int index)
358 {
359 struct xsd_sockmsg *rep;
360 char *msg;
361 char Token[20];
362 struct write_req req[2];
364 req[0].data = path;
365 req[0].len = (ULONG)strlen(path) + 1;
367 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
368 req[1].data = Token;
369 req[1].len = (ULONG)strlen(Token) + 1;
371 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
373 msg = errmsg(rep);
374 if (msg)
375 return msg;
377 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
379 return NULL;
380 }
382 NTSTATUS
383 XenBus_Halt(PXENPCI_DEVICE_DATA xpdd)
384 {
385 NTSTATUS status;
386 int i;
387 LARGE_INTEGER timeout;
389 FUNCTION_ENTER();
391 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
393 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
394 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
395 if (xpdd->XenBus_WatchEntries[i].Active)
396 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
397 }
399 xpdd->XenBus_ShuttingDown = TRUE;
400 KeMemoryBarrier();
402 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
403 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
405 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
406 while ((status = KeWaitForSingleObject(xpdd->XenBus_WatchThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
407 {
408 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
409 KdPrint((__DRIVER_NAME " Waiting for XenBus_WatchThread to stop\n"));
410 }
411 ObDereferenceObject(xpdd->XenBus_WatchThread);
413 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
414 while ((status = KeWaitForSingleObject(xpdd->XenBus_ReadThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
415 {
416 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
417 KdPrint((__DRIVER_NAME " Waiting for XenBus_ReadThread to stop\n"));
418 }
419 ObDereferenceObject(xpdd->XenBus_ReadThread);
421 xpdd->XenBus_ShuttingDown = FALSE;
423 FUNCTION_EXIT();
425 return STATUS_SUCCESS;
426 }
428 char *
429 XenBus_List(
430 PVOID Context,
431 xenbus_transaction_t xbt,
432 char *pre,
433 char ***contents)
434 {
435 PXENPCI_DEVICE_DATA xpdd = Context;
436 struct xsd_sockmsg *reply, *repmsg;
437 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
438 ULONG nr_elems, x, i;
439 char **res;
440 char *msg;
442 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
444 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
446 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
447 msg = errmsg(repmsg);
448 if (msg)
449 {
450 *contents = NULL;
451 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
452 return msg;
453 }
454 reply = repmsg + 1;
455 for (x = nr_elems = 0; x < repmsg->len; x++)
456 {
457 nr_elems += (((char *)reply)[x] == 0);
458 }
459 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
460 XENPCI_POOL_TAG);
461 for (x = i = 0; i < nr_elems; i++)
462 {
463 int l = (int)strlen((char *)reply + x);
464 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
465 memcpy(res[i], (char *)reply + x, l + 1);
466 x += l + 1;
467 }
468 res[i] = NULL;
469 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
470 *contents = res;
471 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
472 return NULL;
473 }
475 static DDKAPI void
476 XenBus_ReadThreadProc(PVOID StartContext)
477 {
478 int NewWriteIndex;
479 struct xsd_sockmsg msg;
480 char *payload;
481 char *path, *token;
482 PXENPCI_DEVICE_DATA xpdd = StartContext;
484 FUNCTION_ENTER();
485 for(;;)
486 {
487 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
488 //KdPrint((__DRIVER_NAME " +++ thread woken\n"));
489 if (xpdd->XenBus_ShuttingDown)
490 {
491 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
492 PsTerminateSystemThread(0);
493 }
494 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
495 {
496 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xpdd->xen_store_interface->rsp_cons, xpdd->xen_store_interface->rsp_prod));
497 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
498 {
499 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
500 break;
501 }
502 KeMemoryBarrier();
503 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
504 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
505 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
506 {
507 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
508 break;
509 }
511 if (msg.type != XS_WATCH_EVENT)
512 {
513 xpdd->xb_reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
514 memcpy_from_ring(xpdd->xen_store_interface->rsp,
515 xpdd->xb_reply,
516 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
517 msg.len + sizeof(msg));
518 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
519 //KdPrint((__DRIVER_NAME " +++ Setting event\n"));
520 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
521 }
522 else // a watch: add to watch ring and signal watch thread
523 {
524 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
525 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
526 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
527 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
528 path = payload + sizeof(msg);
529 token = path + strlen(path) + 1;
531 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
532 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
533 {
534 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
535 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
536 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
537 }
538 else
539 {
540 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
541 // drop the message on the floor
542 continue;
543 }
545 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
546 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
547 }
548 }
549 }
550 FUNCTION_EXIT();
551 }
553 static DDKAPI void
554 XenBus_WatchThreadProc(PVOID StartContext)
555 {
556 int index;
557 PXENBUS_WATCH_ENTRY entry;
558 PXENPCI_DEVICE_DATA xpdd = StartContext;
560 for(;;)
561 {
562 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
563 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
564 if (xpdd->XenBus_ShuttingDown)
565 {
566 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
567 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
568 PsTerminateSystemThread(0);
569 KdPrint((__DRIVER_NAME " WatchThreadProc still running... wtf?\n"));
570 }
571 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
572 {
573 //KdPrint((__DRIVER_NAME " +++ watch triggered\n"));
574 xpdd->XenBus_WatchRingReadIndex =
575 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
576 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
578 entry = &xpdd->XenBus_WatchEntries[index];
579 if (!entry->Active || !entry->ServiceRoutine)
580 {
581 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
582 continue;
583 }
584 entry->Count++;
585 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
586 }
587 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
588 }
589 }
591 /*
592 Called at PASSIVE_LEVEL
593 */
594 static char *
595 XenBus_SendAddWatch(
596 PVOID Context,
597 xenbus_transaction_t xbt,
598 char *Path,
599 int slot)
600 {
601 PXENPCI_DEVICE_DATA xpdd = Context;
602 struct xsd_sockmsg *rep;
603 char *msg;
604 char Token[20];
605 struct write_req req[2];
607 req[0].data = Path;
608 req[0].len = (ULONG)strlen(Path) + 1;
610 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
611 req[1].data = Token;
612 req[1].len = (ULONG)strlen(Token) + 1;
614 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
616 msg = errmsg(rep);
617 if (!msg)
618 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
620 return msg;
621 }
623 /* called at PASSIVE_LEVEL */
624 NTSTATUS
625 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
626 {
627 int i;
629 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
630 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
631 if (xpdd->XenBus_WatchEntries[i].Active)
632 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
633 }
635 // need to synchronise with readthread here too to ensure that it won't do anything silly
636 MmUnmapIoSpace(xpdd->xen_store_interface, PAGE_SIZE);
638 return STATUS_SUCCESS;
639 }
641 /* called at PASSIVE_LEVEL */
642 NTSTATUS
643 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
644 {
645 NTSTATUS status;
646 int i;
648 FUNCTION_ENTER();
650 status = XenBus_Connect(xpdd);
651 if (!NT_SUCCESS(status))
652 {
653 return status;
654 }
655 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
657 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
658 {
659 if (xpdd->XenBus_WatchEntries[i].Active)
660 {
661 //KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
662 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
663 }
664 }
665 FUNCTION_EXIT();
667 return STATUS_SUCCESS;
668 }
670 char *
671 XenBus_AddWatch(
672 PVOID Context,
673 xenbus_transaction_t xbt,
674 char *Path,
675 PXENBUS_WATCH_CALLBACK ServiceRoutine,
676 PVOID ServiceContext)
677 {
678 PXENPCI_DEVICE_DATA xpdd = Context;
679 char *msg;
680 int i;
681 PXENBUS_WATCH_ENTRY w_entry;
683 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
685 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
687 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
689 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
691 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
692 if (xpdd->XenBus_WatchEntries[i].Active == 0)
693 break;
695 if (i == MAX_WATCH_ENTRIES)
696 {
697 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
698 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
699 return NULL;
700 }
702 /* must init watchentry before starting watch */
704 w_entry = &xpdd->XenBus_WatchEntries[i];
705 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
706 w_entry->ServiceRoutine = ServiceRoutine;
707 w_entry->ServiceContext = ServiceContext;
708 w_entry->Count = 0;
709 w_entry->Active = 1;
711 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
713 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
715 if (msg)
716 {
717 xpdd->XenBus_WatchEntries[i].Active = 0;
718 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
719 return msg;
720 }
722 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
724 return NULL;
725 }
727 char *
728 XenBus_RemWatch(
729 PVOID Context,
730 xenbus_transaction_t xbt,
731 char *Path,
732 PXENBUS_WATCH_CALLBACK ServiceRoutine,
733 PVOID ServiceContext)
734 {
735 PXENPCI_DEVICE_DATA xpdd = Context;
736 char *msg;
737 int i;
739 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
740 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
742 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
744 // check that Path < 128 chars
746 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
747 {
748 if (xpdd->XenBus_WatchEntries[i].Active
749 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
750 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
751 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
752 {
753 KdPrint((__DRIVER_NAME " Match\n"));
754 break;
755 }
756 }
758 if (i == MAX_WATCH_ENTRIES)
759 {
760 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
761 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
762 return NULL;
763 }
765 xpdd->XenBus_WatchEntries[i].Active = 0;
766 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
768 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
770 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
772 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
774 return msg;
775 }
778 char *
779 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
780 {
781 PXENPCI_DEVICE_DATA xpdd = Context;
782 /* xenstored becomes angry if you send a length 0 message, so just
783 shove a nul terminator on the end */
784 struct write_req req = { "", 1};
785 struct xsd_sockmsg *rep;
786 char *err;
788 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
789 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
791 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
792 err = errmsg(rep);
793 if (err)
794 return err;
795 *xbt = atoi((char *)(rep + 1));
796 //sscanf((char *)(rep + 1), "%u", xbt);
797 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
799 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
801 return NULL;
802 }
804 char *
805 XenBus_EndTransaction(
806 PVOID Context,
807 xenbus_transaction_t t,
808 int abort,
809 int *retry)
810 {
811 PXENPCI_DEVICE_DATA xpdd = Context;
812 struct xsd_sockmsg *rep;
813 struct write_req req;
814 char *err;
816 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
818 *retry = 0;
820 req.data = abort ? "F" : "T";
821 req.len = 2;
822 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
823 err = errmsg(rep);
824 if (err) {
825 if (!strcmp(err, "EAGAIN")) {
826 *retry = 1;
827 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
828 return NULL;
829 } else {
830 return err;
831 }
832 }
833 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
835 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
837 return NULL;
838 }
840 char *
841 XenBus_Printf(
842 PVOID Context,
843 xenbus_transaction_t xbt,
844 char *path,
845 char *fmt,
846 ...)
847 {
848 PXENPCI_DEVICE_DATA xpdd = Context;
849 va_list ap;
850 char buf[512];
851 char *retval;
853 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
854 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
856 va_start(ap, fmt);
857 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
858 va_end(ap);
859 retval = XenBus_Write(xpdd, xbt, path, buf);
861 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
863 return retval;
864 }