win-pvdrivers

view xenpci/gnttbl.c @ 992:58899e6ed48f

Tidy Up
author James Harper <james.harper@bendigoit.com.au>
date Fri Sep 21 23:25:49 2012 +1000 (2012-09-21)
parents fc54b0c09c08
children cd72cd0e1c19
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 VOID
23 GntTbl_PutRef(PVOID Context, grant_ref_t ref, ULONG tag)
24 {
25 PXENPCI_DEVICE_DATA xpdd = Context;
27 UNREFERENCED_PARAMETER(tag);
29 #if DBG
30 if (xpdd->gnttbl_tag[ref].tag != tag)
31 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s doesn't match %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag));
32 NT_ASSERT(xpdd->gnttbl_tag[ref].tag == tag);
33 xpdd->gnttbl_tag[ref].tag = 0;
34 xpdd->gnttbl_tag[ref].generation = (ULONG)-1;
35 #endif
36 stack_push(xpdd->gnttbl_ss, (PVOID)ref);
37 }
39 grant_ref_t
40 GntTbl_GetRef(PVOID Context, ULONG tag)
41 {
42 PXENPCI_DEVICE_DATA xpdd = Context;
43 unsigned int ref;
44 PVOID ptr_ref;
46 UNREFERENCED_PARAMETER(tag);
48 if (!stack_pop(xpdd->gnttbl_ss, &ptr_ref))
49 {
50 KdPrint((__DRIVER_NAME " No free grant refs\n"));
51 return INVALID_GRANT_REF;
52 }
53 ref = (grant_ref_t)(ULONG_PTR)ptr_ref;
54 #if DBG
55 if (xpdd->gnttbl_tag[ref].tag)
56 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s in use by %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag));
57 NT_ASSERT(!xpdd->gnttbl_tag[ref].tag);
58 xpdd->gnttbl_tag[ref].generation = xpdd->gnttbl_generation;
59 xpdd->gnttbl_tag[ref].tag = tag;
60 #endif
62 return ref;
63 }
65 int
66 GntTbl_Map(PVOID Context, unsigned int start_idx, unsigned int end_idx)
67 {
68 PXENPCI_DEVICE_DATA xpdd = Context;
69 struct xen_add_to_physmap xatp;
70 unsigned int i = end_idx;
72 FUNCTION_ENTER();
73 /* Loop backwards, so that the first hypercall has the largest index, ensuring that the table will grow only once. */
74 do {
75 xatp.domid = DOMID_SELF;
76 xatp.idx = i;
77 xatp.space = XENMAPSPACE_grant_table;
78 xatp.gpfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
79 if (HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp))
80 {
81 KdPrint((__DRIVER_NAME " *** ERROR MAPPING FRAME %d ***\n", i));
82 }
83 } while (i-- > start_idx);
84 FUNCTION_EXIT();
86 return 0;
87 }
89 grant_ref_t
90 GntTbl_GrantAccess(
91 PVOID Context,
92 domid_t domid,
93 uint32_t frame, // xen api limits pfn to 32bit, so no guests over 8TB
94 int readonly,
95 grant_ref_t ref,
96 ULONG tag)
97 {
98 PXENPCI_DEVICE_DATA xpdd = Context;
100 //KdPrint((__DRIVER_NAME " --> GntTbl_GrantAccess\n"));
102 if (ref == INVALID_GRANT_REF)
103 ref = GntTbl_GetRef(Context, tag);
104 if (ref == INVALID_GRANT_REF)
105 return ref;
107 NT_ASSERT(xpdd->gnttbl_tag[ref].tag == tag);
109 xpdd->gnttbl_table[ref].frame = frame;
110 xpdd->gnttbl_table[ref].domid = domid;
112 if (xpdd->gnttbl_table[ref].flags)
113 {
114 #if DBG
115 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still in use by %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag));
116 #else
117 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still in use\n", ref, (PUCHAR)&tag));
118 #endif
119 }
120 NT_ASSERT(!xpdd->gnttbl_table[ref].flags);
122 KeMemoryBarrier();
123 readonly *= GTF_readonly;
124 xpdd->gnttbl_table[ref].flags = GTF_permit_access | (uint16_t)readonly;
126 return ref;
127 }
129 BOOLEAN
130 GntTbl_EndAccess(
131 PVOID Context,
132 grant_ref_t ref,
133 BOOLEAN keepref,
134 ULONG tag)
135 {
136 PXENPCI_DEVICE_DATA xpdd = Context;
137 unsigned short flags, nflags;
139 NT_ASSERT(ref != INVALID_GRANT_REF);
140 NT_ASSERT(xpdd->gnttbl_tag[ref].tag == tag);
142 nflags = xpdd->gnttbl_table[ref].flags;
143 do {
144 if ((flags = nflags) & (GTF_reading|GTF_writing))
145 {
146 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still use\n", ref, (PUCHAR)&tag));
147 return FALSE;
148 }
149 } while ((nflags = InterlockedCompareExchange16(
150 (volatile SHORT *)&xpdd->gnttbl_table[ref].flags, 0, flags)) != flags);
152 if (!keepref)
153 GntTbl_PutRef(Context, ref, tag);
154 //KdPrint((__DRIVER_NAME " <-- GntTbl_EndAccess\n"));
155 return TRUE;
156 }
158 static unsigned int
159 GntTbl_QueryMaxFrames(PXENPCI_DEVICE_DATA xpdd)
160 {
161 struct gnttab_query_size query;
162 int rc;
164 query.dom = DOMID_SELF;
166 rc = HYPERVISOR_grant_table_op(xpdd, GNTTABOP_query_size, &query, 1);
167 if ((rc < 0) || (query.status != GNTST_okay))
168 {
169 KdPrint((__DRIVER_NAME " ***CANNOT QUERY MAX GRANT FRAME***\n"));
170 return 4; /* Legacy max supported number of frames */
171 }
172 return query.max_nr_frames;
173 }
175 VOID
176 GntTbl_Init(PXENPCI_DEVICE_DATA xpdd)
177 {
178 int i;
179 int grant_entries;
181 NT_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
183 FUNCTION_ENTER();
185 xpdd->grant_frames = GntTbl_QueryMaxFrames(xpdd);
186 KdPrint((__DRIVER_NAME " grant_frames = %d\n", xpdd->grant_frames));
187 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
188 KdPrint((__DRIVER_NAME " grant_entries = %d\n", grant_entries));
189 #if DBG
190 xpdd->gnttbl_tag = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(grant_tag_t), XENPCI_POOL_TAG);
191 RtlZeroMemory(xpdd->gnttbl_tag, grant_entries * sizeof(grant_tag_t));
192 xpdd->gnttbl_tag_copy = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(grant_tag_t), XENPCI_POOL_TAG);
193 xpdd->gnttbl_generation = 0;
194 #endif
195 xpdd->gnttbl_table_copy = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
196 NT_ASSERT(xpdd->gnttbl_table_copy); // lazy
197 xpdd->gnttbl_table = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
198 NT_ASSERT(xpdd->gnttbl_table); // lazy
199 /* dom0 crashes if we allocate the wrong amount of memory here! */
200 xpdd->gnttbl_mdl = IoAllocateMdl(xpdd->gnttbl_table, xpdd->grant_frames * PAGE_SIZE, FALSE, FALSE, NULL);
201 NT_ASSERT(xpdd->gnttbl_mdl); // lazy
202 MmBuildMdlForNonPagedPool(xpdd->gnttbl_mdl);
204 /* make some holes for the grant pages to fill in */
205 for (i = 0; i < (int)xpdd->grant_frames; i++)
206 {
207 struct xen_memory_reservation reservation;
208 xen_pfn_t pfn;
209 ULONG ret;
211 reservation.address_bits = 0;
212 reservation.extent_order = 0;
213 reservation.domid = DOMID_SELF;
214 reservation.nr_extents = 1;
215 #pragma warning(disable: 4127) /* conditional expression is constant */
216 pfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
217 KdPrint((__DRIVER_NAME " pfn = %x\n", (ULONG)pfn));
218 set_xen_guest_handle(reservation.extent_start, &pfn);
220 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
221 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
222 KdPrint((__DRIVER_NAME " decreased %d pages for grant table frame %d\n", ret, i));
223 }
225 stack_new(&xpdd->gnttbl_ss, grant_entries);
227 for (i = NR_RESERVED_ENTRIES; i < grant_entries; i++)
228 stack_push(xpdd->gnttbl_ss, (PVOID)i);
230 GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
232 RtlZeroMemory(xpdd->gnttbl_table, PAGE_SIZE * xpdd->grant_frames);
234 FUNCTION_EXIT();
235 }
237 VOID
238 GntTbl_Suspend(PXENPCI_DEVICE_DATA xpdd)
239 {
240 #if DBG
241 int grant_entries;
242 #endif
243 int i;
245 FUNCTION_ENTER();
247 #if DBG
248 for (i = 0; i < (int)min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t))); i++)
249 {
250 if (xpdd->gnttbl_tag[i].tag != 0) // && xpdd->gnttbl_tag[i].generation < xpdd->gnttbl_generation)
251 {
252 KdPrint((__DRIVER_NAME " grant entry for %.4s from generation %d\n", (PUCHAR)&xpdd->gnttbl_tag[i].tag, xpdd->gnttbl_tag[i].generation));
253 }
254 }
255 xpdd->gnttbl_generation++;
256 #endif
258 /* copy some grant refs and switch to an alternate freelist, but only on hiber */
259 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
260 {
261 KdPrint((__DRIVER_NAME " backing up grant ref stack\n"));
262 for (i = 0; i < HIBER_GREF_COUNT; i++)
263 {
264 xpdd->hiber_grefs[i] = INVALID_GRANT_REF;
265 }
266 for (i = 0; i < HIBER_GREF_COUNT; i++)
267 {
268 if ((xpdd->hiber_grefs[i] = GntTbl_GetRef(xpdd, (ULONG)'HIBR')) == INVALID_GRANT_REF)
269 break;
270 }
271 KdPrint((__DRIVER_NAME " %d grant refs reserved\n", i));
272 xpdd->gnttbl_ss_copy = xpdd->gnttbl_ss;
273 stack_new(&xpdd->gnttbl_ss, HIBER_GREF_COUNT);
274 }
275 else
276 {
277 xpdd->gnttbl_ss_copy = NULL;
278 }
280 memcpy(xpdd->gnttbl_table_copy, xpdd->gnttbl_table, xpdd->grant_frames * PAGE_SIZE);
281 #if DBG
282 /* even though gnttbl_tag is actually preserved, it is used by the dump driver so must be restored to exactly the same state as it was on suspend */
283 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
284 memcpy(xpdd->gnttbl_tag_copy, xpdd->gnttbl_tag, grant_entries * sizeof(grant_tag_t));
285 #endif
287 /* put the grant entries on the new freelist, after copying the tables above */
288 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
289 {
290 for (i = 0; i < HIBER_GREF_COUNT; i++)
291 {
292 if (xpdd->hiber_grefs[i] == INVALID_GRANT_REF)
293 break;
294 GntTbl_PutRef(xpdd, xpdd->hiber_grefs[i], (ULONG)'HIBR');
295 }
296 }
298 FUNCTION_EXIT();
299 }
301 VOID
302 GntTbl_Resume(PXENPCI_DEVICE_DATA xpdd)
303 {
304 ULONG new_grant_frames;
305 ULONG result;
306 int i;
307 #if DBG
308 int grant_entries;
309 #endif
311 FUNCTION_ENTER();
313 for (i = 0; i < (int)xpdd->grant_frames; i++)
314 {
315 struct xen_memory_reservation reservation;
316 xen_pfn_t pfn;
317 ULONG ret;
319 reservation.address_bits = 0;
320 reservation.extent_order = 0;
321 reservation.domid = DOMID_SELF;
322 reservation.nr_extents = 1;
323 #pragma warning(disable: 4127) /* conditional expression is constant */
324 pfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
325 KdPrint((__DRIVER_NAME " pfn = %x\n", (ULONG)pfn));
326 set_xen_guest_handle(reservation.extent_start, &pfn);
328 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
329 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
330 KdPrint((__DRIVER_NAME " decreased %d pages for grant table frame %d\n", ret, i));
331 }
333 new_grant_frames = GntTbl_QueryMaxFrames(xpdd);
334 KdPrint((__DRIVER_NAME " new_grant_frames = %d\n", new_grant_frames));
335 NT_ASSERT(new_grant_frames >= xpdd->grant_frames); // lazy
336 result = GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
337 KdPrint((__DRIVER_NAME " GntTbl_Map result = %d\n", result));
338 memcpy(xpdd->gnttbl_table, xpdd->gnttbl_table_copy, xpdd->grant_frames * PAGE_SIZE);
339 #if DBG
340 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
341 memcpy(xpdd->gnttbl_tag, xpdd->gnttbl_tag_copy, grant_entries * sizeof(grant_tag_t));
342 #endif
344 /* switch back and put the hiber grants back again */
345 if (xpdd->gnttbl_ss_copy)
346 {
347 KdPrint((__DRIVER_NAME " restoring grant ref stack\n"));
348 stack_delete(xpdd->gnttbl_ss, NULL, NULL);
349 xpdd->gnttbl_ss = xpdd->gnttbl_ss_copy;
350 for (i = 0; i < HIBER_GREF_COUNT; i++)
351 {
352 if (xpdd->hiber_grefs[i] == INVALID_GRANT_REF)
353 break;
354 GntTbl_PutRef(xpdd, xpdd->hiber_grefs[i], (ULONG)'HIBR');
355 }
356 xpdd->gnttbl_ss_copy = NULL;
357 }
359 FUNCTION_EXIT();
360 }