win-pvdrivers

view xenpci/xenbus_device_interface.c @ 547:ac614e49832c

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