win-pvdrivers
annotate xenpci/xenbus.c @ 1022:cd72cd0e1c19
hooking debug doesn't survive hibernate under win8. Remove it.
Remove initial balloon down - doesn't work under xen 4.2 without xenbus being loaded
Remove initial balloon down - doesn't work under xen 4.2 without xenbus being loaded
author | James Harper <james.harper@bendigoit.com.au> |
---|---|
date | Tue Feb 19 15:11:49 2013 +1100 (2013-02-19) |
parents | df03fde445b8 |
children | 37c0c84a42e8 |
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@1022 | 83 XN_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@1005 | 98 EvtChn_Notify(xpdd, xpdd->xenbus_event); |
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@1022 | 178 XN_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@1022 | 213 XN_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@1004 | 234 PXN_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@853 | 278 ULONG rsp_prod; |
james@515 | 279 |
james@624 | 280 //FUNCTION_ENTER(); |
james@646 | 281 |
james@646 | 282 KeAcquireSpinLockAtDpcLevel(&xpdd->xb_ring_spinlock); |
james@515 | 283 |
james@853 | 284 /* snapshot rsp_prod so it doesn't change while we are looking at it */ |
james@853 | 285 while ((rsp_prod = xpdd->xen_store_interface->rsp_prod) != xpdd->xen_store_interface->rsp_cons) |
james@624 | 286 { |
james@853 | 287 KeMemoryBarrier(); /* make sure the data in the ring is valid */ |
james@683 | 288 if (!xpdd->xb_msg) |
james@624 | 289 { |
james@853 | 290 if (rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(xsd_sockmsg_t)) |
james@683 | 291 { |
james@790 | 292 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n")); |
james@683 | 293 break; |
james@683 | 294 } |
james@683 | 295 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg, |
james@683 | 296 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(xsd_sockmsg_t)); |
james@683 | 297 xpdd->xb_msg = ExAllocatePoolWithTag(NonPagedPool, sizeof(xsd_sockmsg_t) + msg.len, XENPCI_POOL_TAG); |
james@683 | 298 memcpy(xpdd->xb_msg, &msg, sizeof(xsd_sockmsg_t)); |
james@683 | 299 xpdd->xb_msg_offset = sizeof(xsd_sockmsg_t); |
james@683 | 300 xpdd->xen_store_interface->rsp_cons += sizeof(xsd_sockmsg_t); |
james@624 | 301 } |
james@683 | 302 |
james@853 | 303 msg_len = min(rsp_prod - xpdd->xen_store_interface->rsp_cons, sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len - xpdd->xb_msg_offset); |
james@1022 | 304 XN_ASSERT(xpdd->xb_msg_offset + msg_len <= sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len); |
james@683 | 305 memcpy_from_ring(xpdd->xen_store_interface->rsp, |
james@683 | 306 (PUCHAR)xpdd->xb_msg + xpdd->xb_msg_offset, |
james@683 | 307 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), |
james@683 | 308 msg_len); |
james@683 | 309 xpdd->xen_store_interface->rsp_cons += msg_len; |
james@683 | 310 xpdd->xb_msg_offset += msg_len; |
james@683 | 311 |
james@683 | 312 if (xpdd->xb_msg_offset < sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len) |
james@624 | 313 { |
james@790 | 314 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n")); |
james@1005 | 315 EvtChn_Notify(xpdd, xpdd->xenbus_event); /* there is room on the ring now */ |
james@624 | 316 break; |
james@624 | 317 } |
james@515 | 318 |
james@683 | 319 if (xpdd->xb_msg->type != XS_WATCH_EVENT) |
james@624 | 320 { |
james@624 | 321 /* process reply - only ever one outstanding */ |
james@1022 | 322 XN_ASSERT(xpdd->xb_reply == NULL); |
james@683 | 323 xpdd->xb_reply = xpdd->xb_msg; |
james@683 | 324 xpdd->xb_msg = NULL; |
james@624 | 325 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE); |
james@624 | 326 } |
james@624 | 327 else |
james@624 | 328 { |
james@624 | 329 /* process watch */ |
james@624 | 330 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenBus_WatchWorkItemProc); |
james@624 | 331 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workitem_attributes, xsd_sockmsg_t); |
james@624 | 332 workitem_attributes.ParentObject = xpdd->wdf_device; |
james@683 | 333 workitem_attributes.ContextSizeOverride = xpdd->xb_msg_offset; |
james@624 | 334 status = WdfWorkItemCreate(&workitem_config, &workitem_attributes, &workitem); |
james@624 | 335 if (!NT_SUCCESS(status)) |
james@624 | 336 { |
james@624 | 337 KdPrint((__DRIVER_NAME " Failed to create work item for watch\n")); |
james@624 | 338 continue; |
james@624 | 339 } |
james@683 | 340 memcpy(WdfObjectGetTypedContext(workitem, xsd_sockmsg_t), xpdd->xb_msg, xpdd->xb_msg_offset); |
james@683 | 341 xpdd->xb_msg = NULL; |
james@624 | 342 WdfWorkItemEnqueue(workitem); |
james@624 | 343 } |
james@1005 | 344 EvtChn_Notify(xpdd, xpdd->xenbus_event); /* there is room on the ring now */ |
james@624 | 345 } |
james@646 | 346 KeReleaseSpinLockFromDpcLevel(&xpdd->xb_ring_spinlock); |
james@624 | 347 |
james@624 | 348 //FUNCTION_EXIT(); |
james@515 | 349 } |
james@515 | 350 |
james@624 | 351 static NTSTATUS |
james@342 | 352 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd) |
james@342 | 353 { |
james@342 | 354 PHYSICAL_ADDRESS pa_xen_store_interface; |
james@342 | 355 xen_ulong_t xen_store_mfn; |
james@342 | 356 |
james@1005 | 357 xpdd->xenbus_event = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN); |
james@342 | 358 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN); |
james@342 | 359 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT; |
james@342 | 360 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached); |
james@342 | 361 |
james@1005 | 362 EvtChn_BindDpc(xpdd, xpdd->xenbus_event, XenBus_Dpc, xpdd, EVT_ACTION_FLAGS_NO_SUSPEND); |
james@624 | 363 |
james@624 | 364 return STATUS_SUCCESS; |
james@624 | 365 } |
james@624 | 366 |
james@624 | 367 static NTSTATUS |
james@624 | 368 XenBus_Disconnect(PXENPCI_DEVICE_DATA xpdd) |
james@624 | 369 { |
james@1005 | 370 EvtChn_Unbind(xpdd, xpdd->xenbus_event); |
james@624 | 371 |
james@624 | 372 MmUnmapIoSpace(xpdd->xen_store_interface, PAGE_SIZE); |
james@390 | 373 |
james@390 | 374 return STATUS_SUCCESS; |
james@342 | 375 } |
james@342 | 376 |
james@0 | 377 NTSTATUS |
james@258 | 378 XenBus_Init(PXENPCI_DEVICE_DATA xpdd) |
james@0 | 379 { |
james@390 | 380 NTSTATUS status; |
james@35 | 381 int i; |
andy@37 | 382 |
james@624 | 383 FUNCTION_ENTER(); |
james@35 | 384 |
james@1022 | 385 XN_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); |
james@35 | 386 |
james@646 | 387 KeInitializeSpinLock(&xpdd->xb_ring_spinlock); |
james@504 | 388 ExInitializeFastMutex(&xpdd->xb_request_mutex); |
james@504 | 389 ExInitializeFastMutex(&xpdd->xb_watch_mutex); |
james@128 | 390 |
james@35 | 391 for (i = 0; i < MAX_WATCH_ENTRIES; i++) |
james@128 | 392 { |
andy@38 | 393 xpdd->XenBus_WatchEntries[i].Active = 0; |
james@128 | 394 } |
james@0 | 395 |
james@504 | 396 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE); |
james@504 | 397 |
james@390 | 398 status = XenBus_Connect(xpdd); |
james@390 | 399 if (!NT_SUCCESS(status)) |
andy@101 | 400 { |
james@673 | 401 FUNCTION_EXIT(); |
james@390 | 402 return status; |
andy@101 | 403 } |
james@342 | 404 |
james@624 | 405 FUNCTION_EXIT(); |
james@0 | 406 |
james@0 | 407 return STATUS_SUCCESS; |
james@0 | 408 } |
james@0 | 409 |
james@406 | 410 char * |
james@406 | 411 XenBus_SendRemWatch( |
james@406 | 412 PVOID context, |
james@406 | 413 xenbus_transaction_t xbt, |
james@504 | 414 char *path, |
james@504 | 415 int index) |
james@406 | 416 { |
james@406 | 417 struct xsd_sockmsg *rep; |
james@406 | 418 char *msg; |
james@406 | 419 char Token[20]; |
james@406 | 420 struct write_req req[2]; |
james@406 | 421 |
james@406 | 422 req[0].data = path; |
james@406 | 423 req[0].len = (ULONG)strlen(path) + 1; |
james@406 | 424 |
james@406 | 425 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index); |
james@406 | 426 req[1].data = Token; |
james@406 | 427 req[1].len = (ULONG)strlen(Token) + 1; |
james@406 | 428 |
james@504 | 429 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req)); |
james@406 | 430 |
james@406 | 431 msg = errmsg(rep); |
james@406 | 432 if (msg) |
james@406 | 433 return msg; |
james@406 | 434 |
james@406 | 435 ExFreePoolWithTag(rep, XENPCI_POOL_TAG); |
james@406 | 436 |
james@406 | 437 return NULL; |
james@406 | 438 } |
james@406 | 439 |
james@35 | 440 NTSTATUS |
james@622 | 441 XenBus_Halt(PXENPCI_DEVICE_DATA xpdd) |
james@35 | 442 { |
james@406 | 443 int i; |
james@35 | 444 |
james@406 | 445 FUNCTION_ENTER(); |
james@406 | 446 |
james@1022 | 447 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); |
james@272 | 448 |
james@406 | 449 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */ |
james@624 | 450 for (i = 0; i < MAX_WATCH_ENTRIES; i++) |
james@624 | 451 { |
james@406 | 452 if (xpdd->XenBus_WatchEntries[i].Active) |
james@624 | 453 { |
james@624 | 454 xpdd->XenBus_WatchEntries[i].Active = 0; |
james@406 | 455 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i); |
james@624 | 456 } |
james@406 | 457 } |
james@406 | 458 |
james@624 | 459 XenBus_Disconnect(xpdd); |
james@35 | 460 |
james@406 | 461 FUNCTION_EXIT(); |
james@35 | 462 |
james@0 | 463 return STATUS_SUCCESS; |
james@0 | 464 } |
james@0 | 465 |
james@0 | 466 char * |
andy@13 | 467 XenBus_List( |
andy@13 | 468 PVOID Context, |
andy@13 | 469 xenbus_transaction_t xbt, |
james@504 | 470 char *pre, |
andy@13 | 471 char ***contents) |
james@0 | 472 { |
james@258 | 473 PXENPCI_DEVICE_DATA xpdd = Context; |
james@0 | 474 struct xsd_sockmsg *reply, *repmsg; |
james@145 | 475 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } }; |
james@0 | 476 ULONG nr_elems, x, i; |
james@0 | 477 char **res; |
james@0 | 478 char *msg; |
james@0 | 479 |
james@1022 | 480 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); |
james@272 | 481 |
james@504 | 482 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req)); |
james@0 | 483 msg = errmsg(repmsg); |
andy@15 | 484 if (msg) |
andy@15 | 485 { |
james@0 | 486 *contents = NULL; |
james@0 | 487 return msg; |
james@0 | 488 } |
james@0 | 489 reply = repmsg + 1; |
james@0 | 490 for (x = nr_elems = 0; x < repmsg->len; x++) |
andy@15 | 491 { |
james@0 | 492 nr_elems += (((char *)reply)[x] == 0); |
andy@15 | 493 } |
andy@15 | 494 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1), |
andy@15 | 495 XENPCI_POOL_TAG); |
andy@15 | 496 for (x = i = 0; i < nr_elems; i++) |
andy@15 | 497 { |
james@145 | 498 int l = (int)strlen((char *)reply + x); |
james@0 | 499 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG); |
james@0 | 500 memcpy(res[i], (char *)reply + x, l + 1); |
james@0 | 501 x += l + 1; |
james@0 | 502 } |
james@0 | 503 res[i] = NULL; |
james@0 | 504 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG); |
james@0 | 505 *contents = res; |
james@624 | 506 |
james@0 | 507 return NULL; |
james@0 | 508 } |
james@0 | 509 |
james@624 | 510 /* Called at PASSIVE_LEVEL */ |
james@279 | 511 static char * |
james@279 | 512 XenBus_SendAddWatch( |
james@279 | 513 PVOID Context, |
james@279 | 514 xenbus_transaction_t xbt, |
james@504 | 515 char *Path, |
james@279 | 516 int slot) |
james@279 | 517 { |
james@279 | 518 PXENPCI_DEVICE_DATA xpdd = Context; |
james@279 | 519 struct xsd_sockmsg *rep; |
james@279 | 520 char *msg; |
james@279 | 521 char Token[20]; |
james@279 | 522 struct write_req req[2]; |
james@279 | 523 |
james@279 | 524 req[0].data = Path; |
james@279 | 525 req[0].len = (ULONG)strlen(Path) + 1; |
james@279 | 526 |
james@279 | 527 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot); |
james@279 | 528 req[1].data = Token; |
james@279 | 529 req[1].len = (ULONG)strlen(Token) + 1; |
james@279 | 530 |
james@504 | 531 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req)); |
james@404 | 532 |
james@279 | 533 msg = errmsg(rep); |
james@283 | 534 if (!msg) |
james@283 | 535 ExFreePoolWithTag(rep, XENPCI_POOL_TAG); |
james@279 | 536 |
james@279 | 537 return msg; |
james@279 | 538 } |
james@279 | 539 |
james@342 | 540 /* called at PASSIVE_LEVEL */ |
james@390 | 541 NTSTATUS |
james@409 | 542 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd) |
james@409 | 543 { |
james@409 | 544 int i; |
james@409 | 545 |
james@409 | 546 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */ |
james@409 | 547 for (i = 0; i < MAX_WATCH_ENTRIES; i++) { |
james@409 | 548 if (xpdd->XenBus_WatchEntries[i].Active) |
james@409 | 549 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i); |
james@409 | 550 } |
james@624 | 551 XenBus_Disconnect(xpdd); |
james@624 | 552 |
james@409 | 553 return STATUS_SUCCESS; |
james@409 | 554 } |
james@409 | 555 |
james@409 | 556 /* called at PASSIVE_LEVEL */ |
james@409 | 557 NTSTATUS |
james@279 | 558 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd) |
james@279 | 559 { |
james@390 | 560 NTSTATUS status; |
james@279 | 561 int i; |
james@341 | 562 |
andy@398 | 563 FUNCTION_ENTER(); |
james@342 | 564 |
james@390 | 565 status = XenBus_Connect(xpdd); |
james@390 | 566 if (!NT_SUCCESS(status)) |
james@390 | 567 { |
james@390 | 568 return status; |
james@390 | 569 } |
james@279 | 570 |
james@279 | 571 for (i = 0; i < MAX_WATCH_ENTRIES; i++) |
james@341 | 572 { |
james@279 | 573 if (xpdd->XenBus_WatchEntries[i].Active) |
james@341 | 574 { |
james@835 | 575 KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path)); |
james@279 | 576 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i); |
james@341 | 577 } |
james@341 | 578 } |
james@835 | 579 |
andy@398 | 580 FUNCTION_EXIT(); |
james@390 | 581 |
james@390 | 582 return STATUS_SUCCESS; |
james@279 | 583 } |
james@279 | 584 |
james@0 | 585 char * |
andy@15 | 586 XenBus_AddWatch( |
andy@13 | 587 PVOID Context, |
andy@13 | 588 xenbus_transaction_t xbt, |
james@504 | 589 char *Path, |
james@1004 | 590 PXN_WATCH_CALLBACK ServiceRoutine, |
andy@13 | 591 PVOID ServiceContext) |
james@0 | 592 { |
james@258 | 593 PXENPCI_DEVICE_DATA xpdd = Context; |
james@0 | 594 char *msg; |
james@0 | 595 int i; |
andy@94 | 596 PXENBUS_WATCH_ENTRY w_entry; |
james@0 | 597 |
james@1022 | 598 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); |
james@0 | 599 |
james@1022 | 600 XN_ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path)); |
james@0 | 601 |
james@504 | 602 ExAcquireFastMutex(&xpdd->xb_watch_mutex); |
james@128 | 603 |
james@0 | 604 for (i = 0; i < MAX_WATCH_ENTRIES; i++) |
andy@15 | 605 if (xpdd->XenBus_WatchEntries[i].Active == 0) |
james@0 | 606 break; |
james@0 | 607 |
james@0 | 608 if (i == MAX_WATCH_ENTRIES) |
james@0 | 609 { |
james@0 | 610 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n")); |
james@504 | 611 ExReleaseFastMutex(&xpdd->xb_watch_mutex); |
james@0 | 612 return NULL; |
james@0 | 613 } |
james@0 | 614 |
andy@94 | 615 /* must init watchentry before starting watch */ |
james@128 | 616 |
andy@94 | 617 w_entry = &xpdd->XenBus_WatchEntries[i]; |
james@716 | 618 RtlStringCbCopyA(w_entry->Path, ARRAY_SIZE(w_entry->Path), Path); |
andy@94 | 619 w_entry->ServiceRoutine = ServiceRoutine; |
andy@94 | 620 w_entry->ServiceContext = ServiceContext; |
andy@94 | 621 w_entry->Count = 0; |
andy@94 | 622 w_entry->Active = 1; |
andy@94 | 623 |
james@504 | 624 ExReleaseFastMutex(&xpdd->xb_watch_mutex); |
james@128 | 625 |
james@279 | 626 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i); |
james@0 | 627 |
andy@93 | 628 if (msg) |
andy@93 | 629 { |
andy@93 | 630 xpdd->XenBus_WatchEntries[i].Active = 0; |
andy@93 | 631 return msg; |
andy@93 | 632 } |
andy@93 | 633 |
james@0 | 634 return NULL; |
james@0 | 635 } |
james@0 | 636 |
james@0 | 637 char * |
andy@13 | 638 XenBus_RemWatch( |
james@1019 | 639 PVOID Context, |
james@1019 | 640 xenbus_transaction_t xbt, |
james@1019 | 641 char *Path, |
james@1019 | 642 PXN_WATCH_CALLBACK ServiceRoutine, |
james@1019 | 643 PVOID ServiceContext) { |
james@258 | 644 PXENPCI_DEVICE_DATA xpdd = Context; |
james@0 | 645 char *msg; |
james@0 | 646 int i; |
james@0 | 647 |
james@1022 | 648 XN_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@1019 | 654 for (i = 0; i < MAX_WATCH_ENTRIES; i++) { |
james@538 | 655 if (xpdd->XenBus_WatchEntries[i].Active |
james@1019 | 656 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path) |
james@1019 | 657 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine |
james@1019 | 658 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext) { |
james@409 | 659 KdPrint((__DRIVER_NAME " Match\n")); |
james@0 | 660 break; |
james@409 | 661 } |
james@0 | 662 } |
james@0 | 663 |
james@1019 | 664 if (i == MAX_WATCH_ENTRIES) { |
james@504 | 665 ExReleaseFastMutex(&xpdd->xb_watch_mutex); |
james@835 | 666 KdPrint((__DRIVER_NAME " Watch not set for %s - can't remove\n", Path)); |
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@1022 | 690 XN_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@1022 | 747 XN_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 } |