win-pvdrivers

view xenpci/xenbus.c @ 464:4f1c7b79948b

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