win-pvdrivers

view xenpci/xenbus.c @ 607:c2aea3e060a7

Missed a line in cut&paste in previous checksum fix
author James Harper <james.harper@bendigoit.com.au>
date Sun Jul 05 21:06:26 2009 +1000 (2009-07-05)
parents e75bb8d68370
children f905eb3f0545
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() < DISPATCH_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 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, xpdd);
311 if (!NT_SUCCESS(status))
312 {
313 KdPrint((__DRIVER_NAME " Could not start read thread\n"));
314 return status;
315 }
317 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_ReadThread, NULL);
318 ZwClose(thread_handle);
319 if (!NT_SUCCESS(status))
320 {
321 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_ReadThread) = %08x\n", status));
322 return status;
323 }
325 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
326 if (!NT_SUCCESS(status))
327 {
328 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
329 return status;
330 }
331 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_WatchThread, NULL);
332 ZwClose(thread_handle);
333 if (!NT_SUCCESS(status))
334 {
335 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_WatchThread) = %08x\n", status));
336 }
338 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
340 return STATUS_SUCCESS;
341 }
343 char *
344 XenBus_SendRemWatch(
345 PVOID context,
346 xenbus_transaction_t xbt,
347 char *path,
348 int index)
349 {
350 struct xsd_sockmsg *rep;
351 char *msg;
352 char Token[20];
353 struct write_req req[2];
355 req[0].data = path;
356 req[0].len = (ULONG)strlen(path) + 1;
358 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
359 req[1].data = Token;
360 req[1].len = (ULONG)strlen(Token) + 1;
362 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
364 msg = errmsg(rep);
365 if (msg)
366 return msg;
368 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
370 return NULL;
371 }
373 NTSTATUS
374 XenBus_StopThreads(PXENPCI_DEVICE_DATA xpdd)
375 {
376 NTSTATUS status;
377 //KWAIT_BLOCK WaitBlockArray[2];
378 int i;
379 LARGE_INTEGER timeout;
381 FUNCTION_ENTER();
383 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
385 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
386 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
387 if (xpdd->XenBus_WatchEntries[i].Active)
388 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
389 }
391 xpdd->XenBus_ShuttingDown = TRUE;
392 KeMemoryBarrier();
394 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
395 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
397 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
398 while ((status = KeWaitForSingleObject(xpdd->XenBus_ReadThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
399 {
400 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
401 }
402 ObDereferenceObject(xpdd->XenBus_ReadThread);
403 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
404 while ((status = KeWaitForSingleObject(xpdd->XenBus_WatchThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
405 {
406 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
407 }
408 ObDereferenceObject(xpdd->XenBus_WatchThread);
410 xpdd->XenBus_ShuttingDown = FALSE;
412 FUNCTION_EXIT();
414 return STATUS_SUCCESS;
415 }
417 char *
418 XenBus_List(
419 PVOID Context,
420 xenbus_transaction_t xbt,
421 char *pre,
422 char ***contents)
423 {
424 PXENPCI_DEVICE_DATA xpdd = Context;
425 struct xsd_sockmsg *reply, *repmsg;
426 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
427 ULONG nr_elems, x, i;
428 char **res;
429 char *msg;
431 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
433 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
435 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
436 msg = errmsg(repmsg);
437 if (msg)
438 {
439 *contents = NULL;
440 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
441 return msg;
442 }
443 reply = repmsg + 1;
444 for (x = nr_elems = 0; x < repmsg->len; x++)
445 {
446 nr_elems += (((char *)reply)[x] == 0);
447 }
448 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
449 XENPCI_POOL_TAG);
450 for (x = i = 0; i < nr_elems; i++)
451 {
452 int l = (int)strlen((char *)reply + x);
453 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
454 memcpy(res[i], (char *)reply + x, l + 1);
455 x += l + 1;
456 }
457 res[i] = NULL;
458 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
459 *contents = res;
460 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
461 return NULL;
462 }
464 static DDKAPI void
465 XenBus_ReadThreadProc(PVOID StartContext)
466 {
467 int NewWriteIndex;
468 struct xsd_sockmsg msg;
469 char *payload;
470 char *path, *token;
471 PXENPCI_DEVICE_DATA xpdd = StartContext;
473 for(;;)
474 {
475 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
476 //KdPrint((__DRIVER_NAME " +++ thread woken\n"));
477 if (xpdd->XenBus_ShuttingDown)
478 {
479 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
480 PsTerminateSystemThread(0);
481 }
482 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
483 {
484 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xpdd->xen_store_interface->rsp_cons, xpdd->xen_store_interface->rsp_prod));
485 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
486 {
487 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
488 break;
489 }
490 KeMemoryBarrier();
491 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
492 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
493 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
494 {
495 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
496 break;
497 }
499 if (msg.type != XS_WATCH_EVENT)
500 {
501 xpdd->xb_reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
502 memcpy_from_ring(xpdd->xen_store_interface->rsp,
503 xpdd->xb_reply,
504 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
505 msg.len + sizeof(msg));
506 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
507 //KdPrint((__DRIVER_NAME " +++ Setting event\n"));
508 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
509 }
510 else // a watch: add to watch ring and signal watch thread
511 {
512 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
513 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
514 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
515 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
516 path = payload + sizeof(msg);
517 token = path + strlen(path) + 1;
519 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
520 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
521 {
522 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
523 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
524 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
525 }
526 else
527 {
528 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
529 // drop the message on the floor
530 continue;
531 }
533 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
534 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
535 }
536 }
537 }
538 }
540 static DDKAPI void
541 XenBus_WatchThreadProc(PVOID StartContext)
542 {
543 int index;
544 PXENBUS_WATCH_ENTRY entry;
545 PXENPCI_DEVICE_DATA xpdd = StartContext;
547 for(;;)
548 {
549 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
550 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
551 if (xpdd->XenBus_ShuttingDown)
552 {
553 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
554 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
555 PsTerminateSystemThread(0);
556 KdPrint((__DRIVER_NAME " WatchThreadProc still running... wtf?\n"));
557 }
558 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
559 {
560 //KdPrint((__DRIVER_NAME " +++ watch triggered\n"));
561 xpdd->XenBus_WatchRingReadIndex =
562 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
563 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
565 entry = &xpdd->XenBus_WatchEntries[index];
566 if (!entry->Active || !entry->ServiceRoutine)
567 {
568 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
569 continue;
570 }
571 entry->Count++;
572 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
573 }
574 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
575 }
576 }
578 /*
579 Called at PASSIVE_LEVEL
580 */
581 static char *
582 XenBus_SendAddWatch(
583 PVOID Context,
584 xenbus_transaction_t xbt,
585 char *Path,
586 int slot)
587 {
588 PXENPCI_DEVICE_DATA xpdd = Context;
589 struct xsd_sockmsg *rep;
590 char *msg;
591 char Token[20];
592 struct write_req req[2];
594 req[0].data = Path;
595 req[0].len = (ULONG)strlen(Path) + 1;
597 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
598 req[1].data = Token;
599 req[1].len = (ULONG)strlen(Token) + 1;
601 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
603 msg = errmsg(rep);
604 if (!msg)
605 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
607 return msg;
608 }
610 /* called at PASSIVE_LEVEL */
611 NTSTATUS
612 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
613 {
614 int i;
616 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
617 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
618 if (xpdd->XenBus_WatchEntries[i].Active)
619 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
620 }
622 // need to synchronise with readthread here too to ensure that it won't do anything silly
624 return STATUS_SUCCESS;
625 }
627 /* called at PASSIVE_LEVEL */
628 NTSTATUS
629 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
630 {
631 NTSTATUS status;
632 int i;
634 FUNCTION_ENTER();
636 status = XenBus_Connect(xpdd);
637 if (!NT_SUCCESS(status))
638 {
639 return status;
640 }
641 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
643 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
644 {
645 if (xpdd->XenBus_WatchEntries[i].Active)
646 {
647 //KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
648 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
649 }
650 }
651 FUNCTION_EXIT();
653 return STATUS_SUCCESS;
654 }
656 char *
657 XenBus_AddWatch(
658 PVOID Context,
659 xenbus_transaction_t xbt,
660 char *Path,
661 PXENBUS_WATCH_CALLBACK ServiceRoutine,
662 PVOID ServiceContext)
663 {
664 PXENPCI_DEVICE_DATA xpdd = Context;
665 char *msg;
666 int i;
667 PXENBUS_WATCH_ENTRY w_entry;
669 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
671 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
673 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
675 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
677 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
678 if (xpdd->XenBus_WatchEntries[i].Active == 0)
679 break;
681 if (i == MAX_WATCH_ENTRIES)
682 {
683 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
684 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
685 return NULL;
686 }
688 /* must init watchentry before starting watch */
690 w_entry = &xpdd->XenBus_WatchEntries[i];
691 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
692 w_entry->ServiceRoutine = ServiceRoutine;
693 w_entry->ServiceContext = ServiceContext;
694 w_entry->Count = 0;
695 w_entry->Active = 1;
697 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
699 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
701 if (msg)
702 {
703 xpdd->XenBus_WatchEntries[i].Active = 0;
704 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
705 return msg;
706 }
708 //KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
710 return NULL;
711 }
713 char *
714 XenBus_RemWatch(
715 PVOID Context,
716 xenbus_transaction_t xbt,
717 char *Path,
718 PXENBUS_WATCH_CALLBACK ServiceRoutine,
719 PVOID ServiceContext)
720 {
721 PXENPCI_DEVICE_DATA xpdd = Context;
722 char *msg;
723 int i;
725 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
726 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
728 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
730 // check that Path < 128 chars
732 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
733 {
734 if (xpdd->XenBus_WatchEntries[i].Active
735 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
736 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
737 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
738 {
739 KdPrint((__DRIVER_NAME " Match\n"));
740 break;
741 }
742 }
744 if (i == MAX_WATCH_ENTRIES)
745 {
746 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
747 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
748 return NULL;
749 }
751 xpdd->XenBus_WatchEntries[i].Active = 0;
752 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
754 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
756 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
758 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
760 return msg;
761 }
764 char *
765 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
766 {
767 PXENPCI_DEVICE_DATA xpdd = Context;
768 /* xenstored becomes angry if you send a length 0 message, so just
769 shove a nul terminator on the end */
770 struct write_req req = { "", 1};
771 struct xsd_sockmsg *rep;
772 char *err;
774 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
775 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
777 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
778 err = errmsg(rep);
779 if (err)
780 return err;
781 *xbt = atoi((char *)(rep + 1));
782 //sscanf((char *)(rep + 1), "%u", xbt);
783 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
785 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
787 return NULL;
788 }
790 char *
791 XenBus_EndTransaction(
792 PVOID Context,
793 xenbus_transaction_t t,
794 int abort,
795 int *retry)
796 {
797 PXENPCI_DEVICE_DATA xpdd = Context;
798 struct xsd_sockmsg *rep;
799 struct write_req req;
800 char *err;
802 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
804 *retry = 0;
806 req.data = abort ? "F" : "T";
807 req.len = 2;
808 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
809 err = errmsg(rep);
810 if (err) {
811 if (!strcmp(err, "EAGAIN")) {
812 *retry = 1;
813 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
814 return NULL;
815 } else {
816 return err;
817 }
818 }
819 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
821 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
823 return NULL;
824 }
826 char *
827 XenBus_Printf(
828 PVOID Context,
829 xenbus_transaction_t xbt,
830 char *path,
831 char *fmt,
832 ...)
833 {
834 PXENPCI_DEVICE_DATA xpdd = Context;
835 va_list ap;
836 char buf[512];
837 char *retval;
839 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
840 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
842 va_start(ap, fmt);
843 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
844 va_end(ap);
845 retval = XenBus_Write(xpdd, xbt, path, buf);
847 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
849 return retval;
850 }