win-pvdrivers

view xenpci/gnttbl.c @ 1030:37c0c84a42e8

Tidy up KdPrints
author James Harper <james.harper@bendigoit.com.au>
date Wed Feb 20 20:49:26 2013 +1100 (2013-02-20)
parents cd72cd0e1c19
children 471c94d04d8a
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 FUNCTION_MSG("Grant Entry %d for %.4s doesn't match %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag);
32 XN_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 FUNCTION_MSG("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 FUNCTION_MSG("Grant Entry %d for %.4s in use by %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag);
57 XN_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 FUNCTION_MSG("*** 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 if (ref == INVALID_GRANT_REF)
101 ref = GntTbl_GetRef(Context, tag);
102 if (ref == INVALID_GRANT_REF)
103 return ref;
105 XN_ASSERT(xpdd->gnttbl_tag[ref].tag == tag);
107 xpdd->gnttbl_table[ref].frame = frame;
108 xpdd->gnttbl_table[ref].domid = domid;
110 if (xpdd->gnttbl_table[ref].flags)
111 {
112 #if DBG
113 FUNCTION_MSG("Grant Entry %d for %.4s still in use by %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag);
114 #else
115 FUNCTION_MSG("Grant Entry %d for %.4s still in use\n", ref, (PUCHAR)&tag);
116 #endif
117 }
118 XN_ASSERT(!xpdd->gnttbl_table[ref].flags);
120 KeMemoryBarrier();
121 readonly *= GTF_readonly;
122 xpdd->gnttbl_table[ref].flags = GTF_permit_access | (uint16_t)readonly;
124 return ref;
125 }
127 BOOLEAN
128 GntTbl_EndAccess(
129 PVOID Context,
130 grant_ref_t ref,
131 BOOLEAN keepref,
132 ULONG tag)
133 {
134 PXENPCI_DEVICE_DATA xpdd = Context;
135 unsigned short flags, nflags;
137 XN_ASSERT(ref != INVALID_GRANT_REF);
138 XN_ASSERT(xpdd->gnttbl_tag[ref].tag == tag);
140 nflags = xpdd->gnttbl_table[ref].flags;
141 do {
142 if ((flags = nflags) & (GTF_reading|GTF_writing))
143 {
144 FUNCTION_MSG("Grant Entry %d for %.4s still use\n", ref, (PUCHAR)&tag);
145 return FALSE;
146 }
147 } while ((nflags = InterlockedCompareExchange16(
148 (volatile SHORT *)&xpdd->gnttbl_table[ref].flags, 0, flags)) != flags);
150 if (!keepref)
151 GntTbl_PutRef(Context, ref, tag);
153 return TRUE;
154 }
156 static unsigned int
157 GntTbl_QueryMaxFrames(PXENPCI_DEVICE_DATA xpdd)
158 {
159 struct gnttab_query_size query;
160 int rc;
162 query.dom = DOMID_SELF;
164 rc = HYPERVISOR_grant_table_op(xpdd, GNTTABOP_query_size, &query, 1);
165 if ((rc < 0) || (query.status != GNTST_okay))
166 {
167 FUNCTION_MSG("***CANNOT QUERY MAX GRANT FRAME***\n");
168 return 4; /* Legacy max supported number of frames */
169 }
170 return query.max_nr_frames;
171 }
173 VOID
174 GntTbl_Init(PXENPCI_DEVICE_DATA xpdd)
175 {
176 int i;
177 int grant_entries;
179 XN_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
181 FUNCTION_ENTER();
183 xpdd->grant_frames = GntTbl_QueryMaxFrames(xpdd);
184 FUNCTION_MSG("grant_frames = %d\n", xpdd->grant_frames);
185 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
186 FUNCTION_MSG("grant_entries = %d\n", grant_entries);
187 #if DBG
188 xpdd->gnttbl_tag = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(grant_tag_t), XENPCI_POOL_TAG);
189 RtlZeroMemory(xpdd->gnttbl_tag, grant_entries * sizeof(grant_tag_t));
190 xpdd->gnttbl_tag_copy = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(grant_tag_t), XENPCI_POOL_TAG);
191 xpdd->gnttbl_generation = 0;
192 #endif
193 xpdd->gnttbl_table_copy = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
194 XN_ASSERT(xpdd->gnttbl_table_copy); // lazy
195 xpdd->gnttbl_table = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
196 XN_ASSERT(xpdd->gnttbl_table); // lazy
197 /* dom0 crashes if we allocate the wrong amount of memory here! */
198 xpdd->gnttbl_mdl = IoAllocateMdl(xpdd->gnttbl_table, xpdd->grant_frames * PAGE_SIZE, FALSE, FALSE, NULL);
199 XN_ASSERT(xpdd->gnttbl_mdl); // lazy
200 MmBuildMdlForNonPagedPool(xpdd->gnttbl_mdl);
202 /* make some holes for the grant pages to fill in */
203 for (i = 0; i < (int)xpdd->grant_frames; i++)
204 {
205 struct xen_memory_reservation reservation;
206 xen_pfn_t pfn;
207 ULONG ret;
209 reservation.address_bits = 0;
210 reservation.extent_order = 0;
211 reservation.domid = DOMID_SELF;
212 reservation.nr_extents = 1;
213 #pragma warning(disable: 4127) /* conditional expression is constant */
214 pfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
215 FUNCTION_MSG("pfn = %x\n", (ULONG)pfn);
216 set_xen_guest_handle(reservation.extent_start, &pfn);
218 FUNCTION_MSG("Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn);
219 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
220 FUNCTION_MSG("decreased %d pages for grant table frame %d\n", ret, i);
221 }
223 stack_new(&xpdd->gnttbl_ss, grant_entries);
225 for (i = NR_RESERVED_ENTRIES; i < grant_entries; i++)
226 stack_push(xpdd->gnttbl_ss, (PVOID)i);
228 GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
230 RtlZeroMemory(xpdd->gnttbl_table, PAGE_SIZE * xpdd->grant_frames);
232 FUNCTION_EXIT();
233 }
235 VOID
236 GntTbl_Suspend(PXENPCI_DEVICE_DATA xpdd)
237 {
238 #if DBG
239 int grant_entries;
240 #endif
241 int i;
243 FUNCTION_ENTER();
245 #if DBG
246 for (i = 0; i < (int)min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t))); i++)
247 {
248 if (xpdd->gnttbl_tag[i].tag != 0) // && xpdd->gnttbl_tag[i].generation < xpdd->gnttbl_generation)
249 {
250 FUNCTION_MSG("grant entry for %.4s from generation %d\n", (PUCHAR)&xpdd->gnttbl_tag[i].tag, xpdd->gnttbl_tag[i].generation);
251 }
252 }
253 xpdd->gnttbl_generation++;
254 #endif
256 /* copy some grant refs and switch to an alternate freelist, but only on hiber */
257 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
258 {
259 FUNCTION_MSG("backing up grant ref stack\n");
260 for (i = 0; i < HIBER_GREF_COUNT; i++)
261 {
262 xpdd->hiber_grefs[i] = INVALID_GRANT_REF;
263 }
264 for (i = 0; i < HIBER_GREF_COUNT; i++)
265 {
266 if ((xpdd->hiber_grefs[i] = GntTbl_GetRef(xpdd, (ULONG)'HIBR')) == INVALID_GRANT_REF)
267 break;
268 }
269 FUNCTION_MSG("%d grant refs reserved\n", i);
270 xpdd->gnttbl_ss_copy = xpdd->gnttbl_ss;
271 stack_new(&xpdd->gnttbl_ss, HIBER_GREF_COUNT);
272 }
273 else
274 {
275 xpdd->gnttbl_ss_copy = NULL;
276 }
278 memcpy(xpdd->gnttbl_table_copy, xpdd->gnttbl_table, xpdd->grant_frames * PAGE_SIZE);
279 #if DBG
280 /* 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 */
281 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
282 memcpy(xpdd->gnttbl_tag_copy, xpdd->gnttbl_tag, grant_entries * sizeof(grant_tag_t));
283 #endif
285 /* put the grant entries on the new freelist, after copying the tables above */
286 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
287 {
288 for (i = 0; i < HIBER_GREF_COUNT; i++)
289 {
290 if (xpdd->hiber_grefs[i] == INVALID_GRANT_REF)
291 break;
292 GntTbl_PutRef(xpdd, xpdd->hiber_grefs[i], (ULONG)'HIBR');
293 }
294 }
296 FUNCTION_EXIT();
297 }
299 VOID
300 GntTbl_Resume(PXENPCI_DEVICE_DATA xpdd)
301 {
302 ULONG new_grant_frames;
303 ULONG result;
304 int i;
305 #if DBG
306 int grant_entries;
307 #endif
309 FUNCTION_ENTER();
311 for (i = 0; i < (int)xpdd->grant_frames; i++)
312 {
313 struct xen_memory_reservation reservation;
314 xen_pfn_t pfn;
315 ULONG ret;
317 reservation.address_bits = 0;
318 reservation.extent_order = 0;
319 reservation.domid = DOMID_SELF;
320 reservation.nr_extents = 1;
321 #pragma warning(disable: 4127) /* conditional expression is constant */
322 pfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
323 FUNCTION_MSG("pfn = %x\n", (ULONG)pfn);
324 set_xen_guest_handle(reservation.extent_start, &pfn);
326 FUNCTION_MSG("Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn);
327 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
328 FUNCTION_MSG("decreased %d pages for grant table frame %d\n", ret, i);
329 }
331 new_grant_frames = GntTbl_QueryMaxFrames(xpdd);
332 FUNCTION_MSG("new_grant_frames = %d\n", new_grant_frames);
333 XN_ASSERT(new_grant_frames >= xpdd->grant_frames); // lazy
334 result = GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
335 FUNCTION_MSG("GntTbl_Map result = %d\n", result);
336 memcpy(xpdd->gnttbl_table, xpdd->gnttbl_table_copy, xpdd->grant_frames * PAGE_SIZE);
337 #if DBG
338 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
339 memcpy(xpdd->gnttbl_tag, xpdd->gnttbl_tag_copy, grant_entries * sizeof(grant_tag_t));
340 #endif
342 /* switch back and put the hiber grants back again */
343 if (xpdd->gnttbl_ss_copy)
344 {
345 FUNCTION_MSG("restoring grant ref stack\n");
346 stack_delete(xpdd->gnttbl_ss, NULL, NULL);
347 xpdd->gnttbl_ss = xpdd->gnttbl_ss_copy;
348 for (i = 0; i < HIBER_GREF_COUNT; i++)
349 {
350 if (xpdd->hiber_grefs[i] == INVALID_GRANT_REF)
351 break;
352 GntTbl_PutRef(xpdd, xpdd->hiber_grefs[i], (ULONG)'HIBR');
353 }
354 xpdd->gnttbl_ss_copy = NULL;
355 }
357 FUNCTION_EXIT();
358 }