win-pvdrivers

annotate xenpci/xenbus.c @ 341:744c19115142

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