win-pvdrivers

view xenpci/xenbus.c @ 529:6a2d1517e10c

big commit
Implemented TPR optimisation (inspired by amdvopt by Travis Betak)
Converted from Internal bus to PNPBus
Added some bus mapping routines to maybe support larger scsi buffers and ndis sg
author James Harper <james.harper@bendigoit.com.au>
date Fri Jan 16 22:44:19 2009 +1100 (2009-01-16)
parents 331f861accf0
children 1d39de3ab8d6
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 ExAcquireFastMutex(&xpdd->xb_request_mutex);
167 xb_write(xpdd, msg, sizeof(struct xsd_sockmsg) + msg->len);
168 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
169 reply = xpdd->xb_reply;
170 xpdd->xb_reply = NULL;
171 ExReleaseFastMutex(&xpdd->xb_request_mutex);
173 return reply;
174 }
176 /*
177 Called at PASSIVE_LEVEL
178 */
179 char *
180 XenBus_Read(
181 PVOID Context,
182 xenbus_transaction_t xbt,
183 char *path,
184 char **value)
185 {
186 PXENPCI_DEVICE_DATA xpdd = Context;
187 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
188 struct xsd_sockmsg *rep;
189 char *res;
190 char *msg;
192 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
194 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
196 rep = xenbus_format_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
197 msg = errmsg(rep);
198 if (msg) {
199 *value = NULL;
200 return msg;
201 }
202 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
203 memcpy(res, rep + 1, rep->len);
204 res[rep->len] = 0;
205 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
206 *value = res;
208 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
210 return NULL;
211 }
213 /*
214 Called at PASSIVE_LEVEL
215 */
216 char *
217 XenBus_Write(
218 PVOID Context,
219 xenbus_transaction_t xbt,
220 char *path,
221 char *value)
222 {
223 PXENPCI_DEVICE_DATA xpdd = Context;
224 struct write_req req[] = {
225 {path, (ULONG)strlen(path) + 1},
226 {value, (ULONG)strlen(value)},
227 };
228 struct xsd_sockmsg *rep;
229 char *msg;
231 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
233 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
235 rep = xenbus_format_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
236 msg = errmsg(rep);
237 if (msg)
238 return msg;
239 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
241 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
243 return NULL;
244 }
246 static VOID
247 XenBus_Dpc(PVOID ServiceContext)
248 {
249 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
251 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
253 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
255 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
257 return;
258 }
260 NTSTATUS
261 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
262 {
263 PHYSICAL_ADDRESS pa_xen_store_interface;
264 xen_ulong_t xen_store_mfn;
266 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
267 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
268 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
269 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
271 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
273 xpdd->XenBus_ShuttingDown = FALSE;
274 KeMemoryBarrier();
276 return STATUS_SUCCESS;
277 }
279 NTSTATUS
280 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
281 {
282 NTSTATUS status;
283 HANDLE thread_handle;
284 int i;
286 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
288 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
290 ExInitializeFastMutex(&xpdd->xb_request_mutex);
291 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
293 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
294 {
295 xpdd->XenBus_WatchEntries[i].Active = 0;
296 }
298 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
299 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
300 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
302 xpdd->XenBus_ShuttingDown = FALSE;
304 status = XenBus_Connect(xpdd);
305 if (!NT_SUCCESS(status))
306 {
307 return status;
308 }
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 }
316 KdPrint((__DRIVER_NAME " Started ReadThread\n"));
318 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_ReadThread, NULL);
319 ZwClose(thread_handle);
320 if (!NT_SUCCESS(status))
321 {
322 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_ReadThread) = %08x\n", status));
323 return status;
324 }
326 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
327 if (!NT_SUCCESS(status))
328 {
329 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
330 return status;
331 }
332 KdPrint((__DRIVER_NAME " Started WatchThread\n"));
333 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->XenBus_WatchThread, NULL);
334 ZwClose(thread_handle);
335 if (!NT_SUCCESS(status))
336 {
337 KdPrint((__DRIVER_NAME " ObReferenceObjectByHandle(XenBus_WatchThread) = %08x\n", status));
338 }
340 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
342 return STATUS_SUCCESS;
343 }
345 char *
346 XenBus_SendRemWatch(
347 PVOID context,
348 xenbus_transaction_t xbt,
349 char *path,
350 int index)
351 {
352 struct xsd_sockmsg *rep;
353 char *msg;
354 char Token[20];
355 struct write_req req[2];
357 req[0].data = path;
358 req[0].len = (ULONG)strlen(path) + 1;
360 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
361 req[1].data = Token;
362 req[1].len = (ULONG)strlen(Token) + 1;
364 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
366 msg = errmsg(rep);
367 if (msg)
368 return msg;
370 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
372 return NULL;
373 }
375 NTSTATUS
376 XenBus_StopThreads(PXENPCI_DEVICE_DATA xpdd)
377 {
378 NTSTATUS status;
379 //KWAIT_BLOCK WaitBlockArray[2];
380 int i;
381 LARGE_INTEGER timeout;
383 FUNCTION_ENTER();
385 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
387 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
388 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
389 if (xpdd->XenBus_WatchEntries[i].Active)
390 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
391 }
393 xpdd->XenBus_ShuttingDown = TRUE;
394 KeMemoryBarrier();
396 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, IO_NO_INCREMENT, FALSE);
397 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
399 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
400 while ((status = KeWaitForSingleObject(xpdd->XenBus_ReadThread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
401 {
402 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
403 }
404 ObDereferenceObject(xpdd->XenBus_ReadThread);
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 }
410 ObDereferenceObject(xpdd->XenBus_WatchThread);
412 xpdd->XenBus_ShuttingDown = FALSE;
414 FUNCTION_EXIT();
416 return STATUS_SUCCESS;
417 }
419 char *
420 XenBus_List(
421 PVOID Context,
422 xenbus_transaction_t xbt,
423 char *pre,
424 char ***contents)
425 {
426 PXENPCI_DEVICE_DATA xpdd = Context;
427 struct xsd_sockmsg *reply, *repmsg;
428 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
429 ULONG nr_elems, x, i;
430 char **res;
431 char *msg;
433 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
435 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
437 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
438 msg = errmsg(repmsg);
439 if (msg)
440 {
441 *contents = NULL;
442 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
443 return msg;
444 }
445 reply = repmsg + 1;
446 for (x = nr_elems = 0; x < repmsg->len; x++)
447 {
448 nr_elems += (((char *)reply)[x] == 0);
449 }
450 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
451 XENPCI_POOL_TAG);
452 for (x = i = 0; i < nr_elems; i++)
453 {
454 int l = (int)strlen((char *)reply + x);
455 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
456 memcpy(res[i], (char *)reply + x, l + 1);
457 x += l + 1;
458 }
459 res[i] = NULL;
460 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
461 *contents = res;
462 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
463 return NULL;
464 }
466 static DDKAPI void
467 XenBus_ReadThreadProc(PVOID StartContext)
468 {
469 int NewWriteIndex;
470 struct xsd_sockmsg msg;
471 char *payload;
472 char *path, *token;
473 PXENPCI_DEVICE_DATA xpdd = StartContext;
475 for(;;)
476 {
477 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
478 //Print((__DRIVER_NAME " +++ thread woken\n"));
479 if (xpdd->XenBus_ShuttingDown)
480 {
481 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
482 PsTerminateSystemThread(0);
483 }
484 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
485 {
486 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
487 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
488 {
489 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
490 break;
491 }
492 KeMemoryBarrier();
493 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
494 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
495 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
496 {
497 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
498 break;
499 }
501 if (msg.type != XS_WATCH_EVENT)
502 {
503 xpdd->xb_reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
504 memcpy_from_ring(xpdd->xen_store_interface->rsp,
505 xpdd->xb_reply,
506 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
507 msg.len + sizeof(msg));
508 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
509 //KdPrint((__DRIVER_NAME " +++ Setting event\n"));
510 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
511 }
512 else // a watch: add to watch ring and signal watch thread
513 {
514 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
515 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
516 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
517 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
518 path = payload + sizeof(msg);
519 token = path + strlen(path) + 1;
521 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
522 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
523 {
524 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
525 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
526 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
527 }
528 else
529 {
530 //KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
531 // drop the message on the floor
532 continue;
533 }
535 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
536 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, IO_NO_INCREMENT, FALSE);
537 }
538 }
539 }
540 }
542 static DDKAPI void
543 XenBus_WatchThreadProc(PVOID StartContext)
544 {
545 int index;
546 PXENBUS_WATCH_ENTRY entry;
547 PXENPCI_DEVICE_DATA xpdd = StartContext;
549 for(;;)
550 {
551 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
552 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
553 if (xpdd->XenBus_ShuttingDown)
554 {
555 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
556 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
557 PsTerminateSystemThread(0);
558 KdPrint((__DRIVER_NAME " WatchThreadProc still running... wtf?\n"));
559 }
560 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
561 {
562 xpdd->XenBus_WatchRingReadIndex =
563 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
564 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
566 entry = &xpdd->XenBus_WatchEntries[index];
567 if (!entry->Active || !entry->ServiceRoutine)
568 {
569 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
570 continue;
571 }
572 entry->Count++;
573 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
574 }
575 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
576 }
577 }
579 /*
580 Called at PASSIVE_LEVEL
581 */
582 static char *
583 XenBus_SendAddWatch(
584 PVOID Context,
585 xenbus_transaction_t xbt,
586 char *Path,
587 int slot)
588 {
589 PXENPCI_DEVICE_DATA xpdd = Context;
590 struct xsd_sockmsg *rep;
591 char *msg;
592 char Token[20];
593 struct write_req req[2];
595 req[0].data = Path;
596 req[0].len = (ULONG)strlen(Path) + 1;
598 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
599 req[1].data = Token;
600 req[1].len = (ULONG)strlen(Token) + 1;
602 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
604 msg = errmsg(rep);
605 if (!msg)
606 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
608 return msg;
609 }
611 /* called at PASSIVE_LEVEL */
612 NTSTATUS
613 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
614 {
615 int i;
617 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
618 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
619 if (xpdd->XenBus_WatchEntries[i].Active)
620 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
621 }
623 // need to synchronise with readthread here too to ensure that it won't do anything silly
625 return STATUS_SUCCESS;
626 }
628 /* called at PASSIVE_LEVEL */
629 NTSTATUS
630 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
631 {
632 NTSTATUS status;
633 int i;
635 FUNCTION_ENTER();
637 status = XenBus_Connect(xpdd);
638 if (!NT_SUCCESS(status))
639 {
640 return status;
641 }
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 0
735 if (xpdd->XenBus_WatchEntries[i].Active)
736 {
737 KdPrint((__DRIVER_NAME " (%d == 1) = %d\n", xpdd->XenBus_WatchEntries[i].Active, xpdd->XenBus_WatchEntries[i].Active == 1));
738 KdPrint((__DRIVER_NAME " strcmp(%s, %s) = %d\n", xpdd->XenBus_WatchEntries[i].Path, Path, strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)));
739 KdPrint((__DRIVER_NAME " (%p == %p) = %d\n", xpdd->XenBus_WatchEntries[i].ServiceRoutine, ServiceRoutine, xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine));
740 KdPrint((__DRIVER_NAME " (%p == %p) = %d\n", xpdd->XenBus_WatchEntries[i].ServiceContext, ServiceContext, xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext));
741 #endif
742 if (xpdd->XenBus_WatchEntries[i].Active == 1
743 && strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) == 0
744 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
745 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
746 {
747 KdPrint((__DRIVER_NAME " Match\n"));
748 break;
749 }
750 #if 0
751 }
752 #endif
753 }
755 if (i == MAX_WATCH_ENTRIES)
756 {
757 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
758 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
759 return NULL;
760 }
762 xpdd->XenBus_WatchEntries[i].Active = 0;
763 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
765 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
767 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
769 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
771 return msg;
772 }
775 char *
776 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
777 {
778 PXENPCI_DEVICE_DATA xpdd = Context;
779 /* xenstored becomes angry if you send a length 0 message, so just
780 shove a nul terminator on the end */
781 struct write_req req = { "", 1};
782 struct xsd_sockmsg *rep;
783 char *err;
785 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
786 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
788 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
789 err = errmsg(rep);
790 if (err)
791 return err;
792 *xbt = atoi((char *)(rep + 1));
793 //sscanf((char *)(rep + 1), "%u", xbt);
794 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
796 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
798 return NULL;
799 }
801 char *
802 XenBus_EndTransaction(
803 PVOID Context,
804 xenbus_transaction_t t,
805 int abort,
806 int *retry)
807 {
808 PXENPCI_DEVICE_DATA xpdd = Context;
809 struct xsd_sockmsg *rep;
810 struct write_req req;
811 char *err;
813 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
815 *retry = 0;
817 req.data = abort ? "F" : "T";
818 req.len = 2;
819 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
820 err = errmsg(rep);
821 if (err) {
822 if (!strcmp(err, "EAGAIN")) {
823 *retry = 1;
824 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
825 return NULL;
826 } else {
827 return err;
828 }
829 }
830 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
832 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
834 return NULL;
835 }
837 char *
838 XenBus_Printf(
839 PVOID Context,
840 xenbus_transaction_t xbt,
841 char *path,
842 char *fmt,
843 ...)
844 {
845 PXENPCI_DEVICE_DATA xpdd = Context;
846 va_list ap;
847 char buf[512];
848 char *retval;
850 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
851 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
853 va_start(ap, fmt);
854 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
855 va_end(ap);
856 retval = XenBus_Write(xpdd, xbt, path, buf);
858 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
860 return retval;
861 }