win-pvdrivers

annotate xenpci/xenbus.c @ 790:467005e7f509

Big messy changes. Add grant ref tagging to better track when things go wrong (debug build only).
Fix a race in xennet that causes crashes under heavy traffic conditions on driver shutdown.
author James Harper <james.harper@bendigoit.com.au>
date Fri Mar 12 09:38:42 2010 +1100 (2010-03-12)
parents 5bdb7251370c
children bbc6c94b9621
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@790 238 PXENBUS_WATCH_CALLBACK service_routine;
james@790 239 PVOID service_context;
james@624 240
james@624 241 //FUNCTION_ENTER();
james@624 242 msg = WdfObjectGetTypedContext(workitem, xsd_sockmsg_t);
james@624 243 path = (PCHAR)msg + sizeof(xsd_sockmsg_t);
james@624 244 index = atoi(path + strlen(path) + 1);
james@716 245 if (index < 0 || index >= MAX_WATCH_ENTRIES)
james@716 246 {
james@716 247 KdPrint((__DRIVER_NAME " Watch index %d out of range\n", index));
james@716 248 WdfObjectDelete(workitem);
james@790 249 //FUNCTION_ENTER();
james@716 250 return;
james@716 251 }
james@624 252 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@624 253 entry = &xpdd->XenBus_WatchEntries[index];
james@624 254 if (!entry->Active || !entry->ServiceRoutine)
james@624 255 {
james@624 256 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
james@630 257 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@624 258 WdfObjectDelete(workitem);
james@790 259 //FUNCTION_ENTER();
james@624 260 return;
james@624 261 }
james@624 262 entry->Count++;
james@790 263 service_routine = entry->ServiceRoutine;
james@790 264 service_context = entry->ServiceContext;
james@790 265 service_routine(path, service_context);
james@624 266 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@624 267 WdfObjectDelete(workitem);
james@790 268 //FUNCTION_EXIT();
james@624 269 }
james@624 270
james@624 271 /* Called at DISPATCH_LEVEL */
james@515 272 static VOID
james@515 273 XenBus_Dpc(PVOID ServiceContext)
james@515 274 {
james@624 275 NTSTATUS status;
james@515 276 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
james@624 277 xsd_sockmsg_t msg;
james@683 278 ULONG msg_len;
james@624 279 WDF_WORKITEM_CONFIG workitem_config;
james@624 280 WDF_OBJECT_ATTRIBUTES workitem_attributes;
james@624 281 WDFWORKITEM workitem;
james@515 282
james@624 283 //FUNCTION_ENTER();
james@646 284
james@646 285 KeAcquireSpinLockAtDpcLevel(&xpdd->xb_ring_spinlock);
james@515 286
james@624 287 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
james@624 288 {
james@683 289 if (!xpdd->xb_msg)
james@624 290 {
james@683 291 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(xsd_sockmsg_t))
james@683 292 {
james@790 293 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
james@683 294 break;
james@683 295 }
james@683 296 KeMemoryBarrier();
james@683 297 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
james@683 298 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(xsd_sockmsg_t));
james@683 299 xpdd->xb_msg = ExAllocatePoolWithTag(NonPagedPool, sizeof(xsd_sockmsg_t) + msg.len, XENPCI_POOL_TAG);
james@683 300 memcpy(xpdd->xb_msg, &msg, sizeof(xsd_sockmsg_t));
james@683 301 xpdd->xb_msg_offset = sizeof(xsd_sockmsg_t);
james@683 302 xpdd->xen_store_interface->rsp_cons += sizeof(xsd_sockmsg_t);
james@624 303 }
james@683 304
james@683 305 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 306 KeMemoryBarrier(); /* make sure the data in the ring is valid */
james@683 307 ASSERT(xpdd->xb_msg_offset + msg_len <= sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len);
james@683 308 memcpy_from_ring(xpdd->xen_store_interface->rsp,
james@683 309 (PUCHAR)xpdd->xb_msg + xpdd->xb_msg_offset,
james@683 310 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
james@683 311 msg_len);
james@683 312 xpdd->xen_store_interface->rsp_cons += msg_len;
james@683 313 xpdd->xb_msg_offset += msg_len;
james@683 314
james@683 315 if (xpdd->xb_msg_offset < sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len)
james@624 316 {
james@790 317 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
james@683 318 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn); /* there is room on the ring now */
james@624 319 break;
james@624 320 }
james@515 321
james@683 322 if (xpdd->xb_msg->type != XS_WATCH_EVENT)
james@624 323 {
james@624 324 /* process reply - only ever one outstanding */
james@683 325 ASSERT(xpdd->xb_reply == NULL);
james@683 326 xpdd->xb_reply = xpdd->xb_msg;
james@683 327 xpdd->xb_msg = NULL;
james@624 328 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
james@624 329 }
james@624 330 else
james@624 331 {
james@624 332 /* process watch */
james@624 333 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenBus_WatchWorkItemProc);
james@624 334 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workitem_attributes, xsd_sockmsg_t);
james@624 335 workitem_attributes.ParentObject = xpdd->wdf_device;
james@683 336 workitem_attributes.ContextSizeOverride = xpdd->xb_msg_offset;
james@624 337 status = WdfWorkItemCreate(&workitem_config, &workitem_attributes, &workitem);
james@624 338 if (!NT_SUCCESS(status))
james@624 339 {
james@624 340 KdPrint((__DRIVER_NAME " Failed to create work item for watch\n"));
james@624 341 continue;
james@624 342 }
james@683 343 memcpy(WdfObjectGetTypedContext(workitem, xsd_sockmsg_t), xpdd->xb_msg, xpdd->xb_msg_offset);
james@683 344 xpdd->xb_msg = NULL;
james@624 345 WdfWorkItemEnqueue(workitem);
james@624 346 }
james@683 347 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn); /* there is room on the ring now */
james@624 348 }
james@646 349 KeReleaseSpinLockFromDpcLevel(&xpdd->xb_ring_spinlock);
james@624 350
james@624 351 //FUNCTION_EXIT();
james@515 352 }
james@515 353
james@624 354 static NTSTATUS
james@342 355 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
james@342 356 {
james@342 357 PHYSICAL_ADDRESS pa_xen_store_interface;
james@342 358 xen_ulong_t xen_store_mfn;
james@342 359
james@342 360 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
james@342 361 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
james@342 362 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
james@342 363 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
james@342 364
james@624 365 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
james@624 366
james@624 367 return STATUS_SUCCESS;
james@624 368 }
james@624 369
james@624 370 static NTSTATUS
james@624 371 XenBus_Disconnect(PXENPCI_DEVICE_DATA xpdd)
james@624 372 {
james@624 373 EvtChn_Unbind(xpdd, xpdd->xen_store_evtchn);
james@624 374
james@624 375 MmUnmapIoSpace(xpdd->xen_store_interface, PAGE_SIZE);
james@390 376
james@390 377 return STATUS_SUCCESS;
james@342 378 }
james@342 379
james@0 380 NTSTATUS
james@258 381 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
james@0 382 {
james@390 383 NTSTATUS status;
james@35 384 int i;
andy@37 385
james@624 386 FUNCTION_ENTER();
james@35 387
james@622 388 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
james@35 389
james@646 390 KeInitializeSpinLock(&xpdd->xb_ring_spinlock);
james@504 391 ExInitializeFastMutex(&xpdd->xb_request_mutex);
james@504 392 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
james@128 393
james@35 394 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@128 395 {
andy@38 396 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 397 }
james@0 398
james@504 399 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
james@504 400
james@390 401 status = XenBus_Connect(xpdd);
james@390 402 if (!NT_SUCCESS(status))
andy@101 403 {
james@673 404 FUNCTION_EXIT();
james@390 405 return status;
andy@101 406 }
james@342 407
james@624 408 FUNCTION_EXIT();
james@0 409
james@0 410 return STATUS_SUCCESS;
james@0 411 }
james@0 412
james@406 413 char *
james@406 414 XenBus_SendRemWatch(
james@406 415 PVOID context,
james@406 416 xenbus_transaction_t xbt,
james@504 417 char *path,
james@504 418 int index)
james@406 419 {
james@406 420 struct xsd_sockmsg *rep;
james@406 421 char *msg;
james@406 422 char Token[20];
james@406 423 struct write_req req[2];
james@406 424
james@406 425 req[0].data = path;
james@406 426 req[0].len = (ULONG)strlen(path) + 1;
james@406 427
james@406 428 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
james@406 429 req[1].data = Token;
james@406 430 req[1].len = (ULONG)strlen(Token) + 1;
james@406 431
james@504 432 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
james@406 433
james@406 434 msg = errmsg(rep);
james@406 435 if (msg)
james@406 436 return msg;
james@406 437
james@406 438 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@406 439
james@406 440 return NULL;
james@406 441 }
james@406 442
james@35 443 NTSTATUS
james@622 444 XenBus_Halt(PXENPCI_DEVICE_DATA xpdd)
james@35 445 {
james@406 446 int i;
james@35 447
james@406 448 FUNCTION_ENTER();
james@406 449
james@272 450 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 451
james@406 452 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@624 453 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@624 454 {
james@406 455 if (xpdd->XenBus_WatchEntries[i].Active)
james@624 456 {
james@624 457 xpdd->XenBus_WatchEntries[i].Active = 0;
james@406 458 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@624 459 }
james@406 460 }
james@406 461
james@624 462 XenBus_Disconnect(xpdd);
james@35 463
james@406 464 FUNCTION_EXIT();
james@35 465
james@0 466 return STATUS_SUCCESS;
james@0 467 }
james@0 468
james@0 469 char *
andy@13 470 XenBus_List(
andy@13 471 PVOID Context,
andy@13 472 xenbus_transaction_t xbt,
james@504 473 char *pre,
andy@13 474 char ***contents)
james@0 475 {
james@258 476 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 477 struct xsd_sockmsg *reply, *repmsg;
james@145 478 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
james@0 479 ULONG nr_elems, x, i;
james@0 480 char **res;
james@0 481 char *msg;
james@0 482
james@272 483 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@272 484
james@504 485 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
james@0 486 msg = errmsg(repmsg);
andy@15 487 if (msg)
andy@15 488 {
james@0 489 *contents = NULL;
james@0 490 return msg;
james@0 491 }
james@0 492 reply = repmsg + 1;
james@0 493 for (x = nr_elems = 0; x < repmsg->len; x++)
andy@15 494 {
james@0 495 nr_elems += (((char *)reply)[x] == 0);
andy@15 496 }
andy@15 497 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
andy@15 498 XENPCI_POOL_TAG);
andy@15 499 for (x = i = 0; i < nr_elems; i++)
andy@15 500 {
james@145 501 int l = (int)strlen((char *)reply + x);
james@0 502 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
james@0 503 memcpy(res[i], (char *)reply + x, l + 1);
james@0 504 x += l + 1;
james@0 505 }
james@0 506 res[i] = NULL;
james@0 507 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
james@0 508 *contents = res;
james@624 509
james@0 510 return NULL;
james@0 511 }
james@0 512
james@624 513 /* Called at PASSIVE_LEVEL */
james@279 514 static char *
james@279 515 XenBus_SendAddWatch(
james@279 516 PVOID Context,
james@279 517 xenbus_transaction_t xbt,
james@504 518 char *Path,
james@279 519 int slot)
james@279 520 {
james@279 521 PXENPCI_DEVICE_DATA xpdd = Context;
james@279 522 struct xsd_sockmsg *rep;
james@279 523 char *msg;
james@279 524 char Token[20];
james@279 525 struct write_req req[2];
james@279 526
james@279 527 req[0].data = Path;
james@279 528 req[0].len = (ULONG)strlen(Path) + 1;
james@279 529
james@279 530 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
james@279 531 req[1].data = Token;
james@279 532 req[1].len = (ULONG)strlen(Token) + 1;
james@279 533
james@504 534 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
james@404 535
james@279 536 msg = errmsg(rep);
james@283 537 if (!msg)
james@283 538 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@279 539
james@279 540 return msg;
james@279 541 }
james@279 542
james@342 543 /* called at PASSIVE_LEVEL */
james@390 544 NTSTATUS
james@409 545 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
james@409 546 {
james@409 547 int i;
james@409 548
james@409 549 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
james@409 550 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
james@409 551 if (xpdd->XenBus_WatchEntries[i].Active)
james@409 552 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@409 553 }
james@624 554 XenBus_Disconnect(xpdd);
james@624 555
james@409 556 return STATUS_SUCCESS;
james@409 557 }
james@409 558
james@409 559 /* called at PASSIVE_LEVEL */
james@409 560 NTSTATUS
james@279 561 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
james@279 562 {
james@390 563 NTSTATUS status;
james@279 564 int i;
james@341 565
andy@398 566 FUNCTION_ENTER();
james@342 567
james@390 568 status = XenBus_Connect(xpdd);
james@390 569 if (!NT_SUCCESS(status))
james@390 570 {
james@390 571 return status;
james@390 572 }
james@279 573
james@279 574 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@341 575 {
james@279 576 if (xpdd->XenBus_WatchEntries[i].Active)
james@341 577 {
james@536 578 //KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
james@279 579 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
james@341 580 }
james@341 581 }
andy@398 582 FUNCTION_EXIT();
james@390 583
james@390 584 return STATUS_SUCCESS;
james@279 585 }
james@279 586
james@0 587 char *
andy@15 588 XenBus_AddWatch(
andy@13 589 PVOID Context,
andy@13 590 xenbus_transaction_t xbt,
james@504 591 char *Path,
andy@13 592 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 593 PVOID ServiceContext)
james@0 594 {
james@258 595 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 596 char *msg;
james@0 597 int i;
andy@94 598 PXENBUS_WATCH_ENTRY w_entry;
james@0 599
james@272 600 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 601
andy@94 602 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
james@0 603
james@504 604 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 605
james@0 606 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
andy@15 607 if (xpdd->XenBus_WatchEntries[i].Active == 0)
james@0 608 break;
james@0 609
james@0 610 if (i == MAX_WATCH_ENTRIES)
james@0 611 {
james@0 612 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
james@504 613 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 614 return NULL;
james@0 615 }
james@0 616
andy@94 617 /* must init watchentry before starting watch */
james@128 618
andy@94 619 w_entry = &xpdd->XenBus_WatchEntries[i];
james@716 620 RtlStringCbCopyA(w_entry->Path, ARRAY_SIZE(w_entry->Path), Path);
andy@94 621 w_entry->ServiceRoutine = ServiceRoutine;
andy@94 622 w_entry->ServiceContext = ServiceContext;
andy@94 623 w_entry->Count = 0;
andy@94 624 w_entry->Active = 1;
andy@94 625
james@504 626 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@128 627
james@279 628 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
james@0 629
andy@93 630 if (msg)
andy@93 631 {
andy@93 632 xpdd->XenBus_WatchEntries[i].Active = 0;
andy@93 633 return msg;
andy@93 634 }
andy@93 635
james@0 636 return NULL;
james@0 637 }
james@0 638
james@0 639 char *
andy@13 640 XenBus_RemWatch(
andy@13 641 PVOID Context,
andy@13 642 xenbus_transaction_t xbt,
james@504 643 char *Path,
andy@13 644 PXENBUS_WATCH_CALLBACK ServiceRoutine,
andy@13 645 PVOID ServiceContext)
james@0 646 {
james@258 647 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 648 char *msg;
james@0 649 int i;
james@0 650
james@272 651 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 652
james@504 653 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
james@128 654
james@0 655 // check that Path < 128 chars
james@0 656
james@409 657 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
james@409 658 {
james@538 659 if (xpdd->XenBus_WatchEntries[i].Active
james@538 660 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
andy@15 661 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
andy@15 662 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
james@409 663 {
james@409 664 KdPrint((__DRIVER_NAME " Match\n"));
james@0 665 break;
james@409 666 }
james@0 667 }
james@0 668
james@0 669 if (i == MAX_WATCH_ENTRIES)
james@0 670 {
james@504 671 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 672 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
james@0 673 return NULL;
james@0 674 }
james@0 675
james@128 676 xpdd->XenBus_WatchEntries[i].Active = 0;
james@128 677 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
james@128 678
james@504 679 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
james@0 680
james@406 681 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
james@406 682
james@406 683 return msg;
james@0 684 }
james@0 685
james@0 686 char *
andy@13 687 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
james@0 688 {
james@258 689 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 690 /* xenstored becomes angry if you send a length 0 message, so just
james@0 691 shove a nul terminator on the end */
james@0 692 struct write_req req = { "", 1};
james@0 693 struct xsd_sockmsg *rep;
james@0 694 char *err;
james@0 695
james@272 696 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@95 697
james@504 698 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
james@0 699 err = errmsg(rep);
james@0 700 if (err)
james@0 701 return err;
james@0 702 *xbt = atoi((char *)(rep + 1));
james@0 703 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 704
james@0 705 return NULL;
james@0 706 }
james@0 707
james@0 708 char *
andy@15 709 XenBus_EndTransaction(
andy@15 710 PVOID Context,
andy@15 711 xenbus_transaction_t t,
andy@15 712 int abort,
andy@15 713 int *retry)
james@0 714 {
james@258 715 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 716 struct xsd_sockmsg *rep;
james@0 717 struct write_req req;
james@0 718 char *err;
james@0 719
james@0 720 *retry = 0;
james@0 721
james@0 722 req.data = abort ? "F" : "T";
james@0 723 req.len = 2;
james@504 724 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
james@0 725 err = errmsg(rep);
james@0 726 if (err) {
james@0 727 if (!strcmp(err, "EAGAIN")) {
james@0 728 *retry = 1;
james@0 729 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
james@0 730 return NULL;
james@0 731 } else {
james@0 732 return err;
james@0 733 }
james@0 734 }
james@0 735 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
james@95 736
james@0 737 return NULL;
james@0 738 }
james@0 739
james@0 740 char *
andy@15 741 XenBus_Printf(
andy@15 742 PVOID Context,
andy@15 743 xenbus_transaction_t xbt,
james@504 744 char *path,
james@504 745 char *fmt,
andy@15 746 ...)
james@0 747 {
james@258 748 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 749 va_list ap;
andy@101 750 char buf[512];
james@95 751 char *retval;
james@95 752
james@272 753 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
james@0 754
james@0 755 va_start(ap, fmt);
james@0 756 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
james@0 757 va_end(ap);
james@258 758 retval = XenBus_Write(xpdd, xbt, path, buf);
james@95 759
james@95 760 return retval;
andy@37 761 }