win-pvdrivers

annotate xenpci/xenbus_device_interface.c @ 537:2a74ac2f43bb

more big updates
dma now working under xp
author James Harper <james.harper@bendigoit.com.au>
date Wed Feb 18 22:18:23 2009 +1100 (2009-02-18)
parents 1d39de3ab8d6
children 1bae3638ab55
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@536 22 typedef struct {
james@536 23 LIST_ENTRY entry;
james@536 24 PVOID data;
james@536 25 ULONG length;
james@536 26 ULONG offset;
james@536 27 } xenbus_read_queue_item_t;
james@536 28
james@536 29 typedef struct
james@536 30 {
james@536 31 LIST_ENTRY entry;
james@536 32 CHAR path[128];
james@536 33 CHAR token[128];
james@536 34 WDFFILEOBJECT file_object;
james@536 35 } watch_context_t;
james@536 36
james@536 37 VOID
james@536 38 XenPci_EvtDeviceFileCreate(WDFDEVICE device, WDFREQUEST request, WDFFILEOBJECT file_object)
james@536 39 {
james@536 40 NTSTATUS status;
james@536 41 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 42 WDF_IO_QUEUE_CONFIG queue_config;
james@536 43
james@536 44 FUNCTION_ENTER();
james@536 45
james@536 46 xpdid->type = DEVICE_INTERFACE_TYPE_XENBUS;
james@536 47 KeInitializeSpinLock(&xpdid->lock);
james@536 48 InitializeListHead(&xpdid->read_list_head);
james@536 49 InitializeListHead(&xpdid->watch_list_head);
james@536 50 xpdid->len = 0;
james@536 51 WDF_IO_QUEUE_CONFIG_INIT(&queue_config, WdfIoQueueDispatchManual);
james@536 52 //queue_config.EvtIoRead = XenPci_EvtIoRead;
james@536 53 status = WdfIoQueueCreate(device, &queue_config, WDF_NO_OBJECT_ATTRIBUTES, &xpdid->io_queue);
james@536 54 if (!NT_SUCCESS(status)) {
james@536 55 KdPrint(("Error creating queue 0x%x\n", status));
james@536 56 WdfRequestComplete(request, STATUS_UNSUCCESSFUL);
james@536 57 }
james@536 58 //WdfIoQueueStop(xpdid->io_queue, NULL, NULL);
james@536 59
james@536 60 WdfRequestComplete(request, STATUS_SUCCESS);
james@536 61
james@536 62 FUNCTION_EXIT();
james@536 63 }
james@536 64
james@536 65 VOID
james@536 66 XenPci_ProcessReadRequest(WDFQUEUE queue, WDFREQUEST request, size_t length)
james@536 67 {
james@536 68 NTSTATUS status;
james@536 69 WDFFILEOBJECT file_object = WdfRequestGetFileObject(request);
james@536 70 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@537 71 ULONG dst_length = (ULONG)length;
james@536 72 ULONG dst_offset = 0;
james@536 73 ULONG copy_length;
james@536 74 xenbus_read_queue_item_t *list_entry;
james@536 75 PVOID buffer;
james@536 76
james@536 77 UNREFERENCED_PARAMETER(queue);
james@536 78
james@536 79 status = WdfRequestRetrieveOutputBuffer(request, length, &buffer, NULL);
james@536 80 if (!NT_SUCCESS(status))
james@536 81 {
james@536 82 KdPrint((__DRIVER_NAME, " WdfRequestRetrieveOutputBuffer failed status = %08x\n", status));
james@536 83 WdfRequestSetInformation(request, 0);
james@536 84 return;
james@536 85 }
james@536 86 ASSERT(NT_SUCCESS(status)); // lazy?
james@536 87
james@536 88 while(dst_offset < dst_length && (list_entry = (xenbus_read_queue_item_t *)RemoveHeadList(&xpdid->read_list_head)) != (xenbus_read_queue_item_t *)&xpdid->read_list_head)
james@536 89 {
james@536 90 copy_length = min(list_entry->length - list_entry->offset, dst_length - dst_offset);
james@536 91 memcpy((PUCHAR)buffer + dst_offset, (PUCHAR)list_entry->data + list_entry->offset, copy_length);
james@536 92 list_entry->offset += copy_length;
james@536 93 dst_offset += copy_length;
james@536 94 if (list_entry->offset == list_entry->length)
james@536 95 {
james@537 96 ExFreePoolWithTag(list_entry->data, XENPCI_POOL_TAG);
james@537 97 ExFreePoolWithTag(list_entry, XENPCI_POOL_TAG);
james@536 98 }
james@536 99 else
james@536 100 {
james@536 101 InsertHeadList(&xpdid->read_list_head, (PLIST_ENTRY)list_entry);
james@536 102 }
james@536 103 }
james@536 104 WdfRequestSetInformation(request, dst_offset);
james@536 105
james@536 106 FUNCTION_EXIT();
james@536 107 }
james@536 108
james@536 109 static VOID
james@536 110 XenPci_IoWatch(char *path, PVOID context)
james@536 111 {
james@536 112 NTSTATUS status;
james@536 113 watch_context_t *watch_context = context;
james@536 114 WDFFILEOBJECT file_object = watch_context->file_object;
james@536 115 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 116 KIRQL old_irql;
james@536 117 struct xsd_sockmsg *rep;
james@536 118 xenbus_read_queue_item_t *list_entry;
james@537 119 size_t remaining;
james@536 120 WDFREQUEST request;
james@536 121
james@536 122 FUNCTION_ENTER();
james@536 123
james@536 124 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 125
james@537 126 remaining = sizeof(struct xsd_sockmsg) + strlen(path) + 1 + strlen(watch_context->token) + 1;
james@536 127 rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg) + strlen(path) + 1 + strlen(watch_context->token) + 1, XENPCI_POOL_TAG);
james@536 128 rep->type = XS_WATCH_EVENT;
james@536 129 rep->req_id = 0;
james@536 130 rep->tx_id = 0;
james@537 131 rep->len = (ULONG)(strlen(path) + 1 + strlen(watch_context->token) + 1);
james@537 132 remaining -= sizeof(struct xsd_sockmsg);
james@537 133 RtlStringCbCopyA((PCHAR)(rep + 1), remaining, path);
james@537 134 remaining -= strlen(path) + 1;
james@537 135 RtlStringCbCopyA((PCHAR)(rep + 1) + strlen(path) + 1, remaining, watch_context->token);
james@536 136
james@536 137 list_entry = (xenbus_read_queue_item_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(xenbus_read_queue_item_t), XENPCI_POOL_TAG);
james@536 138 list_entry->data = rep;
james@536 139 list_entry->length = sizeof(*rep) + rep->len;
james@536 140 list_entry->offset = 0;
james@536 141 InsertTailList(&xpdid->read_list_head, (PLIST_ENTRY)list_entry);
james@536 142
james@536 143 status = WdfIoQueueRetrieveNextRequest(xpdid->io_queue, &request);
james@536 144 if (NT_SUCCESS(status))
james@536 145 {
james@536 146 WDF_REQUEST_PARAMETERS parameters;
james@536 147 WDF_REQUEST_PARAMETERS_INIT(&parameters);
james@536 148 WdfRequestGetParameters(request, &parameters);
james@536 149
james@536 150 KdPrint((__DRIVER_NAME " found pending read - MinorFunction = %d, length = %d\n", (ULONG)parameters.MinorFunction, (ULONG)parameters.Parameters.Read.Length));
james@536 151 XenPci_ProcessReadRequest(xpdid->io_queue, request, parameters.Parameters.Read.Length);
james@536 152 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 153 WdfRequestComplete(request, STATUS_SUCCESS);
james@536 154 }
james@536 155 else
james@536 156 {
james@536 157 KdPrint((__DRIVER_NAME " no pending read (%08x)\n", status));
james@536 158 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 159 }
james@536 160
james@536 161 FUNCTION_EXIT();
james@536 162 }
james@536 163
james@536 164 VOID
james@536 165 XenPci_EvtFileCleanup(WDFFILEOBJECT file_object)
james@536 166 {
james@536 167 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 168 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfFileObjectGetDevice(file_object));
james@536 169 watch_context_t *watch_context;
james@536 170 KIRQL old_irql;
james@536 171 PCHAR msg;
james@536 172
james@536 173 FUNCTION_ENTER();
james@536 174
james@536 175 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 176
james@536 177 while (!IsListEmpty(&xpdid->watch_list_head))
james@536 178 {
james@536 179 watch_context = (watch_context_t *)RemoveHeadList(&xpdid->watch_list_head);
james@536 180 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 181 msg = XenBus_RemWatch(xpdd, XBT_NIL, watch_context->path, XenPci_IoWatch, watch_context);
james@536 182 if (msg != NULL)
james@536 183 {
james@536 184 KdPrint((__DRIVER_NAME " Error freeing watch (%s)\n", msg));
james@536 185 XenPci_FreeMem(msg);
james@536 186 }
james@536 187 ExFreePoolWithTag(watch_context, XENPCI_POOL_TAG);
james@536 188 WdfObjectDereference(file_object);
james@536 189 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 190 }
james@536 191
james@536 192 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 193
james@536 194 FUNCTION_EXIT();
james@536 195 }
james@536 196
james@536 197 VOID
james@536 198 XenPci_EvtFileClose(WDFFILEOBJECT file_object)
james@536 199 {
james@536 200 UNREFERENCED_PARAMETER(file_object);
james@536 201 FUNCTION_ENTER();
james@536 202 FUNCTION_EXIT();
james@536 203 }
james@536 204
james@536 205 VOID
james@536 206 XenPci_EvtIoRead(WDFQUEUE queue, WDFREQUEST request, size_t length)
james@536 207 {
james@536 208 NTSTATUS status;
james@536 209 WDFFILEOBJECT file_object = WdfRequestGetFileObject(request);
james@536 210 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 211 KIRQL old_irql;
james@536 212
james@537 213 UNREFERENCED_PARAMETER(queue);
james@537 214
james@536 215 FUNCTION_ENTER();
james@536 216 status = WdfRequestForwardToIoQueue(request, xpdid->io_queue);
james@536 217 if (!NT_SUCCESS(status))
james@536 218 {
james@536 219 KdPrint((__DRIVER_NAME " could not forward request (%08x)\n", status));
james@536 220 }
james@536 221 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 222 if (!IsListEmpty(&xpdid->read_list_head))
james@536 223 {
james@536 224 status = WdfIoQueueRetrieveNextRequest(xpdid->io_queue, &request);
james@536 225 if (NT_SUCCESS(status))
james@536 226 {
james@536 227 KdPrint((__DRIVER_NAME " found pending read\n"));
james@536 228 XenPci_ProcessReadRequest(xpdid->io_queue, request, length);
james@536 229 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 230 WdfRequestComplete(request, STATUS_SUCCESS);
james@536 231 }
james@536 232 else
james@536 233 {
james@536 234 KdPrint((__DRIVER_NAME " no pending read (%08x)\n", status));
james@536 235 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 236 }
james@536 237 }
james@536 238 else
james@536 239 {
james@536 240 KdPrint((__DRIVER_NAME " no data to read\n"));
james@536 241 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 242 }
james@536 243
james@536 244 FUNCTION_EXIT();
james@536 245 return;
james@536 246 }
james@536 247
james@536 248 VOID
james@536 249 XenPci_EvtIoWrite(WDFQUEUE queue, WDFREQUEST request, size_t length)
james@536 250 {
james@536 251 NTSTATUS status;
james@536 252 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfIoQueueGetDevice(queue));
james@536 253 WDFFILEOBJECT file_object = WdfRequestGetFileObject(request);
james@536 254 PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object);
james@536 255 KIRQL old_irql;
james@536 256 PUCHAR buffer;
james@536 257 PUCHAR src_ptr;
james@536 258 ULONG src_len;
james@536 259 PUCHAR dst_ptr;
james@536 260 ULONG copy_len;
james@536 261 struct xsd_sockmsg *rep;
james@536 262 xenbus_read_queue_item_t *list_entry;
james@536 263 watch_context_t *watch_context;
james@536 264 PCHAR watch_path;
james@536 265 PCHAR watch_token;
james@536 266 PCHAR msg;
james@536 267
james@536 268 FUNCTION_ENTER();
james@536 269
james@536 270 status = WdfRequestRetrieveInputBuffer(request, length, &buffer, NULL);
james@536 271 ASSERT(NT_SUCCESS(status));
james@536 272
james@536 273 src_ptr = (PUCHAR)buffer;
james@537 274 src_len = (ULONG)length;
james@536 275 dst_ptr = xpdid->u.buffer + xpdid->len;
james@536 276 while (src_len != 0)
james@536 277 {
james@536 278 KdPrint((__DRIVER_NAME " %d bytes of write buffer remaining\n", src_len));
james@536 279 /* get a complete msg header */
james@536 280 if (xpdid->len < sizeof(xpdid->u.msg))
james@536 281 {
james@536 282 copy_len = min(sizeof(xpdid->u.msg) - xpdid->len, src_len);
james@536 283 if (!copy_len)
james@536 284 continue;
james@536 285 memcpy(dst_ptr, src_ptr, copy_len);
james@536 286 dst_ptr += copy_len;
james@536 287 src_ptr += copy_len;
james@536 288 src_len -= copy_len;
james@536 289 xpdid->len += copy_len;
james@536 290 }
james@536 291 /* exit if we can't get that */
james@536 292 if (xpdid->len < sizeof(xpdid->u.msg))
james@536 293 continue;
james@536 294 /* get a complete msg body */
james@536 295 if (xpdid->len < sizeof(xpdid->u.msg) + xpdid->u.msg.len)
james@536 296 {
james@536 297 copy_len = min(sizeof(xpdid->u.msg) + xpdid->u.msg.len - xpdid->len, src_len);
james@536 298 if (!copy_len)
james@536 299 continue;
james@536 300 memcpy(dst_ptr, src_ptr, copy_len);
james@536 301 dst_ptr += copy_len;
james@536 302 src_ptr += copy_len;
james@536 303 src_len -= copy_len;
james@536 304 xpdid->len += copy_len;
james@536 305 }
james@536 306 /* exit if we can't get that */
james@536 307 if (xpdid->len < sizeof(xpdid->u.msg) + xpdid->u.msg.len)
james@536 308 {
james@536 309 continue;
james@536 310 }
james@536 311
james@536 312 switch (xpdid->u.msg.type)
james@536 313 {
james@536 314 case XS_WATCH:
james@536 315 case XS_UNWATCH:
james@536 316 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 317 watch_context = (watch_context_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(watch_context_t), XENPCI_POOL_TAG);
james@537 318 watch_path = (PCHAR)(xpdid->u.buffer + sizeof(struct xsd_sockmsg));
james@537 319 watch_token = (PCHAR)(xpdid->u.buffer + sizeof(struct xsd_sockmsg) + strlen(watch_path) + 1);
james@537 320 RtlStringCbCopyA(watch_context->path, ARRAY_SIZE(watch_context->path), watch_path);
james@537 321 RtlStringCbCopyA(watch_context->token, ARRAY_SIZE(watch_context->path), watch_token);
james@536 322 watch_context->file_object = file_object;
james@536 323 if (xpdid->u.msg.type == XS_WATCH)
james@536 324 InsertTailList(&xpdid->watch_list_head, &watch_context->entry);
james@536 325 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 326 if (xpdid->u.msg.type == XS_WATCH)
james@536 327 msg = XenBus_AddWatch(xpdd, XBT_NIL, watch_path, XenPci_IoWatch, watch_context);
james@536 328 else
james@536 329 msg = XenBus_RemWatch(xpdd, XBT_NIL, watch_path, XenPci_IoWatch, watch_context);
james@536 330 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 331 if (msg != NULL)
james@536 332 {
james@536 333 rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg) + strlen(msg) + 1, XENPCI_POOL_TAG);
james@536 334 rep->type = XS_ERROR;
james@536 335 rep->req_id = xpdid->u.msg.req_id;
james@536 336 rep->tx_id = xpdid->u.msg.tx_id;
james@537 337 rep->len = (ULONG)(strlen(msg) + 0);
james@537 338 RtlStringCbCopyA((PCHAR)(rep + 1), strlen(msg) + 1, msg);
james@536 339 if (xpdid->u.msg.type == XS_WATCH)
james@536 340 RemoveEntryList(&watch_context->entry);
james@536 341 }
james@536 342 else
james@536 343 {
james@536 344 if (xpdid->u.msg.type == XS_WATCH)
james@536 345 {
james@536 346 WdfObjectReference(file_object);
james@536 347 }
james@536 348 else
james@536 349 {
james@536 350 RemoveEntryList(&watch_context->entry);
james@536 351 WdfObjectDereference(file_object);
james@536 352 }
james@536 353 rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg), XENPCI_POOL_TAG);
james@536 354 rep->type = xpdid->u.msg.type;
james@536 355 rep->req_id = xpdid->u.msg.req_id;
james@536 356 rep->tx_id = xpdid->u.msg.tx_id;
james@536 357 rep->len = 0;
james@536 358 }
james@536 359 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 360 break;
james@536 361 default:
james@536 362 rep = XenBus_Raw(xpdd, &xpdid->u.msg);
james@536 363 break;
james@536 364 }
james@536 365 xpdid->len = 0;
james@536 366
james@536 367 KeAcquireSpinLock(&xpdid->lock, &old_irql);
james@536 368 list_entry = (xenbus_read_queue_item_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(xenbus_read_queue_item_t), XENPCI_POOL_TAG);
james@536 369 list_entry->data = rep;
james@536 370 list_entry->length = sizeof(*rep) + rep->len;
james@536 371 list_entry->offset = 0;
james@536 372 InsertTailList(&xpdid->read_list_head, (PLIST_ENTRY)list_entry);
james@536 373 KeReleaseSpinLock(&xpdid->lock, old_irql);
james@536 374 }
james@536 375 KdPrint((__DRIVER_NAME " completing request with length %d\n", length));
james@536 376 WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, length);
james@536 377
james@536 378 FUNCTION_EXIT();
james@537 379 }