VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllPool.cpp@ 18729

Last change on this file since 18729 was 18666, checked in by vboxsync, 16 years ago

VMM: Clean out the VBOX_WITH_NEW_PHYS_CODE #ifdefs. (part 2)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 159.3 KB
Line 
1/* $Id: PGMAllPool.cpp 18666 2009-04-02 23:10:12Z vboxsync $ */
2/** @file
3 * PGM Shadow Page Pool.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_PGM_POOL
27#include <VBox/pgm.h>
28#include <VBox/mm.h>
29#include <VBox/em.h>
30#include <VBox/cpum.h>
31#ifdef IN_RC
32# include <VBox/patm.h>
33#endif
34#include "PGMInternal.h"
35#include <VBox/vm.h>
36#include <VBox/disopcode.h>
37#include <VBox/hwacc_vmx.h>
38
39#include <VBox/log.h>
40#include <VBox/err.h>
41#include <iprt/asm.h>
42#include <iprt/string.h>
43
44
45/*******************************************************************************
46* Internal Functions *
47*******************************************************************************/
48__BEGIN_DECLS
49static void pgmPoolFlushAllInt(PPGMPOOL pPool);
50#ifdef PGMPOOL_WITH_USER_TRACKING
51DECLINLINE(unsigned) pgmPoolTrackGetShadowEntrySize(PGMPOOLKIND enmKind);
52DECLINLINE(unsigned) pgmPoolTrackGetGuestEntrySize(PGMPOOLKIND enmKind);
53static void pgmPoolTrackDeref(PPGMPOOL pPool, PPGMPOOLPAGE pPage);
54#endif
55#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
56static void pgmPoolTracDerefGCPhysHint(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhysHint);
57#endif
58#ifdef PGMPOOL_WITH_CACHE
59static int pgmPoolTrackAddUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable);
60#endif
61#ifdef PGMPOOL_WITH_MONITORING
62static void pgmPoolMonitorModifiedRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage);
63#endif
64#ifndef IN_RING3
65DECLEXPORT(int) pgmPoolAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
66#endif
67#ifdef LOG_ENABLED
68static const char *pgmPoolPoolKindToStr(uint8_t enmKind);
69#endif
70__END_DECLS
71
72
73/**
74 * Checks if the specified page pool kind is for a 4MB or 2MB guest page.
75 *
76 * @returns true if it's the shadow of a 4MB or 2MB guest page, otherwise false.
77 * @param enmKind The page kind.
78 */
79DECLINLINE(bool) pgmPoolIsBigPage(PGMPOOLKIND enmKind)
80{
81 switch (enmKind)
82 {
83 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
84 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
85 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
86 return true;
87 default:
88 return false;
89 }
90}
91
92/** @def PGMPOOL_PAGE_2_LOCKED_PTR
93 * Maps a pool page pool into the current context and lock it (RC only).
94 *
95 * @returns VBox status code.
96 * @param pVM The VM handle.
97 * @param pPage The pool page.
98 *
99 * @remark In RC this uses PGMGCDynMapHCPage(), so it will consume of the
100 * small page window employeed by that function. Be careful.
101 * @remark There is no need to assert on the result.
102 */
103#if defined(IN_RC)
104DECLINLINE(void *) PGMPOOL_PAGE_2_LOCKED_PTR(PVM pVM, PPGMPOOLPAGE pPage)
105{
106 void *pv = pgmPoolMapPageInlined(&pVM->pgm.s, pPage);
107
108 /* Make sure the dynamic mapping will not be reused. */
109 if (pv)
110 PGMDynLockHCPage(pVM, (uint8_t *)pv);
111
112 return pv;
113}
114#else
115# define PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage) PGMPOOL_PAGE_2_PTR(pVM, pPage)
116#endif
117
118/** @def PGMPOOL_UNLOCK_PTR
119 * Unlock a previously locked dynamic caching (RC only).
120 *
121 * @returns VBox status code.
122 * @param pVM The VM handle.
123 * @param pPage The pool page.
124 *
125 * @remark In RC this uses PGMGCDynMapHCPage(), so it will consume of the
126 * small page window employeed by that function. Be careful.
127 * @remark There is no need to assert on the result.
128 */
129#if defined(IN_RC)
130DECLINLINE(void) PGMPOOL_UNLOCK_PTR(PVM pVM, void *pvPage)
131{
132 if (pvPage)
133 PGMDynUnlockHCPage(pVM, (uint8_t *)pvPage);
134}
135#else
136# define PGMPOOL_UNLOCK_PTR(pVM, pPage) do {} while (0)
137#endif
138
139
140#ifdef PGMPOOL_WITH_MONITORING
141/**
142 * Determin the size of a write instruction.
143 * @returns number of bytes written.
144 * @param pDis The disassembler state.
145 */
146static unsigned pgmPoolDisasWriteSize(PDISCPUSTATE pDis)
147{
148 /*
149 * This is very crude and possibly wrong for some opcodes,
150 * but since it's not really supposed to be called we can
151 * probably live with that.
152 */
153 return DISGetParamSize(pDis, &pDis->param1);
154}
155
156
157/**
158 * Flushes a chain of pages sharing the same access monitor.
159 *
160 * @returns VBox status code suitable for scheduling.
161 * @param pPool The pool.
162 * @param pPage A page in the chain.
163 */
164int pgmPoolMonitorChainFlush(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
165{
166 LogFlow(("pgmPoolMonitorChainFlush: Flush page %RGp type=%d\n", pPage->GCPhys, pPage->enmKind));
167
168 /*
169 * Find the list head.
170 */
171 uint16_t idx = pPage->idx;
172 if (pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
173 {
174 while (pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
175 {
176 idx = pPage->iMonitoredPrev;
177 Assert(idx != pPage->idx);
178 pPage = &pPool->aPages[idx];
179 }
180 }
181
182 /*
183 * Iterate the list flushing each shadow page.
184 */
185 int rc = VINF_SUCCESS;
186 for (;;)
187 {
188 idx = pPage->iMonitoredNext;
189 Assert(idx != pPage->idx);
190 if (pPage->idx >= PGMPOOL_IDX_FIRST)
191 {
192 int rc2 = pgmPoolFlushPage(pPool, pPage);
193 AssertRC(rc2);
194 }
195 /* next */
196 if (idx == NIL_PGMPOOL_IDX)
197 break;
198 pPage = &pPool->aPages[idx];
199 }
200 return rc;
201}
202
203
204/**
205 * Wrapper for getting the current context pointer to the entry being modified.
206 *
207 * @returns VBox status code suitable for scheduling.
208 * @param pVM VM Handle.
209 * @param pvDst Destination address
210 * @param pvSrc Source guest virtual address.
211 * @param GCPhysSrc The source guest physical address.
212 * @param cb Size of data to read
213 */
214DECLINLINE(int) pgmPoolPhysSimpleReadGCPhys(PVM pVM, void *pvDst, CTXTYPE(RTGCPTR, RTHCPTR, RTGCPTR) pvSrc, RTGCPHYS GCPhysSrc, size_t cb)
215{
216#if defined(IN_RING3)
217 memcpy(pvDst, (RTHCPTR)((uintptr_t)pvSrc & ~(RTHCUINTPTR)(cb - 1)), cb);
218 return VINF_SUCCESS;
219#else
220 /* @todo in RC we could attempt to use the virtual address, although this can cause many faults (PAE Windows XP guest). */
221 return PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc & ~(RTGCPHYS)(cb - 1), cb);
222#endif
223}
224
225/**
226 * Process shadow entries before they are changed by the guest.
227 *
228 * For PT entries we will clear them. For PD entries, we'll simply check
229 * for mapping conflicts and set the SyncCR3 FF if found.
230 *
231 * @param pPool The pool.
232 * @param pPage The head page.
233 * @param GCPhysFault The guest physical fault address.
234 * @param uAddress In R0 and GC this is the guest context fault address (flat).
235 * In R3 this is the host context 'fault' address.
236 * @param pCpu The disassembler state for figuring out the write size.
237 * This need not be specified if the caller knows we won't do cross entry accesses.
238 */
239void pgmPoolMonitorChainChanging(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTGCPHYS GCPhysFault, CTXTYPE(RTGCPTR, RTHCPTR, RTGCPTR) pvAddress, PDISCPUSTATE pCpu)
240{
241 Assert(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
242 const unsigned off = GCPhysFault & PAGE_OFFSET_MASK;
243 const unsigned cbWrite = (pCpu) ? pgmPoolDisasWriteSize(pCpu) : 0;
244 PVM pVM = pPool->CTX_SUFF(pVM);
245
246 LogFlow(("pgmPoolMonitorChainChanging: %RGv phys=%RGp kind=%s cbWrite=%d\n", (RTGCPTR)pvAddress, GCPhysFault, pgmPoolPoolKindToStr(pPage->enmKind), cbWrite));
247 for (;;)
248 {
249 union
250 {
251 void *pv;
252 PX86PT pPT;
253 PX86PTPAE pPTPae;
254 PX86PD pPD;
255 PX86PDPAE pPDPae;
256 PX86PDPT pPDPT;
257 PX86PML4 pPML4;
258 } uShw;
259
260 uShw.pv = NULL;
261 switch (pPage->enmKind)
262 {
263 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
264 {
265 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
266 const unsigned iShw = off / sizeof(X86PTE);
267 LogFlow(("PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT iShw=%x\n", iShw));
268 if (uShw.pPT->a[iShw].n.u1Present)
269 {
270# ifdef PGMPOOL_WITH_GCPHYS_TRACKING
271 X86PTE GstPte;
272
273 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvAddress, GCPhysFault, sizeof(GstPte));
274 AssertRC(rc);
275 Log4(("pgmPoolMonitorChainChanging 32_32: deref %016RX64 GCPhys %08RX32\n", uShw.pPT->a[iShw].u & X86_PTE_PAE_PG_MASK, GstPte.u & X86_PTE_PG_MASK));
276 pgmPoolTracDerefGCPhysHint(pPool, pPage,
277 uShw.pPT->a[iShw].u & X86_PTE_PAE_PG_MASK,
278 GstPte.u & X86_PTE_PG_MASK);
279# endif
280 uShw.pPT->a[iShw].u = 0;
281 }
282 break;
283 }
284
285 /* page/2 sized */
286 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
287 {
288 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
289 if (!((off ^ pPage->GCPhys) & (PAGE_SIZE / 2)))
290 {
291 const unsigned iShw = (off / sizeof(X86PTE)) & (X86_PG_PAE_ENTRIES - 1);
292 LogFlow(("PGMPOOLKIND_PAE_PT_FOR_32BIT_PT iShw=%x\n", iShw));
293 if (uShw.pPTPae->a[iShw].n.u1Present)
294 {
295# ifdef PGMPOOL_WITH_GCPHYS_TRACKING
296 X86PTE GstPte;
297 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvAddress, GCPhysFault, sizeof(GstPte));
298 AssertRC(rc);
299
300 Log4(("pgmPoolMonitorChainChanging pae_32: deref %016RX64 GCPhys %08RX32\n", uShw.pPT->a[iShw].u & X86_PTE_PAE_PG_MASK, GstPte.u & X86_PTE_PG_MASK));
301 pgmPoolTracDerefGCPhysHint(pPool, pPage,
302 uShw.pPTPae->a[iShw].u & X86_PTE_PAE_PG_MASK,
303 GstPte.u & X86_PTE_PG_MASK);
304# endif
305 uShw.pPTPae->a[iShw].u = 0;
306 }
307 }
308 break;
309 }
310
311 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
312 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
313 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
314 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
315 {
316 unsigned iGst = off / sizeof(X86PDE);
317 unsigned iShwPdpt = iGst / 256;
318 unsigned iShw = (iGst % 256) * 2;
319 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
320
321 LogFlow(("pgmPoolMonitorChainChanging PAE for 32 bits: iGst=%x iShw=%x idx = %d page idx=%d\n", iGst, iShw, iShwPdpt, pPage->enmKind - PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD));
322 if (iShwPdpt == pPage->enmKind - (unsigned)PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD)
323 {
324 for (unsigned i = 0; i < 2; i++)
325 {
326# ifndef IN_RING0
327 if ((uShw.pPDPae->a[iShw + i].u & (PGM_PDFLAGS_MAPPING | X86_PDE_P)) == (PGM_PDFLAGS_MAPPING | X86_PDE_P))
328 {
329 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
330 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
331 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShwPdpt=%#x iShw=%#x!\n", iShwPdpt, iShw+i));
332 break;
333 }
334 else
335# endif /* !IN_RING0 */
336 if (uShw.pPDPae->a[iShw+i].n.u1Present)
337 {
338 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw+i, uShw.pPDPae->a[iShw+i].u));
339 pgmPoolFree(pVM,
340 uShw.pPDPae->a[iShw+i].u & X86_PDE_PAE_PG_MASK,
341 pPage->idx,
342 iShw + i);
343 uShw.pPDPae->a[iShw+i].u = 0;
344 }
345
346 /* paranoia / a bit assumptive. */
347 if ( pCpu
348 && (off & 3)
349 && (off & 3) + cbWrite > 4)
350 {
351 const unsigned iShw2 = iShw + 2 + i;
352 if (iShw2 < RT_ELEMENTS(uShw.pPDPae->a))
353 {
354# ifndef IN_RING0
355 if ((uShw.pPDPae->a[iShw2].u & (PGM_PDFLAGS_MAPPING | X86_PDE_P)) == (PGM_PDFLAGS_MAPPING | X86_PDE_P))
356 {
357 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
358 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
359 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShwPdpt=%#x iShw2=%#x!\n", iShwPdpt, iShw2));
360 break;
361 }
362 else
363# endif /* !IN_RING0 */
364 if (uShw.pPDPae->a[iShw2].n.u1Present)
365 {
366 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPae->a[iShw2].u));
367 pgmPoolFree(pVM,
368 uShw.pPDPae->a[iShw2].u & X86_PDE_PAE_PG_MASK,
369 pPage->idx,
370 iShw2);
371 uShw.pPDPae->a[iShw2].u = 0;
372 }
373 }
374 }
375 }
376 }
377 break;
378 }
379
380 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
381 {
382 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
383 const unsigned iShw = off / sizeof(X86PTEPAE);
384 if (uShw.pPTPae->a[iShw].n.u1Present)
385 {
386# ifdef PGMPOOL_WITH_GCPHYS_TRACKING
387 X86PTEPAE GstPte;
388 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvAddress, GCPhysFault, sizeof(GstPte));
389 AssertRC(rc);
390
391 Log4(("pgmPoolMonitorChainChanging pae: deref %016RX64 GCPhys %016RX64\n", uShw.pPTPae->a[iShw].u & X86_PTE_PAE_PG_MASK, GstPte.u & X86_PTE_PAE_PG_MASK));
392 pgmPoolTracDerefGCPhysHint(pPool, pPage,
393 uShw.pPTPae->a[iShw].u & X86_PTE_PAE_PG_MASK,
394 GstPte.u & X86_PTE_PAE_PG_MASK);
395# endif
396 uShw.pPTPae->a[iShw].u = 0;
397 }
398
399 /* paranoia / a bit assumptive. */
400 if ( pCpu
401 && (off & 7)
402 && (off & 7) + cbWrite > sizeof(X86PTEPAE))
403 {
404 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PTEPAE);
405 AssertBreak(iShw2 < RT_ELEMENTS(uShw.pPTPae->a));
406
407 if (uShw.pPTPae->a[iShw2].n.u1Present)
408 {
409# ifdef PGMPOOL_WITH_GCPHYS_TRACKING
410 X86PTEPAE GstPte;
411# ifdef IN_RING3
412 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, (RTHCPTR)((RTHCUINTPTR)pvAddress + sizeof(GstPte)), GCPhysFault + sizeof(GstPte), sizeof(GstPte));
413# else
414 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvAddress + sizeof(GstPte), GCPhysFault + sizeof(GstPte), sizeof(GstPte));
415# endif
416 AssertRC(rc);
417 Log4(("pgmPoolMonitorChainChanging pae: deref %016RX64 GCPhys %016RX64\n", uShw.pPTPae->a[iShw2].u & X86_PTE_PAE_PG_MASK, GstPte.u & X86_PTE_PAE_PG_MASK));
418 pgmPoolTracDerefGCPhysHint(pPool, pPage,
419 uShw.pPTPae->a[iShw2].u & X86_PTE_PAE_PG_MASK,
420 GstPte.u & X86_PTE_PAE_PG_MASK);
421# endif
422 uShw.pPTPae->a[iShw2].u = 0;
423 }
424 }
425 break;
426 }
427
428 case PGMPOOLKIND_32BIT_PD:
429 {
430 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
431 const unsigned iShw = off / sizeof(X86PTE); // ASSUMING 32-bit guest paging!
432
433 LogFlow(("pgmPoolMonitorChainChanging: PGMPOOLKIND_32BIT_PD %x\n", iShw));
434# ifndef IN_RING0
435 if (uShw.pPD->a[iShw].u & PGM_PDFLAGS_MAPPING)
436 {
437 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
438 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
439 STAM_COUNTER_INC(&(pVM->pgm.s.StatRZGuestCR3WriteConflict));
440 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw=%#x!\n", iShw));
441 break;
442 }
443# endif /* !IN_RING0 */
444# ifndef IN_RING0
445 else
446# endif /* !IN_RING0 */
447 {
448 if (uShw.pPD->a[iShw].n.u1Present)
449 {
450 LogFlow(("pgmPoolMonitorChainChanging: 32 bit pd iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPD->a[iShw].u));
451 pgmPoolFree(pVM,
452 uShw.pPD->a[iShw].u & X86_PDE_PAE_PG_MASK,
453 pPage->idx,
454 iShw);
455 uShw.pPD->a[iShw].u = 0;
456 }
457 }
458 /* paranoia / a bit assumptive. */
459 if ( pCpu
460 && (off & 3)
461 && (off & 3) + cbWrite > sizeof(X86PTE))
462 {
463 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PTE);
464 if ( iShw2 != iShw
465 && iShw2 < RT_ELEMENTS(uShw.pPD->a))
466 {
467# ifndef IN_RING0
468 if (uShw.pPD->a[iShw2].u & PGM_PDFLAGS_MAPPING)
469 {
470 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
471 STAM_COUNTER_INC(&(pVM->pgm.s.StatRZGuestCR3WriteConflict));
472 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
473 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
474 break;
475 }
476# endif /* !IN_RING0 */
477# ifndef IN_RING0
478 else
479# endif /* !IN_RING0 */
480 {
481 if (uShw.pPD->a[iShw2].n.u1Present)
482 {
483 LogFlow(("pgmPoolMonitorChainChanging: 32 bit pd iShw=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPD->a[iShw2].u));
484 pgmPoolFree(pVM,
485 uShw.pPD->a[iShw2].u & X86_PDE_PAE_PG_MASK,
486 pPage->idx,
487 iShw2);
488 uShw.pPD->a[iShw2].u = 0;
489 }
490 }
491 }
492 }
493#if 0 /* useful when running PGMAssertCR3(), a bit too troublesome for general use (TLBs). */
494 if ( uShw.pPD->a[iShw].n.u1Present
495 && !VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3))
496 {
497 LogFlow(("pgmPoolMonitorChainChanging: iShw=%#x: %RX32 -> freeing it!\n", iShw, uShw.pPD->a[iShw].u));
498# ifdef IN_RC /* TLB load - we're pushing things a bit... */
499 ASMProbeReadByte(pvAddress);
500# endif
501 pgmPoolFree(pVM, uShw.pPD->a[iShw].u & X86_PDE_PG_MASK, pPage->idx, iShw);
502 uShw.pPD->a[iShw].u = 0;
503 }
504#endif
505 break;
506 }
507
508 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
509 {
510 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
511 const unsigned iShw = off / sizeof(X86PDEPAE);
512#ifndef IN_RING0
513 if (uShw.pPDPae->a[iShw].u & PGM_PDFLAGS_MAPPING)
514 {
515 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
516 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
517 STAM_COUNTER_INC(&(pVM->pgm.s.StatRZGuestCR3WriteConflict));
518 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw=%#x!\n", iShw));
519 break;
520 }
521#endif /* !IN_RING0 */
522 /*
523 * Causes trouble when the guest uses a PDE to refer to the whole page table level
524 * structure. (Invalidate here; faults later on when it tries to change the page
525 * table entries -> recheck; probably only applies to the RC case.)
526 */
527# ifndef IN_RING0
528 else
529# endif /* !IN_RING0 */
530 {
531 if (uShw.pPDPae->a[iShw].n.u1Present)
532 {
533 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPae->a[iShw].u));
534 pgmPoolFree(pVM,
535 uShw.pPDPae->a[iShw].u & X86_PDE_PAE_PG_MASK,
536 pPage->idx,
537 iShw);
538 uShw.pPDPae->a[iShw].u = 0;
539 }
540 }
541 /* paranoia / a bit assumptive. */
542 if ( pCpu
543 && (off & 7)
544 && (off & 7) + cbWrite > sizeof(X86PDEPAE))
545 {
546 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDEPAE);
547 AssertBreak(iShw2 < RT_ELEMENTS(uShw.pPDPae->a));
548
549#ifndef IN_RING0
550 if ( iShw2 != iShw
551 && uShw.pPDPae->a[iShw2].u & PGM_PDFLAGS_MAPPING)
552 {
553 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
554 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
555 STAM_COUNTER_INC(&(pVM->pgm.s.StatRZGuestCR3WriteConflict));
556 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
557 break;
558 }
559#endif /* !IN_RING0 */
560# ifndef IN_RING0
561 else
562# endif /* !IN_RING0 */
563 if (uShw.pPDPae->a[iShw2].n.u1Present)
564 {
565 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPae->a[iShw2].u));
566 pgmPoolFree(pVM,
567 uShw.pPDPae->a[iShw2].u & X86_PDE_PAE_PG_MASK,
568 pPage->idx,
569 iShw2);
570 uShw.pPDPae->a[iShw2].u = 0;
571 }
572 }
573 break;
574 }
575
576 case PGMPOOLKIND_PAE_PDPT:
577 {
578 /*
579 * Hopefully this doesn't happen very often:
580 * - touching unused parts of the page
581 * - messing with the bits of pd pointers without changing the physical address
582 */
583 /* PDPT roots are not page aligned; 32 byte only! */
584 const unsigned offPdpt = GCPhysFault - pPage->GCPhys;
585
586 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
587 const unsigned iShw = offPdpt / sizeof(X86PDPE);
588 if (iShw < X86_PG_PAE_PDPE_ENTRIES) /* don't use RT_ELEMENTS(uShw.pPDPT->a), because that's for long mode only */
589 {
590# ifndef IN_RING0
591 if (uShw.pPDPT->a[iShw].u & PGM_PLXFLAGS_MAPPING)
592 {
593 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
594 STAM_COUNTER_INC(&(pVM->pgm.s.StatRZGuestCR3WriteConflict));
595 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
596 LogFlow(("pgmPoolMonitorChainChanging: Detected pdpt conflict at iShw=%#x!\n", iShw));
597 break;
598 }
599# endif /* !IN_RING0 */
600# ifndef IN_RING0
601 else
602# endif /* !IN_RING0 */
603 if (uShw.pPDPT->a[iShw].n.u1Present)
604 {
605 LogFlow(("pgmPoolMonitorChainChanging: pae pdpt iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPT->a[iShw].u));
606 pgmPoolFree(pVM,
607 uShw.pPDPT->a[iShw].u & X86_PDPE_PG_MASK,
608 pPage->idx,
609 iShw);
610 uShw.pPDPT->a[iShw].u = 0;
611 }
612
613 /* paranoia / a bit assumptive. */
614 if ( pCpu
615 && (offPdpt & 7)
616 && (offPdpt & 7) + cbWrite > sizeof(X86PDPE))
617 {
618 const unsigned iShw2 = (offPdpt + cbWrite - 1) / sizeof(X86PDPE);
619 if ( iShw2 != iShw
620 && iShw2 < X86_PG_PAE_PDPE_ENTRIES)
621 {
622# ifndef IN_RING0
623 if (uShw.pPDPT->a[iShw2].u & PGM_PLXFLAGS_MAPPING)
624 {
625 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
626 STAM_COUNTER_INC(&(pVM->pgm.s.StatRZGuestCR3WriteConflict));
627 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
628 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
629 break;
630 }
631# endif /* !IN_RING0 */
632# ifndef IN_RING0
633 else
634# endif /* !IN_RING0 */
635 if (uShw.pPDPT->a[iShw2].n.u1Present)
636 {
637 LogFlow(("pgmPoolMonitorChainChanging: pae pdpt iShw=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPT->a[iShw2].u));
638 pgmPoolFree(pVM,
639 uShw.pPDPT->a[iShw2].u & X86_PDPE_PG_MASK,
640 pPage->idx,
641 iShw2);
642 uShw.pPDPT->a[iShw2].u = 0;
643 }
644 }
645 }
646 }
647 break;
648 }
649
650#ifndef IN_RC
651 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
652 {
653 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
654 const unsigned iShw = off / sizeof(X86PDEPAE);
655 Assert(!(uShw.pPDPae->a[iShw].u & PGM_PDFLAGS_MAPPING));
656 if (uShw.pPDPae->a[iShw].n.u1Present)
657 {
658 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPae->a[iShw].u));
659 pgmPoolFree(pVM,
660 uShw.pPDPae->a[iShw].u & X86_PDE_PAE_PG_MASK,
661 pPage->idx,
662 iShw);
663 uShw.pPDPae->a[iShw].u = 0;
664 }
665 /* paranoia / a bit assumptive. */
666 if ( pCpu
667 && (off & 7)
668 && (off & 7) + cbWrite > sizeof(X86PDEPAE))
669 {
670 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDEPAE);
671 AssertBreak(iShw2 < RT_ELEMENTS(uShw.pPDPae->a));
672
673 Assert(!(uShw.pPDPae->a[iShw2].u & PGM_PDFLAGS_MAPPING));
674 if (uShw.pPDPae->a[iShw2].n.u1Present)
675 {
676 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPae->a[iShw2].u));
677 pgmPoolFree(pVM,
678 uShw.pPDPae->a[iShw2].u & X86_PDE_PAE_PG_MASK,
679 pPage->idx,
680 iShw2);
681 uShw.pPDPae->a[iShw2].u = 0;
682 }
683 }
684 break;
685 }
686
687 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
688 {
689 /*
690 * Hopefully this doesn't happen very often:
691 * - messing with the bits of pd pointers without changing the physical address
692 */
693 if (!VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3))
694 {
695 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
696 const unsigned iShw = off / sizeof(X86PDPE);
697 if (uShw.pPDPT->a[iShw].n.u1Present)
698 {
699 LogFlow(("pgmPoolMonitorChainChanging: pdpt iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPT->a[iShw].u));
700 pgmPoolFree(pVM, uShw.pPDPT->a[iShw].u & X86_PDPE_PG_MASK, pPage->idx, iShw);
701 uShw.pPDPT->a[iShw].u = 0;
702 }
703 /* paranoia / a bit assumptive. */
704 if ( pCpu
705 && (off & 7)
706 && (off & 7) + cbWrite > sizeof(X86PDPE))
707 {
708 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDPE);
709 if (uShw.pPDPT->a[iShw2].n.u1Present)
710 {
711 LogFlow(("pgmPoolMonitorChainChanging: pdpt iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPT->a[iShw2].u));
712 pgmPoolFree(pVM, uShw.pPDPT->a[iShw2].u & X86_PDPE_PG_MASK, pPage->idx, iShw2);
713 uShw.pPDPT->a[iShw2].u = 0;
714 }
715 }
716 }
717 break;
718 }
719
720 case PGMPOOLKIND_64BIT_PML4:
721 {
722 /*
723 * Hopefully this doesn't happen very often:
724 * - messing with the bits of pd pointers without changing the physical address
725 */
726 if (!VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3))
727 {
728 uShw.pv = PGMPOOL_PAGE_2_LOCKED_PTR(pVM, pPage);
729 const unsigned iShw = off / sizeof(X86PDPE);
730 if (uShw.pPML4->a[iShw].n.u1Present)
731 {
732 LogFlow(("pgmPoolMonitorChainChanging: pml4 iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPML4->a[iShw].u));
733 pgmPoolFree(pVM, uShw.pPML4->a[iShw].u & X86_PML4E_PG_MASK, pPage->idx, iShw);
734 uShw.pPML4->a[iShw].u = 0;
735 }
736 /* paranoia / a bit assumptive. */
737 if ( pCpu
738 && (off & 7)
739 && (off & 7) + cbWrite > sizeof(X86PDPE))
740 {
741 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PML4E);
742 if (uShw.pPML4->a[iShw2].n.u1Present)
743 {
744 LogFlow(("pgmPoolMonitorChainChanging: pml4 iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPML4->a[iShw2].u));
745 pgmPoolFree(pVM, uShw.pPML4->a[iShw2].u & X86_PML4E_PG_MASK, pPage->idx, iShw2);
746 uShw.pPML4->a[iShw2].u = 0;
747 }
748 }
749 }
750 break;
751 }
752#endif /* IN_RING0 */
753
754 default:
755 AssertFatalMsgFailed(("enmKind=%d\n", pPage->enmKind));
756 }
757 PGMPOOL_UNLOCK_PTR(pVM, uShw.pv);
758
759 /* next */
760 if (pPage->iMonitoredNext == NIL_PGMPOOL_IDX)
761 return;
762 pPage = &pPool->aPages[pPage->iMonitoredNext];
763 }
764}
765
766# ifndef IN_RING3
767/**
768 * Checks if a access could be a fork operation in progress.
769 *
770 * Meaning, that the guest is setuping up the parent process for Copy-On-Write.
771 *
772 * @returns true if it's likly that we're forking, otherwise false.
773 * @param pPool The pool.
774 * @param pCpu The disassembled instruction.
775 * @param offFault The access offset.
776 */
777DECLINLINE(bool) pgmPoolMonitorIsForking(PPGMPOOL pPool, PDISCPUSTATE pCpu, unsigned offFault)
778{
779 /*
780 * i386 linux is using btr to clear X86_PTE_RW.
781 * The functions involved are (2.6.16 source inspection):
782 * clear_bit
783 * ptep_set_wrprotect
784 * copy_one_pte
785 * copy_pte_range
786 * copy_pmd_range
787 * copy_pud_range
788 * copy_page_range
789 * dup_mmap
790 * dup_mm
791 * copy_mm
792 * copy_process
793 * do_fork
794 */
795 if ( pCpu->pCurInstr->opcode == OP_BTR
796 && !(offFault & 4)
797 /** @todo Validate that the bit index is X86_PTE_RW. */
798 )
799 {
800 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,Fork));
801 return true;
802 }
803 return false;
804}
805
806
807/**
808 * Determine whether the page is likely to have been reused.
809 *
810 * @returns true if we consider the page as being reused for a different purpose.
811 * @returns false if we consider it to still be a paging page.
812 * @param pVM VM Handle.
813 * @param pPage The page in question.
814 * @param pRegFrame Trap register frame.
815 * @param pCpu The disassembly info for the faulting instruction.
816 * @param pvFault The fault address.
817 *
818 * @remark The REP prefix check is left to the caller because of STOSD/W.
819 */
820DECLINLINE(bool) pgmPoolMonitorIsReused(PVM pVM, PPGMPOOLPAGE pPage, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR pvFault)
821{
822#ifndef IN_RC
823 /** @todo could make this general, faulting close to rsp should be safe reuse heuristic. */
824 if ( HWACCMHasPendingIrq(pVM)
825 && (pRegFrame->rsp - pvFault) < 32)
826 {
827 /* Fault caused by stack writes while trying to inject an interrupt event. */
828 Log(("pgmPoolMonitorIsReused: reused %RGv for interrupt stack (rsp=%RGv).\n", pvFault, pRegFrame->rsp));
829 return true;
830 }
831#else
832 NOREF(pVM); NOREF(pvFault);
833#endif
834
835 switch (pCpu->pCurInstr->opcode)
836 {
837 /* call implies the actual push of the return address faulted */
838 case OP_CALL:
839 Log4(("pgmPoolMonitorIsReused: CALL\n"));
840 return true;
841 case OP_PUSH:
842 Log4(("pgmPoolMonitorIsReused: PUSH\n"));
843 return true;
844 case OP_PUSHF:
845 Log4(("pgmPoolMonitorIsReused: PUSHF\n"));
846 return true;
847 case OP_PUSHA:
848 Log4(("pgmPoolMonitorIsReused: PUSHA\n"));
849 return true;
850 case OP_FXSAVE:
851 Log4(("pgmPoolMonitorIsReused: FXSAVE\n"));
852 return true;
853 case OP_MOVNTI: /* solaris - block_zero_no_xmm */
854 Log4(("pgmPoolMonitorIsReused: MOVNTI\n"));
855 return true;
856 case OP_MOVNTDQ: /* solaris - hwblkclr & hwblkpagecopy */
857 Log4(("pgmPoolMonitorIsReused: MOVNTDQ\n"));
858 return true;
859 case OP_MOVSWD:
860 case OP_STOSWD:
861 if ( pCpu->prefix == (PREFIX_REP|PREFIX_REX)
862 && pRegFrame->rcx >= 0x40
863 )
864 {
865 Assert(pCpu->mode == CPUMODE_64BIT);
866
867 Log(("pgmPoolMonitorIsReused: OP_STOSQ\n"));
868 return true;
869 }
870 return false;
871 }
872 if ( (pCpu->param1.flags & USE_REG_GEN32)
873 && (pCpu->param1.base.reg_gen == USE_REG_ESP))
874 {
875 Log4(("pgmPoolMonitorIsReused: ESP\n"));
876 return true;
877 }
878
879 //if (pPage->fCR3Mix)
880 // return false;
881 return false;
882}
883
884
885/**
886 * Flushes the page being accessed.
887 *
888 * @returns VBox status code suitable for scheduling.
889 * @param pVM The VM handle.
890 * @param pPool The pool.
891 * @param pPage The pool page (head).
892 * @param pCpu The disassembly of the write instruction.
893 * @param pRegFrame The trap register frame.
894 * @param GCPhysFault The fault address as guest physical address.
895 * @param pvFault The fault address.
896 */
897static int pgmPoolAccessHandlerFlush(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pCpu,
898 PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
899{
900 /*
901 * First, do the flushing.
902 */
903 int rc = pgmPoolMonitorChainFlush(pPool, pPage);
904
905 /*
906 * Emulate the instruction (xp/w2k problem, requires pc/cr2/sp detection).
907 */
908 uint32_t cbWritten;
909 int rc2 = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, pvFault, &cbWritten);
910 if (RT_SUCCESS(rc2))
911 pRegFrame->rip += pCpu->opsize;
912 else if (rc2 == VERR_EM_INTERPRETER)
913 {
914#ifdef IN_RC
915 if (PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip))
916 {
917 LogFlow(("pgmPoolAccessHandlerPTWorker: Interpretation failed for patch code %04x:%RGv, ignoring.\n",
918 pRegFrame->cs, (RTGCPTR)pRegFrame->eip));
919 rc = VINF_SUCCESS;
920 STAM_COUNTER_INC(&pPool->StatMonitorRZIntrFailPatch2);
921 }
922 else
923#endif
924 {
925 rc = VINF_EM_RAW_EMULATE_INSTR;
926 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,EmulateInstr));
927 }
928 }
929 else
930 rc = rc2;
931
932 /* See use in pgmPoolAccessHandlerSimple(). */
933 PGM_INVL_GUEST_TLBS();
934
935 LogFlow(("pgmPoolAccessHandlerPT: returns %Rrc (flushed)\n", rc));
936 return rc;
937
938}
939
940
941/**
942 * Handles the STOSD write accesses.
943 *
944 * @returns VBox status code suitable for scheduling.
945 * @param pVM The VM handle.
946 * @param pPool The pool.
947 * @param pPage The pool page (head).
948 * @param pCpu The disassembly of the write instruction.
949 * @param pRegFrame The trap register frame.
950 * @param GCPhysFault The fault address as guest physical address.
951 * @param pvFault The fault address.
952 */
953DECLINLINE(int) pgmPoolAccessHandlerSTOSD(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pCpu,
954 PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
955{
956 Assert(pCpu->mode == CPUMODE_32BIT);
957
958 Log3(("pgmPoolAccessHandlerSTOSD\n"));
959
960 /*
961 * Increment the modification counter and insert it into the list
962 * of modified pages the first time.
963 */
964 if (!pPage->cModifications++)
965 pgmPoolMonitorModifiedInsert(pPool, pPage);
966
967 /*
968 * Execute REP STOSD.
969 *
970 * This ASSUMES that we're not invoked by Trap0e on in a out-of-sync
971 * write situation, meaning that it's safe to write here.
972 */
973#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
974 PVMCPU pVCpu = VMMGetCpu(pPool->CTX_SUFF(pVM));
975#endif
976 RTGCUINTPTR pu32 = (RTGCUINTPTR)pvFault;
977 while (pRegFrame->ecx)
978 {
979#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
980 uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
981 pgmPoolMonitorChainChanging(pPool, pPage, GCPhysFault, (RTGCPTR)pu32, NULL);
982 PGMDynMapPopAutoSubset(pVCpu, iPrevSubset);
983#else
984 pgmPoolMonitorChainChanging(pPool, pPage, GCPhysFault, (RTGCPTR)pu32, NULL);
985#endif
986#ifdef IN_RC
987 *(uint32_t *)pu32 = pRegFrame->eax;
988#else
989 PGMPhysSimpleWriteGCPhys(pVM, GCPhysFault, &pRegFrame->eax, 4);
990#endif
991 pu32 += 4;
992 GCPhysFault += 4;
993 pRegFrame->edi += 4;
994 pRegFrame->ecx--;
995 }
996 pRegFrame->rip += pCpu->opsize;
997
998#ifdef IN_RC
999 /* See use in pgmPoolAccessHandlerSimple(). */
1000 PGM_INVL_GUEST_TLBS();
1001#endif
1002
1003 LogFlow(("pgmPoolAccessHandlerSTOSD: returns\n"));
1004 return VINF_SUCCESS;
1005}
1006
1007
1008/**
1009 * Handles the simple write accesses.
1010 *
1011 * @returns VBox status code suitable for scheduling.
1012 * @param pVM The VM handle.
1013 * @param pPool The pool.
1014 * @param pPage The pool page (head).
1015 * @param pCpu The disassembly of the write instruction.
1016 * @param pRegFrame The trap register frame.
1017 * @param GCPhysFault The fault address as guest physical address.
1018 * @param pvFault The fault address.
1019 */
1020DECLINLINE(int) pgmPoolAccessHandlerSimple(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pCpu,
1021 PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
1022{
1023 Log3(("pgmPoolAccessHandlerSimple\n"));
1024 /*
1025 * Increment the modification counter and insert it into the list
1026 * of modified pages the first time.
1027 */
1028 if (!pPage->cModifications++)
1029 pgmPoolMonitorModifiedInsert(pPool, pPage);
1030
1031 /*
1032 * Clear all the pages. ASSUMES that pvFault is readable.
1033 */
1034#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
1035 PVMCPU pVCpu = VMMGetCpu(pPool->CTX_SUFF(pVM));
1036 uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
1037 pgmPoolMonitorChainChanging(pPool, pPage, GCPhysFault, pvFault, pCpu);
1038 PGMDynMapPopAutoSubset(pVCpu, iPrevSubset);
1039#else
1040 pgmPoolMonitorChainChanging(pPool, pPage, GCPhysFault, pvFault, pCpu);
1041#endif
1042
1043 /*
1044 * Interpret the instruction.
1045 */
1046 uint32_t cb;
1047 int rc = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, pvFault, &cb);
1048 if (RT_SUCCESS(rc))
1049 pRegFrame->rip += pCpu->opsize;
1050 else if (rc == VERR_EM_INTERPRETER)
1051 {
1052 LogFlow(("pgmPoolAccessHandlerPTWorker: Interpretation failed for %04x:%RGv - opcode=%d\n",
1053 pRegFrame->cs, (RTGCPTR)pRegFrame->rip, pCpu->pCurInstr->opcode));
1054 rc = VINF_EM_RAW_EMULATE_INSTR;
1055 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,EmulateInstr));
1056 }
1057
1058#ifdef IN_RC
1059 /*
1060 * Quick hack, with logging enabled we're getting stale
1061 * code TLBs but no data TLB for EIP and crash in EMInterpretDisasOne.
1062 * Flushing here is BAD and expensive, I think EMInterpretDisasOne will
1063 * have to be fixed to support this. But that'll have to wait till next week.
1064 *
1065 * An alternative is to keep track of the changed PTEs together with the
1066 * GCPhys from the guest PT. This may proove expensive though.
1067 *
1068 * At the moment, it's VITAL that it's done AFTER the instruction interpreting
1069 * because we need the stale TLBs in some cases (XP boot). This MUST be fixed properly!
1070 */
1071 PGM_INVL_GUEST_TLBS();
1072#endif
1073
1074 LogFlow(("pgmPoolAccessHandlerSimple: returns %Rrc cb=%d\n", rc, cb));
1075 return rc;
1076}
1077
1078/**
1079 * \#PF Handler callback for PT write accesses.
1080 *
1081 * @returns VBox status code (appropriate for GC return).
1082 * @param pVM VM Handle.
1083 * @param uErrorCode CPU Error code.
1084 * @param pRegFrame Trap register frame.
1085 * NULL on DMA and other non CPU access.
1086 * @param pvFault The fault address (cr2).
1087 * @param GCPhysFault The GC physical address corresponding to pvFault.
1088 * @param pvUser User argument.
1089 */
1090DECLEXPORT(int) pgmPoolAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1091{
1092 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), a);
1093 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1094 PPGMPOOLPAGE pPage = (PPGMPOOLPAGE)pvUser;
1095 LogFlow(("pgmPoolAccessHandler: pvFault=%RGv pPage=%p:{.idx=%d} GCPhysFault=%RGp\n", pvFault, pPage, pPage->idx, GCPhysFault));
1096
1097 /*
1098 * We should ALWAYS have the list head as user parameter. This
1099 * is because we use that page to record the changes.
1100 */
1101 Assert(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
1102
1103 /*
1104 * Disassemble the faulting instruction.
1105 */
1106 DISCPUSTATE Cpu;
1107 int rc = EMInterpretDisasOne(pVM, pRegFrame, &Cpu, NULL);
1108 AssertRCReturn(rc, rc);
1109
1110 /*
1111 * Check if it's worth dealing with.
1112 */
1113 bool fReused = false;
1114 if ( ( pPage->cModifications < 48 /** @todo #define */ /** @todo need to check that it's not mapping EIP. */ /** @todo adjust this! */
1115 || pgmPoolIsPageLocked(&pVM->pgm.s, pPage)
1116 )
1117 && !(fReused = pgmPoolMonitorIsReused(pVM, pPage, pRegFrame, &Cpu, pvFault))
1118 && !pgmPoolMonitorIsForking(pPool, &Cpu, GCPhysFault & PAGE_OFFSET_MASK))
1119 {
1120 /*
1121 * Simple instructions, no REP prefix.
1122 */
1123 if (!(Cpu.prefix & (PREFIX_REP | PREFIX_REPNE)))
1124 {
1125 rc = pgmPoolAccessHandlerSimple(pVM, pPool, pPage, &Cpu, pRegFrame, GCPhysFault, pvFault);
1126 STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,Handled), a);
1127 return rc;
1128 }
1129
1130 /*
1131 * Windows is frequently doing small memset() operations (netio test 4k+).
1132 * We have to deal with these or we'll kill the cache and performance.
1133 */
1134 if ( Cpu.pCurInstr->opcode == OP_STOSWD
1135 && CPUMGetGuestCPL(pVM, pRegFrame) == 0
1136 && pRegFrame->ecx <= 0x20
1137 && pRegFrame->ecx * 4 <= PAGE_SIZE - ((uintptr_t)pvFault & PAGE_OFFSET_MASK)
1138 && !((uintptr_t)pvFault & 3)
1139 && (pRegFrame->eax == 0 || pRegFrame->eax == 0x80) /* the two values observed. */
1140 && Cpu.mode == CPUMODE_32BIT
1141 && Cpu.opmode == CPUMODE_32BIT
1142 && Cpu.addrmode == CPUMODE_32BIT
1143 && Cpu.prefix == PREFIX_REP
1144 && !pRegFrame->eflags.Bits.u1DF
1145 )
1146 {
1147 rc = pgmPoolAccessHandlerSTOSD(pVM, pPool, pPage, &Cpu, pRegFrame, GCPhysFault, pvFault);
1148 STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,RepStosd), a);
1149 return rc;
1150 }
1151
1152 /* REP prefix, don't bother. */
1153 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,RepPrefix));
1154 Log4(("pgmPoolAccessHandler: eax=%#x ecx=%#x edi=%#x esi=%#x rip=%RGv opcode=%d prefix=%#x\n",
1155 pRegFrame->eax, pRegFrame->ecx, pRegFrame->edi, pRegFrame->esi, (RTGCPTR)pRegFrame->rip, Cpu.pCurInstr->opcode, Cpu.prefix));
1156 }
1157
1158 /*
1159 * Not worth it, so flush it.
1160 *
1161 * If we considered it to be reused, don't to back to ring-3
1162 * to emulate failed instructions since we usually cannot
1163 * interpret then. This may be a bit risky, in which case
1164 * the reuse detection must be fixed.
1165 */
1166 rc = pgmPoolAccessHandlerFlush(pVM, pPool, pPage, &Cpu, pRegFrame, GCPhysFault, pvFault);
1167 if (rc == VINF_EM_RAW_EMULATE_INSTR && fReused)
1168 rc = VINF_SUCCESS;
1169 STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,FlushPage), a);
1170 return rc;
1171}
1172
1173# endif /* !IN_RING3 */
1174#endif /* PGMPOOL_WITH_MONITORING */
1175
1176#ifdef PGMPOOL_WITH_CACHE
1177
1178/**
1179 * Inserts a page into the GCPhys hash table.
1180 *
1181 * @param pPool The pool.
1182 * @param pPage The page.
1183 */
1184DECLINLINE(void) pgmPoolHashInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1185{
1186 Log3(("pgmPoolHashInsert: %RGp\n", pPage->GCPhys));
1187 Assert(pPage->GCPhys != NIL_RTGCPHYS); Assert(pPage->iNext == NIL_PGMPOOL_IDX);
1188 uint16_t iHash = PGMPOOL_HASH(pPage->GCPhys);
1189 pPage->iNext = pPool->aiHash[iHash];
1190 pPool->aiHash[iHash] = pPage->idx;
1191}
1192
1193
1194/**
1195 * Removes a page from the GCPhys hash table.
1196 *
1197 * @param pPool The pool.
1198 * @param pPage The page.
1199 */
1200DECLINLINE(void) pgmPoolHashRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1201{
1202 Log3(("pgmPoolHashRemove: %RGp\n", pPage->GCPhys));
1203 uint16_t iHash = PGMPOOL_HASH(pPage->GCPhys);
1204 if (pPool->aiHash[iHash] == pPage->idx)
1205 pPool->aiHash[iHash] = pPage->iNext;
1206 else
1207 {
1208 uint16_t iPrev = pPool->aiHash[iHash];
1209 for (;;)
1210 {
1211 const int16_t i = pPool->aPages[iPrev].iNext;
1212 if (i == pPage->idx)
1213 {
1214 pPool->aPages[iPrev].iNext = pPage->iNext;
1215 break;
1216 }
1217 if (i == NIL_PGMPOOL_IDX)
1218 {
1219 AssertReleaseMsgFailed(("GCPhys=%RGp idx=%#x\n", pPage->GCPhys, pPage->idx));
1220 break;
1221 }
1222 iPrev = i;
1223 }
1224 }
1225 pPage->iNext = NIL_PGMPOOL_IDX;
1226}
1227
1228
1229/**
1230 * Frees up one cache page.
1231 *
1232 * @returns VBox status code.
1233 * @retval VINF_SUCCESS on success.
1234 * @param pPool The pool.
1235 * @param iUser The user index.
1236 */
1237static int pgmPoolCacheFreeOne(PPGMPOOL pPool, uint16_t iUser)
1238{
1239#ifndef IN_RC
1240 const PVM pVM = pPool->CTX_SUFF(pVM);
1241#endif
1242 Assert(pPool->iAgeHead != pPool->iAgeTail); /* We shouldn't be here if there < 2 cached entries! */
1243 STAM_COUNTER_INC(&pPool->StatCacheFreeUpOne);
1244
1245 /*
1246 * Select one page from the tail of the age list.
1247 */
1248 PPGMPOOLPAGE pPage;
1249 for (unsigned iLoop = 0; ; iLoop++)
1250 {
1251 uint16_t iToFree = pPool->iAgeTail;
1252 if (iToFree == iUser)
1253 iToFree = pPool->aPages[iToFree].iAgePrev;
1254/* This is the alternative to the SyncCR3 pgmPoolCacheUsed calls.
1255 if (pPool->aPages[iToFree].iUserHead != NIL_PGMPOOL_USER_INDEX)
1256 {
1257 uint16_t i = pPool->aPages[iToFree].iAgePrev;
1258 for (unsigned j = 0; j < 10 && i != NIL_PGMPOOL_USER_INDEX; j++, i = pPool->aPages[i].iAgePrev)
1259 {
1260 if (pPool->aPages[iToFree].iUserHead == NIL_PGMPOOL_USER_INDEX)
1261 continue;
1262 iToFree = i;
1263 break;
1264 }
1265 }
1266*/
1267 Assert(iToFree != iUser);
1268 AssertRelease(iToFree != NIL_PGMPOOL_IDX);
1269 pPage = &pPool->aPages[iToFree];
1270
1271 /*
1272 * Reject any attempts at flushing the currently active shadow CR3 mapping.
1273 * Call pgmPoolCacheUsed to move the page to the head of the age list.
1274 */
1275 if (!pgmPoolIsPageLocked(&pPool->CTX_SUFF(pVM)->pgm.s, pPage))
1276 break;
1277 LogFlow(("pgmPoolCacheFreeOne: refuse CR3 mapping\n"));
1278 pgmPoolCacheUsed(pPool, pPage);
1279 AssertLogRelReturn(iLoop < 8192, VERR_INTERNAL_ERROR);
1280 }
1281
1282 /*
1283 * Found a usable page, flush it and return.
1284 */
1285 int rc = pgmPoolFlushPage(pPool, pPage);
1286 if (rc == VINF_SUCCESS)
1287 PGM_INVL_GUEST_TLBS(); /* see PT handler. */
1288 return rc;
1289}
1290
1291
1292/**
1293 * Checks if a kind mismatch is really a page being reused
1294 * or if it's just normal remappings.
1295 *
1296 * @returns true if reused and the cached page (enmKind1) should be flushed
1297 * @returns false if not reused.
1298 * @param enmKind1 The kind of the cached page.
1299 * @param enmKind2 The kind of the requested page.
1300 */
1301static bool pgmPoolCacheReusedByKind(PGMPOOLKIND enmKind1, PGMPOOLKIND enmKind2)
1302{
1303 switch (enmKind1)
1304 {
1305 /*
1306 * Never reuse them. There is no remapping in non-paging mode.
1307 */
1308 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1309 case PGMPOOLKIND_32BIT_PD_PHYS:
1310 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1311 case PGMPOOLKIND_PAE_PD_PHYS:
1312 case PGMPOOLKIND_PAE_PDPT_PHYS:
1313 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
1314 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
1315 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
1316 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
1317 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
1318 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT: /* never reuse them for other types */
1319 return false;
1320
1321 /*
1322 * It's perfectly fine to reuse these, except for PAE and non-paging stuff.
1323 */
1324 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1325 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1326 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1327 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1328 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
1329 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
1330 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
1331 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
1332 case PGMPOOLKIND_32BIT_PD:
1333 case PGMPOOLKIND_PAE_PDPT:
1334 switch (enmKind2)
1335 {
1336 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
1337 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1338 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
1339 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
1340 case PGMPOOLKIND_64BIT_PML4:
1341 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1342 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1343 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1344 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
1345 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
1346 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
1347 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
1348 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
1349 return true;
1350 default:
1351 return false;
1352 }
1353
1354 /*
1355 * It's perfectly fine to reuse these, except for PAE and non-paging stuff.
1356 */
1357 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
1358 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1359 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
1360 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
1361 case PGMPOOLKIND_64BIT_PML4:
1362 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1363 switch (enmKind2)
1364 {
1365 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1366 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1367 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1368 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1369 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
1370 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
1371 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
1372 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
1373 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1374 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1375 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
1376 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
1377 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
1378 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
1379 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
1380 return true;
1381 default:
1382 return false;
1383 }
1384
1385 /*
1386 * These cannot be flushed, and it's common to reuse the PDs as PTs.
1387 */
1388 case PGMPOOLKIND_ROOT_NESTED:
1389 return false;
1390
1391 default:
1392 AssertFatalMsgFailed(("enmKind1=%d\n", enmKind1));
1393 }
1394}
1395
1396
1397/**
1398 * Attempts to satisfy a pgmPoolAlloc request from the cache.
1399 *
1400 * @returns VBox status code.
1401 * @retval VINF_PGM_CACHED_PAGE on success.
1402 * @retval VERR_FILE_NOT_FOUND if not found.
1403 * @param pPool The pool.
1404 * @param GCPhys The GC physical address of the page we're gonna shadow.
1405 * @param enmKind The kind of mapping.
1406 * @param iUser The shadow page pool index of the user table.
1407 * @param iUserTable The index into the user table (shadowed).
1408 * @param ppPage Where to store the pointer to the page.
1409 */
1410static int pgmPoolCacheAlloc(PPGMPOOL pPool, RTGCPHYS GCPhys, PGMPOOLKIND enmKind, uint16_t iUser, uint32_t iUserTable, PPPGMPOOLPAGE ppPage)
1411{
1412#ifndef IN_RC
1413 const PVM pVM = pPool->CTX_SUFF(pVM);
1414#endif
1415 /*
1416 * Look up the GCPhys in the hash.
1417 */
1418 unsigned i = pPool->aiHash[PGMPOOL_HASH(GCPhys)];
1419 Log3(("pgmPoolCacheAlloc: %RGp kind %s iUser=%x iUserTable=%x SLOT=%d\n", GCPhys, pgmPoolPoolKindToStr(enmKind), iUser, iUserTable, i));
1420 if (i != NIL_PGMPOOL_IDX)
1421 {
1422 do
1423 {
1424 PPGMPOOLPAGE pPage = &pPool->aPages[i];
1425 Log4(("pgmPoolCacheAlloc: slot %d found page %RGp\n", i, pPage->GCPhys));
1426 if (pPage->GCPhys == GCPhys)
1427 {
1428 if ((PGMPOOLKIND)pPage->enmKind == enmKind)
1429 {
1430 /* Put it at the start of the use list to make sure pgmPoolTrackAddUser
1431 * doesn't flush it in case there are no more free use records.
1432 */
1433 pgmPoolCacheUsed(pPool, pPage);
1434
1435 int rc = pgmPoolTrackAddUser(pPool, pPage, iUser, iUserTable);
1436 if (RT_SUCCESS(rc))
1437 {
1438 Assert((PGMPOOLKIND)pPage->enmKind == enmKind);
1439 *ppPage = pPage;
1440 STAM_COUNTER_INC(&pPool->StatCacheHits);
1441 return VINF_PGM_CACHED_PAGE;
1442 }
1443 return rc;
1444 }
1445
1446 /*
1447 * The kind is different. In some cases we should now flush the page
1448 * as it has been reused, but in most cases this is normal remapping
1449 * of PDs as PT or big pages using the GCPhys field in a slightly
1450 * different way than the other kinds.
1451 */
1452 if (pgmPoolCacheReusedByKind((PGMPOOLKIND)pPage->enmKind, enmKind))
1453 {
1454 STAM_COUNTER_INC(&pPool->StatCacheKindMismatches);
1455 pgmPoolFlushPage(pPool, pPage);
1456 PGM_INVL_GUEST_TLBS(); /* see PT handler. */
1457 break;
1458 }
1459 }
1460
1461 /* next */
1462 i = pPage->iNext;
1463 } while (i != NIL_PGMPOOL_IDX);
1464 }
1465
1466 Log3(("pgmPoolCacheAlloc: Missed GCPhys=%RGp enmKind=%s\n", GCPhys, pgmPoolPoolKindToStr(enmKind)));
1467 STAM_COUNTER_INC(&pPool->StatCacheMisses);
1468 return VERR_FILE_NOT_FOUND;
1469}
1470
1471
1472/**
1473 * Inserts a page into the cache.
1474 *
1475 * @param pPool The pool.
1476 * @param pPage The cached page.
1477 * @param fCanBeCached Set if the page is fit for caching from the caller's point of view.
1478 */
1479static void pgmPoolCacheInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage, bool fCanBeCached)
1480{
1481 /*
1482 * Insert into the GCPhys hash if the page is fit for that.
1483 */
1484 Assert(!pPage->fCached);
1485 if (fCanBeCached)
1486 {
1487 pPage->fCached = true;
1488 pgmPoolHashInsert(pPool, pPage);
1489 Log3(("pgmPoolCacheInsert: Caching %p:{.Core=%RHp, .idx=%d, .enmKind=%s, GCPhys=%RGp}\n",
1490 pPage, pPage->Core.Key, pPage->idx, pgmPoolPoolKindToStr(pPage->enmKind), pPage->GCPhys));
1491 STAM_COUNTER_INC(&pPool->StatCacheCacheable);
1492 }
1493 else
1494 {
1495 Log3(("pgmPoolCacheInsert: Not caching %p:{.Core=%RHp, .idx=%d, .enmKind=%s, GCPhys=%RGp}\n",
1496 pPage, pPage->Core.Key, pPage->idx, pgmPoolPoolKindToStr(pPage->enmKind), pPage->GCPhys));
1497 STAM_COUNTER_INC(&pPool->StatCacheUncacheable);
1498 }
1499
1500 /*
1501 * Insert at the head of the age list.
1502 */
1503 pPage->iAgePrev = NIL_PGMPOOL_IDX;
1504 pPage->iAgeNext = pPool->iAgeHead;
1505 if (pPool->iAgeHead != NIL_PGMPOOL_IDX)
1506 pPool->aPages[pPool->iAgeHead].iAgePrev = pPage->idx;
1507 else
1508 pPool->iAgeTail = pPage->idx;
1509 pPool->iAgeHead = pPage->idx;
1510}
1511
1512
1513/**
1514 * Flushes a cached page.
1515 *
1516 * @param pPool The pool.
1517 * @param pPage The cached page.
1518 */
1519static void pgmPoolCacheFlushPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1520{
1521 Log3(("pgmPoolCacheFlushPage: %RGp\n", pPage->GCPhys));
1522
1523 /*
1524 * Remove the page from the hash.
1525 */
1526 if (pPage->fCached)
1527 {
1528 pPage->fCached = false;
1529 pgmPoolHashRemove(pPool, pPage);
1530 }
1531 else
1532 Assert(pPage->iNext == NIL_PGMPOOL_IDX);
1533
1534 /*
1535 * Remove it from the age list.
1536 */
1537 if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
1538 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
1539 else
1540 pPool->iAgeTail = pPage->iAgePrev;
1541 if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
1542 pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
1543 else
1544 pPool->iAgeHead = pPage->iAgeNext;
1545 pPage->iAgeNext = NIL_PGMPOOL_IDX;
1546 pPage->iAgePrev = NIL_PGMPOOL_IDX;
1547}
1548
1549#endif /* PGMPOOL_WITH_CACHE */
1550#ifdef PGMPOOL_WITH_MONITORING
1551
1552/**
1553 * Looks for pages sharing the monitor.
1554 *
1555 * @returns Pointer to the head page.
1556 * @returns NULL if not found.
1557 * @param pPool The Pool
1558 * @param pNewPage The page which is going to be monitored.
1559 */
1560static PPGMPOOLPAGE pgmPoolMonitorGetPageByGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pNewPage)
1561{
1562#ifdef PGMPOOL_WITH_CACHE
1563 /*
1564 * Look up the GCPhys in the hash.
1565 */
1566 RTGCPHYS GCPhys = pNewPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1);
1567 unsigned i = pPool->aiHash[PGMPOOL_HASH(GCPhys)];
1568 if (i == NIL_PGMPOOL_IDX)
1569 return NULL;
1570 do
1571 {
1572 PPGMPOOLPAGE pPage = &pPool->aPages[i];
1573 if ( pPage->GCPhys - GCPhys < PAGE_SIZE
1574 && pPage != pNewPage)
1575 {
1576 switch (pPage->enmKind)
1577 {
1578 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1579 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1580 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1581 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
1582 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
1583 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
1584 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
1585 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
1586 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
1587 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
1588 case PGMPOOLKIND_64BIT_PML4:
1589 case PGMPOOLKIND_32BIT_PD:
1590 case PGMPOOLKIND_PAE_PDPT:
1591 {
1592 /* find the head */
1593 while (pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
1594 {
1595 Assert(pPage->iMonitoredPrev != pPage->idx);
1596 pPage = &pPool->aPages[pPage->iMonitoredPrev];
1597 }
1598 return pPage;
1599 }
1600
1601 /* ignore, no monitoring. */
1602 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1603 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1604 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1605 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1606 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1607 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
1608 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
1609 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
1610 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
1611 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
1612 case PGMPOOLKIND_ROOT_NESTED:
1613 case PGMPOOLKIND_PAE_PD_PHYS:
1614 case PGMPOOLKIND_PAE_PDPT_PHYS:
1615 case PGMPOOLKIND_32BIT_PD_PHYS:
1616 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
1617 break;
1618 default:
1619 AssertFatalMsgFailed(("enmKind=%d idx=%d\n", pPage->enmKind, pPage->idx));
1620 }
1621 }
1622
1623 /* next */
1624 i = pPage->iNext;
1625 } while (i != NIL_PGMPOOL_IDX);
1626#endif
1627 return NULL;
1628}
1629
1630
1631/**
1632 * Enabled write monitoring of a guest page.
1633 *
1634 * @returns VBox status code.
1635 * @retval VINF_SUCCESS on success.
1636 * @param pPool The pool.
1637 * @param pPage The cached page.
1638 */
1639static int pgmPoolMonitorInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1640{
1641 LogFlow(("pgmPoolMonitorInsert %RGp\n", pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1)));
1642
1643 /*
1644 * Filter out the relevant kinds.
1645 */
1646 switch (pPage->enmKind)
1647 {
1648 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1649 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1650 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
1651 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1652 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
1653 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
1654 case PGMPOOLKIND_64BIT_PML4:
1655 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
1656 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
1657 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
1658 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
1659 case PGMPOOLKIND_32BIT_PD:
1660 case PGMPOOLKIND_PAE_PDPT:
1661 break;
1662
1663 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1664 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1665 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1666 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1667 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1668 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
1669 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
1670 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
1671 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
1672 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
1673 case PGMPOOLKIND_ROOT_NESTED:
1674 /* Nothing to monitor here. */
1675 return VINF_SUCCESS;
1676
1677 case PGMPOOLKIND_32BIT_PD_PHYS:
1678 case PGMPOOLKIND_PAE_PDPT_PHYS:
1679 case PGMPOOLKIND_PAE_PD_PHYS:
1680 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
1681 /* Nothing to monitor here. */
1682 return VINF_SUCCESS;
1683#ifdef PGMPOOL_WITH_MIXED_PT_CR3
1684 break;
1685#else
1686 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
1687#endif
1688 default:
1689 AssertFatalMsgFailed(("This can't happen! enmKind=%d\n", pPage->enmKind));
1690 }
1691
1692 /*
1693 * Install handler.
1694 */
1695 int rc;
1696 PPGMPOOLPAGE pPageHead = pgmPoolMonitorGetPageByGCPhys(pPool, pPage);
1697 if (pPageHead)
1698 {
1699 Assert(pPageHead != pPage); Assert(pPageHead->iMonitoredNext != pPage->idx);
1700 Assert(pPageHead->iMonitoredPrev != pPage->idx);
1701 pPage->iMonitoredPrev = pPageHead->idx;
1702 pPage->iMonitoredNext = pPageHead->iMonitoredNext;
1703 if (pPageHead->iMonitoredNext != NIL_PGMPOOL_IDX)
1704 pPool->aPages[pPageHead->iMonitoredNext].iMonitoredPrev = pPage->idx;
1705 pPageHead->iMonitoredNext = pPage->idx;
1706 rc = VINF_SUCCESS;
1707 }
1708 else
1709 {
1710 Assert(pPage->iMonitoredNext == NIL_PGMPOOL_IDX); Assert(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
1711 PVM pVM = pPool->CTX_SUFF(pVM);
1712 const RTGCPHYS GCPhysPage = pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1);
1713 rc = PGMHandlerPhysicalRegisterEx(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1714 GCPhysPage, GCPhysPage + (PAGE_SIZE - 1),
1715 pPool->pfnAccessHandlerR3, MMHyperCCToR3(pVM, pPage),
1716 pPool->pfnAccessHandlerR0, MMHyperCCToR0(pVM, pPage),
1717 pPool->pfnAccessHandlerRC, MMHyperCCToRC(pVM, pPage),
1718 pPool->pszAccessHandler);
1719 /** @todo we should probably deal with out-of-memory conditions here, but for now increasing
1720 * the heap size should suffice. */
1721 AssertFatalRC(rc);
1722 Assert(!(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL) || VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3));
1723 }
1724 pPage->fMonitored = true;
1725 return rc;
1726}
1727
1728
1729/**
1730 * Disables write monitoring of a guest page.
1731 *
1732 * @returns VBox status code.
1733 * @retval VINF_SUCCESS on success.
1734 * @param pPool The pool.
1735 * @param pPage The cached page.
1736 */
1737static int pgmPoolMonitorFlush(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1738{
1739 /*
1740 * Filter out the relevant kinds.
1741 */
1742 switch (pPage->enmKind)
1743 {
1744 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1745 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1746 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
1747 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1748 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
1749 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
1750 case PGMPOOLKIND_64BIT_PML4:
1751 case PGMPOOLKIND_32BIT_PD:
1752 case PGMPOOLKIND_PAE_PDPT:
1753 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
1754 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
1755 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
1756 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
1757 break;
1758
1759 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1760 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1761 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1762 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1763 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1764 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
1765 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
1766 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
1767 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
1768 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
1769 case PGMPOOLKIND_ROOT_NESTED:
1770 case PGMPOOLKIND_PAE_PD_PHYS:
1771 case PGMPOOLKIND_PAE_PDPT_PHYS:
1772 case PGMPOOLKIND_32BIT_PD_PHYS:
1773 /* Nothing to monitor here. */
1774 return VINF_SUCCESS;
1775
1776#ifdef PGMPOOL_WITH_MIXED_PT_CR3
1777 break;
1778#endif
1779 default:
1780 AssertFatalMsgFailed(("This can't happen! enmKind=%d\n", pPage->enmKind));
1781 }
1782
1783 /*
1784 * Remove the page from the monitored list or uninstall it if last.
1785 */
1786 const PVM pVM = pPool->CTX_SUFF(pVM);
1787 int rc;
1788 if ( pPage->iMonitoredNext != NIL_PGMPOOL_IDX
1789 || pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
1790 {
1791 if (pPage->iMonitoredPrev == NIL_PGMPOOL_IDX)
1792 {
1793 PPGMPOOLPAGE pNewHead = &pPool->aPages[pPage->iMonitoredNext];
1794 pNewHead->iMonitoredPrev = NIL_PGMPOOL_IDX;
1795 rc = PGMHandlerPhysicalChangeCallbacks(pVM, pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1),
1796 pPool->pfnAccessHandlerR3, MMHyperCCToR3(pVM, pNewHead),
1797 pPool->pfnAccessHandlerR0, MMHyperCCToR0(pVM, pNewHead),
1798 pPool->pfnAccessHandlerRC, MMHyperCCToRC(pVM, pNewHead),
1799 pPool->pszAccessHandler);
1800 AssertFatalRCSuccess(rc);
1801 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
1802 }
1803 else
1804 {
1805 pPool->aPages[pPage->iMonitoredPrev].iMonitoredNext = pPage->iMonitoredNext;
1806 if (pPage->iMonitoredNext != NIL_PGMPOOL_IDX)
1807 {
1808 pPool->aPages[pPage->iMonitoredNext].iMonitoredPrev = pPage->iMonitoredPrev;
1809 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
1810 }
1811 pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
1812 rc = VINF_SUCCESS;
1813 }
1814 }
1815 else
1816 {
1817 rc = PGMHandlerPhysicalDeregister(pVM, pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1));
1818 AssertFatalRC(rc);
1819 AssertMsg(!(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL) || VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3),
1820 ("%#x %#x\n", pVM->pgm.s.fSyncFlags, pVM->fForcedActions));
1821 }
1822 pPage->fMonitored = false;
1823
1824 /*
1825 * Remove it from the list of modified pages (if in it).
1826 */
1827 pgmPoolMonitorModifiedRemove(pPool, pPage);
1828
1829 return rc;
1830}
1831
1832
1833/**
1834 * Inserts the page into the list of modified pages.
1835 *
1836 * @param pPool The pool.
1837 * @param pPage The page.
1838 */
1839void pgmPoolMonitorModifiedInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1840{
1841 Log3(("pgmPoolMonitorModifiedInsert: idx=%d\n", pPage->idx));
1842 AssertMsg( pPage->iModifiedNext == NIL_PGMPOOL_IDX
1843 && pPage->iModifiedPrev == NIL_PGMPOOL_IDX
1844 && pPool->iModifiedHead != pPage->idx,
1845 ("Next=%d Prev=%d idx=%d cModifications=%d Head=%d cModifiedPages=%d\n",
1846 pPage->iModifiedNext, pPage->iModifiedPrev, pPage->idx, pPage->cModifications,
1847 pPool->iModifiedHead, pPool->cModifiedPages));
1848
1849 pPage->iModifiedNext = pPool->iModifiedHead;
1850 if (pPool->iModifiedHead != NIL_PGMPOOL_IDX)
1851 pPool->aPages[pPool->iModifiedHead].iModifiedPrev = pPage->idx;
1852 pPool->iModifiedHead = pPage->idx;
1853 pPool->cModifiedPages++;
1854#ifdef VBOX_WITH_STATISTICS
1855 if (pPool->cModifiedPages > pPool->cModifiedPagesHigh)
1856 pPool->cModifiedPagesHigh = pPool->cModifiedPages;
1857#endif
1858}
1859
1860
1861/**
1862 * Removes the page from the list of modified pages and resets the
1863 * moficiation counter.
1864 *
1865 * @param pPool The pool.
1866 * @param pPage The page which is believed to be in the list of modified pages.
1867 */
1868static void pgmPoolMonitorModifiedRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1869{
1870 Log3(("pgmPoolMonitorModifiedRemove: idx=%d cModifications=%d\n", pPage->idx, pPage->cModifications));
1871 if (pPool->iModifiedHead == pPage->idx)
1872 {
1873 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX);
1874 pPool->iModifiedHead = pPage->iModifiedNext;
1875 if (pPage->iModifiedNext != NIL_PGMPOOL_IDX)
1876 {
1877 pPool->aPages[pPage->iModifiedNext].iModifiedPrev = NIL_PGMPOOL_IDX;
1878 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1879 }
1880 pPool->cModifiedPages--;
1881 }
1882 else if (pPage->iModifiedPrev != NIL_PGMPOOL_IDX)
1883 {
1884 pPool->aPages[pPage->iModifiedPrev].iModifiedNext = pPage->iModifiedNext;
1885 if (pPage->iModifiedNext != NIL_PGMPOOL_IDX)
1886 {
1887 pPool->aPages[pPage->iModifiedNext].iModifiedPrev = pPage->iModifiedPrev;
1888 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1889 }
1890 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
1891 pPool->cModifiedPages--;
1892 }
1893 else
1894 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX);
1895 pPage->cModifications = 0;
1896}
1897
1898
1899/**
1900 * Zaps the list of modified pages, resetting their modification counters in the process.
1901 *
1902 * @param pVM The VM handle.
1903 */
1904void pgmPoolMonitorModifiedClearAll(PVM pVM)
1905{
1906 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1907 LogFlow(("pgmPoolMonitorModifiedClearAll: cModifiedPages=%d\n", pPool->cModifiedPages));
1908
1909 unsigned cPages = 0; NOREF(cPages);
1910 uint16_t idx = pPool->iModifiedHead;
1911 pPool->iModifiedHead = NIL_PGMPOOL_IDX;
1912 while (idx != NIL_PGMPOOL_IDX)
1913 {
1914 PPGMPOOLPAGE pPage = &pPool->aPages[idx];
1915 idx = pPage->iModifiedNext;
1916 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1917 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
1918 pPage->cModifications = 0;
1919 Assert(++cPages);
1920 }
1921 AssertMsg(cPages == pPool->cModifiedPages, ("%d != %d\n", cPages, pPool->cModifiedPages));
1922 pPool->cModifiedPages = 0;
1923}
1924
1925
1926#ifdef IN_RING3
1927/**
1928 * Clear all shadow pages and clear all modification counters.
1929 *
1930 * @param pVM The VM handle.
1931 * @remark Should only be used when monitoring is available, thus placed in
1932 * the PGMPOOL_WITH_MONITORING #ifdef.
1933 */
1934void pgmPoolClearAll(PVM pVM)
1935{
1936 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1937 STAM_PROFILE_START(&pPool->StatClearAll, c);
1938 LogFlow(("pgmPoolClearAll: cUsedPages=%d\n", pPool->cUsedPages));
1939
1940 /*
1941 * Iterate all the pages until we've encountered all that in use.
1942 * This is simple but not quite optimal solution.
1943 */
1944 unsigned cModifiedPages = 0; NOREF(cModifiedPages);
1945 unsigned cLeft = pPool->cUsedPages;
1946 unsigned iPage = pPool->cCurPages;
1947 while (--iPage >= PGMPOOL_IDX_FIRST)
1948 {
1949 PPGMPOOLPAGE pPage = &pPool->aPages[iPage];
1950 if (pPage->GCPhys != NIL_RTGCPHYS)
1951 {
1952 switch (pPage->enmKind)
1953 {
1954 /*
1955 * We only care about shadow page tables.
1956 */
1957 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1958 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1959 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1960 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1961 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1962 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1963 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1964 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1965 {
1966#ifdef PGMPOOL_WITH_USER_TRACKING
1967 if (pPage->cPresent)
1968#endif
1969 {
1970 void *pvShw = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
1971 STAM_PROFILE_START(&pPool->StatZeroPage, z);
1972 ASMMemZeroPage(pvShw);
1973 STAM_PROFILE_STOP(&pPool->StatZeroPage, z);
1974#ifdef PGMPOOL_WITH_USER_TRACKING
1975 pPage->cPresent = 0;
1976 pPage->iFirstPresent = ~0;
1977#endif
1978 }
1979 }
1980 /* fall thru */
1981
1982 default:
1983 Assert(!pPage->cModifications || ++cModifiedPages);
1984 Assert(pPage->iModifiedNext == NIL_PGMPOOL_IDX || pPage->cModifications);
1985 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX || pPage->cModifications);
1986 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1987 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
1988 pPage->cModifications = 0;
1989 break;
1990
1991 }
1992 if (!--cLeft)
1993 break;
1994 }
1995 }
1996
1997 /* swipe the special pages too. */
1998 for (iPage = PGMPOOL_IDX_FIRST_SPECIAL; iPage < PGMPOOL_IDX_FIRST; iPage++)
1999 {
2000 PPGMPOOLPAGE pPage = &pPool->aPages[iPage];
2001 if (pPage->GCPhys != NIL_RTGCPHYS)
2002 {
2003 Assert(!pPage->cModifications || ++cModifiedPages);
2004 Assert(pPage->iModifiedNext == NIL_PGMPOOL_IDX || pPage->cModifications);
2005 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX || pPage->cModifications);
2006 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
2007 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
2008 pPage->cModifications = 0;
2009 }
2010 }
2011
2012#ifndef DEBUG_michael
2013 AssertMsg(cModifiedPages == pPool->cModifiedPages, ("%d != %d\n", cModifiedPages, pPool->cModifiedPages));
2014#endif
2015 pPool->iModifiedHead = NIL_PGMPOOL_IDX;
2016 pPool->cModifiedPages = 0;
2017
2018#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
2019 /*
2020 * Clear all the GCPhys links and rebuild the phys ext free list.
2021 */
2022 for (PPGMRAMRANGE pRam = pPool->CTX_SUFF(pVM)->pgm.s.CTX_SUFF(pRamRanges);
2023 pRam;
2024 pRam = pRam->CTX_SUFF(pNext))
2025 {
2026 unsigned iPage = pRam->cb >> PAGE_SHIFT;
2027 while (iPage-- > 0)
2028 PGM_PAGE_SET_TRACKING(&pRam->aPages[iPage], 0);
2029 }
2030
2031 pPool->iPhysExtFreeHead = 0;
2032 PPGMPOOLPHYSEXT paPhysExts = pPool->CTX_SUFF(paPhysExts);
2033 const unsigned cMaxPhysExts = pPool->cMaxPhysExts;
2034 for (unsigned i = 0; i < cMaxPhysExts; i++)
2035 {
2036 paPhysExts[i].iNext = i + 1;
2037 paPhysExts[i].aidx[0] = NIL_PGMPOOL_IDX;
2038 paPhysExts[i].aidx[1] = NIL_PGMPOOL_IDX;
2039 paPhysExts[i].aidx[2] = NIL_PGMPOOL_IDX;
2040 }
2041 paPhysExts[cMaxPhysExts - 1].iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
2042#endif
2043
2044
2045 pPool->cPresent = 0;
2046 STAM_PROFILE_STOP(&pPool->StatClearAll, c);
2047}
2048#endif /* IN_RING3 */
2049
2050
2051/**
2052 * Handle SyncCR3 pool tasks
2053 *
2054 * @returns VBox status code.
2055 * @retval VINF_SUCCESS if successfully added.
2056 * @retval VINF_PGM_SYNC_CR3 is it needs to be deferred to ring 3 (GC only)
2057 * @param pVM The VM handle.
2058 * @remark Should only be used when monitoring is available, thus placed in
2059 * the PGMPOOL_WITH_MONITORING #ifdef.
2060 */
2061int pgmPoolSyncCR3(PVM pVM)
2062{
2063 LogFlow(("pgmPoolSyncCR3\n"));
2064 /*
2065 * When monitoring shadowed pages, we reset the modification counters on CR3 sync.
2066 * Occasionally we will have to clear all the shadow page tables because we wanted
2067 * to monitor a page which was mapped by too many shadowed page tables. This operation
2068 * sometimes refered to as a 'lightweight flush'.
2069 */
2070 if (!(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL))
2071 pgmPoolMonitorModifiedClearAll(pVM);
2072 else
2073 {
2074# ifdef IN_RING3 /* Don't flush in ring-0 or raw mode, it's taking too long. */
2075 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_CLEAR_PGM_POOL;
2076 pgmPoolClearAll(pVM);
2077# else /* !IN_RING3 */
2078 LogFlow(("SyncCR3: PGM_SYNC_CLEAR_PGM_POOL is set -> VINF_PGM_SYNC_CR3\n"));
2079 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3); /** @todo no need to do global sync, right? */
2080 return VINF_PGM_SYNC_CR3;
2081# endif /* !IN_RING3 */
2082 }
2083 return VINF_SUCCESS;
2084}
2085
2086#endif /* PGMPOOL_WITH_MONITORING */
2087#ifdef PGMPOOL_WITH_USER_TRACKING
2088
2089/**
2090 * Frees up at least one user entry.
2091 *
2092 * @returns VBox status code.
2093 * @retval VINF_SUCCESS if successfully added.
2094 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
2095 * @param pPool The pool.
2096 * @param iUser The user index.
2097 */
2098static int pgmPoolTrackFreeOneUser(PPGMPOOL pPool, uint16_t iUser)
2099{
2100 STAM_COUNTER_INC(&pPool->StatTrackFreeUpOneUser);
2101#ifdef PGMPOOL_WITH_CACHE
2102 /*
2103 * Just free cached pages in a braindead fashion.
2104 */
2105 /** @todo walk the age list backwards and free the first with usage. */
2106 int rc = VINF_SUCCESS;
2107 do
2108 {
2109 int rc2 = pgmPoolCacheFreeOne(pPool, iUser);
2110 if (RT_FAILURE(rc2) && rc == VINF_SUCCESS)
2111 rc = rc2;
2112 } while (pPool->iUserFreeHead == NIL_PGMPOOL_USER_INDEX);
2113 return rc;
2114#else
2115 /*
2116 * Lazy approach.
2117 */
2118 /* @todo This path no longer works (CR3 root pages will be flushed)!! */
2119 AssertCompileFailed();
2120 Assert(!CPUMIsGuestInLongMode(pVM));
2121 pgmPoolFlushAllInt(pPool);
2122 return VERR_PGM_POOL_FLUSHED;
2123#endif
2124}
2125
2126
2127/**
2128 * Inserts a page into the cache.
2129 *
2130 * This will create user node for the page, insert it into the GCPhys
2131 * hash, and insert it into the age list.
2132 *
2133 * @returns VBox status code.
2134 * @retval VINF_SUCCESS if successfully added.
2135 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
2136 * @param pPool The pool.
2137 * @param pPage The cached page.
2138 * @param GCPhys The GC physical address of the page we're gonna shadow.
2139 * @param iUser The user index.
2140 * @param iUserTable The user table index.
2141 */
2142DECLINLINE(int) pgmPoolTrackInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTGCPHYS GCPhys, uint16_t iUser, uint32_t iUserTable)
2143{
2144 int rc = VINF_SUCCESS;
2145 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
2146
2147 LogFlow(("pgmPoolTrackInsert GCPhys=%RGp iUser %x iUserTable %x\n", GCPhys, iUser, iUserTable));
2148
2149#ifdef VBOX_STRICT
2150 /*
2151 * Check that the entry doesn't already exists.
2152 */
2153 if (pPage->iUserHead != NIL_PGMPOOL_USER_INDEX)
2154 {
2155 uint16_t i = pPage->iUserHead;
2156 do
2157 {
2158 Assert(i < pPool->cMaxUsers);
2159 AssertMsg(paUsers[i].iUser != iUser || paUsers[i].iUserTable != iUserTable, ("%x %x vs new %x %x\n", paUsers[i].iUser, paUsers[i].iUserTable, iUser, iUserTable));
2160 i = paUsers[i].iNext;
2161 } while (i != NIL_PGMPOOL_USER_INDEX);
2162 }
2163#endif
2164
2165 /*
2166 * Find free a user node.
2167 */
2168 uint16_t i = pPool->iUserFreeHead;
2169 if (i == NIL_PGMPOOL_USER_INDEX)
2170 {
2171 int rc = pgmPoolTrackFreeOneUser(pPool, iUser);
2172 if (RT_FAILURE(rc))
2173 return rc;
2174 i = pPool->iUserFreeHead;
2175 }
2176
2177 /*
2178 * Unlink the user node from the free list,
2179 * initialize and insert it into the user list.
2180 */
2181 pPool->iUserFreeHead = paUsers[i].iNext;
2182 paUsers[i].iNext = NIL_PGMPOOL_USER_INDEX;
2183 paUsers[i].iUser = iUser;
2184 paUsers[i].iUserTable = iUserTable;
2185 pPage->iUserHead = i;
2186
2187 /*
2188 * Insert into cache and enable monitoring of the guest page if enabled.
2189 *
2190 * Until we implement caching of all levels, including the CR3 one, we'll
2191 * have to make sure we don't try monitor & cache any recursive reuse of
2192 * a monitored CR3 page. Because all windows versions are doing this we'll
2193 * have to be able to do combined access monitoring, CR3 + PT and
2194 * PD + PT (guest PAE).
2195 *
2196 * Update:
2197 * We're now cooperating with the CR3 monitor if an uncachable page is found.
2198 */
2199#if defined(PGMPOOL_WITH_MONITORING) || defined(PGMPOOL_WITH_CACHE)
2200# ifdef PGMPOOL_WITH_MIXED_PT_CR3
2201 const bool fCanBeMonitored = true;
2202# else
2203 bool fCanBeMonitored = pPool->CTX_SUFF(pVM)->pgm.s.GCPhysGstCR3Monitored == NIL_RTGCPHYS
2204 || (GCPhys & X86_PTE_PAE_PG_MASK) != (pPool->CTX_SUFF(pVM)->pgm.s.GCPhysGstCR3Monitored & X86_PTE_PAE_PG_MASK)
2205 || pgmPoolIsBigPage((PGMPOOLKIND)pPage->enmKind);
2206# endif
2207# ifdef PGMPOOL_WITH_CACHE
2208 pgmPoolCacheInsert(pPool, pPage, fCanBeMonitored); /* This can be expanded. */
2209# endif
2210 if (fCanBeMonitored)
2211 {
2212# ifdef PGMPOOL_WITH_MONITORING
2213 rc = pgmPoolMonitorInsert(pPool, pPage);
2214 AssertRC(rc);
2215 }
2216# endif
2217#endif /* PGMPOOL_WITH_MONITORING */
2218 return rc;
2219}
2220
2221
2222# ifdef PGMPOOL_WITH_CACHE /* (only used when the cache is enabled.) */
2223/**
2224 * Adds a user reference to a page.
2225 *
2226 * This will move the page to the head of the
2227 *
2228 * @returns VBox status code.
2229 * @retval VINF_SUCCESS if successfully added.
2230 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
2231 * @param pPool The pool.
2232 * @param pPage The cached page.
2233 * @param iUser The user index.
2234 * @param iUserTable The user table.
2235 */
2236static int pgmPoolTrackAddUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable)
2237{
2238 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
2239
2240 Log3(("pgmPoolTrackAddUser GCPhys = %RGp iUser %x iUserTable %x\n", pPage->GCPhys, iUser, iUserTable));
2241# ifdef VBOX_STRICT
2242 /*
2243 * Check that the entry doesn't already exists.
2244 */
2245 if (pPage->iUserHead != NIL_PGMPOOL_USER_INDEX)
2246 {
2247 uint16_t i = pPage->iUserHead;
2248 do
2249 {
2250 Assert(i < pPool->cMaxUsers);
2251 AssertMsg(paUsers[i].iUser != iUser || paUsers[i].iUserTable != iUserTable, ("%x %x vs new %x %x\n", paUsers[i].iUser, paUsers[i].iUserTable, iUser, iUserTable));
2252 i = paUsers[i].iNext;
2253 } while (i != NIL_PGMPOOL_USER_INDEX);
2254 }
2255# endif
2256
2257 /*
2258 * Allocate a user node.
2259 */
2260 uint16_t i = pPool->iUserFreeHead;
2261 if (i == NIL_PGMPOOL_USER_INDEX)
2262 {
2263 int rc = pgmPoolTrackFreeOneUser(pPool, iUser);
2264 if (RT_FAILURE(rc))
2265 return rc;
2266 i = pPool->iUserFreeHead;
2267 }
2268 pPool->iUserFreeHead = paUsers[i].iNext;
2269
2270 /*
2271 * Initialize the user node and insert it.
2272 */
2273 paUsers[i].iNext = pPage->iUserHead;
2274 paUsers[i].iUser = iUser;
2275 paUsers[i].iUserTable = iUserTable;
2276 pPage->iUserHead = i;
2277
2278# ifdef PGMPOOL_WITH_CACHE
2279 /*
2280 * Tell the cache to update its replacement stats for this page.
2281 */
2282 pgmPoolCacheUsed(pPool, pPage);
2283# endif
2284 return VINF_SUCCESS;
2285}
2286# endif /* PGMPOOL_WITH_CACHE */
2287
2288
2289/**
2290 * Frees a user record associated with a page.
2291 *
2292 * This does not clear the entry in the user table, it simply replaces the
2293 * user record to the chain of free records.
2294 *
2295 * @param pPool The pool.
2296 * @param HCPhys The HC physical address of the shadow page.
2297 * @param iUser The shadow page pool index of the user table.
2298 * @param iUserTable The index into the user table (shadowed).
2299 */
2300static void pgmPoolTrackFreeUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable)
2301{
2302 /*
2303 * Unlink and free the specified user entry.
2304 */
2305 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
2306
2307 Log3(("pgmPoolTrackFreeUser %RGp %x %x\n", pPage->GCPhys, iUser, iUserTable));
2308 /* Special: For PAE and 32-bit paging, there is usually no more than one user. */
2309 uint16_t i = pPage->iUserHead;
2310 if ( i != NIL_PGMPOOL_USER_INDEX
2311 && paUsers[i].iUser == iUser
2312 && paUsers[i].iUserTable == iUserTable)
2313 {
2314 pPage->iUserHead = paUsers[i].iNext;
2315
2316 paUsers[i].iUser = NIL_PGMPOOL_IDX;
2317 paUsers[i].iNext = pPool->iUserFreeHead;
2318 pPool->iUserFreeHead = i;
2319 return;
2320 }
2321
2322 /* General: Linear search. */
2323 uint16_t iPrev = NIL_PGMPOOL_USER_INDEX;
2324 while (i != NIL_PGMPOOL_USER_INDEX)
2325 {
2326 if ( paUsers[i].iUser == iUser
2327 && paUsers[i].iUserTable == iUserTable)
2328 {
2329 if (iPrev != NIL_PGMPOOL_USER_INDEX)
2330 paUsers[iPrev].iNext = paUsers[i].iNext;
2331 else
2332 pPage->iUserHead = paUsers[i].iNext;
2333
2334 paUsers[i].iUser = NIL_PGMPOOL_IDX;
2335 paUsers[i].iNext = pPool->iUserFreeHead;
2336 pPool->iUserFreeHead = i;
2337 return;
2338 }
2339 iPrev = i;
2340 i = paUsers[i].iNext;
2341 }
2342
2343 /* Fatal: didn't find it */
2344 AssertFatalMsgFailed(("Didn't find the user entry! iUser=%#x iUserTable=%#x GCPhys=%RGp\n",
2345 iUser, iUserTable, pPage->GCPhys));
2346}
2347
2348
2349/**
2350 * Gets the entry size of a shadow table.
2351 *
2352 * @param enmKind The kind of page.
2353 *
2354 * @returns The size of the entry in bytes. That is, 4 or 8.
2355 * @returns If the kind is not for a table, an assertion is raised and 0 is
2356 * returned.
2357 */
2358DECLINLINE(unsigned) pgmPoolTrackGetShadowEntrySize(PGMPOOLKIND enmKind)
2359{
2360 switch (enmKind)
2361 {
2362 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2363 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2364 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2365 case PGMPOOLKIND_32BIT_PD:
2366 case PGMPOOLKIND_32BIT_PD_PHYS:
2367 return 4;
2368
2369 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2370 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2371 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2372 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2373 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2374 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2375 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2376 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2377 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2378 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2379 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2380 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2381 case PGMPOOLKIND_64BIT_PML4:
2382 case PGMPOOLKIND_PAE_PDPT:
2383 case PGMPOOLKIND_ROOT_NESTED:
2384 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2385 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2386 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2387 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2388 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2389 case PGMPOOLKIND_PAE_PD_PHYS:
2390 case PGMPOOLKIND_PAE_PDPT_PHYS:
2391 return 8;
2392
2393 default:
2394 AssertFatalMsgFailed(("enmKind=%d\n", enmKind));
2395 }
2396}
2397
2398
2399/**
2400 * Gets the entry size of a guest table.
2401 *
2402 * @param enmKind The kind of page.
2403 *
2404 * @returns The size of the entry in bytes. That is, 0, 4 or 8.
2405 * @returns If the kind is not for a table, an assertion is raised and 0 is
2406 * returned.
2407 */
2408DECLINLINE(unsigned) pgmPoolTrackGetGuestEntrySize(PGMPOOLKIND enmKind)
2409{
2410 switch (enmKind)
2411 {
2412 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2413 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2414 case PGMPOOLKIND_32BIT_PD:
2415 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2416 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2417 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2418 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2419 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2420 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2421 return 4;
2422
2423 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2424 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2425 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2426 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2427 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2428 case PGMPOOLKIND_64BIT_PML4:
2429 case PGMPOOLKIND_PAE_PDPT:
2430 return 8;
2431
2432 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2433 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2434 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2435 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2436 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2437 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2438 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2439 case PGMPOOLKIND_ROOT_NESTED:
2440 case PGMPOOLKIND_PAE_PD_PHYS:
2441 case PGMPOOLKIND_PAE_PDPT_PHYS:
2442 case PGMPOOLKIND_32BIT_PD_PHYS:
2443 /** @todo can we return 0? (nobody is calling this...) */
2444 AssertFailed();
2445 return 0;
2446
2447 default:
2448 AssertFatalMsgFailed(("enmKind=%d\n", enmKind));
2449 }
2450}
2451
2452#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
2453
2454/**
2455 * Scans one shadow page table for mappings of a physical page.
2456 *
2457 * @param pVM The VM handle.
2458 * @param pPhysPage The guest page in question.
2459 * @param iShw The shadow page table.
2460 * @param cRefs The number of references made in that PT.
2461 */
2462static void pgmPoolTrackFlushGCPhysPTInt(PVM pVM, PCPGMPAGE pPhysPage, uint16_t iShw, uint16_t cRefs)
2463{
2464 LogFlow(("pgmPoolTrackFlushGCPhysPT: pPhysPage=%R[pgmpage] iShw=%d cRefs=%d\n", pPhysPage, iShw, cRefs));
2465 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2466
2467 /*
2468 * Assert sanity.
2469 */
2470 Assert(cRefs == 1);
2471 AssertFatalMsg(iShw < pPool->cCurPages && iShw != NIL_PGMPOOL_IDX, ("iShw=%d\n", iShw));
2472 PPGMPOOLPAGE pPage = &pPool->aPages[iShw];
2473
2474 /*
2475 * Then, clear the actual mappings to the page in the shadow PT.
2476 */
2477 switch (pPage->enmKind)
2478 {
2479 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2480 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2481 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2482 {
2483 const uint32_t u32 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
2484 PX86PT pPT = (PX86PT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2485 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
2486 if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
2487 {
2488 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX32 cRefs=%#x\n", i, pPT->a[i], cRefs));
2489 pPT->a[i].u = 0;
2490 cRefs--;
2491 if (!cRefs)
2492 return;
2493 }
2494#ifdef LOG_ENABLED
2495 RTLogPrintf("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent);
2496 for (unsigned i = 0; i < RT_ELEMENTS(pPT->a); i++)
2497 if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
2498 {
2499 RTLogPrintf("i=%d cRefs=%d\n", i, cRefs--);
2500 pPT->a[i].u = 0;
2501 }
2502#endif
2503 AssertFatalMsgFailed(("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent));
2504 break;
2505 }
2506
2507 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2508 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2509 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2510 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2511 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2512 {
2513 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
2514 PX86PTPAE pPT = (PX86PTPAE)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2515 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
2516 if ((pPT->a[i].u & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
2517 {
2518 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX64 cRefs=%#x\n", i, pPT->a[i], cRefs));
2519 pPT->a[i].u = 0;
2520 cRefs--;
2521 if (!cRefs)
2522 return;
2523 }
2524#ifdef LOG_ENABLED
2525 RTLogPrintf("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent);
2526 for (unsigned i = 0; i < RT_ELEMENTS(pPT->a); i++)
2527 if ((pPT->a[i].u & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
2528 {
2529 RTLogPrintf("i=%d cRefs=%d\n", i, cRefs--);
2530 pPT->a[i].u = 0;
2531 }
2532#endif
2533 AssertFatalMsgFailed(("cRefs=%d iFirstPresent=%d cPresent=%d u64=%RX64\n", cRefs, pPage->iFirstPresent, pPage->cPresent, u64));
2534 break;
2535 }
2536
2537 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2538 {
2539 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
2540 PEPTPT pPT = (PEPTPT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2541 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
2542 if ((pPT->a[i].u & (EPT_PTE_PG_MASK | X86_PTE_P)) == u64)
2543 {
2544 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX64 cRefs=%#x\n", i, pPT->a[i], cRefs));
2545 pPT->a[i].u = 0;
2546 cRefs--;
2547 if (!cRefs)
2548 return;
2549 }
2550#ifdef LOG_ENABLED
2551 RTLogPrintf("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent);
2552 for (unsigned i = 0; i < RT_ELEMENTS(pPT->a); i++)
2553 if ((pPT->a[i].u & (EPT_PTE_PG_MASK | X86_PTE_P)) == u64)
2554 {
2555 RTLogPrintf("i=%d cRefs=%d\n", i, cRefs--);
2556 pPT->a[i].u = 0;
2557 }
2558#endif
2559 AssertFatalMsgFailed(("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent));
2560 break;
2561 }
2562
2563 default:
2564 AssertFatalMsgFailed(("enmKind=%d iShw=%d\n", pPage->enmKind, iShw));
2565 }
2566}
2567
2568
2569/**
2570 * Scans one shadow page table for mappings of a physical page.
2571 *
2572 * @param pVM The VM handle.
2573 * @param pPhysPage The guest page in question.
2574 * @param iShw The shadow page table.
2575 * @param cRefs The number of references made in that PT.
2576 */
2577void pgmPoolTrackFlushGCPhysPT(PVM pVM, PPGMPAGE pPhysPage, uint16_t iShw, uint16_t cRefs)
2578{
2579 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool); NOREF(pPool);
2580 LogFlow(("pgmPoolTrackFlushGCPhysPT: pPhysPage=%R[pgmpage] iShw=%d cRefs=%d\n", pPhysPage, iShw, cRefs));
2581 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPT, f);
2582 pgmPoolTrackFlushGCPhysPTInt(pVM, pPhysPage, iShw, cRefs);
2583 PGM_PAGE_SET_TRACKING(pPhysPage, 0);
2584 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPT, f);
2585}
2586
2587
2588/**
2589 * Flushes a list of shadow page tables mapping the same physical page.
2590 *
2591 * @param pVM The VM handle.
2592 * @param pPhysPage The guest page in question.
2593 * @param iPhysExt The physical cross reference extent list to flush.
2594 */
2595void pgmPoolTrackFlushGCPhysPTs(PVM pVM, PPGMPAGE pPhysPage, uint16_t iPhysExt)
2596{
2597 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2598 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPTs, f);
2599 LogFlow(("pgmPoolTrackFlushGCPhysPTs: pPhysPage=%R[pgmpage] iPhysExt\n", pPhysPage, iPhysExt));
2600
2601 const uint16_t iPhysExtStart = iPhysExt;
2602 PPGMPOOLPHYSEXT pPhysExt;
2603 do
2604 {
2605 Assert(iPhysExt < pPool->cMaxPhysExts);
2606 pPhysExt = &pPool->CTX_SUFF(paPhysExts)[iPhysExt];
2607 for (unsigned i = 0; i < RT_ELEMENTS(pPhysExt->aidx); i++)
2608 if (pPhysExt->aidx[i] != NIL_PGMPOOL_IDX)
2609 {
2610 pgmPoolTrackFlushGCPhysPTInt(pVM, pPhysPage, pPhysExt->aidx[i], 1);
2611 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
2612 }
2613
2614 /* next */
2615 iPhysExt = pPhysExt->iNext;
2616 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
2617
2618 /* insert the list into the free list and clear the ram range entry. */
2619 pPhysExt->iNext = pPool->iPhysExtFreeHead;
2620 pPool->iPhysExtFreeHead = iPhysExtStart;
2621 PGM_PAGE_SET_TRACKING(pPhysPage, 0);
2622
2623 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTs, f);
2624}
2625
2626#endif /* PGMPOOL_WITH_GCPHYS_TRACKING */
2627
2628/**
2629 * Flushes all shadow page table mappings of the given guest page.
2630 *
2631 * This is typically called when the host page backing the guest one has been
2632 * replaced or when the page protection was changed due to an access handler.
2633 *
2634 * @returns VBox status code.
2635 * @retval VINF_SUCCESS if all references has been successfully cleared.
2636 * @retval VINF_PGM_SYNC_CR3 if we're better off with a CR3 sync and a page
2637 * pool cleaning. FF and sync flags are set.
2638 *
2639 * @param pVM The VM handle.
2640 * @param pPhysPage The guest page in question.
2641 * @param pfFlushTLBs This is set to @a true if the shadow TLBs should be
2642 * flushed, it is NOT touched if this isn't necessary.
2643 * The caller MUST initialized this to @a false.
2644 */
2645int pgmPoolTrackFlushGCPhys(PVM pVM, PPGMPAGE pPhysPage, bool *pfFlushTLBs)
2646{
2647 int rc = VINF_SUCCESS;
2648#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
2649 const uint16_t u16 = PGM_PAGE_GET_TRACKING(pPhysPage);
2650 if (u16)
2651 {
2652 /*
2653 * The zero page is currently screwing up the tracking and we'll
2654 * have to flush the whole shebang. Unless VBOX_WITH_NEW_LAZY_PAGE_ALLOC
2655 * is defined, zero pages won't normally be mapped. Some kind of solution
2656 * will be needed for this problem of course, but it will have to wait...
2657 */
2658 if (PGM_PAGE_IS_ZERO(pPhysPage))
2659 rc = VINF_PGM_GCPHYS_ALIASED;
2660 else
2661 {
2662# ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2663 /* Start a subset here because pgmPoolTrackFlushGCPhysPTsSlow and
2664 pgmPoolTrackFlushGCPhysPTs will/may kill the pool otherwise. */
2665 PVMCPU pVCpu = VMMGetCpu(pVM);
2666 uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
2667# endif
2668
2669 if (PGMPOOL_TD_GET_CREFS(u16) != PGMPOOL_TD_CREFS_PHYSEXT)
2670 pgmPoolTrackFlushGCPhysPT(pVM,
2671 pPhysPage,
2672 PGMPOOL_TD_GET_IDX(u16),
2673 PGMPOOL_TD_GET_CREFS(u16));
2674 else if (u16 != PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED))
2675 pgmPoolTrackFlushGCPhysPTs(pVM, pPhysPage, PGMPOOL_TD_GET_IDX(u16));
2676 else
2677 rc = pgmPoolTrackFlushGCPhysPTsSlow(pVM, pPhysPage);
2678 *pfFlushTLBs = true;
2679
2680# ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2681 PGMDynMapPopAutoSubset(pVCpu, iPrevSubset);
2682# endif
2683 }
2684 }
2685
2686#elif defined(PGMPOOL_WITH_CACHE)
2687 if (PGM_PAGE_IS_ZERO(pPhysPage))
2688 rc = VINF_PGM_GCPHYS_ALIASED;
2689 else
2690 {
2691# ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2692 /* Start a subset here because pgmPoolTrackFlushGCPhysPTsSlow kill the pool otherwise. */
2693 PVMCPU pVCpu = VMMGetCpu(pVM);
2694 uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
2695# endif
2696 rc = pgmPoolTrackFlushGCPhysPTsSlow(pVM, pPhysPage);
2697 if (rc == VINF_SUCCESS)
2698 *pfFlushTLBs = true;
2699 }
2700
2701# ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2702 PGMDynMapPopAutoSubset(pVCpu, iPrevSubset);
2703# endif
2704
2705#else
2706 rc = VINF_PGM_GCPHYS_ALIASED;
2707#endif
2708
2709 if (rc == VINF_PGM_GCPHYS_ALIASED)
2710 {
2711 pVM->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2712 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
2713 rc = VINF_PGM_SYNC_CR3;
2714 }
2715
2716 return rc;
2717}
2718
2719
2720/**
2721 * Scans all shadow page tables for mappings of a physical page.
2722 *
2723 * This may be slow, but it's most likely more efficient than cleaning
2724 * out the entire page pool / cache.
2725 *
2726 * @returns VBox status code.
2727 * @retval VINF_SUCCESS if all references has been successfully cleared.
2728 * @retval VINF_PGM_GCPHYS_ALIASED if we're better off with a CR3 sync and
2729 * a page pool cleaning.
2730 *
2731 * @param pVM The VM handle.
2732 * @param pPhysPage The guest page in question.
2733 */
2734int pgmPoolTrackFlushGCPhysPTsSlow(PVM pVM, PPGMPAGE pPhysPage)
2735{
2736 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2737 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPTsSlow, s);
2738 LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: cUsedPages=%d cPresent=%d pPhysPage=%R[pgmpage]\n",
2739 pPool->cUsedPages, pPool->cPresent, pPhysPage));
2740
2741#if 1
2742 /*
2743 * There is a limit to what makes sense.
2744 */
2745 if (pPool->cPresent > 1024)
2746 {
2747 LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: giving up... (cPresent=%d)\n", pPool->cPresent));
2748 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTsSlow, s);
2749 return VINF_PGM_GCPHYS_ALIASED;
2750 }
2751#endif
2752
2753 /*
2754 * Iterate all the pages until we've encountered all that in use.
2755 * This is simple but not quite optimal solution.
2756 */
2757 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
2758 const uint32_t u32 = u64;
2759 unsigned cLeft = pPool->cUsedPages;
2760 unsigned iPage = pPool->cCurPages;
2761 while (--iPage >= PGMPOOL_IDX_FIRST)
2762 {
2763 PPGMPOOLPAGE pPage = &pPool->aPages[iPage];
2764 if (pPage->GCPhys != NIL_RTGCPHYS)
2765 {
2766 switch (pPage->enmKind)
2767 {
2768 /*
2769 * We only care about shadow page tables.
2770 */
2771 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2772 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2773 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2774 {
2775 unsigned cPresent = pPage->cPresent;
2776 PX86PT pPT = (PX86PT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2777 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
2778 if (pPT->a[i].n.u1Present)
2779 {
2780 if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
2781 {
2782 //Log4(("pgmPoolTrackFlushGCPhysPTsSlow: idx=%d i=%d pte=%RX32\n", iPage, i, pPT->a[i]));
2783 pPT->a[i].u = 0;
2784 }
2785 if (!--cPresent)
2786 break;
2787 }
2788 break;
2789 }
2790
2791 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2792 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2793 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2794 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2795 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2796 {
2797 unsigned cPresent = pPage->cPresent;
2798 PX86PTPAE pPT = (PX86PTPAE)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2799 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
2800 if (pPT->a[i].n.u1Present)
2801 {
2802 if ((pPT->a[i].u & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
2803 {
2804 //Log4(("pgmPoolTrackFlushGCPhysPTsSlow: idx=%d i=%d pte=%RX64\n", iPage, i, pPT->a[i]));
2805 pPT->a[i].u = 0;
2806 }
2807 if (!--cPresent)
2808 break;
2809 }
2810 break;
2811 }
2812 }
2813 if (!--cLeft)
2814 break;
2815 }
2816 }
2817
2818 PGM_PAGE_SET_TRACKING(pPhysPage, 0);
2819 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTsSlow, s);
2820 return VINF_SUCCESS;
2821}
2822
2823
2824/**
2825 * Clears the user entry in a user table.
2826 *
2827 * This is used to remove all references to a page when flushing it.
2828 */
2829static void pgmPoolTrackClearPageUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PCPGMPOOLUSER pUser)
2830{
2831 Assert(pUser->iUser != NIL_PGMPOOL_IDX);
2832 Assert(pUser->iUser < pPool->cCurPages);
2833 uint32_t iUserTable = pUser->iUserTable;
2834
2835 /*
2836 * Map the user page.
2837 */
2838 PPGMPOOLPAGE pUserPage = &pPool->aPages[pUser->iUser];
2839 union
2840 {
2841 uint64_t *pau64;
2842 uint32_t *pau32;
2843 } u;
2844 u.pau64 = (uint64_t *)PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pUserPage);
2845
2846 LogFlow(("pgmPoolTrackClearPageUser: clear %x in %s (%RGp) (flushing %s)\n", iUserTable, pgmPoolPoolKindToStr(pUserPage->enmKind), pUserPage->Core.Key, pgmPoolPoolKindToStr(pPage->enmKind)));
2847
2848 /* Safety precaution in case we change the paging for other modes too in the future. */
2849 Assert(!pgmPoolIsPageLocked(&pPool->CTX_SUFF(pVM)->pgm.s, pPage));
2850
2851#ifdef VBOX_STRICT
2852 /*
2853 * Some sanity checks.
2854 */
2855 switch (pUserPage->enmKind)
2856 {
2857 case PGMPOOLKIND_32BIT_PD:
2858 case PGMPOOLKIND_32BIT_PD_PHYS:
2859 Assert(iUserTable < X86_PG_ENTRIES);
2860 break;
2861 case PGMPOOLKIND_PAE_PDPT:
2862 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
2863 case PGMPOOLKIND_PAE_PDPT_PHYS:
2864 Assert(iUserTable < 4);
2865 Assert(!(u.pau64[iUserTable] & PGM_PLXFLAGS_PERMANENT));
2866 break;
2867 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2868 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2869 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2870 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2871 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2872 case PGMPOOLKIND_PAE_PD_PHYS:
2873 Assert(iUserTable < X86_PG_PAE_ENTRIES);
2874 break;
2875 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2876 Assert(iUserTable < X86_PG_PAE_ENTRIES);
2877 Assert(!(u.pau64[iUserTable] & PGM_PDFLAGS_MAPPING));
2878 break;
2879 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2880 Assert(iUserTable < X86_PG_PAE_ENTRIES);
2881 Assert(!(u.pau64[iUserTable] & PGM_PLXFLAGS_PERMANENT));
2882 break;
2883 case PGMPOOLKIND_64BIT_PML4:
2884 Assert(!(u.pau64[iUserTable] & PGM_PLXFLAGS_PERMANENT));
2885 /* GCPhys >> PAGE_SHIFT is the index here */
2886 break;
2887 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2888 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2889 Assert(iUserTable < X86_PG_PAE_ENTRIES);
2890 break;
2891
2892 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2893 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2894 Assert(iUserTable < X86_PG_PAE_ENTRIES);
2895 break;
2896
2897 case PGMPOOLKIND_ROOT_NESTED:
2898 Assert(iUserTable < X86_PG_PAE_ENTRIES);
2899 break;
2900
2901 default:
2902 AssertMsgFailed(("enmKind=%d\n", pUserPage->enmKind));
2903 break;
2904 }
2905#endif /* VBOX_STRICT */
2906
2907 /*
2908 * Clear the entry in the user page.
2909 */
2910 switch (pUserPage->enmKind)
2911 {
2912 /* 32-bit entries */
2913 case PGMPOOLKIND_32BIT_PD:
2914 case PGMPOOLKIND_32BIT_PD_PHYS:
2915 u.pau32[iUserTable] = 0;
2916 break;
2917
2918 /* 64-bit entries */
2919 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2920 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2921 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2922 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2923 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2924#if defined(IN_RC)
2925 /* In 32 bits PAE mode we *must* invalidate the TLB when changing a PDPT entry; the CPU fetches them only during cr3 load, so any
2926 * non-present PDPT will continue to cause page faults.
2927 */
2928 ASMReloadCR3();
2929#endif
2930 /* no break */
2931 case PGMPOOLKIND_PAE_PD_PHYS:
2932 case PGMPOOLKIND_PAE_PDPT_PHYS:
2933 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2934 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2935 case PGMPOOLKIND_64BIT_PML4:
2936 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2937 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2938 case PGMPOOLKIND_PAE_PDPT:
2939 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
2940 case PGMPOOLKIND_ROOT_NESTED:
2941 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2942 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2943 u.pau64[iUserTable] = 0;
2944 break;
2945
2946 default:
2947 AssertFatalMsgFailed(("enmKind=%d iUser=%#x iUserTable=%#x\n", pUserPage->enmKind, pUser->iUser, pUser->iUserTable));
2948 }
2949}
2950
2951
2952/**
2953 * Clears all users of a page.
2954 */
2955static void pgmPoolTrackClearPageUsers(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2956{
2957 /*
2958 * Free all the user records.
2959 */
2960 LogFlow(("pgmPoolTrackClearPageUsers %RGp\n", pPage->GCPhys));
2961
2962 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
2963 uint16_t i = pPage->iUserHead;
2964 while (i != NIL_PGMPOOL_USER_INDEX)
2965 {
2966 /* Clear enter in user table. */
2967 pgmPoolTrackClearPageUser(pPool, pPage, &paUsers[i]);
2968
2969 /* Free it. */
2970 const uint16_t iNext = paUsers[i].iNext;
2971 paUsers[i].iUser = NIL_PGMPOOL_IDX;
2972 paUsers[i].iNext = pPool->iUserFreeHead;
2973 pPool->iUserFreeHead = i;
2974
2975 /* Next. */
2976 i = iNext;
2977 }
2978 pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
2979}
2980
2981#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
2982
2983/**
2984 * Allocates a new physical cross reference extent.
2985 *
2986 * @returns Pointer to the allocated extent on success. NULL if we're out of them.
2987 * @param pVM The VM handle.
2988 * @param piPhysExt Where to store the phys ext index.
2989 */
2990PPGMPOOLPHYSEXT pgmPoolTrackPhysExtAlloc(PVM pVM, uint16_t *piPhysExt)
2991{
2992 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2993 uint16_t iPhysExt = pPool->iPhysExtFreeHead;
2994 if (iPhysExt == NIL_PGMPOOL_PHYSEXT_INDEX)
2995 {
2996 STAM_COUNTER_INC(&pPool->StamTrackPhysExtAllocFailures);
2997 return NULL;
2998 }
2999 PPGMPOOLPHYSEXT pPhysExt = &pPool->CTX_SUFF(paPhysExts)[iPhysExt];
3000 pPool->iPhysExtFreeHead = pPhysExt->iNext;
3001 pPhysExt->iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
3002 *piPhysExt = iPhysExt;
3003 return pPhysExt;
3004}
3005
3006
3007/**
3008 * Frees a physical cross reference extent.
3009 *
3010 * @param pVM The VM handle.
3011 * @param iPhysExt The extent to free.
3012 */
3013void pgmPoolTrackPhysExtFree(PVM pVM, uint16_t iPhysExt)
3014{
3015 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
3016 Assert(iPhysExt < pPool->cMaxPhysExts);
3017 PPGMPOOLPHYSEXT pPhysExt = &pPool->CTX_SUFF(paPhysExts)[iPhysExt];
3018 for (unsigned i = 0; i < RT_ELEMENTS(pPhysExt->aidx); i++)
3019 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
3020 pPhysExt->iNext = pPool->iPhysExtFreeHead;
3021 pPool->iPhysExtFreeHead = iPhysExt;
3022}
3023
3024
3025/**
3026 * Frees a physical cross reference extent.
3027 *
3028 * @param pVM The VM handle.
3029 * @param iPhysExt The extent to free.
3030 */
3031void pgmPoolTrackPhysExtFreeList(PVM pVM, uint16_t iPhysExt)
3032{
3033 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
3034
3035 const uint16_t iPhysExtStart = iPhysExt;
3036 PPGMPOOLPHYSEXT pPhysExt;
3037 do
3038 {
3039 Assert(iPhysExt < pPool->cMaxPhysExts);
3040 pPhysExt = &pPool->CTX_SUFF(paPhysExts)[iPhysExt];
3041 for (unsigned i = 0; i < RT_ELEMENTS(pPhysExt->aidx); i++)
3042 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
3043
3044 /* next */
3045 iPhysExt = pPhysExt->iNext;
3046 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
3047
3048 pPhysExt->iNext = pPool->iPhysExtFreeHead;
3049 pPool->iPhysExtFreeHead = iPhysExtStart;
3050}
3051
3052
3053/**
3054 * Insert a reference into a list of physical cross reference extents.
3055 *
3056 * @returns The new tracking data for PGMPAGE.
3057 *
3058 * @param pVM The VM handle.
3059 * @param iPhysExt The physical extent index of the list head.
3060 * @param iShwPT The shadow page table index.
3061 *
3062 */
3063static uint16_t pgmPoolTrackPhysExtInsert(PVM pVM, uint16_t iPhysExt, uint16_t iShwPT)
3064{
3065 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
3066 PPGMPOOLPHYSEXT paPhysExts = pPool->CTX_SUFF(paPhysExts);
3067
3068 /* special common case. */
3069 if (paPhysExts[iPhysExt].aidx[2] == NIL_PGMPOOL_IDX)
3070 {
3071 paPhysExts[iPhysExt].aidx[2] = iShwPT;
3072 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackAliasedMany);
3073 LogFlow(("pgmPoolTrackPhysExtAddref: %d:{,,%d}\n", iPhysExt, iShwPT));
3074 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExt);
3075 }
3076
3077 /* general treatment. */
3078 const uint16_t iPhysExtStart = iPhysExt;
3079 unsigned cMax = 15;
3080 for (;;)
3081 {
3082 Assert(iPhysExt < pPool->cMaxPhysExts);
3083 for (unsigned i = 0; i < RT_ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
3084 if (paPhysExts[iPhysExt].aidx[i] == NIL_PGMPOOL_IDX)
3085 {
3086 paPhysExts[iPhysExt].aidx[i] = iShwPT;
3087 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackAliasedMany);
3088 LogFlow(("pgmPoolTrackPhysExtAddref: %d:{%d} i=%d cMax=%d\n", iPhysExt, iShwPT, i, cMax));
3089 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExtStart);
3090 }
3091 if (!--cMax)
3092 {
3093 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackOverflows);
3094 pgmPoolTrackPhysExtFreeList(pVM, iPhysExtStart);
3095 LogFlow(("pgmPoolTrackPhysExtAddref: overflow (1) iShwPT=%d\n", iShwPT));
3096 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED);
3097 }
3098 }
3099
3100 /* add another extent to the list. */
3101 PPGMPOOLPHYSEXT pNew = pgmPoolTrackPhysExtAlloc(pVM, &iPhysExt);
3102 if (!pNew)
3103 {
3104 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackOverflows);
3105 pgmPoolTrackPhysExtFreeList(pVM, iPhysExtStart);
3106 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED);
3107 }
3108 pNew->iNext = iPhysExtStart;
3109 pNew->aidx[0] = iShwPT;
3110 LogFlow(("pgmPoolTrackPhysExtAddref: added new extent %d:{%d}->%d\n", iPhysExt, iShwPT, iPhysExtStart));
3111 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExt);
3112}
3113
3114
3115/**
3116 * Add a reference to guest physical page where extents are in use.
3117 *
3118 * @returns The new tracking data for PGMPAGE.
3119 *
3120 * @param pVM The VM handle.
3121 * @param u16 The ram range flags (top 16-bits).
3122 * @param iShwPT The shadow page table index.
3123 */
3124uint16_t pgmPoolTrackPhysExtAddref(PVM pVM, uint16_t u16, uint16_t iShwPT)
3125{
3126 if (PGMPOOL_TD_GET_CREFS(u16) != PGMPOOL_TD_CREFS_PHYSEXT)
3127 {
3128 /*
3129 * Convert to extent list.
3130 */
3131 Assert(PGMPOOL_TD_GET_CREFS(u16) == 1);
3132 uint16_t iPhysExt;
3133 PPGMPOOLPHYSEXT pPhysExt = pgmPoolTrackPhysExtAlloc(pVM, &iPhysExt);
3134 if (pPhysExt)
3135 {
3136 LogFlow(("pgmPoolTrackPhysExtAddref: new extent: %d:{%d, %d}\n", iPhysExt, PGMPOOL_TD_GET_IDX(u16), iShwPT));
3137 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackAliased);
3138 pPhysExt->aidx[0] = PGMPOOL_TD_GET_IDX(u16);
3139 pPhysExt->aidx[1] = iShwPT;
3140 u16 = PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExt);
3141 }
3142 else
3143 u16 = PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED);
3144 }
3145 else if (u16 != PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED))
3146 {
3147 /*
3148 * Insert into the extent list.
3149 */
3150 u16 = pgmPoolTrackPhysExtInsert(pVM, PGMPOOL_TD_GET_IDX(u16), iShwPT);
3151 }
3152 else
3153 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackAliasedLots);
3154 return u16;
3155}
3156
3157
3158/**
3159 * Clear references to guest physical memory.
3160 *
3161 * @param pPool The pool.
3162 * @param pPage The page.
3163 * @param pPhysPage Pointer to the aPages entry in the ram range.
3164 */
3165void pgmPoolTrackPhysExtDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMPAGE pPhysPage)
3166{
3167 const unsigned cRefs = PGM_PAGE_GET_TD_CREFS(pPhysPage);
3168 AssertFatalMsg(cRefs == PGMPOOL_TD_CREFS_PHYSEXT, ("cRefs=%d pPhysPage=%R[pgmpage] pPage=%p:{.idx=%d}\n", cRefs, pPhysPage, pPage, pPage->idx));
3169
3170 uint16_t iPhysExt = PGM_PAGE_GET_TD_IDX(pPhysPage);
3171 if (iPhysExt != PGMPOOL_TD_IDX_OVERFLOWED)
3172 {
3173 uint16_t iPhysExtPrev = NIL_PGMPOOL_PHYSEXT_INDEX;
3174 PPGMPOOLPHYSEXT paPhysExts = pPool->CTX_SUFF(paPhysExts);
3175 do
3176 {
3177 Assert(iPhysExt < pPool->cMaxPhysExts);
3178
3179 /*
3180 * Look for the shadow page and check if it's all freed.
3181 */
3182 for (unsigned i = 0; i < RT_ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
3183 {
3184 if (paPhysExts[iPhysExt].aidx[i] == pPage->idx)
3185 {
3186 paPhysExts[iPhysExt].aidx[i] = NIL_PGMPOOL_IDX;
3187
3188 for (i = 0; i < RT_ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
3189 if (paPhysExts[iPhysExt].aidx[i] != NIL_PGMPOOL_IDX)
3190 {
3191 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage] idx=%d\n", pPhysPage, pPage->idx));
3192 return;
3193 }
3194
3195 /* we can free the node. */
3196 PVM pVM = pPool->CTX_SUFF(pVM);
3197 const uint16_t iPhysExtNext = paPhysExts[iPhysExt].iNext;
3198 if ( iPhysExtPrev == NIL_PGMPOOL_PHYSEXT_INDEX
3199 && iPhysExtNext == NIL_PGMPOOL_PHYSEXT_INDEX)
3200 {
3201 /* lonely node */
3202 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
3203 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage] idx=%d lonely\n", pPhysPage, pPage->idx));
3204 PGM_PAGE_SET_TRACKING(pPhysPage, 0);
3205 }
3206 else if (iPhysExtPrev == NIL_PGMPOOL_PHYSEXT_INDEX)
3207 {
3208 /* head */
3209 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage] idx=%d head\n", pPhysPage, pPage->idx));
3210 PGM_PAGE_SET_TRACKING(pPhysPage, PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExtNext));
3211 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
3212 }
3213 else
3214 {
3215 /* in list */
3216 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage] idx=%d\n", pPhysPage, pPage->idx));
3217 paPhysExts[iPhysExtPrev].iNext = iPhysExtNext;
3218 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
3219 }
3220 iPhysExt = iPhysExtNext;
3221 return;
3222 }
3223 }
3224
3225 /* next */
3226 iPhysExtPrev = iPhysExt;
3227 iPhysExt = paPhysExts[iPhysExt].iNext;
3228 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
3229
3230 AssertFatalMsgFailed(("not-found! cRefs=%d pPhysPage=%R[pgmpage] pPage=%p:{.idx=%d}\n", cRefs, pPhysPage, pPage, pPage->idx));
3231 }
3232 else /* nothing to do */
3233 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage]\n", pPhysPage));
3234}
3235
3236
3237/**
3238 * Clear references to guest physical memory.
3239 *
3240 * This is the same as pgmPoolTracDerefGCPhys except that the guest physical address
3241 * is assumed to be correct, so the linear search can be skipped and we can assert
3242 * at an earlier point.
3243 *
3244 * @param pPool The pool.
3245 * @param pPage The page.
3246 * @param HCPhys The host physical address corresponding to the guest page.
3247 * @param GCPhys The guest physical address corresponding to HCPhys.
3248 */
3249static void pgmPoolTracDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhys)
3250{
3251 /*
3252 * Walk range list.
3253 */
3254 PPGMRAMRANGE pRam = pPool->CTX_SUFF(pVM)->pgm.s.CTX_SUFF(pRamRanges);
3255 while (pRam)
3256 {
3257 RTGCPHYS off = GCPhys - pRam->GCPhys;
3258 if (off < pRam->cb)
3259 {
3260 /* does it match? */
3261 const unsigned iPage = off >> PAGE_SHIFT;
3262 Assert(PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]));
3263#ifdef LOG_ENABLED
3264RTHCPHYS HCPhysPage = PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]);
3265Log2(("pgmPoolTracDerefGCPhys %RHp vs %RHp\n", HCPhysPage, HCPhys));
3266#endif
3267 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
3268 {
3269 pgmTrackDerefGCPhys(pPool, pPage, &pRam->aPages[iPage]);
3270 return;
3271 }
3272 break;
3273 }
3274 pRam = pRam->CTX_SUFF(pNext);
3275 }
3276 AssertFatalMsgFailed(("HCPhys=%RHp GCPhys=%RGp\n", HCPhys, GCPhys));
3277}
3278
3279
3280/**
3281 * Clear references to guest physical memory.
3282 *
3283 * @param pPool The pool.
3284 * @param pPage The page.
3285 * @param HCPhys The host physical address corresponding to the guest page.
3286 * @param GCPhysHint The guest physical address which may corresponding to HCPhys.
3287 */
3288static void pgmPoolTracDerefGCPhysHint(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhysHint)
3289{
3290 Log4(("pgmPoolTracDerefGCPhysHint %RHp %RGp\n", HCPhys, GCPhysHint));
3291
3292 /*
3293 * Walk range list.
3294 */
3295 PPGMRAMRANGE pRam = pPool->CTX_SUFF(pVM)->pgm.s.CTX_SUFF(pRamRanges);
3296 while (pRam)
3297 {
3298 RTGCPHYS off = GCPhysHint - pRam->GCPhys;
3299 if (off < pRam->cb)
3300 {
3301 /* does it match? */
3302 const unsigned iPage = off >> PAGE_SHIFT;
3303 Assert(PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]));
3304 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
3305 {
3306 pgmTrackDerefGCPhys(pPool, pPage, &pRam->aPages[iPage]);
3307 return;
3308 }
3309 break;
3310 }
3311 pRam = pRam->CTX_SUFF(pNext);
3312 }
3313
3314 /*
3315 * Damn, the hint didn't work. We'll have to do an expensive linear search.
3316 */
3317 STAM_COUNTER_INC(&pPool->StatTrackLinearRamSearches);
3318 pRam = pPool->CTX_SUFF(pVM)->pgm.s.CTX_SUFF(pRamRanges);
3319 while (pRam)
3320 {
3321 unsigned iPage = pRam->cb >> PAGE_SHIFT;
3322 while (iPage-- > 0)
3323 {
3324 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
3325 {
3326 Log4(("pgmPoolTracDerefGCPhysHint: Linear HCPhys=%RHp GCPhysHint=%RGp GCPhysReal=%RGp\n",
3327 HCPhys, GCPhysHint, pRam->GCPhys + (iPage << PAGE_SHIFT)));
3328 pgmTrackDerefGCPhys(pPool, pPage, &pRam->aPages[iPage]);
3329 return;
3330 }
3331 }
3332 pRam = pRam->CTX_SUFF(pNext);
3333 }
3334
3335 AssertFatalMsgFailed(("HCPhys=%RHp GCPhysHint=%RGp\n", HCPhys, GCPhysHint));
3336}
3337
3338
3339/**
3340 * Clear references to guest physical memory in a 32-bit / 32-bit page table.
3341 *
3342 * @param pPool The pool.
3343 * @param pPage The page.
3344 * @param pShwPT The shadow page table (mapping of the page).
3345 * @param pGstPT The guest page table.
3346 */
3347DECLINLINE(void) pgmPoolTrackDerefPT32Bit32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PT pShwPT, PCX86PT pGstPT)
3348{
3349 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++)
3350 if (pShwPT->a[i].n.u1Present)
3351 {
3352 Log4(("pgmPoolTrackDerefPT32Bit32Bit: i=%d pte=%RX32 hint=%RX32\n",
3353 i, pShwPT->a[i].u & X86_PTE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK));
3354 pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK);
3355 if (!--pPage->cPresent)
3356 break;
3357 }
3358}
3359
3360
3361/**
3362 * Clear references to guest physical memory in a PAE / 32-bit page table.
3363 *
3364 * @param pPool The pool.
3365 * @param pPage The page.
3366 * @param pShwPT The shadow page table (mapping of the page).
3367 * @param pGstPT The guest page table (just a half one).
3368 */
3369DECLINLINE(void) pgmPoolTrackDerefPTPae32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PTPAE pShwPT, PCX86PT pGstPT)
3370{
3371 for (unsigned i = 0; i < RT_ELEMENTS(pShwPT->a); i++)
3372 if (pShwPT->a[i].n.u1Present)
3373 {
3374 Log4(("pgmPoolTrackDerefPTPae32Bit: i=%d pte=%RX64 hint=%RX32\n",
3375 i, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK));
3376 pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK);
3377 }
3378}
3379
3380
3381/**
3382 * Clear references to guest physical memory in a PAE / PAE page table.
3383 *
3384 * @param pPool The pool.
3385 * @param pPage The page.
3386 * @param pShwPT The shadow page table (mapping of the page).
3387 * @param pGstPT The guest page table.
3388 */
3389DECLINLINE(void) pgmPoolTrackDerefPTPaePae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PTPAE pShwPT, PCX86PTPAE pGstPT)
3390{
3391 for (unsigned i = 0; i < RT_ELEMENTS(pShwPT->a); i++)
3392 if (pShwPT->a[i].n.u1Present)
3393 {
3394 Log4(("pgmPoolTrackDerefPTPaePae: i=%d pte=%RX32 hint=%RX32\n",
3395 i, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PAE_PG_MASK));
3396 pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PAE_PG_MASK);
3397 }
3398}
3399
3400
3401/**
3402 * Clear references to guest physical memory in a 32-bit / 4MB page table.
3403 *
3404 * @param pPool The pool.
3405 * @param pPage The page.
3406 * @param pShwPT The shadow page table (mapping of the page).
3407 */
3408DECLINLINE(void) pgmPoolTrackDerefPT32Bit4MB(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PT pShwPT)
3409{
3410 RTGCPHYS GCPhys = pPage->GCPhys;
3411 for (unsigned i = 0; i < RT_ELEMENTS(pShwPT->a); i++, GCPhys += PAGE_SIZE)
3412 if (pShwPT->a[i].n.u1Present)
3413 {
3414 Log4(("pgmPoolTrackDerefPT32Bit4MB: i=%d pte=%RX32 GCPhys=%RGp\n",
3415 i, pShwPT->a[i].u & X86_PTE_PG_MASK, GCPhys));
3416 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPT->a[i].u & X86_PTE_PG_MASK, GCPhys);
3417 }
3418}
3419
3420
3421/**
3422 * Clear references to guest physical memory in a PAE / 2/4MB page table.
3423 *
3424 * @param pPool The pool.
3425 * @param pPage The page.
3426 * @param pShwPT The shadow page table (mapping of the page).
3427 */
3428DECLINLINE(void) pgmPoolTrackDerefPTPaeBig(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PTPAE pShwPT)
3429{
3430 RTGCPHYS GCPhys = pPage->GCPhys;
3431 for (unsigned i = 0; i < RT_ELEMENTS(pShwPT->a); i++, GCPhys += PAGE_SIZE)
3432 if (pShwPT->a[i].n.u1Present)
3433 {
3434 Log4(("pgmPoolTrackDerefPTPaeBig: i=%d pte=%RX64 hint=%RGp\n",
3435 i, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, GCPhys));
3436 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, GCPhys);
3437 }
3438}
3439
3440#endif /* PGMPOOL_WITH_GCPHYS_TRACKING */
3441
3442
3443/**
3444 * Clear references to shadowed pages in a 32 bits page directory.
3445 *
3446 * @param pPool The pool.
3447 * @param pPage The page.
3448 * @param pShwPD The shadow page directory (mapping of the page).
3449 */
3450DECLINLINE(void) pgmPoolTrackDerefPD(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PD pShwPD)
3451{
3452 for (unsigned i = 0; i < RT_ELEMENTS(pShwPD->a); i++)
3453 {
3454 if ( pShwPD->a[i].n.u1Present
3455 && !(pShwPD->a[i].u & PGM_PDFLAGS_MAPPING)
3456 )
3457 {
3458 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & X86_PDE_PG_MASK);
3459 if (pSubPage)
3460 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
3461 else
3462 AssertFatalMsgFailed(("%x\n", pShwPD->a[i].u & X86_PDE_PG_MASK));
3463 }
3464 }
3465}
3466
3467/**
3468 * Clear references to shadowed pages in a PAE (legacy or 64 bits) page directory.
3469 *
3470 * @param pPool The pool.
3471 * @param pPage The page.
3472 * @param pShwPD The shadow page directory (mapping of the page).
3473 */
3474DECLINLINE(void) pgmPoolTrackDerefPDPae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PDPAE pShwPD)
3475{
3476 for (unsigned i = 0; i < RT_ELEMENTS(pShwPD->a); i++)
3477 {
3478 if ( pShwPD->a[i].n.u1Present
3479 && !(pShwPD->a[i].u & PGM_PDFLAGS_MAPPING)
3480 )
3481 {
3482 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & X86_PDE_PAE_PG_MASK);
3483 if (pSubPage)
3484 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
3485 else
3486 AssertFatalMsgFailed(("%RX64\n", pShwPD->a[i].u & X86_PDE_PAE_PG_MASK));
3487 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
3488 }
3489 }
3490}
3491
3492/**
3493 * Clear references to shadowed pages in a PAE page directory pointer table.
3494 *
3495 * @param pPool The pool.
3496 * @param pPage The page.
3497 * @param pShwPDPT The shadow page directory pointer table (mapping of the page).
3498 */
3499DECLINLINE(void) pgmPoolTrackDerefPDPTPae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PDPT pShwPDPT)
3500{
3501 for (unsigned i = 0; i < X86_PG_PAE_PDPE_ENTRIES; i++)
3502 {
3503 if ( pShwPDPT->a[i].n.u1Present
3504 && !(pShwPDPT->a[i].u & PGM_PLXFLAGS_MAPPING)
3505 )
3506 {
3507 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & X86_PDPE_PG_MASK);
3508 if (pSubPage)
3509 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
3510 else
3511 AssertFatalMsgFailed(("%RX64\n", pShwPDPT->a[i].u & X86_PDPE_PG_MASK));
3512 }
3513 }
3514}
3515
3516
3517/**
3518 * Clear references to shadowed pages in a 64-bit page directory pointer table.
3519 *
3520 * @param pPool The pool.
3521 * @param pPage The page.
3522 * @param pShwPDPT The shadow page directory pointer table (mapping of the page).
3523 */
3524DECLINLINE(void) pgmPoolTrackDerefPDPT64Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PDPT pShwPDPT)
3525{
3526 for (unsigned i = 0; i < RT_ELEMENTS(pShwPDPT->a); i++)
3527 {
3528 Assert(!(pShwPDPT->a[i].u & PGM_PLXFLAGS_MAPPING));
3529 if (pShwPDPT->a[i].n.u1Present)
3530 {
3531 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & X86_PDPE_PG_MASK);
3532 if (pSubPage)
3533 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
3534 else
3535 AssertFatalMsgFailed(("%RX64\n", pShwPDPT->a[i].u & X86_PDPE_PG_MASK));
3536 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
3537 }
3538 }
3539}
3540
3541
3542/**
3543 * Clear references to shadowed pages in a 64-bit level 4 page table.
3544 *
3545 * @param pPool The pool.
3546 * @param pPage The page.
3547 * @param pShwPML4 The shadow page directory pointer table (mapping of the page).
3548 */
3549DECLINLINE(void) pgmPoolTrackDerefPML464Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PML4 pShwPML4)
3550{
3551 for (unsigned i = 0; i < RT_ELEMENTS(pShwPML4->a); i++)
3552 {
3553 if (pShwPML4->a[i].n.u1Present)
3554 {
3555 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPML4->a[i].u & X86_PDPE_PG_MASK);
3556 if (pSubPage)
3557 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
3558 else
3559 AssertFatalMsgFailed(("%RX64\n", pShwPML4->a[i].u & X86_PML4E_PG_MASK));
3560 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
3561 }
3562 }
3563}
3564
3565
3566/**
3567 * Clear references to shadowed pages in an EPT page table.
3568 *
3569 * @param pPool The pool.
3570 * @param pPage The page.
3571 * @param pShwPML4 The shadow page directory pointer table (mapping of the page).
3572 */
3573DECLINLINE(void) pgmPoolTrackDerefPTEPT(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PEPTPT pShwPT)
3574{
3575 RTGCPHYS GCPhys = pPage->GCPhys;
3576 for (unsigned i = 0; i < RT_ELEMENTS(pShwPT->a); i++, GCPhys += PAGE_SIZE)
3577 if (pShwPT->a[i].n.u1Present)
3578 {
3579 Log4(("pgmPoolTrackDerefPTEPT: i=%d pte=%RX64 GCPhys=%RX64\n",
3580 i, pShwPT->a[i].u & EPT_PTE_PG_MASK, pPage->GCPhys));
3581 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPT->a[i].u & EPT_PTE_PG_MASK, GCPhys);
3582 }
3583}
3584
3585
3586/**
3587 * Clear references to shadowed pages in an EPT page directory.
3588 *
3589 * @param pPool The pool.
3590 * @param pPage The page.
3591 * @param pShwPD The shadow page directory (mapping of the page).
3592 */
3593DECLINLINE(void) pgmPoolTrackDerefPDEPT(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PEPTPD pShwPD)
3594{
3595 for (unsigned i = 0; i < RT_ELEMENTS(pShwPD->a); i++)
3596 {
3597 if (pShwPD->a[i].n.u1Present)
3598 {
3599 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & EPT_PDE_PG_MASK);
3600 if (pSubPage)
3601 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
3602 else
3603 AssertFatalMsgFailed(("%RX64\n", pShwPD->a[i].u & EPT_PDE_PG_MASK));
3604 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
3605 }
3606 }
3607}
3608
3609
3610/**
3611 * Clear references to shadowed pages in an EPT page directory pointer table.
3612 *
3613 * @param pPool The pool.
3614 * @param pPage The page.
3615 * @param pShwPDPT The shadow page directory pointer table (mapping of the page).
3616 */
3617DECLINLINE(void) pgmPoolTrackDerefPDPTEPT(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PEPTPDPT pShwPDPT)
3618{
3619 for (unsigned i = 0; i < RT_ELEMENTS(pShwPDPT->a); i++)
3620 {
3621 if (pShwPDPT->a[i].n.u1Present)
3622 {
3623 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & EPT_PDPTE_PG_MASK);
3624 if (pSubPage)
3625 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
3626 else
3627 AssertFatalMsgFailed(("%RX64\n", pShwPDPT->a[i].u & EPT_PDPTE_PG_MASK));
3628 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
3629 }
3630 }
3631}
3632
3633
3634/**
3635 * Clears all references made by this page.
3636 *
3637 * This includes other shadow pages and GC physical addresses.
3638 *
3639 * @param pPool The pool.
3640 * @param pPage The page.
3641 */
3642static void pgmPoolTrackDeref(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
3643{
3644 /*
3645 * Map the shadow page and take action according to the page kind.
3646 */
3647 void *pvShw = PGMPOOL_PAGE_2_LOCKED_PTR(pPool->CTX_SUFF(pVM), pPage);
3648 switch (pPage->enmKind)
3649 {
3650#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
3651 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
3652 {
3653 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
3654 void *pvGst;
3655 int rc = PGM_GCPHYS_2_PTR(pPool->CTX_SUFF(pVM), pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
3656 pgmPoolTrackDerefPT32Bit32Bit(pPool, pPage, (PX86PT)pvShw, (PCX86PT)pvGst);
3657 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
3658 break;
3659 }
3660
3661 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
3662 {
3663 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
3664 void *pvGst;
3665 int rc = PGM_GCPHYS_2_PTR_EX(pPool->CTX_SUFF(pVM), pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
3666 pgmPoolTrackDerefPTPae32Bit(pPool, pPage, (PX86PTPAE)pvShw, (PCX86PT)pvGst);
3667 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
3668 break;
3669 }
3670
3671 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
3672 {
3673 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
3674 void *pvGst;
3675 int rc = PGM_GCPHYS_2_PTR(pPool->CTX_SUFF(pVM), pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
3676 pgmPoolTrackDerefPTPaePae(pPool, pPage, (PX86PTPAE)pvShw, (PCX86PTPAE)pvGst);
3677 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
3678 break;
3679 }
3680
3681 case PGMPOOLKIND_32BIT_PT_FOR_PHYS: /* treat it like a 4 MB page */
3682 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
3683 {
3684 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
3685 pgmPoolTrackDerefPT32Bit4MB(pPool, pPage, (PX86PT)pvShw);
3686 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
3687 break;
3688 }
3689
3690 case PGMPOOLKIND_PAE_PT_FOR_PHYS: /* treat it like a 2 MB page */
3691 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
3692 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
3693 {
3694 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
3695 pgmPoolTrackDerefPTPaeBig(pPool, pPage, (PX86PTPAE)pvShw);
3696 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
3697 break;
3698 }
3699
3700#else /* !PGMPOOL_WITH_GCPHYS_TRACKING */
3701 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
3702 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
3703 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
3704 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
3705 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
3706 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
3707 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
3708 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
3709 break;
3710#endif /* !PGMPOOL_WITH_GCPHYS_TRACKING */
3711
3712 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
3713 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
3714 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
3715 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
3716 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
3717 case PGMPOOLKIND_PAE_PD_PHYS:
3718 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
3719 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
3720 pgmPoolTrackDerefPDPae(pPool, pPage, (PX86PDPAE)pvShw);
3721 break;
3722
3723 case PGMPOOLKIND_32BIT_PD_PHYS:
3724 case PGMPOOLKIND_32BIT_PD:
3725 pgmPoolTrackDerefPD(pPool, pPage, (PX86PD)pvShw);
3726 break;
3727
3728 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
3729 case PGMPOOLKIND_PAE_PDPT:
3730 case PGMPOOLKIND_PAE_PDPT_PHYS:
3731 pgmPoolTrackDerefPDPTPae(pPool, pPage, (PX86PDPT)pvShw);
3732 break;
3733
3734 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
3735 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
3736 pgmPoolTrackDerefPDPT64Bit(pPool, pPage, (PX86PDPT)pvShw);
3737 break;
3738
3739 case PGMPOOLKIND_64BIT_PML4:
3740 pgmPoolTrackDerefPML464Bit(pPool, pPage, (PX86PML4)pvShw);
3741 break;
3742
3743 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
3744 pgmPoolTrackDerefPTEPT(pPool, pPage, (PEPTPT)pvShw);
3745 break;
3746
3747 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
3748 pgmPoolTrackDerefPDEPT(pPool, pPage, (PEPTPD)pvShw);
3749 break;
3750
3751 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
3752 pgmPoolTrackDerefPDPTEPT(pPool, pPage, (PEPTPDPT)pvShw);
3753 break;
3754
3755 default:
3756 AssertFatalMsgFailed(("enmKind=%d\n", pPage->enmKind));
3757 }
3758
3759 /* paranoia, clear the shadow page. Remove this laser (i.e. let Alloc and ClearAll do it). */
3760 STAM_PROFILE_START(&pPool->StatZeroPage, z);
3761 ASMMemZeroPage(pvShw);
3762 STAM_PROFILE_STOP(&pPool->StatZeroPage, z);
3763 pPage->fZeroed = true;
3764 PGMPOOL_UNLOCK_PTR(pPool->CTX_SUFF(pVM), pvShw);
3765}
3766
3767#endif /* PGMPOOL_WITH_USER_TRACKING */
3768#ifdef IN_RING3
3769
3770/**
3771 * Flushes all the special root pages as part of a pgmPoolFlushAllInt operation.
3772 *
3773 * @param pPool The pool.
3774 */
3775static void pgmPoolFlushAllSpecialRoots(PPGMPOOL pPool)
3776{
3777 /*
3778 * These special pages are all mapped into the indexes 1..PGMPOOL_IDX_FIRST.
3779 */
3780 Assert(NIL_PGMPOOL_IDX == 0);
3781
3782 /*
3783 * Paranoia (to be removed), flag a global CR3 sync.
3784 */
3785 VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
3786}
3787
3788
3789/**
3790 * Flushes the entire cache.
3791 *
3792 * It will assert a global CR3 flush (FF) and assumes the caller is aware of this
3793 * and execute this CR3 flush.
3794 *
3795 * @param pPool The pool.
3796 */
3797static void pgmPoolFlushAllInt(PPGMPOOL pPool)
3798{
3799 PVM pVM = pPool->CTX_SUFF(pVM);
3800
3801 STAM_PROFILE_START(&pPool->StatFlushAllInt, a);
3802 LogFlow(("pgmPoolFlushAllInt:\n"));
3803
3804 /*
3805 * If there are no pages in the pool, there is nothing to do.
3806 */
3807 if (pPool->cCurPages <= PGMPOOL_IDX_FIRST)
3808 {
3809 STAM_PROFILE_STOP(&pPool->StatFlushAllInt, a);
3810 return;
3811 }
3812
3813 /* Unmap the old CR3 value before flushing everything. */
3814 int rc = PGM_BTH_PFN(UnmapCR3, pVM)(pVM);
3815 AssertRC(rc);
3816
3817 /* Exit the current shadow paging mode as well; nested paging and EPT use a root CR3 which will get flushed here. */
3818 rc = PGM_SHW_PFN(Exit, pVM)(pVM);
3819 AssertRC(rc);
3820
3821 /*
3822 * Nuke the free list and reinsert all pages into it.
3823 */
3824 for (unsigned i = pPool->cCurPages - 1; i >= PGMPOOL_IDX_FIRST; i--)
3825 {
3826 PPGMPOOLPAGE pPage = &pPool->aPages[i];
3827
3828#ifdef IN_RING3
3829 Assert(pPage->Core.Key == MMPage2Phys(pVM, pPage->pvPageR3));
3830#endif
3831#ifdef PGMPOOL_WITH_MONITORING
3832 if (pPage->fMonitored)
3833 pgmPoolMonitorFlush(pPool, pPage);
3834 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
3835 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
3836 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
3837 pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
3838 pPage->cModifications = 0;
3839#endif
3840 pPage->GCPhys = NIL_RTGCPHYS;
3841 pPage->enmKind = PGMPOOLKIND_FREE;
3842 Assert(pPage->idx == i);
3843 pPage->iNext = i + 1;
3844 pPage->fZeroed = false; /* This could probably be optimized, but better safe than sorry. */
3845 pPage->fSeenNonGlobal = false;
3846 pPage->fMonitored= false;
3847 pPage->fCached = false;
3848 pPage->fReusedFlushPending = false;
3849#ifdef PGMPOOL_WITH_USER_TRACKING
3850 pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
3851#else
3852 pPage->fCR3Mix = false;
3853#endif
3854#ifdef PGMPOOL_WITH_CACHE
3855 pPage->iAgeNext = NIL_PGMPOOL_IDX;
3856 pPage->iAgePrev = NIL_PGMPOOL_IDX;
3857#endif
3858 pPage->fLocked = false;
3859 }
3860 pPool->aPages[pPool->cCurPages - 1].iNext = NIL_PGMPOOL_IDX;
3861 pPool->iFreeHead = PGMPOOL_IDX_FIRST;
3862 pPool->cUsedPages = 0;
3863
3864#ifdef PGMPOOL_WITH_USER_TRACKING
3865 /*
3866 * Zap and reinitialize the user records.
3867 */
3868 pPool->cPresent = 0;
3869 pPool->iUserFreeHead = 0;
3870 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
3871 const unsigned cMaxUsers = pPool->cMaxUsers;
3872 for (unsigned i = 0; i < cMaxUsers; i++)
3873 {
3874 paUsers[i].iNext = i + 1;
3875 paUsers[i].iUser = NIL_PGMPOOL_IDX;
3876 paUsers[i].iUserTable = 0xfffffffe;
3877 }
3878 paUsers[cMaxUsers - 1].iNext = NIL_PGMPOOL_USER_INDEX;
3879#endif
3880
3881#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
3882 /*
3883 * Clear all the GCPhys links and rebuild the phys ext free list.
3884 */
3885 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
3886 pRam;
3887 pRam = pRam->CTX_SUFF(pNext))
3888 {
3889 unsigned iPage = pRam->cb >> PAGE_SHIFT;
3890 while (iPage-- > 0)
3891 PGM_PAGE_SET_TRACKING(&pRam->aPages[iPage], 0);
3892 }
3893
3894 pPool->iPhysExtFreeHead = 0;
3895 PPGMPOOLPHYSEXT paPhysExts = pPool->CTX_SUFF(paPhysExts);
3896 const unsigned cMaxPhysExts = pPool->cMaxPhysExts;
3897 for (unsigned i = 0; i < cMaxPhysExts; i++)
3898 {
3899 paPhysExts[i].iNext = i + 1;
3900 paPhysExts[i].aidx[0] = NIL_PGMPOOL_IDX;
3901 paPhysExts[i].aidx[1] = NIL_PGMPOOL_IDX;
3902 paPhysExts[i].aidx[2] = NIL_PGMPOOL_IDX;
3903 }
3904 paPhysExts[cMaxPhysExts - 1].iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
3905#endif
3906
3907#ifdef PGMPOOL_WITH_MONITORING
3908 /*
3909 * Just zap the modified list.
3910 */
3911 pPool->cModifiedPages = 0;
3912 pPool->iModifiedHead = NIL_PGMPOOL_IDX;
3913#endif
3914
3915#ifdef PGMPOOL_WITH_CACHE
3916 /*
3917 * Clear the GCPhys hash and the age list.
3918 */
3919 for (unsigned i = 0; i < RT_ELEMENTS(pPool->aiHash); i++)
3920 pPool->aiHash[i] = NIL_PGMPOOL_IDX;
3921 pPool->iAgeHead = NIL_PGMPOOL_IDX;
3922 pPool->iAgeTail = NIL_PGMPOOL_IDX;
3923#endif
3924
3925 /*
3926 * Flush all the special root pages.
3927 * Reinsert active pages into the hash and ensure monitoring chains are correct.
3928 */
3929 pgmPoolFlushAllSpecialRoots(pPool);
3930 for (unsigned i = PGMPOOL_IDX_FIRST_SPECIAL; i < PGMPOOL_IDX_FIRST; i++)
3931 {
3932 PPGMPOOLPAGE pPage = &pPool->aPages[i];
3933 pPage->iNext = NIL_PGMPOOL_IDX;
3934#ifdef PGMPOOL_WITH_MONITORING
3935 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
3936 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
3937 pPage->cModifications = 0;
3938 /* ASSUMES that we're not sharing with any of the other special pages (safe for now). */
3939 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
3940 pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
3941 if (pPage->fMonitored)
3942 {
3943 int rc = PGMHandlerPhysicalChangeCallbacks(pVM, pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1),
3944 pPool->pfnAccessHandlerR3, MMHyperCCToR3(pVM, pPage),
3945 pPool->pfnAccessHandlerR0, MMHyperCCToR0(pVM, pPage),
3946 pPool->pfnAccessHandlerRC, MMHyperCCToRC(pVM, pPage),
3947 pPool->pszAccessHandler);
3948 AssertFatalRCSuccess(rc);
3949# ifdef PGMPOOL_WITH_CACHE
3950 pgmPoolHashInsert(pPool, pPage);
3951# endif
3952 }
3953#endif
3954#ifdef PGMPOOL_WITH_USER_TRACKING
3955 Assert(pPage->iUserHead == NIL_PGMPOOL_USER_INDEX); /* for now */
3956#endif
3957#ifdef PGMPOOL_WITH_CACHE
3958 Assert(pPage->iAgeNext == NIL_PGMPOOL_IDX);
3959 Assert(pPage->iAgePrev == NIL_PGMPOOL_IDX);
3960#endif
3961 }
3962
3963 /*
3964 * Force a shadow mode reinit (necessary for nested paging and ept).
3965 * Reinit the current shadow paging mode as well; nested paging and
3966 * EPT use a root CR3 which will get flushed here.
3967 */
3968 pVM->pgm.s.enmShadowMode = PGMMODE_INVALID;
3969 rc = PGMR3ChangeMode(pVM, PGMGetGuestMode(pVM));
3970 AssertRC(rc);
3971
3972 /*
3973 * Finally, assert the FF.
3974 */
3975 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
3976
3977 STAM_PROFILE_STOP(&pPool->StatFlushAllInt, a);
3978}
3979
3980#endif /* IN_RING3 */
3981
3982/**
3983 * Flushes a pool page.
3984 *
3985 * This moves the page to the free list after removing all user references to it.
3986 * In GC this will cause a CR3 reload if the page is traced back to an active root page.
3987 *
3988 * @returns VBox status code.
3989 * @retval VINF_SUCCESS on success.
3990 * @param pPool The pool.
3991 * @param HCPhys The HC physical address of the shadow page.
3992 */
3993int pgmPoolFlushPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
3994{
3995 int rc = VINF_SUCCESS;
3996 STAM_PROFILE_START(&pPool->StatFlushPage, f);
3997 LogFlow(("pgmPoolFlushPage: pPage=%p:{.Key=%RHp, .idx=%d, .enmKind=%s, .GCPhys=%RGp}\n",
3998 pPage, pPage->Core.Key, pPage->idx, pgmPoolPoolKindToStr(pPage->enmKind), pPage->GCPhys));
3999
4000 /*
4001 * Quietly reject any attempts at flushing any of the special root pages.
4002 */
4003 if (pPage->idx < PGMPOOL_IDX_FIRST)
4004 {
4005 AssertFailed(); /* can no longer happen */
4006 Log(("pgmPoolFlushPage: special root page, rejected. enmKind=%s idx=%d\n", pgmPoolPoolKindToStr(pPage->enmKind), pPage->idx));
4007 return VINF_SUCCESS;
4008 }
4009
4010 /*
4011 * Quietly reject any attempts at flushing the currently active shadow CR3 mapping
4012 */
4013 if (pgmPoolIsPageLocked(&pPool->CTX_SUFF(pVM)->pgm.s, pPage))
4014 {
4015 AssertMsg( pPage->enmKind == PGMPOOLKIND_64BIT_PML4
4016 || pPage->enmKind == PGMPOOLKIND_PAE_PDPT
4017 || pPage->enmKind == PGMPOOLKIND_PAE_PDPT_FOR_32BIT
4018 || pPage->enmKind == PGMPOOLKIND_32BIT_PD
4019 || pPage->enmKind == PGMPOOLKIND_PAE_PD_FOR_PAE_PD
4020 || pPage->enmKind == PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD
4021 || pPage->enmKind == PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD
4022 || pPage->enmKind == PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD
4023 || pPage->enmKind == PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD,
4024 ("Can't free the shadow CR3! (%RHp vs %RHp kind=%d\n", PGMGetHyperCR3(pPool->CTX_SUFF(pVM)), pPage->Core.Key, pPage->enmKind));
4025 Log(("pgmPoolFlushPage: current active shadow CR3, rejected. enmKind=%s idx=%d\n", pgmPoolPoolKindToStr(pPage->enmKind), pPage->idx));
4026 return VINF_SUCCESS;
4027 }
4028
4029#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
4030 /* Start a subset so we won't run out of mapping space. */
4031 PVMCPU pVCpu = VMMGetCpu(pPool->CTX_SUFF(pVM));
4032 uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
4033#endif
4034
4035 /*
4036 * Mark the page as being in need of a ASMMemZeroPage().
4037 */
4038 pPage->fZeroed = false;
4039
4040#ifdef PGMPOOL_WITH_USER_TRACKING
4041 /*
4042 * Clear the page.
4043 */
4044 pgmPoolTrackClearPageUsers(pPool, pPage);
4045 STAM_PROFILE_START(&pPool->StatTrackDeref,a);
4046 pgmPoolTrackDeref(pPool, pPage);
4047 STAM_PROFILE_STOP(&pPool->StatTrackDeref,a);
4048#endif
4049
4050#ifdef PGMPOOL_WITH_CACHE
4051 /*
4052 * Flush it from the cache.
4053 */
4054 pgmPoolCacheFlushPage(pPool, pPage);
4055#endif /* PGMPOOL_WITH_CACHE */
4056
4057#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
4058 /* Heavy stuff done. */
4059 PGMDynMapPopAutoSubset(pVCpu, iPrevSubset);
4060#endif
4061
4062#ifdef PGMPOOL_WITH_MONITORING
4063 /*
4064 * Deregistering the monitoring.
4065 */
4066 if (pPage->fMonitored)
4067 rc = pgmPoolMonitorFlush(pPool, pPage);
4068#endif
4069
4070 /*
4071 * Free the page.
4072 */
4073 Assert(pPage->iNext == NIL_PGMPOOL_IDX);
4074 pPage->iNext = pPool->iFreeHead;
4075 pPool->iFreeHead = pPage->idx;
4076 pPage->enmKind = PGMPOOLKIND_FREE;
4077 pPage->GCPhys = NIL_RTGCPHYS;
4078 pPage->fReusedFlushPending = false;
4079
4080 pPool->cUsedPages--;
4081 STAM_PROFILE_STOP(&pPool->StatFlushPage, f);
4082 return rc;
4083}
4084
4085
4086/**
4087 * Frees a usage of a pool page.
4088 *
4089 * The caller is responsible to updating the user table so that it no longer
4090 * references the shadow page.
4091 *
4092 * @param pPool The pool.
4093 * @param HCPhys The HC physical address of the shadow page.
4094 * @param iUser The shadow page pool index of the user table.
4095 * @param iUserTable The index into the user table (shadowed).
4096 */
4097void pgmPoolFreeByPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable)
4098{
4099 STAM_PROFILE_START(&pPool->StatFree, a);
4100 LogFlow(("pgmPoolFreeByPage: pPage=%p:{.Key=%RHp, .idx=%d, enmKind=%s} iUser=%#x iUserTable=%#x\n",
4101 pPage, pPage->Core.Key, pPage->idx, pgmPoolPoolKindToStr(pPage->enmKind), iUser, iUserTable));
4102 Assert(pPage->idx >= PGMPOOL_IDX_FIRST);
4103#ifdef PGMPOOL_WITH_USER_TRACKING
4104 pgmPoolTrackFreeUser(pPool, pPage, iUser, iUserTable);
4105#endif
4106#ifdef PGMPOOL_WITH_CACHE
4107 if (!pPage->fCached)
4108#endif
4109 pgmPoolFlushPage(pPool, pPage);
4110 STAM_PROFILE_STOP(&pPool->StatFree, a);
4111}
4112
4113
4114/**
4115 * Makes one or more free page free.
4116 *
4117 * @returns VBox status code.
4118 * @retval VINF_SUCCESS on success.
4119 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
4120 *
4121 * @param pPool The pool.
4122 * @param enmKind Page table kind
4123 * @param iUser The user of the page.
4124 */
4125static int pgmPoolMakeMoreFreePages(PPGMPOOL pPool, PGMPOOLKIND enmKind, uint16_t iUser)
4126{
4127 LogFlow(("pgmPoolMakeMoreFreePages: iUser=%#x\n", iUser));
4128
4129 /*
4130 * If the pool isn't full grown yet, expand it.
4131 */
4132 if ( pPool->cCurPages < pPool->cMaxPages
4133#if defined(IN_RC)
4134 /* Hack alert: we can't deal with jumps to ring 3 when called from MapCR3 and allocating pages for PAE PDs. */
4135 && enmKind != PGMPOOLKIND_PAE_PD_FOR_PAE_PD
4136 && (enmKind < PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD || enmKind > PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD)
4137#endif
4138 )
4139 {
4140 STAM_PROFILE_ADV_SUSPEND(&pPool->StatAlloc, a);
4141#ifdef IN_RING3
4142 int rc = PGMR3PoolGrow(pPool->pVMR3);
4143#else
4144 int rc = CTXALLMID(VMM, CallHost)(pPool->CTX_SUFF(pVM), VMMCALLHOST_PGM_POOL_GROW, 0);
4145#endif
4146 if (RT_FAILURE(rc))
4147 return rc;
4148 STAM_PROFILE_ADV_RESUME(&pPool->StatAlloc, a);
4149 if (pPool->iFreeHead != NIL_PGMPOOL_IDX)
4150 return VINF_SUCCESS;
4151 }
4152
4153#ifdef PGMPOOL_WITH_CACHE
4154 /*
4155 * Free one cached page.
4156 */
4157 return pgmPoolCacheFreeOne(pPool, iUser);
4158#else
4159 /*
4160 * Flush the pool.
4161 *
4162 * If we have tracking enabled, it should be possible to come up with
4163 * a cheap replacement strategy...
4164 */
4165 /* @todo This path no longer works (CR3 root pages will be flushed)!! */
4166 AssertCompileFailed();
4167 Assert(!CPUMIsGuestInLongMode(pVM));
4168 pgmPoolFlushAllInt(pPool);
4169 return VERR_PGM_POOL_FLUSHED;
4170#endif
4171}
4172
4173
4174/**
4175 * Allocates a page from the pool.
4176 *
4177 * This page may actually be a cached page and not in need of any processing
4178 * on the callers part.
4179 *
4180 * @returns VBox status code.
4181 * @retval VINF_SUCCESS if a NEW page was allocated.
4182 * @retval VINF_PGM_CACHED_PAGE if a CACHED page was returned.
4183 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
4184 * @param pVM The VM handle.
4185 * @param GCPhys The GC physical address of the page we're gonna shadow.
4186 * For 4MB and 2MB PD entries, it's the first address the
4187 * shadow PT is covering.
4188 * @param enmKind The kind of mapping.
4189 * @param iUser The shadow page pool index of the user table.
4190 * @param iUserTable The index into the user table (shadowed).
4191 * @param ppPage Where to store the pointer to the page. NULL is stored here on failure.
4192 */
4193int pgmPoolAlloc(PVM pVM, RTGCPHYS GCPhys, PGMPOOLKIND enmKind, uint16_t iUser, uint32_t iUserTable, PPPGMPOOLPAGE ppPage)
4194{
4195 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4196 STAM_PROFILE_ADV_START(&pPool->StatAlloc, a);
4197 LogFlow(("pgmPoolAlloc: GCPhys=%RGp enmKind=%s iUser=%#x iUserTable=%#x\n", GCPhys, pgmPoolPoolKindToStr(enmKind), iUser, iUserTable));
4198 *ppPage = NULL;
4199 /** @todo CSAM/PGMPrefetchPage messes up here during CSAMR3CheckGates
4200 * (TRPMR3SyncIDT) because of FF priority. Try fix that?
4201 * Assert(!(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)); */
4202
4203#ifdef PGMPOOL_WITH_CACHE
4204 if (pPool->fCacheEnabled)
4205 {
4206 int rc2 = pgmPoolCacheAlloc(pPool, GCPhys, enmKind, iUser, iUserTable, ppPage);
4207 if (RT_SUCCESS(rc2))
4208 {
4209 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
4210 LogFlow(("pgmPoolAlloc: cached returns %Rrc *ppPage=%p:{.Key=%RHp, .idx=%d}\n", rc2, *ppPage, (*ppPage)->Core.Key, (*ppPage)->idx));
4211 return rc2;
4212 }
4213 }
4214#endif
4215
4216 /*
4217 * Allocate a new one.
4218 */
4219 int rc = VINF_SUCCESS;
4220 uint16_t iNew = pPool->iFreeHead;
4221 if (iNew == NIL_PGMPOOL_IDX)
4222 {
4223 rc = pgmPoolMakeMoreFreePages(pPool, enmKind, iUser);
4224 if (RT_FAILURE(rc))
4225 {
4226 Log(("pgmPoolAlloc: returns %Rrc (Free)\n", rc));
4227 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
4228 return rc;
4229 }
4230 iNew = pPool->iFreeHead;
4231 AssertReleaseReturn(iNew != NIL_PGMPOOL_IDX, VERR_INTERNAL_ERROR);
4232 }
4233
4234 /* unlink the free head */
4235 PPGMPOOLPAGE pPage = &pPool->aPages[iNew];
4236 pPool->iFreeHead = pPage->iNext;
4237 pPage->iNext = NIL_PGMPOOL_IDX;
4238
4239 /*
4240 * Initialize it.
4241 */
4242 pPool->cUsedPages++; /* physical handler registration / pgmPoolTrackFlushGCPhysPTsSlow requirement. */
4243 pPage->enmKind = enmKind;
4244 pPage->GCPhys = GCPhys;
4245 pPage->fSeenNonGlobal = false; /* Set this to 'true' to disable this feature. */
4246 pPage->fMonitored = false;
4247 pPage->fCached = false;
4248 pPage->fReusedFlushPending = false;
4249#ifdef PGMPOOL_WITH_MONITORING
4250 pPage->cModifications = 0;
4251 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
4252 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
4253#else
4254 pPage->fCR3Mix = false;
4255#endif
4256#ifdef PGMPOOL_WITH_USER_TRACKING
4257 pPage->cPresent = 0;
4258 pPage->iFirstPresent = ~0;
4259
4260 /*
4261 * Insert into the tracking and cache. If this fails, free the page.
4262 */
4263 int rc3 = pgmPoolTrackInsert(pPool, pPage, GCPhys, iUser, iUserTable);
4264 if (RT_FAILURE(rc3))
4265 {
4266 pPool->cUsedPages--;
4267 pPage->enmKind = PGMPOOLKIND_FREE;
4268 pPage->GCPhys = NIL_RTGCPHYS;
4269 pPage->iNext = pPool->iFreeHead;
4270 pPool->iFreeHead = pPage->idx;
4271 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
4272 Log(("pgmPoolAlloc: returns %Rrc (Insert)\n", rc3));
4273 return rc3;
4274 }
4275#endif /* PGMPOOL_WITH_USER_TRACKING */
4276
4277 /*
4278 * Commit the allocation, clear the page and return.
4279 */
4280#ifdef VBOX_WITH_STATISTICS
4281 if (pPool->cUsedPages > pPool->cUsedPagesHigh)
4282 pPool->cUsedPagesHigh = pPool->cUsedPages;
4283#endif
4284
4285 if (!pPage->fZeroed)
4286 {
4287 STAM_PROFILE_START(&pPool->StatZeroPage, z);
4288 void *pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
4289 ASMMemZeroPage(pv);
4290 STAM_PROFILE_STOP(&pPool->StatZeroPage, z);
4291 }
4292
4293 *ppPage = pPage;
4294 LogFlow(("pgmPoolAlloc: returns %Rrc *ppPage=%p:{.Key=%RHp, .idx=%d, .fCached=%RTbool, .fMonitored=%RTbool}\n",
4295 rc, pPage, pPage->Core.Key, pPage->idx, pPage->fCached, pPage->fMonitored));
4296 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
4297 return rc;
4298}
4299
4300
4301/**
4302 * Frees a usage of a pool page.
4303 *
4304 * @param pVM The VM handle.
4305 * @param HCPhys The HC physical address of the shadow page.
4306 * @param iUser The shadow page pool index of the user table.
4307 * @param iUserTable The index into the user table (shadowed).
4308 */
4309void pgmPoolFree(PVM pVM, RTHCPHYS HCPhys, uint16_t iUser, uint32_t iUserTable)
4310{
4311 LogFlow(("pgmPoolFree: HCPhys=%RHp iUser=%#x iUserTable=%#x\n", HCPhys, iUser, iUserTable));
4312 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4313 pgmPoolFreeByPage(pPool, pgmPoolGetPage(pPool, HCPhys), iUser, iUserTable);
4314}
4315
4316
4317/**
4318 * Gets a in-use page in the pool by it's physical address.
4319 *
4320 * @returns Pointer to the page.
4321 * @param pVM The VM handle.
4322 * @param HCPhys The HC physical address of the shadow page.
4323 * @remark This function will NEVER return NULL. It will assert if HCPhys is invalid.
4324 */
4325PPGMPOOLPAGE pgmPoolGetPageByHCPhys(PVM pVM, RTHCPHYS HCPhys)
4326{
4327 /** @todo profile this! */
4328 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4329 PPGMPOOLPAGE pPage = pgmPoolGetPage(pPool, HCPhys);
4330#ifndef DEBUG_bird /* extremely noisy */
4331 Log5(("pgmPoolGetPageByHCPhys: HCPhys=%RHp -> %p:{.idx=%d .GCPhys=%RGp .enmKind=%s}\n",
4332 HCPhys, pPage, pPage->idx, pPage->GCPhys, pgmPoolPoolKindToStr(pPage->enmKind)));
4333#endif
4334 return pPage;
4335}
4336
4337#ifdef IN_RING3
4338/**
4339 * Flushes the entire cache.
4340 *
4341 * It will assert a global CR3 flush (FF) and assumes the caller is aware of this
4342 * and execute this CR3 flush.
4343 *
4344 * @param pPool The pool.
4345 */
4346void pgmPoolFlushAll(PVM pVM)
4347{
4348 LogFlow(("pgmPoolFlushAll:\n"));
4349 pgmPoolFlushAllInt(pVM->pgm.s.CTX_SUFF(pPool));
4350}
4351#endif /* IN_RING3 */
4352
4353#ifdef LOG_ENABLED
4354static const char *pgmPoolPoolKindToStr(uint8_t enmKind)
4355{
4356 switch(enmKind)
4357 {
4358 case PGMPOOLKIND_INVALID:
4359 return "PGMPOOLKIND_INVALID";
4360 case PGMPOOLKIND_FREE:
4361 return "PGMPOOLKIND_FREE";
4362 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
4363 return "PGMPOOLKIND_32BIT_PT_FOR_PHYS";
4364 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
4365 return "PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT";
4366 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
4367 return "PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB";
4368 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
4369 return "PGMPOOLKIND_PAE_PT_FOR_PHYS";
4370 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
4371 return "PGMPOOLKIND_PAE_PT_FOR_32BIT_PT";
4372 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
4373 return "PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB";
4374 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
4375 return "PGMPOOLKIND_PAE_PT_FOR_PAE_PT";
4376 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
4377 return "PGMPOOLKIND_PAE_PT_FOR_PAE_2MB";
4378 case PGMPOOLKIND_32BIT_PD:
4379 return "PGMPOOLKIND_32BIT_PD";
4380 case PGMPOOLKIND_32BIT_PD_PHYS:
4381 return "PGMPOOLKIND_32BIT_PD_PHYS";
4382 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
4383 return "PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD";
4384 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
4385 return "PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD";
4386 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
4387 return "PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD";
4388 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
4389 return "PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD";
4390 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
4391 return "PGMPOOLKIND_PAE_PD_FOR_PAE_PD";
4392 case PGMPOOLKIND_PAE_PD_PHYS:
4393 return "PGMPOOLKIND_PAE_PD_PHYS";
4394 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
4395 return "PGMPOOLKIND_PAE_PDPT_FOR_32BIT";
4396 case PGMPOOLKIND_PAE_PDPT:
4397 return "PGMPOOLKIND_PAE_PDPT";
4398 case PGMPOOLKIND_PAE_PDPT_PHYS:
4399 return "PGMPOOLKIND_PAE_PDPT_PHYS";
4400 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
4401 return "PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT";
4402 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
4403 return "PGMPOOLKIND_64BIT_PDPT_FOR_PHYS";
4404 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
4405 return "PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD";
4406 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
4407 return "PGMPOOLKIND_64BIT_PD_FOR_PHYS";
4408 case PGMPOOLKIND_64BIT_PML4:
4409 return "PGMPOOLKIND_64BIT_PML4";
4410 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
4411 return "PGMPOOLKIND_EPT_PDPT_FOR_PHYS";
4412 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
4413 return "PGMPOOLKIND_EPT_PD_FOR_PHYS";
4414 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
4415 return "PGMPOOLKIND_EPT_PT_FOR_PHYS";
4416 case PGMPOOLKIND_ROOT_NESTED:
4417 return "PGMPOOLKIND_ROOT_NESTED";
4418 }
4419 return "Unknown kind!";
4420}
4421#endif /* LOG_ENABLED*/
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette