win-pvdrivers

annotate xenpci/xenbus.c @ 716:5bdb7251370c

Use WinDDK 7600.16385.0
Update userspace binaries to build for XP not 2K (2K not supported in new DDK)
Fix lots of PREfast errors
Make build and installer less dependant on DDK version
Fix IRQL crash in DpgPrint hooking
author James Harper <james.harper@bendigoit.com.au>
date Tue Dec 22 22:44:07 2009 +1100 (2009-12-22)
parents 4baaaaa23235
children 467005e7f509
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 <stdlib.h>
james@0 22
james@0 23 #pragma warning( disable : 4204 )
james@0 24 #pragma warning( disable : 4221 )
james@0 25
james@716 26 /* Not really necessary but keeps PREfast happy */
james@716 27 static EVT_WDF_WORKITEM XenBus_WatchWorkItemProc;
james@716 28
james@624 29 WDF_DECLARE_CONTEXT_TYPE(xsd_sockmsg_t)
james@624 30
andy@15 31 struct write_req {
james@504 32 void *data;
andy@15 33 unsigned len;
james@0 34 };
james@0 35
james@157 36 // This routine free's the rep structure if there was an error!!!
james@0 37 static char *errmsg(struct xsd_sockmsg *rep)
james@0 38 {
james@0 39 char *res;
andy@15 40
james@0 41 if (!rep) {
james@0 42 char msg[] = "No reply";
james@0 43 size_t len = strlen(msg) + 1;
james@0 44 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
james@0 45 }
james@0 46 if (rep->type != XS_ERROR)
james@0 47 return NULL;
james@0 48 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
james@0 49 memcpy(res, rep + 1, rep->len);
james@0 50 res[rep->len] = 0;
james@0 51 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@0 52 return res;
james@0 53 }
james@0 54
james@504 55 static void memcpy_from_ring(void *Ring,
james@0 56 void *Dest,
james@0 57 int off,
james@0 58 int len)
james@0 59 {
james@0 60 int c1, c2;
james@504 61 char *ring = Ring;
james@0 62 char *dest = Dest;
james@0 63 c1 = min(len, XENSTORE_RING_SIZE - off);
james@0 64 c2 = len - c1;
james@0 65 memcpy(dest, ring + off, c1);
james@0 66 memcpy(dest + c1, ring, c2);
james@0 67 }
james@0 68
james@404 69 /* called with xenbus_mutex held */
andy@15 70 static void xb_write(
james@258 71 PXENPCI_DEVICE_DATA xpdd,
james@504 72 PVOID data,
james@504 73 ULONG len
james@504 74 )
james@0 75 {
james@0 76 XENSTORE_RING_IDX prod;
james@504 77 ULONG copy_len;
james@504 78 PUCHAR ptr;
james@504 79 ULONG remaining;
james@504 80
james@523 81 //FUNCTION_ENTER();
james@0 82
james@390 83 ASSERT(len <= XENSTORE_RING_SIZE);
andy@15 84 prod = xpdd->xen_store_interface->req_prod;
james@504 85 ptr = data;
james@504 86 remaining = len;
james@504 87 while (remaining)
james@0 88 {
james@504 89 copy_len = min(remaining, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
james@504 90 memcpy((PUCHAR)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), ptr, copy_len);
james@504 91 prod += (XENSTORE_RING_IDX)copy_len;
james@504 92 ptr += copy_len;
james@504 93 remaining -= copy_len;
james@0 94 }
james@0 95 /* Remote must see entire message before updating indexes */
james@0 96 KeMemoryBarrier();
james@504 97 xpdd->xen_store_interface->req_prod = prod;
james@258 98 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn);
james@0 99
james@523 100 //FUNCTION_EXIT();
james@0 101 }
james@0 102
james@504 103 /* takes and releases xb_request_mutex */
james@0 104 static struct xsd_sockmsg *
james@504 105 xenbus_format_msg_reply(
james@258 106 PXENPCI_DEVICE_DATA xpdd,
andy@13 107 int type,
james@504 108 xenbus_transaction_t trans_id,
james@504 109 struct write_req *req,
andy@13 110 int nr_reqs)
james@0 111 {
james@504 112 struct xsd_sockmsg msg;
james@504 113 struct xsd_sockmsg *reply;
james@504 114 int i;
andy@94 115
james@529 116 //FUNCTION_ENTER();
james@504 117
james@504 118 msg.type = type;
james@504 119 msg.req_id = 0;
james@504 120 msg.tx_id = trans_id;
james@504 121 msg.len = 0;
james@504 122 for (i = 0; i < nr_reqs; i++)
james@515 123 msg.len += req[i].len;
james@95 124
james@504 125 ExAcquireFastMutex(&xpdd->xb_request_mutex);
james@504 126 xb_write(xpdd, &msg, sizeof(msg));
james@504 127 for (i = 0; i < nr_reqs; i++)
james@504 128 xb_write(xpdd, req[i].data, req[i].len);
james@0 129
james@504 130 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
james@504 131 reply = xpdd->xb_reply;
james@504 132 xpdd->xb_reply = NULL;
james@512 133 ExReleaseFastMutex(&xpdd->xb_request_mutex);
james@96 134
james@529 135 //FUNCTION_EXIT();
james@504 136
james@504 137 return reply;
james@504 138 }
james@504 139
james@504 140 /* takes and releases xb_request_mutex */
james@504 141 struct xsd_sockmsg *
james@504 142 XenBus_Raw(
james@504 143 PXENPCI_DEVICE_DATA xpdd,
james@504 144 struct xsd_sockmsg *msg)
james@504 145 {
james@504 146 struct xsd_sockmsg *reply;
james@536 147
james@624 148 //FUNCTION_ENTER();
james@504 149
james@504 150 ExAcquireFastMutex(&xpdd->xb_request_mutex);
james@504 151 xb_write(xpdd, msg, sizeof(struct xsd_sockmsg) + msg->len);
james@504 152 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
james@504 153 reply = xpdd->xb_reply;
james@504 154 xpdd->xb_reply = NULL;
james@504 155 ExReleaseFastMutex(&xpdd->xb_request_mutex);
james@504 156
james@624 157 //FUNCTION_EXIT();
james@536 158
james@504 159 return reply;
james@0 160 }
james@0 161
james@624 162 /* Called at PASSIVE_LEVEL */
james@0 163 char *
andy@15 164 XenBus_Read(
andy@13 165 PVOID Context,
andy@13 166 xenbus_transaction_t xbt,
james@504 167 char *path,
andy@13 168 char **value)
james@0 169 {
james@258 170 PXENPCI_DEVICE_DATA xpdd = Context;
james@145 171 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
andy@13 172 struct xsd_sockmsg *rep;
andy@13 173 char *res;
andy@13 174 char *msg;
james@0 175
james@342 176 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 177
james@272 178 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 179
james@504 180 rep = xenbus_format_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
andy@13 181 msg = errmsg(rep);
andy@13 182 if (msg) {
andy@13 183 *value = NULL;
andy@13 184 return msg;
andy@13 185 }
andy@13 186 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
andy@13 187 memcpy(res, rep + 1, rep->len);
andy@13 188 res[rep->len] = 0;
andy@13 189 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
andy@13 190 *value = res;
james@95 191
james@342 192 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 193
andy@13 194 return NULL;
james@0 195 }
james@0 196
james@624 197 /* Called at PASSIVE_LEVEL */
james@0 198 char *
andy@13 199 XenBus_Write(
andy@13 200 PVOID Context,
andy@13 201 xenbus_transaction_t xbt,
james@504 202 char *path,
james@504 203 char *value)
james@0 204 {
james@258 205 PXENPCI_DEVICE_DATA xpdd = Context;
andy@13 206 struct write_req req[] = {
james@145 207 {path, (ULONG)strlen(path) + 1},
andy@264 208 {value, (ULONG)strlen(value)},
andy@13 209 };
andy@13 210 struct xsd_sockmsg *rep;
andy@13 211 char *msg;
james@0 212
james@342 213 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
james@95 214
james@272 215 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 216
james@504 217 rep = xenbus_format_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
andy@13 218 msg = errmsg(rep);
andy@13 219 if (msg)
andy@13 220 return msg;
andy@13 221 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 222
james@342 223 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
james@95 224
andy@13 225 return NULL;
james@0 226 }
james@0 227
james@624 228 /* Called at PASSIVE_LEVEL */
james@624 229 static VOID
james@624 230 XenBus_WatchWorkItemProc(WDFWORKITEM workitem)
james@624 231 {
james@624 232 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
james@624 233 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
james@624 234 xsd_sockmsg_t *msg;
james@624 235 PCHAR path;
james@624 236 int index;
james@624 237 PXENBUS_WATCH_ENTRY entry;
james@624 238
james@624 239 //FUNCTION_ENTER();
james@624 240 msg = WdfObjectGetTypedContext(workitem, xsd_sockmsg_t);
james@624 241 path = (PCHAR)msg + sizeof(xsd_sockmsg_t);
james@624 242 index = atoi(path + strlen(path) + 1);
james@716 243 if (index < 0 || index >= MAX_WATCH_ENTRIES)
james@716 244 {
james@716 245 KdPrint((__DRIVER_NAME " Watch index %d out of range\n", index));
james@716 246 WdfObjectDelete(workitem);
james@716 247 return;
james@716 248 }
james@624 249 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@624 250 entry = &xpdd->XenBus_WatchEntries[index];
james@624 251 if (!entry->Active || !entry->ServiceRoutine)
james@624 252 {
james@624 253 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
james@630 254 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@624 255 WdfObjectDelete(workitem);
james@624 256 return;
james@624 257 }
james@624 258 entry->Count++;
james@624 259 entry->ServiceRoutine(path, entry->ServiceContext);
james@624 260 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@624 261 WdfObjectDelete(workitem);
james@624 262 //FUNCTION_ENTER();
james@624 263 }
james@624 264
james@624 265 /* Called at DISPATCH_LEVEL */
james@515 266 static VOID
james@515 267 XenBus_Dpc(PVOID ServiceContext)
james@515 268 {
james@624 269 NTSTATUS status;
james@515 270 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
james@624 271 xsd_sockmsg_t msg;
james@683 272 ULONG msg_len;
james@624 273 WDF_WORKITEM_CONFIG workitem_config;
james@624 274 WDF_OBJECT_ATTRIBUTES workitem_attributes;
james@624 275 WDFWORKITEM workitem;
james@515 276
james@624 277 //FUNCTION_ENTER();
james@646 278
james@646 279 KeAcquireSpinLockAtDpcLevel(&xpdd->xb_ring_spinlock);
james@515 280
james@624 281 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
james@624 282 {
james@683 283 if (!xpdd->xb_msg)
james@624 284 {
james@683 285 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(xsd_sockmsg_t))
james@683 286 {
james@683 287 KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
james@683 288 break;
james@683 289 }
james@683 290 KeMemoryBarrier();
james@683 291 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
james@683 292 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(xsd_sockmsg_t));
james@683 293 xpdd->xb_msg = ExAllocatePoolWithTag(NonPagedPool, sizeof(xsd_sockmsg_t) + msg.len, XENPCI_POOL_TAG);
james@683 294 memcpy(xpdd->xb_msg, &msg, sizeof(xsd_sockmsg_t));
james@683 295 xpdd->xb_msg_offset = sizeof(xsd_sockmsg_t);
james@683 296 xpdd->xen_store_interface->rsp_cons += sizeof(xsd_sockmsg_t);
james@624 297 }
james@683 298
james@683 299 msg_len = min(xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons, sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len - xpdd->xb_msg_offset);
james@683 300 KeMemoryBarrier(); /* make sure the data in the ring is valid */
james@683 301 ASSERT(xpdd->xb_msg_offset + msg_len <= sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len);
james@683 302 memcpy_from_ring(xpdd->xen_store_interface->rsp,
james@683 303 (PUCHAR)xpdd->xb_msg + xpdd->xb_msg_offset,
james@683 304 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
james@683 305 msg_len);
james@683 306 xpdd->xen_store_interface->rsp_cons += msg_len;
james@683 307 xpdd->xb_msg_offset += msg_len;
james@683 308
james@683 309 if (xpdd->xb_msg_offset < sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len)
james@624 310 {
james@683 311 KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
james@683 312 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn); /* there is room on the ring now */
james@624 313 break;
james@624 314 }
james@515 315
james@683 316 if (xpdd->xb_msg->type != XS_WATCH_EVENT)
james@624 317 {
james@624 318 /* process reply - only ever one outstanding */
james@683 319 ASSERT(xpdd->xb_reply == NULL);
james@683 320 xpdd->xb_reply = xpdd->xb_msg;
james@683 321 xpdd->xb_msg = NULL;
james@624 322 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
james@624 323 }
james@624 324 else
james@624 325 {
james@624 326 /* process watch */
james@624 327 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenBus_WatchWorkItemProc);
james@624 328 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workitem_attributes, xsd_sockmsg_t);
james@624 329 workitem_attributes.ParentObject = xpdd->wdf_device;
james@683 330 workitem_attributes.ContextSizeOverride = xpdd->xb_msg_offset;
james@624 331 status = WdfWorkItemCreate(&workitem_config, &workitem_attributes, &workitem);
james@624 332 if (!NT_SUCCESS(status))
james@624 333 {
james@624 334 KdPrint((__DRIVER_NAME " Failed to create work item for watch\n"));
james@624 335 continue;
james@624 336 }
james@683 337 memcpy(WdfObjectGetTypedContext(workitem, xsd_sockmsg_t), xpdd->xb_msg, xpdd->xb_msg_offset);
james@683 338 xpdd->xb_msg = NULL;
james@624 339 WdfWorkItemEnqueue(workitem);
james@624 340 }
james@683 341 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn); /* there is room on the ring now */
james@624 342 }
james@646 343 KeReleaseSpinLockFromDpcLevel(&xpdd->xb_ring_spinlock);
james@624 344
james@624 345 //FUNCTION_EXIT();
james@515 346 }
james@515 347
james@624 348 static NTSTATUS
james@342 349 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
james@342 350 {
james@342 351 PHYSICAL_ADDRESS pa_xen_store_interface;
james@342 352 xen_ulong_t xen_store_mfn;
james@342 353
james@342 354 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
james@342 355 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
james@342 356 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
james@342 357 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
james@342 358
james@624 359 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
james@624 360
james@624 361 return STATUS_SUCCESS;
james@624 362 }
james@624 363
james@624 364 static NTSTATUS
james@624 365 XenBus_Disconnect(PXENPCI_DEVICE_DATA xpdd)
james@624 366 {
james@624 367 EvtChn_Unbind(xpdd, xpdd->xen_store_evtchn);
james@624 368
james@624 369 MmUnmapIoSpace(xpdd->xen_store_interface, PAGE_SIZE);
james@390 370
james@390 371 return STATUS_SUCCESS;
james@342 372 }
james@342 373
james@0 374 NTSTATUS
james@258 375 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
james@0 376 {
james@390 377 NTSTATUS status;
james@35 378 int i;
andy@37 379
james@624 380 FUNCTION_ENTER();
james@35 381
james@622 382 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
james@35 383
james@646 384 KeInitializeSpinLock(&xpdd->xb_ring_spinlock);
james@504 385 ExInitializeFastMutex(&xpdd->xb_request_mutex);
james@504 386 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
james@128 387
james@35 388 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@128 389 {
andy@38 390 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 391 }
james@0 392
james@504 393 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
james@504 394
james@390 395 status = XenBus_Connect(xpdd);
james@390 396 if (!NT_SUCCESS(status))
andy@101 397 {
james@673 398 FUNCTION_EXIT();
james@390 399 return status;
andy@101 400 }
james@342 401
james@624 402 FUNCTION_EXIT();
james@0 403
james@0 404 return STATUS_SUCCESS;
james@0 405 }
james@0 406
james@406 407 char *
james@406 408 XenBus_SendRemWatch(
james@406 409 PVOID context,
james@406 410 xenbus_transaction_t xbt,
james@504 411 char *path,
james@504 412 int index)
james@406 413 {
james@406 414 struct xsd_sockmsg *rep;
james@406 415 char *msg;
james@406 416 char Token[20];
james@406 417 struct write_req req[2];
james@406 418
james@406 419 req[0].data = path;
james@406 420 req[0].len = (ULONG)strlen(path) + 1;
james@406 421
james@406 422 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
james@406 423 req[1].data = Token;
james@406 424 req[1].len = (ULONG)strlen(Token) + 1;
james@406 425
james@504 426 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
james@406 427
james@406 428 msg = errmsg(rep);
james@406 429 if (msg)
james@406 430 return msg;
james@406 431
james@406 432 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@406 433
james@406 434 return NULL;
james@406 435 }
james@406 436
james@35 437 NTSTATUS
james@622 438 XenBus_Halt(PXENPCI_DEVICE_DATA xpdd)
james@35 439 {
james@406 440 int i;
james@35 441
james@406 442 FUNCTION_ENTER();
james@406 443
james@272 444 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 445
james@406 446 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@624 447 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@624 448 {
james@406 449 if (xpdd->XenBus_WatchEntries[i].Active)
james@624 450 {
james@624 451 xpdd->XenBus_WatchEntries[i].Active = 0;
james@406 452 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@624 453 }
james@406 454 }
james@406 455
james@624 456 XenBus_Disconnect(xpdd);
james@35 457
james@406 458 FUNCTION_EXIT();
james@35 459
james@0 460 return STATUS_SUCCESS;
james@0 461 }
james@0 462
james@0 463 char *
andy@13 464 XenBus_List(
andy@13 465 PVOID Context,
andy@13 466 xenbus_transaction_t xbt,
james@504 467 char *pre,
andy@13 468 char ***contents)
james@0 469 {
james@258 470 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 471 struct xsd_sockmsg *reply, *repmsg;
james@145 472 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
james@0 473 ULONG nr_elems, x, i;
james@0 474 char **res;
james@0 475 char *msg;
james@0 476
james@272 477 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 478
james@504 479 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
james@0 480 msg = errmsg(repmsg);
andy@15 481 if (msg)
andy@15 482 {
james@0 483 *contents = NULL;
james@0 484 return msg;
james@0 485 }
james@0 486 reply = repmsg + 1;
james@0 487 for (x = nr_elems = 0; x < repmsg->len; x++)
andy@15 488 {
james@0 489 nr_elems += (((char *)reply)[x] == 0);
andy@15 490 }
andy@15 491 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
andy@15 492 XENPCI_POOL_TAG);
andy@15 493 for (x = i = 0; i < nr_elems; i++)
andy@15 494 {
james@145 495 int l = (int)strlen((char *)reply + x);
james@0 496 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
james@0 497 memcpy(res[i], (char *)reply + x, l + 1);
james@0 498 x += l + 1;
james@0 499 }
james@0 500 res[i] = NULL;
james@0 501 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
james@0 502 *contents = res;
james@624 503
james@0 504 return NULL;
james@0 505 }
james@0 506
james@624 507 /* Called at PASSIVE_LEVEL */
james@279 508 static char *
james@279 509 XenBus_SendAddWatch(
james@279 510 PVOID Context,
james@279 511 xenbus_transaction_t xbt,
james@504 512 char *Path,
james@279 513 int slot)
james@279 514 {
james@279 515 PXENPCI_DEVICE_DATA xpdd = Context;
james@279 516 struct xsd_sockmsg *rep;
james@279 517 char *msg;
james@279 518 char Token[20];
james@279 519 struct write_req req[2];
james@279 520
james@279 521 req[0].data = Path;
james@279 522 req[0].len = (ULONG)strlen(Path) + 1;
james@279 523
james@279 524 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
james@279 525 req[1].data = Token;
james@279 526 req[1].len = (ULONG)strlen(Token) + 1;
james@279 527
james@504 528 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
james@404 529
james@279 530 msg = errmsg(rep);
james@283 531 if (!msg)
james@283 532 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@279 533
james@279 534 return msg;
james@279 535 }
james@279 536
james@342 537 /* called at PASSIVE_LEVEL */
james@390 538 NTSTATUS
james@409 539 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
james@409 540 {
james@409 541 int i;
james@409 542
james@409 543 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@409 544 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@409 545 if (xpdd->XenBus_WatchEntries[i].Active)
james@409 546 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@409 547 }
james@624 548 XenBus_Disconnect(xpdd);
james@624 549
james@409 550 return STATUS_SUCCESS;
james@409 551 }
james@409 552
james@409 553 /* called at PASSIVE_LEVEL */
james@409 554 NTSTATUS
james@279 555 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
james@279 556 {
james@390 557 NTSTATUS status;
james@279 558 int i;
james@341 559
andy@398 560 FUNCTION_ENTER();
james@342 561
james@390 562 status = XenBus_Connect(xpdd);
james@390 563 if (!NT_SUCCESS(status))
james@390 564 {
james@390 565 return status;
james@390 566 }
james@279 567
james@279 568 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@341 569 {
james@279 570 if (xpdd->XenBus_WatchEntries[i].Active)
james@341 571 {
james@536 572 //KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
james@279 573 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@341 574 }
james@341 575 }
andy@398 576 FUNCTION_EXIT();
james@390 577
james@390 578 return STATUS_SUCCESS;
james@279 579 }
james@279 580
james@0 581 char *
andy@15 582 XenBus_AddWatch(
andy@13 583 PVOID Context,
andy@13 584 xenbus_transaction_t xbt,
james@504 585 char *Path,
andy@13 586 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 587 PVOID ServiceContext)
james@0 588 {
james@258 589 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 590 char *msg;
james@0 591 int i;
andy@94 592 PXENBUS_WATCH_ENTRY w_entry;
james@0 593
james@272 594 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 595
andy@94 596 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
james@0 597
james@504 598 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 599
james@0 600 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
andy@15 601 if (xpdd->XenBus_WatchEntries[i].Active == 0)
james@0 602 break;
james@0 603
james@0 604 if (i == MAX_WATCH_ENTRIES)
james@0 605 {
james@0 606 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
james@504 607 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 608 return NULL;
james@0 609 }
james@0 610
andy@94 611 /* must init watchentry before starting watch */
james@128 612
andy@94 613 w_entry = &xpdd->XenBus_WatchEntries[i];
james@716 614 RtlStringCbCopyA(w_entry->Path, ARRAY_SIZE(w_entry->Path), Path);
andy@94 615 w_entry->ServiceRoutine = ServiceRoutine;
andy@94 616 w_entry->ServiceContext = ServiceContext;
andy@94 617 w_entry->Count = 0;
andy@94 618 w_entry->Active = 1;
andy@94 619
james@504 620 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@128 621
james@279 622 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
james@0 623
andy@93 624 if (msg)
andy@93 625 {
andy@93 626 xpdd->XenBus_WatchEntries[i].Active = 0;
andy@93 627 return msg;
andy@93 628 }
andy@93 629
james@0 630 return NULL;
james@0 631 }
james@0 632
james@0 633 char *
andy@13 634 XenBus_RemWatch(
andy@13 635 PVOID Context,
andy@13 636 xenbus_transaction_t xbt,
james@504 637 char *Path,
andy@13 638 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 639 PVOID ServiceContext)
james@0 640 {
james@258 641 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 642 char *msg;
james@0 643 int i;
james@0 644
james@272 645 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 646
james@504 647 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 648
james@0 649 // check that Path < 128 chars
james@0 650
james@409 651 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@409 652 {
james@538 653 if (xpdd->XenBus_WatchEntries[i].Active
james@538 654 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
andy@15 655 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
andy@15 656 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
james@409 657 {
james@409 658 KdPrint((__DRIVER_NAME " Match\n"));
james@0 659 break;
james@409 660 }
james@0 661 }
james@0 662
james@0 663 if (i == MAX_WATCH_ENTRIES)
james@0 664 {
james@504 665 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 666 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
james@0 667 return NULL;
james@0 668 }
james@0 669
james@128 670 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 671 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
james@128 672
james@504 673 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 674
james@406 675 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
james@406 676
james@406 677 return msg;
james@0 678 }
james@0 679
james@0 680 char *
andy@13 681 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
james@0 682 {
james@258 683 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 684 /* xenstored becomes angry if you send a length 0 message, so just
james@0 685 shove a nul terminator on the end */
james@0 686 struct write_req req = { "", 1};
james@0 687 struct xsd_sockmsg *rep;
james@0 688 char *err;
james@0 689
james@272 690 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@95 691
james@504 692 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
james@0 693 err = errmsg(rep);
james@0 694 if (err)
james@0 695 return err;
james@0 696 *xbt = atoi((char *)(rep + 1));
james@0 697 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 698
james@0 699 return NULL;
james@0 700 }
james@0 701
james@0 702 char *
andy@15 703 XenBus_EndTransaction(
andy@15 704 PVOID Context,
andy@15 705 xenbus_transaction_t t,
andy@15 706 int abort,
andy@15 707 int *retry)
james@0 708 {
james@258 709 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 710 struct xsd_sockmsg *rep;
james@0 711 struct write_req req;
james@0 712 char *err;
james@0 713
james@0 714 *retry = 0;
james@0 715
james@0 716 req.data = abort ? "F" : "T";
james@0 717 req.len = 2;
james@504 718 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
james@0 719 err = errmsg(rep);
james@0 720 if (err) {
james@0 721 if (!strcmp(err, "EAGAIN")) {
james@0 722 *retry = 1;
james@0 723 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
james@0 724 return NULL;
james@0 725 } else {
james@0 726 return err;
james@0 727 }
james@0 728 }
james@0 729 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 730
james@0 731 return NULL;
james@0 732 }
james@0 733
james@0 734 char *
andy@15 735 XenBus_Printf(
andy@15 736 PVOID Context,
andy@15 737 xenbus_transaction_t xbt,
james@504 738 char *path,
james@504 739 char *fmt,
andy@15 740 ...)
james@0 741 {
james@258 742 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 743 va_list ap;
andy@101 744 char buf[512];
james@95 745 char *retval;
james@95 746
james@272 747 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 748
james@0 749 va_start(ap, fmt);
james@0 750 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
james@0 751 va_end(ap);
james@258 752 retval = XenBus_Write(xpdd, xbt, path, buf);
james@95 753
james@95 754 return retval;
andy@37 755 }