win-pvdrivers

annotate xenpci/xenbus.c @ 835:e5651aba4e03

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