win-pvdrivers

view xenpci/xenbus_device_interface.c @ 716:5bdb7251370c

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