win-pvdrivers

annotate xenpci/xenbus_device_interface.c @ 804:6ea80e94e8cf

Added tag 0.11.0.218 for changeset bbc6c94b9621
author James Harper <james.harper@bendigoit.com.au>
date Sun Jun 27 16:15:21 2010 +1000 (2010-06-27)
parents 5bdb7251370c
children
rev   line source
james@504 1 /*
james@504 2 PV Drivers for Windows Xen HVM Domains
james@504 3 Copyright (C) 2007 James Harper
james@504 4
james@504 5 This program is free software; you can redistribute it and/or
james@504 6 modify it under the terms of the GNU General Public License
james@504 7 as published by the Free Software Foundation; either version 2
james@504 8 of the License, or (at your option) any later version.
james@504 9
james@504 10 This program is distributed in the hope that it will be useful,
james@504 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@504 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@504 13 GNU General Public License for more details.
james@504 14
james@504 15 You should have received a copy of the GNU General Public License
james@504 16 along with this program; if not, write to the Free Software
james@504 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@504 18 */
james@504 19
james@504 20 #include "xenpci.h"
james@504 21
james@716 22 /* Not really necessary but keeps PREfast happy */
james@716 23 static EVT_WDF_FILE_CLEANUP XenBus_EvtFileCleanup;
james@716 24 static EVT_WDF_FILE_CLOSE XenBus_EvtFileClose;
james@716 25 static EVT_WDF_IO_QUEUE_IO_READ XenBus_EvtIoRead;
james@716 26 static EVT_WDF_IO_QUEUE_IO_WRITE XenBus_EvtIoWrite;
james@716 27
james@536 28 typedef struct {
james@536 29 LIST_ENTRY entry;
james@536 30 PVOID data;
james@536 31 ULONG length;
james@536 32 ULONG offset;
james@536 33 } xenbus_read_queue_item_t;
james@536 34
james@536 35 typedef struct
james@536 36 {
james@536 37 LIST_ENTRY entry;
james@536 38 CHAR path[128];
james@536 39 CHAR token[128];
james@536 40 WDFFILEOBJECT file_object;
james@536 41 } watch_context_t;
james@536 42
james@671 43 static VOID
james@671 44 XenBus_ProcessReadRequest(WDFQUEUE queue, WDFREQUEST request, size_t length)
james@536 45 {
james@536 46 NTSTATUS status;
james@536 47 WDFFILEOBJECT file_object = WdfRequestGetFileObject(request);
james@536 48 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@537 49 ULONG dst_length = (ULONG)length;
james@536 50 ULONG dst_offset = 0;
james@536 51 ULONG copy_length;
james@536 52 xenbus_read_queue_item_t *list_entry;
james@536 53 PVOID buffer;
james@536 54
james@536 55 UNREFERENCED_PARAMETER(queue);
james@536 56
james@536 57 status = WdfRequestRetrieveOutputBuffer(request, length, &buffer, NULL);
james@536 58 if (!NT_SUCCESS(status))
james@536 59 {
james@536 60 KdPrint((__DRIVER_NAME, " WdfRequestRetrieveOutputBuffer failed status = %08x\n", status));
james@536 61 WdfRequestSetInformation(request, 0);
james@536 62 return;
james@536 63 }
james@536 64 ASSERT(NT_SUCCESS(status)); // lazy?
james@536 65
james@671 66 while(dst_offset < dst_length && (list_entry = (xenbus_read_queue_item_t *)RemoveHeadList(&xpdid->xenbus.read_list_head)) != (xenbus_read_queue_item_t *)&xpdid->xenbus.read_list_head)
james@536 67 {
james@536 68 copy_length = min(list_entry->length - list_entry->offset, dst_length - dst_offset);
james@536 69 memcpy((PUCHAR)buffer + dst_offset, (PUCHAR)list_entry->data + list_entry->offset, copy_length);
james@536 70 list_entry->offset += copy_length;
james@536 71 dst_offset += copy_length;
james@536 72 if (list_entry->offset == list_entry->length)
james@536 73 {
james@537 74 ExFreePoolWithTag(list_entry->data, XENPCI_POOL_TAG);
james@537 75 ExFreePoolWithTag(list_entry, XENPCI_POOL_TAG);
james@536 76 }
james@536 77 else
james@536 78 {
james@671 79 InsertHeadList(&xpdid->xenbus.read_list_head, (PLIST_ENTRY)list_entry);
james@536 80 }
james@536 81 }
james@536 82 WdfRequestSetInformation(request, dst_offset);
james@536 83
james@536 84 FUNCTION_EXIT();
james@536 85 }
james@536 86
james@536 87 static VOID
james@536 88 XenPci_IoWatch(char *path, PVOID context)
james@536 89 {
james@536 90 NTSTATUS status;
james@536 91 watch_context_t *watch_context = context;
james@536 92 WDFFILEOBJECT file_object = watch_context->file_object;
james@536 93 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 94 KIRQL old_irql;
james@536 95 struct xsd_sockmsg *rep;
james@536 96 xenbus_read_queue_item_t *list_entry;
james@537 97 size_t remaining;
james@536 98 WDFREQUEST request;
james@536 99
james@536 100 FUNCTION_ENTER();
james@536 101
james@536 102 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 103
james@537 104 remaining = sizeof(struct xsd_sockmsg) + strlen(path) + 1 + strlen(watch_context->token) + 1;
james@536 105 rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg) + strlen(path) + 1 + strlen(watch_context->token) + 1, XENPCI_POOL_TAG);
james@536 106 rep->type = XS_WATCH_EVENT;
james@536 107 rep->req_id = 0;
james@536 108 rep->tx_id = 0;
james@537 109 rep->len = (ULONG)(strlen(path) + 1 + strlen(watch_context->token) + 1);
james@537 110 remaining -= sizeof(struct xsd_sockmsg);
james@537 111 RtlStringCbCopyA((PCHAR)(rep + 1), remaining, path);
james@537 112 remaining -= strlen(path) + 1;
james@537 113 RtlStringCbCopyA((PCHAR)(rep + 1) + strlen(path) + 1, remaining, watch_context->token);
james@536 114
james@536 115 list_entry = (xenbus_read_queue_item_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(xenbus_read_queue_item_t), XENPCI_POOL_TAG);
james@536 116 list_entry->data = rep;
james@536 117 list_entry->length = sizeof(*rep) + rep->len;
james@536 118 list_entry->offset = 0;
james@671 119 InsertTailList(&xpdid->xenbus.read_list_head, (PLIST_ENTRY)list_entry);
james@536 120
james@671 121 status = WdfIoQueueRetrieveNextRequest(xpdid->xenbus.io_queue, &request);
james@536 122 if (NT_SUCCESS(status))
james@536 123 {
james@536 124 WDF_REQUEST_PARAMETERS parameters;
james@536 125 WDF_REQUEST_PARAMETERS_INIT(&parameters);
james@536 126 WdfRequestGetParameters(request, &parameters);
james@536 127
james@536 128 KdPrint((__DRIVER_NAME " found pending read - MinorFunction = %d, length = %d\n", (ULONG)parameters.MinorFunction, (ULONG)parameters.Parameters.Read.Length));
james@671 129 XenBus_ProcessReadRequest(xpdid->xenbus.io_queue, request, parameters.Parameters.Read.Length);
james@536 130 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 131 WdfRequestComplete(request, STATUS_SUCCESS);
james@536 132 }
james@536 133 else
james@536 134 {
james@536 135 KdPrint((__DRIVER_NAME " no pending read (%08x)\n", status));
james@536 136 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 137 }
james@536 138
james@536 139 FUNCTION_EXIT();
james@536 140 }
james@536 141
james@671 142 static VOID
james@671 143 XenBus_EvtFileCleanup(WDFFILEOBJECT file_object)
james@536 144 {
james@536 145 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 146 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfFileObjectGetDevice(file_object));
james@536 147 watch_context_t *watch_context;
james@536 148 KIRQL old_irql;
james@536 149 PCHAR msg;
james@536 150
james@536 151 FUNCTION_ENTER();
james@536 152
james@536 153 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 154
james@671 155 while (!IsListEmpty(&xpdid->xenbus.watch_list_head))
james@536 156 {
james@671 157 watch_context = (watch_context_t *)RemoveHeadList(&xpdid->xenbus.watch_list_head);
james@536 158 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 159 msg = XenBus_RemWatch(xpdd, XBT_NIL, watch_context->path, XenPci_IoWatch, watch_context);
james@536 160 if (msg != NULL)
james@536 161 {
james@536 162 KdPrint((__DRIVER_NAME " Error freeing watch (%s)\n", msg));
james@536 163 XenPci_FreeMem(msg);
james@536 164 }
james@536 165 ExFreePoolWithTag(watch_context, XENPCI_POOL_TAG);
james@536 166 WdfObjectDereference(file_object);
james@536 167 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 168 }
james@536 169
james@536 170 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 171
james@536 172 FUNCTION_EXIT();
james@536 173 }
james@536 174
james@671 175 static VOID
james@671 176 XenBus_EvtFileClose(WDFFILEOBJECT file_object)
james@536 177 {
james@536 178 UNREFERENCED_PARAMETER(file_object);
james@536 179 FUNCTION_ENTER();
james@536 180 FUNCTION_EXIT();
james@536 181 }
james@536 182
james@671 183 static VOID
james@671 184 XenBus_EvtIoRead(WDFQUEUE queue, WDFREQUEST request, size_t length)
james@536 185 {
james@536 186 NTSTATUS status;
james@536 187 WDFFILEOBJECT file_object = WdfRequestGetFileObject(request);
james@536 188 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 189 KIRQL old_irql;
james@536 190
james@537 191 UNREFERENCED_PARAMETER(queue);
james@537 192
james@536 193 FUNCTION_ENTER();
james@671 194 status = WdfRequestForwardToIoQueue(request, xpdid->xenbus.io_queue);
james@536 195 if (!NT_SUCCESS(status))
james@536 196 {
james@536 197 KdPrint((__DRIVER_NAME " could not forward request (%08x)\n", status));
james@536 198 }
james@536 199 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@671 200 if (!IsListEmpty(&xpdid->xenbus.read_list_head))
james@536 201 {
james@671 202 status = WdfIoQueueRetrieveNextRequest(xpdid->xenbus.io_queue, &request);
james@536 203 if (NT_SUCCESS(status))
james@536 204 {
james@536 205 KdPrint((__DRIVER_NAME " found pending read\n"));
james@671 206 XenBus_ProcessReadRequest(xpdid->xenbus.io_queue, request, length);
james@536 207 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 208 WdfRequestComplete(request, STATUS_SUCCESS);
james@536 209 }
james@536 210 else
james@536 211 {
james@536 212 KdPrint((__DRIVER_NAME " no pending read (%08x)\n", status));
james@536 213 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 214 }
james@536 215 }
james@536 216 else
james@536 217 {
james@536 218 KdPrint((__DRIVER_NAME " no data to read\n"));
james@536 219 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 220 }
james@536 221
james@536 222 FUNCTION_EXIT();
james@536 223 return;
james@536 224 }
james@536 225
james@671 226 static VOID
james@671 227 XenBus_EvtIoWrite(WDFQUEUE queue, WDFREQUEST request, size_t length)
james@536 228 {
james@536 229 NTSTATUS status;
james@536 230 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfIoQueueGetDevice(queue));
james@536 231 WDFFILEOBJECT file_object = WdfRequestGetFileObject(request);
james@536 232 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 233 KIRQL old_irql;
james@536 234 PUCHAR buffer;
james@536 235 PUCHAR src_ptr;
james@536 236 ULONG src_len;
james@536 237 PUCHAR dst_ptr;
james@536 238 ULONG copy_len;
james@536 239 struct xsd_sockmsg *rep;
james@536 240 xenbus_read_queue_item_t *list_entry;
james@536 241 watch_context_t *watch_context;
james@536 242 PCHAR watch_path;
james@536 243 PCHAR watch_token;
james@536 244 PCHAR msg;
james@536 245
james@536 246 FUNCTION_ENTER();
james@536 247
james@536 248 status = WdfRequestRetrieveInputBuffer(request, length, &buffer, NULL);
james@536 249 ASSERT(NT_SUCCESS(status));
james@536 250
james@536 251 src_ptr = (PUCHAR)buffer;
james@537 252 src_len = (ULONG)length;
james@671 253 dst_ptr = xpdid->xenbus.u.buffer + xpdid->xenbus.len;
james@536 254 while (src_len != 0)
james@536 255 {
james@536 256 KdPrint((__DRIVER_NAME " %d bytes of write buffer remaining\n", src_len));
james@536 257 /* get a complete msg header */
james@671 258 if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg))
james@536 259 {
james@671 260 copy_len = min(sizeof(xpdid->xenbus.u.msg) - xpdid->xenbus.len, src_len);
james@536 261 if (!copy_len)
james@536 262 continue;
james@536 263 memcpy(dst_ptr, src_ptr, copy_len);
james@536 264 dst_ptr += copy_len;
james@536 265 src_ptr += copy_len;
james@536 266 src_len -= copy_len;
james@671 267 xpdid->xenbus.len += copy_len;
james@536 268 }
james@536 269 /* exit if we can't get that */
james@671 270 if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg))
james@536 271 continue;
james@536 272 /* get a complete msg body */
james@671 273 if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len)
james@536 274 {
james@671 275 copy_len = min(sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len - xpdid->xenbus.len, src_len);
james@536 276 if (!copy_len)
james@536 277 continue;
james@536 278 memcpy(dst_ptr, src_ptr, copy_len);
james@536 279 dst_ptr += copy_len;
james@536 280 src_ptr += copy_len;
james@536 281 src_len -= copy_len;
james@671 282 xpdid->xenbus.len += copy_len;
james@536 283 }
james@536 284 /* exit if we can't get that */
james@671 285 if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len)
james@536 286 {
james@536 287 continue;
james@536 288 }
james@536 289
james@671 290 switch (xpdid->xenbus.u.msg.type)
james@536 291 {
james@536 292 case XS_WATCH:
james@536 293 case XS_UNWATCH:
james@536 294 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 295 watch_context = (watch_context_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(watch_context_t), XENPCI_POOL_TAG);
james@671 296 watch_path = (PCHAR)(xpdid->xenbus.u.buffer + sizeof(struct xsd_sockmsg));
james@671 297 watch_token = (PCHAR)(xpdid->xenbus.u.buffer + sizeof(struct xsd_sockmsg) + strlen(watch_path) + 1);
james@537 298 RtlStringCbCopyA(watch_context->path, ARRAY_SIZE(watch_context->path), watch_path);
james@537 299 RtlStringCbCopyA(watch_context->token, ARRAY_SIZE(watch_context->path), watch_token);
james@536 300 watch_context->file_object = file_object;
james@671 301 if (xpdid->xenbus.u.msg.type == XS_WATCH)
james@671 302 InsertTailList(&xpdid->xenbus.watch_list_head, &watch_context->entry);
james@536 303 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@671 304 if (xpdid->xenbus.u.msg.type == XS_WATCH)
james@536 305 msg = XenBus_AddWatch(xpdd, XBT_NIL, watch_path, XenPci_IoWatch, watch_context);
james@536 306 else
james@536 307 msg = XenBus_RemWatch(xpdd, XBT_NIL, watch_path, XenPci_IoWatch, watch_context);
james@536 308 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 309 if (msg != NULL)
james@536 310 {
james@536 311 rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg) + strlen(msg) + 1, XENPCI_POOL_TAG);
james@536 312 rep->type = XS_ERROR;
james@671 313 rep->req_id = xpdid->xenbus.u.msg.req_id;
james@671 314 rep->tx_id = xpdid->xenbus.u.msg.tx_id;
james@537 315 rep->len = (ULONG)(strlen(msg) + 0);
james@537 316 RtlStringCbCopyA((PCHAR)(rep + 1), strlen(msg) + 1, msg);
james@671 317 if (xpdid->xenbus.u.msg.type == XS_WATCH)
james@536 318 RemoveEntryList(&watch_context->entry);
james@536 319 }
james@536 320 else
james@536 321 {
james@671 322 if (xpdid->xenbus.u.msg.type == XS_WATCH)
james@536 323 {
james@536 324 WdfObjectReference(file_object);
james@536 325 }
james@536 326 else
james@536 327 {
james@536 328 RemoveEntryList(&watch_context->entry);
james@536 329 WdfObjectDereference(file_object);
james@536 330 }
james@536 331 rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg), XENPCI_POOL_TAG);
james@671 332 rep->type = xpdid->xenbus.u.msg.type;
james@671 333 rep->req_id = xpdid->xenbus.u.msg.req_id;
james@671 334 rep->tx_id = xpdid->xenbus.u.msg.tx_id;
james@536 335 rep->len = 0;
james@536 336 }
james@536 337 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 338 break;
james@536 339 default:
james@671 340 rep = XenBus_Raw(xpdd, &xpdid->xenbus.u.msg);
james@536 341 break;
james@536 342 }
james@671 343 xpdid->xenbus.len = 0;
james@536 344
james@536 345 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 346 list_entry = (xenbus_read_queue_item_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(xenbus_read_queue_item_t), XENPCI_POOL_TAG);
james@536 347 list_entry->data = rep;
james@536 348 list_entry->length = sizeof(*rep) + rep->len;
james@536 349 list_entry->offset = 0;
james@671 350 InsertTailList(&xpdid->xenbus.read_list_head, (PLIST_ENTRY)list_entry);
james@536 351 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 352 }
james@536 353 KdPrint((__DRIVER_NAME " completing request with length %d\n", length));
james@536 354 WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, length);
james@536 355
james@536 356 FUNCTION_EXIT();
james@671 357 }
james@671 358
james@671 359 NTSTATUS
james@671 360 XenBus_DeviceFileInit(WDFDEVICE device, PWDF_IO_QUEUE_CONFIG queue_config, WDFFILEOBJECT file_object)
james@671 361 {
james@671 362 NTSTATUS status;
james@671 363 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@671 364 WDF_IO_QUEUE_CONFIG internal_queue_config;
james@671 365
james@671 366 FUNCTION_ENTER();
james@671 367
james@671 368 xpdid->EvtFileCleanup = XenBus_EvtFileCleanup;
james@671 369 xpdid->EvtFileClose = XenBus_EvtFileClose;
james@671 370 queue_config->EvtIoRead = XenBus_EvtIoRead;
james@671 371 queue_config->EvtIoWrite = XenBus_EvtIoWrite;
james@671 372 // queue_config->EvtIoDeviceControl = XenBus_EvtIoDeviceControl;
james@671 373
james@671 374 InitializeListHead(&xpdid->xenbus.read_list_head);
james@671 375 InitializeListHead(&xpdid->xenbus.watch_list_head);
james@671 376 xpdid->xenbus.len = 0;
james@671 377 WDF_IO_QUEUE_CONFIG_INIT(&internal_queue_config, WdfIoQueueDispatchManual);
james@671 378
james@671 379 status = WdfIoQueueCreate(device, &internal_queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdid->xenbus.io_queue);
james@671 380 if (!NT_SUCCESS(status)) {
james@671 381 KdPrint(("Error creating queue 0x%x\n", status));
james@671 382 FUNCTION_EXIT();
james@671 383 return status;
james@671 384 }
james@671 385
james@671 386 FUNCTION_EXIT();
james@671 387
james@671 388 return status;
james@671 389 }