win-pvdrivers

annotate xenpci/gnttbl.c @ 1022:cd72cd0e1c19

hooking debug doesn't survive hibernate under win8. Remove it.
Remove initial balloon down - doesn't work under xen 4.2 without xenbus being loaded
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 19 15:11:49 2013 +1100 (2013-02-19)
parents 58899e6ed48f
children 37c0c84a42e8
rev   line source
james@0 1 /*
james@0 2 PV Drivers for Windows Xen HVM Domains
james@0 3 Copyright (C) 2007 James Harper
james@0 4
james@0 5 This program is free software; you can redistribute it and/or
james@0 6 modify it under the terms of the GNU General Public License
james@0 7 as published by the Free Software Foundation; either version 2
james@0 8 of the License, or (at your option) any later version.
james@0 9
james@0 10 This program is distributed in the hope that it will be useful,
james@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@0 13 GNU General Public License for more details.
james@0 14
james@0 15 You should have received a copy of the GNU General Public License
james@0 16 along with this program; if not, write to the Free Software
james@0 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@0 18 */
james@0 19
james@0 20 #include "xenpci.h"
james@0 21
james@206 22 VOID
james@790 23 GntTbl_PutRef(PVOID Context, grant_ref_t ref, ULONG tag)
james@0 24 {
james@258 25 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 26
james@790 27 UNREFERENCED_PARAMETER(tag);
james@790 28
james@790 29 #if DBG
james@858 30 if (xpdd->gnttbl_tag[ref].tag != tag)
james@858 31 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s doesn't match %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag));
james@1022 32 XN_ASSERT(xpdd->gnttbl_tag[ref].tag == tag);
james@858 33 xpdd->gnttbl_tag[ref].tag = 0;
james@858 34 xpdd->gnttbl_tag[ref].generation = (ULONG)-1;
james@790 35 #endif
james@835 36 stack_push(xpdd->gnttbl_ss, (PVOID)ref);
james@0 37 }
james@0 38
james@206 39 grant_ref_t
james@790 40 GntTbl_GetRef(PVOID Context, ULONG tag)
james@0 41 {
james@258 42 PXENPCI_DEVICE_DATA xpdd = Context;
james@176 43 unsigned int ref;
james@766 44 PVOID ptr_ref;
james@766 45
james@790 46 UNREFERENCED_PARAMETER(tag);
james@790 47
james@835 48 if (!stack_pop(xpdd->gnttbl_ss, &ptr_ref))
james@385 49 {
james@766 50 KdPrint((__DRIVER_NAME " No free grant refs\n"));
james@415 51 return INVALID_GRANT_REF;
james@415 52 }
james@776 53 ref = (grant_ref_t)(ULONG_PTR)ptr_ref;
james@790 54 #if DBG
james@858 55 if (xpdd->gnttbl_tag[ref].tag)
james@858 56 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s in use by %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag));
james@1022 57 XN_ASSERT(!xpdd->gnttbl_tag[ref].tag);
james@858 58 xpdd->gnttbl_tag[ref].generation = xpdd->gnttbl_generation;
james@858 59 xpdd->gnttbl_tag[ref].tag = tag;
james@790 60 #endif
james@176 61
andy@13 62 return ref;
james@0 63 }
james@0 64
james@279 65 int
james@258 66 GntTbl_Map(PVOID Context, unsigned int start_idx, unsigned int end_idx)
james@0 67 {
james@258 68 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 69 struct xen_add_to_physmap xatp;
james@0 70 unsigned int i = end_idx;
james@0 71
james@832 72 FUNCTION_ENTER();
james@258 73 /* Loop backwards, so that the first hypercall has the largest index, ensuring that the table will grow only once. */
james@0 74 do {
james@0 75 xatp.domid = DOMID_SELF;
james@0 76 xatp.idx = i;
james@0 77 xatp.space = XENMAPSPACE_grant_table;
james@835 78 xatp.gpfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
james@258 79 if (HYPERVISOR_memory_op(xpdd, XENMEM_add_to_physmap, &xatp))
james@0 80 {
james@832 81 KdPrint((__DRIVER_NAME " *** ERROR MAPPING FRAME %d ***\n", i));
james@0 82 }
james@0 83 } while (i-- > start_idx);
james@832 84 FUNCTION_EXIT();
james@0 85
james@0 86 return 0;
james@0 87 }
james@0 88
james@0 89 grant_ref_t
andy@13 90 GntTbl_GrantAccess(
james@258 91 PVOID Context,
andy@13 92 domid_t domid,
andy@265 93 uint32_t frame, // xen api limits pfn to 32bit, so no guests over 8TB
james@206 94 int readonly,
james@790 95 grant_ref_t ref,
james@790 96 ULONG tag)
james@0 97 {
james@258 98 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 99
james@0 100 //KdPrint((__DRIVER_NAME " --> GntTbl_GrantAccess\n"));
james@0 101
james@415 102 if (ref == INVALID_GRANT_REF)
james@790 103 ref = GntTbl_GetRef(Context, tag);
james@415 104 if (ref == INVALID_GRANT_REF)
james@415 105 return ref;
james@790 106
james@1022 107 XN_ASSERT(xpdd->gnttbl_tag[ref].tag == tag);
james@415 108
james@835 109 xpdd->gnttbl_table[ref].frame = frame;
james@835 110 xpdd->gnttbl_table[ref].domid = domid;
james@254 111
james@835 112 if (xpdd->gnttbl_table[ref].flags)
james@790 113 {
james@790 114 #if DBG
james@858 115 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still in use by %.4s\n", ref, (PUCHAR)&tag, (PUCHAR)&xpdd->gnttbl_tag[ref].tag));
james@790 116 #else
james@790 117 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still in use\n", ref, (PUCHAR)&tag));
james@790 118 #endif
james@790 119 }
james@1022 120 XN_ASSERT(!xpdd->gnttbl_table[ref].flags);
james@254 121
james@0 122 KeMemoryBarrier();
james@0 123 readonly *= GTF_readonly;
james@835 124 xpdd->gnttbl_table[ref].flags = GTF_permit_access | (uint16_t)readonly;
james@0 125
james@0 126 return ref;
james@0 127 }
james@0 128
james@0 129 BOOLEAN
andy@13 130 GntTbl_EndAccess(
james@258 131 PVOID Context,
james@206 132 grant_ref_t ref,
james@790 133 BOOLEAN keepref,
james@790 134 ULONG tag)
james@0 135 {
james@258 136 PXENPCI_DEVICE_DATA xpdd = Context;
james@0 137 unsigned short flags, nflags;
james@0 138
james@1022 139 XN_ASSERT(ref != INVALID_GRANT_REF);
james@1022 140 XN_ASSERT(xpdd->gnttbl_tag[ref].tag == tag);
james@415 141
james@835 142 nflags = xpdd->gnttbl_table[ref].flags;
james@0 143 do {
james@0 144 if ((flags = nflags) & (GTF_reading|GTF_writing))
james@0 145 {
james@790 146 KdPrint((__DRIVER_NAME " Grant Entry %d for %.4s still use\n", ref, (PUCHAR)&tag));
james@0 147 return FALSE;
james@0 148 }
andy@13 149 } while ((nflags = InterlockedCompareExchange16(
james@835 150 (volatile SHORT *)&xpdd->gnttbl_table[ref].flags, 0, flags)) != flags);
james@0 151
james@206 152 if (!keepref)
james@790 153 GntTbl_PutRef(Context, ref, tag);
james@0 154 //KdPrint((__DRIVER_NAME " <-- GntTbl_EndAccess\n"));
james@0 155 return TRUE;
james@0 156 }
james@258 157
wayne@363 158 static unsigned int
wayne@363 159 GntTbl_QueryMaxFrames(PXENPCI_DEVICE_DATA xpdd)
wayne@363 160 {
wayne@363 161 struct gnttab_query_size query;
wayne@363 162 int rc;
wayne@363 163
wayne@363 164 query.dom = DOMID_SELF;
wayne@363 165
james@536 166 rc = HYPERVISOR_grant_table_op(xpdd, GNTTABOP_query_size, &query, 1);
wayne@363 167 if ((rc < 0) || (query.status != GNTST_okay))
wayne@363 168 {
wayne@363 169 KdPrint((__DRIVER_NAME " ***CANNOT QUERY MAX GRANT FRAME***\n"));
wayne@363 170 return 4; /* Legacy max supported number of frames */
wayne@363 171 }
wayne@363 172 return query.max_nr_frames;
wayne@363 173 }
james@374 174
james@374 175 VOID
james@536 176 GntTbl_Init(PXENPCI_DEVICE_DATA xpdd)
james@374 177 {
james@374 178 int i;
james@374 179 int grant_entries;
james@790 180
james@1022 181 XN_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
james@536 182
james@536 183 FUNCTION_ENTER();
james@536 184
james@536 185 xpdd->grant_frames = GntTbl_QueryMaxFrames(xpdd);
james@536 186 KdPrint((__DRIVER_NAME " grant_frames = %d\n", xpdd->grant_frames));
james@536 187 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
james@536 188 KdPrint((__DRIVER_NAME " grant_entries = %d\n", grant_entries));
james@790 189 #if DBG
james@858 190 xpdd->gnttbl_tag = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(grant_tag_t), XENPCI_POOL_TAG);
james@858 191 RtlZeroMemory(xpdd->gnttbl_tag, grant_entries * sizeof(grant_tag_t));
james@858 192 xpdd->gnttbl_tag_copy = ExAllocatePoolWithTag(NonPagedPool, grant_entries * sizeof(grant_tag_t), XENPCI_POOL_TAG);
james@858 193 xpdd->gnttbl_generation = 0;
james@790 194 #endif
james@835 195 xpdd->gnttbl_table_copy = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
james@1022 196 XN_ASSERT(xpdd->gnttbl_table_copy); // lazy
james@835 197 xpdd->gnttbl_table = ExAllocatePoolWithTag(NonPagedPool, xpdd->grant_frames * PAGE_SIZE, XENPCI_POOL_TAG);
james@1022 198 XN_ASSERT(xpdd->gnttbl_table); // lazy
james@832 199 /* dom0 crashes if we allocate the wrong amount of memory here! */
james@835 200 xpdd->gnttbl_mdl = IoAllocateMdl(xpdd->gnttbl_table, xpdd->grant_frames * PAGE_SIZE, FALSE, FALSE, NULL);
james@1022 201 XN_ASSERT(xpdd->gnttbl_mdl); // lazy
james@835 202 MmBuildMdlForNonPagedPool(xpdd->gnttbl_mdl);
james@832 203
james@835 204 /* make some holes for the grant pages to fill in */
james@832 205 for (i = 0; i < (int)xpdd->grant_frames; i++)
james@832 206 {
james@832 207 struct xen_memory_reservation reservation;
james@832 208 xen_pfn_t pfn;
james@832 209 ULONG ret;
james@832 210
james@832 211 reservation.address_bits = 0;
james@832 212 reservation.extent_order = 0;
james@832 213 reservation.domid = DOMID_SELF;
james@832 214 reservation.nr_extents = 1;
james@832 215 #pragma warning(disable: 4127) /* conditional expression is constant */
james@835 216 pfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
james@832 217 KdPrint((__DRIVER_NAME " pfn = %x\n", (ULONG)pfn));
james@832 218 set_xen_guest_handle(reservation.extent_start, &pfn);
james@832 219
james@832 220 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
james@832 221 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
james@832 222 KdPrint((__DRIVER_NAME " decreased %d pages for grant table frame %d\n", ret, i));
james@832 223 }
james@832 224
james@835 225 stack_new(&xpdd->gnttbl_ss, grant_entries);
james@374 226
james@374 227 for (i = NR_RESERVED_ENTRIES; i < grant_entries; i++)
james@835 228 stack_push(xpdd->gnttbl_ss, (PVOID)i);
james@374 229
james@536 230 GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
james@536 231
james@835 232 RtlZeroMemory(xpdd->gnttbl_table, PAGE_SIZE * xpdd->grant_frames);
james@536 233
james@536 234 FUNCTION_EXIT();
james@374 235 }
wayne@363 236
james@258 237 VOID
james@536 238 GntTbl_Suspend(PXENPCI_DEVICE_DATA xpdd)
james@258 239 {
james@842 240 #if DBG
james@841 241 int grant_entries;
james@842 242 #endif
james@841 243 int i;
james@841 244
james@841 245 FUNCTION_ENTER();
james@841 246
james@858 247 #if DBG
james@858 248 for (i = 0; i < (int)min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t))); i++)
james@858 249 {
james@858 250 if (xpdd->gnttbl_tag[i].tag != 0) // && xpdd->gnttbl_tag[i].generation < xpdd->gnttbl_generation)
james@858 251 {
james@858 252 KdPrint((__DRIVER_NAME " grant entry for %.4s from generation %d\n", (PUCHAR)&xpdd->gnttbl_tag[i].tag, xpdd->gnttbl_tag[i].generation));
james@858 253 }
james@858 254 }
james@858 255 xpdd->gnttbl_generation++;
james@858 256 #endif
james@858 257
james@841 258 /* copy some grant refs and switch to an alternate freelist, but only on hiber */
james@841 259 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
james@841 260 {
james@841 261 KdPrint((__DRIVER_NAME " backing up grant ref stack\n"));
james@841 262 for (i = 0; i < HIBER_GREF_COUNT; i++)
james@841 263 {
james@841 264 xpdd->hiber_grefs[i] = INVALID_GRANT_REF;
james@841 265 }
james@841 266 for (i = 0; i < HIBER_GREF_COUNT; i++)
james@841 267 {
james@841 268 if ((xpdd->hiber_grefs[i] = GntTbl_GetRef(xpdd, (ULONG)'HIBR')) == INVALID_GRANT_REF)
james@841 269 break;
james@841 270 }
james@841 271 KdPrint((__DRIVER_NAME " %d grant refs reserved\n", i));
james@841 272 xpdd->gnttbl_ss_copy = xpdd->gnttbl_ss;
james@841 273 stack_new(&xpdd->gnttbl_ss, HIBER_GREF_COUNT);
james@841 274 }
james@841 275 else
james@841 276 {
james@841 277 xpdd->gnttbl_ss_copy = NULL;
james@841 278 }
james@841 279
james@835 280 memcpy(xpdd->gnttbl_table_copy, xpdd->gnttbl_table, xpdd->grant_frames * PAGE_SIZE);
james@841 281 #if DBG
james@841 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 */
james@841 283 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
james@858 284 memcpy(xpdd->gnttbl_tag_copy, xpdd->gnttbl_tag, grant_entries * sizeof(grant_tag_t));
james@841 285 #endif
james@841 286
james@841 287 /* put the grant entries on the new freelist, after copying the tables above */
james@841 288 if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
james@841 289 {
james@841 290 for (i = 0; i < HIBER_GREF_COUNT; i++)
james@841 291 {
james@841 292 if (xpdd->hiber_grefs[i] == INVALID_GRANT_REF)
james@841 293 break;
james@841 294 GntTbl_PutRef(xpdd, xpdd->hiber_grefs[i], (ULONG)'HIBR');
james@841 295 }
james@841 296 }
james@841 297
james@841 298 FUNCTION_EXIT();
james@536 299 }
james@536 300
james@536 301 VOID
james@536 302 GntTbl_Resume(PXENPCI_DEVICE_DATA xpdd)
james@536 303 {
james@536 304 ULONG new_grant_frames;
james@536 305 ULONG result;
james@835 306 int i;
james@842 307 #if DBG
james@841 308 int grant_entries;
james@842 309 #endif
james@841 310
james@536 311 FUNCTION_ENTER();
james@841 312
james@835 313 for (i = 0; i < (int)xpdd->grant_frames; i++)
james@835 314 {
james@835 315 struct xen_memory_reservation reservation;
james@835 316 xen_pfn_t pfn;
james@835 317 ULONG ret;
james@835 318
james@835 319 reservation.address_bits = 0;
james@835 320 reservation.extent_order = 0;
james@835 321 reservation.domid = DOMID_SELF;
james@835 322 reservation.nr_extents = 1;
james@835 323 #pragma warning(disable: 4127) /* conditional expression is constant */
james@835 324 pfn = (xen_pfn_t)MmGetMdlPfnArray(xpdd->gnttbl_mdl)[i];
james@835 325 KdPrint((__DRIVER_NAME " pfn = %x\n", (ULONG)pfn));
james@835 326 set_xen_guest_handle(reservation.extent_start, &pfn);
james@835 327
james@835 328 KdPrint((__DRIVER_NAME " Calling HYPERVISOR_memory_op - pfn = %x\n", (ULONG)pfn));
james@835 329 ret = HYPERVISOR_memory_op(xpdd, XENMEM_decrease_reservation, &reservation);
james@835 330 KdPrint((__DRIVER_NAME " decreased %d pages for grant table frame %d\n", ret, i));
james@835 331 }
james@835 332
james@536 333 new_grant_frames = GntTbl_QueryMaxFrames(xpdd);
james@536 334 KdPrint((__DRIVER_NAME " new_grant_frames = %d\n", new_grant_frames));
james@1022 335 XN_ASSERT(new_grant_frames >= xpdd->grant_frames); // lazy
james@536 336 result = GntTbl_Map(xpdd, 0, xpdd->grant_frames - 1);
james@536 337 KdPrint((__DRIVER_NAME " GntTbl_Map result = %d\n", result));
james@835 338 memcpy(xpdd->gnttbl_table, xpdd->gnttbl_table_copy, xpdd->grant_frames * PAGE_SIZE);
james@841 339 #if DBG
james@841 340 grant_entries = min(NR_GRANT_ENTRIES, (xpdd->grant_frames * PAGE_SIZE / sizeof(grant_entry_t)));
james@858 341 memcpy(xpdd->gnttbl_tag, xpdd->gnttbl_tag_copy, grant_entries * sizeof(grant_tag_t));
james@841 342 #endif
james@841 343
james@841 344 /* switch back and put the hiber grants back again */
james@841 345 if (xpdd->gnttbl_ss_copy)
james@841 346 {
james@841 347 KdPrint((__DRIVER_NAME " restoring grant ref stack\n"));
james@841 348 stack_delete(xpdd->gnttbl_ss, NULL, NULL);
james@841 349 xpdd->gnttbl_ss = xpdd->gnttbl_ss_copy;
james@841 350 for (i = 0; i < HIBER_GREF_COUNT; i++)
james@841 351 {
james@841 352 if (xpdd->hiber_grefs[i] == INVALID_GRANT_REF)
james@841 353 break;
james@841 354 GntTbl_PutRef(xpdd, xpdd->hiber_grefs[i], (ULONG)'HIBR');
james@841 355 }
james@841 356 xpdd->gnttbl_ss_copy = NULL;
james@841 357 }
james@841 358
james@536 359 FUNCTION_EXIT();
james@258 360 }