win-pvdrivers

view xenpci/xenbus.c @ 271:da9b1e17fbc0

xennet now working. working on graceful shutdown
author James Harper <james.harper@bendigoit.com.au>
date Thu May 15 00:25:25 2008 +1000 (2008-05-15)
parents f157f82e0293
children 909b775a891f
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 void
33 XenBus_ReadThreadProc(PVOID StartContext);
34 static void
35 XenBus_WatchThreadProc(PVOID StartContext);
36 static BOOLEAN
37 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext);
39 static int allocate_xenbus_id(PXENPCI_DEVICE_DATA xpdd)
40 {
41 static int probe;
42 int o_probe;
44 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
46 for (;;)
47 {
48 // spin_lock(&req_lock);
49 if (xpdd->nr_live_reqs < NR_XB_REQS)
50 break;
51 // spin_unlock(&req_lock);
52 // wait_event(req_wq, (nr_live_reqs < NR_REQS));
53 }
55 o_probe = probe;
57 for (;;)
58 {
59 if (!xpdd->req_info[o_probe].In_Use)
60 break;
61 o_probe = (o_probe + 1) % NR_XB_REQS;
62 // BUG_ON(o_probe == probe);
63 }
64 xpdd->nr_live_reqs++;
65 xpdd->req_info[o_probe].In_Use = 1;
66 probe = (o_probe + 1) % NR_XB_REQS;
67 //spin_unlock(&req_lock);
68 //init_waitqueue_head(&req_info[o_probe].waitq);
69 KeInitializeEvent(&xpdd->req_info[o_probe].WaitEvent, SynchronizationEvent, FALSE);
71 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
73 return o_probe;
74 }
76 static void release_xenbus_id(PXENPCI_DEVICE_DATA xpdd, int id)
77 {
78 // BUG_ON(!req_info[id].in_use);
79 // spin_lock(&req_lock);
80 xpdd->req_info[id].In_Use = 0;
81 xpdd->nr_live_reqs--;
82 xpdd->req_info[id].In_Use = 0;
83 // if (nr_live_reqs == NR_REQS - 1)
84 // wake_up(&req_wq);
85 // spin_unlock(&req_lock);
86 }
88 // This routine free's the rep structure if there was an error!!!
89 static char *errmsg(struct xsd_sockmsg *rep)
90 {
91 char *res;
93 if (!rep) {
94 char msg[] = "No reply";
95 size_t len = strlen(msg) + 1;
96 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
97 }
98 if (rep->type != XS_ERROR)
99 return NULL;
100 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
101 memcpy(res, rep + 1, rep->len);
102 res[rep->len] = 0;
103 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
104 return res;
105 }
107 static void memcpy_from_ring(const void *Ring,
108 void *Dest,
109 int off,
110 int len)
111 {
112 int c1, c2;
113 const char *ring = Ring;
114 char *dest = Dest;
115 c1 = min(len, XENSTORE_RING_SIZE - off);
116 c2 = len - c1;
117 memcpy(dest, ring + off, c1);
118 memcpy(dest + c1, ring, c2);
119 }
121 static void xb_write(
122 PXENPCI_DEVICE_DATA xpdd,
123 int type,
124 int req_id,
125 xenbus_transaction_t trans_id,
126 const struct write_req *req,
127 int nr_reqs)
128 {
129 XENSTORE_RING_IDX prod;
130 int r;
131 size_t len = 0;
132 const struct write_req *cur_req;
133 size_t req_off;
134 size_t total_off;
135 size_t this_chunk;
136 struct xsd_sockmsg m = {type, req_id, trans_id };
137 struct write_req header_req = { &m, sizeof(m) };
139 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
141 for (r = 0; r < nr_reqs; r++)
142 len += (size_t)req[r].len;
143 m.len = (ULONG)len;
144 len += sizeof(m);
146 cur_req = &header_req;
148 // BUG_ON(len > XENSTORE_RING_SIZE);
149 /* Wait for the ring to drain to the point where we can send the
150 message. */
151 prod = xpdd->xen_store_interface->req_prod;
153 //KdPrint((__DRIVER_NAME " prod = %08x\n", prod));
155 if (prod + len - xpdd->xen_store_interface->req_cons > XENSTORE_RING_SIZE)
156 {
157 /* Wait for there to be space on the ring */
158 //KdPrint((__DRIVER_NAME " prod %d, len %d, cons %d, size %d; waiting.\n", prod, len, xen_store_interface->req_cons, XENSTORE_RING_SIZE));
159 // wait_event(xb_waitq, xen_store_interface->req_prod + len - xen_store_interface->req_cons <= XENSTORE_RING_SIZE);
160 //KdPrint((__DRIVER_NAME " Back from wait.\n"));
161 prod = xpdd->xen_store_interface->req_prod;
162 }
164 /* We're now guaranteed to be able to send the message without
165 overflowing the ring. Do so. */
167 total_off = 0;
168 req_off = 0;
170 while (total_off < len)
171 {
172 this_chunk = min(cur_req->len - req_off,XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
173 memcpy((char *)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), (char *)cur_req->data + req_off, this_chunk);
174 prod += (XENSTORE_RING_IDX)this_chunk;
175 req_off += this_chunk;
176 total_off += this_chunk;
177 if (req_off == cur_req->len)
178 {
179 req_off = 0;
180 if (cur_req == &header_req)
181 cur_req = req;
182 else
183 cur_req++;
184 }
185 }
187 //KdPrint((__DRIVER_NAME " Complete main loop of xb_write.\n"));
189 // BUG_ON(req_off != 0);
190 // BUG_ON(total_off != len);
191 // BUG_ON(prod > xen_store_interface->req_cons + XENSTORE_RING_SIZE);
193 /* Remote must see entire message before updating indexes */
194 //_WriteBarrier();
195 KeMemoryBarrier();
197 xpdd->xen_store_interface->req_prod += (XENSTORE_RING_IDX)len;
199 //KdPrint((__DRIVER_NAME " prod = %08x\n", xen_store_interface->req_prod));
201 /* Send evtchn to notify remote */
202 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn);
204 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
205 }
207 static struct xsd_sockmsg *
208 xenbus_msg_reply(
209 PXENPCI_DEVICE_DATA xpdd,
210 int type,
211 xenbus_transaction_t trans,
212 struct write_req *io,
213 int nr_reqs)
214 {
215 int id;
217 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
219 id = allocate_xenbus_id(xpdd);
221 xb_write(xpdd, type, id, trans, io, nr_reqs);
223 KeWaitForSingleObject(&xpdd->req_info[id].WaitEvent, Executive, KernelMode, FALSE, NULL);
225 release_xenbus_id(xpdd, id);
227 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
229 return xpdd->req_info[id].Reply;
230 }
232 char *
233 XenBus_Read(
234 PVOID Context,
235 xenbus_transaction_t xbt,
236 const char *path,
237 char **value)
238 {
239 PXENPCI_DEVICE_DATA xpdd = Context;
240 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
241 struct xsd_sockmsg *rep;
242 char *res;
243 char *msg;
245 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
247 rep = xenbus_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
248 msg = errmsg(rep);
249 if (msg) {
250 *value = NULL;
251 return msg;
252 }
253 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
254 memcpy(res, rep + 1, rep->len);
255 res[rep->len] = 0;
256 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
257 *value = res;
259 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
261 return NULL;
262 }
264 char *
265 XenBus_Write(
266 PVOID Context,
267 xenbus_transaction_t xbt,
268 const char *path,
269 const char *value)
270 {
271 PXENPCI_DEVICE_DATA xpdd = Context;
272 struct write_req req[] = {
273 {path, (ULONG)strlen(path) + 1},
274 {value, (ULONG)strlen(value) + 1},
275 // {path, (ULONG)strlen(path)},
276 // {value, (ULONG)strlen(value)},
277 };
278 struct xsd_sockmsg *rep;
279 char *msg;
281 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
283 rep = xenbus_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
284 msg = errmsg(rep);
285 if (msg)
286 return msg;
287 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
289 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
291 return NULL;
292 }
294 NTSTATUS
295 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
296 {
297 PHYSICAL_ADDRESS pa_xen_store_interface;
298 xen_ulong_t xen_store_mfn;
299 NTSTATUS Status;
300 int i;
302 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
304 KeInitializeSpinLock(&xpdd->WatchLock);
306 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
308 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
309 pa_xen_store_interface.QuadPart = xen_store_mfn << PAGE_SHIFT;
310 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
312 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
313 {
314 xpdd->XenBus_WatchEntries[i].Active = 0;
315 xpdd->XenBus_WatchEntries[i].Running = 0;
316 KeInitializeEvent(&xpdd->XenBus_WatchEntries[i].CompleteEvent, SynchronizationEvent, FALSE);
317 }
319 KeInitializeEvent(&xpdd->XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
320 KeInitializeEvent(&xpdd->XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
321 xpdd->XenBus_ShuttingDown = FALSE;
323 Status = PsCreateSystemThread(&xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, xpdd);
324 if (!NT_SUCCESS(Status))
325 {
326 KdPrint((__DRIVER_NAME " Could not start read thread\n"));
327 return STATUS_UNSUCCESSFUL;
328 }
330 Status = PsCreateSystemThread(&xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, xpdd);
331 if (!NT_SUCCESS(Status))
332 {
333 KdPrint((__DRIVER_NAME " Could not start watch thread\n"));
334 return STATUS_UNSUCCESSFUL;
335 }
337 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Interrupt, xpdd);
339 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
341 return STATUS_SUCCESS;
342 }
344 NTSTATUS
345 XenBus_Stop(PXENPCI_DEVICE_DATA xpdd)
346 {
347 int i;
349 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
351 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
352 {
353 if (xpdd->XenBus_WatchEntries[i].Active)
354 XenBus_RemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path,
355 xpdd->XenBus_WatchEntries[i].ServiceRoutine,
356 xpdd->XenBus_WatchEntries[i].ServiceContext);
357 }
359 EvtChn_Unbind(xpdd, xpdd->xen_store_evtchn);
361 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
363 return STATUS_SUCCESS;
364 }
366 NTSTATUS
367 XenBus_Close(PXENPCI_DEVICE_DATA xpdd)
368 {
369 //KWAIT_BLOCK WaitBlockArray[2];
370 PVOID WaitArray[2];
372 xpdd->XenBus_ShuttingDown = TRUE;
374 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
375 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
376 ObReferenceObjectByHandle(xpdd->XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[0], NULL);
377 ObReferenceObjectByHandle(xpdd->XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[1], NULL);
378 KeWaitForSingleObject(WaitArray[0], Executive, KernelMode, FALSE, NULL);
379 KeWaitForSingleObject(WaitArray[1], Executive, KernelMode, FALSE, NULL);
380 xpdd->XenBus_ShuttingDown = FALSE;
382 ZwClose(xpdd->XenBus_WatchThreadHandle);
383 ZwClose(xpdd->XenBus_ReadThreadHandle);
385 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
387 return STATUS_SUCCESS;
388 }
390 char *
391 XenBus_List(
392 PVOID Context,
393 xenbus_transaction_t xbt,
394 const char *pre,
395 char ***contents)
396 {
397 PXENPCI_DEVICE_DATA xpdd = Context;
398 struct xsd_sockmsg *reply, *repmsg;
399 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
400 ULONG nr_elems, x, i;
401 char **res;
402 char *msg;
404 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
406 repmsg = xenbus_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
407 msg = errmsg(repmsg);
408 if (msg)
409 {
410 *contents = NULL;
411 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
412 return msg;
413 }
414 reply = repmsg + 1;
415 for (x = nr_elems = 0; x < repmsg->len; x++)
416 {
417 nr_elems += (((char *)reply)[x] == 0);
418 }
419 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
420 XENPCI_POOL_TAG);
421 for (x = i = 0; i < nr_elems; i++)
422 {
423 int l = (int)strlen((char *)reply + x);
424 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
425 memcpy(res[i], (char *)reply + x, l + 1);
426 x += l + 1;
427 }
428 res[i] = NULL;
429 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
430 *contents = res;
431 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
432 return NULL;
433 }
435 static void
436 XenBus_ReadThreadProc(PVOID StartContext)
437 {
438 int NewWriteIndex;
439 struct xsd_sockmsg msg;
440 char *payload;
441 char *path, *token;
442 PXENPCI_DEVICE_DATA xpdd = StartContext;
444 for(;;)
445 {
446 KeWaitForSingleObject(&xpdd->XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
447 if (xpdd->XenBus_ShuttingDown)
448 {
449 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
450 PsTerminateSystemThread(0);
451 }
452 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
453 {
454 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
455 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg))
456 {
457 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
458 break;
459 }
460 //_ReadBarrier();
461 KeMemoryBarrier();
462 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
463 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(msg));
464 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
465 {
466 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
467 break;
468 }
470 if (msg.type != XS_WATCH_EVENT)
471 {
472 xpdd->req_info[msg.req_id].Reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
473 memcpy_from_ring(xpdd->xen_store_interface->rsp,
474 xpdd->req_info[msg.req_id].Reply,
475 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
476 msg.len + sizeof(msg));
477 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
478 KeSetEvent(&xpdd->req_info[msg.req_id].WaitEvent, 1, FALSE);
479 }
480 else // a watch: add to watch ring and signal watch thread
481 {
482 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
483 memcpy_from_ring(xpdd->xen_store_interface->rsp, payload,
484 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), msg.len + sizeof(msg));
485 xpdd->xen_store_interface->rsp_cons += msg.len + sizeof(msg);
486 path = payload + sizeof(msg);
487 token = path + strlen(path) + 1;
489 NewWriteIndex = (xpdd->XenBus_WatchRingWriteIndex + 1) & 127;
490 if (NewWriteIndex != xpdd->XenBus_WatchRingReadIndex)
491 {
492 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Path, path, 128);
493 strncpy(xpdd->XenBus_WatchRing[NewWriteIndex].Token, token, 10);
494 xpdd->XenBus_WatchRingWriteIndex = NewWriteIndex;
495 }
496 else
497 {
498 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
499 // drop the message on the floor
500 continue;
501 }
503 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
504 //KdPrint((__DRIVER_NAME " +++ Watch Path = %s Token = %s\n", path, token));
505 KeSetEvent(&xpdd->XenBus_WatchThreadEvent, 1, FALSE);
506 }
507 }
508 }
509 }
511 static void
512 XenBus_WatchThreadProc(PVOID StartContext)
513 {
514 int index;
515 PXENBUS_WATCH_ENTRY entry;
516 PXENPCI_DEVICE_DATA xpdd = StartContext;
517 KIRQL OldIrql;
519 for(;;)
520 {
521 KeWaitForSingleObject(&xpdd->XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
522 if (xpdd->XenBus_ShuttingDown)
523 {
524 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
525 PsTerminateSystemThread(0);
526 }
527 while (xpdd->XenBus_WatchRingReadIndex != xpdd->XenBus_WatchRingWriteIndex)
528 {
529 xpdd->XenBus_WatchRingReadIndex =
530 (xpdd->XenBus_WatchRingReadIndex + 1) % WATCH_RING_SIZE;
531 index = atoi(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Token);
533 entry = &xpdd->XenBus_WatchEntries[index];
534 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
535 if (!entry->Active || !entry->ServiceRoutine)
536 {
537 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
538 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
539 continue;
540 }
541 if (entry->RemovePending)
542 {
543 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
544 KdPrint((__DRIVER_NAME " Not calling watch - remove is pending\n"));
545 continue;
546 }
547 entry->Running = 1;
548 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
549 entry->Count++;
550 KdPrint((__DRIVER_NAME " --- for %s\n", xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path));
551 entry->ServiceRoutine(xpdd->XenBus_WatchRing[xpdd->XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
552 entry->Running = 0;
553 KeSetEvent(&entry->CompleteEvent, 1, FALSE);
554 }
555 }
556 }
558 char *
559 XenBus_AddWatch(
560 PVOID Context,
561 xenbus_transaction_t xbt,
562 const char *Path,
563 PXENBUS_WATCH_CALLBACK ServiceRoutine,
564 PVOID ServiceContext)
565 {
566 PXENPCI_DEVICE_DATA xpdd = Context;
567 struct xsd_sockmsg *rep;
568 char *msg;
569 int i;
570 char Token[20];
571 struct write_req req[2];
572 PXENBUS_WATCH_ENTRY w_entry;
573 KIRQL OldIrql;
575 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
577 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
579 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
581 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
582 if (xpdd->XenBus_WatchEntries[i].Active == 0)
583 break;
585 if (i == MAX_WATCH_ENTRIES)
586 {
587 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
588 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
589 return NULL;
590 }
592 /* must init watchentry before starting watch */
594 w_entry = &xpdd->XenBus_WatchEntries[i];
595 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
596 w_entry->ServiceRoutine = ServiceRoutine;
597 w_entry->ServiceContext = ServiceContext;
598 w_entry->Count = 0;
599 w_entry->Active = 1;
601 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
603 req[0].data = Path;
604 req[0].len = (ULONG)strlen(Path) + 1;
606 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
607 req[1].data = Token;
608 req[1].len = (ULONG)strlen(Token) + 1;
610 rep = xenbus_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
612 msg = errmsg(rep);
613 if (msg)
614 {
615 xpdd->XenBus_WatchEntries[i].Active = 0;
616 KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch (%s)\n", msg));
617 return msg;
618 }
619 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
621 KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
623 return NULL;
624 }
626 char *
627 XenBus_RemWatch(
628 PVOID Context,
629 xenbus_transaction_t xbt,
630 const char *Path,
631 PXENBUS_WATCH_CALLBACK ServiceRoutine,
632 PVOID ServiceContext)
633 {
634 PXENPCI_DEVICE_DATA xpdd = Context;
635 struct xsd_sockmsg *rep;
636 char *msg;
637 int i;
638 char Token[20];
639 struct write_req req[2];
640 KIRQL OldIrql;
642 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
644 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
646 // check that Path < 128 chars
648 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
649 if (xpdd->XenBus_WatchEntries[i].Active == 1
650 && strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) == 0
651 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
652 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
653 break;
654 }
656 if (i == MAX_WATCH_ENTRIES)
657 {
658 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
659 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
660 return NULL;
661 }
663 if (xpdd->XenBus_WatchEntries[i].RemovePending)
664 {
665 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
666 KdPrint((__DRIVER_NAME " Remove already pending - can't remove\n"));
667 return NULL;
668 }
669 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
671 while (xpdd->XenBus_WatchEntries[i].Running)
672 KeWaitForSingleObject(&xpdd->XenBus_WatchEntries[i].CompleteEvent, Executive, KernelMode, FALSE, NULL);
674 KeAcquireSpinLock(&xpdd->WatchLock, &OldIrql);
676 xpdd->XenBus_WatchEntries[i].Active = 0;
677 xpdd->XenBus_WatchEntries[i].RemovePending = 0;
678 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
680 KeReleaseSpinLock(&xpdd->WatchLock, OldIrql);
682 req[0].data = Path;
683 req[0].len = (ULONG)strlen(Path) + 1;
685 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
686 req[1].data = Token;
687 req[1].len = (ULONG)strlen(Token) + 1;
689 rep = xenbus_msg_reply(xpdd, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
691 msg = errmsg(rep);
692 if (msg)
693 {
694 return msg;
695 }
697 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
699 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
701 return NULL;
702 }
705 char *
706 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
707 {
708 PXENPCI_DEVICE_DATA xpdd = Context;
709 /* xenstored becomes angry if you send a length 0 message, so just
710 shove a nul terminator on the end */
711 struct write_req req = { "", 1};
712 struct xsd_sockmsg *rep;
713 char *err;
715 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
717 rep = xenbus_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
718 err = errmsg(rep);
719 if (err)
720 return err;
721 *xbt = atoi((char *)(rep + 1));
722 //sscanf((char *)(rep + 1), "%u", xbt);
723 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
725 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
727 return NULL;
728 }
730 char *
731 XenBus_EndTransaction(
732 PVOID Context,
733 xenbus_transaction_t t,
734 int abort,
735 int *retry)
736 {
737 PXENPCI_DEVICE_DATA xpdd = Context;
738 struct xsd_sockmsg *rep;
739 struct write_req req;
740 char *err;
742 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
744 *retry = 0;
746 req.data = abort ? "F" : "T";
747 req.len = 2;
748 rep = xenbus_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
749 err = errmsg(rep);
750 if (err) {
751 if (!strcmp(err, "EAGAIN")) {
752 *retry = 1;
753 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
754 return NULL;
755 } else {
756 return err;
757 }
758 }
759 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
761 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
763 return NULL;
764 }
766 static BOOLEAN
767 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext)
768 {
769 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
771 UNREFERENCED_PARAMETER(Interrupt);
773 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
775 KeSetEvent(&xpdd->XenBus_ReadThreadEvent, 1, FALSE);
777 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
779 return TRUE;
780 }
782 char *
783 XenBus_Printf(
784 PVOID Context,
785 xenbus_transaction_t xbt,
786 const char *path,
787 const char *fmt,
788 ...)
789 {
790 PXENPCI_DEVICE_DATA xpdd = Context;
791 va_list ap;
792 char buf[512];
793 char *retval;
795 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
797 va_start(ap, fmt);
798 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
799 va_end(ap);
800 retval = XenBus_Write(xpdd, xbt, path, buf);
802 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
804 return retval;
805 }