rev |
line source |
james@259
|
1 /*
|
james@259
|
2 PV Drivers for Windows Xen HVM Domains
|
james@259
|
3 Copyright (C) 2007 James Harper
|
james@259
|
4
|
james@259
|
5 This program is free software; you can redistribute it and/or
|
james@259
|
6 modify it under the terms of the GNU General Public License
|
james@259
|
7 as published by the Free Software Foundation; either version 2
|
james@259
|
8 of the License, or (at your option) any later version.
|
james@259
|
9
|
james@259
|
10 This program is distributed in the hope that it will be useful,
|
james@259
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
james@259
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
james@259
|
13 GNU General Public License for more details.
|
james@259
|
14
|
james@259
|
15 You should have received a copy of the GNU General Public License
|
james@259
|
16 along with this program; if not, write to the Free Software
|
james@259
|
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
james@259
|
18 */
|
james@259
|
19
|
james@259
|
20 #include "xenpci.h"
|
james@259
|
21 #include <stdlib.h>
|
james@529
|
22 #include <aux_klib.h>
|
james@259
|
23
|
james@259
|
24 #define SYSRQ_PATH "control/sysrq"
|
james@259
|
25 #define SHUTDOWN_PATH "control/shutdown"
|
james@259
|
26 #define BALLOON_PATH "memory/target"
|
james@259
|
27
|
james@716
|
28 /* Not really necessary but keeps PREfast happy */
|
james@716
|
29 static EVT_WDF_WORKITEM XenPci_SuspendResume;
|
james@716
|
30 static KSTART_ROUTINE XenPci_BalloonThreadProc;
|
james@716
|
31
|
james@536
|
32 static VOID
|
james@536
|
33 XenPci_MapHalThenPatchKernel(PXENPCI_DEVICE_DATA xpdd)
|
james@536
|
34 {
|
james@536
|
35 NTSTATUS status;
|
james@536
|
36 PAUX_MODULE_EXTENDED_INFO amei;
|
james@536
|
37 ULONG module_info_buffer_size;
|
james@536
|
38 ULONG i;
|
james@536
|
39
|
james@536
|
40 FUNCTION_ENTER();
|
james@536
|
41
|
james@536
|
42 amei = NULL;
|
james@536
|
43 /* buffer size could change between requesting and allocating - need to loop until we are successful */
|
james@536
|
44 while ((status = AuxKlibQueryModuleInformation(&module_info_buffer_size, sizeof(AUX_MODULE_EXTENDED_INFO), amei)) == STATUS_BUFFER_TOO_SMALL || amei == NULL)
|
james@536
|
45 {
|
james@536
|
46 if (amei != NULL)
|
james@536
|
47 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
|
james@536
|
48 amei = ExAllocatePoolWithTag(NonPagedPool, module_info_buffer_size, XENPCI_POOL_TAG);
|
james@536
|
49 }
|
james@536
|
50
|
james@536
|
51 KdPrint((__DRIVER_NAME " AuxKlibQueryModuleInformation = %d\n", status));
|
james@536
|
52 for (i = 0; i < module_info_buffer_size / sizeof(AUX_MODULE_EXTENDED_INFO); i++)
|
james@536
|
53 {
|
james@536
|
54 if (strcmp((PCHAR)amei[i].FullPathName + amei[i].FileNameOffset, "hal.dll") == 0)
|
james@536
|
55 {
|
james@536
|
56 KdPrint((__DRIVER_NAME " hal.dll found at %p - %p\n",
|
james@536
|
57 amei[i].BasicInfo.ImageBase,
|
james@536
|
58 ((PUCHAR)amei[i].BasicInfo.ImageBase) + amei[i].ImageSize));
|
james@536
|
59 XenPci_PatchKernel(xpdd, amei[i].BasicInfo.ImageBase, amei[i].ImageSize);
|
james@536
|
60 }
|
james@536
|
61 }
|
james@536
|
62 ExFreePoolWithTag(amei, XENPCI_POOL_TAG);
|
james@536
|
63 FUNCTION_EXIT();
|
james@536
|
64 }
|
james@536
|
65
|
james@536
|
66 /*
|
james@536
|
67 * Alloc MMIO from the device's MMIO region. There is no corresponding free() fn
|
james@536
|
68 */
|
james@536
|
69 PHYSICAL_ADDRESS
|
james@536
|
70 XenPci_AllocMMIO(PXENPCI_DEVICE_DATA xpdd, ULONG len)
|
james@536
|
71 {
|
james@536
|
72 PHYSICAL_ADDRESS addr;
|
james@536
|
73
|
james@536
|
74 len = (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
|
james@536
|
75
|
james@536
|
76 addr = xpdd->platform_mmio_addr;
|
james@536
|
77 addr.QuadPart += xpdd->platform_mmio_alloc;
|
james@536
|
78 xpdd->platform_mmio_alloc += len;
|
james@536
|
79
|
james@536
|
80 ASSERT(xpdd->platform_mmio_alloc <= xpdd->platform_mmio_len);
|
james@536
|
81
|
james@536
|
82 return addr;
|
james@536
|
83 }
|
james@536
|
84
|
james@536
|
85 extern ULONG tpr_patch_requested;
|
james@536
|
86
|
james@537
|
87 NTSTATUS
|
james@537
|
88 XenPci_EvtDeviceQueryRemove(WDFDEVICE device)
|
james@537
|
89 {
|
james@537
|
90 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@537
|
91 NTSTATUS status;
|
james@537
|
92
|
james@537
|
93 FUNCTION_ENTER();
|
james@537
|
94 if (xpdd->removable)
|
james@537
|
95 status = STATUS_SUCCESS;
|
james@537
|
96 else
|
james@537
|
97 status = STATUS_UNSUCCESSFUL;
|
james@537
|
98 FUNCTION_EXIT();
|
james@537
|
99 return status;
|
james@537
|
100 }
|
james@537
|
101
|
james@536
|
102 static NTSTATUS
|
james@536
|
103 XenPci_Init(PXENPCI_DEVICE_DATA xpdd)
|
james@536
|
104 {
|
james@666
|
105 NTSTATUS status;
|
james@536
|
106 struct xen_add_to_physmap xatp;
|
james@536
|
107 int ret;
|
james@536
|
108
|
james@536
|
109 FUNCTION_ENTER();
|
james@536
|
110
|
james@666
|
111 status = hvm_get_stubs(xpdd);
|
james@666
|
112 if (!NT_SUCCESS(status))
|
james@666
|
113 return status;
|
james@536
|
114
|
james@536
|
115 if (!xpdd->shared_info_area)
|
james@536
|
116 {
|
james@536
|
117 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
|
james@536
|
118 /* this should be safe as this part will never be called on resume where IRQL == HIGH_LEVEL */
|
james@536
|
119 xpdd->shared_info_area_unmapped = XenPci_AllocMMIO(xpdd, PAGE_SIZE);
|
james@536
|
120 xpdd->shared_info_area = MmMapIoSpace(xpdd->shared_info_area_unmapped,
|
james@536
|
121 PAGE_SIZE, MmNonCached);
|
james@536
|
122 }
|
james@536
|
123 KdPrint((__DRIVER_NAME " shared_info_area_unmapped.QuadPart = %lx\n", xpdd->shared_info_area_unmapped.QuadPart));
|
james@536
|
124 xatp.domid = DOMID_SELF;
|
james@536
|
125 xatp.idx = 0;
|
james@536
|
126 xatp.space = XENMAPSPACE_shared_info;
|
james@536
|
127 xatp.gpfn = (xen_pfn_t)(xpdd->shared_info_area_unmapped.QuadPart >> PAGE_SHIFT);
|
james@536
|
128 KdPrint((__DRIVER_NAME " gpfn = %x\n", xatp.gpfn));
|
james@536
|
129 ret = HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp);
|
james@536
|
130 KdPrint((__DRIVER_NAME " hypervisor memory op (XENMAPSPACE_shared_info) ret = %d\n", ret));
|
james@622
|
131
|
james@536
|
132 FUNCTION_EXIT();
|
james@536
|
133
|
james@536
|
134 return STATUS_SUCCESS;
|
james@536
|
135 }
|
james@536
|
136
|
james@536
|
137 static NTSTATUS
|
james@536
|
138 XenPci_Resume(PXENPCI_DEVICE_DATA xpdd)
|
james@536
|
139 {
|
james@536
|
140 return XenPci_Init(xpdd);
|
james@536
|
141 }
|
james@536
|
142
|
james@536
|
143 static VOID
|
james@536
|
144 XenPci_SysrqHandler(char *path, PVOID context)
|
james@536
|
145 {
|
james@536
|
146 PXENPCI_DEVICE_DATA xpdd = context;
|
james@536
|
147 char *value;
|
james@536
|
148 char letter;
|
james@536
|
149 char *res;
|
james@536
|
150
|
james@536
|
151 UNREFERENCED_PARAMETER(path);
|
james@536
|
152
|
james@536
|
153 FUNCTION_ENTER();
|
james@536
|
154
|
james@536
|
155 XenBus_Read(xpdd, XBT_NIL, SYSRQ_PATH, &value);
|
james@536
|
156
|
james@536
|
157 KdPrint((__DRIVER_NAME " SysRq Value = %s\n", value));
|
james@536
|
158
|
james@536
|
159 if (value != NULL && strlen(value) != 0)
|
james@536
|
160 {
|
james@536
|
161 letter = *value;
|
james@536
|
162 res = XenBus_Write(xpdd, XBT_NIL, SYSRQ_PATH, "");
|
james@536
|
163 if (res)
|
james@536
|
164 {
|
james@536
|
165 KdPrint(("Error writing sysrq path\n"));
|
james@536
|
166 XenPci_FreeMem(res);
|
james@536
|
167 return;
|
james@536
|
168 }
|
james@536
|
169 }
|
james@536
|
170 else
|
james@536
|
171 {
|
james@536
|
172 letter = 0;
|
james@536
|
173 }
|
james@536
|
174
|
james@536
|
175 if (value != NULL)
|
james@536
|
176 {
|
james@536
|
177 XenPci_FreeMem(value);
|
james@536
|
178 }
|
james@536
|
179
|
james@536
|
180 switch (letter)
|
james@536
|
181 {
|
james@536
|
182 case 0:
|
james@536
|
183 break;
|
james@536
|
184 case 'B': /* cause a bug check */
|
james@536
|
185 KeBugCheckEx(('X' << 16)|('E' << 8)|('N'), 0x00000001, 0x00000000, 0x00000000, 0x00000000);
|
james@536
|
186 break;
|
james@702
|
187 case 'A': /* cause an assert */
|
james@702
|
188 ASSERT(1 == 0);
|
james@702
|
189 break;
|
james@536
|
190 default:
|
james@536
|
191 KdPrint((" Unhandled sysrq letter %c\n", letter));
|
james@536
|
192 break;
|
james@536
|
193 }
|
james@536
|
194
|
james@536
|
195 FUNCTION_EXIT();
|
james@536
|
196 }
|
james@536
|
197
|
james@536
|
198 #if 0
|
james@536
|
199 static VOID
|
james@536
|
200 XenPci_PrintPendingInterrupts()
|
james@536
|
201 {
|
james@536
|
202 PULONG bitmap = (PULONG)0xFFFE0200;
|
james@536
|
203 int i;
|
james@536
|
204 int j;
|
james@536
|
205 ULONG value;
|
james@536
|
206
|
james@536
|
207 for (i = 0; i < 8; i++)
|
james@536
|
208 {
|
james@536
|
209 value = bitmap[(7 - i) * 4];
|
james@536
|
210 if (value)
|
james@536
|
211 {
|
james@536
|
212 for (j = 0; j < 32; j++)
|
james@536
|
213 {
|
james@536
|
214 if ((value >> j) & 1)
|
james@536
|
215 KdPrint((" Interrupt pending on pin %d\n", ((7 - i) << 5) | j));
|
james@536
|
216 }
|
james@536
|
217 }
|
james@536
|
218 }
|
james@536
|
219 }
|
james@536
|
220 #endif
|
james@536
|
221
|
james@591
|
222 #define BALLOON_UNIT_PAGES (BALLOON_UNITS >> PAGE_SHIFT)
|
james@591
|
223
|
james@591
|
224 static VOID
|
james@591
|
225 XenPci_BalloonThreadProc(PVOID StartContext)
|
james@591
|
226 {
|
james@591
|
227 PXENPCI_DEVICE_DATA xpdd = StartContext;
|
james@591
|
228 ULONG new_target = xpdd->current_memory;
|
james@591
|
229 LARGE_INTEGER timeout;
|
james@591
|
230 PLARGE_INTEGER ptimeout;
|
james@591
|
231 PMDL head = NULL;
|
james@794
|
232 PMDL mdl;
|
james@794
|
233 struct xen_memory_reservation reservation;
|
james@794
|
234 xen_pfn_t *pfns;
|
james@794
|
235 int i;
|
james@794
|
236 ULONG ret;
|
james@794
|
237 int pfn_count;
|
james@794
|
238
|
james@591
|
239 FUNCTION_ENTER();
|
james@591
|
240
|
james@591
|
241 for(;;)
|
james@591
|
242 {
|
james@794
|
243 /* wait for 1 second if we have adjustments to make, or forever if we don't */
|
james@591
|
244 if (xpdd->current_memory != new_target)
|
james@591
|
245 {
|
james@591
|
246 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
|
james@591
|
247 ptimeout = &timeout;
|
james@591
|
248 }
|
james@591
|
249 else
|
james@591
|
250 {
|
james@591
|
251 ptimeout = NULL;
|
james@591
|
252 }
|
james@591
|
253 KeWaitForSingleObject(&xpdd->balloon_event, Executive, KernelMode, FALSE, ptimeout);
|
james@622
|
254 if (xpdd->balloon_shutdown)
|
james@622
|
255 PsTerminateSystemThread(0);
|
james@591
|
256 KdPrint((__DRIVER_NAME " Got balloon event, current = %d, target = %d\n", xpdd->current_memory, xpdd->target_memory));
|
james@591
|
257 /* not really worried about races here, but cache target so we only read it once */
|
james@591
|
258 new_target = xpdd->target_memory;
|
james@591
|
259 // perform some sanity checks on target_memory
|
james@591
|
260 // make sure target <= initial
|
james@591
|
261 // make sure target > some % of initial
|
james@591
|
262
|
james@591
|
263 if (xpdd->current_memory == new_target)
|
james@591
|
264 {
|
james@591
|
265 KdPrint((__DRIVER_NAME " No change to memory\n"));
|
james@591
|
266 continue;
|
james@591
|
267 }
|
james@591
|
268 else if (xpdd->current_memory < new_target)
|
james@591
|
269 {
|
james@591
|
270 KdPrint((__DRIVER_NAME " Trying to take %d MB from Xen\n", new_target - xpdd->current_memory));
|
james@591
|
271 while ((mdl = head) != NULL && xpdd->current_memory < new_target)
|
james@591
|
272 {
|
james@591
|
273 head = mdl->Next;
|
james@591
|
274 mdl->Next = NULL;
|
james@794
|
275
|
james@794
|
276 pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
|
james@794
|
277 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
|
james@794
|
278 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
|
james@794
|
279 for (i = 0; i < pfn_count; i++)
|
james@794
|
280 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
|
james@794
|
281 reservation.address_bits = 0;
|
james@794
|
282 reservation.extent_order = 0;
|
james@794
|
283 reservation.domid = DOMID_SELF;
|
james@794
|
284 reservation.nr_extents = pfn_count;
|
james@794
|
285 #pragma warning(disable: 4127) /* conditional expression is constant */
|
james@794
|
286 set_xen_guest_handle(reservation.extent_start, pfns);
|
james@794
|
287
|
james@794
|
288 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_populate_physmap) - pfn_count = %d\n", pfn_count));
|
james@794
|
289 ret = HYPERVISOR_memory_op(xpdd, XENMEM_populate_physmap, &reservation);
|
james@794
|
290 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
|
james@794
|
291 KdPrint((__DRIVER_NAME " populated %d pages\n", ret));
|
james@794
|
292 /* TODO: what do we do if less than the required number of pages were populated??? */
|
james@794
|
293
|
james@591
|
294 MmFreePagesFromMdl(mdl);
|
james@591
|
295 ExFreePool(mdl);
|
james@591
|
296 xpdd->current_memory++;
|
james@591
|
297 }
|
james@591
|
298 }
|
james@591
|
299 else
|
james@591
|
300 {
|
james@591
|
301 KdPrint((__DRIVER_NAME " Trying to give %d MB to Xen\n", xpdd->current_memory - new_target));
|
james@591
|
302 while (xpdd->current_memory > new_target)
|
james@591
|
303 {
|
james@591
|
304 PHYSICAL_ADDRESS alloc_low;
|
james@591
|
305 PHYSICAL_ADDRESS alloc_high;
|
james@591
|
306 PHYSICAL_ADDRESS alloc_skip;
|
james@591
|
307 alloc_low.QuadPart = 0;
|
james@591
|
308 alloc_high.QuadPart = 0xFFFFFFFFFFFFFFFFULL;
|
james@591
|
309 alloc_skip.QuadPart = 0;
|
james@794
|
310 mdl = MmAllocatePagesForMdlEx(alloc_low, alloc_high, alloc_skip, BALLOON_UNITS, MmCached, MM_DONT_ZERO_ALLOCATION);
|
james@591
|
311 if (!mdl)
|
james@591
|
312 {
|
james@591
|
313 KdPrint((__DRIVER_NAME " Allocation failed - try again in 1 second\n"));
|
james@591
|
314 break;
|
james@591
|
315 }
|
james@591
|
316 else
|
james@591
|
317 {
|
james@794
|
318 int i;
|
james@794
|
319 ULONG ret;
|
james@794
|
320 int pfn_count = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(mdl), MmGetMdlByteCount(mdl));
|
james@794
|
321 if (pfn_count != BALLOON_UNIT_PAGES)
|
james@794
|
322 {
|
james@794
|
323 /* we could probably do this better but it will only happen in low memory conditions... */
|
james@794
|
324 KdPrint((__DRIVER_NAME " wanted %d pages got %d pages\n", BALLOON_UNIT_PAGES, pfn_count));
|
james@794
|
325 MmFreePagesFromMdl(mdl);
|
james@794
|
326 ExFreePool(mdl);
|
james@794
|
327 break;
|
james@794
|
328 }
|
james@794
|
329 pfns = ExAllocatePoolWithTag(NonPagedPool, pfn_count * sizeof(xen_pfn_t), XENPCI_POOL_TAG);
|
james@794
|
330 /* sizeof(xen_pfn_t) may not be the same as PPFN_NUMBER */
|
james@794
|
331 for (i = 0; i < pfn_count; i++)
|
james@794
|
332 pfns[i] = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[i]);
|
james@794
|
333 reservation.address_bits = 0;
|
james@794
|
334 reservation.extent_order = 0;
|
james@794
|
335 reservation.domid = DOMID_SELF;
|
james@794
|
336 reservation.nr_extents = pfn_count;
|
james@794
|
337 #pragma warning(disable: 4127) /* conditional expression is constant */
|
james@794
|
338 set_xen_guest_handle(reservation.extent_start, pfns);
|
james@794
|
339
|
james@794
|
340 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op(XENMEM_decrease_reservation) - pfn_count = %d\n", pfn_count));
|
james@794
|
341 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
|
james@794
|
342 ExFreePoolWithTag(pfns, XENPCI_POOL_TAG);
|
james@794
|
343 KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
|
james@591
|
344 if (head)
|
james@591
|
345 {
|
james@591
|
346 mdl->Next = head;
|
james@591
|
347 head = mdl;
|
james@591
|
348 }
|
james@591
|
349 else
|
james@591
|
350 {
|
james@591
|
351 head = mdl;
|
james@591
|
352 }
|
james@591
|
353 xpdd->current_memory--;
|
james@591
|
354 }
|
james@591
|
355 }
|
james@591
|
356 }
|
james@591
|
357 }
|
james@591
|
358 //FUNCTION_EXIT();
|
james@591
|
359 }
|
james@591
|
360
|
james@591
|
361 static VOID
|
james@591
|
362 XenPci_BalloonHandler(char *Path, PVOID Data)
|
james@591
|
363 {
|
james@591
|
364 WDFDEVICE device = Data;
|
james@591
|
365 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@591
|
366 char *value;
|
james@591
|
367 xenbus_transaction_t xbt;
|
james@591
|
368 int retry;
|
james@591
|
369
|
james@591
|
370 UNREFERENCED_PARAMETER(Path);
|
james@591
|
371
|
james@591
|
372 FUNCTION_ENTER();
|
james@591
|
373
|
james@591
|
374 XenBus_StartTransaction(xpdd, &xbt);
|
james@591
|
375
|
james@591
|
376 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
|
james@591
|
377
|
steve@620
|
378 if (value == NULL)
|
steve@620
|
379 {
|
steve@620
|
380 KdPrint((__DRIVER_NAME " Failed to read value\n"));
|
steve@620
|
381 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
|
steve@620
|
382 FUNCTION_EXIT();
|
steve@620
|
383 return;
|
steve@620
|
384 }
|
steve@620
|
385
|
james@591
|
386 if (atoi(value) > 0)
|
james@591
|
387 xpdd->target_memory = atoi(value) >> 10; /* convert to MB */
|
james@591
|
388
|
james@591
|
389 KdPrint((__DRIVER_NAME " target memory value = %d (%s)\n", xpdd->target_memory, value));
|
james@591
|
390
|
james@591
|
391 XenBus_EndTransaction(xpdd, xbt, 0, &retry);
|
james@591
|
392
|
james@591
|
393 XenPci_FreeMem(value);
|
james@591
|
394
|
james@591
|
395 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
|
james@591
|
396
|
james@591
|
397 FUNCTION_EXIT();
|
james@591
|
398 }
|
james@591
|
399
|
james@536
|
400 static VOID
|
james@536
|
401 XenPci_Suspend0(PVOID context)
|
james@536
|
402 {
|
james@536
|
403 PXENPCI_DEVICE_DATA xpdd = context;
|
james@536
|
404 ULONG cancelled;
|
james@536
|
405
|
james@536
|
406 FUNCTION_ENTER();
|
james@536
|
407
|
james@536
|
408 GntTbl_Suspend(xpdd);
|
james@536
|
409
|
james@536
|
410 cancelled = hvm_shutdown(xpdd, SHUTDOWN_suspend);
|
james@536
|
411 KdPrint((__DRIVER_NAME " back from suspend, cancelled = %d\n", cancelled));
|
james@536
|
412
|
james@747
|
413 if (qemu_hide_flags_value)
|
james@536
|
414 {
|
james@536
|
415 XenPci_HideQemuDevices();
|
james@551
|
416 }
|
james@536
|
417
|
james@536
|
418 XenPci_Resume(xpdd);
|
james@536
|
419 GntTbl_Resume(xpdd);
|
james@536
|
420 EvtChn_Resume(xpdd); /* this enables interrupts again too */
|
james@536
|
421
|
james@536
|
422 FUNCTION_EXIT();
|
james@536
|
423 }
|
james@536
|
424
|
james@536
|
425 static VOID
|
james@536
|
426 XenPci_SuspendN(PVOID context)
|
james@536
|
427 {
|
james@536
|
428 UNREFERENCED_PARAMETER(context);
|
james@536
|
429
|
james@536
|
430 FUNCTION_ENTER();
|
james@536
|
431 KdPrint((__DRIVER_NAME " doing nothing on cpu N\n"));
|
james@536
|
432 FUNCTION_EXIT();
|
james@536
|
433 }
|
james@536
|
434
|
james@622
|
435 static VOID
|
james@622
|
436 XenPci_SuspendEvtDpc(PVOID context);
|
james@622
|
437 static NTSTATUS
|
james@622
|
438 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd);
|
james@622
|
439
|
james@622
|
440 /* called at PASSIVE_LEVEL */
|
james@622
|
441 static NTSTATUS
|
james@622
|
442 XenPci_ConnectSuspendEvt(PXENPCI_DEVICE_DATA xpdd)
|
james@622
|
443 {
|
james@622
|
444 CHAR path[128];
|
james@622
|
445
|
james@622
|
446 xpdd->suspend_evtchn = EvtChn_AllocUnbound(xpdd, 0);
|
james@622
|
447 KdPrint((__DRIVER_NAME " suspend event channel = %d\n", xpdd->suspend_evtchn));
|
james@622
|
448 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/suspend/event-channel");
|
james@622
|
449 XenBus_Printf(xpdd, XBT_NIL, path, "%d", xpdd->suspend_evtchn);
|
james@622
|
450 EvtChn_BindDpc(xpdd, xpdd->suspend_evtchn, XenPci_SuspendEvtDpc, xpdd->wdf_device);
|
james@622
|
451
|
james@622
|
452 return STATUS_SUCCESS;
|
james@622
|
453 }
|
james@622
|
454
|
james@536
|
455 /* Called at PASSIVE_LEVEL */
|
james@536
|
456 static VOID DDKAPI
|
james@536
|
457 XenPci_SuspendResume(WDFWORKITEM workitem)
|
james@536
|
458 {
|
james@536
|
459 NTSTATUS status;
|
james@536
|
460 //KAFFINITY ActiveProcessorMask = 0; // this is for Vista+
|
james@536
|
461 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
|
james@536
|
462 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@536
|
463 WDFCHILDLIST child_list = WdfFdoGetDefaultChildList(device);
|
james@536
|
464 WDF_CHILD_LIST_ITERATOR child_iterator;
|
james@536
|
465 WDFDEVICE child_device;
|
james@536
|
466
|
james@536
|
467 FUNCTION_ENTER();
|
james@536
|
468
|
james@536
|
469 if (xpdd->suspend_state == SUSPEND_STATE_NONE)
|
james@536
|
470 {
|
james@536
|
471 xpdd->suspend_state = SUSPEND_STATE_SCHEDULED;
|
james@536
|
472 KeMemoryBarrier();
|
james@536
|
473
|
james@536
|
474 WDF_CHILD_LIST_ITERATOR_INIT(&child_iterator, WdfRetrievePresentChildren);
|
james@536
|
475 WdfChildListBeginIteration(child_list, &child_iterator);
|
james@536
|
476 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
|
james@536
|
477 {
|
james@536
|
478 KdPrint((__DRIVER_NAME " Suspending child\n"));
|
james@536
|
479 XenPci_Pdo_Suspend(child_device);
|
james@536
|
480 }
|
james@536
|
481 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
|
james@536
|
482 WdfChildListEndIteration(child_list, &child_iterator);
|
james@536
|
483
|
james@536
|
484 XenBus_Suspend(xpdd);
|
james@536
|
485 EvtChn_Suspend(xpdd);
|
james@536
|
486 XenPci_HighSync(XenPci_Suspend0, XenPci_SuspendN, xpdd);
|
james@536
|
487
|
james@536
|
488 xpdd->suspend_state = SUSPEND_STATE_RESUMING;
|
james@536
|
489 XenBus_Resume(xpdd);
|
james@536
|
490
|
james@622
|
491 XenPci_ConnectSuspendEvt(xpdd);
|
james@622
|
492
|
james@536
|
493 WdfChildListBeginIteration(child_list, &child_iterator);
|
james@536
|
494 while ((status = WdfChildListRetrieveNextDevice(child_list, &child_iterator, &child_device, NULL)) == STATUS_SUCCESS)
|
james@536
|
495 {
|
james@536
|
496 KdPrint((__DRIVER_NAME " Resuming child\n"));
|
james@536
|
497 XenPci_Pdo_Resume(child_device);
|
james@536
|
498 }
|
james@536
|
499 KdPrint((__DRIVER_NAME " WdfChildListRetrieveNextDevice = %08x, STATUS_NO_MORE_ENTRIES = %08x\n", status, STATUS_NO_MORE_ENTRIES));
|
james@536
|
500 WdfChildListEndIteration(child_list, &child_iterator);
|
james@536
|
501
|
james@536
|
502 xpdd->suspend_state = SUSPEND_STATE_NONE;
|
james@536
|
503 }
|
james@536
|
504 FUNCTION_EXIT();
|
james@536
|
505 }
|
james@536
|
506
|
james@622
|
507 /* called at DISPATCH_LEVEL */
|
james@622
|
508 static VOID
|
james@622
|
509 XenPci_SuspendEvtDpc(PVOID context)
|
james@622
|
510 {
|
james@622
|
511 NTSTATUS status;
|
james@622
|
512 WDFDEVICE device = context;
|
james@622
|
513 //KIRQL old_irql;
|
james@622
|
514 WDF_OBJECT_ATTRIBUTES attributes;
|
james@622
|
515 WDF_WORKITEM_CONFIG workitem_config;
|
james@622
|
516 WDFWORKITEM workitem;
|
james@622
|
517
|
james@622
|
518 KdPrint((__DRIVER_NAME " Suspend detected via Dpc\n"));
|
james@622
|
519 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
|
james@622
|
520 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
james@622
|
521 attributes.ParentObject = device;
|
james@622
|
522 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
|
james@622
|
523 // TODO: check status here
|
james@622
|
524 WdfWorkItemEnqueue(workitem);
|
james@622
|
525 }
|
james@622
|
526
|
james@536
|
527 static void
|
james@536
|
528 XenPci_ShutdownHandler(char *path, PVOID context)
|
james@536
|
529 {
|
james@536
|
530 NTSTATUS status;
|
james@536
|
531 WDFDEVICE device = context;
|
james@536
|
532 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@536
|
533 char *res;
|
james@536
|
534 char *value;
|
james@536
|
535 //KIRQL old_irql;
|
james@536
|
536 WDF_OBJECT_ATTRIBUTES attributes;
|
james@536
|
537 WDF_WORKITEM_CONFIG workitem_config;
|
james@536
|
538 WDFWORKITEM workitem;
|
james@536
|
539
|
james@536
|
540 UNREFERENCED_PARAMETER(path);
|
james@536
|
541
|
james@536
|
542 FUNCTION_ENTER();
|
james@536
|
543
|
james@536
|
544 res = XenBus_Read(xpdd, XBT_NIL, SHUTDOWN_PATH, &value);
|
james@536
|
545 if (res)
|
james@536
|
546 {
|
james@536
|
547 KdPrint(("Error reading shutdown path - %s\n", res));
|
james@536
|
548 XenPci_FreeMem(res);
|
james@551
|
549 FUNCTION_EXIT();
|
james@536
|
550 return;
|
james@536
|
551 }
|
james@536
|
552
|
james@536
|
553 KdPrint((__DRIVER_NAME " Shutdown value = %s\n", value));
|
james@536
|
554
|
james@536
|
555 if (strlen(value) && strcmp(value, "suspend") == 0)
|
james@536
|
556 {
|
james@536
|
557 {
|
james@536
|
558 KdPrint((__DRIVER_NAME " Suspend detected\n"));
|
james@536
|
559 /* we have to queue this as a work item as we stop the xenbus thread, which we are currently running in! */
|
james@536
|
560 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenPci_SuspendResume);
|
james@536
|
561 WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
|
james@536
|
562 attributes.ParentObject = device;
|
james@536
|
563 status = WdfWorkItemCreate(&workitem_config, &attributes, &workitem);
|
james@536
|
564 // TODO: check status here
|
james@536
|
565 WdfWorkItemEnqueue(workitem);
|
james@536
|
566 }
|
james@536
|
567 }
|
james@536
|
568
|
james@536
|
569 XenPci_FreeMem(value);
|
james@536
|
570
|
james@536
|
571 FUNCTION_EXIT();
|
james@536
|
572 }
|
james@536
|
573
|
james@536
|
574 static VOID
|
james@536
|
575 XenPci_DeviceWatchHandler(char *path, PVOID context)
|
james@536
|
576 {
|
james@536
|
577 char **bits;
|
james@536
|
578 int count;
|
james@536
|
579 char *err;
|
james@536
|
580 char *value;
|
james@536
|
581 PXENPCI_DEVICE_DATA xpdd = context;
|
james@536
|
582
|
james@624
|
583 FUNCTION_ENTER();
|
james@536
|
584
|
james@536
|
585 bits = SplitString(path, '/', 4, &count);
|
james@536
|
586 if (count == 3)
|
james@536
|
587 {
|
james@536
|
588 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
|
james@536
|
589 if (err)
|
james@536
|
590 {
|
james@536
|
591 /* obviously path no longer exists, in which case the removal is being taken care of elsewhere and we shouldn't invalidate now */
|
james@536
|
592 XenPci_FreeMem(err);
|
james@536
|
593 }
|
james@536
|
594 else
|
james@536
|
595 {
|
james@536
|
596 XenPci_FreeMem(value);
|
james@536
|
597 /* we probably have to be a bit smarter here and do nothing if xenpci isn't running yet */
|
james@599
|
598 KdPrint((__DRIVER_NAME " Rescanning child list\n"));
|
james@599
|
599 XenPci_EvtChildListScanForChildren(xpdd->child_list);
|
james@536
|
600 }
|
james@536
|
601 }
|
james@536
|
602 FreeSplitString(bits, count);
|
james@536
|
603
|
james@624
|
604 FUNCTION_EXIT();
|
james@536
|
605 }
|
james@536
|
606
|
james@536
|
607 NTSTATUS
|
james@536
|
608 XenPci_EvtDevicePrepareHardware (WDFDEVICE device, WDFCMRESLIST resources_raw, WDFCMRESLIST resources_translated)
|
james@536
|
609 {
|
james@536
|
610 NTSTATUS status = STATUS_SUCCESS;
|
james@536
|
611 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@536
|
612 PCM_PARTIAL_RESOURCE_DESCRIPTOR raw_descriptor, translated_descriptor;
|
james@536
|
613 ULONG i;
|
james@536
|
614
|
james@536
|
615 FUNCTION_ENTER();
|
james@536
|
616
|
james@536
|
617 ASSERT(WdfCmResourceListGetCount(resources_raw) == WdfCmResourceListGetCount(resources_translated));
|
james@536
|
618
|
james@536
|
619 for (i = 0; i < WdfCmResourceListGetCount(resources_raw); i++)
|
james@536
|
620 {
|
james@536
|
621 raw_descriptor = WdfCmResourceListGetDescriptor(resources_raw, i);
|
james@536
|
622 translated_descriptor = WdfCmResourceListGetDescriptor(resources_translated, i);
|
james@536
|
623 switch (raw_descriptor->Type) {
|
james@536
|
624 case CmResourceTypePort:
|
james@536
|
625 KdPrint((__DRIVER_NAME " IoPort Address(%x) Length: %d\n", translated_descriptor->u.Port.Start.LowPart, translated_descriptor->u.Port.Length));
|
james@536
|
626 xpdd->platform_ioport_addr = translated_descriptor->u.Port.Start.LowPart;
|
james@536
|
627 xpdd->platform_ioport_len = translated_descriptor->u.Port.Length;
|
james@536
|
628 break;
|
james@536
|
629 case CmResourceTypeMemory:
|
james@536
|
630 KdPrint((__DRIVER_NAME " Memory mapped CSR:(%x:%x) Length:(%d)\n", translated_descriptor->u.Memory.Start.LowPart, translated_descriptor->u.Memory.Start.HighPart, translated_descriptor->u.Memory.Length));
|
james@536
|
631 KdPrint((__DRIVER_NAME " Memory flags = %04X\n", translated_descriptor->Flags));
|
james@536
|
632 #if 0
|
james@536
|
633 mmio_freelist_free = 0;
|
james@536
|
634 for (j = 0; j < translated_descriptor->u.Memory.Length >> PAGE_SHIFT; j++)
|
james@536
|
635 put_mmio_on_freelist((xpdd->platform_mmio_addr >> PAGE_SHIFT) + j);
|
james@536
|
636 #endif
|
james@536
|
637 xpdd->platform_mmio_addr = translated_descriptor->u.Memory.Start;
|
james@536
|
638 xpdd->platform_mmio_len = translated_descriptor->u.Memory.Length;
|
james@536
|
639 xpdd->platform_mmio_flags = translated_descriptor->Flags;
|
james@536
|
640 break;
|
james@536
|
641 case CmResourceTypeInterrupt:
|
james@536
|
642 xpdd->irq_level = (KIRQL)translated_descriptor->u.Interrupt.Level;
|
james@536
|
643 xpdd->irq_vector = translated_descriptor->u.Interrupt.Vector;
|
james@536
|
644 xpdd->irq_affinity = translated_descriptor->u.Interrupt.Affinity;
|
james@536
|
645 xpdd->irq_mode = (translated_descriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)?Latched:LevelSensitive;
|
james@536
|
646 xpdd->irq_number = raw_descriptor->u.Interrupt.Vector;
|
james@536
|
647 KdPrint((__DRIVER_NAME " irq_number = %03x\n", raw_descriptor->u.Interrupt.Vector));
|
james@536
|
648 KdPrint((__DRIVER_NAME " irq_vector = %03x\n", translated_descriptor->u.Interrupt.Vector));
|
james@536
|
649 KdPrint((__DRIVER_NAME " irq_level = %03x\n", translated_descriptor->u.Interrupt.Level));
|
james@536
|
650 KdPrint((__DRIVER_NAME " irq_mode = %s\n", (xpdd->irq_mode == Latched)?"Latched":"LevelSensitive"));
|
james@536
|
651 switch(translated_descriptor->ShareDisposition)
|
james@536
|
652 {
|
james@536
|
653 case CmResourceShareDeviceExclusive:
|
james@536
|
654 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDeviceExclusive\n"));
|
james@536
|
655 break;
|
james@536
|
656 case CmResourceShareDriverExclusive:
|
james@536
|
657 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareDriverExclusive\n"));
|
james@536
|
658 break;
|
james@536
|
659 case CmResourceShareShared:
|
james@536
|
660 KdPrint((__DRIVER_NAME " ShareDisposition = CmResourceShareShared\n"));
|
james@536
|
661 break;
|
james@536
|
662 default:
|
james@536
|
663 KdPrint((__DRIVER_NAME " ShareDisposition = %d\n", translated_descriptor->ShareDisposition));
|
james@536
|
664 break;
|
james@536
|
665 }
|
james@536
|
666 break;
|
james@536
|
667 case CmResourceTypeDevicePrivate:
|
james@536
|
668 KdPrint((__DRIVER_NAME " Private Data: 0x%02x 0x%02x 0x%02x\n", translated_descriptor->u.DevicePrivate.Data[0], translated_descriptor->u.DevicePrivate.Data[1], translated_descriptor->u.DevicePrivate.Data[2]));
|
james@536
|
669 break;
|
james@536
|
670 default:
|
james@536
|
671 KdPrint((__DRIVER_NAME " Unhandled resource type (0x%x)\n", translated_descriptor->Type));
|
james@536
|
672 break;
|
james@536
|
673 }
|
james@536
|
674 }
|
james@536
|
675
|
james@536
|
676 FUNCTION_EXIT();
|
james@536
|
677
|
james@536
|
678 return status;
|
james@536
|
679 }
|
james@536
|
680
|
james@536
|
681 NTSTATUS
|
james@536
|
682 XenPci_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
|
james@536
|
683 {
|
james@536
|
684 NTSTATUS status = STATUS_SUCCESS;
|
james@536
|
685 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@694
|
686 ULONG i;
|
james@694
|
687 ULONG ret;
|
james@536
|
688
|
james@538
|
689 FUNCTION_ENTER();
|
james@536
|
690
|
james@538
|
691 xpdd->hibernated = FALSE;
|
james@538
|
692 switch (previous_state)
|
james@538
|
693 {
|
james@538
|
694 case WdfPowerDeviceD0:
|
james@538
|
695 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
|
james@538
|
696 break;
|
james@538
|
697 case WdfPowerDeviceD1:
|
james@538
|
698 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
|
james@538
|
699 break;
|
james@538
|
700 case WdfPowerDeviceD2:
|
james@538
|
701 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
|
james@538
|
702 break;
|
james@538
|
703 case WdfPowerDeviceD3:
|
james@538
|
704 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
|
james@538
|
705 break;
|
james@538
|
706 case WdfPowerDeviceD3Final:
|
james@538
|
707 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
|
james@538
|
708 break;
|
james@538
|
709 case WdfPowerDevicePrepareForHibernation:
|
james@538
|
710 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
|
james@538
|
711 break;
|
james@538
|
712 default:
|
james@538
|
713 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
|
james@538
|
714 break;
|
james@538
|
715 }
|
james@551
|
716
|
james@747
|
717 if (previous_state == WdfPowerDevicePrepareForHibernation && qemu_hide_flags_value)
|
james@551
|
718 {
|
james@551
|
719 XenPci_HideQemuDevices();
|
james@624
|
720 }
|
james@536
|
721
|
james@624
|
722 if (previous_state == WdfPowerDeviceD3Final)
|
james@536
|
723 {
|
james@624
|
724 XenPci_Init(xpdd);
|
james@624
|
725 if (tpr_patch_requested && !xpdd->tpr_patched)
|
james@624
|
726 {
|
james@624
|
727 XenPci_MapHalThenPatchKernel(xpdd);
|
james@624
|
728 xpdd->tpr_patched = TRUE;
|
james@624
|
729 }
|
james@624
|
730 GntTbl_Init(xpdd);
|
james@624
|
731 EvtChn_Init(xpdd);
|
james@694
|
732
|
james@694
|
733 for (i = 0; i < NR_GRANT_FRAMES + 1; i++)
|
james@694
|
734 {
|
james@694
|
735 struct xen_memory_reservation reservation;
|
james@697
|
736 xen_pfn_t pfn;
|
james@694
|
737 PMDL mdl = AllocatePage();
|
james@697
|
738 pfn = (xen_pfn_t)(MmGetMdlPfnArray(mdl)[0]);
|
james@694
|
739 reservation.address_bits = 0;
|
james@694
|
740 reservation.extent_order = 0;
|
james@694
|
741 reservation.domid = DOMID_SELF;
|
james@694
|
742 reservation.nr_extents = 1;
|
james@694
|
743 #pragma warning(disable: 4127) /* conditional expression is constant */
|
james@694
|
744 set_xen_guest_handle(reservation.extent_start, &pfn);
|
james@702
|
745
|
james@702
|
746 //KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
|
james@694
|
747 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
|
james@702
|
748 //KdPrint((__DRIVER_NAME " decreased %d pages\n", ret));
|
james@694
|
749 }
|
james@694
|
750
|
james@694
|
751 // use the memory_op(unsigned int op, void *arg) hypercall to adjust memory
|
james@694
|
752 // use XENMEM_increase_reservation and XENMEM_decrease_reservation
|
james@551
|
753 }
|
james@551
|
754 else
|
james@551
|
755 {
|
james@624
|
756 XenPci_Resume(xpdd);
|
james@624
|
757 GntTbl_Resume(xpdd);
|
james@624
|
758 EvtChn_Resume(xpdd);
|
james@551
|
759 }
|
james@536
|
760
|
james@536
|
761 FUNCTION_EXIT();
|
james@536
|
762
|
james@536
|
763 return status;
|
james@536
|
764 }
|
james@536
|
765
|
james@536
|
766 NTSTATUS
|
james@536
|
767 XenPci_EvtDeviceD0EntryPostInterruptsEnabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state)
|
james@536
|
768 {
|
james@536
|
769 NTSTATUS status = STATUS_SUCCESS;
|
james@536
|
770 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@536
|
771 PCHAR response;
|
james@591
|
772 char *value;
|
james@591
|
773 domid_t domid = DOMID_SELF;
|
james@591
|
774 ULONG ret;
|
james@594
|
775 xen_ulong_t *max_ram_page;
|
james@622
|
776 HANDLE thread_handle;
|
james@536
|
777
|
james@536
|
778 UNREFERENCED_PARAMETER(previous_state);
|
james@536
|
779
|
james@536
|
780 FUNCTION_ENTER();
|
james@536
|
781
|
james@624
|
782 if (previous_state == WdfPowerDeviceD3Final)
|
james@624
|
783 {
|
james@624
|
784 XenBus_Init(xpdd);
|
james@536
|
785
|
james@624
|
786 XenPci_ConnectSuspendEvt(xpdd);
|
james@624
|
787
|
james@624
|
788 response = XenBus_AddWatch(xpdd, XBT_NIL, SYSRQ_PATH, XenPci_SysrqHandler, xpdd);
|
james@624
|
789
|
james@624
|
790 response = XenBus_AddWatch(xpdd, XBT_NIL, SHUTDOWN_PATH, XenPci_ShutdownHandler, device);
|
james@536
|
791
|
james@624
|
792 response = XenBus_AddWatch(xpdd, XBT_NIL, "device", XenPci_DeviceWatchHandler, xpdd);
|
james@624
|
793
|
james@624
|
794 ret = HYPERVISOR_memory_op(xpdd, XENMEM_current_reservation, &domid);
|
james@624
|
795 KdPrint((__DRIVER_NAME " XENMEM_current_reservation = %d\n", ret));
|
james@624
|
796 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_reservation, &domid);
|
james@624
|
797 KdPrint((__DRIVER_NAME " XENMEM_maximum_reservation = %d\n", ret));
|
james@624
|
798 ret = HYPERVISOR_memory_op(xpdd, XENMEM_maximum_ram_page, &max_ram_page);
|
james@624
|
799 KdPrint((__DRIVER_NAME " XENMEM_maximum_ram_page = %d\n", ret));
|
james@624
|
800
|
james@624
|
801 if (!xpdd->initial_memory)
|
james@624
|
802 {
|
james@624
|
803 XenBus_Read(xpdd, XBT_NIL, BALLOON_PATH, &value);
|
james@624
|
804 if (atoi(value) > 0)
|
james@624
|
805 {
|
james@624
|
806 xpdd->initial_memory = atoi(value) >> 10; /* convert to MB */
|
james@624
|
807 xpdd->current_memory = xpdd->initial_memory;
|
james@624
|
808 xpdd->target_memory = xpdd->initial_memory;
|
james@624
|
809 }
|
james@624
|
810 KdPrint((__DRIVER_NAME " Initial Memory Value = %d (%s)\n", xpdd->initial_memory, value));
|
james@624
|
811 KeInitializeEvent(&xpdd->balloon_event, SynchronizationEvent, FALSE);
|
james@624
|
812 xpdd->balloon_shutdown = FALSE;
|
james@624
|
813 status = PsCreateSystemThread(&thread_handle, THREAD_ALL_ACCESS, NULL, NULL, NULL, XenPci_BalloonThreadProc, xpdd);
|
james@624
|
814 if (!NT_SUCCESS(status))
|
james@624
|
815 {
|
james@624
|
816 KdPrint((__DRIVER_NAME " Could not start balloon thread\n"));
|
james@624
|
817 return status;
|
james@624
|
818 }
|
james@624
|
819 status = ObReferenceObjectByHandle(thread_handle, THREAD_ALL_ACCESS, NULL, KernelMode, &xpdd->balloon_thread, NULL);
|
james@624
|
820 ZwClose(thread_handle);
|
james@624
|
821 }
|
james@624
|
822 response = XenBus_AddWatch(xpdd, XBT_NIL, BALLOON_PATH, XenPci_BalloonHandler, device);
|
james@624
|
823 }
|
james@624
|
824 else
|
james@536
|
825 {
|
james@624
|
826 XenBus_Resume(xpdd);
|
james@624
|
827 XenPci_ConnectSuspendEvt(xpdd);
|
james@536
|
828 }
|
james@536
|
829 FUNCTION_EXIT();
|
james@536
|
830
|
james@536
|
831 return status;
|
james@536
|
832 }
|
james@536
|
833
|
james@536
|
834 NTSTATUS
|
james@536
|
835 XenPci_EvtDeviceD0ExitPreInterruptsDisabled(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
|
james@536
|
836 {
|
james@536
|
837 NTSTATUS status = STATUS_SUCCESS;
|
james@622
|
838 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@622
|
839 LARGE_INTEGER timeout;
|
james@536
|
840
|
james@536
|
841 FUNCTION_ENTER();
|
james@538
|
842
|
james@538
|
843 switch (target_state)
|
james@538
|
844 {
|
james@538
|
845 case WdfPowerDeviceD0:
|
james@538
|
846 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
|
james@538
|
847 break;
|
james@538
|
848 case WdfPowerDeviceD1:
|
james@538
|
849 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
|
james@538
|
850 break;
|
james@538
|
851 case WdfPowerDeviceD2:
|
james@538
|
852 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
|
james@538
|
853 break;
|
james@538
|
854 case WdfPowerDeviceD3:
|
james@538
|
855 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
|
james@538
|
856 break;
|
james@538
|
857 case WdfPowerDeviceD3Final:
|
james@538
|
858 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
|
james@538
|
859 break;
|
james@538
|
860 case WdfPowerDevicePrepareForHibernation:
|
james@538
|
861 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
|
james@538
|
862 break;
|
james@538
|
863 default:
|
james@538
|
864 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
|
james@538
|
865 break;
|
james@538
|
866 }
|
james@624
|
867
|
james@624
|
868 if (target_state == WdfPowerDeviceD3Final)
|
james@624
|
869 {
|
james@624
|
870 KdPrint((__DRIVER_NAME " Shutting down threads\n"));
|
james@624
|
871
|
james@624
|
872 xpdd->balloon_shutdown = TRUE;
|
james@624
|
873 KeSetEvent(&xpdd->balloon_event, IO_NO_INCREMENT, FALSE);
|
james@622
|
874
|
james@622
|
875 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
|
james@624
|
876 while ((status = KeWaitForSingleObject(xpdd->balloon_thread, Executive, KernelMode, FALSE, &timeout)) != STATUS_SUCCESS)
|
james@624
|
877 {
|
james@624
|
878 timeout.QuadPart = (LONGLONG)-1 * 1000 * 1000 * 10;
|
james@624
|
879 KdPrint((__DRIVER_NAME " Waiting for balloon thread to stop\n"));
|
james@624
|
880 }
|
james@624
|
881 ObDereferenceObject(xpdd->balloon_thread);
|
james@624
|
882
|
james@624
|
883 XenBus_Halt(xpdd);
|
james@622
|
884 }
|
james@624
|
885 else
|
james@624
|
886 {
|
james@624
|
887 XenBus_Suspend(xpdd);
|
james@624
|
888 }
|
james@622
|
889
|
james@536
|
890 FUNCTION_EXIT();
|
james@536
|
891
|
james@536
|
892 return status;
|
james@536
|
893 }
|
james@536
|
894
|
james@536
|
895 NTSTATUS
|
james@536
|
896 XenPci_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state)
|
james@536
|
897 {
|
james@536
|
898 NTSTATUS status = STATUS_SUCCESS;
|
james@538
|
899 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
|
james@536
|
900
|
james@536
|
901 FUNCTION_ENTER();
|
james@538
|
902
|
james@538
|
903 switch (target_state)
|
james@538
|
904 {
|
james@538
|
905 case WdfPowerDeviceD0:
|
james@538
|
906 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
|
james@538
|
907 break;
|
james@538
|
908 case WdfPowerDeviceD1:
|
james@538
|
909 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
|
james@538
|
910 break;
|
james@538
|
911 case WdfPowerDeviceD2:
|
james@538
|
912 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
|
james@538
|
913 break;
|
james@538
|
914 case WdfPowerDeviceD3:
|
james@538
|
915 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
|
james@538
|
916 break;
|
james@538
|
917 case WdfPowerDeviceD3Final:
|
james@538
|
918 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
|
james@538
|
919 break;
|
james@538
|
920 case WdfPowerDevicePrepareForHibernation:
|
james@538
|
921 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
|
james@538
|
922 xpdd->hibernated = TRUE;
|
james@538
|
923 break;
|
james@538
|
924 default:
|
james@538
|
925 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
|
james@538
|
926 break;
|
james@538
|
927 }
|
james@551
|
928
|
james@624
|
929 if (target_state == WdfPowerDeviceD3Final)
|
james@624
|
930 {
|
james@624
|
931 /* we don't really support exit here */
|
james@624
|
932 }
|
james@624
|
933 else
|
james@551
|
934 {
|
james@551
|
935 GntTbl_Suspend(xpdd);
|
james@551
|
936 }
|
james@538
|
937
|
james@536
|
938 FUNCTION_EXIT();
|
james@536
|
939
|
james@536
|
940 return status;
|
james@536
|
941 }
|
james@536
|
942
|
james@536
|
943 NTSTATUS
|
james@536
|
944 XenPci_EvtDeviceReleaseHardware(WDFDEVICE device, WDFCMRESLIST resources_translated)
|
james@536
|
945 {
|
james@536
|
946 NTSTATUS status = STATUS_SUCCESS;
|
james@536
|
947
|
james@536
|
948 UNREFERENCED_PARAMETER(device);
|
james@536
|
949 UNREFERENCED_PARAMETER(resources_translated);
|
james@536
|
950
|
james@536
|
951 FUNCTION_ENTER();
|
james@536
|
952 FUNCTION_EXIT();
|
james@536
|
953
|
james@536
|
954 return status;
|
james@536
|
955 }
|
james@536
|
956
|
james@624
|
957 /* Called at PASSIVE_LEVEL but with pagefile unavailable */
|
james@790
|
958 /* Can be called concurrently, but KMDF takes care of concurrent calls to WdfChildListXxx */
|
james@536
|
959 VOID
|
james@536
|
960 XenPci_EvtChildListScanForChildren(WDFCHILDLIST child_list)
|
james@536
|
961 {
|
james@536
|
962 NTSTATUS status;
|
james@536
|
963 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
|
james@536
|
964 char *msg;
|
james@536
|
965 char **devices;
|
james@536
|
966 char **instances;
|
james@538
|
967 ULONG i, j;
|
james@536
|
968 CHAR path[128];
|
james@536
|
969 XENPCI_PDO_IDENTIFICATION_DESCRIPTION child_description;
|
james@624
|
970 PVOID entry;
|
james@536
|
971
|
james@536
|
972 FUNCTION_ENTER();
|
james@536
|
973
|
james@536
|
974 WdfChildListBeginScan(child_list);
|
james@536
|
975
|
james@536
|
976 msg = XenBus_List(xpdd, XBT_NIL, "device", &devices);
|
james@536
|
977 if (!msg)
|
james@536
|
978 {
|
james@536
|
979 for (i = 0; devices[i]; i++)
|
james@536
|
980 {
|
james@628
|
981 /* make sure the key is not in the veto list */
|
james@624
|
982 for (entry = xpdd->veto_list.Flink; entry != &xpdd->veto_list; entry = ((PLIST_ENTRY)entry)->Flink)
|
james@538
|
983 {
|
james@624
|
984 if (!strcmp(devices[i], (PCHAR)entry + sizeof(LIST_ENTRY)))
|
james@538
|
985 break;
|
james@538
|
986 }
|
james@624
|
987 if (entry != &xpdd->veto_list)
|
james@538
|
988 {
|
james@538
|
989 XenPci_FreeMem(devices[i]);
|
james@538
|
990 continue;
|
james@538
|
991 }
|
james@538
|
992
|
james@628
|
993 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s", devices[i]);
|
james@536
|
994 msg = XenBus_List(xpdd, XBT_NIL, path, &instances);
|
james@536
|
995 if (!msg)
|
james@536
|
996 {
|
james@536
|
997 for (j = 0; instances[j]; j++)
|
james@536
|
998 {
|
james@536
|
999 /* the device comparison is done as a memory compare so zero-ing the structure is important */
|
james@536
|
1000 RtlZeroMemory(&child_description, sizeof(child_description));
|
james@536
|
1001 WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_INIT(&child_description.header, sizeof(child_description));
|
james@536
|
1002 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "device/%s/%s", devices[i], instances[j]);
|
james@683
|
1003 KdPrint((__DRIVER_NAME " Found path = %s\n", path));
|
james@536
|
1004 RtlStringCbCopyA(child_description.path, ARRAY_SIZE(child_description.path), path);
|
james@536
|
1005 RtlStringCbCopyA(child_description.device, ARRAY_SIZE(child_description.device), devices[i]);
|
james@536
|
1006 child_description.index = atoi(instances[j]);
|
james@536
|
1007 status = WdfChildListAddOrUpdateChildDescriptionAsPresent(child_list, &child_description.header, NULL);
|
james@536
|
1008 if (!NT_SUCCESS(status))
|
james@536
|
1009 {
|
james@536
|
1010 KdPrint((__DRIVER_NAME " WdfChildListAddOrUpdateChildDescriptionAsPresent failed with status 0x%08x\n", status));
|
james@536
|
1011 }
|
james@536
|
1012 XenPci_FreeMem(instances[j]);
|
james@536
|
1013 }
|
james@536
|
1014 XenPci_FreeMem(instances);
|
james@536
|
1015 }
|
james@536
|
1016 else
|
james@536
|
1017 {
|
james@536
|
1018 // wtf do we do here???
|
james@536
|
1019 KdPrint((__DRIVER_NAME " Failed to list %s tree\n", devices[i]));
|
james@536
|
1020 }
|
james@536
|
1021 XenPci_FreeMem(devices[i]);
|
james@536
|
1022 }
|
james@536
|
1023 XenPci_FreeMem(devices);
|
james@536
|
1024 }
|
james@536
|
1025 else
|
james@536
|
1026 {
|
james@536
|
1027 // wtf do we do here???
|
james@536
|
1028 KdPrint((__DRIVER_NAME " Failed to list device tree\n"));
|
james@536
|
1029 }
|
james@536
|
1030
|
james@536
|
1031 WdfChildListEndScan(child_list);
|
james@624
|
1032
|
james@536
|
1033 FUNCTION_EXIT();
|
james@536
|
1034 }
|