VirtualBox

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

Last change on this file since 20563 was 20530, checked in by vboxsync, 16 years ago

VMM: remove DISCPUSTATE from the stack.

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