win-pvdrivers

view xenpci/gnttbl.c @ 1054:471c94d04d8a

Refactoring to support xencache (tmem)
author James Harper <james.harper@bendigoit.com.au>
date Sun Jun 02 16:37:21 2013 +1000 (2013-06-02)
parents 37c0c84a42e8
children 27bd2a5a4704
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(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 struct gnttab_query_size query;
159 int rc;
161 UNREFERENCED_PARAMETER(xpdd);
162 query.dom = DOMID_SELF;
164 rc = HYPERVISOR_grant_table_op(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 int i;
176 int grant_entries;
178 XN_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
180 FUNCTION_ENTER();
182 xpdd->grant_frames = GntTbl_QueryMaxFrames(xpdd);
183 FUNCTION_MSG("grant_frames = %d\n", xpdd->grant_frames);
184 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
185 FUNCTION_MSG("grant_entries = %d\n", grant_entries);
186 #if DBG
187 xpdd->gnttbl_tag = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(grant_tag_t), XENPCI_POOL_TAG);
188 RtlZeroMemory(xpdd->gnttbl_tag, grant_entries * sizeof(grant_tag_t));
189 xpdd->gnttbl_tag_copy = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(grant_tag_t), XENPCI_POOL_TAG);
190 xpdd->gnttbl_generation = 0;
191 #endif
192 xpdd->gnttbl_table_copy = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
193 XN_ASSERT(xpdd->gnttbl_table_copy); // lazy
194 xpdd->gnttbl_table = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
195 XN_ASSERT(xpdd->gnttbl_table); // lazy
196 /* dom0 crashes if we allocate the wrong amount of memory here! */
197 xpdd->gnttbl_mdl = IoAllocateMdl(xpdd->gnttbl_table, xpdd->grant_frames * PAGE_SIZE, FALSE, FALSE, NULL);
198 XN_ASSERT(xpdd->gnttbl_mdl); // lazy
199 MmBuildMdlForNonPagedPool(xpdd->gnttbl_mdl);
201 /* make some holes for the grant pages to fill in */
202 for (i = 0; i < (int)xpdd->grant_frames; i++)
203 {
204 struct xen_memory_reservation reservation;
205 xen_pfn_t pfn;
206 ULONG ret;
208 reservation.address_bits = 0;
209 reservation.extent_order = 0;
210 reservation.domid = DOMID_SELF;
211 reservation.nr_extents = 1;
212 #pragma warning(disable: 4127) /* conditional expression is constant */
213 pfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
214 FUNCTION_MSG("pfn = %x\n", (ULONG)pfn);
215 set_xen_guest_handle(reservation.extent_start, &pfn);
217 FUNCTION_MSG("Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn);
218 ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
219 FUNCTION_MSG("decreased %d pages for grant table frame %d\n", ret, i);
220 }
222 stack_new(&xpdd->gnttbl_ss, grant_entries);
224 for (i = NR_RESERVED_ENTRIES; i < grant_entries; i++)
225 stack_push(xpdd->gnttbl_ss, (PVOID)i);
227 GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
229 RtlZeroMemory(xpdd->gnttbl_table, PAGE_SIZE * xpdd->grant_frames);
231 FUNCTION_EXIT();
232 }
234 VOID
235 GntTbl_Suspend(PXENPCI_DEVICE_DATA xpdd)
236 {
237 #if DBG
238 int grant_entries;
239 #endif
240 int i;
242 FUNCTION_ENTER();
244 #if DBG
245 for (i = 0; i < (int)min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t))); i++)
246 {
247 if (xpdd->gnttbl_tag[i].tag != 0) // && xpdd->gnttbl_tag[i].generation < xpdd->gnttbl_generation)
248 {
249 FUNCTION_MSG("grant entry for %.4s from generation %d\n", (PUCHAR)&xpdd->gnttbl_tag[i].tag, xpdd->gnttbl_tag[i].generation);
250 }
251 }
252 xpdd->gnttbl_generation++;
253 #endif
255 /* copy some grant refs and switch to an alternate freelist, but only on hiber */
256 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
257 {
258 FUNCTION_MSG("backing up grant ref stack\n");
259 for (i = 0; i < HIBER_GREF_COUNT; i++)
260 {
261 xpdd->hiber_grefs[i] = INVALID_GRANT_REF;
262 }
263 for (i = 0; i < HIBER_GREF_COUNT; i++)
264 {
265 if ((xpdd->hiber_grefs[i] = GntTbl_GetRef(xpdd, (ULONG)'HIBR')) == INVALID_GRANT_REF)
266 break;
267 }
268 FUNCTION_MSG("%d grant refs reserved\n", i);
269 xpdd->gnttbl_ss_copy = xpdd->gnttbl_ss;
270 stack_new(&xpdd->gnttbl_ss, HIBER_GREF_COUNT);
271 }
272 else
273 {
274 xpdd->gnttbl_ss_copy = NULL;
275 }
277 memcpy(xpdd->gnttbl_table_copy, xpdd->gnttbl_table, xpdd->grant_frames * PAGE_SIZE);
278 #if DBG
279 /* 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 */
280 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
281 memcpy(xpdd->gnttbl_tag_copy, xpdd->gnttbl_tag, grant_entries * sizeof(grant_tag_t));
282 #endif
284 /* put the grant entries on the new freelist, after copying the tables above */
285 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
286 {
287 for (i = 0; i < HIBER_GREF_COUNT; i++)
288 {
289 if (xpdd->hiber_grefs[i] == INVALID_GRANT_REF)
290 break;
291 GntTbl_PutRef(xpdd, xpdd->hiber_grefs[i], (ULONG)'HIBR');
292 }
293 }
295 FUNCTION_EXIT();
296 }
298 VOID
299 GntTbl_Resume(PXENPCI_DEVICE_DATA xpdd)
300 {
301 ULONG new_grant_frames;
302 ULONG result;
303 int i;
304 #if DBG
305 int grant_entries;
306 #endif
308 FUNCTION_ENTER();
310 for (i = 0; i < (int)xpdd->grant_frames; i++)
311 {
312 struct xen_memory_reservation reservation;
313 xen_pfn_t pfn;
314 ULONG ret;
316 reservation.address_bits = 0;
317 reservation.extent_order = 0;
318 reservation.domid = DOMID_SELF;
319 reservation.nr_extents = 1;
320 #pragma warning(disable: 4127) /* conditional expression is constant */
321 pfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
322 FUNCTION_MSG("pfn = %x\n", (ULONG)pfn);
323 set_xen_guest_handle(reservation.extent_start, &pfn);
325 FUNCTION_MSG("Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn);
326 ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
327 FUNCTION_MSG("decreased %d pages for grant table frame %d\n", ret, i);
328 }
330 new_grant_frames = GntTbl_QueryMaxFrames(xpdd);
331 FUNCTION_MSG("new_grant_frames = %d\n", new_grant_frames);
332 XN_ASSERT(new_grant_frames >= xpdd->grant_frames); // lazy
333 result = GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
334 FUNCTION_MSG("GntTbl_Map result = %d\n", result);
335 memcpy(xpdd->gnttbl_table, xpdd->gnttbl_table_copy, xpdd->grant_frames * PAGE_SIZE);
336 #if DBG
337 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
338 memcpy(xpdd->gnttbl_tag, xpdd->gnttbl_tag_copy, grant_entries * sizeof(grant_tag_t));
339 #endif
341 /* switch back and put the hiber grants back again */
342 if (xpdd->gnttbl_ss_copy)
343 {
344 FUNCTION_MSG("restoring grant ref stack\n");
345 stack_delete(xpdd->gnttbl_ss, NULL, NULL);
346 xpdd->gnttbl_ss = xpdd->gnttbl_ss_copy;
347 for (i = 0; i < HIBER_GREF_COUNT; i++)
348 {
349 if (xpdd->hiber_grefs[i] == INVALID_GRANT_REF)
350 break;
351 GntTbl_PutRef(xpdd, xpdd->hiber_grefs[i], (ULONG)'HIBR');
352 }
353 xpdd->gnttbl_ss_copy = NULL;
354 }
356 FUNCTION_EXIT();
357 }