VirtualBox

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

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

More PGM api changes

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