win-pvdrivers

annotate xenpci/xenbus.c @ 48:a70cbf588756

scsiport updates all working now
author James Harper <james.harper@bendigoit.com.au>
date Sat Dec 15 15:42:55 2007 +1100 (2007-12-15)
parents 2e1d570b69e9
children 94d0f2823b42
rev   line source
james@0 1 /*
james@0 2 PV Drivers for Windows Xen HVM Domains
james@0 3 Copyright (C) 2007 James Harper
james@0 4
james@0 5 This program is free software; you can redistribute it and/or
james@0 6 modify it under the terms of the GNU General Public License
james@0 7 as published by the Free Software Foundation; either version 2
james@0 8 of the License, or (at your option) any later version.
james@0 9
james@0 10 This program is distributed in the hope that it will be useful,
james@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@0 13 GNU General Public License for more details.
james@0 14
james@0 15 You should have received a copy of the GNU General Public License
james@0 16 along with this program; if not, write to the Free Software
james@0 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@0 18 */
james@0 19
james@0 20 #include "xenpci.h"
james@0 21 #include "io/xs_wire.h"
james@0 22 #include <stdlib.h>
james@0 23
james@0 24 #pragma warning( disable : 4204 )
james@0 25 #pragma warning( disable : 4221 )
james@0 26
james@0 27 struct xenbus_req_info
james@0 28 {
james@0 29 int In_Use:1;
james@0 30 KEVENT WaitEvent;
james@0 31 void *Reply;
james@0 32 };
james@0 33
james@0 34 typedef struct {
james@0 35 char Path[128];
james@0 36 PXENBUS_WATCH_CALLBACK ServiceRoutine;
james@0 37 PVOID ServiceContext;
james@0 38 int Count;
james@0 39 int Active;
james@0 40 } XENBUS_WATCH_ENTRY, *PXENBUS_WATCH_ENTRY;
james@0 41
james@0 42 typedef struct {
james@0 43 char Path[128];
james@0 44 char Token[10];
james@0 45 } XENBUS_WATCH_RING;
james@0 46
james@0 47 #define WATCH_RING_SIZE 128
james@0 48
james@0 49 static XENBUS_WATCH_RING XenBus_WatchRing[WATCH_RING_SIZE];
james@0 50 static int XenBus_WatchRingReadIndex;
james@0 51 static int XenBus_WatchRingWriteIndex;
james@0 52
james@0 53 #define MAX_WATCH_ENTRIES 128
james@0 54
james@0 55 static XENBUS_WATCH_ENTRY XenBus_WatchEntries[MAX_WATCH_ENTRIES];
james@0 56
james@0 57 #define NR_REQS 32
james@0 58 //#define XENSTORE_RING_SIZE 1024
james@0 59
james@0 60 //#define XENSTORE_RING_SIZE 1024
james@0 61 //typedef uint32_t XENSTORE_RING_IDX;
james@0 62 //#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1))
james@0 63
james@0 64 static struct xenstore_domain_interface *xen_store_interface;
james@0 65
james@0 66 static struct xenbus_req_info req_info[NR_REQS];
james@0 67 static int nr_live_reqs;
james@0 68 //static spinlock_t req_lock = SPIN_LOCK_UNLOCKED;
james@0 69
james@0 70 static HANDLE XenBus_ReadThreadHandle;
james@0 71 static KEVENT XenBus_ReadThreadEvent;
james@0 72
james@0 73 static HANDLE XenBus_WatchThreadHandle;
james@0 74 static KEVENT XenBus_WatchThreadEvent;
james@0 75
james@35 76 static BOOLEAN XenBus_ShuttingDown;
james@35 77
james@0 78 static void
james@0 79 XenBus_ReadThreadProc(PVOID StartContext);
james@0 80 static void
james@0 81 XenBus_WatchThreadProc(PVOID StartContext);
james@0 82
james@0 83 static BOOLEAN
james@0 84 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext);
james@0 85
james@0 86 static int allocate_xenbus_id(void)
james@0 87 {
james@0 88 static int probe;
james@0 89 int o_probe;
james@0 90
james@0 91 //KdPrint((__DRIVER_NAME " --> allocate_xenbus_id\n"));
james@0 92
james@0 93 for (;;)
james@0 94 {
james@0 95 // spin_lock(&req_lock);
james@0 96 if (nr_live_reqs < NR_REQS)
james@0 97 break;
james@0 98 // spin_unlock(&req_lock);
james@0 99 // wait_event(req_wq, (nr_live_reqs < NR_REQS));
james@0 100 }
james@0 101
james@0 102 o_probe = probe;
james@0 103
james@0 104 for (;;)
james@0 105 {
james@0 106 if (!req_info[o_probe].In_Use)
james@0 107 break;
james@0 108 o_probe = (o_probe + 1) % NR_REQS;
james@0 109 // BUG_ON(o_probe == probe);
james@0 110 }
james@0 111 nr_live_reqs++;
james@0 112 req_info[o_probe].In_Use = 1;
james@0 113 probe = (o_probe + 1) % NR_REQS;
james@0 114 //spin_unlock(&req_lock);
james@0 115 //init_waitqueue_head(&req_info[o_probe].waitq);
james@0 116 KeInitializeEvent(&req_info[o_probe].WaitEvent, SynchronizationEvent, FALSE);
james@0 117
james@0 118 //KdPrint((__DRIVER_NAME " <-- allocate_xenbus_id\n"));
james@0 119
james@0 120 return o_probe;
james@0 121 }
james@0 122
james@0 123 static void release_xenbus_id(int id)
james@0 124 {
james@0 125 // BUG_ON(!req_info[id].in_use);
james@0 126 // spin_lock(&req_lock);
james@0 127 req_info[id].In_Use = 0;
james@0 128 nr_live_reqs--;
james@0 129 req_info[id].In_Use = 0;
james@0 130 // if (nr_live_reqs == NR_REQS - 1)
james@0 131 // wake_up(&req_wq);
james@0 132 // spin_unlock(&req_lock);
james@0 133 }
james@0 134
james@0 135
james@0 136 static char *errmsg(struct xsd_sockmsg *rep)
james@0 137 {
james@0 138 char *res;
james@0 139 if (!rep) {
james@0 140 char msg[] = "No reply";
james@0 141 size_t len = strlen(msg) + 1;
james@0 142 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
james@0 143 }
james@0 144 if (rep->type != XS_ERROR)
james@0 145 return NULL;
james@0 146 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
james@0 147 memcpy(res, rep + 1, rep->len);
james@0 148 res[rep->len] = 0;
james@0 149 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 150 return res;
james@0 151 }
james@0 152
james@0 153 static void memcpy_from_ring(const void *Ring,
james@0 154 void *Dest,
james@0 155 int off,
james@0 156 int len)
james@0 157 {
james@0 158 int c1, c2;
james@0 159 const char *ring = Ring;
james@0 160 char *dest = Dest;
james@0 161 c1 = min(len, XENSTORE_RING_SIZE - off);
james@0 162 c2 = len - c1;
james@0 163 memcpy(dest, ring + off, c1);
james@0 164 memcpy(dest + c1, ring, c2);
james@0 165 }
james@0 166
james@0 167 void wait_for_watch(void)
james@0 168 {
james@0 169 // DEFINE_WAIT(w);
james@0 170 // add_waiter(w,watch_queue);
james@0 171 // schedule();
james@0 172 // remove_waiter(w);
james@0 173 // wake(current);
james@0 174 }
james@0 175
james@0 176 struct write_req {
james@0 177 const void *data;
james@0 178 unsigned len;
james@0 179 };
james@0 180
james@0 181 static evtchn_port_t xen_store_evtchn;
james@0 182
james@0 183 static void xb_write(int type, int req_id, xenbus_transaction_t trans_id,
james@0 184 const struct write_req *req, int nr_reqs)
james@0 185 {
james@0 186 XENSTORE_RING_IDX prod;
james@0 187 int r;
james@0 188 size_t len = 0;
james@0 189 const struct write_req *cur_req;
james@0 190 size_t req_off;
james@0 191 size_t total_off;
james@0 192 size_t this_chunk;
james@0 193 struct xsd_sockmsg m = {type, req_id, trans_id };
james@0 194 struct write_req header_req = { &m, sizeof(m) };
james@0 195
james@0 196 //KdPrint((__DRIVER_NAME " --> xb_write\n"));
james@0 197
james@0 198 for (r = 0; r < nr_reqs; r++)
james@0 199 len += req[r].len;
james@0 200 m.len = len;
james@0 201 len += sizeof(m);
james@0 202
james@0 203 cur_req = &header_req;
james@0 204
james@0 205 // BUG_ON(len > XENSTORE_RING_SIZE);
james@0 206 /* Wait for the ring to drain to the point where we can send the
james@0 207 message. */
james@0 208 prod = xen_store_interface->req_prod;
james@0 209
james@0 210 //KdPrint((__DRIVER_NAME " prod = %08x\n", prod));
james@0 211
james@0 212 if (prod + len - xen_store_interface->req_cons > XENSTORE_RING_SIZE)
james@0 213 {
james@0 214 /* Wait for there to be space on the ring */
james@0 215 //KdPrint((__DRIVER_NAME " prod %d, len %d, cons %d, size %d; waiting.\n", prod, len, xen_store_interface->req_cons, XENSTORE_RING_SIZE));
james@0 216 // wait_event(xb_waitq, xen_store_interface->req_prod + len - xen_store_interface->req_cons <= XENSTORE_RING_SIZE);
james@0 217 //KdPrint((__DRIVER_NAME " Back from wait.\n"));
james@0 218 prod = xen_store_interface->req_prod;
james@0 219 }
james@0 220
james@0 221 /* We're now guaranteed to be able to send the message without
james@0 222 overflowing the ring. Do so. */
james@0 223
james@0 224 total_off = 0;
james@0 225 req_off = 0;
james@0 226
james@0 227 while (total_off < len)
james@0 228 {
james@0 229 this_chunk = min(cur_req->len - req_off,XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
james@0 230 memcpy((char *)xen_store_interface->req + MASK_XENSTORE_IDX(prod), (char *)cur_req->data + req_off, this_chunk);
james@0 231 prod += this_chunk;
james@0 232 req_off += this_chunk;
james@0 233 total_off += this_chunk;
james@0 234 if (req_off == cur_req->len)
james@0 235 {
james@0 236 req_off = 0;
james@0 237 if (cur_req == &header_req)
james@0 238 cur_req = req;
james@0 239 else
james@0 240 cur_req++;
james@0 241 }
james@0 242 }
james@0 243
james@0 244 //KdPrint((__DRIVER_NAME " Complete main loop of xb_write.\n"));
james@0 245
james@0 246 // BUG_ON(req_off != 0);
james@0 247 // BUG_ON(total_off != len);
james@0 248 // BUG_ON(prod > xen_store_interface->req_cons + XENSTORE_RING_SIZE);
james@0 249
james@0 250 /* Remote must see entire message before updating indexes */
james@0 251 //_WriteBarrier();
james@0 252 KeMemoryBarrier();
james@0 253
james@0 254 xen_store_interface->req_prod += len;
james@0 255
james@0 256 //KdPrint((__DRIVER_NAME " prod = %08x\n", xen_store_interface->req_prod));
james@0 257
james@0 258 /* Send evtchn to notify remote */
james@0 259 EvtChn_Notify(xen_store_evtchn);
james@0 260
james@0 261 //KdPrint((__DRIVER_NAME " <-- xb_write\n"));
james@0 262 }
james@0 263
james@0 264 static struct xsd_sockmsg *
james@6 265 xenbus_msg_reply(int type, xenbus_transaction_t trans, struct write_req *io, int nr_reqs)
james@0 266 {
james@0 267 int id;
james@0 268 // DEFINE_WAIT(w);
james@0 269 struct xsd_sockmsg *rep;
james@0 270
james@35 271 // KdPrint((__DRIVER_NAME " --> xenbus_msg_reply\n"));
james@0 272
james@0 273 id = allocate_xenbus_id();
james@0 274 // add_waiter(w, req_info[id].waitq);
james@0 275
james@0 276 xb_write(type, id, trans, io, nr_reqs);
james@0 277 //
james@0 278 // schedule();
james@0 279 // remove_waiter(w);
james@0 280 // wake(current);
james@0 281 //
james@35 282 // KdPrint((__DRIVER_NAME " starting wait\n"));
james@0 283
james@0 284 KeWaitForSingleObject(&req_info[id].WaitEvent, Executive, KernelMode, FALSE, NULL);
james@0 285
james@9 286 //KdPrint((__DRIVER_NAME " wait complete\n"));
james@0 287
james@0 288 rep = req_info[id].Reply;
james@0 289 // BUG_ON(rep->req_id != id);
james@0 290 release_xenbus_id(id);
james@35 291 // KdPrint((__DRIVER_NAME " <-- xenbus_msg_reply\n"));
james@0 292 return rep;
james@0 293 }
james@0 294
james@0 295 char *
james@0 296 XenBus_Read(xenbus_transaction_t xbt, const char *path, char **value)
james@0 297 {
james@0 298 struct write_req req[] = { {path, strlen(path) + 1} };
james@0 299 struct xsd_sockmsg *rep;
james@0 300 char *res;
james@0 301 char *msg;
james@0 302
james@0 303 rep = xenbus_msg_reply(XS_READ, xbt, req, ARRAY_SIZE(req));
james@0 304 msg = errmsg(rep);
james@0 305 if (msg) {
james@0 306 *value = NULL;
james@0 307 return msg;
james@0 308 }
james@0 309 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
james@0 310 memcpy(res, rep + 1, rep->len);
james@0 311 res[rep->len] = 0;
james@0 312 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 313 *value = res;
james@0 314 return NULL;
james@0 315 }
james@0 316
james@0 317 char *
james@0 318 XenBus_Write(xenbus_transaction_t xbt, const char *path, const char *value)
james@0 319 {
james@0 320 struct write_req req[] = {
james@0 321 {path, strlen(path) + 1},
james@0 322 {value, strlen(value) + 1},
james@0 323 };
james@0 324 struct xsd_sockmsg *rep;
james@0 325 char *msg;
james@0 326
james@0 327 rep = xenbus_msg_reply(XS_WRITE, xbt, req, ARRAY_SIZE(req));
james@0 328 msg = errmsg(rep);
james@0 329 if (msg)
james@0 330 return msg;
james@0 331 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 332 return NULL;
james@0 333 }
james@0 334
james@0 335 char* xenbus_wait_for_value(const char* path,const char* value)
james@0 336 {
james@0 337 UNREFERENCED_PARAMETER(path);
james@0 338 UNREFERENCED_PARAMETER(value);
james@0 339 // for(;;)
james@0 340 // {
james@0 341 // char *res, *msg;
james@0 342 // int r;
james@0 343 //
james@0 344 // msg = xenbus_read(XBT_NIL, path, &res);
james@0 345 // if(msg) return msg;
james@0 346 //
james@0 347 // r = strcmp(value,res);
james@0 348 // ExFreePoolWithTag(res, XENPCI_POOL_TAG);
james@0 349 //
james@0 350 // if(r==0)
james@0 351 // break;
james@0 352 // else
james@0 353 // wait_for_watch();
james@0 354 // }
james@0 355 return NULL;
james@0 356 }
james@0 357
james@0 358 NTSTATUS
james@0 359 XenBus_Init()
james@0 360 {
james@35 361 NTSTATUS Status;
james@35 362 OBJECT_ATTRIBUTES oa;
james@35 363 int i;
james@35 364
james@35 365 KdPrint((__DRIVER_NAME " --> XenBus_Init\n"));
james@0 366
james@0 367 xen_store_evtchn = EvtChn_GetXenStorePort();
james@0 368 xen_store_interface = EvtChn_GetXenStoreRingAddr();
james@0 369
james@35 370 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@35 371 XenBus_WatchEntries[i].Active = 0;
james@0 372
james@0 373 KeInitializeEvent(&XenBus_ReadThreadEvent, SynchronizationEvent, FALSE);
james@0 374 KeInitializeEvent(&XenBus_WatchThreadEvent, SynchronizationEvent, FALSE);
james@35 375 XenBus_ShuttingDown = FALSE;
james@0 376
james@35 377 //InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
james@35 378 //Status = PsCreateSystemThread(&XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, &oa, NULL, NULL, XenBus_ReadThreadProc, NULL);
james@35 379 Status = PsCreateSystemThread(&XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_ReadThreadProc, NULL);
james@35 380
james@35 381 //InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
james@35 382 //Status = PsCreateSystemThread(&XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, &oa, NULL, NULL, XenBus_WatchThreadProc, NULL);
james@35 383 Status = PsCreateSystemThread(&XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenBus_WatchThreadProc, NULL);
james@35 384
james@35 385 KdPrint((__DRIVER_NAME " <-- XenBus_Init\n"));
james@0 386
james@0 387 return STATUS_SUCCESS;
james@0 388 }
james@0 389
james@0 390 NTSTATUS
james@0 391 XenBus_Start()
james@0 392 {
james@6 393 KdPrint((__DRIVER_NAME " --> XenBus_Start\n"));
james@0 394
james@0 395 EvtChn_Bind(xen_store_evtchn, XenBus_Interrupt, NULL);
james@0 396
james@6 397 KdPrint((__DRIVER_NAME " <-- XenBus_Start\n"));
james@0 398
james@0 399 return STATUS_SUCCESS;
james@0 400 }
james@0 401
james@0 402 NTSTATUS
james@0 403 XenBus_Stop()
james@0 404 {
james@0 405 int i;
james@0 406
james@35 407 KdPrint((__DRIVER_NAME " --> XenBus_Stop\n"));
james@35 408
james@0 409 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@0 410 {
james@35 411 if (XenBus_WatchEntries[i].Active)
james@35 412 XenBus_RemWatch(XBT_NIL, XenBus_WatchEntries[i].Path, XenBus_WatchEntries[i].ServiceRoutine, XenBus_WatchEntries[i].ServiceContext);
james@0 413 }
james@0 414
james@0 415 EvtChn_Unbind(xen_store_evtchn);
james@0 416
james@35 417 KdPrint((__DRIVER_NAME " <-- XenBus_Stop\n"));
james@35 418
james@35 419 return STATUS_SUCCESS;
james@35 420 }
james@35 421
james@35 422 NTSTATUS
james@35 423 XenBus_Close()
james@35 424 {
james@35 425 PKWAIT_BLOCK WaitBlockArray[2];
james@35 426 PVOID WaitArray[2];
james@35 427
james@35 428 XenBus_ShuttingDown = TRUE;
james@35 429
james@35 430 KdPrint((__DRIVER_NAME " Signalling Threads\n"));
james@35 431 KeSetEvent(&XenBus_ReadThreadEvent, 1, FALSE);
james@35 432 KeSetEvent(&XenBus_WatchThreadEvent, 1, FALSE);
james@35 433 KdPrint((__DRIVER_NAME " Waiting for threads to die\n"));
james@35 434 ObReferenceObjectByHandle(XenBus_ReadThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[0], NULL);
james@35 435 ObReferenceObjectByHandle(XenBus_WatchThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &WaitArray[1], NULL);
james@48 436 //KeWaitForMultipleObjects(1, &WaitArray[0], WaitAny, Executive, KernelMode, FALSE, NULL, WaitBlockArray);
james@48 437 KdPrint((__DRIVER_NAME " Waiting for ReadThread\n"));
james@48 438 KeWaitForSingleObject(WaitArray[0], Executive, KernelMode, FALSE, NULL);
james@48 439 KdPrint((__DRIVER_NAME " Waiting for WatchThread\n"));
james@48 440 //KeWaitForMultipleObjects(1, &WaitArray[1], WaitAny, Executive, KernelMode, FALSE, NULL, WaitBlockArray);
james@48 441 KeWaitForSingleObject(WaitArray[1], Executive, KernelMode, FALSE, NULL);
james@35 442 KdPrint((__DRIVER_NAME " Threads are dead\n"));
james@35 443
james@35 444 XenBus_ShuttingDown = FALSE;
james@35 445
james@48 446 // ObDereferenceObject(WaitArray[0]);
james@48 447 // ObDereferenceObject(WaitArray[1]);
james@48 448
james@48 449 KdPrint((__DRIVER_NAME " A\n"));
james@35 450
james@0 451 ZwClose(XenBus_WatchThreadHandle);
james@48 452
james@48 453 KdPrint((__DRIVER_NAME " B\n"));
james@48 454
james@0 455 ZwClose(XenBus_ReadThreadHandle);
james@0 456
james@35 457 KdPrint((__DRIVER_NAME " <-- XenBus_Close\n"));
james@35 458
james@0 459 return STATUS_SUCCESS;
james@0 460 }
james@0 461
james@0 462 char *
james@0 463 XenBus_List(xenbus_transaction_t xbt, const char *pre, char ***contents)
james@0 464 {
james@0 465 struct xsd_sockmsg *reply, *repmsg;
james@0 466 struct write_req req[] = { { pre, strlen(pre)+1 } };
james@0 467 ULONG nr_elems, x, i;
james@0 468 char **res;
james@0 469 char *msg;
james@0 470
james@0 471 //KdPrint((__DRIVER_NAME " --> xenbus_ls\n"));
james@0 472
james@0 473 repmsg = xenbus_msg_reply(XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
james@0 474 msg = errmsg(repmsg);
james@0 475 if (msg) {
james@0 476 *contents = NULL;
james@0 477 //KdPrint((__DRIVER_NAME " <-- xenbus_ls (error)\n"));
james@0 478 return msg;
james@0 479 }
james@0 480 reply = repmsg + 1;
james@0 481 for (x = nr_elems = 0; x < repmsg->len; x++)
james@0 482 nr_elems += (((char *)reply)[x] == 0);
james@0 483 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1), XENPCI_POOL_TAG);
james@0 484 for (x = i = 0; i < nr_elems; i++) {
james@0 485 int l = strlen((char *)reply + x);
james@0 486 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
james@0 487 memcpy(res[i], (char *)reply + x, l + 1);
james@0 488 x += l + 1;
james@0 489 }
james@0 490 res[i] = NULL;
james@0 491 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
james@0 492 *contents = res;
james@0 493 //KdPrint((__DRIVER_NAME " <-- xenbus_ls\n"));
james@0 494 return NULL;
james@0 495 }
james@0 496
james@0 497 void
james@0 498 do_ls_test(const char *pre)
james@0 499 {
james@0 500 char **dirs;
james@0 501 int x;
james@0 502 char *msg;
james@0 503
james@0 504 //KdPrint((__DRIVER_NAME " <-- do_ls_test(\"%s\")\n", pre));
james@0 505
james@0 506 msg = XenBus_List(XBT_NIL, pre, &dirs);
james@0 507 if (msg)
james@0 508 {
james@0 509 //KdPrint((__DRIVER_NAME " Error in xenbus ls: %s\n", msg));
james@0 510 ExFreePoolWithTag(msg, XENPCI_POOL_TAG);
james@0 511 return;
james@0 512 }
james@0 513 for (x = 0; dirs[x]; x++)
james@0 514 {
james@0 515 //KdPrint((__DRIVER_NAME " ls %s[%d] -> %s\n", pre, x, dirs[x]));
james@0 516 ExFreePoolWithTag(dirs[x], XENPCI_POOL_TAG);
james@0 517 }
james@0 518 ExFreePoolWithTag(dirs, XENPCI_POOL_TAG);
james@0 519 //KdPrint((__DRIVER_NAME " --> do_ls_test\n"));
james@0 520 }
james@0 521
james@0 522 static void
james@0 523 XenBus_ReadThreadProc(PVOID StartContext) {
james@0 524 int NewWriteIndex;
james@0 525 struct xsd_sockmsg msg;
james@0 526 char *payload;
james@0 527 char *path, *token;
james@0 528
james@0 529 UNREFERENCED_PARAMETER(StartContext);
james@0 530
james@0 531 for(;;)
james@0 532 {
james@0 533 KeWaitForSingleObject(&XenBus_ReadThreadEvent, Executive, KernelMode, FALSE, NULL);
james@35 534 if (XenBus_ShuttingDown)
james@35 535 {
james@35 536 KdPrint((__DRIVER_NAME " Shutdown detected in ReadThreadProc\n"));
james@35 537 PsTerminateSystemThread(0);
james@35 538 }
james@0 539 //KdPrint((__DRIVER_NAME " ReadThread Woken (Count = %d)\n", ReadThreadWaitCount++));
james@0 540 while (xen_store_interface->rsp_prod != xen_store_interface->rsp_cons)
james@0 541 {
james@0 542 //KdPrint((__DRIVER_NAME " a - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
james@0 543 if (xen_store_interface->rsp_prod - xen_store_interface->rsp_cons < sizeof(msg))
james@0 544 {
james@0 545 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
james@0 546 break;
james@0 547 }
james@0 548 //_ReadBarrier();
james@0 549 KeMemoryBarrier();
james@0 550 memcpy_from_ring(xen_store_interface->rsp, &msg, MASK_XENSTORE_IDX(xen_store_interface->rsp_cons), sizeof(msg));
james@0 551 if (xen_store_interface->rsp_prod - xen_store_interface->rsp_cons < sizeof(msg) + msg.len)
james@0 552 {
james@0 553 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
james@0 554 break;
james@0 555 }
james@0 556
james@0 557 if(msg.type == XS_WATCH_EVENT)
james@0 558 {
james@0 559 payload = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
james@0 560
james@0 561 memcpy_from_ring(xen_store_interface->rsp, payload, MASK_XENSTORE_IDX(xen_store_interface->rsp_cons), msg.len + sizeof(msg));
james@0 562
james@0 563 xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@0 564 //KdPrint((__DRIVER_NAME " b - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
james@0 565
james@0 566 path = payload + sizeof(msg);
james@0 567 token = path + strlen(path) + 1;
james@0 568
james@0 569 NewWriteIndex = (XenBus_WatchRingWriteIndex + 1) & 127;
james@0 570 if (NewWriteIndex != XenBus_WatchRingReadIndex)
james@0 571 {
james@0 572 strncpy(XenBus_WatchRing[NewWriteIndex].Path, path, 128);
james@0 573 strncpy(XenBus_WatchRing[NewWriteIndex].Token, token, 10);
james@0 574 XenBus_WatchRingWriteIndex = NewWriteIndex;
james@0 575 }
james@0 576 else
james@0 577 {
james@0 578 KdPrint((__DRIVER_NAME " +++ Queue full Path = %s Token = %s\n", path, token));
james@0 579 // drop the message on the floor
james@0 580 continue;
james@0 581 }
james@0 582
james@0 583 ExFreePoolWithTag(payload, XENPCI_POOL_TAG);
james@0 584 //KdPrint((__DRIVER_NAME " +++ Watch Path = %s Token = %s\n", path, token));
james@0 585 KeSetEvent(&XenBus_WatchThreadEvent, 1, FALSE);
james@0 586 }
james@0 587 else
james@0 588 {
james@0 589 req_info[msg.req_id].Reply = ExAllocatePoolWithTag(NonPagedPool, sizeof(msg) + msg.len, XENPCI_POOL_TAG);
james@0 590 memcpy_from_ring(xen_store_interface->rsp, req_info[msg.req_id].Reply, MASK_XENSTORE_IDX(xen_store_interface->rsp_cons), msg.len + sizeof(msg));
james@0 591 xen_store_interface->rsp_cons += msg.len + sizeof(msg);
james@0 592 //KdPrint((__DRIVER_NAME " c - Rsp_cons %d, rsp_prod %d.\n", xen_store_interface->rsp_cons, xen_store_interface->rsp_prod));
james@0 593 //KdPrint((__DRIVER_NAME " +++ Message = %s\n", ((char *)req_info[msg.req_id].Reply) + sizeof(msg)));
james@0 594 KeSetEvent(&req_info[msg.req_id].WaitEvent, 1, FALSE);
james@0 595 }
james@0 596 }
james@0 597 }
james@0 598 }
james@0 599
james@0 600 static void
james@0 601 XenBus_WatchThreadProc(PVOID StartContext)
james@0 602 {
james@0 603 int index;
james@0 604 PXENBUS_WATCH_ENTRY entry;
james@0 605
james@0 606 UNREFERENCED_PARAMETER(StartContext);
james@0 607
james@0 608 for(;;)
james@0 609 {
james@0 610 KeWaitForSingleObject(&XenBus_WatchThreadEvent, Executive, KernelMode, FALSE, NULL);
james@35 611 if (XenBus_ShuttingDown)
james@35 612 {
james@35 613 KdPrint((__DRIVER_NAME " Shutdown detected in WatchThreadProc\n"));
james@35 614 PsTerminateSystemThread(0);
james@35 615 }
james@0 616 while (XenBus_WatchRingReadIndex != XenBus_WatchRingWriteIndex)
james@0 617 {
james@0 618 XenBus_WatchRingReadIndex = (XenBus_WatchRingReadIndex + 1) & 127;
james@0 619 index = atoi(XenBus_WatchRing[XenBus_WatchRingReadIndex].Token);
james@0 620 //XenBus_WatchRing[XenBus_WatchRingReadIndex].Path
james@0 621 //XenBus_WatchRing[XenBus_WatchRingReadIndex].Token
james@0 622
james@0 623 entry = &XenBus_WatchEntries[index];
james@0 624 if (!entry->Active)
james@0 625 {
james@0 626 KdPrint((__DRIVER_NAME " +++ Watch not active! = %s Token = %s\n", XenBus_WatchRing[XenBus_WatchRingReadIndex].Path, XenBus_WatchRing[XenBus_WatchRingReadIndex].Token));
james@0 627 continue;
james@0 628 }
james@0 629 entry->Count++;
james@0 630 if (!entry->ServiceRoutine)
james@0 631 {
james@0 632 KdPrint((__DRIVER_NAME " +++ no handler for watch! = %s Token = %s\n", XenBus_WatchRing[XenBus_WatchRingReadIndex].Path, XenBus_WatchRing[XenBus_WatchRingReadIndex].Token));
james@0 633 continue;
james@0 634 }
james@0 635 //KdPrint((__DRIVER_NAME " +++ Watch Triggered Path = %s Token = %d (%s)\n", XenBus_WatchRing[XenBus_WatchRingReadIndex].Path, index, XenBus_WatchRing[XenBus_WatchRingReadIndex].Token));
james@0 636 entry->ServiceRoutine(XenBus_WatchRing[XenBus_WatchRingReadIndex].Path, entry->ServiceContext);
james@0 637 }
james@0 638 }
james@0 639 }
james@0 640
james@0 641 char *
james@0 642 XenBus_AddWatch(xenbus_transaction_t xbt, const char *Path, PXENBUS_WATCH_CALLBACK ServiceRoutine, PVOID ServiceContext)
james@0 643 {
james@0 644 struct xsd_sockmsg *rep;
james@0 645 char *msg;
james@0 646 int i;
james@0 647 char Token[20];
james@0 648 struct write_req req[2];
james@0 649
james@35 650 // KdPrint((__DRIVER_NAME " --> XenBus_AddWatch\n"));
james@0 651
james@0 652 // check that Path < 128 chars
james@0 653
james@0 654 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@0 655 if (XenBus_WatchEntries[i].Active == 0)
james@0 656 break;
james@0 657
james@0 658 if (i == MAX_WATCH_ENTRIES)
james@0 659 {
james@0 660 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
james@0 661 return NULL;
james@0 662 }
james@0 663
james@0 664 req[0].data = Path;
james@0 665 req[0].len = strlen(Path) + 1;
james@0 666
james@0 667 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
james@0 668 req[1].data = Token;
james@0 669 req[1].len = strlen(Token) + 1;
james@0 670
james@0 671 rep = xenbus_msg_reply(XS_WATCH, xbt, req, ARRAY_SIZE(req));
james@0 672
james@0 673 msg = errmsg(rep);
james@0 674 if (msg)
james@0 675 return msg;
james@0 676
james@0 677 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 678
james@0 679 strncpy(XenBus_WatchEntries[i].Path, Path, 128);
james@0 680 XenBus_WatchEntries[i].ServiceRoutine = ServiceRoutine;
james@0 681 XenBus_WatchEntries[i].ServiceContext = ServiceContext;
james@0 682 XenBus_WatchEntries[i].Count = 0;
james@0 683 XenBus_WatchEntries[i].Active = 1;
james@0 684
james@35 685 // KdPrint((__DRIVER_NAME " <-- XenBus_AddWatch\n"));
james@0 686
james@0 687 return NULL;
james@0 688 }
james@0 689
james@0 690 char *
james@0 691 XenBus_RemWatch(xenbus_transaction_t xbt, const char *Path, PXENBUS_WATCH_CALLBACK ServiceRoutine, PVOID ServiceContext)
james@0 692 {
james@0 693 struct xsd_sockmsg *rep;
james@0 694 char *msg;
james@0 695 int i;
james@0 696 char Token[20];
james@0 697 struct write_req req[2];
james@0 698
james@0 699 //KdPrint((__DRIVER_NAME " --> XenBus_RemWatch\n"));
james@0 700
james@0 701 // check that Path < 128 chars
james@0 702
james@0 703 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@0 704 if (XenBus_WatchEntries[i].Active == 1 && strcmp(XenBus_WatchEntries[i].Path, Path) == 0 && XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine && XenBus_WatchEntries[i].ServiceContext == ServiceContext)
james@0 705 break;
james@0 706 }
james@0 707
james@0 708 if (i == MAX_WATCH_ENTRIES)
james@0 709 {
james@0 710 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
james@0 711 return NULL;
james@0 712 }
james@0 713
james@0 714 req[0].data = Path;
james@0 715 req[0].len = strlen(Path) + 1;
james@0 716
james@0 717 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", i);
james@0 718 req[1].data = Token;
james@0 719 req[1].len = strlen(Token) + 1;
james@0 720
james@0 721 rep = xenbus_msg_reply(XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
james@0 722
james@0 723 msg = errmsg(rep);
james@0 724 if (msg)
james@0 725 return msg;
james@0 726
james@0 727 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 728
james@0 729 XenBus_WatchEntries[i].Active = 0;
james@0 730
james@0 731 //KdPrint((__DRIVER_NAME " <-- XenBus_RemWatch\n"));
james@0 732
james@0 733 return NULL;
james@0 734 }
james@0 735
james@0 736
james@0 737 char *
james@0 738 XenBus_StartTransaction(xenbus_transaction_t *xbt)
james@0 739 {
james@0 740 /* xenstored becomes angry if you send a length 0 message, so just
james@0 741 shove a nul terminator on the end */
james@0 742 struct write_req req = { "", 1};
james@0 743 struct xsd_sockmsg *rep;
james@0 744 char *err;
james@0 745
james@0 746 rep = xenbus_msg_reply(XS_TRANSACTION_START, 0, &req, 1);
james@0 747 err = errmsg(rep);
james@0 748 if (err)
james@0 749 return err;
james@0 750 *xbt = atoi((char *)(rep + 1));
james@0 751 //sscanf((char *)(rep + 1), "%u", xbt);
james@0 752 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 753 return NULL;
james@0 754 }
james@0 755
james@0 756 char *
james@0 757 XenBus_EndTransaction(xenbus_transaction_t t, int abort, int *retry)
james@0 758 {
james@0 759 struct xsd_sockmsg *rep;
james@0 760 struct write_req req;
james@0 761 char *err;
james@0 762
james@0 763 *retry = 0;
james@0 764
james@0 765 req.data = abort ? "F" : "T";
james@0 766 req.len = 2;
james@0 767 rep = xenbus_msg_reply(XS_TRANSACTION_END, t, &req, 1);
james@0 768 err = errmsg(rep);
james@0 769 if (err) {
james@0 770 if (!strcmp(err, "EAGAIN")) {
james@0 771 *retry = 1;
james@0 772 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
james@0 773 return NULL;
james@0 774 } else {
james@0 775 return err;
james@0 776 }
james@0 777 }
james@0 778 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 779 return NULL;
james@0 780 }
james@0 781 /*
james@0 782 void
james@0 783 XenBus_ThreadProc(PVOID StartContext)
james@0 784 {
james@0 785 char *response;
james@0 786
james@0 787 //KdPrint((__DRIVER_NAME " --> XenBus_ThreadProc\n"));
james@0 788
james@0 789 //do_ls_test("device");
james@0 790
james@0 791 // do_ls_test("local");
james@0 792
james@0 793 // do_ls_test("control");
james@0 794
james@0 795 // do_ls_test(".");
james@0 796
james@0 797 response = XenBus_AddWatch(XBT_NIL, SHUTDOWN_PATH, XenBus_ShutdownHandler, NULL);
james@0 798
james@0 799 //KdPrint((__DRIVER_NAME " <-- watch response = '%s'\n", response));
james@0 800
james@0 801 //KdPrint((__DRIVER_NAME " <-- XenBus_ThreadProc\n"));
james@0 802 }
james@0 803 */
james@0 804
james@0 805 static BOOLEAN
james@0 806 XenBus_Interrupt(PKINTERRUPT Interrupt, PVOID ServiceContext)
james@0 807 {
james@0 808 UNREFERENCED_PARAMETER(Interrupt);
james@0 809 UNREFERENCED_PARAMETER(ServiceContext);
james@0 810
james@0 811 //KdPrint((__DRIVER_NAME " --> XenBus_Interrupt (Count = %d)\n", ReadThreadSetCount++));
james@0 812
james@0 813 KeSetEvent(&XenBus_ReadThreadEvent, 1, FALSE);
james@0 814
james@0 815 //KdPrint((__DRIVER_NAME " <-- XenBus_Interrupt\n"));
james@0 816
james@0 817 return TRUE;
james@0 818 }
james@0 819
james@0 820 char *
james@0 821 XenBus_Printf(xenbus_transaction_t xbt, const char *path, const char *fmt, ...)
james@0 822 {
james@0 823 va_list ap;
james@0 824 char buf[1024];
james@0 825
james@0 826 va_start(ap, fmt);
james@0 827 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
james@0 828 va_end(ap);
james@0 829 return XenBus_Write(xbt, path, buf);
james@0 830 }