VirtualBox

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

Last change on this file since 69120 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 216.5 KB
Line 
1/* $Id: PGMAllPool.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * PGM Shadow Page Pool.
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_PGM_POOL
23#include <VBox/vmm/pgm.h>
24#include <VBox/vmm/mm.h>
25#include <VBox/vmm/em.h>
26#include <VBox/vmm/cpum.h>
27#ifdef IN_RC
28# include <VBox/vmm/patm.h>
29#endif
30#include "PGMInternal.h"
31#include <VBox/vmm/vm.h>
32#include "PGMInline.h"
33#include <VBox/disopcode.h>
34#include <VBox/vmm/hm_vmx.h>
35
36#include <VBox/log.h>
37#include <VBox/err.h>
38#include <iprt/asm.h>
39#include <iprt/asm-amd64-x86.h>
40#include <iprt/string.h>
41
42
43/*********************************************************************************************************************************
44* Internal Functions *
45*********************************************************************************************************************************/
46RT_C_DECLS_BEGIN
47#if 0 /* unused */
48DECLINLINE(unsigned) pgmPoolTrackGetShadowEntrySize(PGMPOOLKIND enmKind);
49DECLINLINE(unsigned) pgmPoolTrackGetGuestEntrySize(PGMPOOLKIND enmKind);
50#endif /* unused */
51static void pgmPoolTrackClearPageUsers(PPGMPOOL pPool, PPGMPOOLPAGE pPage);
52static void pgmPoolTrackDeref(PPGMPOOL pPool, PPGMPOOLPAGE pPage);
53static int pgmPoolTrackAddUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable);
54static void pgmPoolMonitorModifiedRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage);
55#if defined(LOG_ENABLED) || defined(VBOX_STRICT)
56static const char *pgmPoolPoolKindToStr(uint8_t enmKind);
57#endif
58#if 0 /*defined(VBOX_STRICT) && defined(PGMPOOL_WITH_OPTIMIZED_DIRTY_PT)*/
59static void pgmPoolTrackCheckPTPaePae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMSHWPTPAE pShwPT, PCX86PTPAE pGstPT);
60#endif
61
62int pgmPoolTrackFlushGCPhysPTsSlow(PVM pVM, PPGMPAGE pPhysPage);
63PPGMPOOLPHYSEXT pgmPoolTrackPhysExtAlloc(PVM pVM, uint16_t *piPhysExt);
64void pgmPoolTrackPhysExtFree(PVM pVM, uint16_t iPhysExt);
65void pgmPoolTrackPhysExtFreeList(PVM pVM, uint16_t iPhysExt);
66
67RT_C_DECLS_END
68
69
70#if 0 /* unused */
71/**
72 * Checks if the specified page pool kind is for a 4MB or 2MB guest page.
73 *
74 * @returns true if it's the shadow of a 4MB or 2MB guest page, otherwise false.
75 * @param enmKind The page kind.
76 */
77DECLINLINE(bool) pgmPoolIsBigPage(PGMPOOLKIND enmKind)
78{
79 switch (enmKind)
80 {
81 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
82 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
83 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
84 return true;
85 default:
86 return false;
87 }
88}
89#endif /* unused */
90
91
92/**
93 * Flushes a chain of pages sharing the same access monitor.
94 *
95 * @returns VBox status code suitable for scheduling.
96 * @param pPool The pool.
97 * @param pPage A page in the chain.
98 * @todo VBOXSTRICTRC
99 */
100int pgmPoolMonitorChainFlush(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
101{
102 LogFlow(("pgmPoolMonitorChainFlush: Flush page %RGp type=%d\n", pPage->GCPhys, pPage->enmKind));
103
104 /*
105 * Find the list head.
106 */
107 uint16_t idx = pPage->idx;
108 if (pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
109 {
110 while (pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
111 {
112 idx = pPage->iMonitoredPrev;
113 Assert(idx != pPage->idx);
114 pPage = &pPool->aPages[idx];
115 }
116 }
117
118 /*
119 * Iterate the list flushing each shadow page.
120 */
121 int rc = VINF_SUCCESS;
122 for (;;)
123 {
124 idx = pPage->iMonitoredNext;
125 Assert(idx != pPage->idx);
126 if (pPage->idx >= PGMPOOL_IDX_FIRST)
127 {
128 int rc2 = pgmPoolFlushPage(pPool, pPage);
129 AssertRC(rc2);
130 }
131 /* next */
132 if (idx == NIL_PGMPOOL_IDX)
133 break;
134 pPage = &pPool->aPages[idx];
135 }
136 return rc;
137}
138
139
140/**
141 * Wrapper for getting the current context pointer to the entry being modified.
142 *
143 * @returns VBox status code suitable for scheduling.
144 * @param pVM The cross context VM structure.
145 * @param pvDst Destination address
146 * @param pvSrc Pointer to the mapping of @a GCPhysSrc or NULL depending
147 * on the context (e.g. \#PF in R0 & RC).
148 * @param GCPhysSrc The source guest physical address.
149 * @param cb Size of data to read
150 */
151DECLINLINE(int) pgmPoolPhysSimpleReadGCPhys(PVM pVM, void *pvDst, void const *pvSrc, RTGCPHYS GCPhysSrc, size_t cb)
152{
153#if defined(IN_RING3)
154 NOREF(pVM); NOREF(GCPhysSrc);
155 memcpy(pvDst, (RTHCPTR)((uintptr_t)pvSrc & ~(RTHCUINTPTR)(cb - 1)), cb);
156 return VINF_SUCCESS;
157#else
158 /** @todo in RC we could attempt to use the virtual address, although this can cause many faults (PAE Windows XP guest). */
159 NOREF(pvSrc);
160 return PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc & ~(RTGCPHYS)(cb - 1), cb);
161#endif
162}
163
164
165/**
166 * Process shadow entries before they are changed by the guest.
167 *
168 * For PT entries we will clear them. For PD entries, we'll simply check
169 * for mapping conflicts and set the SyncCR3 FF if found.
170 *
171 * @param pVCpu The cross context virtual CPU structure.
172 * @param pPool The pool.
173 * @param pPage The head page.
174 * @param GCPhysFault The guest physical fault address.
175 * @param pvAddress Pointer to the mapping of @a GCPhysFault or NULL
176 * depending on the context (e.g. \#PF in R0 & RC).
177 * @param cbWrite Write size; might be zero if the caller knows we're not crossing entry boundaries
178 */
179static void pgmPoolMonitorChainChanging(PVMCPU pVCpu, PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTGCPHYS GCPhysFault,
180 void const *pvAddress, unsigned cbWrite)
181{
182 AssertMsg(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX, ("%u (idx=%u)\n", pPage->iMonitoredPrev, pPage->idx));
183 const unsigned off = GCPhysFault & PAGE_OFFSET_MASK;
184 PVM pVM = pPool->CTX_SUFF(pVM);
185 NOREF(pVCpu);
186
187 LogFlow(("pgmPoolMonitorChainChanging: %RGv phys=%RGp cbWrite=%d\n",
188 (RTGCPTR)(CTXTYPE(RTGCPTR, uintptr_t, RTGCPTR))(uintptr_t)pvAddress, GCPhysFault, cbWrite));
189
190 for (;;)
191 {
192 union
193 {
194 void *pv;
195 PX86PT pPT;
196 PPGMSHWPTPAE pPTPae;
197 PX86PD pPD;
198 PX86PDPAE pPDPae;
199 PX86PDPT pPDPT;
200 PX86PML4 pPML4;
201 } uShw;
202
203 LogFlow(("pgmPoolMonitorChainChanging: page idx=%d phys=%RGp (next=%d) kind=%s write=%#x\n",
204 pPage->idx, pPage->GCPhys, pPage->iMonitoredNext, pgmPoolPoolKindToStr(pPage->enmKind), cbWrite));
205
206 uShw.pv = NULL;
207 switch (pPage->enmKind)
208 {
209 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
210 {
211 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPT));
212 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
213 const unsigned iShw = off / sizeof(X86PTE);
214 LogFlow(("PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT iShw=%x\n", iShw));
215 if (uShw.pPT->a[iShw].n.u1Present)
216 {
217 X86PTE GstPte;
218
219 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvAddress, GCPhysFault, sizeof(GstPte));
220 AssertRC(rc);
221 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));
222 pgmPoolTracDerefGCPhysHint(pPool, pPage,
223 uShw.pPT->a[iShw].u & X86_PTE_PAE_PG_MASK,
224 GstPte.u & X86_PTE_PG_MASK,
225 iShw);
226 ASMAtomicWriteU32(&uShw.pPT->a[iShw].u, 0);
227 }
228 break;
229 }
230
231 /* page/2 sized */
232 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
233 {
234 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPT));
235 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
236 if (!((off ^ pPage->GCPhys) & (PAGE_SIZE / 2)))
237 {
238 const unsigned iShw = (off / sizeof(X86PTE)) & (X86_PG_PAE_ENTRIES - 1);
239 LogFlow(("PGMPOOLKIND_PAE_PT_FOR_32BIT_PT iShw=%x\n", iShw));
240 if (PGMSHWPTEPAE_IS_P(uShw.pPTPae->a[iShw]))
241 {
242 X86PTE GstPte;
243 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvAddress, GCPhysFault, sizeof(GstPte));
244 AssertRC(rc);
245
246 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));
247 pgmPoolTracDerefGCPhysHint(pPool, pPage,
248 PGMSHWPTEPAE_GET_HCPHYS(uShw.pPTPae->a[iShw]),
249 GstPte.u & X86_PTE_PG_MASK,
250 iShw);
251 PGMSHWPTEPAE_ATOMIC_SET(uShw.pPTPae->a[iShw], 0);
252 }
253 }
254 break;
255 }
256
257 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
258 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
259 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
260 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
261 {
262 unsigned iGst = off / sizeof(X86PDE);
263 unsigned iShwPdpt = iGst / 256;
264 unsigned iShw = (iGst % 256) * 2;
265 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
266
267 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));
268 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPD));
269 if (iShwPdpt == pPage->enmKind - (unsigned)PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD)
270 {
271 for (unsigned i = 0; i < 2; i++)
272 {
273# ifdef VBOX_WITH_RAW_MODE_NOT_R0
274 if ((uShw.pPDPae->a[iShw + i].u & (PGM_PDFLAGS_MAPPING | X86_PDE_P)) == (PGM_PDFLAGS_MAPPING | X86_PDE_P))
275 {
276 Assert(pgmMapAreMappingsEnabled(pVM));
277 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
278 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShwPdpt=%#x iShw=%#x!\n", iShwPdpt, iShw+i));
279 break;
280 }
281# endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
282 if (uShw.pPDPae->a[iShw+i].n.u1Present)
283 {
284 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw+i, uShw.pPDPae->a[iShw+i].u));
285 pgmPoolFree(pVM,
286 uShw.pPDPae->a[iShw+i].u & X86_PDE_PAE_PG_MASK,
287 pPage->idx,
288 iShw + i);
289 ASMAtomicWriteU64(&uShw.pPDPae->a[iShw+i].u, 0);
290 }
291
292 /* paranoia / a bit assumptive. */
293 if ( (off & 3)
294 && (off & 3) + cbWrite > 4)
295 {
296 const unsigned iShw2 = iShw + 2 + i;
297 if (iShw2 < RT_ELEMENTS(uShw.pPDPae->a))
298 {
299# ifdef VBOX_WITH_RAW_MODE_NOT_R0
300 if ((uShw.pPDPae->a[iShw2].u & (PGM_PDFLAGS_MAPPING | X86_PDE_P)) == (PGM_PDFLAGS_MAPPING | X86_PDE_P))
301 {
302 Assert(pgmMapAreMappingsEnabled(pVM));
303 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
304 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShwPdpt=%#x iShw2=%#x!\n", iShwPdpt, iShw2));
305 break;
306 }
307# endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
308 if (uShw.pPDPae->a[iShw2].n.u1Present)
309 {
310 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPae->a[iShw2].u));
311 pgmPoolFree(pVM,
312 uShw.pPDPae->a[iShw2].u & X86_PDE_PAE_PG_MASK,
313 pPage->idx,
314 iShw2);
315 ASMAtomicWriteU64(&uShw.pPDPae->a[iShw2].u, 0);
316 }
317 }
318 }
319 }
320 }
321 break;
322 }
323
324 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
325 {
326 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
327 const unsigned iShw = off / sizeof(X86PTEPAE);
328 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPT));
329 if (PGMSHWPTEPAE_IS_P(uShw.pPTPae->a[iShw]))
330 {
331 X86PTEPAE GstPte;
332 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvAddress, GCPhysFault, sizeof(GstPte));
333 AssertRC(rc);
334
335 Log4(("pgmPoolMonitorChainChanging pae: deref %016RX64 GCPhys %016RX64\n", PGMSHWPTEPAE_GET_HCPHYS(uShw.pPTPae->a[iShw]), GstPte.u & X86_PTE_PAE_PG_MASK));
336 pgmPoolTracDerefGCPhysHint(pPool, pPage,
337 PGMSHWPTEPAE_GET_HCPHYS(uShw.pPTPae->a[iShw]),
338 GstPte.u & X86_PTE_PAE_PG_MASK,
339 iShw);
340 PGMSHWPTEPAE_ATOMIC_SET(uShw.pPTPae->a[iShw], 0);
341 }
342
343 /* paranoia / a bit assumptive. */
344 if ( (off & 7)
345 && (off & 7) + cbWrite > sizeof(X86PTEPAE))
346 {
347 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PTEPAE);
348 AssertBreak(iShw2 < RT_ELEMENTS(uShw.pPTPae->a));
349
350 if (PGMSHWPTEPAE_IS_P(uShw.pPTPae->a[iShw2]))
351 {
352 X86PTEPAE GstPte;
353 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte,
354 pvAddress ? (uint8_t const *)pvAddress + sizeof(GstPte) : NULL,
355 GCPhysFault + sizeof(GstPte), sizeof(GstPte));
356 AssertRC(rc);
357 Log4(("pgmPoolMonitorChainChanging pae: deref %016RX64 GCPhys %016RX64\n", PGMSHWPTEPAE_GET_HCPHYS(uShw.pPTPae->a[iShw2]), GstPte.u & X86_PTE_PAE_PG_MASK));
358 pgmPoolTracDerefGCPhysHint(pPool, pPage,
359 PGMSHWPTEPAE_GET_HCPHYS(uShw.pPTPae->a[iShw2]),
360 GstPte.u & X86_PTE_PAE_PG_MASK,
361 iShw2);
362 PGMSHWPTEPAE_ATOMIC_SET(uShw.pPTPae->a[iShw2], 0);
363 }
364 }
365 break;
366 }
367
368 case PGMPOOLKIND_32BIT_PD:
369 {
370 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
371 const unsigned iShw = off / sizeof(X86PTE); // ASSUMING 32-bit guest paging!
372
373 LogFlow(("pgmPoolMonitorChainChanging: PGMPOOLKIND_32BIT_PD %x\n", iShw));
374 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPD));
375# ifdef VBOX_WITH_RAW_MODE_NOT_R0
376 if (uShw.pPD->a[iShw].u & PGM_PDFLAGS_MAPPING)
377 {
378 Assert(pgmMapAreMappingsEnabled(pVM));
379 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
380 STAM_COUNTER_INC(&(pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZGuestCR3WriteConflict));
381 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw=%#x!\n", iShw));
382 break;
383 }
384 else
385# endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
386 {
387 if (uShw.pPD->a[iShw].n.u1Present)
388 {
389 LogFlow(("pgmPoolMonitorChainChanging: 32 bit pd iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPD->a[iShw].u));
390 pgmPoolFree(pVM,
391 uShw.pPD->a[iShw].u & X86_PDE_PAE_PG_MASK,
392 pPage->idx,
393 iShw);
394 ASMAtomicWriteU32(&uShw.pPD->a[iShw].u, 0);
395 }
396 }
397 /* paranoia / a bit assumptive. */
398 if ( (off & 3)
399 && (off & 3) + cbWrite > sizeof(X86PTE))
400 {
401 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PTE);
402 if ( iShw2 != iShw
403 && iShw2 < RT_ELEMENTS(uShw.pPD->a))
404 {
405# ifdef VBOX_WITH_RAW_MODE_NOT_R0
406 if (uShw.pPD->a[iShw2].u & PGM_PDFLAGS_MAPPING)
407 {
408 Assert(pgmMapAreMappingsEnabled(pVM));
409 STAM_COUNTER_INC(&(pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZGuestCR3WriteConflict));
410 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
411 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
412 break;
413 }
414# endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
415 if (uShw.pPD->a[iShw2].n.u1Present)
416 {
417 LogFlow(("pgmPoolMonitorChainChanging: 32 bit pd iShw=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPD->a[iShw2].u));
418 pgmPoolFree(pVM,
419 uShw.pPD->a[iShw2].u & X86_PDE_PAE_PG_MASK,
420 pPage->idx,
421 iShw2);
422 ASMAtomicWriteU32(&uShw.pPD->a[iShw2].u, 0);
423 }
424 }
425 }
426#if 0 /* useful when running PGMAssertCR3(), a bit too troublesome for general use (TLBs). - not working any longer... */
427 if ( uShw.pPD->a[iShw].n.u1Present
428 && !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3))
429 {
430 LogFlow(("pgmPoolMonitorChainChanging: iShw=%#x: %RX32 -> freeing it!\n", iShw, uShw.pPD->a[iShw].u));
431# ifdef IN_RC /* TLB load - we're pushing things a bit... */
432 ASMProbeReadByte(pvAddress);
433# endif
434 pgmPoolFree(pVM, uShw.pPD->a[iShw].u & X86_PDE_PG_MASK, pPage->idx, iShw);
435 ASMAtomicWriteU32(&uShw.pPD->a[iShw].u, 0);
436 }
437#endif
438 break;
439 }
440
441 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
442 {
443 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
444 const unsigned iShw = off / sizeof(X86PDEPAE);
445 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPD));
446#ifdef VBOX_WITH_RAW_MODE_NOT_R0
447 if (uShw.pPDPae->a[iShw].u & PGM_PDFLAGS_MAPPING)
448 {
449 Assert(pgmMapAreMappingsEnabled(pVM));
450 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
451 STAM_COUNTER_INC(&(pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZGuestCR3WriteConflict));
452 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw=%#x!\n", iShw));
453 break;
454 }
455#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
456 /*
457 * Causes trouble when the guest uses a PDE to refer to the whole page table level
458 * structure. (Invalidate here; faults later on when it tries to change the page
459 * table entries -> recheck; probably only applies to the RC case.)
460 */
461#ifdef VBOX_WITH_RAW_MODE_NOT_R0
462 else
463#endif
464 {
465 if (uShw.pPDPae->a[iShw].n.u1Present)
466 {
467 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPae->a[iShw].u));
468 pgmPoolFree(pVM,
469 uShw.pPDPae->a[iShw].u & X86_PDE_PAE_PG_MASK,
470 pPage->idx,
471 iShw);
472 ASMAtomicWriteU64(&uShw.pPDPae->a[iShw].u, 0);
473 }
474 }
475 /* paranoia / a bit assumptive. */
476 if ( (off & 7)
477 && (off & 7) + cbWrite > sizeof(X86PDEPAE))
478 {
479 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDEPAE);
480 AssertBreak(iShw2 < RT_ELEMENTS(uShw.pPDPae->a));
481
482#ifdef VBOX_WITH_RAW_MODE_NOT_R0
483 if ( iShw2 != iShw
484 && uShw.pPDPae->a[iShw2].u & PGM_PDFLAGS_MAPPING)
485 {
486 Assert(pgmMapAreMappingsEnabled(pVM));
487 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
488 STAM_COUNTER_INC(&(pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZGuestCR3WriteConflict));
489 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
490 break;
491 }
492 else
493#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
494 if (uShw.pPDPae->a[iShw2].n.u1Present)
495 {
496 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPae->a[iShw2].u));
497 pgmPoolFree(pVM,
498 uShw.pPDPae->a[iShw2].u & X86_PDE_PAE_PG_MASK,
499 pPage->idx,
500 iShw2);
501 ASMAtomicWriteU64(&uShw.pPDPae->a[iShw2].u, 0);
502 }
503 }
504 break;
505 }
506
507 case PGMPOOLKIND_PAE_PDPT:
508 {
509 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPDPT));
510 /*
511 * Hopefully this doesn't happen very often:
512 * - touching unused parts of the page
513 * - messing with the bits of pd pointers without changing the physical address
514 */
515 /* PDPT roots are not page aligned; 32 byte only! */
516 const unsigned offPdpt = GCPhysFault - pPage->GCPhys;
517
518 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
519 const unsigned iShw = offPdpt / sizeof(X86PDPE);
520 if (iShw < X86_PG_PAE_PDPE_ENTRIES) /* don't use RT_ELEMENTS(uShw.pPDPT->a), because that's for long mode only */
521 {
522# ifdef VBOX_WITH_RAW_MODE_NOT_R0
523 if (uShw.pPDPT->a[iShw].u & PGM_PLXFLAGS_MAPPING)
524 {
525 Assert(pgmMapAreMappingsEnabled(pVM));
526 STAM_COUNTER_INC(&(pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZGuestCR3WriteConflict));
527 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
528 LogFlow(("pgmPoolMonitorChainChanging: Detected pdpt conflict at iShw=%#x!\n", iShw));
529 break;
530 }
531 else
532# endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
533 if (uShw.pPDPT->a[iShw].n.u1Present)
534 {
535 LogFlow(("pgmPoolMonitorChainChanging: pae pdpt iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPT->a[iShw].u));
536 pgmPoolFree(pVM,
537 uShw.pPDPT->a[iShw].u & X86_PDPE_PG_MASK,
538 pPage->idx,
539 iShw);
540 ASMAtomicWriteU64(&uShw.pPDPT->a[iShw].u, 0);
541 }
542
543 /* paranoia / a bit assumptive. */
544 if ( (offPdpt & 7)
545 && (offPdpt & 7) + cbWrite > sizeof(X86PDPE))
546 {
547 const unsigned iShw2 = (offPdpt + cbWrite - 1) / sizeof(X86PDPE);
548 if ( iShw2 != iShw
549 && iShw2 < X86_PG_PAE_PDPE_ENTRIES)
550 {
551# ifdef VBOX_WITH_RAW_MODE_NOT_R0
552 if (uShw.pPDPT->a[iShw2].u & PGM_PLXFLAGS_MAPPING)
553 {
554 Assert(pgmMapAreMappingsEnabled(pVM));
555 STAM_COUNTER_INC(&(pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZGuestCR3WriteConflict));
556 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
557 LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
558 break;
559 }
560 else
561# endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
562 if (uShw.pPDPT->a[iShw2].n.u1Present)
563 {
564 LogFlow(("pgmPoolMonitorChainChanging: pae pdpt iShw=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPT->a[iShw2].u));
565 pgmPoolFree(pVM,
566 uShw.pPDPT->a[iShw2].u & X86_PDPE_PG_MASK,
567 pPage->idx,
568 iShw2);
569 ASMAtomicWriteU64(&uShw.pPDPT->a[iShw2].u, 0);
570 }
571 }
572 }
573 }
574 break;
575 }
576
577#ifndef IN_RC
578 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
579 {
580 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPD));
581 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
582 const unsigned iShw = off / sizeof(X86PDEPAE);
583 Assert(!(uShw.pPDPae->a[iShw].u & PGM_PDFLAGS_MAPPING));
584 if (uShw.pPDPae->a[iShw].n.u1Present)
585 {
586 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPae->a[iShw].u));
587 pgmPoolFree(pVM,
588 uShw.pPDPae->a[iShw].u & X86_PDE_PAE_PG_MASK,
589 pPage->idx,
590 iShw);
591 ASMAtomicWriteU64(&uShw.pPDPae->a[iShw].u, 0);
592 }
593 /* paranoia / a bit assumptive. */
594 if ( (off & 7)
595 && (off & 7) + cbWrite > sizeof(X86PDEPAE))
596 {
597 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDEPAE);
598 AssertBreak(iShw2 < RT_ELEMENTS(uShw.pPDPae->a));
599
600 Assert(!(uShw.pPDPae->a[iShw2].u & PGM_PDFLAGS_MAPPING));
601 if (uShw.pPDPae->a[iShw2].n.u1Present)
602 {
603 LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPae->a[iShw2].u));
604 pgmPoolFree(pVM,
605 uShw.pPDPae->a[iShw2].u & X86_PDE_PAE_PG_MASK,
606 pPage->idx,
607 iShw2);
608 ASMAtomicWriteU64(&uShw.pPDPae->a[iShw2].u, 0);
609 }
610 }
611 break;
612 }
613
614 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
615 {
616 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPDPT));
617 /*
618 * Hopefully this doesn't happen very often:
619 * - messing with the bits of pd pointers without changing the physical address
620 */
621 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
622 const unsigned iShw = off / sizeof(X86PDPE);
623 if (uShw.pPDPT->a[iShw].n.u1Present)
624 {
625 LogFlow(("pgmPoolMonitorChainChanging: pdpt iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPT->a[iShw].u));
626 pgmPoolFree(pVM, uShw.pPDPT->a[iShw].u & X86_PDPE_PG_MASK, pPage->idx, iShw);
627 ASMAtomicWriteU64(&uShw.pPDPT->a[iShw].u, 0);
628 }
629 /* paranoia / a bit assumptive. */
630 if ( (off & 7)
631 && (off & 7) + cbWrite > sizeof(X86PDPE))
632 {
633 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDPE);
634 if (uShw.pPDPT->a[iShw2].n.u1Present)
635 {
636 LogFlow(("pgmPoolMonitorChainChanging: pdpt iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPT->a[iShw2].u));
637 pgmPoolFree(pVM, uShw.pPDPT->a[iShw2].u & X86_PDPE_PG_MASK, pPage->idx, iShw2);
638 ASMAtomicWriteU64(&uShw.pPDPT->a[iShw2].u, 0);
639 }
640 }
641 break;
642 }
643
644 case PGMPOOLKIND_64BIT_PML4:
645 {
646 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,FaultPML4));
647 /*
648 * Hopefully this doesn't happen very often:
649 * - messing with the bits of pd pointers without changing the physical address
650 */
651 uShw.pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
652 const unsigned iShw = off / sizeof(X86PDPE);
653 if (uShw.pPML4->a[iShw].n.u1Present)
654 {
655 LogFlow(("pgmPoolMonitorChainChanging: pml4 iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPML4->a[iShw].u));
656 pgmPoolFree(pVM, uShw.pPML4->a[iShw].u & X86_PML4E_PG_MASK, pPage->idx, iShw);
657 ASMAtomicWriteU64(&uShw.pPML4->a[iShw].u, 0);
658 }
659 /* paranoia / a bit assumptive. */
660 if ( (off & 7)
661 && (off & 7) + cbWrite > sizeof(X86PDPE))
662 {
663 const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PML4E);
664 if (uShw.pPML4->a[iShw2].n.u1Present)
665 {
666 LogFlow(("pgmPoolMonitorChainChanging: pml4 iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPML4->a[iShw2].u));
667 pgmPoolFree(pVM, uShw.pPML4->a[iShw2].u & X86_PML4E_PG_MASK, pPage->idx, iShw2);
668 ASMAtomicWriteU64(&uShw.pPML4->a[iShw2].u, 0);
669 }
670 }
671 break;
672 }
673#endif /* IN_RING0 */
674
675 default:
676 AssertFatalMsgFailed(("enmKind=%d\n", pPage->enmKind));
677 }
678 PGM_DYNMAP_UNUSED_HINT_VM(pVM, uShw.pv);
679
680 /* next */
681 if (pPage->iMonitoredNext == NIL_PGMPOOL_IDX)
682 return;
683 pPage = &pPool->aPages[pPage->iMonitoredNext];
684 }
685}
686
687#ifndef IN_RING3
688
689/**
690 * Checks if a access could be a fork operation in progress.
691 *
692 * Meaning, that the guest is setting up the parent process for Copy-On-Write.
693 *
694 * @returns true if it's likely that we're forking, otherwise false.
695 * @param pPool The pool.
696 * @param pDis The disassembled instruction.
697 * @param offFault The access offset.
698 */
699DECLINLINE(bool) pgmRZPoolMonitorIsForking(PPGMPOOL pPool, PDISCPUSTATE pDis, unsigned offFault)
700{
701 /*
702 * i386 linux is using btr to clear X86_PTE_RW.
703 * The functions involved are (2.6.16 source inspection):
704 * clear_bit
705 * ptep_set_wrprotect
706 * copy_one_pte
707 * copy_pte_range
708 * copy_pmd_range
709 * copy_pud_range
710 * copy_page_range
711 * dup_mmap
712 * dup_mm
713 * copy_mm
714 * copy_process
715 * do_fork
716 */
717 if ( pDis->pCurInstr->uOpcode == OP_BTR
718 && !(offFault & 4)
719 /** @todo Validate that the bit index is X86_PTE_RW. */
720 )
721 {
722 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitorPf,Fork)); RT_NOREF_PV(pPool);
723 return true;
724 }
725 return false;
726}
727
728
729/**
730 * Determine whether the page is likely to have been reused.
731 *
732 * @returns true if we consider the page as being reused for a different purpose.
733 * @returns false if we consider it to still be a paging page.
734 * @param pVM The cross context VM structure.
735 * @param pVCpu The cross context virtual CPU structure.
736 * @param pRegFrame Trap register frame.
737 * @param pDis The disassembly info for the faulting instruction.
738 * @param pvFault The fault address.
739 * @param pPage The pool page being accessed.
740 *
741 * @remark The REP prefix check is left to the caller because of STOSD/W.
742 */
743DECLINLINE(bool) pgmRZPoolMonitorIsReused(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pDis, RTGCPTR pvFault,
744 PPGMPOOLPAGE pPage)
745{
746 /* Locked (CR3, PDPTR*4) should not be reusable. Considering them as
747 such may cause loops booting tst-ubuntu-15_10-64-efi, ++. */
748 if (pPage->cLocked)
749 {
750 Log2(("pgmRZPoolMonitorIsReused: %RGv (%p) can't have been resued, because it's locked!\n", pvFault, pPage));
751 return false;
752 }
753
754# ifndef IN_RC
755 /** @todo could make this general, faulting close to rsp should be a safe reuse heuristic. */
756 if ( HMHasPendingIrq(pVM)
757 && (pRegFrame->rsp - pvFault) < 32)
758 {
759 /* Fault caused by stack writes while trying to inject an interrupt event. */
760 Log(("pgmRZPoolMonitorIsReused: reused %RGv for interrupt stack (rsp=%RGv).\n", pvFault, pRegFrame->rsp));
761 return true;
762 }
763# else
764 NOREF(pVM); NOREF(pvFault);
765# endif
766
767 LogFlow(("Reused instr %RGv %d at %RGv param1.fUse=%llx param1.reg=%d\n", pRegFrame->rip, pDis->pCurInstr->uOpcode, pvFault, pDis->Param1.fUse, pDis->Param1.Base.idxGenReg));
768
769 /* Non-supervisor mode write means it's used for something else. */
770 if (CPUMGetGuestCPL(pVCpu) == 3)
771 return true;
772
773 switch (pDis->pCurInstr->uOpcode)
774 {
775 /* call implies the actual push of the return address faulted */
776 case OP_CALL:
777 Log4(("pgmRZPoolMonitorIsReused: CALL\n"));
778 return true;
779 case OP_PUSH:
780 Log4(("pgmRZPoolMonitorIsReused: PUSH\n"));
781 return true;
782 case OP_PUSHF:
783 Log4(("pgmRZPoolMonitorIsReused: PUSHF\n"));
784 return true;
785 case OP_PUSHA:
786 Log4(("pgmRZPoolMonitorIsReused: PUSHA\n"));
787 return true;
788 case OP_FXSAVE:
789 Log4(("pgmRZPoolMonitorIsReused: FXSAVE\n"));
790 return true;
791 case OP_MOVNTI: /* solaris - block_zero_no_xmm */
792 Log4(("pgmRZPoolMonitorIsReused: MOVNTI\n"));
793 return true;
794 case OP_MOVNTDQ: /* solaris - hwblkclr & hwblkpagecopy */
795 Log4(("pgmRZPoolMonitorIsReused: MOVNTDQ\n"));
796 return true;
797 case OP_MOVSWD:
798 case OP_STOSWD:
799 if ( pDis->fPrefix == (DISPREFIX_REP|DISPREFIX_REX)
800 && pRegFrame->rcx >= 0x40
801 )
802 {
803 Assert(pDis->uCpuMode == DISCPUMODE_64BIT);
804
805 Log(("pgmRZPoolMonitorIsReused: OP_STOSQ\n"));
806 return true;
807 }
808 break;
809
810 default:
811 /*
812 * Anything having ESP on the left side means stack writes.
813 */
814 if ( ( (pDis->Param1.fUse & DISUSE_REG_GEN32)
815 || (pDis->Param1.fUse & DISUSE_REG_GEN64))
816 && (pDis->Param1.Base.idxGenReg == DISGREG_ESP))
817 {
818 Log4(("pgmRZPoolMonitorIsReused: ESP\n"));
819 return true;
820 }
821 break;
822 }
823
824 /*
825 * Page table updates are very very unlikely to be crossing page boundraries,
826 * and we don't want to deal with that in pgmPoolMonitorChainChanging and such.
827 */
828 uint32_t const cbWrite = DISGetParamSize(pDis, &pDis->Param1);
829 if ( (((uintptr_t)pvFault + cbWrite) >> X86_PAGE_SHIFT) != ((uintptr_t)pvFault >> X86_PAGE_SHIFT) )
830 {
831 Log4(("pgmRZPoolMonitorIsReused: cross page write\n"));
832 return true;
833 }
834
835 /*
836 * Nobody does an unaligned 8 byte write to a page table, right.
837 */
838 if (cbWrite >= 8 && ((uintptr_t)pvFault & 7) != 0)
839 {
840 Log4(("pgmRZPoolMonitorIsReused: Unaligned 8+ byte write\n"));
841 return true;
842 }
843
844 return false;
845}
846
847
848/**
849 * Flushes the page being accessed.
850 *
851 * @returns VBox status code suitable for scheduling.
852 * @param pVM The cross context VM structure.
853 * @param pVCpu The cross context virtual CPU structure.
854 * @param pPool The pool.
855 * @param pPage The pool page (head).
856 * @param pDis The disassembly of the write instruction.
857 * @param pRegFrame The trap register frame.
858 * @param GCPhysFault The fault address as guest physical address.
859 * @param pvFault The fault address.
860 * @todo VBOXSTRICTRC
861 */
862static int pgmRZPoolAccessPfHandlerFlush(PVM pVM, PVMCPU pVCpu, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pDis,
863 PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
864{
865 NOREF(pVM); NOREF(GCPhysFault);
866
867 /*
868 * First, do the flushing.
869 */
870 int rc = pgmPoolMonitorChainFlush(pPool, pPage);
871
872 /*
873 * Emulate the instruction (xp/w2k problem, requires pc/cr2/sp detection).
874 * Must do this in raw mode (!); XP boot will fail otherwise.
875 */
876 VBOXSTRICTRC rc2 = EMInterpretInstructionDisasState(pVCpu, pDis, pRegFrame, pvFault, EMCODETYPE_ALL);
877 if (rc2 == VINF_SUCCESS)
878 { /* do nothing */ }
879 else if (rc2 == VINF_EM_RESCHEDULE)
880 {
881 if (rc == VINF_SUCCESS)
882 rc = VBOXSTRICTRC_VAL(rc2);
883# ifndef IN_RING3
884 VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);
885# endif
886 }
887 else if (rc2 == VERR_EM_INTERPRETER)
888 {
889# ifdef IN_RC
890 if (PATMIsPatchGCAddr(pVM, pRegFrame->eip))
891 {
892 LogFlow(("pgmRZPoolAccessPfHandlerFlush: Interpretation failed for patch code %04x:%RGv, ignoring.\n",
893 pRegFrame->cs.Sel, (RTGCPTR)pRegFrame->eip));
894 rc = VINF_SUCCESS;
895 STAM_COUNTER_INC(&pPool->StatMonitorPfRZIntrFailPatch2);
896 }
897 else
898# endif
899 {
900 rc = VINF_EM_RAW_EMULATE_INSTR;
901 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitorPf,EmulateInstr));
902 }
903 }
904 else if (RT_FAILURE_NP(rc2))
905 rc = VBOXSTRICTRC_VAL(rc2);
906 else
907 AssertMsgFailed(("%Rrc\n", VBOXSTRICTRC_VAL(rc2))); /* ASSUMES no complicated stuff here. */
908
909 LogFlow(("pgmRZPoolAccessPfHandlerFlush: returns %Rrc (flushed)\n", rc));
910 return rc;
911}
912
913
914/**
915 * Handles the STOSD write accesses.
916 *
917 * @returns VBox status code suitable for scheduling.
918 * @param pVM The cross context VM structure.
919 * @param pPool The pool.
920 * @param pPage The pool page (head).
921 * @param pDis The disassembly of the write instruction.
922 * @param pRegFrame The trap register frame.
923 * @param GCPhysFault The fault address as guest physical address.
924 * @param pvFault The fault address.
925 */
926DECLINLINE(int) pgmRZPoolAccessPfHandlerSTOSD(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pDis,
927 PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
928{
929 unsigned uIncrement = pDis->Param1.cb;
930 NOREF(pVM);
931
932 Assert(pDis->uCpuMode == DISCPUMODE_32BIT || pDis->uCpuMode == DISCPUMODE_64BIT);
933 Assert(pRegFrame->rcx <= 0x20);
934
935# ifdef VBOX_STRICT
936 if (pDis->uOpMode == DISCPUMODE_32BIT)
937 Assert(uIncrement == 4);
938 else
939 Assert(uIncrement == 8);
940# endif
941
942 Log3(("pgmRZPoolAccessPfHandlerSTOSD\n"));
943
944 /*
945 * Increment the modification counter and insert it into the list
946 * of modified pages the first time.
947 */
948 if (!pPage->cModifications++)
949 pgmPoolMonitorModifiedInsert(pPool, pPage);
950
951 /*
952 * Execute REP STOSD.
953 *
954 * This ASSUMES that we're not invoked by Trap0e on in a out-of-sync
955 * write situation, meaning that it's safe to write here.
956 */
957 PVMCPU pVCpu = VMMGetCpu(pPool->CTX_SUFF(pVM));
958 RTGCUINTPTR pu32 = (RTGCUINTPTR)pvFault;
959 while (pRegFrame->rcx)
960 {
961# if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
962 uint32_t iPrevSubset = PGMRZDynMapPushAutoSubset(pVCpu);
963 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault, NULL, uIncrement);
964 PGMRZDynMapPopAutoSubset(pVCpu, iPrevSubset);
965# else
966 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault, NULL, uIncrement);
967# endif
968# ifdef IN_RC
969 *(uint32_t *)(uintptr_t)pu32 = pRegFrame->eax;
970# else
971 PGMPhysSimpleWriteGCPhys(pVM, GCPhysFault, &pRegFrame->rax, uIncrement);
972# endif
973 pu32 += uIncrement;
974 GCPhysFault += uIncrement;
975 pRegFrame->rdi += uIncrement;
976 pRegFrame->rcx--;
977 }
978 pRegFrame->rip += pDis->cbInstr;
979
980 LogFlow(("pgmRZPoolAccessPfHandlerSTOSD: returns\n"));
981 return VINF_SUCCESS;
982}
983
984
985/**
986 * Handles the simple write accesses.
987 *
988 * @returns VBox status code suitable for scheduling.
989 * @param pVM The cross context VM structure.
990 * @param pVCpu The cross context virtual CPU structure.
991 * @param pPool The pool.
992 * @param pPage The pool page (head).
993 * @param pDis The disassembly of the write instruction.
994 * @param pRegFrame The trap register frame.
995 * @param GCPhysFault The fault address as guest physical address.
996 * @param pvFault The fault address.
997 * @param pfReused Reused state (in/out)
998 */
999DECLINLINE(int) pgmRZPoolAccessPfHandlerSimple(PVM pVM, PVMCPU pVCpu, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pDis,
1000 PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault, bool *pfReused)
1001{
1002 Log3(("pgmRZPoolAccessPfHandlerSimple\n"));
1003 NOREF(pVM);
1004 NOREF(pfReused); /* initialized by caller */
1005
1006 /*
1007 * Increment the modification counter and insert it into the list
1008 * of modified pages the first time.
1009 */
1010 if (!pPage->cModifications++)
1011 pgmPoolMonitorModifiedInsert(pPool, pPage);
1012
1013 /*
1014 * Clear all the pages. ASSUMES that pvFault is readable.
1015 */
1016# if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
1017 uint32_t iPrevSubset = PGMRZDynMapPushAutoSubset(pVCpu);
1018# endif
1019
1020 uint32_t cbWrite = DISGetParamSize(pDis, &pDis->Param1);
1021 if (cbWrite <= 8)
1022 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault, NULL, cbWrite);
1023 else if (cbWrite <= 16)
1024 {
1025 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault, NULL, 8);
1026 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault + 8, NULL, cbWrite - 8);
1027 }
1028 else
1029 {
1030 Assert(cbWrite <= 32);
1031 for (uint32_t off = 0; off < cbWrite; off += 8)
1032 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhysFault + off, NULL, RT_MIN(8, cbWrite - off));
1033 }
1034
1035# if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
1036 PGMRZDynMapPopAutoSubset(pVCpu, iPrevSubset);
1037# endif
1038
1039 /*
1040 * Interpret the instruction.
1041 */
1042 VBOXSTRICTRC rc = EMInterpretInstructionDisasState(pVCpu, pDis, pRegFrame, pvFault, EMCODETYPE_ALL);
1043 if (RT_SUCCESS(rc))
1044 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rc))); /* ASSUMES no complicated stuff here. */
1045 else if (rc == VERR_EM_INTERPRETER)
1046 {
1047 LogFlow(("pgmRZPoolAccessPfHandlerSimple: Interpretation failed for %04x:%RGv - opcode=%d\n",
1048 pRegFrame->cs.Sel, (RTGCPTR)pRegFrame->rip, pDis->pCurInstr->uOpcode));
1049 rc = VINF_EM_RAW_EMULATE_INSTR;
1050 STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitorPf,EmulateInstr));
1051 }
1052
1053# if 0 /* experimental code */
1054 if (rc == VINF_SUCCESS)
1055 {
1056 switch (pPage->enmKind)
1057 {
1058 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1059 {
1060 X86PTEPAE GstPte;
1061 int rc = pgmPoolPhysSimpleReadGCPhys(pVM, &GstPte, pvFault, GCPhysFault, sizeof(GstPte));
1062 AssertRC(rc);
1063
1064 /* Check the new value written by the guest. If present and with a bogus physical address, then
1065 * it's fairly safe to assume the guest is reusing the PT.
1066 */
1067 if (GstPte.n.u1Present)
1068 {
1069 RTHCPHYS HCPhys = -1;
1070 int rc = PGMPhysGCPhys2HCPhys(pVM, GstPte.u & X86_PTE_PAE_PG_MASK, &HCPhys);
1071 if (rc != VINF_SUCCESS)
1072 {
1073 *pfReused = true;
1074 STAM_COUNTER_INC(&pPool->StatForceFlushReused);
1075 }
1076 }
1077 break;
1078 }
1079 }
1080 }
1081# endif
1082
1083 LogFlow(("pgmRZPoolAccessPfHandlerSimple: returns %Rrc\n", VBOXSTRICTRC_VAL(rc)));
1084 return VBOXSTRICTRC_VAL(rc);
1085}
1086
1087
1088/**
1089 * @callback_method_impl{FNPGMRZPHYSPFHANDLER,
1090 * \#PF access handler callback for page table pages.}
1091 *
1092 * @remarks The @a pvUser argument points to the PGMPOOLPAGE.
1093 */
1094DECLEXPORT(VBOXSTRICTRC) pgmRZPoolAccessPfHandler(PVM pVM, PVMCPU pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
1095 RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1096{
1097 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pPool)->StatMonitorRZ, a);
1098 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1099 PPGMPOOLPAGE pPage = (PPGMPOOLPAGE)pvUser;
1100 unsigned cMaxModifications;
1101 bool fForcedFlush = false;
1102 NOREF(uErrorCode);
1103
1104 LogFlow(("pgmRZPoolAccessPfHandler: pvFault=%RGv pPage=%p:{.idx=%d} GCPhysFault=%RGp\n", pvFault, pPage, pPage->idx, GCPhysFault));
1105
1106 pgmLock(pVM);
1107 if (PHYS_PAGE_ADDRESS(GCPhysFault) != PHYS_PAGE_ADDRESS(pPage->GCPhys))
1108 {
1109 /* Pool page changed while we were waiting for the lock; ignore. */
1110 Log(("CPU%d: pgmRZPoolAccessPfHandler pgm pool page for %RGp changed (to %RGp) while waiting!\n", pVCpu->idCpu, PHYS_PAGE_ADDRESS(GCPhysFault), PHYS_PAGE_ADDRESS(pPage->GCPhys)));
1111 STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->StatMonitorPfRZ, &pPool->StatMonitorPfRZHandled, a);
1112 pgmUnlock(pVM);
1113 return VINF_SUCCESS;
1114 }
1115# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
1116 if (pPage->fDirty)
1117 {
1118 Assert(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_TLB_FLUSH));
1119 pgmUnlock(pVM);
1120 return VINF_SUCCESS; /* SMP guest case where we were blocking on the pgm lock while the same page was being marked dirty. */
1121 }
1122# endif
1123
1124# if 0 /* test code defined(VBOX_STRICT) && defined(PGMPOOL_WITH_OPTIMIZED_DIRTY_PT) */
1125 if (pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT)
1126 {
1127 void *pvShw = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
1128 void *pvGst;
1129 int rc = PGM_GCPHYS_2_PTR(pPool->CTX_SUFF(pVM), pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
1130 pgmPoolTrackCheckPTPaePae(pPool, pPage, (PPGMSHWPTPAE)pvShw, (PCX86PTPAE)pvGst);
1131 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvGst);
1132 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvShw);
1133 }
1134# endif
1135
1136 /*
1137 * Disassemble the faulting instruction.
1138 */
1139 PDISCPUSTATE pDis = &pVCpu->pgm.s.DisState;
1140 int rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL);
1141 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1142 {
1143 AssertMsg(rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("Unexpected rc %d\n", rc));
1144 pgmUnlock(pVM);
1145 return rc;
1146 }
1147
1148 Assert(pPage->enmKind != PGMPOOLKIND_FREE);
1149
1150 /*
1151 * We should ALWAYS have the list head as user parameter. This
1152 * is because we use that page to record the changes.
1153 */
1154 Assert(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
1155
1156# ifdef IN_RING0
1157 /* Maximum nr of modifications depends on the page type. */
1158 if ( pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT
1159 || pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_32BIT_PT)
1160 cMaxModifications = 4;
1161 else
1162 cMaxModifications = 24;
1163# else
1164 cMaxModifications = 48;
1165# endif
1166
1167 /*
1168 * Incremental page table updates should weigh more than random ones.
1169 * (Only applies when started from offset 0)
1170 */
1171 pVCpu->pgm.s.cPoolAccessHandler++;
1172 if ( pPage->GCPtrLastAccessHandlerRip >= pRegFrame->rip - 0x40 /* observed loops in Windows 7 x64 */
1173 && pPage->GCPtrLastAccessHandlerRip < pRegFrame->rip + 0x40
1174 && pvFault == (pPage->GCPtrLastAccessHandlerFault + pDis->Param1.cb)
1175 && pVCpu->pgm.s.cPoolAccessHandler == pPage->cLastAccessHandler + 1)
1176 {
1177 Log(("Possible page reuse cMods=%d -> %d (locked=%d type=%s)\n", pPage->cModifications, pPage->cModifications * 2, pgmPoolIsPageLocked(pPage), pgmPoolPoolKindToStr(pPage->enmKind)));
1178 Assert(pPage->cModifications < 32000);
1179 pPage->cModifications = pPage->cModifications * 2;
1180 pPage->GCPtrLastAccessHandlerFault = pvFault;
1181 pPage->cLastAccessHandler = pVCpu->pgm.s.cPoolAccessHandler;
1182 if (pPage->cModifications >= cMaxModifications)
1183 {
1184 STAM_COUNTER_INC(&pPool->StatMonitorPfRZFlushReinit);
1185 fForcedFlush = true;
1186 }
1187 }
1188
1189 if (pPage->cModifications >= cMaxModifications)
1190 Log(("Mod overflow %RGv cMods=%d (locked=%d type=%s)\n", pvFault, pPage->cModifications, pgmPoolIsPageLocked(pPage), pgmPoolPoolKindToStr(pPage->enmKind)));
1191
1192 /*
1193 * Check if it's worth dealing with.
1194 */
1195 bool fReused = false;
1196 bool fNotReusedNotForking = false;
1197 if ( ( pPage->cModifications < cMaxModifications /** @todo \#define */ /** @todo need to check that it's not mapping EIP. */ /** @todo adjust this! */
1198 || pgmPoolIsPageLocked(pPage)
1199 )
1200 && !(fReused = pgmRZPoolMonitorIsReused(pVM, pVCpu, pRegFrame, pDis, pvFault, pPage))
1201 && !pgmRZPoolMonitorIsForking(pPool, pDis, GCPhysFault & PAGE_OFFSET_MASK))
1202 {
1203 /*
1204 * Simple instructions, no REP prefix.
1205 */
1206 if (!(pDis->fPrefix & (DISPREFIX_REP | DISPREFIX_REPNE)))
1207 {
1208 rc = pgmRZPoolAccessPfHandlerSimple(pVM, pVCpu, pPool, pPage, pDis, pRegFrame, GCPhysFault, pvFault, &fReused);
1209 if (fReused)
1210 goto flushPage;
1211
1212 /* A mov instruction to change the first page table entry will be remembered so we can detect
1213 * full page table changes early on. This will reduce the amount of unnecessary traps we'll take.
1214 */
1215 if ( rc == VINF_SUCCESS
1216 && !pPage->cLocked /* only applies to unlocked pages as we can't free locked ones (e.g. cr3 root). */
1217 && pDis->pCurInstr->uOpcode == OP_MOV
1218 && (pvFault & PAGE_OFFSET_MASK) == 0)
1219 {
1220 pPage->GCPtrLastAccessHandlerFault = pvFault;
1221 pPage->cLastAccessHandler = pVCpu->pgm.s.cPoolAccessHandler;
1222 pPage->GCPtrLastAccessHandlerRip = pRegFrame->rip;
1223 /* Make sure we don't kick out a page too quickly. */
1224 if (pPage->cModifications > 8)
1225 pPage->cModifications = 2;
1226 }
1227 else if (pPage->GCPtrLastAccessHandlerFault == pvFault)
1228 {
1229 /* ignore the 2nd write to this page table entry. */
1230 pPage->cLastAccessHandler = pVCpu->pgm.s.cPoolAccessHandler;
1231 }
1232 else
1233 {
1234 pPage->GCPtrLastAccessHandlerFault = NIL_RTGCPTR;
1235 pPage->GCPtrLastAccessHandlerRip = 0;
1236 }
1237
1238 STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->StatMonitorPfRZ, &pPool->StatMonitorPfRZHandled, a);
1239 pgmUnlock(pVM);
1240 return rc;
1241 }
1242
1243 /*
1244 * Windows is frequently doing small memset() operations (netio test 4k+).
1245 * We have to deal with these or we'll kill the cache and performance.
1246 */
1247 if ( pDis->pCurInstr->uOpcode == OP_STOSWD
1248 && !pRegFrame->eflags.Bits.u1DF
1249 && pDis->uOpMode == pDis->uCpuMode
1250 && pDis->uAddrMode == pDis->uCpuMode)
1251 {
1252 bool fValidStosd = false;
1253
1254 if ( pDis->uCpuMode == DISCPUMODE_32BIT
1255 && pDis->fPrefix == DISPREFIX_REP
1256 && pRegFrame->ecx <= 0x20
1257 && pRegFrame->ecx * 4 <= PAGE_SIZE - ((uintptr_t)pvFault & PAGE_OFFSET_MASK)
1258 && !((uintptr_t)pvFault & 3)
1259 && (pRegFrame->eax == 0 || pRegFrame->eax == 0x80) /* the two values observed. */
1260 )
1261 {
1262 fValidStosd = true;
1263 pRegFrame->rcx &= 0xffffffff; /* paranoia */
1264 }
1265 else
1266 if ( pDis->uCpuMode == DISCPUMODE_64BIT
1267 && pDis->fPrefix == (DISPREFIX_REP | DISPREFIX_REX)
1268 && pRegFrame->rcx <= 0x20
1269 && pRegFrame->rcx * 8 <= PAGE_SIZE - ((uintptr_t)pvFault & PAGE_OFFSET_MASK)
1270 && !((uintptr_t)pvFault & 7)
1271 && (pRegFrame->rax == 0 || pRegFrame->rax == 0x80) /* the two values observed. */
1272 )
1273 {
1274 fValidStosd = true;
1275 }
1276
1277 if (fValidStosd)
1278 {
1279 rc = pgmRZPoolAccessPfHandlerSTOSD(pVM, pPool, pPage, pDis, pRegFrame, GCPhysFault, pvFault);
1280 STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->StatMonitorPfRZ, &pPool->StatMonitorPfRZRepStosd, a);
1281 pgmUnlock(pVM);
1282 return rc;
1283 }
1284 }
1285
1286 /* REP prefix, don't bother. */
1287 STAM_COUNTER_INC(&pPool->StatMonitorPfRZRepPrefix);
1288 Log4(("pgmRZPoolAccessPfHandler: eax=%#x ecx=%#x edi=%#x esi=%#x rip=%RGv opcode=%d prefix=%#x\n",
1289 pRegFrame->eax, pRegFrame->ecx, pRegFrame->edi, pRegFrame->esi, (RTGCPTR)pRegFrame->rip, pDis->pCurInstr->uOpcode, pDis->fPrefix));
1290 fNotReusedNotForking = true;
1291 }
1292
1293# if defined(PGMPOOL_WITH_OPTIMIZED_DIRTY_PT) && defined(IN_RING0)
1294 /* E.g. Windows 7 x64 initializes page tables and touches some pages in the table during the process. This
1295 * leads to pgm pool trashing and an excessive amount of write faults due to page monitoring.
1296 */
1297 if ( pPage->cModifications >= cMaxModifications
1298 && !fForcedFlush
1299 && (pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT || pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_32BIT_PT)
1300 && ( fNotReusedNotForking
1301 || ( !pgmRZPoolMonitorIsReused(pVM, pVCpu, pRegFrame, pDis, pvFault, pPage)
1302 && !pgmRZPoolMonitorIsForking(pPool, pDis, GCPhysFault & PAGE_OFFSET_MASK))
1303 )
1304 )
1305 {
1306 Assert(!pgmPoolIsPageLocked(pPage));
1307 Assert(pPage->fDirty == false);
1308
1309 /* Flush any monitored duplicates as we will disable write protection. */
1310 if ( pPage->iMonitoredNext != NIL_PGMPOOL_IDX
1311 || pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
1312 {
1313 PPGMPOOLPAGE pPageHead = pPage;
1314
1315 /* Find the monitor head. */
1316 while (pPageHead->iMonitoredPrev != NIL_PGMPOOL_IDX)
1317 pPageHead = &pPool->aPages[pPageHead->iMonitoredPrev];
1318
1319 while (pPageHead)
1320 {
1321 unsigned idxNext = pPageHead->iMonitoredNext;
1322
1323 if (pPageHead != pPage)
1324 {
1325 STAM_COUNTER_INC(&pPool->StatDirtyPageDupFlush);
1326 Log(("Flush duplicate page idx=%d GCPhys=%RGp type=%s\n", pPageHead->idx, pPageHead->GCPhys, pgmPoolPoolKindToStr(pPageHead->enmKind)));
1327 int rc2 = pgmPoolFlushPage(pPool, pPageHead);
1328 AssertRC(rc2);
1329 }
1330
1331 if (idxNext == NIL_PGMPOOL_IDX)
1332 break;
1333
1334 pPageHead = &pPool->aPages[idxNext];
1335 }
1336 }
1337
1338 /* The flushing above might fail for locked pages, so double check. */
1339 if ( pPage->iMonitoredNext == NIL_PGMPOOL_IDX
1340 && pPage->iMonitoredPrev == NIL_PGMPOOL_IDX)
1341 {
1342 pgmPoolAddDirtyPage(pVM, pPool, pPage);
1343
1344 /* Temporarily allow write access to the page table again. */
1345 rc = PGMHandlerPhysicalPageTempOff(pVM, pPage->GCPhys & PAGE_BASE_GC_MASK, pPage->GCPhys & PAGE_BASE_GC_MASK);
1346 if (rc == VINF_SUCCESS)
1347 {
1348 rc = PGMShwMakePageWritable(pVCpu, pvFault, PGM_MK_PG_IS_WRITE_FAULT);
1349 AssertMsg(rc == VINF_SUCCESS
1350 /* In the SMP case the page table might be removed while we wait for the PGM lock in the trap handler. */
1351 || rc == VERR_PAGE_TABLE_NOT_PRESENT
1352 || rc == VERR_PAGE_NOT_PRESENT,
1353 ("PGMShwModifyPage -> GCPtr=%RGv rc=%d\n", pvFault, rc));
1354# ifdef VBOX_STRICT
1355 pPage->GCPtrDirtyFault = pvFault;
1356# endif
1357
1358 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pPool)->StatMonitorPfRZ, a);
1359 pgmUnlock(pVM);
1360 return rc;
1361 }
1362 }
1363 }
1364# endif /* PGMPOOL_WITH_OPTIMIZED_DIRTY_PT */
1365
1366 STAM_COUNTER_INC(&pPool->StatMonitorPfRZFlushModOverflow);
1367flushPage:
1368 /*
1369 * Not worth it, so flush it.
1370 *
1371 * If we considered it to be reused, don't go back to ring-3
1372 * to emulate failed instructions since we usually cannot
1373 * interpret then. This may be a bit risky, in which case
1374 * the reuse detection must be fixed.
1375 */
1376 rc = pgmRZPoolAccessPfHandlerFlush(pVM, pVCpu, pPool, pPage, pDis, pRegFrame, GCPhysFault, pvFault);
1377 if ( rc == VINF_EM_RAW_EMULATE_INSTR
1378 && fReused)
1379 {
1380 /* Make sure that the current instruction still has shadow page backing, otherwise we'll end up in a loop. */
1381 if (PGMShwGetPage(pVCpu, pRegFrame->rip, NULL, NULL) == VINF_SUCCESS)
1382 rc = VINF_SUCCESS; /* safe to restart the instruction. */
1383 }
1384 STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->StatMonitorPfRZ, &pPool->StatMonitorPfRZFlushPage, a);
1385 pgmUnlock(pVM);
1386 return rc;
1387}
1388
1389#endif /* !IN_RING3 */
1390
1391/**
1392 * @callback_method_impl{FNPGMPHYSHANDLER,
1393 * Access handler for shadowed page table pages.}
1394 *
1395 * @remarks Only uses the VINF_PGM_HANDLER_DO_DEFAULT status.
1396 */
1397PGM_ALL_CB2_DECL(VBOXSTRICTRC)
1398pgmPoolAccessHandler(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
1399 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
1400{
1401 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1402 STAM_PROFILE_START(&pPool->CTX_SUFF_Z(StatMonitor), a);
1403 PPGMPOOLPAGE pPage = (PPGMPOOLPAGE)pvUser;
1404 LogFlow(("PGM_ALL_CB_DECL: GCPhys=%RGp %p:{.Core=%RHp, .idx=%d, .GCPhys=%RGp, .enmType=%d}\n",
1405 GCPhys, pPage, pPage->Core.Key, pPage->idx, pPage->GCPhys, pPage->enmKind));
1406
1407 NOREF(pvPhys); NOREF(pvBuf); NOREF(enmAccessType);
1408
1409 pgmLock(pVM);
1410
1411#ifdef VBOX_WITH_STATISTICS
1412 /*
1413 * Collect stats on the access.
1414 */
1415 AssertCompile(RT_ELEMENTS(pPool->CTX_MID_Z(aStatMonitor,Sizes)) == 19);
1416 if (cbBuf <= 16 && cbBuf > 0)
1417 STAM_COUNTER_INC(&pPool->CTX_MID_Z(aStatMonitor,Sizes)[cbBuf - 1]);
1418 else if (cbBuf >= 17 && cbBuf < 32)
1419 STAM_COUNTER_INC(&pPool->CTX_MID_Z(aStatMonitor,Sizes)[16]);
1420 else if (cbBuf >= 32 && cbBuf < 64)
1421 STAM_COUNTER_INC(&pPool->CTX_MID_Z(aStatMonitor,Sizes)[17]);
1422 else if (cbBuf >= 64)
1423 STAM_COUNTER_INC(&pPool->CTX_MID_Z(aStatMonitor,Sizes)[18]);
1424
1425 uint8_t cbAlign;
1426 switch (pPage->enmKind)
1427 {
1428 default:
1429 cbAlign = 7;
1430 break;
1431 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1432 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1433 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1434 case PGMPOOLKIND_32BIT_PD:
1435 case PGMPOOLKIND_32BIT_PD_PHYS:
1436 cbAlign = 3;
1437 break;
1438 }
1439 AssertCompile(RT_ELEMENTS(pPool->CTX_MID_Z(aStatMonitor,Misaligned)) == 7);
1440 if ((uint8_t)GCPhys & cbAlign)
1441 STAM_COUNTER_INC(&pPool->CTX_MID_Z(aStatMonitor,Misaligned)[((uint8_t)GCPhys & cbAlign) - 1]);
1442#endif
1443
1444 /*
1445 * Make sure the pool page wasn't modified by a different CPU.
1446 */
1447 if (PHYS_PAGE_ADDRESS(GCPhys) == PHYS_PAGE_ADDRESS(pPage->GCPhys))
1448 {
1449 Assert(pPage->enmKind != PGMPOOLKIND_FREE);
1450
1451 /* The max modification count before flushing depends on the context and page type. */
1452#ifdef IN_RING3
1453 uint16_t const cMaxModifications = 96; /* it's cheaper here, right? */
1454#else
1455 uint16_t cMaxModifications;
1456 if ( pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT
1457 || pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_32BIT_PT)
1458 cMaxModifications = 4;
1459 else
1460 cMaxModifications = 24;
1461# ifdef IN_RC
1462 cMaxModifications *= 2; /* traps are cheaper than exists. */
1463# endif
1464#endif
1465
1466 /*
1467 * We don't have to be very sophisticated about this since there are relativly few calls here.
1468 * However, we must try our best to detect any non-cpu accesses (disk / networking).
1469 */
1470 if ( ( pPage->cModifications < cMaxModifications
1471 || pgmPoolIsPageLocked(pPage) )
1472 && enmOrigin != PGMACCESSORIGIN_DEVICE
1473 && cbBuf <= 16)
1474 {
1475 /* Clear the shadow entry. */
1476 if (!pPage->cModifications++)
1477 pgmPoolMonitorModifiedInsert(pPool, pPage);
1478
1479 if (cbBuf <= 8)
1480 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhys, pvBuf, (uint32_t)cbBuf);
1481 else
1482 {
1483 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhys, pvBuf, 8);
1484 pgmPoolMonitorChainChanging(pVCpu, pPool, pPage, GCPhys + 8, (uint8_t *)pvBuf + 8, (uint32_t)cbBuf - 8);
1485 }
1486 }
1487 else
1488 {
1489 /* ASSUME that VERR_PGM_POOL_CLEARED can be ignored here and that FFs will deal with it in due time. */
1490 pgmPoolMonitorChainFlush(pPool, pPage);
1491 }
1492
1493 STAM_PROFILE_STOP_EX(&pPool->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,FlushPage), a);
1494 }
1495 else
1496 Log(("CPU%d: PGM_ALL_CB_DECL pgm pool page for %RGp changed (to %RGp) while waiting!\n", pVCpu->idCpu, PHYS_PAGE_ADDRESS(GCPhys), PHYS_PAGE_ADDRESS(pPage->GCPhys)));
1497 pgmUnlock(pVM);
1498 return VINF_PGM_HANDLER_DO_DEFAULT;
1499}
1500
1501
1502# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
1503
1504# if defined(VBOX_STRICT) && !defined(IN_RING3)
1505
1506/**
1507 * Check references to guest physical memory in a PAE / PAE page table.
1508 *
1509 * @param pPool The pool.
1510 * @param pPage The page.
1511 * @param pShwPT The shadow page table (mapping of the page).
1512 * @param pGstPT The guest page table.
1513 */
1514static void pgmPoolTrackCheckPTPaePae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMSHWPTPAE pShwPT, PCX86PTPAE pGstPT)
1515{
1516 unsigned cErrors = 0;
1517 int LastRc = -1; /* initialized to shut up gcc */
1518 unsigned LastPTE = ~0U; /* initialized to shut up gcc */
1519 RTHCPHYS LastHCPhys = NIL_RTHCPHYS; /* initialized to shut up gcc */
1520 PVM pVM = pPool->CTX_SUFF(pVM);
1521
1522#ifdef VBOX_STRICT
1523 for (unsigned i = 0; i < RT_MIN(RT_ELEMENTS(pShwPT->a), pPage->iFirstPresent); i++)
1524 AssertMsg(!PGMSHWPTEPAE_IS_P(pShwPT->a[i]), ("Unexpected PTE: idx=%d %RX64 (first=%d)\n", i, PGMSHWPTEPAE_GET_LOG(pShwPT->a[i]), pPage->iFirstPresent));
1525#endif
1526 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++)
1527 {
1528 if (PGMSHWPTEPAE_IS_P(pShwPT->a[i]))
1529 {
1530 RTHCPHYS HCPhys = NIL_RTHCPHYS;
1531 int rc = PGMPhysGCPhys2HCPhys(pVM, pGstPT->a[i].u & X86_PTE_PAE_PG_MASK, &HCPhys);
1532 if ( rc != VINF_SUCCESS
1533 || PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]) != HCPhys)
1534 {
1535 Log(("rc=%d idx=%d guest %RX64 shw=%RX64 vs %RHp\n", rc, i, pGstPT->a[i].u, PGMSHWPTEPAE_GET_LOG(pShwPT->a[i]), HCPhys));
1536 LastPTE = i;
1537 LastRc = rc;
1538 LastHCPhys = HCPhys;
1539 cErrors++;
1540
1541 RTHCPHYS HCPhysPT = NIL_RTHCPHYS;
1542 rc = PGMPhysGCPhys2HCPhys(pVM, pPage->GCPhys, &HCPhysPT);
1543 AssertRC(rc);
1544
1545 for (unsigned iPage = 0; iPage < pPool->cCurPages; iPage++)
1546 {
1547 PPGMPOOLPAGE pTempPage = &pPool->aPages[iPage];
1548
1549 if (pTempPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT)
1550 {
1551 PPGMSHWPTPAE pShwPT2 = (PPGMSHWPTPAE)PGMPOOL_PAGE_2_PTR(pVM, pTempPage);
1552
1553 for (unsigned j = 0; j < RT_ELEMENTS(pShwPT->a); j++)
1554 {
1555 if ( PGMSHWPTEPAE_IS_P_RW(pShwPT2->a[j])
1556 && PGMSHWPTEPAE_GET_HCPHYS(pShwPT2->a[j]) == HCPhysPT)
1557 {
1558 Log(("GCPhys=%RGp idx=%d %RX64 vs %RX64\n", pTempPage->GCPhys, j, PGMSHWPTEPAE_GET_LOG(pShwPT->a[j]), PGMSHWPTEPAE_GET_LOG(pShwPT2->a[j])));
1559 }
1560 }
1561
1562 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pShwPT2);
1563 }
1564 }
1565 }
1566 }
1567 }
1568 AssertMsg(!cErrors, ("cErrors=%d: last rc=%d idx=%d guest %RX64 shw=%RX64 vs %RHp\n", cErrors, LastRc, LastPTE, pGstPT->a[LastPTE].u, PGMSHWPTEPAE_GET_LOG(pShwPT->a[LastPTE]), LastHCPhys));
1569}
1570
1571
1572/**
1573 * Check references to guest physical memory in a PAE / 32-bit page table.
1574 *
1575 * @param pPool The pool.
1576 * @param pPage The page.
1577 * @param pShwPT The shadow page table (mapping of the page).
1578 * @param pGstPT The guest page table.
1579 */
1580static void pgmPoolTrackCheckPTPae32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMSHWPTPAE pShwPT, PCX86PT pGstPT)
1581{
1582 unsigned cErrors = 0;
1583 int LastRc = -1; /* initialized to shut up gcc */
1584 unsigned LastPTE = ~0U; /* initialized to shut up gcc */
1585 RTHCPHYS LastHCPhys = NIL_RTHCPHYS; /* initialized to shut up gcc */
1586 PVM pVM = pPool->CTX_SUFF(pVM);
1587
1588#ifdef VBOX_STRICT
1589 for (unsigned i = 0; i < RT_MIN(RT_ELEMENTS(pShwPT->a), pPage->iFirstPresent); i++)
1590 AssertMsg(!PGMSHWPTEPAE_IS_P(pShwPT->a[i]), ("Unexpected PTE: idx=%d %RX64 (first=%d)\n", i, PGMSHWPTEPAE_GET_LOG(pShwPT->a[i]), pPage->iFirstPresent));
1591#endif
1592 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++)
1593 {
1594 if (PGMSHWPTEPAE_IS_P(pShwPT->a[i]))
1595 {
1596 RTHCPHYS HCPhys = NIL_RTHCPHYS;
1597 int rc = PGMPhysGCPhys2HCPhys(pVM, pGstPT->a[i].u & X86_PTE_PG_MASK, &HCPhys);
1598 if ( rc != VINF_SUCCESS
1599 || PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]) != HCPhys)
1600 {
1601 Log(("rc=%d idx=%d guest %x shw=%RX64 vs %RHp\n", rc, i, pGstPT->a[i].u, PGMSHWPTEPAE_GET_LOG(pShwPT->a[i]), HCPhys));
1602 LastPTE = i;
1603 LastRc = rc;
1604 LastHCPhys = HCPhys;
1605 cErrors++;
1606
1607 RTHCPHYS HCPhysPT = NIL_RTHCPHYS;
1608 rc = PGMPhysGCPhys2HCPhys(pVM, pPage->GCPhys, &HCPhysPT);
1609 AssertRC(rc);
1610
1611 for (unsigned iPage = 0; iPage < pPool->cCurPages; iPage++)
1612 {
1613 PPGMPOOLPAGE pTempPage = &pPool->aPages[iPage];
1614
1615 if (pTempPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_32BIT_PT)
1616 {
1617 PPGMSHWPTPAE pShwPT2 = (PPGMSHWPTPAE)PGMPOOL_PAGE_2_PTR(pVM, pTempPage);
1618
1619 for (unsigned j = 0; j < RT_ELEMENTS(pShwPT->a); j++)
1620 {
1621 if ( PGMSHWPTEPAE_IS_P_RW(pShwPT2->a[j])
1622 && PGMSHWPTEPAE_GET_HCPHYS(pShwPT2->a[j]) == HCPhysPT)
1623 {
1624 Log(("GCPhys=%RGp idx=%d %RX64 vs %RX64\n", pTempPage->GCPhys, j, PGMSHWPTEPAE_GET_LOG(pShwPT->a[j]), PGMSHWPTEPAE_GET_LOG(pShwPT2->a[j])));
1625 }
1626 }
1627
1628 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pShwPT2);
1629 }
1630 }
1631 }
1632 }
1633 }
1634 AssertMsg(!cErrors, ("cErrors=%d: last rc=%d idx=%d guest %x shw=%RX64 vs %RHp\n", cErrors, LastRc, LastPTE, pGstPT->a[LastPTE].u, PGMSHWPTEPAE_GET_LOG(pShwPT->a[LastPTE]), LastHCPhys));
1635}
1636
1637# endif /* VBOX_STRICT && !IN_RING3 */
1638
1639/**
1640 * Clear references to guest physical memory in a PAE / PAE page table.
1641 *
1642 * @returns nr of changed PTEs
1643 * @param pPool The pool.
1644 * @param pPage The page.
1645 * @param pShwPT The shadow page table (mapping of the page).
1646 * @param pGstPT The guest page table.
1647 * @param pOldGstPT The old cached guest page table.
1648 * @param fAllowRemoval Bail out as soon as we encounter an invalid PTE
1649 * @param pfFlush Flush reused page table (out)
1650 */
1651DECLINLINE(unsigned) pgmPoolTrackFlushPTPaePae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMSHWPTPAE pShwPT, PCX86PTPAE pGstPT,
1652 PCX86PTPAE pOldGstPT, bool fAllowRemoval, bool *pfFlush)
1653{
1654 unsigned cChanged = 0;
1655
1656#ifdef VBOX_STRICT
1657 for (unsigned i = 0; i < RT_MIN(RT_ELEMENTS(pShwPT->a), pPage->iFirstPresent); i++)
1658 AssertMsg(!PGMSHWPTEPAE_IS_P(pShwPT->a[i]), ("Unexpected PTE: idx=%d %RX64 (first=%d)\n", i, PGMSHWPTEPAE_GET_LOG(pShwPT->a[i]), pPage->iFirstPresent));
1659#endif
1660 *pfFlush = false;
1661
1662 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++)
1663 {
1664 /* Check the new value written by the guest. If present and with a bogus physical address, then
1665 * it's fairly safe to assume the guest is reusing the PT.
1666 */
1667 if ( fAllowRemoval
1668 && pGstPT->a[i].n.u1Present)
1669 {
1670 if (!PGMPhysIsGCPhysValid(pPool->CTX_SUFF(pVM), pGstPT->a[i].u & X86_PTE_PAE_PG_MASK))
1671 {
1672 *pfFlush = true;
1673 return ++cChanged;
1674 }
1675 }
1676 if (PGMSHWPTEPAE_IS_P(pShwPT->a[i]))
1677 {
1678 /* If the old cached PTE is identical, then there's no need to flush the shadow copy. */
1679 if ((pGstPT->a[i].u & X86_PTE_PAE_PG_MASK) == (pOldGstPT->a[i].u & X86_PTE_PAE_PG_MASK))
1680 {
1681#ifdef VBOX_STRICT
1682 RTHCPHYS HCPhys = NIL_RTGCPHYS;
1683 int rc = PGMPhysGCPhys2HCPhys(pPool->CTX_SUFF(pVM), pGstPT->a[i].u & X86_PTE_PAE_PG_MASK, &HCPhys);
1684 AssertMsg(rc == VINF_SUCCESS && PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]) == HCPhys, ("rc=%d guest %RX64 old %RX64 shw=%RX64 vs %RHp\n", rc, pGstPT->a[i].u, pOldGstPT->a[i].u, PGMSHWPTEPAE_GET_LOG(pShwPT->a[i]), HCPhys));
1685#endif
1686 uint64_t uHostAttr = PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & (X86_PTE_P | X86_PTE_US | X86_PTE_A | X86_PTE_D | X86_PTE_G | X86_PTE_PAE_NX);
1687 bool fHostRW = !!(PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & X86_PTE_RW);
1688 uint64_t uGuestAttr = pGstPT->a[i].u & (X86_PTE_P | X86_PTE_US | X86_PTE_A | X86_PTE_D | X86_PTE_G | X86_PTE_PAE_NX);
1689 bool fGuestRW = !!(pGstPT->a[i].u & X86_PTE_RW);
1690
1691 if ( uHostAttr == uGuestAttr
1692 && fHostRW <= fGuestRW)
1693 continue;
1694 }
1695 cChanged++;
1696 /* Something was changed, so flush it. */
1697 Log4(("pgmPoolTrackDerefPTPaePae: i=%d pte=%RX64 hint=%RX64\n",
1698 i, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), pOldGstPT->a[i].u & X86_PTE_PAE_PG_MASK));
1699 pgmPoolTracDerefGCPhysHint(pPool, pPage, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), pOldGstPT->a[i].u & X86_PTE_PAE_PG_MASK, i);
1700 PGMSHWPTEPAE_ATOMIC_SET(pShwPT->a[i], 0);
1701 }
1702 }
1703 return cChanged;
1704}
1705
1706
1707/**
1708 * Clear references to guest physical memory in a PAE / PAE page table.
1709 *
1710 * @returns nr of changed PTEs
1711 * @param pPool The pool.
1712 * @param pPage The page.
1713 * @param pShwPT The shadow page table (mapping of the page).
1714 * @param pGstPT The guest page table.
1715 * @param pOldGstPT The old cached guest page table.
1716 * @param fAllowRemoval Bail out as soon as we encounter an invalid PTE
1717 * @param pfFlush Flush reused page table (out)
1718 */
1719DECLINLINE(unsigned) pgmPoolTrackFlushPTPae32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMSHWPTPAE pShwPT, PCX86PT pGstPT,
1720 PCX86PT pOldGstPT, bool fAllowRemoval, bool *pfFlush)
1721{
1722 unsigned cChanged = 0;
1723
1724#ifdef VBOX_STRICT
1725 for (unsigned i = 0; i < RT_MIN(RT_ELEMENTS(pShwPT->a), pPage->iFirstPresent); i++)
1726 AssertMsg(!PGMSHWPTEPAE_IS_P(pShwPT->a[i]), ("Unexpected PTE: idx=%d %RX64 (first=%d)\n", i, PGMSHWPTEPAE_GET_LOG(pShwPT->a[i]), pPage->iFirstPresent));
1727#endif
1728 *pfFlush = false;
1729
1730 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++)
1731 {
1732 /* Check the new value written by the guest. If present and with a bogus physical address, then
1733 * it's fairly safe to assume the guest is reusing the PT.
1734 */
1735 if ( fAllowRemoval
1736 && pGstPT->a[i].n.u1Present)
1737 {
1738 if (!PGMPhysIsGCPhysValid(pPool->CTX_SUFF(pVM), pGstPT->a[i].u & X86_PTE_PG_MASK))
1739 {
1740 *pfFlush = true;
1741 return ++cChanged;
1742 }
1743 }
1744 if (PGMSHWPTEPAE_IS_P(pShwPT->a[i]))
1745 {
1746 /* If the old cached PTE is identical, then there's no need to flush the shadow copy. */
1747 if ((pGstPT->a[i].u & X86_PTE_PG_MASK) == (pOldGstPT->a[i].u & X86_PTE_PG_MASK))
1748 {
1749#ifdef VBOX_STRICT
1750 RTHCPHYS HCPhys = NIL_RTGCPHYS;
1751 int rc = PGMPhysGCPhys2HCPhys(pPool->CTX_SUFF(pVM), pGstPT->a[i].u & X86_PTE_PG_MASK, &HCPhys);
1752 AssertMsg(rc == VINF_SUCCESS && PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]) == HCPhys, ("rc=%d guest %x old %x shw=%RX64 vs %RHp\n", rc, pGstPT->a[i].u, pOldGstPT->a[i].u, PGMSHWPTEPAE_GET_LOG(pShwPT->a[i]), HCPhys));
1753#endif
1754 uint64_t uHostAttr = PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & (X86_PTE_P | X86_PTE_US | X86_PTE_A | X86_PTE_D | X86_PTE_G);
1755 bool fHostRW = !!(PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & X86_PTE_RW);
1756 uint64_t uGuestAttr = pGstPT->a[i].u & (X86_PTE_P | X86_PTE_US | X86_PTE_A | X86_PTE_D | X86_PTE_G);
1757 bool fGuestRW = !!(pGstPT->a[i].u & X86_PTE_RW);
1758
1759 if ( uHostAttr == uGuestAttr
1760 && fHostRW <= fGuestRW)
1761 continue;
1762 }
1763 cChanged++;
1764 /* Something was changed, so flush it. */
1765 Log4(("pgmPoolTrackDerefPTPaePae: i=%d pte=%RX64 hint=%x\n",
1766 i, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), pOldGstPT->a[i].u & X86_PTE_PG_MASK));
1767 pgmPoolTracDerefGCPhysHint(pPool, pPage, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), pOldGstPT->a[i].u & X86_PTE_PG_MASK, i);
1768 PGMSHWPTEPAE_ATOMIC_SET(pShwPT->a[i], 0);
1769 }
1770 }
1771 return cChanged;
1772}
1773
1774
1775/**
1776 * Flush a dirty page
1777 *
1778 * @param pVM The cross context VM structure.
1779 * @param pPool The pool.
1780 * @param idxSlot Dirty array slot index
1781 * @param fAllowRemoval Allow a reused page table to be removed
1782 */
1783static void pgmPoolFlushDirtyPage(PVM pVM, PPGMPOOL pPool, unsigned idxSlot, bool fAllowRemoval = false)
1784{
1785 PPGMPOOLPAGE pPage;
1786 unsigned idxPage;
1787
1788 Assert(idxSlot < RT_ELEMENTS(pPool->aDirtyPages));
1789 if (pPool->aDirtyPages[idxSlot].uIdx == NIL_PGMPOOL_IDX)
1790 return;
1791
1792 idxPage = pPool->aDirtyPages[idxSlot].uIdx;
1793 AssertRelease(idxPage != NIL_PGMPOOL_IDX);
1794 pPage = &pPool->aPages[idxPage];
1795 Assert(pPage->idx == idxPage);
1796 Assert(pPage->iMonitoredNext == NIL_PGMPOOL_IDX && pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
1797
1798 AssertMsg(pPage->fDirty, ("Page %RGp (slot=%d) not marked dirty!", pPage->GCPhys, idxSlot));
1799 Log(("Flush dirty page %RGp cMods=%d\n", pPage->GCPhys, pPage->cModifications));
1800
1801#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
1802 PVMCPU pVCpu = VMMGetCpu(pVM);
1803 uint32_t iPrevSubset = PGMRZDynMapPushAutoSubset(pVCpu);
1804#endif
1805
1806 /* First write protect the page again to catch all write accesses. (before checking for changes -> SMP) */
1807 int rc = PGMHandlerPhysicalReset(pVM, pPage->GCPhys & PAGE_BASE_GC_MASK);
1808 Assert(rc == VINF_SUCCESS);
1809 pPage->fDirty = false;
1810
1811#ifdef VBOX_STRICT
1812 uint64_t fFlags = 0;
1813 RTHCPHYS HCPhys;
1814 rc = PGMShwGetPage(VMMGetCpu(pVM), pPage->GCPtrDirtyFault, &fFlags, &HCPhys);
1815 AssertMsg( ( rc == VINF_SUCCESS
1816 && (!(fFlags & X86_PTE_RW) || HCPhys != pPage->Core.Key))
1817 /* In the SMP case the page table might be removed while we wait for the PGM lock in the trap handler. */
1818 || rc == VERR_PAGE_TABLE_NOT_PRESENT
1819 || rc == VERR_PAGE_NOT_PRESENT,
1820 ("PGMShwGetPage -> GCPtr=%RGv rc=%d flags=%RX64\n", pPage->GCPtrDirtyFault, rc, fFlags));
1821#endif
1822
1823 /* Flush those PTEs that have changed. */
1824 STAM_PROFILE_START(&pPool->StatTrackDeref,a);
1825 void *pvShw = PGMPOOL_PAGE_2_PTR(pVM, pPage);
1826 void *pvGst;
1827 rc = PGM_GCPHYS_2_PTR_EX(pVM, pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
1828 bool fFlush;
1829 unsigned cChanges;
1830
1831 if (pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT)
1832 cChanges = pgmPoolTrackFlushPTPaePae(pPool, pPage, (PPGMSHWPTPAE)pvShw, (PCX86PTPAE)pvGst,
1833 (PCX86PTPAE)&pPool->aDirtyPages[idxSlot].aPage[0], fAllowRemoval, &fFlush);
1834 else
1835 cChanges = pgmPoolTrackFlushPTPae32Bit(pPool, pPage, (PPGMSHWPTPAE)pvShw, (PCX86PT)pvGst,
1836 (PCX86PT)&pPool->aDirtyPages[idxSlot].aPage[0], fAllowRemoval, &fFlush);
1837
1838 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvGst);
1839 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvShw);
1840 STAM_PROFILE_STOP(&pPool->StatTrackDeref,a);
1841 /* Note: we might want to consider keeping the dirty page active in case there were many changes. */
1842
1843 /* This page is likely to be modified again, so reduce the nr of modifications just a bit here. */
1844 Assert(pPage->cModifications);
1845 if (cChanges < 4)
1846 pPage->cModifications = 1; /* must use > 0 here */
1847 else
1848 pPage->cModifications = RT_MAX(1, pPage->cModifications / 2);
1849
1850 STAM_COUNTER_INC(&pPool->StatResetDirtyPages);
1851 if (pPool->cDirtyPages == RT_ELEMENTS(pPool->aDirtyPages))
1852 pPool->idxFreeDirtyPage = idxSlot;
1853
1854 pPool->cDirtyPages--;
1855 pPool->aDirtyPages[idxSlot].uIdx = NIL_PGMPOOL_IDX;
1856 Assert(pPool->cDirtyPages <= RT_ELEMENTS(pPool->aDirtyPages));
1857 if (fFlush)
1858 {
1859 Assert(fAllowRemoval);
1860 Log(("Flush reused page table!\n"));
1861 pgmPoolFlushPage(pPool, pPage);
1862 STAM_COUNTER_INC(&pPool->StatForceFlushReused);
1863 }
1864 else
1865 Log(("Removed dirty page %RGp cMods=%d cChanges=%d\n", pPage->GCPhys, pPage->cModifications, cChanges));
1866
1867#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
1868 PGMRZDynMapPopAutoSubset(pVCpu, iPrevSubset);
1869#endif
1870}
1871
1872
1873# ifndef IN_RING3
1874/**
1875 * Add a new dirty page
1876 *
1877 * @param pVM The cross context VM structure.
1878 * @param pPool The pool.
1879 * @param pPage The page.
1880 */
1881void pgmPoolAddDirtyPage(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1882{
1883 unsigned idxFree;
1884
1885 PGM_LOCK_ASSERT_OWNER(pVM);
1886 AssertCompile(RT_ELEMENTS(pPool->aDirtyPages) == 8 || RT_ELEMENTS(pPool->aDirtyPages) == 16);
1887 Assert(!pPage->fDirty);
1888
1889 idxFree = pPool->idxFreeDirtyPage;
1890 Assert(idxFree < RT_ELEMENTS(pPool->aDirtyPages));
1891 Assert(pPage->iMonitoredNext == NIL_PGMPOOL_IDX && pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
1892
1893 if (pPool->cDirtyPages >= RT_ELEMENTS(pPool->aDirtyPages))
1894 {
1895 STAM_COUNTER_INC(&pPool->StatDirtyPageOverFlowFlush);
1896 pgmPoolFlushDirtyPage(pVM, pPool, idxFree, true /* allow removal of reused page tables*/);
1897 }
1898 Assert(pPool->cDirtyPages < RT_ELEMENTS(pPool->aDirtyPages));
1899 AssertMsg(pPool->aDirtyPages[idxFree].uIdx == NIL_PGMPOOL_IDX, ("idxFree=%d cDirtyPages=%d\n", idxFree, pPool->cDirtyPages));
1900
1901 Log(("Add dirty page %RGp (slot=%d)\n", pPage->GCPhys, idxFree));
1902
1903 /*
1904 * Make a copy of the guest page table as we require valid GCPhys addresses
1905 * when removing references to physical pages.
1906 * (The HCPhys linear lookup is *extremely* expensive!)
1907 */
1908 void *pvGst;
1909 int rc = PGM_GCPHYS_2_PTR_EX(pVM, pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
1910 memcpy(&pPool->aDirtyPages[idxFree].aPage[0], pvGst, (pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT) ? PAGE_SIZE : PAGE_SIZE/2);
1911# ifdef VBOX_STRICT
1912 void *pvShw = PGMPOOL_PAGE_2_PTR(pVM, pPage);
1913 if (pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT)
1914 pgmPoolTrackCheckPTPaePae(pPool, pPage, (PPGMSHWPTPAE)pvShw, (PCX86PTPAE)pvGst);
1915 else
1916 pgmPoolTrackCheckPTPae32Bit(pPool, pPage, (PPGMSHWPTPAE)pvShw, (PCX86PT)pvGst);
1917 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvShw);
1918# endif
1919 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvGst);
1920
1921 STAM_COUNTER_INC(&pPool->StatDirtyPage);
1922 pPage->fDirty = true;
1923 pPage->idxDirtyEntry = (uint8_t)idxFree; Assert(pPage->idxDirtyEntry == idxFree);
1924 pPool->aDirtyPages[idxFree].uIdx = pPage->idx;
1925 pPool->cDirtyPages++;
1926
1927 pPool->idxFreeDirtyPage = (pPool->idxFreeDirtyPage + 1) & (RT_ELEMENTS(pPool->aDirtyPages) - 1);
1928 if ( pPool->cDirtyPages < RT_ELEMENTS(pPool->aDirtyPages)
1929 && pPool->aDirtyPages[pPool->idxFreeDirtyPage].uIdx != NIL_PGMPOOL_IDX)
1930 {
1931 unsigned i;
1932 for (i = 1; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
1933 {
1934 idxFree = (pPool->idxFreeDirtyPage + i) & (RT_ELEMENTS(pPool->aDirtyPages) - 1);
1935 if (pPool->aDirtyPages[idxFree].uIdx == NIL_PGMPOOL_IDX)
1936 {
1937 pPool->idxFreeDirtyPage = idxFree;
1938 break;
1939 }
1940 }
1941 Assert(i != RT_ELEMENTS(pPool->aDirtyPages));
1942 }
1943
1944 Assert(pPool->cDirtyPages == RT_ELEMENTS(pPool->aDirtyPages) || pPool->aDirtyPages[pPool->idxFreeDirtyPage].uIdx == NIL_PGMPOOL_IDX);
1945
1946 /*
1947 * Clear all references to this shadow table. See @bugref{7298}.
1948 */
1949 pgmPoolTrackClearPageUsers(pPool, pPage);
1950}
1951# endif /* !IN_RING3 */
1952
1953
1954/**
1955 * Check if the specified page is dirty (not write monitored)
1956 *
1957 * @return dirty or not
1958 * @param pVM The cross context VM structure.
1959 * @param GCPhys Guest physical address
1960 */
1961bool pgmPoolIsDirtyPage(PVM pVM, RTGCPHYS GCPhys)
1962{
1963 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1964 PGM_LOCK_ASSERT_OWNER(pVM);
1965 if (!pPool->cDirtyPages)
1966 return false;
1967
1968 GCPhys = GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK;
1969
1970 for (unsigned i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
1971 {
1972 if (pPool->aDirtyPages[i].uIdx != NIL_PGMPOOL_IDX)
1973 {
1974 PPGMPOOLPAGE pPage;
1975 unsigned idxPage = pPool->aDirtyPages[i].uIdx;
1976
1977 pPage = &pPool->aPages[idxPage];
1978 if (pPage->GCPhys == GCPhys)
1979 return true;
1980 }
1981 }
1982 return false;
1983}
1984
1985
1986/**
1987 * Reset all dirty pages by reinstating page monitoring.
1988 *
1989 * @param pVM The cross context VM structure.
1990 */
1991void pgmPoolResetDirtyPages(PVM pVM)
1992{
1993 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1994 PGM_LOCK_ASSERT_OWNER(pVM);
1995 Assert(pPool->cDirtyPages <= RT_ELEMENTS(pPool->aDirtyPages));
1996
1997 if (!pPool->cDirtyPages)
1998 return;
1999
2000 Log(("pgmPoolResetDirtyPages\n"));
2001 for (unsigned i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
2002 pgmPoolFlushDirtyPage(pVM, pPool, i, true /* allow removal of reused page tables*/);
2003
2004 pPool->idxFreeDirtyPage = 0;
2005 if ( pPool->cDirtyPages != RT_ELEMENTS(pPool->aDirtyPages)
2006 && pPool->aDirtyPages[pPool->idxFreeDirtyPage].uIdx != NIL_PGMPOOL_IDX)
2007 {
2008 unsigned i;
2009 for (i = 1; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
2010 {
2011 if (pPool->aDirtyPages[i].uIdx == NIL_PGMPOOL_IDX)
2012 {
2013 pPool->idxFreeDirtyPage = i;
2014 break;
2015 }
2016 }
2017 AssertMsg(i != RT_ELEMENTS(pPool->aDirtyPages), ("cDirtyPages %d", pPool->cDirtyPages));
2018 }
2019
2020 Assert(pPool->aDirtyPages[pPool->idxFreeDirtyPage].uIdx == NIL_PGMPOOL_IDX || pPool->cDirtyPages == RT_ELEMENTS(pPool->aDirtyPages));
2021 return;
2022}
2023
2024
2025/**
2026 * Invalidate the PT entry for the specified page
2027 *
2028 * @param pVM The cross context VM structure.
2029 * @param GCPtrPage Guest page to invalidate
2030 */
2031void pgmPoolResetDirtyPage(PVM pVM, RTGCPTR GCPtrPage)
2032{
2033 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2034 PGM_LOCK_ASSERT_OWNER(pVM);
2035 Assert(pPool->cDirtyPages <= RT_ELEMENTS(pPool->aDirtyPages));
2036
2037 if (!pPool->cDirtyPages)
2038 return;
2039
2040 Log(("pgmPoolResetDirtyPage %RGv\n", GCPtrPage)); RT_NOREF_PV(GCPtrPage);
2041 for (unsigned i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
2042 {
2043 }
2044}
2045
2046
2047/**
2048 * Reset all dirty pages by reinstating page monitoring.
2049 *
2050 * @param pVM The cross context VM structure.
2051 * @param GCPhysPT Physical address of the page table
2052 */
2053void pgmPoolInvalidateDirtyPage(PVM pVM, RTGCPHYS GCPhysPT)
2054{
2055 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2056 PGM_LOCK_ASSERT_OWNER(pVM);
2057 Assert(pPool->cDirtyPages <= RT_ELEMENTS(pPool->aDirtyPages));
2058 unsigned idxDirtyPage = RT_ELEMENTS(pPool->aDirtyPages);
2059
2060 if (!pPool->cDirtyPages)
2061 return;
2062
2063 GCPhysPT = GCPhysPT & ~(RTGCPHYS)PAGE_OFFSET_MASK;
2064
2065 for (unsigned i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
2066 {
2067 if (pPool->aDirtyPages[i].uIdx != NIL_PGMPOOL_IDX)
2068 {
2069 unsigned idxPage = pPool->aDirtyPages[i].uIdx;
2070
2071 PPGMPOOLPAGE pPage = &pPool->aPages[idxPage];
2072 if (pPage->GCPhys == GCPhysPT)
2073 {
2074 idxDirtyPage = i;
2075 break;
2076 }
2077 }
2078 }
2079
2080 if (idxDirtyPage != RT_ELEMENTS(pPool->aDirtyPages))
2081 {
2082 pgmPoolFlushDirtyPage(pVM, pPool, idxDirtyPage, true /* allow removal of reused page tables*/);
2083 if ( pPool->cDirtyPages != RT_ELEMENTS(pPool->aDirtyPages)
2084 && pPool->aDirtyPages[pPool->idxFreeDirtyPage].uIdx != NIL_PGMPOOL_IDX)
2085 {
2086 unsigned i;
2087 for (i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
2088 {
2089 if (pPool->aDirtyPages[i].uIdx == NIL_PGMPOOL_IDX)
2090 {
2091 pPool->idxFreeDirtyPage = i;
2092 break;
2093 }
2094 }
2095 AssertMsg(i != RT_ELEMENTS(pPool->aDirtyPages), ("cDirtyPages %d", pPool->cDirtyPages));
2096 }
2097 }
2098}
2099
2100# endif /* PGMPOOL_WITH_OPTIMIZED_DIRTY_PT */
2101
2102/**
2103 * Inserts a page into the GCPhys hash table.
2104 *
2105 * @param pPool The pool.
2106 * @param pPage The page.
2107 */
2108DECLINLINE(void) pgmPoolHashInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2109{
2110 Log3(("pgmPoolHashInsert: %RGp\n", pPage->GCPhys));
2111 Assert(pPage->GCPhys != NIL_RTGCPHYS); Assert(pPage->iNext == NIL_PGMPOOL_IDX);
2112 uint16_t iHash = PGMPOOL_HASH(pPage->GCPhys);
2113 pPage->iNext = pPool->aiHash[iHash];
2114 pPool->aiHash[iHash] = pPage->idx;
2115}
2116
2117
2118/**
2119 * Removes a page from the GCPhys hash table.
2120 *
2121 * @param pPool The pool.
2122 * @param pPage The page.
2123 */
2124DECLINLINE(void) pgmPoolHashRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2125{
2126 Log3(("pgmPoolHashRemove: %RGp\n", pPage->GCPhys));
2127 uint16_t iHash = PGMPOOL_HASH(pPage->GCPhys);
2128 if (pPool->aiHash[iHash] == pPage->idx)
2129 pPool->aiHash[iHash] = pPage->iNext;
2130 else
2131 {
2132 uint16_t iPrev = pPool->aiHash[iHash];
2133 for (;;)
2134 {
2135 const int16_t i = pPool->aPages[iPrev].iNext;
2136 if (i == pPage->idx)
2137 {
2138 pPool->aPages[iPrev].iNext = pPage->iNext;
2139 break;
2140 }
2141 if (i == NIL_PGMPOOL_IDX)
2142 {
2143 AssertReleaseMsgFailed(("GCPhys=%RGp idx=%d\n", pPage->GCPhys, pPage->idx));
2144 break;
2145 }
2146 iPrev = i;
2147 }
2148 }
2149 pPage->iNext = NIL_PGMPOOL_IDX;
2150}
2151
2152
2153/**
2154 * Frees up one cache page.
2155 *
2156 * @returns VBox status code.
2157 * @retval VINF_SUCCESS on success.
2158 * @param pPool The pool.
2159 * @param iUser The user index.
2160 */
2161static int pgmPoolCacheFreeOne(PPGMPOOL pPool, uint16_t iUser)
2162{
2163#ifndef IN_RC
2164 const PVM pVM = pPool->CTX_SUFF(pVM);
2165#endif
2166 Assert(pPool->iAgeHead != pPool->iAgeTail); /* We shouldn't be here if there < 2 cached entries! */
2167 STAM_COUNTER_INC(&pPool->StatCacheFreeUpOne);
2168
2169 /*
2170 * Select one page from the tail of the age list.
2171 */
2172 PPGMPOOLPAGE pPage;
2173 for (unsigned iLoop = 0; ; iLoop++)
2174 {
2175 uint16_t iToFree = pPool->iAgeTail;
2176 if (iToFree == iUser && iUser != NIL_PGMPOOL_IDX)
2177 iToFree = pPool->aPages[iToFree].iAgePrev;
2178/* This is the alternative to the SyncCR3 pgmPoolCacheUsed calls.
2179 if (pPool->aPages[iToFree].iUserHead != NIL_PGMPOOL_USER_INDEX)
2180 {
2181 uint16_t i = pPool->aPages[iToFree].iAgePrev;
2182 for (unsigned j = 0; j < 10 && i != NIL_PGMPOOL_USER_INDEX; j++, i = pPool->aPages[i].iAgePrev)
2183 {
2184 if (pPool->aPages[iToFree].iUserHead == NIL_PGMPOOL_USER_INDEX)
2185 continue;
2186 iToFree = i;
2187 break;
2188 }
2189 }
2190*/
2191 Assert(iToFree != iUser);
2192 AssertRelease(iToFree != NIL_PGMPOOL_IDX);
2193 pPage = &pPool->aPages[iToFree];
2194
2195 /*
2196 * Reject any attempts at flushing the currently active shadow CR3 mapping.
2197 * Call pgmPoolCacheUsed to move the page to the head of the age list.
2198 */
2199 if ( !pgmPoolIsPageLocked(pPage)
2200 && pPage->idx >= PGMPOOL_IDX_FIRST /* paranoia (#6349) */)
2201 break;
2202 LogFlow(("pgmPoolCacheFreeOne: refuse CR3 mapping\n"));
2203 pgmPoolCacheUsed(pPool, pPage);
2204 AssertLogRelReturn(iLoop < 8192, VERR_PGM_POOL_TOO_MANY_LOOPS);
2205 }
2206
2207 /*
2208 * Found a usable page, flush it and return.
2209 */
2210 int rc = pgmPoolFlushPage(pPool, pPage);
2211 /* This flush was initiated by us and not the guest, so explicitly flush the TLB. */
2212 /** @todo find out why this is necessary; pgmPoolFlushPage should trigger a flush if one is really needed. */
2213 if (rc == VINF_SUCCESS)
2214 PGM_INVL_ALL_VCPU_TLBS(pVM);
2215 return rc;
2216}
2217
2218
2219/**
2220 * Checks if a kind mismatch is really a page being reused
2221 * or if it's just normal remappings.
2222 *
2223 * @returns true if reused and the cached page (enmKind1) should be flushed
2224 * @returns false if not reused.
2225 * @param enmKind1 The kind of the cached page.
2226 * @param enmKind2 The kind of the requested page.
2227 */
2228static bool pgmPoolCacheReusedByKind(PGMPOOLKIND enmKind1, PGMPOOLKIND enmKind2)
2229{
2230 switch (enmKind1)
2231 {
2232 /*
2233 * Never reuse them. There is no remapping in non-paging mode.
2234 */
2235 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2236 case PGMPOOLKIND_32BIT_PD_PHYS:
2237 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2238 case PGMPOOLKIND_PAE_PD_PHYS:
2239 case PGMPOOLKIND_PAE_PDPT_PHYS:
2240 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2241 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2242 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2243 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2244 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2245 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT: /* never reuse them for other types */
2246 return false;
2247
2248 /*
2249 * It's perfectly fine to reuse these, except for PAE and non-paging stuff.
2250 */
2251 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2252 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2253 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2254 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2255 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2256 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2257 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2258 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2259 case PGMPOOLKIND_32BIT_PD:
2260 case PGMPOOLKIND_PAE_PDPT:
2261 switch (enmKind2)
2262 {
2263 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2264 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2265 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2266 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2267 case PGMPOOLKIND_64BIT_PML4:
2268 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2269 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2270 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2271 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2272 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2273 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2274 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2275 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2276 return true;
2277 default:
2278 return false;
2279 }
2280
2281 /*
2282 * It's perfectly fine to reuse these, except for PAE and non-paging stuff.
2283 */
2284 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2285 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2286 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2287 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2288 case PGMPOOLKIND_64BIT_PML4:
2289 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2290 switch (enmKind2)
2291 {
2292 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2293 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2294 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2295 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2296 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2297 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2298 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2299 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2300 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2301 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2302 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2303 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2304 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2305 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2306 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2307 return true;
2308 default:
2309 return false;
2310 }
2311
2312 /*
2313 * These cannot be flushed, and it's common to reuse the PDs as PTs.
2314 */
2315 case PGMPOOLKIND_ROOT_NESTED:
2316 return false;
2317
2318 default:
2319 AssertFatalMsgFailed(("enmKind1=%d\n", enmKind1));
2320 }
2321}
2322
2323
2324/**
2325 * Attempts to satisfy a pgmPoolAlloc request from the cache.
2326 *
2327 * @returns VBox status code.
2328 * @retval VINF_PGM_CACHED_PAGE on success.
2329 * @retval VERR_FILE_NOT_FOUND if not found.
2330 * @param pPool The pool.
2331 * @param GCPhys The GC physical address of the page we're gonna shadow.
2332 * @param enmKind The kind of mapping.
2333 * @param enmAccess Access type for the mapping (only relevant for big pages)
2334 * @param fA20Enabled Whether the CPU has the A20 gate enabled.
2335 * @param iUser The shadow page pool index of the user table. This is
2336 * NIL_PGMPOOL_IDX for root pages.
2337 * @param iUserTable The index into the user table (shadowed). Ignored if
2338 * root page
2339 * @param ppPage Where to store the pointer to the page.
2340 */
2341static int pgmPoolCacheAlloc(PPGMPOOL pPool, RTGCPHYS GCPhys, PGMPOOLKIND enmKind, PGMPOOLACCESS enmAccess, bool fA20Enabled,
2342 uint16_t iUser, uint32_t iUserTable, PPPGMPOOLPAGE ppPage)
2343{
2344 /*
2345 * Look up the GCPhys in the hash.
2346 */
2347 unsigned i = pPool->aiHash[PGMPOOL_HASH(GCPhys)];
2348 Log3(("pgmPoolCacheAlloc: %RGp kind %s iUser=%d iUserTable=%x SLOT=%d\n", GCPhys, pgmPoolPoolKindToStr(enmKind), iUser, iUserTable, i));
2349 if (i != NIL_PGMPOOL_IDX)
2350 {
2351 do
2352 {
2353 PPGMPOOLPAGE pPage = &pPool->aPages[i];
2354 Log4(("pgmPoolCacheAlloc: slot %d found page %RGp\n", i, pPage->GCPhys));
2355 if (pPage->GCPhys == GCPhys)
2356 {
2357 if ( (PGMPOOLKIND)pPage->enmKind == enmKind
2358 && (PGMPOOLACCESS)pPage->enmAccess == enmAccess
2359 && pPage->fA20Enabled == fA20Enabled)
2360 {
2361 /* Put it at the start of the use list to make sure pgmPoolTrackAddUser
2362 * doesn't flush it in case there are no more free use records.
2363 */
2364 pgmPoolCacheUsed(pPool, pPage);
2365
2366 int rc = VINF_SUCCESS;
2367 if (iUser != NIL_PGMPOOL_IDX)
2368 rc = pgmPoolTrackAddUser(pPool, pPage, iUser, iUserTable);
2369 if (RT_SUCCESS(rc))
2370 {
2371 Assert((PGMPOOLKIND)pPage->enmKind == enmKind);
2372 *ppPage = pPage;
2373 if (pPage->cModifications)
2374 pPage->cModifications = 1; /* reset counter (can't use 0, or else it will be reinserted in the modified list) */
2375 STAM_COUNTER_INC(&pPool->StatCacheHits);
2376 return VINF_PGM_CACHED_PAGE;
2377 }
2378 return rc;
2379 }
2380
2381 if ((PGMPOOLKIND)pPage->enmKind != enmKind)
2382 {
2383 /*
2384 * The kind is different. In some cases we should now flush the page
2385 * as it has been reused, but in most cases this is normal remapping
2386 * of PDs as PT or big pages using the GCPhys field in a slightly
2387 * different way than the other kinds.
2388 */
2389 if (pgmPoolCacheReusedByKind((PGMPOOLKIND)pPage->enmKind, enmKind))
2390 {
2391 STAM_COUNTER_INC(&pPool->StatCacheKindMismatches);
2392 pgmPoolFlushPage(pPool, pPage);
2393 break;
2394 }
2395 }
2396 }
2397
2398 /* next */
2399 i = pPage->iNext;
2400 } while (i != NIL_PGMPOOL_IDX);
2401 }
2402
2403 Log3(("pgmPoolCacheAlloc: Missed GCPhys=%RGp enmKind=%s\n", GCPhys, pgmPoolPoolKindToStr(enmKind)));
2404 STAM_COUNTER_INC(&pPool->StatCacheMisses);
2405 return VERR_FILE_NOT_FOUND;
2406}
2407
2408
2409/**
2410 * Inserts a page into the cache.
2411 *
2412 * @param pPool The pool.
2413 * @param pPage The cached page.
2414 * @param fCanBeCached Set if the page is fit for caching from the caller's point of view.
2415 */
2416static void pgmPoolCacheInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage, bool fCanBeCached)
2417{
2418 /*
2419 * Insert into the GCPhys hash if the page is fit for that.
2420 */
2421 Assert(!pPage->fCached);
2422 if (fCanBeCached)
2423 {
2424 pPage->fCached = true;
2425 pgmPoolHashInsert(pPool, pPage);
2426 Log3(("pgmPoolCacheInsert: Caching %p:{.Core=%RHp, .idx=%d, .enmKind=%s, GCPhys=%RGp}\n",
2427 pPage, pPage->Core.Key, pPage->idx, pgmPoolPoolKindToStr(pPage->enmKind), pPage->GCPhys));
2428 STAM_COUNTER_INC(&pPool->StatCacheCacheable);
2429 }
2430 else
2431 {
2432 Log3(("pgmPoolCacheInsert: Not caching %p:{.Core=%RHp, .idx=%d, .enmKind=%s, GCPhys=%RGp}\n",
2433 pPage, pPage->Core.Key, pPage->idx, pgmPoolPoolKindToStr(pPage->enmKind), pPage->GCPhys));
2434 STAM_COUNTER_INC(&pPool->StatCacheUncacheable);
2435 }
2436
2437 /*
2438 * Insert at the head of the age list.
2439 */
2440 pPage->iAgePrev = NIL_PGMPOOL_IDX;
2441 pPage->iAgeNext = pPool->iAgeHead;
2442 if (pPool->iAgeHead != NIL_PGMPOOL_IDX)
2443 pPool->aPages[pPool->iAgeHead].iAgePrev = pPage->idx;
2444 else
2445 pPool->iAgeTail = pPage->idx;
2446 pPool->iAgeHead = pPage->idx;
2447}
2448
2449
2450/**
2451 * Flushes a cached page.
2452 *
2453 * @param pPool The pool.
2454 * @param pPage The cached page.
2455 */
2456static void pgmPoolCacheFlushPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2457{
2458 Log3(("pgmPoolCacheFlushPage: %RGp\n", pPage->GCPhys));
2459
2460 /*
2461 * Remove the page from the hash.
2462 */
2463 if (pPage->fCached)
2464 {
2465 pPage->fCached = false;
2466 pgmPoolHashRemove(pPool, pPage);
2467 }
2468 else
2469 Assert(pPage->iNext == NIL_PGMPOOL_IDX);
2470
2471 /*
2472 * Remove it from the age list.
2473 */
2474 if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
2475 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
2476 else
2477 pPool->iAgeTail = pPage->iAgePrev;
2478 if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
2479 pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
2480 else
2481 pPool->iAgeHead = pPage->iAgeNext;
2482 pPage->iAgeNext = NIL_PGMPOOL_IDX;
2483 pPage->iAgePrev = NIL_PGMPOOL_IDX;
2484}
2485
2486
2487/**
2488 * Looks for pages sharing the monitor.
2489 *
2490 * @returns Pointer to the head page.
2491 * @returns NULL if not found.
2492 * @param pPool The Pool
2493 * @param pNewPage The page which is going to be monitored.
2494 */
2495static PPGMPOOLPAGE pgmPoolMonitorGetPageByGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pNewPage)
2496{
2497 /*
2498 * Look up the GCPhys in the hash.
2499 */
2500 RTGCPHYS GCPhys = pNewPage->GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK;
2501 unsigned i = pPool->aiHash[PGMPOOL_HASH(GCPhys)];
2502 if (i == NIL_PGMPOOL_IDX)
2503 return NULL;
2504 do
2505 {
2506 PPGMPOOLPAGE pPage = &pPool->aPages[i];
2507 if ( pPage->GCPhys - GCPhys < PAGE_SIZE
2508 && pPage != pNewPage)
2509 {
2510 switch (pPage->enmKind)
2511 {
2512 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2513 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2514 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2515 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2516 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2517 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2518 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2519 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2520 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2521 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2522 case PGMPOOLKIND_64BIT_PML4:
2523 case PGMPOOLKIND_32BIT_PD:
2524 case PGMPOOLKIND_PAE_PDPT:
2525 {
2526 /* find the head */
2527 while (pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
2528 {
2529 Assert(pPage->iMonitoredPrev != pPage->idx);
2530 pPage = &pPool->aPages[pPage->iMonitoredPrev];
2531 }
2532 return pPage;
2533 }
2534
2535 /* ignore, no monitoring. */
2536 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2537 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2538 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2539 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2540 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2541 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2542 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2543 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2544 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2545 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2546 case PGMPOOLKIND_ROOT_NESTED:
2547 case PGMPOOLKIND_PAE_PD_PHYS:
2548 case PGMPOOLKIND_PAE_PDPT_PHYS:
2549 case PGMPOOLKIND_32BIT_PD_PHYS:
2550 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
2551 break;
2552 default:
2553 AssertFatalMsgFailed(("enmKind=%d idx=%d\n", pPage->enmKind, pPage->idx));
2554 }
2555 }
2556
2557 /* next */
2558 i = pPage->iNext;
2559 } while (i != NIL_PGMPOOL_IDX);
2560 return NULL;
2561}
2562
2563
2564/**
2565 * Enabled write monitoring of a guest page.
2566 *
2567 * @returns VBox status code.
2568 * @retval VINF_SUCCESS on success.
2569 * @param pPool The pool.
2570 * @param pPage The cached page.
2571 */
2572static int pgmPoolMonitorInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2573{
2574 LogFlow(("pgmPoolMonitorInsert %RGp\n", pPage->GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK));
2575
2576 /*
2577 * Filter out the relevant kinds.
2578 */
2579 switch (pPage->enmKind)
2580 {
2581 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2582 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2583 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2584 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2585 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2586 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2587 case PGMPOOLKIND_64BIT_PML4:
2588 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2589 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2590 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2591 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2592 case PGMPOOLKIND_32BIT_PD:
2593 case PGMPOOLKIND_PAE_PDPT:
2594 break;
2595
2596 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2597 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2598 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2599 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2600 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2601 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2602 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2603 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2604 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2605 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2606 case PGMPOOLKIND_ROOT_NESTED:
2607 /* Nothing to monitor here. */
2608 return VINF_SUCCESS;
2609
2610 case PGMPOOLKIND_32BIT_PD_PHYS:
2611 case PGMPOOLKIND_PAE_PDPT_PHYS:
2612 case PGMPOOLKIND_PAE_PD_PHYS:
2613 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
2614 /* Nothing to monitor here. */
2615 return VINF_SUCCESS;
2616 default:
2617 AssertFatalMsgFailed(("This can't happen! enmKind=%d\n", pPage->enmKind));
2618 }
2619
2620 /*
2621 * Install handler.
2622 */
2623 int rc;
2624 PPGMPOOLPAGE pPageHead = pgmPoolMonitorGetPageByGCPhys(pPool, pPage);
2625 if (pPageHead)
2626 {
2627 Assert(pPageHead != pPage); Assert(pPageHead->iMonitoredNext != pPage->idx);
2628 Assert(pPageHead->iMonitoredPrev != pPage->idx);
2629
2630#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
2631 if (pPageHead->fDirty)
2632 pgmPoolFlushDirtyPage(pPool->CTX_SUFF(pVM), pPool, pPageHead->idxDirtyEntry, false /* do not remove */);
2633#endif
2634
2635 pPage->iMonitoredPrev = pPageHead->idx;
2636 pPage->iMonitoredNext = pPageHead->iMonitoredNext;
2637 if (pPageHead->iMonitoredNext != NIL_PGMPOOL_IDX)
2638 pPool->aPages[pPageHead->iMonitoredNext].iMonitoredPrev = pPage->idx;
2639 pPageHead->iMonitoredNext = pPage->idx;
2640 rc = VINF_SUCCESS;
2641 }
2642 else
2643 {
2644 Assert(pPage->iMonitoredNext == NIL_PGMPOOL_IDX); Assert(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
2645 PVM pVM = pPool->CTX_SUFF(pVM);
2646 const RTGCPHYS GCPhysPage = pPage->GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK;
2647 rc = PGMHandlerPhysicalRegister(pVM, GCPhysPage, GCPhysPage + PAGE_OFFSET_MASK, pPool->hAccessHandlerType,
2648 MMHyperCCToR3(pVM, pPage), MMHyperCCToR0(pVM, pPage), MMHyperCCToRC(pVM, pPage),
2649 NIL_RTR3PTR /*pszDesc*/);
2650 /** @todo we should probably deal with out-of-memory conditions here, but for now increasing
2651 * the heap size should suffice. */
2652 AssertFatalMsgRC(rc, ("PGMHandlerPhysicalRegisterEx %RGp failed with %Rrc\n", GCPhysPage, rc));
2653 PVMCPU pVCpu = VMMGetCpu(pVM);
2654 AssertFatalMsg(!(pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL) || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3), ("fSyncFlags=%x syncff=%d\n", pVCpu->pgm.s.fSyncFlags, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3)));
2655 }
2656 pPage->fMonitored = true;
2657 return rc;
2658}
2659
2660
2661/**
2662 * Disables write monitoring of a guest page.
2663 *
2664 * @returns VBox status code.
2665 * @retval VINF_SUCCESS on success.
2666 * @param pPool The pool.
2667 * @param pPage The cached page.
2668 */
2669static int pgmPoolMonitorFlush(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2670{
2671 /*
2672 * Filter out the relevant kinds.
2673 */
2674 switch (pPage->enmKind)
2675 {
2676 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2677 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2678 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2679 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2680 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
2681 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2682 case PGMPOOLKIND_64BIT_PML4:
2683 case PGMPOOLKIND_32BIT_PD:
2684 case PGMPOOLKIND_PAE_PDPT:
2685 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
2686 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
2687 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
2688 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
2689 break;
2690
2691 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2692 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2693 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2694 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2695 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2696 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
2697 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
2698 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
2699 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
2700 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
2701 case PGMPOOLKIND_ROOT_NESTED:
2702 case PGMPOOLKIND_PAE_PD_PHYS:
2703 case PGMPOOLKIND_PAE_PDPT_PHYS:
2704 case PGMPOOLKIND_32BIT_PD_PHYS:
2705 /* Nothing to monitor here. */
2706 Assert(!pPage->fMonitored);
2707 return VINF_SUCCESS;
2708
2709 default:
2710 AssertFatalMsgFailed(("This can't happen! enmKind=%d\n", pPage->enmKind));
2711 }
2712 Assert(pPage->fMonitored);
2713
2714 /*
2715 * Remove the page from the monitored list or uninstall it if last.
2716 */
2717 const PVM pVM = pPool->CTX_SUFF(pVM);
2718 int rc;
2719 if ( pPage->iMonitoredNext != NIL_PGMPOOL_IDX
2720 || pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
2721 {
2722 if (pPage->iMonitoredPrev == NIL_PGMPOOL_IDX)
2723 {
2724 PPGMPOOLPAGE pNewHead = &pPool->aPages[pPage->iMonitoredNext];
2725 pNewHead->iMonitoredPrev = NIL_PGMPOOL_IDX;
2726 rc = PGMHandlerPhysicalChangeUserArgs(pVM, pPage->GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK, MMHyperCCToR3(pVM, pNewHead),
2727 MMHyperCCToR0(pVM, pNewHead), MMHyperCCToRC(pVM, pNewHead));
2728
2729 AssertFatalRCSuccess(rc);
2730 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
2731 }
2732 else
2733 {
2734 pPool->aPages[pPage->iMonitoredPrev].iMonitoredNext = pPage->iMonitoredNext;
2735 if (pPage->iMonitoredNext != NIL_PGMPOOL_IDX)
2736 {
2737 pPool->aPages[pPage->iMonitoredNext].iMonitoredPrev = pPage->iMonitoredPrev;
2738 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
2739 }
2740 pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
2741 rc = VINF_SUCCESS;
2742 }
2743 }
2744 else
2745 {
2746 rc = PGMHandlerPhysicalDeregister(pVM, pPage->GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK);
2747 AssertFatalRC(rc);
2748 PVMCPU pVCpu = VMMGetCpu(pVM);
2749 AssertFatalMsg(!(pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL) || VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3),
2750 ("%#x %#x\n", pVCpu->pgm.s.fSyncFlags, pVM->fGlobalForcedActions));
2751 }
2752 pPage->fMonitored = false;
2753
2754 /*
2755 * Remove it from the list of modified pages (if in it).
2756 */
2757 pgmPoolMonitorModifiedRemove(pPool, pPage);
2758
2759 return rc;
2760}
2761
2762
2763/**
2764 * Inserts the page into the list of modified pages.
2765 *
2766 * @param pPool The pool.
2767 * @param pPage The page.
2768 */
2769void pgmPoolMonitorModifiedInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2770{
2771 Log3(("pgmPoolMonitorModifiedInsert: idx=%d\n", pPage->idx));
2772 AssertMsg( pPage->iModifiedNext == NIL_PGMPOOL_IDX
2773 && pPage->iModifiedPrev == NIL_PGMPOOL_IDX
2774 && pPool->iModifiedHead != pPage->idx,
2775 ("Next=%d Prev=%d idx=%d cModifications=%d Head=%d cModifiedPages=%d\n",
2776 pPage->iModifiedNext, pPage->iModifiedPrev, pPage->idx, pPage->cModifications,
2777 pPool->iModifiedHead, pPool->cModifiedPages));
2778
2779 pPage->iModifiedNext = pPool->iModifiedHead;
2780 if (pPool->iModifiedHead != NIL_PGMPOOL_IDX)
2781 pPool->aPages[pPool->iModifiedHead].iModifiedPrev = pPage->idx;
2782 pPool->iModifiedHead = pPage->idx;
2783 pPool->cModifiedPages++;
2784#ifdef VBOX_WITH_STATISTICS
2785 if (pPool->cModifiedPages > pPool->cModifiedPagesHigh)
2786 pPool->cModifiedPagesHigh = pPool->cModifiedPages;
2787#endif
2788}
2789
2790
2791/**
2792 * Removes the page from the list of modified pages and resets the
2793 * modification counter.
2794 *
2795 * @param pPool The pool.
2796 * @param pPage The page which is believed to be in the list of modified pages.
2797 */
2798static void pgmPoolMonitorModifiedRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2799{
2800 Log3(("pgmPoolMonitorModifiedRemove: idx=%d cModifications=%d\n", pPage->idx, pPage->cModifications));
2801 if (pPool->iModifiedHead == pPage->idx)
2802 {
2803 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX);
2804 pPool->iModifiedHead = pPage->iModifiedNext;
2805 if (pPage->iModifiedNext != NIL_PGMPOOL_IDX)
2806 {
2807 pPool->aPages[pPage->iModifiedNext].iModifiedPrev = NIL_PGMPOOL_IDX;
2808 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
2809 }
2810 pPool->cModifiedPages--;
2811 }
2812 else if (pPage->iModifiedPrev != NIL_PGMPOOL_IDX)
2813 {
2814 pPool->aPages[pPage->iModifiedPrev].iModifiedNext = pPage->iModifiedNext;
2815 if (pPage->iModifiedNext != NIL_PGMPOOL_IDX)
2816 {
2817 pPool->aPages[pPage->iModifiedNext].iModifiedPrev = pPage->iModifiedPrev;
2818 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
2819 }
2820 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
2821 pPool->cModifiedPages--;
2822 }
2823 else
2824 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX);
2825 pPage->cModifications = 0;
2826}
2827
2828
2829/**
2830 * Zaps the list of modified pages, resetting their modification counters in the process.
2831 *
2832 * @param pVM The cross context VM structure.
2833 */
2834static void pgmPoolMonitorModifiedClearAll(PVM pVM)
2835{
2836 pgmLock(pVM);
2837 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2838 LogFlow(("pgmPoolMonitorModifiedClearAll: cModifiedPages=%d\n", pPool->cModifiedPages));
2839
2840 unsigned cPages = 0; NOREF(cPages);
2841
2842#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
2843 pgmPoolResetDirtyPages(pVM);
2844#endif
2845
2846 uint16_t idx = pPool->iModifiedHead;
2847 pPool->iModifiedHead = NIL_PGMPOOL_IDX;
2848 while (idx != NIL_PGMPOOL_IDX)
2849 {
2850 PPGMPOOLPAGE pPage = &pPool->aPages[idx];
2851 idx = pPage->iModifiedNext;
2852 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
2853 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
2854 pPage->cModifications = 0;
2855 Assert(++cPages);
2856 }
2857 AssertMsg(cPages == pPool->cModifiedPages, ("%d != %d\n", cPages, pPool->cModifiedPages));
2858 pPool->cModifiedPages = 0;
2859 pgmUnlock(pVM);
2860}
2861
2862
2863/**
2864 * Handle SyncCR3 pool tasks
2865 *
2866 * @returns VBox status code.
2867 * @retval VINF_SUCCESS if successfully added.
2868 * @retval VINF_PGM_SYNC_CR3 is it needs to be deferred to ring 3 (GC only)
2869 * @param pVCpu The cross context virtual CPU structure.
2870 * @remark Should only be used when monitoring is available, thus placed in
2871 * the PGMPOOL_WITH_MONITORING \#ifdef.
2872 */
2873int pgmPoolSyncCR3(PVMCPU pVCpu)
2874{
2875 PVM pVM = pVCpu->CTX_SUFF(pVM);
2876 LogFlow(("pgmPoolSyncCR3 fSyncFlags=%x\n", pVCpu->pgm.s.fSyncFlags));
2877
2878 /*
2879 * When monitoring shadowed pages, we reset the modification counters on CR3 sync.
2880 * Occasionally we will have to clear all the shadow page tables because we wanted
2881 * to monitor a page which was mapped by too many shadowed page tables. This operation
2882 * sometimes referred to as a 'lightweight flush'.
2883 */
2884# ifdef IN_RING3 /* Don't flush in ring-0 or raw mode, it's taking too long. */
2885 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)
2886 pgmR3PoolClearAll(pVM, false /*fFlushRemTlb*/);
2887# else /* !IN_RING3 */
2888 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)
2889 {
2890 Log(("SyncCR3: PGM_SYNC_CLEAR_PGM_POOL is set -> VINF_PGM_SYNC_CR3\n"));
2891 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3); /** @todo no need to do global sync, right? */
2892
2893 /* Make sure all other VCPUs return to ring 3. */
2894 if (pVM->cCpus > 1)
2895 {
2896 VM_FF_SET(pVM, VM_FF_PGM_POOL_FLUSH_PENDING);
2897 PGM_INVL_ALL_VCPU_TLBS(pVM);
2898 }
2899 return VINF_PGM_SYNC_CR3;
2900 }
2901# endif /* !IN_RING3 */
2902 else
2903 {
2904 pgmPoolMonitorModifiedClearAll(pVM);
2905
2906 /* pgmPoolMonitorModifiedClearAll can cause a pgm pool flush (dirty page clearing), so make sure we handle this! */
2907 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)
2908 {
2909 Log(("pgmPoolMonitorModifiedClearAll caused a pgm flush -> call pgmPoolSyncCR3 again!\n"));
2910 return pgmPoolSyncCR3(pVCpu);
2911 }
2912 }
2913 return VINF_SUCCESS;
2914}
2915
2916
2917/**
2918 * Frees up at least one user entry.
2919 *
2920 * @returns VBox status code.
2921 * @retval VINF_SUCCESS if successfully added.
2922 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
2923 * @param pPool The pool.
2924 * @param iUser The user index.
2925 */
2926static int pgmPoolTrackFreeOneUser(PPGMPOOL pPool, uint16_t iUser)
2927{
2928 STAM_COUNTER_INC(&pPool->StatTrackFreeUpOneUser);
2929 /*
2930 * Just free cached pages in a braindead fashion.
2931 */
2932 /** @todo walk the age list backwards and free the first with usage. */
2933 int rc = VINF_SUCCESS;
2934 do
2935 {
2936 int rc2 = pgmPoolCacheFreeOne(pPool, iUser);
2937 if (RT_FAILURE(rc2) && rc == VINF_SUCCESS)
2938 rc = rc2;
2939 } while (pPool->iUserFreeHead == NIL_PGMPOOL_USER_INDEX);
2940 return rc;
2941}
2942
2943
2944/**
2945 * Inserts a page into the cache.
2946 *
2947 * This will create user node for the page, insert it into the GCPhys
2948 * hash, and insert it into the age list.
2949 *
2950 * @returns VBox status code.
2951 * @retval VINF_SUCCESS if successfully added.
2952 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
2953 * @param pPool The pool.
2954 * @param pPage The cached page.
2955 * @param GCPhys The GC physical address of the page we're gonna shadow.
2956 * @param iUser The user index.
2957 * @param iUserTable The user table index.
2958 */
2959DECLINLINE(int) pgmPoolTrackInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTGCPHYS GCPhys, uint16_t iUser, uint32_t iUserTable)
2960{
2961 int rc = VINF_SUCCESS;
2962 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
2963
2964 LogFlow(("pgmPoolTrackInsert GCPhys=%RGp iUser=%d iUserTable=%x\n", GCPhys, iUser, iUserTable)); RT_NOREF_PV(GCPhys);
2965
2966 if (iUser != NIL_PGMPOOL_IDX)
2967 {
2968#ifdef VBOX_STRICT
2969 /*
2970 * Check that the entry doesn't already exists.
2971 */
2972 if (pPage->iUserHead != NIL_PGMPOOL_USER_INDEX)
2973 {
2974 uint16_t i = pPage->iUserHead;
2975 do
2976 {
2977 Assert(i < pPool->cMaxUsers);
2978 AssertMsg(paUsers[i].iUser != iUser || paUsers[i].iUserTable != iUserTable, ("%x %x vs new %x %x\n", paUsers[i].iUser, paUsers[i].iUserTable, iUser, iUserTable));
2979 i = paUsers[i].iNext;
2980 } while (i != NIL_PGMPOOL_USER_INDEX);
2981 }
2982#endif
2983
2984 /*
2985 * Find free a user node.
2986 */
2987 uint16_t i = pPool->iUserFreeHead;
2988 if (i == NIL_PGMPOOL_USER_INDEX)
2989 {
2990 rc = pgmPoolTrackFreeOneUser(pPool, iUser);
2991 if (RT_FAILURE(rc))
2992 return rc;
2993 i = pPool->iUserFreeHead;
2994 }
2995
2996 /*
2997 * Unlink the user node from the free list,
2998 * initialize and insert it into the user list.
2999 */
3000 pPool->iUserFreeHead = paUsers[i].iNext;
3001 paUsers[i].iNext = NIL_PGMPOOL_USER_INDEX;
3002 paUsers[i].iUser = iUser;
3003 paUsers[i].iUserTable = iUserTable;
3004 pPage->iUserHead = i;
3005 }
3006 else
3007 pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
3008
3009
3010 /*
3011 * Insert into cache and enable monitoring of the guest page if enabled.
3012 *
3013 * Until we implement caching of all levels, including the CR3 one, we'll
3014 * have to make sure we don't try monitor & cache any recursive reuse of
3015 * a monitored CR3 page. Because all windows versions are doing this we'll
3016 * have to be able to do combined access monitoring, CR3 + PT and
3017 * PD + PT (guest PAE).
3018 *
3019 * Update:
3020 * We're now cooperating with the CR3 monitor if an uncachable page is found.
3021 */
3022 const bool fCanBeMonitored = true;
3023 pgmPoolCacheInsert(pPool, pPage, fCanBeMonitored); /* This can be expanded. */
3024 if (fCanBeMonitored)
3025 {
3026 rc = pgmPoolMonitorInsert(pPool, pPage);
3027 AssertRC(rc);
3028 }
3029 return rc;
3030}
3031
3032
3033/**
3034 * Adds a user reference to a page.
3035 *
3036 * This will move the page to the head of the
3037 *
3038 * @returns VBox status code.
3039 * @retval VINF_SUCCESS if successfully added.
3040 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
3041 * @param pPool The pool.
3042 * @param pPage The cached page.
3043 * @param iUser The user index.
3044 * @param iUserTable The user table.
3045 */
3046static int pgmPoolTrackAddUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable)
3047{
3048 Log3(("pgmPoolTrackAddUser: GCPhys=%RGp iUser=%x iUserTable=%x\n", pPage->GCPhys, iUser, iUserTable));
3049 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
3050 Assert(iUser != NIL_PGMPOOL_IDX);
3051
3052# ifdef VBOX_STRICT
3053 /*
3054 * Check that the entry doesn't already exists. We only allow multiple
3055 * users of top-level paging structures (SHW_POOL_ROOT_IDX).
3056 */
3057 if (pPage->iUserHead != NIL_PGMPOOL_USER_INDEX)
3058 {
3059 uint16_t i = pPage->iUserHead;
3060 do
3061 {
3062 Assert(i < pPool->cMaxUsers);
3063 /** @todo this assertion looks odd... Shouldn't it be && here? */
3064 AssertMsg(paUsers[i].iUser != iUser || paUsers[i].iUserTable != iUserTable, ("%x %x vs new %x %x\n", paUsers[i].iUser, paUsers[i].iUserTable, iUser, iUserTable));
3065 i = paUsers[i].iNext;
3066 } while (i != NIL_PGMPOOL_USER_INDEX);
3067 }
3068# endif
3069
3070 /*
3071 * Allocate a user node.
3072 */
3073 uint16_t i = pPool->iUserFreeHead;
3074 if (i == NIL_PGMPOOL_USER_INDEX)
3075 {
3076 int rc = pgmPoolTrackFreeOneUser(pPool, iUser);
3077 if (RT_FAILURE(rc))
3078 return rc;
3079 i = pPool->iUserFreeHead;
3080 }
3081 pPool->iUserFreeHead = paUsers[i].iNext;
3082
3083 /*
3084 * Initialize the user node and insert it.
3085 */
3086 paUsers[i].iNext = pPage->iUserHead;
3087 paUsers[i].iUser = iUser;
3088 paUsers[i].iUserTable = iUserTable;
3089 pPage->iUserHead = i;
3090
3091# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
3092 if (pPage->fDirty)
3093 pgmPoolFlushDirtyPage(pPool->CTX_SUFF(pVM), pPool, pPage->idxDirtyEntry, false /* do not remove */);
3094# endif
3095
3096 /*
3097 * Tell the cache to update its replacement stats for this page.
3098 */
3099 pgmPoolCacheUsed(pPool, pPage);
3100 return VINF_SUCCESS;
3101}
3102
3103
3104/**
3105 * Frees a user record associated with a page.
3106 *
3107 * This does not clear the entry in the user table, it simply replaces the
3108 * user record to the chain of free records.
3109 *
3110 * @param pPool The pool.
3111 * @param pPage The shadow page.
3112 * @param iUser The shadow page pool index of the user table.
3113 * @param iUserTable The index into the user table (shadowed).
3114 *
3115 * @remarks Don't call this for root pages.
3116 */
3117static void pgmPoolTrackFreeUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable)
3118{
3119 Log3(("pgmPoolTrackFreeUser %RGp %x %x\n", pPage->GCPhys, iUser, iUserTable));
3120 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
3121 Assert(iUser != NIL_PGMPOOL_IDX);
3122
3123 /*
3124 * Unlink and free the specified user entry.
3125 */
3126
3127 /* Special: For PAE and 32-bit paging, there is usually no more than one user. */
3128 uint16_t i = pPage->iUserHead;
3129 if ( i != NIL_PGMPOOL_USER_INDEX
3130 && paUsers[i].iUser == iUser
3131 && paUsers[i].iUserTable == iUserTable)
3132 {
3133 pPage->iUserHead = paUsers[i].iNext;
3134
3135 paUsers[i].iUser = NIL_PGMPOOL_IDX;
3136 paUsers[i].iNext = pPool->iUserFreeHead;
3137 pPool->iUserFreeHead = i;
3138 return;
3139 }
3140
3141 /* General: Linear search. */
3142 uint16_t iPrev = NIL_PGMPOOL_USER_INDEX;
3143 while (i != NIL_PGMPOOL_USER_INDEX)
3144 {
3145 if ( paUsers[i].iUser == iUser
3146 && paUsers[i].iUserTable == iUserTable)
3147 {
3148 if (iPrev != NIL_PGMPOOL_USER_INDEX)
3149 paUsers[iPrev].iNext = paUsers[i].iNext;
3150 else
3151 pPage->iUserHead = paUsers[i].iNext;
3152
3153 paUsers[i].iUser = NIL_PGMPOOL_IDX;
3154 paUsers[i].iNext = pPool->iUserFreeHead;
3155 pPool->iUserFreeHead = i;
3156 return;
3157 }
3158 iPrev = i;
3159 i = paUsers[i].iNext;
3160 }
3161
3162 /* Fatal: didn't find it */
3163 AssertFatalMsgFailed(("Didn't find the user entry! iUser=%d iUserTable=%#x GCPhys=%RGp\n",
3164 iUser, iUserTable, pPage->GCPhys));
3165}
3166
3167
3168#if 0 /* unused */
3169/**
3170 * Gets the entry size of a shadow table.
3171 *
3172 * @param enmKind The kind of page.
3173 *
3174 * @returns The size of the entry in bytes. That is, 4 or 8.
3175 * @returns If the kind is not for a table, an assertion is raised and 0 is
3176 * returned.
3177 */
3178DECLINLINE(unsigned) pgmPoolTrackGetShadowEntrySize(PGMPOOLKIND enmKind)
3179{
3180 switch (enmKind)
3181 {
3182 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
3183 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
3184 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
3185 case PGMPOOLKIND_32BIT_PD:
3186 case PGMPOOLKIND_32BIT_PD_PHYS:
3187 return 4;
3188
3189 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
3190 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
3191 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
3192 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
3193 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
3194 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
3195 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
3196 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
3197 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
3198 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
3199 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
3200 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
3201 case PGMPOOLKIND_64BIT_PML4:
3202 case PGMPOOLKIND_PAE_PDPT:
3203 case PGMPOOLKIND_ROOT_NESTED:
3204 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
3205 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
3206 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
3207 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
3208 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
3209 case PGMPOOLKIND_PAE_PD_PHYS:
3210 case PGMPOOLKIND_PAE_PDPT_PHYS:
3211 return 8;
3212
3213 default:
3214 AssertFatalMsgFailed(("enmKind=%d\n", enmKind));
3215 }
3216}
3217#endif /* unused */
3218
3219#if 0 /* unused */
3220/**
3221 * Gets the entry size of a guest table.
3222 *
3223 * @param enmKind The kind of page.
3224 *
3225 * @returns The size of the entry in bytes. That is, 0, 4 or 8.
3226 * @returns If the kind is not for a table, an assertion is raised and 0 is
3227 * returned.
3228 */
3229DECLINLINE(unsigned) pgmPoolTrackGetGuestEntrySize(PGMPOOLKIND enmKind)
3230{
3231 switch (enmKind)
3232 {
3233 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
3234 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
3235 case PGMPOOLKIND_32BIT_PD:
3236 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
3237 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
3238 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
3239 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
3240 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
3241 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
3242 return 4;
3243
3244 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
3245 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
3246 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
3247 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
3248 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
3249 case PGMPOOLKIND_64BIT_PML4:
3250 case PGMPOOLKIND_PAE_PDPT:
3251 return 8;
3252
3253 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
3254 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
3255 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
3256 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
3257 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
3258 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
3259 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
3260 case PGMPOOLKIND_ROOT_NESTED:
3261 case PGMPOOLKIND_PAE_PD_PHYS:
3262 case PGMPOOLKIND_PAE_PDPT_PHYS:
3263 case PGMPOOLKIND_32BIT_PD_PHYS:
3264 /** @todo can we return 0? (nobody is calling this...) */
3265 AssertFailed();
3266 return 0;
3267
3268 default:
3269 AssertFatalMsgFailed(("enmKind=%d\n", enmKind));
3270 }
3271}
3272#endif /* unused */
3273
3274
3275/**
3276 * Checks one shadow page table entry for a mapping of a physical page.
3277 *
3278 * @returns true / false indicating removal of all relevant PTEs
3279 *
3280 * @param pVM The cross context VM structure.
3281 * @param pPhysPage The guest page in question.
3282 * @param fFlushPTEs Flush PTEs or allow them to be updated (e.g. in case of an RW bit change)
3283 * @param iShw The shadow page table.
3284 * @param iPte Page table entry or NIL_PGMPOOL_PHYSEXT_IDX_PTE if unknown
3285 */
3286static bool pgmPoolTrackFlushGCPhysPTInt(PVM pVM, PCPGMPAGE pPhysPage, bool fFlushPTEs, uint16_t iShw, uint16_t iPte)
3287{
3288 LogFlow(("pgmPoolTrackFlushGCPhysPTInt: pPhysPage=%RHp iShw=%d iPte=%d\n", PGM_PAGE_GET_HCPHYS(pPhysPage), iShw, iPte));
3289 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
3290 bool fRet = false;
3291
3292 /*
3293 * Assert sanity.
3294 */
3295 Assert(iPte != NIL_PGMPOOL_PHYSEXT_IDX_PTE);
3296 AssertFatalMsg(iShw < pPool->cCurPages && iShw != NIL_PGMPOOL_IDX, ("iShw=%d\n", iShw));
3297 PPGMPOOLPAGE pPage = &pPool->aPages[iShw];
3298
3299 /*
3300 * Then, clear the actual mappings to the page in the shadow PT.
3301 */
3302 switch (pPage->enmKind)
3303 {
3304 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
3305 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
3306 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
3307 {
3308 const uint32_t u32 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
3309 PX86PT pPT = (PX86PT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
3310 uint32_t u32AndMask = 0;
3311 uint32_t u32OrMask = 0;
3312
3313 if (!fFlushPTEs)
3314 {
3315 switch (PGM_PAGE_GET_HNDL_PHYS_STATE(pPhysPage))
3316 {
3317 case PGM_PAGE_HNDL_PHYS_STATE_NONE: /** No handler installed. */
3318 case PGM_PAGE_HNDL_PHYS_STATE_DISABLED: /** Monitoring is temporarily disabled. */
3319 u32OrMask = X86_PTE_RW;
3320 u32AndMask = UINT32_MAX;
3321 fRet = true;
3322 STAM_COUNTER_INC(&pPool->StatTrackFlushEntryKeep);
3323 break;
3324
3325 case PGM_PAGE_HNDL_PHYS_STATE_WRITE: /** Write access is monitored. */
3326 u32OrMask = 0;
3327 u32AndMask = ~X86_PTE_RW;
3328 fRet = true;
3329 STAM_COUNTER_INC(&pPool->StatTrackFlushEntryKeep);
3330 break;
3331 default:
3332 /* (shouldn't be here, will assert below) */
3333 STAM_COUNTER_INC(&pPool->StatTrackFlushEntry);
3334 break;
3335 }
3336 }
3337 else
3338 STAM_COUNTER_INC(&pPool->StatTrackFlushEntry);
3339
3340 /* Update the counter if we're removing references. */
3341 if (!u32AndMask)
3342 {
3343 Assert(pPage->cPresent);
3344 Assert(pPool->cPresent);
3345 pPage->cPresent--;
3346 pPool->cPresent--;
3347 }
3348
3349 if ((pPT->a[iPte].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
3350 {
3351 X86PTE Pte;
3352
3353 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX32\n", iPte, pPT->a[iPte]));
3354 Pte.u = (pPT->a[iPte].u & u32AndMask) | u32OrMask;
3355 if (Pte.u & PGM_PTFLAGS_TRACK_DIRTY)
3356 Pte.n.u1Write = 0; /* need to disallow writes when dirty bit tracking is still active. */
3357
3358 ASMAtomicWriteU32(&pPT->a[iPte].u, Pte.u);
3359 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPT);
3360 return fRet;
3361 }
3362#ifdef LOG_ENABLED
3363 Log(("iFirstPresent=%d cPresent=%d\n", pPage->iFirstPresent, pPage->cPresent));
3364 for (unsigned i = 0, cFound = 0; i < RT_ELEMENTS(pPT->a); i++)
3365 if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
3366 {
3367 Log(("i=%d cFound=%d\n", i, ++cFound));
3368 }
3369#endif
3370 AssertFatalMsgFailed(("iFirstPresent=%d cPresent=%d u32=%RX32 poolkind=%x\n", pPage->iFirstPresent, pPage->cPresent, u32, pPage->enmKind));
3371 /*PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPT);*/
3372 break;
3373 }
3374
3375 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
3376 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
3377 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
3378 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
3379 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
3380 case PGMPOOLKIND_EPT_PT_FOR_PHYS: /* physical mask the same as PAE; RW bit as well; be careful! */
3381 {
3382 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
3383 PPGMSHWPTPAE pPT = (PPGMSHWPTPAE)PGMPOOL_PAGE_2_PTR(pVM, pPage);
3384 uint64_t u64OrMask = 0;
3385 uint64_t u64AndMask = 0;
3386
3387 if (!fFlushPTEs)
3388 {
3389 switch (PGM_PAGE_GET_HNDL_PHYS_STATE(pPhysPage))
3390 {
3391 case PGM_PAGE_HNDL_PHYS_STATE_NONE: /* No handler installed. */
3392 case PGM_PAGE_HNDL_PHYS_STATE_DISABLED: /* Monitoring is temporarily disabled. */
3393 u64OrMask = X86_PTE_RW;
3394 u64AndMask = UINT64_MAX;
3395 fRet = true;
3396 STAM_COUNTER_INC(&pPool->StatTrackFlushEntryKeep);
3397 break;
3398
3399 case PGM_PAGE_HNDL_PHYS_STATE_WRITE: /* Write access is monitored. */
3400 u64OrMask = 0;
3401 u64AndMask = ~(uint64_t)X86_PTE_RW;
3402 fRet = true;
3403 STAM_COUNTER_INC(&pPool->StatTrackFlushEntryKeep);
3404 break;
3405
3406 default:
3407 /* (shouldn't be here, will assert below) */
3408 STAM_COUNTER_INC(&pPool->StatTrackFlushEntry);
3409 break;
3410 }
3411 }
3412 else
3413 STAM_COUNTER_INC(&pPool->StatTrackFlushEntry);
3414
3415 /* Update the counter if we're removing references. */
3416 if (!u64AndMask)
3417 {
3418 Assert(pPage->cPresent);
3419 Assert(pPool->cPresent);
3420 pPage->cPresent--;
3421 pPool->cPresent--;
3422 }
3423
3424 if ((PGMSHWPTEPAE_GET_U(pPT->a[iPte]) & (X86_PTE_PAE_PG_MASK | X86_PTE_P | X86_PTE_PAE_MBZ_MASK_NX)) == u64)
3425 {
3426 X86PTEPAE Pte;
3427
3428 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX64\n", iPte, PGMSHWPTEPAE_GET_LOG(pPT->a[iPte])));
3429 Pte.u = (PGMSHWPTEPAE_GET_U(pPT->a[iPte]) & u64AndMask) | u64OrMask;
3430 if (Pte.u & PGM_PTFLAGS_TRACK_DIRTY)
3431 Pte.n.u1Write = 0; /* need to disallow writes when dirty bit tracking is still active. */
3432
3433 PGMSHWPTEPAE_ATOMIC_SET(pPT->a[iPte], Pte.u);
3434 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPT);
3435 return fRet;
3436 }
3437#ifdef LOG_ENABLED
3438 Log(("iFirstPresent=%d cPresent=%d\n", pPage->iFirstPresent, pPage->cPresent));
3439 Log(("Found %RX64 expected %RX64\n", PGMSHWPTEPAE_GET_U(pPT->a[iPte]) & (X86_PTE_PAE_PG_MASK | X86_PTE_P | X86_PTE_PAE_MBZ_MASK_NX), u64));
3440 for (unsigned i = 0, cFound = 0; i < RT_ELEMENTS(pPT->a); i++)
3441 if ((PGMSHWPTEPAE_GET_U(pPT->a[i]) & (X86_PTE_PAE_PG_MASK | X86_PTE_P | X86_PTE_PAE_MBZ_MASK_NX)) == u64)
3442 Log(("i=%d cFound=%d\n", i, ++cFound));
3443#endif
3444 AssertFatalMsgFailed(("iFirstPresent=%d cPresent=%d u64=%RX64 poolkind=%x iPte=%d PT=%RX64\n", pPage->iFirstPresent, pPage->cPresent, u64, pPage->enmKind, iPte, PGMSHWPTEPAE_GET_LOG(pPT->a[iPte])));
3445 /*PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPT);*/
3446 break;
3447 }
3448
3449#ifdef PGM_WITH_LARGE_PAGES
3450 /* Large page case only. */
3451 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
3452 {
3453 Assert(pVM->pgm.s.fNestedPaging);
3454
3455 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PDE4M_P | X86_PDE4M_PS;
3456 PEPTPD pPD = (PEPTPD)PGMPOOL_PAGE_2_PTR(pVM, pPage);
3457
3458 if ((pPD->a[iPte].u & (EPT_PDE2M_PG_MASK | X86_PDE4M_P | X86_PDE4M_PS)) == u64)
3459 {
3460 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pde=%RX64\n", iPte, pPD->a[iPte]));
3461 STAM_COUNTER_INC(&pPool->StatTrackFlushEntry);
3462 pPD->a[iPte].u = 0;
3463 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPD);
3464
3465 /* Update the counter as we're removing references. */
3466 Assert(pPage->cPresent);
3467 Assert(pPool->cPresent);
3468 pPage->cPresent--;
3469 pPool->cPresent--;
3470
3471 return fRet;
3472 }
3473# ifdef LOG_ENABLED
3474 Log(("iFirstPresent=%d cPresent=%d\n", pPage->iFirstPresent, pPage->cPresent));
3475 for (unsigned i = 0, cFound = 0; i < RT_ELEMENTS(pPD->a); i++)
3476 if ((pPD->a[i].u & (EPT_PDE2M_PG_MASK | X86_PDE4M_P | X86_PDE4M_PS)) == u64)
3477 Log(("i=%d cFound=%d\n", i, ++cFound));
3478# endif
3479 AssertFatalMsgFailed(("iFirstPresent=%d cPresent=%d\n", pPage->iFirstPresent, pPage->cPresent));
3480 /*PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPD);*/
3481 break;
3482 }
3483
3484 /* AMD-V nested paging */ /** @todo merge with EPT as we only check the parts that are identical. */
3485 case PGMPOOLKIND_PAE_PD_PHYS:
3486 {
3487 Assert(pVM->pgm.s.fNestedPaging);
3488
3489 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PDE4M_P | X86_PDE4M_PS;
3490 PX86PD pPD = (PX86PD)PGMPOOL_PAGE_2_PTR(pVM, pPage);
3491
3492 if ((pPD->a[iPte].u & (X86_PDE2M_PAE_PG_MASK | X86_PDE4M_P | X86_PDE4M_PS)) == u64)
3493 {
3494 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pde=%RX64\n", iPte, pPD->a[iPte]));
3495 STAM_COUNTER_INC(&pPool->StatTrackFlushEntry);
3496 pPD->a[iPte].u = 0;
3497 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPD);
3498
3499 /* Update the counter as we're removing references. */
3500 Assert(pPage->cPresent);
3501 Assert(pPool->cPresent);
3502 pPage->cPresent--;
3503 pPool->cPresent--;
3504 return fRet;
3505 }
3506# ifdef LOG_ENABLED
3507 Log(("iFirstPresent=%d cPresent=%d\n", pPage->iFirstPresent, pPage->cPresent));
3508 for (unsigned i = 0, cFound = 0; i < RT_ELEMENTS(pPD->a); i++)
3509 if ((pPD->a[i].u & (X86_PDE2M_PAE_PG_MASK | X86_PDE4M_P | X86_PDE4M_PS)) == u64)
3510 Log(("i=%d cFound=%d\n", i, ++cFound));
3511# endif
3512 AssertFatalMsgFailed(("iFirstPresent=%d cPresent=%d\n", pPage->iFirstPresent, pPage->cPresent));
3513 /*PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPD);*/
3514 break;
3515 }
3516#endif /* PGM_WITH_LARGE_PAGES */
3517
3518 default:
3519 AssertFatalMsgFailed(("enmKind=%d iShw=%d\n", pPage->enmKind, iShw));
3520 }
3521
3522 /* not reached. */
3523#ifndef _MSC_VER
3524 return fRet;
3525#endif
3526}
3527
3528
3529/**
3530 * Scans one shadow page table for mappings of a physical page.
3531 *
3532 * @param pVM The cross context VM structure.
3533 * @param pPhysPage The guest page in question.
3534 * @param fFlushPTEs Flush PTEs or allow them to be updated (e.g. in case of an RW bit change)
3535 * @param iShw The shadow page table.
3536 */
3537static void pgmPoolTrackFlushGCPhysPT(PVM pVM, PPGMPAGE pPhysPage, bool fFlushPTEs, uint16_t iShw)
3538{
3539 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool); NOREF(pPool);
3540
3541 /* We should only come here with when there's only one reference to this physical page. */
3542 Assert(PGMPOOL_TD_GET_CREFS(PGM_PAGE_GET_TRACKING(pPhysPage)) == 1);
3543
3544 Log2(("pgmPoolTrackFlushGCPhysPT: pPhysPage=%RHp iShw=%d\n", PGM_PAGE_GET_HCPHYS(pPhysPage), iShw));
3545 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPT, f);
3546 bool fKeptPTEs = pgmPoolTrackFlushGCPhysPTInt(pVM, pPhysPage, fFlushPTEs, iShw, PGM_PAGE_GET_PTE_INDEX(pPhysPage));
3547 if (!fKeptPTEs)
3548 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, 0);
3549 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPT, f);
3550}
3551
3552
3553/**
3554 * Flushes a list of shadow page tables mapping the same physical page.
3555 *
3556 * @param pVM The cross context VM structure.
3557 * @param pPhysPage The guest page in question.
3558 * @param fFlushPTEs Flush PTEs or allow them to be updated (e.g. in case of an RW bit change)
3559 * @param iPhysExt The physical cross reference extent list to flush.
3560 */
3561static void pgmPoolTrackFlushGCPhysPTs(PVM pVM, PPGMPAGE pPhysPage, bool fFlushPTEs, uint16_t iPhysExt)
3562{
3563 PGM_LOCK_ASSERT_OWNER(pVM);
3564 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
3565 bool fKeepList = false;
3566
3567 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPTs, f);
3568 Log2(("pgmPoolTrackFlushGCPhysPTs: pPhysPage=%RHp iPhysExt=%u\n", PGM_PAGE_GET_HCPHYS(pPhysPage), iPhysExt));
3569
3570 const uint16_t iPhysExtStart = iPhysExt;
3571 PPGMPOOLPHYSEXT pPhysExt;
3572 do
3573 {
3574 Assert(iPhysExt < pPool->cMaxPhysExts);
3575 pPhysExt = &pPool->CTX_SUFF(paPhysExts)[iPhysExt];
3576 for (unsigned i = 0; i < RT_ELEMENTS(pPhysExt->aidx); i++)
3577 {
3578 if (pPhysExt->aidx[i] != NIL_PGMPOOL_IDX)
3579 {
3580 bool fKeptPTEs = pgmPoolTrackFlushGCPhysPTInt(pVM, pPhysPage, fFlushPTEs, pPhysExt->aidx[i], pPhysExt->apte[i]);
3581 if (!fKeptPTEs)
3582 {
3583 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
3584 pPhysExt->apte[i] = NIL_PGMPOOL_PHYSEXT_IDX_PTE;
3585 }
3586 else
3587 fKeepList = true;
3588 }
3589 }
3590 /* next */
3591 iPhysExt = pPhysExt->iNext;
3592 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
3593
3594 if (!fKeepList)
3595 {
3596 /* insert the list into the free list and clear the ram range entry. */
3597 pPhysExt->iNext = pPool->iPhysExtFreeHead;
3598 pPool->iPhysExtFreeHead = iPhysExtStart;
3599 /* Invalidate the tracking data. */
3600 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, 0);
3601 }
3602
3603 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTs, f);
3604}
3605
3606
3607/**
3608 * Flushes all shadow page table mappings of the given guest page.
3609 *
3610 * This is typically called when the host page backing the guest one has been
3611 * replaced or when the page protection was changed due to a guest access
3612 * caught by the monitoring.
3613 *
3614 * @returns VBox status code.
3615 * @retval VINF_SUCCESS if all references has been successfully cleared.
3616 * @retval VINF_PGM_SYNC_CR3 if we're better off with a CR3 sync and a page
3617 * pool cleaning. FF and sync flags are set.
3618 *
3619 * @param pVM The cross context VM structure.
3620 * @param GCPhysPage GC physical address of the page in question
3621 * @param pPhysPage The guest page in question.
3622 * @param fFlushPTEs Flush PTEs or allow them to be updated (e.g. in case of an RW bit change)
3623 * @param pfFlushTLBs This is set to @a true if the shadow TLBs should be
3624 * flushed, it is NOT touched if this isn't necessary.
3625 * The caller MUST initialized this to @a false.
3626 */
3627int pgmPoolTrackUpdateGCPhys(PVM pVM, RTGCPHYS GCPhysPage, PPGMPAGE pPhysPage, bool fFlushPTEs, bool *pfFlushTLBs)
3628{
3629 PVMCPU pVCpu = VMMGetCpu(pVM);
3630 pgmLock(pVM);
3631 int rc = VINF_SUCCESS;
3632
3633#ifdef PGM_WITH_LARGE_PAGES
3634 /* Is this page part of a large page? */
3635 if (PGM_PAGE_GET_PDE_TYPE(pPhysPage) == PGM_PAGE_PDE_TYPE_PDE)
3636 {
3637 RTGCPHYS GCPhysBase = GCPhysPage & X86_PDE2M_PAE_PG_MASK;
3638 GCPhysPage &= X86_PDE_PAE_PG_MASK;
3639
3640 /* Fetch the large page base. */
3641 PPGMPAGE pLargePage;
3642 if (GCPhysBase != GCPhysPage)
3643 {
3644 pLargePage = pgmPhysGetPage(pVM, GCPhysBase);
3645 AssertFatal(pLargePage);
3646 }
3647 else
3648 pLargePage = pPhysPage;
3649
3650 Log(("pgmPoolTrackUpdateGCPhys: update large page PDE for %RGp (%RGp)\n", GCPhysBase, GCPhysPage));
3651
3652 if (PGM_PAGE_GET_PDE_TYPE(pLargePage) == PGM_PAGE_PDE_TYPE_PDE)
3653 {
3654 /* Mark the large page as disabled as we need to break it up to change a single page in the 2 MB range. */
3655 PGM_PAGE_SET_PDE_TYPE(pVM, pLargePage, PGM_PAGE_PDE_TYPE_PDE_DISABLED);
3656 pVM->pgm.s.cLargePagesDisabled++;
3657
3658 /* Update the base as that *only* that one has a reference and there's only one PDE to clear. */
3659 rc = pgmPoolTrackUpdateGCPhys(pVM, GCPhysBase, pLargePage, fFlushPTEs, pfFlushTLBs);
3660
3661 *pfFlushTLBs = true;
3662 pgmUnlock(pVM);
3663 return rc;
3664 }
3665 }
3666#else
3667 NOREF(GCPhysPage);
3668#endif /* PGM_WITH_LARGE_PAGES */
3669
3670 const uint16_t u16 = PGM_PAGE_GET_TRACKING(pPhysPage);
3671 if (u16)
3672 {
3673 /*
3674 * The zero page is currently screwing up the tracking and we'll
3675 * have to flush the whole shebang. Unless VBOX_WITH_NEW_LAZY_PAGE_ALLOC
3676 * is defined, zero pages won't normally be mapped. Some kind of solution
3677 * will be needed for this problem of course, but it will have to wait...
3678 */
3679 if ( PGM_PAGE_IS_ZERO(pPhysPage)
3680 || PGM_PAGE_IS_BALLOONED(pPhysPage))
3681 rc = VINF_PGM_GCPHYS_ALIASED;
3682 else
3683 {
3684# if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC) /** @todo we can drop this now. */
3685 /* Start a subset here because pgmPoolTrackFlushGCPhysPTsSlow and
3686 pgmPoolTrackFlushGCPhysPTs will/may kill the pool otherwise. */
3687 uint32_t iPrevSubset = PGMRZDynMapPushAutoSubset(pVCpu);
3688# endif
3689
3690 if (PGMPOOL_TD_GET_CREFS(u16) != PGMPOOL_TD_CREFS_PHYSEXT)
3691 {
3692 Assert(PGMPOOL_TD_GET_CREFS(u16) == 1);
3693 pgmPoolTrackFlushGCPhysPT(pVM,
3694 pPhysPage,
3695 fFlushPTEs,
3696 PGMPOOL_TD_GET_IDX(u16));
3697 }
3698 else if (u16 != PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED))
3699 pgmPoolTrackFlushGCPhysPTs(pVM, pPhysPage, fFlushPTEs, PGMPOOL_TD_GET_IDX(u16));
3700 else
3701 rc = pgmPoolTrackFlushGCPhysPTsSlow(pVM, pPhysPage);
3702 *pfFlushTLBs = true;
3703
3704# if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
3705 PGMRZDynMapPopAutoSubset(pVCpu, iPrevSubset);
3706# endif
3707 }
3708 }
3709
3710 if (rc == VINF_PGM_GCPHYS_ALIASED)
3711 {
3712 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
3713 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
3714 rc = VINF_PGM_SYNC_CR3;
3715 }
3716 pgmUnlock(pVM);
3717 return rc;
3718}
3719
3720
3721/**
3722 * Scans all shadow page tables for mappings of a physical page.
3723 *
3724 * This may be slow, but it's most likely more efficient than cleaning
3725 * out the entire page pool / cache.
3726 *
3727 * @returns VBox status code.
3728 * @retval VINF_SUCCESS if all references has been successfully cleared.
3729 * @retval VINF_PGM_GCPHYS_ALIASED if we're better off with a CR3 sync and
3730 * a page pool cleaning.
3731 *
3732 * @param pVM The cross context VM structure.
3733 * @param pPhysPage The guest page in question.
3734 */
3735int pgmPoolTrackFlushGCPhysPTsSlow(PVM pVM, PPGMPAGE pPhysPage)
3736{
3737 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
3738 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPTsSlow, s);
3739 LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: cUsedPages=%d cPresent=%d pPhysPage=%R[pgmpage]\n",
3740 pPool->cUsedPages, pPool->cPresent, pPhysPage));
3741
3742 /*
3743 * There is a limit to what makes sense.
3744 */
3745 if ( pPool->cPresent > 1024
3746 && pVM->cCpus == 1)
3747 {
3748 LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: giving up... (cPresent=%d)\n", pPool->cPresent));
3749 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTsSlow, s);
3750 return VINF_PGM_GCPHYS_ALIASED;
3751 }
3752
3753 /*
3754 * Iterate all the pages until we've encountered all that in use.
3755 * This is simple but not quite optimal solution.
3756 */
3757 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P; /** @todo drop X86_PTE_P here as we always test if present separately, anyway. */
3758 const uint32_t u32 = u64; /** @todo move into the 32BIT_PT_xx case */
3759 unsigned cLeft = pPool->cUsedPages;
3760 unsigned iPage = pPool->cCurPages;
3761 while (--iPage >= PGMPOOL_IDX_FIRST)
3762 {
3763 PPGMPOOLPAGE pPage = &pPool->aPages[iPage];
3764 if ( pPage->GCPhys != NIL_RTGCPHYS
3765 && pPage->cPresent)
3766 {
3767 switch (pPage->enmKind)
3768 {
3769 /*
3770 * We only care about shadow page tables.
3771 */
3772 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
3773 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
3774 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
3775 {
3776 unsigned cPresent = pPage->cPresent;
3777 PX86PT pPT = (PX86PT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
3778 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
3779 if (pPT->a[i].n.u1Present)
3780 {
3781 if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
3782 {
3783 //Log4(("pgmPoolTrackFlushGCPhysPTsSlow: idx=%d i=%d pte=%RX32\n", iPage, i, pPT->a[i]));
3784 pPT->a[i].u = 0;
3785
3786 /* Update the counter as we're removing references. */
3787 Assert(pPage->cPresent);
3788 Assert(pPool->cPresent);
3789 pPage->cPresent--;
3790 pPool->cPresent--;
3791 }
3792 if (!--cPresent)
3793 break;
3794 }
3795 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPT);
3796 break;
3797 }
3798
3799 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
3800 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
3801 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
3802 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
3803 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
3804 {
3805 unsigned cPresent = pPage->cPresent;
3806 PPGMSHWPTPAE pPT = (PPGMSHWPTPAE)PGMPOOL_PAGE_2_PTR(pVM, pPage);
3807 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
3808 if (PGMSHWPTEPAE_IS_P(pPT->a[i]))
3809 {
3810 if ((PGMSHWPTEPAE_GET_U(pPT->a[i]) & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
3811 {
3812 //Log4(("pgmPoolTrackFlushGCPhysPTsSlow: idx=%d i=%d pte=%RX64\n", iPage, i, pPT->a[i]));
3813 PGMSHWPTEPAE_SET(pPT->a[i], 0); /// @todo why not atomic?
3814
3815 /* Update the counter as we're removing references. */
3816 Assert(pPage->cPresent);
3817 Assert(pPool->cPresent);
3818 pPage->cPresent--;
3819 pPool->cPresent--;
3820 }
3821 if (!--cPresent)
3822 break;
3823 }
3824 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPT);
3825 break;
3826 }
3827#ifndef IN_RC
3828 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
3829 {
3830 unsigned cPresent = pPage->cPresent;
3831 PEPTPT pPT = (PEPTPT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
3832 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
3833 if (pPT->a[i].n.u1Present)
3834 {
3835 if ((pPT->a[i].u & (EPT_PTE_PG_MASK | X86_PTE_P)) == u64)
3836 {
3837 //Log4(("pgmPoolTrackFlushGCPhysPTsSlow: idx=%d i=%d pte=%RX64\n", iPage, i, pPT->a[i]));
3838 pPT->a[i].u = 0;
3839
3840 /* Update the counter as we're removing references. */
3841 Assert(pPage->cPresent);
3842 Assert(pPool->cPresent);
3843 pPage->cPresent--;
3844 pPool->cPresent--;
3845 }
3846 if (!--cPresent)
3847 break;
3848 }
3849 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pPT);
3850 break;
3851 }
3852#endif
3853 }
3854 if (!--cLeft)
3855 break;
3856 }
3857 }
3858
3859 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, 0);
3860 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTsSlow, s);
3861
3862 /*
3863 * There is a limit to what makes sense. The above search is very expensive, so force a pgm pool flush.
3864 */
3865 if (pPool->cPresent > 1024)
3866 {
3867 LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: giving up... (cPresent=%d)\n", pPool->cPresent));
3868 return VINF_PGM_GCPHYS_ALIASED;
3869 }
3870
3871 return VINF_SUCCESS;
3872}
3873
3874
3875/**
3876 * Clears the user entry in a user table.
3877 *
3878 * This is used to remove all references to a page when flushing it.
3879 */
3880static void pgmPoolTrackClearPageUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PCPGMPOOLUSER pUser)
3881{
3882 Assert(pUser->iUser != NIL_PGMPOOL_IDX);
3883 Assert(pUser->iUser < pPool->cCurPages);
3884 uint32_t iUserTable = pUser->iUserTable;
3885
3886 /*
3887 * Map the user page. Ignore references made by fictitious pages.
3888 */
3889 PPGMPOOLPAGE pUserPage = &pPool->aPages[pUser->iUser];
3890 LogFlow(("pgmPoolTrackClearPageUser: clear %x in %s (%RGp) (flushing %s)\n", iUserTable, pgmPoolPoolKindToStr(pUserPage->enmKind), pUserPage->Core.Key, pgmPoolPoolKindToStr(pPage->enmKind)));
3891 union
3892 {
3893 uint64_t *pau64;
3894 uint32_t *pau32;
3895 } u;
3896 if (pUserPage->idx < PGMPOOL_IDX_FIRST)
3897 {
3898 Assert(!pUserPage->pvPageR3);
3899 return;
3900 }
3901 u.pau64 = (uint64_t *)PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pUserPage);
3902
3903
3904 /* Safety precaution in case we change the paging for other modes too in the future. */
3905 Assert(!pgmPoolIsPageLocked(pPage)); RT_NOREF_PV(pPage);
3906
3907#ifdef VBOX_STRICT
3908 /*
3909 * Some sanity checks.
3910 */
3911 switch (pUserPage->enmKind)
3912 {
3913 case PGMPOOLKIND_32BIT_PD:
3914 case PGMPOOLKIND_32BIT_PD_PHYS:
3915 Assert(iUserTable < X86_PG_ENTRIES);
3916 break;
3917 case PGMPOOLKIND_PAE_PDPT:
3918 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
3919 case PGMPOOLKIND_PAE_PDPT_PHYS:
3920 Assert(iUserTable < 4);
3921 Assert(!(u.pau64[iUserTable] & PGM_PLXFLAGS_PERMANENT));
3922 break;
3923 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
3924 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
3925 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
3926 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
3927 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
3928 case PGMPOOLKIND_PAE_PD_PHYS:
3929 Assert(iUserTable < X86_PG_PAE_ENTRIES);
3930 break;
3931 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
3932 Assert(iUserTable < X86_PG_PAE_ENTRIES);
3933 Assert(!(u.pau64[iUserTable] & PGM_PDFLAGS_MAPPING));
3934 break;
3935 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
3936 Assert(iUserTable < X86_PG_PAE_ENTRIES);
3937 Assert(!(u.pau64[iUserTable] & PGM_PLXFLAGS_PERMANENT));
3938 break;
3939 case PGMPOOLKIND_64BIT_PML4:
3940 Assert(!(u.pau64[iUserTable] & PGM_PLXFLAGS_PERMANENT));
3941 /* GCPhys >> PAGE_SHIFT is the index here */
3942 break;
3943 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
3944 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
3945 Assert(iUserTable < X86_PG_PAE_ENTRIES);
3946 break;
3947
3948 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
3949 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
3950 Assert(iUserTable < X86_PG_PAE_ENTRIES);
3951 break;
3952
3953 case PGMPOOLKIND_ROOT_NESTED:
3954 Assert(iUserTable < X86_PG_PAE_ENTRIES);
3955 break;
3956
3957 default:
3958 AssertMsgFailed(("enmKind=%d\n", pUserPage->enmKind));
3959 break;
3960 }
3961#endif /* VBOX_STRICT */
3962
3963 /*
3964 * Clear the entry in the user page.
3965 */
3966 switch (pUserPage->enmKind)
3967 {
3968 /* 32-bit entries */
3969 case PGMPOOLKIND_32BIT_PD:
3970 case PGMPOOLKIND_32BIT_PD_PHYS:
3971 ASMAtomicWriteU32(&u.pau32[iUserTable], 0);
3972 break;
3973
3974 /* 64-bit entries */
3975 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
3976 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
3977 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
3978 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
3979 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
3980#ifdef IN_RC
3981 /*
3982 * In 32 bits PAE mode we *must* invalidate the TLB when changing a
3983 * PDPT entry; the CPU fetches them only during cr3 load, so any
3984 * non-present PDPT will continue to cause page faults.
3985 */
3986 ASMReloadCR3();
3987#endif
3988 RT_FALL_THRU();
3989 case PGMPOOLKIND_PAE_PD_PHYS:
3990 case PGMPOOLKIND_PAE_PDPT_PHYS:
3991 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
3992 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
3993 case PGMPOOLKIND_64BIT_PML4:
3994 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
3995 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
3996 case PGMPOOLKIND_PAE_PDPT:
3997 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
3998 case PGMPOOLKIND_ROOT_NESTED:
3999 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
4000 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
4001 ASMAtomicWriteU64(&u.pau64[iUserTable], 0);
4002 break;
4003
4004 default:
4005 AssertFatalMsgFailed(("enmKind=%d iUser=%d iUserTable=%#x\n", pUserPage->enmKind, pUser->iUser, pUser->iUserTable));
4006 }
4007 PGM_DYNMAP_UNUSED_HINT_VM(pPool->CTX_SUFF(pVM), u.pau64);
4008}
4009
4010
4011/**
4012 * Clears all users of a page.
4013 */
4014static void pgmPoolTrackClearPageUsers(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
4015{
4016 /*
4017 * Free all the user records.
4018 */
4019 LogFlow(("pgmPoolTrackClearPageUsers %RGp\n", pPage->GCPhys));
4020
4021 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
4022 uint16_t i = pPage->iUserHead;
4023 while (i != NIL_PGMPOOL_USER_INDEX)
4024 {
4025 /* Clear enter in user table. */
4026 pgmPoolTrackClearPageUser(pPool, pPage, &paUsers[i]);
4027
4028 /* Free it. */
4029 const uint16_t iNext = paUsers[i].iNext;
4030 paUsers[i].iUser = NIL_PGMPOOL_IDX;
4031 paUsers[i].iNext = pPool->iUserFreeHead;
4032 pPool->iUserFreeHead = i;
4033
4034 /* Next. */
4035 i = iNext;
4036 }
4037 pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
4038}
4039
4040
4041/**
4042 * Allocates a new physical cross reference extent.
4043 *
4044 * @returns Pointer to the allocated extent on success. NULL if we're out of them.
4045 * @param pVM The cross context VM structure.
4046 * @param piPhysExt Where to store the phys ext index.
4047 */
4048PPGMPOOLPHYSEXT pgmPoolTrackPhysExtAlloc(PVM pVM, uint16_t *piPhysExt)
4049{
4050 PGM_LOCK_ASSERT_OWNER(pVM);
4051 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4052 uint16_t iPhysExt = pPool->iPhysExtFreeHead;
4053 if (iPhysExt == NIL_PGMPOOL_PHYSEXT_INDEX)
4054 {
4055 STAM_COUNTER_INC(&pPool->StamTrackPhysExtAllocFailures);
4056 return NULL;
4057 }
4058 PPGMPOOLPHYSEXT pPhysExt = &pPool->CTX_SUFF(paPhysExts)[iPhysExt];
4059 pPool->iPhysExtFreeHead = pPhysExt->iNext;
4060 pPhysExt->iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
4061 *piPhysExt = iPhysExt;
4062 return pPhysExt;
4063}
4064
4065
4066/**
4067 * Frees a physical cross reference extent.
4068 *
4069 * @param pVM The cross context VM structure.
4070 * @param iPhysExt The extent to free.
4071 */
4072void pgmPoolTrackPhysExtFree(PVM pVM, uint16_t iPhysExt)
4073{
4074 PGM_LOCK_ASSERT_OWNER(pVM);
4075 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4076 Assert(iPhysExt < pPool->cMaxPhysExts);
4077 PPGMPOOLPHYSEXT pPhysExt = &pPool->CTX_SUFF(paPhysExts)[iPhysExt];
4078 for (unsigned i = 0; i < RT_ELEMENTS(pPhysExt->aidx); i++)
4079 {
4080 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
4081 pPhysExt->apte[i] = NIL_PGMPOOL_PHYSEXT_IDX_PTE;
4082 }
4083 pPhysExt->iNext = pPool->iPhysExtFreeHead;
4084 pPool->iPhysExtFreeHead = iPhysExt;
4085}
4086
4087
4088/**
4089 * Frees a physical cross reference extent.
4090 *
4091 * @param pVM The cross context VM structure.
4092 * @param iPhysExt The extent to free.
4093 */
4094void pgmPoolTrackPhysExtFreeList(PVM pVM, uint16_t iPhysExt)
4095{
4096 PGM_LOCK_ASSERT_OWNER(pVM);
4097 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4098
4099 const uint16_t iPhysExtStart = iPhysExt;
4100 PPGMPOOLPHYSEXT pPhysExt;
4101 do
4102 {
4103 Assert(iPhysExt < pPool->cMaxPhysExts);
4104 pPhysExt = &pPool->CTX_SUFF(paPhysExts)[iPhysExt];
4105 for (unsigned i = 0; i < RT_ELEMENTS(pPhysExt->aidx); i++)
4106 {
4107 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
4108 pPhysExt->apte[i] = NIL_PGMPOOL_PHYSEXT_IDX_PTE;
4109 }
4110
4111 /* next */
4112 iPhysExt = pPhysExt->iNext;
4113 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
4114
4115 pPhysExt->iNext = pPool->iPhysExtFreeHead;
4116 pPool->iPhysExtFreeHead = iPhysExtStart;
4117}
4118
4119
4120/**
4121 * Insert a reference into a list of physical cross reference extents.
4122 *
4123 * @returns The new tracking data for PGMPAGE.
4124 *
4125 * @param pVM The cross context VM structure.
4126 * @param iPhysExt The physical extent index of the list head.
4127 * @param iShwPT The shadow page table index.
4128 * @param iPte Page table entry
4129 *
4130 */
4131static uint16_t pgmPoolTrackPhysExtInsert(PVM pVM, uint16_t iPhysExt, uint16_t iShwPT, uint16_t iPte)
4132{
4133 PGM_LOCK_ASSERT_OWNER(pVM);
4134 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4135 PPGMPOOLPHYSEXT paPhysExts = pPool->CTX_SUFF(paPhysExts);
4136
4137 /*
4138 * Special common cases.
4139 */
4140 if (paPhysExts[iPhysExt].aidx[1] == NIL_PGMPOOL_IDX)
4141 {
4142 paPhysExts[iPhysExt].aidx[1] = iShwPT;
4143 paPhysExts[iPhysExt].apte[1] = iPte;
4144 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackAliasedMany);
4145 LogFlow(("pgmPoolTrackPhysExtInsert: %d:{,%d pte %d,}\n", iPhysExt, iShwPT, iPte));
4146 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExt);
4147 }
4148 if (paPhysExts[iPhysExt].aidx[2] == NIL_PGMPOOL_IDX)
4149 {
4150 paPhysExts[iPhysExt].aidx[2] = iShwPT;
4151 paPhysExts[iPhysExt].apte[2] = iPte;
4152 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackAliasedMany);
4153 LogFlow(("pgmPoolTrackPhysExtInsert: %d:{,,%d pte %d}\n", iPhysExt, iShwPT, iPte));
4154 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExt);
4155 }
4156 AssertCompile(RT_ELEMENTS(paPhysExts[iPhysExt].aidx) == 3);
4157
4158 /*
4159 * General treatment.
4160 */
4161 const uint16_t iPhysExtStart = iPhysExt;
4162 unsigned cMax = 15;
4163 for (;;)
4164 {
4165 Assert(iPhysExt < pPool->cMaxPhysExts);
4166 for (unsigned i = 0; i < RT_ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
4167 if (paPhysExts[iPhysExt].aidx[i] == NIL_PGMPOOL_IDX)
4168 {
4169 paPhysExts[iPhysExt].aidx[i] = iShwPT;
4170 paPhysExts[iPhysExt].apte[i] = iPte;
4171 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackAliasedMany);
4172 LogFlow(("pgmPoolTrackPhysExtInsert: %d:{%d pte %d} i=%d cMax=%d\n", iPhysExt, iShwPT, iPte, i, cMax));
4173 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExtStart);
4174 }
4175 if (!--cMax)
4176 {
4177 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackOverflows);
4178 pgmPoolTrackPhysExtFreeList(pVM, iPhysExtStart);
4179 LogFlow(("pgmPoolTrackPhysExtInsert: overflow (1) iShwPT=%d\n", iShwPT));
4180 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED);
4181 }
4182
4183 /* advance */
4184 iPhysExt = paPhysExts[iPhysExt].iNext;
4185 if (iPhysExt == NIL_PGMPOOL_PHYSEXT_INDEX)
4186 break;
4187 }
4188
4189 /*
4190 * Add another extent to the list.
4191 */
4192 PPGMPOOLPHYSEXT pNew = pgmPoolTrackPhysExtAlloc(pVM, &iPhysExt);
4193 if (!pNew)
4194 {
4195 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackNoExtentsLeft);
4196 pgmPoolTrackPhysExtFreeList(pVM, iPhysExtStart);
4197 LogFlow(("pgmPoolTrackPhysExtInsert: pgmPoolTrackPhysExtAlloc failed iShwPT=%d\n", iShwPT));
4198 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED);
4199 }
4200 pNew->iNext = iPhysExtStart;
4201 pNew->aidx[0] = iShwPT;
4202 pNew->apte[0] = iPte;
4203 LogFlow(("pgmPoolTrackPhysExtInsert: added new extent %d:{%d pte %d}->%d\n", iPhysExt, iShwPT, iPte, iPhysExtStart));
4204 return PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExt);
4205}
4206
4207
4208/**
4209 * Add a reference to guest physical page where extents are in use.
4210 *
4211 * @returns The new tracking data for PGMPAGE.
4212 *
4213 * @param pVM The cross context VM structure.
4214 * @param pPhysPage Pointer to the aPages entry in the ram range.
4215 * @param u16 The ram range flags (top 16-bits).
4216 * @param iShwPT The shadow page table index.
4217 * @param iPte Page table entry
4218 */
4219uint16_t pgmPoolTrackPhysExtAddref(PVM pVM, PPGMPAGE pPhysPage, uint16_t u16, uint16_t iShwPT, uint16_t iPte)
4220{
4221 pgmLock(pVM);
4222 if (PGMPOOL_TD_GET_CREFS(u16) != PGMPOOL_TD_CREFS_PHYSEXT)
4223 {
4224 /*
4225 * Convert to extent list.
4226 */
4227 Assert(PGMPOOL_TD_GET_CREFS(u16) == 1);
4228 uint16_t iPhysExt;
4229 PPGMPOOLPHYSEXT pPhysExt = pgmPoolTrackPhysExtAlloc(pVM, &iPhysExt);
4230 if (pPhysExt)
4231 {
4232 LogFlow(("pgmPoolTrackPhysExtAddref: new extent: %d:{%d, %d}\n", iPhysExt, PGMPOOL_TD_GET_IDX(u16), iShwPT));
4233 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackAliased);
4234 pPhysExt->aidx[0] = PGMPOOL_TD_GET_IDX(u16);
4235 pPhysExt->apte[0] = PGM_PAGE_GET_PTE_INDEX(pPhysPage);
4236 pPhysExt->aidx[1] = iShwPT;
4237 pPhysExt->apte[1] = iPte;
4238 u16 = PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExt);
4239 }
4240 else
4241 u16 = PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED);
4242 }
4243 else if (u16 != PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, PGMPOOL_TD_IDX_OVERFLOWED))
4244 {
4245 /*
4246 * Insert into the extent list.
4247 */
4248 u16 = pgmPoolTrackPhysExtInsert(pVM, PGMPOOL_TD_GET_IDX(u16), iShwPT, iPte);
4249 }
4250 else
4251 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatTrackAliasedLots);
4252 pgmUnlock(pVM);
4253 return u16;
4254}
4255
4256
4257/**
4258 * Clear references to guest physical memory.
4259 *
4260 * @param pPool The pool.
4261 * @param pPage The page.
4262 * @param pPhysPage Pointer to the aPages entry in the ram range.
4263 * @param iPte Shadow PTE index
4264 */
4265void pgmPoolTrackPhysExtDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMPAGE pPhysPage, uint16_t iPte)
4266{
4267 PVM pVM = pPool->CTX_SUFF(pVM);
4268 const unsigned cRefs = PGM_PAGE_GET_TD_CREFS(pPhysPage);
4269 AssertFatalMsg(cRefs == PGMPOOL_TD_CREFS_PHYSEXT, ("cRefs=%d pPhysPage=%R[pgmpage] pPage=%p:{.idx=%d}\n", cRefs, pPhysPage, pPage, pPage->idx));
4270
4271 uint16_t iPhysExt = PGM_PAGE_GET_TD_IDX(pPhysPage);
4272 if (iPhysExt != PGMPOOL_TD_IDX_OVERFLOWED)
4273 {
4274 pgmLock(pVM);
4275
4276 uint16_t iPhysExtPrev = NIL_PGMPOOL_PHYSEXT_INDEX;
4277 PPGMPOOLPHYSEXT paPhysExts = pPool->CTX_SUFF(paPhysExts);
4278 do
4279 {
4280 Assert(iPhysExt < pPool->cMaxPhysExts);
4281
4282 /*
4283 * Look for the shadow page and check if it's all freed.
4284 */
4285 for (unsigned i = 0; i < RT_ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
4286 {
4287 if ( paPhysExts[iPhysExt].aidx[i] == pPage->idx
4288 && paPhysExts[iPhysExt].apte[i] == iPte)
4289 {
4290 paPhysExts[iPhysExt].aidx[i] = NIL_PGMPOOL_IDX;
4291 paPhysExts[iPhysExt].apte[i] = NIL_PGMPOOL_PHYSEXT_IDX_PTE;
4292
4293 for (i = 0; i < RT_ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
4294 if (paPhysExts[iPhysExt].aidx[i] != NIL_PGMPOOL_IDX)
4295 {
4296 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage] idx=%d\n", pPhysPage, pPage->idx));
4297 pgmUnlock(pVM);
4298 return;
4299 }
4300
4301 /* we can free the node. */
4302 const uint16_t iPhysExtNext = paPhysExts[iPhysExt].iNext;
4303 if ( iPhysExtPrev == NIL_PGMPOOL_PHYSEXT_INDEX
4304 && iPhysExtNext == NIL_PGMPOOL_PHYSEXT_INDEX)
4305 {
4306 /* lonely node */
4307 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
4308 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage] idx=%d lonely\n", pPhysPage, pPage->idx));
4309 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, 0);
4310 }
4311 else if (iPhysExtPrev == NIL_PGMPOOL_PHYSEXT_INDEX)
4312 {
4313 /* head */
4314 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage] idx=%d head\n", pPhysPage, pPage->idx));
4315 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, PGMPOOL_TD_MAKE(PGMPOOL_TD_CREFS_PHYSEXT, iPhysExtNext));
4316 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
4317 }
4318 else
4319 {
4320 /* in list */
4321 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage] idx=%d in list\n", pPhysPage, pPage->idx));
4322 paPhysExts[iPhysExtPrev].iNext = iPhysExtNext;
4323 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
4324 }
4325 iPhysExt = iPhysExtNext;
4326 pgmUnlock(pVM);
4327 return;
4328 }
4329 }
4330
4331 /* next */
4332 iPhysExtPrev = iPhysExt;
4333 iPhysExt = paPhysExts[iPhysExt].iNext;
4334 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
4335
4336 pgmUnlock(pVM);
4337 AssertFatalMsgFailed(("not-found! cRefs=%d pPhysPage=%R[pgmpage] pPage=%p:{.idx=%d}\n", cRefs, pPhysPage, pPage, pPage->idx));
4338 }
4339 else /* nothing to do */
4340 Log2(("pgmPoolTrackPhysExtDerefGCPhys: pPhysPage=%R[pgmpage]\n", pPhysPage));
4341}
4342
4343/**
4344 * Clear references to guest physical memory.
4345 *
4346 * This is the same as pgmPoolTracDerefGCPhysHint except that the guest
4347 * physical address is assumed to be correct, so the linear search can be
4348 * skipped and we can assert at an earlier point.
4349 *
4350 * @param pPool The pool.
4351 * @param pPage The page.
4352 * @param HCPhys The host physical address corresponding to the guest page.
4353 * @param GCPhys The guest physical address corresponding to HCPhys.
4354 * @param iPte Shadow PTE index
4355 */
4356static void pgmPoolTracDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhys, uint16_t iPte)
4357{
4358 /*
4359 * Lookup the page and check if it checks out before derefing it.
4360 */
4361 PVM pVM = pPool->CTX_SUFF(pVM);
4362 PPGMPAGE pPhysPage = pgmPhysGetPage(pVM, GCPhys);
4363 if (pPhysPage)
4364 {
4365 Assert(PGM_PAGE_GET_HCPHYS(pPhysPage));
4366#ifdef LOG_ENABLED
4367 RTHCPHYS HCPhysPage = PGM_PAGE_GET_HCPHYS(pPhysPage);
4368 Log2(("pgmPoolTracDerefGCPhys %RHp vs %RHp\n", HCPhysPage, HCPhys));
4369#endif
4370 if (PGM_PAGE_GET_HCPHYS(pPhysPage) == HCPhys)
4371 {
4372 Assert(pPage->cPresent);
4373 Assert(pPool->cPresent);
4374 pPage->cPresent--;
4375 pPool->cPresent--;
4376 pgmTrackDerefGCPhys(pPool, pPage, pPhysPage, iPte);
4377 return;
4378 }
4379
4380 AssertFatalMsgFailed(("HCPhys=%RHp GCPhys=%RGp; found page has HCPhys=%RHp\n",
4381 HCPhys, GCPhys, PGM_PAGE_GET_HCPHYS(pPhysPage)));
4382 }
4383 AssertFatalMsgFailed(("HCPhys=%RHp GCPhys=%RGp\n", HCPhys, GCPhys));
4384}
4385
4386
4387/**
4388 * Clear references to guest physical memory.
4389 *
4390 * @param pPool The pool.
4391 * @param pPage The page.
4392 * @param HCPhys The host physical address corresponding to the guest page.
4393 * @param GCPhysHint The guest physical address which may corresponding to HCPhys.
4394 * @param iPte Shadow pte index
4395 */
4396void pgmPoolTracDerefGCPhysHint(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhysHint, uint16_t iPte)
4397{
4398 Log4(("pgmPoolTracDerefGCPhysHint %RHp %RGp\n", HCPhys, GCPhysHint));
4399
4400 /*
4401 * Try the hint first.
4402 */
4403 RTHCPHYS HCPhysHinted;
4404 PVM pVM = pPool->CTX_SUFF(pVM);
4405 PPGMPAGE pPhysPage = pgmPhysGetPage(pVM, GCPhysHint);
4406 if (pPhysPage)
4407 {
4408 HCPhysHinted = PGM_PAGE_GET_HCPHYS(pPhysPage);
4409 Assert(HCPhysHinted);
4410 if (HCPhysHinted == HCPhys)
4411 {
4412 Assert(pPage->cPresent);
4413 Assert(pPool->cPresent);
4414 pPage->cPresent--;
4415 pPool->cPresent--;
4416 pgmTrackDerefGCPhys(pPool, pPage, pPhysPage, iPte);
4417 return;
4418 }
4419 }
4420 else
4421 HCPhysHinted = UINT64_C(0xdeadbeefdeadbeef);
4422
4423 /*
4424 * Damn, the hint didn't work. We'll have to do an expensive linear search.
4425 */
4426 STAM_COUNTER_INC(&pPool->StatTrackLinearRamSearches);
4427 PPGMRAMRANGE pRam = pPool->CTX_SUFF(pVM)->pgm.s.CTX_SUFF(pRamRangesX);
4428 while (pRam)
4429 {
4430 unsigned iPage = pRam->cb >> PAGE_SHIFT;
4431 while (iPage-- > 0)
4432 {
4433 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
4434 {
4435 Log4(("pgmPoolTracDerefGCPhysHint: Linear HCPhys=%RHp GCPhysHint=%RGp GCPhysReal=%RGp\n",
4436 HCPhys, GCPhysHint, pRam->GCPhys + (iPage << PAGE_SHIFT)));
4437 Assert(pPage->cPresent);
4438 Assert(pPool->cPresent);
4439 pPage->cPresent--;
4440 pPool->cPresent--;
4441 pgmTrackDerefGCPhys(pPool, pPage, &pRam->aPages[iPage], iPte);
4442 return;
4443 }
4444 }
4445 pRam = pRam->CTX_SUFF(pNext);
4446 }
4447
4448 AssertFatalMsgFailed(("HCPhys=%RHp GCPhysHint=%RGp (Hinted page has HCPhys = %RHp)\n", HCPhys, GCPhysHint, HCPhysHinted));
4449}
4450
4451
4452/**
4453 * Clear references to guest physical memory in a 32-bit / 32-bit page table.
4454 *
4455 * @param pPool The pool.
4456 * @param pPage The page.
4457 * @param pShwPT The shadow page table (mapping of the page).
4458 * @param pGstPT The guest page table.
4459 */
4460DECLINLINE(void) pgmPoolTrackDerefPT32Bit32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PT pShwPT, PCX86PT pGstPT)
4461{
4462 RTGCPHYS32 const fPgMask = pPage->fA20Enabled ? X86_PTE_PG_MASK : X86_PTE_PG_MASK & ~RT_BIT_32(20);
4463 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++)
4464 {
4465 Assert(!(pShwPT->a[i].u & RT_BIT_32(10)));
4466 if (pShwPT->a[i].n.u1Present)
4467 {
4468 Log4(("pgmPoolTrackDerefPT32Bit32Bit: i=%d pte=%RX32 hint=%RX32\n",
4469 i, pShwPT->a[i].u & X86_PTE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK));
4470 pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PG_MASK, pGstPT->a[i].u & fPgMask, i);
4471 if (!pPage->cPresent)
4472 break;
4473 }
4474 }
4475}
4476
4477
4478/**
4479 * Clear references to guest physical memory in a PAE / 32-bit page table.
4480 *
4481 * @param pPool The pool.
4482 * @param pPage The page.
4483 * @param pShwPT The shadow page table (mapping of the page).
4484 * @param pGstPT The guest page table (just a half one).
4485 */
4486DECLINLINE(void) pgmPoolTrackDerefPTPae32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMSHWPTPAE pShwPT, PCX86PT pGstPT)
4487{
4488 RTGCPHYS32 const fPgMask = pPage->fA20Enabled ? X86_PTE_PG_MASK : X86_PTE_PG_MASK & ~RT_BIT_32(20);
4489 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++)
4490 {
4491 Assert( (PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & UINT64_C(0x7ff0000000000400)) == 0
4492 || (PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & UINT64_C(0x7ff0000000000400)) == UINT64_C(0x7ff0000000000000));
4493 if (PGMSHWPTEPAE_IS_P(pShwPT->a[i]))
4494 {
4495 Log4(("pgmPoolTrackDerefPTPae32Bit: i=%d pte=%RX64 hint=%RX32\n",
4496 i, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), pGstPT->a[i].u & X86_PTE_PG_MASK));
4497 pgmPoolTracDerefGCPhysHint(pPool, pPage, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), pGstPT->a[i].u & fPgMask, i);
4498 if (!pPage->cPresent)
4499 break;
4500 }
4501 }
4502}
4503
4504
4505/**
4506 * Clear references to guest physical memory in a PAE / PAE page table.
4507 *
4508 * @param pPool The pool.
4509 * @param pPage The page.
4510 * @param pShwPT The shadow page table (mapping of the page).
4511 * @param pGstPT The guest page table.
4512 */
4513DECLINLINE(void) pgmPoolTrackDerefPTPaePae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMSHWPTPAE pShwPT, PCX86PTPAE pGstPT)
4514{
4515 RTGCPHYS const fPgMask = pPage->fA20Enabled ? X86_PTE_PAE_PG_MASK : X86_PTE_PAE_PG_MASK & ~RT_BIT_64(20);
4516 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++)
4517 {
4518 Assert( (PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & UINT64_C(0x7ff0000000000400)) == 0
4519 || (PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & UINT64_C(0x7ff0000000000400)) == UINT64_C(0x7ff0000000000000));
4520 if (PGMSHWPTEPAE_IS_P(pShwPT->a[i]))
4521 {
4522 Log4(("pgmPoolTrackDerefPTPaePae: i=%d pte=%RX32 hint=%RX32\n",
4523 i, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), pGstPT->a[i].u & X86_PTE_PAE_PG_MASK));
4524 pgmPoolTracDerefGCPhysHint(pPool, pPage, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), pGstPT->a[i].u & fPgMask, i);
4525 if (!pPage->cPresent)
4526 break;
4527 }
4528 }
4529}
4530
4531
4532/**
4533 * Clear references to guest physical memory in a 32-bit / 4MB page table.
4534 *
4535 * @param pPool The pool.
4536 * @param pPage The page.
4537 * @param pShwPT The shadow page table (mapping of the page).
4538 */
4539DECLINLINE(void) pgmPoolTrackDerefPT32Bit4MB(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PT pShwPT)
4540{
4541 RTGCPHYS const GCPhysA20Mask = pPage->fA20Enabled ? UINT64_MAX : ~RT_BIT_64(20);
4542 RTGCPHYS GCPhys = pPage->GCPhys + PAGE_SIZE * pPage->iFirstPresent;
4543 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++, GCPhys += PAGE_SIZE)
4544 {
4545 Assert(!(pShwPT->a[i].u & RT_BIT_32(10)));
4546 if (pShwPT->a[i].n.u1Present)
4547 {
4548 Log4(("pgmPoolTrackDerefPT32Bit4MB: i=%d pte=%RX32 GCPhys=%RGp\n",
4549 i, pShwPT->a[i].u & X86_PTE_PG_MASK, GCPhys));
4550 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPT->a[i].u & X86_PTE_PG_MASK, GCPhys & GCPhysA20Mask, i);
4551 if (!pPage->cPresent)
4552 break;
4553 }
4554 }
4555}
4556
4557
4558/**
4559 * Clear references to guest physical memory in a PAE / 2/4MB page table.
4560 *
4561 * @param pPool The pool.
4562 * @param pPage The page.
4563 * @param pShwPT The shadow page table (mapping of the page).
4564 */
4565DECLINLINE(void) pgmPoolTrackDerefPTPaeBig(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMSHWPTPAE pShwPT)
4566{
4567 RTGCPHYS const GCPhysA20Mask = pPage->fA20Enabled ? UINT64_MAX : ~RT_BIT_64(20);
4568 RTGCPHYS GCPhys = pPage->GCPhys + PAGE_SIZE * pPage->iFirstPresent;
4569 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++, GCPhys += PAGE_SIZE)
4570 {
4571 Assert( (PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & UINT64_C(0x7ff0000000000400)) == 0
4572 || (PGMSHWPTEPAE_GET_U(pShwPT->a[i]) & UINT64_C(0x7ff0000000000400)) == UINT64_C(0x7ff0000000000000));
4573 if (PGMSHWPTEPAE_IS_P(pShwPT->a[i]))
4574 {
4575 Log4(("pgmPoolTrackDerefPTPaeBig: i=%d pte=%RX64 hint=%RGp\n",
4576 i, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), GCPhys));
4577 pgmPoolTracDerefGCPhys(pPool, pPage, PGMSHWPTEPAE_GET_HCPHYS(pShwPT->a[i]), GCPhys & GCPhysA20Mask, i);
4578 if (!pPage->cPresent)
4579 break;
4580 }
4581 }
4582}
4583
4584
4585/**
4586 * Clear references to shadowed pages in an EPT page table.
4587 *
4588 * @param pPool The pool.
4589 * @param pPage The page.
4590 * @param pShwPT The shadow page directory pointer table (mapping of the
4591 * page).
4592 */
4593DECLINLINE(void) pgmPoolTrackDerefPTEPT(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PEPTPT pShwPT)
4594{
4595 RTGCPHYS const GCPhysA20Mask = pPage->fA20Enabled ? UINT64_MAX : ~RT_BIT_64(20);
4596 RTGCPHYS GCPhys = pPage->GCPhys + PAGE_SIZE * pPage->iFirstPresent;
4597 for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pShwPT->a); i++, GCPhys += PAGE_SIZE)
4598 {
4599 Assert((pShwPT->a[i].u & UINT64_C(0xfff0000000000f80)) == 0);
4600 if (pShwPT->a[i].n.u1Present)
4601 {
4602 Log4(("pgmPoolTrackDerefPTEPT: i=%d pte=%RX64 GCPhys=%RX64\n",
4603 i, pShwPT->a[i].u & EPT_PTE_PG_MASK, pPage->GCPhys));
4604 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPT->a[i].u & EPT_PTE_PG_MASK, GCPhys & GCPhysA20Mask, i);
4605 if (!pPage->cPresent)
4606 break;
4607 }
4608 }
4609}
4610
4611
4612/**
4613 * Clear references to shadowed pages in a 32 bits page directory.
4614 *
4615 * @param pPool The pool.
4616 * @param pPage The page.
4617 * @param pShwPD The shadow page directory (mapping of the page).
4618 */
4619DECLINLINE(void) pgmPoolTrackDerefPD(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PD pShwPD)
4620{
4621 for (unsigned i = 0; i < RT_ELEMENTS(pShwPD->a); i++)
4622 {
4623 if ( pShwPD->a[i].n.u1Present
4624 && !(pShwPD->a[i].u & PGM_PDFLAGS_MAPPING)
4625 )
4626 {
4627 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & X86_PDE_PG_MASK);
4628 if (pSubPage)
4629 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
4630 else
4631 AssertFatalMsgFailed(("%x\n", pShwPD->a[i].u & X86_PDE_PG_MASK));
4632 }
4633 }
4634}
4635
4636
4637/**
4638 * Clear references to shadowed pages in a PAE (legacy or 64 bits) page directory.
4639 *
4640 * @param pPool The pool.
4641 * @param pPage The page.
4642 * @param pShwPD The shadow page directory (mapping of the page).
4643 */
4644DECLINLINE(void) pgmPoolTrackDerefPDPae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PDPAE pShwPD)
4645{
4646 for (unsigned i = 0; i < RT_ELEMENTS(pShwPD->a); i++)
4647 {
4648 if ( pShwPD->a[i].n.u1Present
4649 && !(pShwPD->a[i].u & PGM_PDFLAGS_MAPPING))
4650 {
4651#ifdef PGM_WITH_LARGE_PAGES
4652 if (pShwPD->a[i].b.u1Size)
4653 {
4654 Log4(("pgmPoolTrackDerefPDPae: i=%d pde=%RX64 GCPhys=%RX64\n",
4655 i, pShwPD->a[i].u & X86_PDE2M_PAE_PG_MASK, pPage->GCPhys));
4656 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPD->a[i].u & X86_PDE2M_PAE_PG_MASK,
4657 pPage->GCPhys + i * 2 * _1M /* pPage->GCPhys = base address of the memory described by the PD */,
4658 i);
4659 }
4660 else
4661#endif
4662 {
4663 Assert((pShwPD->a[i].u & (X86_PDE_PAE_MBZ_MASK_NX | UINT64_C(0x7ff0000000000000))) == 0);
4664 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & X86_PDE_PAE_PG_MASK);
4665 if (pSubPage)
4666 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
4667 else
4668 AssertFatalMsgFailed(("%RX64\n", pShwPD->a[i].u & X86_PDE_PAE_PG_MASK));
4669 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
4670 }
4671 }
4672 }
4673}
4674
4675
4676/**
4677 * Clear references to shadowed pages in a PAE page directory pointer table.
4678 *
4679 * @param pPool The pool.
4680 * @param pPage The page.
4681 * @param pShwPDPT The shadow page directory pointer table (mapping of the page).
4682 */
4683DECLINLINE(void) pgmPoolTrackDerefPDPTPae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PDPT pShwPDPT)
4684{
4685 for (unsigned i = 0; i < X86_PG_PAE_PDPE_ENTRIES; i++)
4686 {
4687 Assert((pShwPDPT->a[i].u & (X86_PDPE_PAE_MBZ_MASK | UINT64_C(0x7ff0000000000200))) == 0);
4688 if ( pShwPDPT->a[i].n.u1Present
4689 && !(pShwPDPT->a[i].u & PGM_PLXFLAGS_MAPPING)
4690 )
4691 {
4692 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & X86_PDPE_PG_MASK);
4693 if (pSubPage)
4694 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
4695 else
4696 AssertFatalMsgFailed(("%RX64\n", pShwPDPT->a[i].u & X86_PDPE_PG_MASK));
4697 }
4698 }
4699}
4700
4701
4702/**
4703 * Clear references to shadowed pages in a 64-bit page directory pointer table.
4704 *
4705 * @param pPool The pool.
4706 * @param pPage The page.
4707 * @param pShwPDPT The shadow page directory pointer table (mapping of the page).
4708 */
4709DECLINLINE(void) pgmPoolTrackDerefPDPT64Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PDPT pShwPDPT)
4710{
4711 for (unsigned i = 0; i < RT_ELEMENTS(pShwPDPT->a); i++)
4712 {
4713 Assert((pShwPDPT->a[i].u & (X86_PDPE_LM_MBZ_MASK_NX | UINT64_C(0x7ff0000000000200))) == 0);
4714 if (pShwPDPT->a[i].n.u1Present)
4715 {
4716 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & X86_PDPE_PG_MASK);
4717 if (pSubPage)
4718 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
4719 else
4720 AssertFatalMsgFailed(("%RX64\n", pShwPDPT->a[i].u & X86_PDPE_PG_MASK));
4721 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
4722 }
4723 }
4724}
4725
4726
4727/**
4728 * Clear references to shadowed pages in a 64-bit level 4 page table.
4729 *
4730 * @param pPool The pool.
4731 * @param pPage The page.
4732 * @param pShwPML4 The shadow page directory pointer table (mapping of the page).
4733 */
4734DECLINLINE(void) pgmPoolTrackDerefPML464Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PML4 pShwPML4)
4735{
4736 for (unsigned i = 0; i < RT_ELEMENTS(pShwPML4->a); i++)
4737 {
4738 Assert((pShwPML4->a[i].u & (X86_PML4E_MBZ_MASK_NX | UINT64_C(0x7ff0000000000200))) == 0);
4739 if (pShwPML4->a[i].n.u1Present)
4740 {
4741 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPML4->a[i].u & X86_PDPE_PG_MASK);
4742 if (pSubPage)
4743 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
4744 else
4745 AssertFatalMsgFailed(("%RX64\n", pShwPML4->a[i].u & X86_PML4E_PG_MASK));
4746 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
4747 }
4748 }
4749}
4750
4751
4752/**
4753 * Clear references to shadowed pages in an EPT page directory.
4754 *
4755 * @param pPool The pool.
4756 * @param pPage The page.
4757 * @param pShwPD The shadow page directory (mapping of the page).
4758 */
4759DECLINLINE(void) pgmPoolTrackDerefPDEPT(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PEPTPD pShwPD)
4760{
4761 for (unsigned i = 0; i < RT_ELEMENTS(pShwPD->a); i++)
4762 {
4763 Assert((pShwPD->a[i].u & UINT64_C(0xfff0000000000f80)) == 0);
4764 if (pShwPD->a[i].n.u1Present)
4765 {
4766#ifdef PGM_WITH_LARGE_PAGES
4767 if (pShwPD->a[i].b.u1Size)
4768 {
4769 Log4(("pgmPoolTrackDerefPDEPT: i=%d pde=%RX64 GCPhys=%RX64\n",
4770 i, pShwPD->a[i].u & X86_PDE2M_PAE_PG_MASK, pPage->GCPhys));
4771 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPD->a[i].u & X86_PDE2M_PAE_PG_MASK,
4772 pPage->GCPhys + i * 2 * _1M /* pPage->GCPhys = base address of the memory described by the PD */,
4773 i);
4774 }
4775 else
4776#endif
4777 {
4778 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & EPT_PDE_PG_MASK);
4779 if (pSubPage)
4780 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
4781 else
4782 AssertFatalMsgFailed(("%RX64\n", pShwPD->a[i].u & EPT_PDE_PG_MASK));
4783 }
4784 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
4785 }
4786 }
4787}
4788
4789
4790/**
4791 * Clear references to shadowed pages in an EPT page directory pointer table.
4792 *
4793 * @param pPool The pool.
4794 * @param pPage The page.
4795 * @param pShwPDPT The shadow page directory pointer table (mapping of the page).
4796 */
4797DECLINLINE(void) pgmPoolTrackDerefPDPTEPT(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PEPTPDPT pShwPDPT)
4798{
4799 for (unsigned i = 0; i < RT_ELEMENTS(pShwPDPT->a); i++)
4800 {
4801 Assert((pShwPDPT->a[i].u & UINT64_C(0xfff0000000000f80)) == 0);
4802 if (pShwPDPT->a[i].n.u1Present)
4803 {
4804 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & EPT_PDPTE_PG_MASK);
4805 if (pSubPage)
4806 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
4807 else
4808 AssertFatalMsgFailed(("%RX64\n", pShwPDPT->a[i].u & EPT_PDPTE_PG_MASK));
4809 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
4810 }
4811 }
4812}
4813
4814
4815/**
4816 * Clears all references made by this page.
4817 *
4818 * This includes other shadow pages and GC physical addresses.
4819 *
4820 * @param pPool The pool.
4821 * @param pPage The page.
4822 */
4823static void pgmPoolTrackDeref(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
4824{
4825 /*
4826 * Map the shadow page and take action according to the page kind.
4827 */
4828 PVM pVM = pPool->CTX_SUFF(pVM);
4829 void *pvShw = PGMPOOL_PAGE_2_PTR(pVM, pPage);
4830 switch (pPage->enmKind)
4831 {
4832 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
4833 {
4834 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
4835 void *pvGst;
4836 int rc = PGM_GCPHYS_2_PTR(pVM, pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
4837 pgmPoolTrackDerefPT32Bit32Bit(pPool, pPage, (PX86PT)pvShw, (PCX86PT)pvGst);
4838 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvGst);
4839 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
4840 break;
4841 }
4842
4843 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
4844 {
4845 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
4846 void *pvGst;
4847 int rc = PGM_GCPHYS_2_PTR_EX(pVM, pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
4848 pgmPoolTrackDerefPTPae32Bit(pPool, pPage, (PPGMSHWPTPAE)pvShw, (PCX86PT)pvGst);
4849 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvGst);
4850 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
4851 break;
4852 }
4853
4854 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
4855 {
4856 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
4857 void *pvGst;
4858 int rc = PGM_GCPHYS_2_PTR(pVM, pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
4859 pgmPoolTrackDerefPTPaePae(pPool, pPage, (PPGMSHWPTPAE)pvShw, (PCX86PTPAE)pvGst);
4860 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvGst);
4861 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
4862 break;
4863 }
4864
4865 case PGMPOOLKIND_32BIT_PT_FOR_PHYS: /* treat it like a 4 MB page */
4866 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
4867 {
4868 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
4869 pgmPoolTrackDerefPT32Bit4MB(pPool, pPage, (PX86PT)pvShw);
4870 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
4871 break;
4872 }
4873
4874 case PGMPOOLKIND_PAE_PT_FOR_PHYS: /* treat it like a 2 MB page */
4875 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
4876 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
4877 {
4878 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
4879 pgmPoolTrackDerefPTPaeBig(pPool, pPage, (PPGMSHWPTPAE)pvShw);
4880 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
4881 break;
4882 }
4883
4884 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
4885 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
4886 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
4887 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
4888 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
4889 case PGMPOOLKIND_PAE_PD_PHYS:
4890 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
4891 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
4892 pgmPoolTrackDerefPDPae(pPool, pPage, (PX86PDPAE)pvShw);
4893 break;
4894
4895 case PGMPOOLKIND_32BIT_PD_PHYS:
4896 case PGMPOOLKIND_32BIT_PD:
4897 pgmPoolTrackDerefPD(pPool, pPage, (PX86PD)pvShw);
4898 break;
4899
4900 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
4901 case PGMPOOLKIND_PAE_PDPT:
4902 case PGMPOOLKIND_PAE_PDPT_PHYS:
4903 pgmPoolTrackDerefPDPTPae(pPool, pPage, (PX86PDPT)pvShw);
4904 break;
4905
4906 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
4907 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
4908 pgmPoolTrackDerefPDPT64Bit(pPool, pPage, (PX86PDPT)pvShw);
4909 break;
4910
4911 case PGMPOOLKIND_64BIT_PML4:
4912 pgmPoolTrackDerefPML464Bit(pPool, pPage, (PX86PML4)pvShw);
4913 break;
4914
4915 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
4916 pgmPoolTrackDerefPTEPT(pPool, pPage, (PEPTPT)pvShw);
4917 break;
4918
4919 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
4920 pgmPoolTrackDerefPDEPT(pPool, pPage, (PEPTPD)pvShw);
4921 break;
4922
4923 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
4924 pgmPoolTrackDerefPDPTEPT(pPool, pPage, (PEPTPDPT)pvShw);
4925 break;
4926
4927 default:
4928 AssertFatalMsgFailed(("enmKind=%d\n", pPage->enmKind));
4929 }
4930
4931 /* paranoia, clear the shadow page. Remove this laser (i.e. let Alloc and ClearAll do it). */
4932 STAM_PROFILE_START(&pPool->StatZeroPage, z);
4933 ASMMemZeroPage(pvShw);
4934 STAM_PROFILE_STOP(&pPool->StatZeroPage, z);
4935 pPage->fZeroed = true;
4936 Assert(!pPage->cPresent);
4937 PGM_DYNMAP_UNUSED_HINT_VM(pVM, pvShw);
4938}
4939
4940
4941/**
4942 * Flushes a pool page.
4943 *
4944 * This moves the page to the free list after removing all user references to it.
4945 *
4946 * @returns VBox status code.
4947 * @retval VINF_SUCCESS on success.
4948 * @param pPool The pool.
4949 * @param pPage The shadow page.
4950 * @param fFlush Flush the TLBS when required (should only be false in very specific use cases!!)
4951 */
4952int pgmPoolFlushPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage, bool fFlush)
4953{
4954 PVM pVM = pPool->CTX_SUFF(pVM);
4955 bool fFlushRequired = false;
4956
4957 int rc = VINF_SUCCESS;
4958 STAM_PROFILE_START(&pPool->StatFlushPage, f);
4959 LogFlow(("pgmPoolFlushPage: pPage=%p:{.Key=%RHp, .idx=%d, .enmKind=%s, .GCPhys=%RGp}\n",
4960 pPage, pPage->Core.Key, pPage->idx, pgmPoolPoolKindToStr(pPage->enmKind), pPage->GCPhys));
4961
4962 /*
4963 * Reject any attempts at flushing any of the special root pages (shall
4964 * not happen).
4965 */
4966 AssertMsgReturn(pPage->idx >= PGMPOOL_IDX_FIRST,
4967 ("pgmPoolFlushPage: special root page, rejected. enmKind=%s idx=%d\n",
4968 pgmPoolPoolKindToStr(pPage->enmKind), pPage->idx),
4969 VINF_SUCCESS);
4970
4971 pgmLock(pVM);
4972
4973 /*
4974 * Quietly reject any attempts at flushing the currently active shadow CR3 mapping
4975 */
4976 if (pgmPoolIsPageLocked(pPage))
4977 {
4978 AssertMsg( pPage->enmKind == PGMPOOLKIND_64BIT_PML4
4979 || pPage->enmKind == PGMPOOLKIND_PAE_PDPT
4980 || pPage->enmKind == PGMPOOLKIND_PAE_PDPT_FOR_32BIT
4981 || pPage->enmKind == PGMPOOLKIND_32BIT_PD
4982 || pPage->enmKind == PGMPOOLKIND_PAE_PD_FOR_PAE_PD
4983 || pPage->enmKind == PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD
4984 || pPage->enmKind == PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD
4985 || pPage->enmKind == PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD
4986 || pPage->enmKind == PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD
4987 || pPage->enmKind == PGMPOOLKIND_ROOT_NESTED,
4988 ("Can't free the shadow CR3! (%RHp vs %RHp kind=%d\n", PGMGetHyperCR3(VMMGetCpu(pVM)), pPage->Core.Key, pPage->enmKind));
4989 Log(("pgmPoolFlushPage: current active shadow CR3, rejected. enmKind=%s idx=%d\n", pgmPoolPoolKindToStr(pPage->enmKind), pPage->idx));
4990 pgmUnlock(pVM);
4991 return VINF_SUCCESS;
4992 }
4993
4994#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
4995 /* Start a subset so we won't run out of mapping space. */
4996 PVMCPU pVCpu = VMMGetCpu(pVM);
4997 uint32_t iPrevSubset = PGMRZDynMapPushAutoSubset(pVCpu);
4998#endif
4999
5000 /*
5001 * Mark the page as being in need of an ASMMemZeroPage().
5002 */
5003 pPage->fZeroed = false;
5004
5005#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
5006 if (pPage->fDirty)
5007 pgmPoolFlushDirtyPage(pVM, pPool, pPage->idxDirtyEntry, false /* do not remove */);
5008#endif
5009
5010 /* If there are any users of this table, then we *must* issue a tlb flush on all VCPUs. */
5011 if (pPage->iUserHead != NIL_PGMPOOL_USER_INDEX)
5012 fFlushRequired = true;
5013
5014 /*
5015 * Clear the page.
5016 */
5017 pgmPoolTrackClearPageUsers(pPool, pPage);
5018 STAM_PROFILE_START(&pPool->StatTrackDeref,a);
5019 pgmPoolTrackDeref(pPool, pPage);
5020 STAM_PROFILE_STOP(&pPool->StatTrackDeref,a);
5021
5022 /*
5023 * Flush it from the cache.
5024 */
5025 pgmPoolCacheFlushPage(pPool, pPage);
5026
5027#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
5028 /* Heavy stuff done. */
5029 PGMRZDynMapPopAutoSubset(pVCpu, iPrevSubset);
5030#endif
5031
5032 /*
5033 * Deregistering the monitoring.
5034 */
5035 if (pPage->fMonitored)
5036 rc = pgmPoolMonitorFlush(pPool, pPage);
5037
5038 /*
5039 * Free the page.
5040 */
5041 Assert(pPage->iNext == NIL_PGMPOOL_IDX);
5042 pPage->iNext = pPool->iFreeHead;
5043 pPool->iFreeHead = pPage->idx;
5044 pPage->enmKind = PGMPOOLKIND_FREE;
5045 pPage->enmAccess = PGMPOOLACCESS_DONTCARE;
5046 pPage->GCPhys = NIL_RTGCPHYS;
5047 pPage->fReusedFlushPending = false;
5048
5049 pPool->cUsedPages--;
5050
5051 /* Flush the TLBs of all VCPUs if required. */
5052 if ( fFlushRequired
5053 && fFlush)
5054 {
5055 PGM_INVL_ALL_VCPU_TLBS(pVM);
5056 }
5057
5058 pgmUnlock(pVM);
5059 STAM_PROFILE_STOP(&pPool->StatFlushPage, f);
5060 return rc;
5061}
5062
5063
5064/**
5065 * Frees a usage of a pool page.
5066 *
5067 * The caller is responsible to updating the user table so that it no longer
5068 * references the shadow page.
5069 *
5070 * @param pPool The pool.
5071 * @param pPage The shadow page.
5072 * @param iUser The shadow page pool index of the user table.
5073 * NIL_PGMPOOL_IDX for root pages.
5074 * @param iUserTable The index into the user table (shadowed). Ignored if
5075 * root page.
5076 */
5077void pgmPoolFreeByPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable)
5078{
5079 PVM pVM = pPool->CTX_SUFF(pVM);
5080
5081 STAM_PROFILE_START(&pPool->StatFree, a);
5082 LogFlow(("pgmPoolFreeByPage: pPage=%p:{.Key=%RHp, .idx=%d, enmKind=%s} iUser=%d iUserTable=%#x\n",
5083 pPage, pPage->Core.Key, pPage->idx, pgmPoolPoolKindToStr(pPage->enmKind), iUser, iUserTable));
5084 AssertReturnVoid(pPage->idx >= PGMPOOL_IDX_FIRST); /* paranoia (#6349) */
5085
5086 pgmLock(pVM);
5087 if (iUser != NIL_PGMPOOL_IDX)
5088 pgmPoolTrackFreeUser(pPool, pPage, iUser, iUserTable);
5089 if (!pPage->fCached)
5090 pgmPoolFlushPage(pPool, pPage);
5091 pgmUnlock(pVM);
5092 STAM_PROFILE_STOP(&pPool->StatFree, a);
5093}
5094
5095
5096/**
5097 * Makes one or more free page free.
5098 *
5099 * @returns VBox status code.
5100 * @retval VINF_SUCCESS on success.
5101 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
5102 *
5103 * @param pPool The pool.
5104 * @param enmKind Page table kind
5105 * @param iUser The user of the page.
5106 */
5107static int pgmPoolMakeMoreFreePages(PPGMPOOL pPool, PGMPOOLKIND enmKind, uint16_t iUser)
5108{
5109 PVM pVM = pPool->CTX_SUFF(pVM);
5110 LogFlow(("pgmPoolMakeMoreFreePages: enmKind=%d iUser=%d\n", enmKind, iUser));
5111 NOREF(enmKind);
5112
5113 /*
5114 * If the pool isn't full grown yet, expand it.
5115 */
5116 if ( pPool->cCurPages < pPool->cMaxPages
5117#if defined(IN_RC)
5118 /* Hack alert: we can't deal with jumps to ring 3 when called from MapCR3 and allocating pages for PAE PDs. */
5119 && enmKind != PGMPOOLKIND_PAE_PD_FOR_PAE_PD
5120 && (enmKind < PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD || enmKind > PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD)
5121#endif
5122 )
5123 {
5124 STAM_PROFILE_ADV_SUSPEND(&pPool->StatAlloc, a);
5125#ifdef IN_RING3
5126 int rc = PGMR3PoolGrow(pVM);
5127#else
5128 int rc = VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_PGM_POOL_GROW, 0);
5129#endif
5130 if (RT_FAILURE(rc))
5131 return rc;
5132 STAM_PROFILE_ADV_RESUME(&pPool->StatAlloc, a);
5133 if (pPool->iFreeHead != NIL_PGMPOOL_IDX)
5134 return VINF_SUCCESS;
5135 }
5136
5137 /*
5138 * Free one cached page.
5139 */
5140 return pgmPoolCacheFreeOne(pPool, iUser);
5141}
5142
5143
5144/**
5145 * Allocates a page from the pool.
5146 *
5147 * This page may actually be a cached page and not in need of any processing
5148 * on the callers part.
5149 *
5150 * @returns VBox status code.
5151 * @retval VINF_SUCCESS if a NEW page was allocated.
5152 * @retval VINF_PGM_CACHED_PAGE if a CACHED page was returned.
5153 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
5154 *
5155 * @param pVM The cross context VM structure.
5156 * @param GCPhys The GC physical address of the page we're gonna shadow.
5157 * For 4MB and 2MB PD entries, it's the first address the
5158 * shadow PT is covering.
5159 * @param enmKind The kind of mapping.
5160 * @param enmAccess Access type for the mapping (only relevant for big pages)
5161 * @param fA20Enabled Whether the A20 gate is enabled or not.
5162 * @param iUser The shadow page pool index of the user table. Root
5163 * pages should pass NIL_PGMPOOL_IDX.
5164 * @param iUserTable The index into the user table (shadowed). Ignored for
5165 * root pages (iUser == NIL_PGMPOOL_IDX).
5166 * @param fLockPage Lock the page
5167 * @param ppPage Where to store the pointer to the page. NULL is stored here on failure.
5168 */
5169int pgmPoolAlloc(PVM pVM, RTGCPHYS GCPhys, PGMPOOLKIND enmKind, PGMPOOLACCESS enmAccess, bool fA20Enabled,
5170 uint16_t iUser, uint32_t iUserTable, bool fLockPage, PPPGMPOOLPAGE ppPage)
5171{
5172 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
5173 STAM_PROFILE_ADV_START(&pPool->StatAlloc, a);
5174 LogFlow(("pgmPoolAlloc: GCPhys=%RGp enmKind=%s iUser=%d iUserTable=%#x\n", GCPhys, pgmPoolPoolKindToStr(enmKind), iUser, iUserTable));
5175 *ppPage = NULL;
5176 /** @todo CSAM/PGMPrefetchPage messes up here during CSAMR3CheckGates
5177 * (TRPMR3SyncIDT) because of FF priority. Try fix that?
5178 * Assert(!(pVM->pgm.s.fGlobalSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)); */
5179
5180 pgmLock(pVM);
5181
5182 if (pPool->fCacheEnabled)
5183 {
5184 int rc2 = pgmPoolCacheAlloc(pPool, GCPhys, enmKind, enmAccess, fA20Enabled, iUser, iUserTable, ppPage);
5185 if (RT_SUCCESS(rc2))
5186 {
5187 if (fLockPage)
5188 pgmPoolLockPage(pPool, *ppPage);
5189 pgmUnlock(pVM);
5190 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
5191 LogFlow(("pgmPoolAlloc: cached returns %Rrc *ppPage=%p:{.Key=%RHp, .idx=%d}\n", rc2, *ppPage, (*ppPage)->Core.Key, (*ppPage)->idx));
5192 return rc2;
5193 }
5194 }
5195
5196 /*
5197 * Allocate a new one.
5198 */
5199 int rc = VINF_SUCCESS;
5200 uint16_t iNew = pPool->iFreeHead;
5201 if (iNew == NIL_PGMPOOL_IDX)
5202 {
5203 rc = pgmPoolMakeMoreFreePages(pPool, enmKind, iUser);
5204 if (RT_FAILURE(rc))
5205 {
5206 pgmUnlock(pVM);
5207 Log(("pgmPoolAlloc: returns %Rrc (Free)\n", rc));
5208 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
5209 return rc;
5210 }
5211 iNew = pPool->iFreeHead;
5212 AssertReleaseReturn(iNew != NIL_PGMPOOL_IDX, VERR_PGM_POOL_IPE);
5213 }
5214
5215 /* unlink the free head */
5216 PPGMPOOLPAGE pPage = &pPool->aPages[iNew];
5217 pPool->iFreeHead = pPage->iNext;
5218 pPage->iNext = NIL_PGMPOOL_IDX;
5219
5220 /*
5221 * Initialize it.
5222 */
5223 pPool->cUsedPages++; /* physical handler registration / pgmPoolTrackFlushGCPhysPTsSlow requirement. */
5224 pPage->enmKind = enmKind;
5225 pPage->enmAccess = enmAccess;
5226 pPage->GCPhys = GCPhys;
5227 pPage->fA20Enabled = fA20Enabled;
5228 pPage->fSeenNonGlobal = false; /* Set this to 'true' to disable this feature. */
5229 pPage->fMonitored = false;
5230 pPage->fCached = false;
5231 pPage->fDirty = false;
5232 pPage->fReusedFlushPending = false;
5233 pPage->cModifications = 0;
5234 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
5235 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
5236 pPage->cPresent = 0;
5237 pPage->iFirstPresent = NIL_PGMPOOL_PRESENT_INDEX;
5238 pPage->idxDirtyEntry = 0;
5239 pPage->GCPtrLastAccessHandlerFault = NIL_RTGCPTR;
5240 pPage->GCPtrLastAccessHandlerRip = NIL_RTGCPTR;
5241 pPage->cLastAccessHandler = 0;
5242 pPage->cLocked = 0;
5243# ifdef VBOX_STRICT
5244 pPage->GCPtrDirtyFault = NIL_RTGCPTR;
5245# endif
5246
5247 /*
5248 * Insert into the tracking and cache. If this fails, free the page.
5249 */
5250 int rc3 = pgmPoolTrackInsert(pPool, pPage, GCPhys, iUser, iUserTable);
5251 if (RT_FAILURE(rc3))
5252 {
5253 pPool->cUsedPages--;
5254 pPage->enmKind = PGMPOOLKIND_FREE;
5255 pPage->enmAccess = PGMPOOLACCESS_DONTCARE;
5256 pPage->GCPhys = NIL_RTGCPHYS;
5257 pPage->iNext = pPool->iFreeHead;
5258 pPool->iFreeHead = pPage->idx;
5259 pgmUnlock(pVM);
5260 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
5261 Log(("pgmPoolAlloc: returns %Rrc (Insert)\n", rc3));
5262 return rc3;
5263 }
5264
5265 /*
5266 * Commit the allocation, clear the page and return.
5267 */
5268#ifdef VBOX_WITH_STATISTICS
5269 if (pPool->cUsedPages > pPool->cUsedPagesHigh)
5270 pPool->cUsedPagesHigh = pPool->cUsedPages;
5271#endif
5272
5273 if (!pPage->fZeroed)
5274 {
5275 STAM_PROFILE_START(&pPool->StatZeroPage, z);
5276 void *pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
5277 ASMMemZeroPage(pv);
5278 STAM_PROFILE_STOP(&pPool->StatZeroPage, z);
5279 }
5280
5281 *ppPage = pPage;
5282 if (fLockPage)
5283 pgmPoolLockPage(pPool, pPage);
5284 pgmUnlock(pVM);
5285 LogFlow(("pgmPoolAlloc: returns %Rrc *ppPage=%p:{.Key=%RHp, .idx=%d, .fCached=%RTbool, .fMonitored=%RTbool}\n",
5286 rc, pPage, pPage->Core.Key, pPage->idx, pPage->fCached, pPage->fMonitored));
5287 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
5288 return rc;
5289}
5290
5291
5292/**
5293 * Frees a usage of a pool page.
5294 *
5295 * @param pVM The cross context VM structure.
5296 * @param HCPhys The HC physical address of the shadow page.
5297 * @param iUser The shadow page pool index of the user table.
5298 * NIL_PGMPOOL_IDX if root page.
5299 * @param iUserTable The index into the user table (shadowed). Ignored if
5300 * root page.
5301 */
5302void pgmPoolFree(PVM pVM, RTHCPHYS HCPhys, uint16_t iUser, uint32_t iUserTable)
5303{
5304 LogFlow(("pgmPoolFree: HCPhys=%RHp iUser=%d iUserTable=%#x\n", HCPhys, iUser, iUserTable));
5305 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
5306 pgmPoolFreeByPage(pPool, pgmPoolGetPage(pPool, HCPhys), iUser, iUserTable);
5307}
5308
5309
5310/**
5311 * Internal worker for finding a 'in-use' shadow page give by it's physical address.
5312 *
5313 * @returns Pointer to the shadow page structure.
5314 * @param pPool The pool.
5315 * @param HCPhys The HC physical address of the shadow page.
5316 */
5317PPGMPOOLPAGE pgmPoolGetPage(PPGMPOOL pPool, RTHCPHYS HCPhys)
5318{
5319 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM));
5320
5321 /*
5322 * Look up the page.
5323 */
5324 PPGMPOOLPAGE pPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, HCPhys & X86_PTE_PAE_PG_MASK);
5325
5326 AssertFatalMsg(pPage && pPage->enmKind != PGMPOOLKIND_FREE, ("HCPhys=%RHp pPage=%p idx=%d\n", HCPhys, pPage, (pPage) ? pPage->idx : 0));
5327 return pPage;
5328}
5329
5330
5331/**
5332 * Internal worker for finding a page for debugging purposes, no assertions.
5333 *
5334 * @returns Pointer to the shadow page structure. NULL on if not found.
5335 * @param pPool The pool.
5336 * @param HCPhys The HC physical address of the shadow page.
5337 */
5338PPGMPOOLPAGE pgmPoolQueryPageForDbg(PPGMPOOL pPool, RTHCPHYS HCPhys)
5339{
5340 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM));
5341 return (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, HCPhys & X86_PTE_PAE_PG_MASK);
5342}
5343
5344#ifdef IN_RING3 /* currently only used in ring 3; save some space in the R0 & GC modules (left it here as we might need it elsewhere later on) */
5345
5346/**
5347 * Flush the specified page if present
5348 *
5349 * @param pVM The cross context VM structure.
5350 * @param GCPhys Guest physical address of the page to flush
5351 */
5352void pgmPoolFlushPageByGCPhys(PVM pVM, RTGCPHYS GCPhys)
5353{
5354 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
5355
5356 VM_ASSERT_EMT(pVM);
5357
5358 /*
5359 * Look up the GCPhys in the hash.
5360 */
5361 GCPhys = GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK;
5362 unsigned i = pPool->aiHash[PGMPOOL_HASH(GCPhys)];
5363 if (i == NIL_PGMPOOL_IDX)
5364 return;
5365
5366 do
5367 {
5368 PPGMPOOLPAGE pPage = &pPool->aPages[i];
5369 if (pPage->GCPhys - GCPhys < PAGE_SIZE)
5370 {
5371 switch (pPage->enmKind)
5372 {
5373 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
5374 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
5375 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
5376 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
5377 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
5378 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
5379 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
5380 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
5381 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
5382 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
5383 case PGMPOOLKIND_64BIT_PML4:
5384 case PGMPOOLKIND_32BIT_PD:
5385 case PGMPOOLKIND_PAE_PDPT:
5386 {
5387 Log(("PGMPoolFlushPage: found pgm pool pages for %RGp\n", GCPhys));
5388#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
5389 if (pPage->fDirty)
5390 STAM_COUNTER_INC(&pPool->StatForceFlushDirtyPage);
5391 else
5392#endif
5393 STAM_COUNTER_INC(&pPool->StatForceFlushPage);
5394 Assert(!pgmPoolIsPageLocked(pPage));
5395 pgmPoolMonitorChainFlush(pPool, pPage);
5396 return;
5397 }
5398
5399 /* ignore, no monitoring. */
5400 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
5401 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
5402 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
5403 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
5404 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
5405 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
5406 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
5407 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
5408 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
5409 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
5410 case PGMPOOLKIND_ROOT_NESTED:
5411 case PGMPOOLKIND_PAE_PD_PHYS:
5412 case PGMPOOLKIND_PAE_PDPT_PHYS:
5413 case PGMPOOLKIND_32BIT_PD_PHYS:
5414 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
5415 break;
5416
5417 default:
5418 AssertFatalMsgFailed(("enmKind=%d idx=%d\n", pPage->enmKind, pPage->idx));
5419 }
5420 }
5421
5422 /* next */
5423 i = pPage->iNext;
5424 } while (i != NIL_PGMPOOL_IDX);
5425 return;
5426}
5427
5428#endif /* IN_RING3 */
5429#ifdef IN_RING3
5430
5431/**
5432 * Reset CPU on hot plugging.
5433 *
5434 * @param pVM The cross context VM structure.
5435 * @param pVCpu The cross context virtual CPU structure.
5436 */
5437void pgmR3PoolResetUnpluggedCpu(PVM pVM, PVMCPU pVCpu)
5438{
5439 pgmR3ExitShadowModeBeforePoolFlush(pVCpu);
5440
5441 pgmR3ReEnterShadowModeAfterPoolFlush(pVM, pVCpu);
5442 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
5443 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
5444}
5445
5446
5447/**
5448 * Flushes the entire cache.
5449 *
5450 * It will assert a global CR3 flush (FF) and assumes the caller is aware of
5451 * this and execute this CR3 flush.
5452 *
5453 * @param pVM The cross context VM structure.
5454 */
5455void pgmR3PoolReset(PVM pVM)
5456{
5457 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
5458
5459 PGM_LOCK_ASSERT_OWNER(pVM);
5460 STAM_PROFILE_START(&pPool->StatR3Reset, a);
5461 LogFlow(("pgmR3PoolReset:\n"));
5462
5463 /*
5464 * If there are no pages in the pool, there is nothing to do.
5465 */
5466 if (pPool->cCurPages <= PGMPOOL_IDX_FIRST)
5467 {
5468 STAM_PROFILE_STOP(&pPool->StatR3Reset, a);
5469 return;
5470 }
5471
5472 /*
5473 * Exit the shadow mode since we're going to clear everything,
5474 * including the root page.
5475 */
5476 for (VMCPUID i = 0; i < pVM->cCpus; i++)
5477 pgmR3ExitShadowModeBeforePoolFlush(&pVM->aCpus[i]);
5478
5479 /*
5480 * Nuke the free list and reinsert all pages into it.
5481 */
5482 for (unsigned i = pPool->cCurPages - 1; i >= PGMPOOL_IDX_FIRST; i--)
5483 {
5484 PPGMPOOLPAGE pPage = &pPool->aPages[i];
5485
5486 Assert(pPage->Core.Key == MMPage2Phys(pVM, pPage->pvPageR3));
5487 if (pPage->fMonitored)
5488 pgmPoolMonitorFlush(pPool, pPage);
5489 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
5490 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
5491 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
5492 pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
5493 pPage->GCPhys = NIL_RTGCPHYS;
5494 pPage->enmKind = PGMPOOLKIND_FREE;
5495 pPage->enmAccess = PGMPOOLACCESS_DONTCARE;
5496 Assert(pPage->idx == i);
5497 pPage->iNext = i + 1;
5498 pPage->fA20Enabled = true;
5499 pPage->fZeroed = false; /* This could probably be optimized, but better safe than sorry. */
5500 pPage->fSeenNonGlobal = false;
5501 pPage->fMonitored = false;
5502 pPage->fDirty = false;
5503 pPage->fCached = false;
5504 pPage->fReusedFlushPending = false;
5505 pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
5506 pPage->cPresent = 0;
5507 pPage->iFirstPresent = NIL_PGMPOOL_PRESENT_INDEX;
5508 pPage->cModifications = 0;
5509 pPage->iAgeNext = NIL_PGMPOOL_IDX;
5510 pPage->iAgePrev = NIL_PGMPOOL_IDX;
5511 pPage->idxDirtyEntry = 0;
5512 pPage->GCPtrLastAccessHandlerRip = NIL_RTGCPTR;
5513 pPage->GCPtrLastAccessHandlerFault = NIL_RTGCPTR;
5514 pPage->cLastAccessHandler = 0;
5515 pPage->cLocked = 0;
5516#ifdef VBOX_STRICT
5517 pPage->GCPtrDirtyFault = NIL_RTGCPTR;
5518#endif
5519 }
5520 pPool->aPages[pPool->cCurPages - 1].iNext = NIL_PGMPOOL_IDX;
5521 pPool->iFreeHead = PGMPOOL_IDX_FIRST;
5522 pPool->cUsedPages = 0;
5523
5524 /*
5525 * Zap and reinitialize the user records.
5526 */
5527 pPool->cPresent = 0;
5528 pPool->iUserFreeHead = 0;
5529 PPGMPOOLUSER paUsers = pPool->CTX_SUFF(paUsers);
5530 const unsigned cMaxUsers = pPool->cMaxUsers;
5531 for (unsigned i = 0; i < cMaxUsers; i++)
5532 {
5533 paUsers[i].iNext = i + 1;
5534 paUsers[i].iUser = NIL_PGMPOOL_IDX;
5535 paUsers[i].iUserTable = 0xfffffffe;
5536 }
5537 paUsers[cMaxUsers - 1].iNext = NIL_PGMPOOL_USER_INDEX;
5538
5539 /*
5540 * Clear all the GCPhys links and rebuild the phys ext free list.
5541 */
5542 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX);
5543 pRam;
5544 pRam = pRam->CTX_SUFF(pNext))
5545 {
5546 unsigned iPage = pRam->cb >> PAGE_SHIFT;
5547 while (iPage-- > 0)
5548 PGM_PAGE_SET_TRACKING(pVM, &pRam->aPages[iPage], 0);
5549 }
5550
5551 pPool->iPhysExtFreeHead = 0;
5552 PPGMPOOLPHYSEXT paPhysExts = pPool->CTX_SUFF(paPhysExts);
5553 const unsigned cMaxPhysExts = pPool->cMaxPhysExts;
5554 for (unsigned i = 0; i < cMaxPhysExts; i++)
5555 {
5556 paPhysExts[i].iNext = i + 1;
5557 paPhysExts[i].aidx[0] = NIL_PGMPOOL_IDX;
5558 paPhysExts[i].apte[0] = NIL_PGMPOOL_PHYSEXT_IDX_PTE;
5559 paPhysExts[i].aidx[1] = NIL_PGMPOOL_IDX;
5560 paPhysExts[i].apte[1] = NIL_PGMPOOL_PHYSEXT_IDX_PTE;
5561 paPhysExts[i].aidx[2] = NIL_PGMPOOL_IDX;
5562 paPhysExts[i].apte[2] = NIL_PGMPOOL_PHYSEXT_IDX_PTE;
5563 }
5564 paPhysExts[cMaxPhysExts - 1].iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
5565
5566 /*
5567 * Just zap the modified list.
5568 */
5569 pPool->cModifiedPages = 0;
5570 pPool->iModifiedHead = NIL_PGMPOOL_IDX;
5571
5572 /*
5573 * Clear the GCPhys hash and the age list.
5574 */
5575 for (unsigned i = 0; i < RT_ELEMENTS(pPool->aiHash); i++)
5576 pPool->aiHash[i] = NIL_PGMPOOL_IDX;
5577 pPool->iAgeHead = NIL_PGMPOOL_IDX;
5578 pPool->iAgeTail = NIL_PGMPOOL_IDX;
5579
5580#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
5581 /* Clear all dirty pages. */
5582 pPool->idxFreeDirtyPage = 0;
5583 pPool->cDirtyPages = 0;
5584 for (unsigned i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
5585 pPool->aDirtyPages[i].uIdx = NIL_PGMPOOL_IDX;
5586#endif
5587
5588 /*
5589 * Reinsert active pages into the hash and ensure monitoring chains are correct.
5590 */
5591 for (VMCPUID i = 0; i < pVM->cCpus; i++)
5592 {
5593 /*
5594 * Re-enter the shadowing mode and assert Sync CR3 FF.
5595 */
5596 PVMCPU pVCpu = &pVM->aCpus[i];
5597 pgmR3ReEnterShadowModeAfterPoolFlush(pVM, pVCpu);
5598 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
5599 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
5600 }
5601
5602 STAM_PROFILE_STOP(&pPool->StatR3Reset, a);
5603}
5604
5605#endif /* IN_RING3 */
5606
5607#if defined(LOG_ENABLED) || defined(VBOX_STRICT)
5608/**
5609 * Stringifies a PGMPOOLKIND value.
5610 */
5611static const char *pgmPoolPoolKindToStr(uint8_t enmKind)
5612{
5613 switch ((PGMPOOLKIND)enmKind)
5614 {
5615 case PGMPOOLKIND_INVALID:
5616 return "PGMPOOLKIND_INVALID";
5617 case PGMPOOLKIND_FREE:
5618 return "PGMPOOLKIND_FREE";
5619 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
5620 return "PGMPOOLKIND_32BIT_PT_FOR_PHYS";
5621 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
5622 return "PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT";
5623 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
5624 return "PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB";
5625 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
5626 return "PGMPOOLKIND_PAE_PT_FOR_PHYS";
5627 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
5628 return "PGMPOOLKIND_PAE_PT_FOR_32BIT_PT";
5629 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
5630 return "PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB";
5631 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
5632 return "PGMPOOLKIND_PAE_PT_FOR_PAE_PT";
5633 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
5634 return "PGMPOOLKIND_PAE_PT_FOR_PAE_2MB";
5635 case PGMPOOLKIND_32BIT_PD:
5636 return "PGMPOOLKIND_32BIT_PD";
5637 case PGMPOOLKIND_32BIT_PD_PHYS:
5638 return "PGMPOOLKIND_32BIT_PD_PHYS";
5639 case PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD:
5640 return "PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD";
5641 case PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD:
5642 return "PGMPOOLKIND_PAE_PD1_FOR_32BIT_PD";
5643 case PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD:
5644 return "PGMPOOLKIND_PAE_PD2_FOR_32BIT_PD";
5645 case PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD:
5646 return "PGMPOOLKIND_PAE_PD3_FOR_32BIT_PD";
5647 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
5648 return "PGMPOOLKIND_PAE_PD_FOR_PAE_PD";
5649 case PGMPOOLKIND_PAE_PD_PHYS:
5650 return "PGMPOOLKIND_PAE_PD_PHYS";
5651 case PGMPOOLKIND_PAE_PDPT_FOR_32BIT:
5652 return "PGMPOOLKIND_PAE_PDPT_FOR_32BIT";
5653 case PGMPOOLKIND_PAE_PDPT:
5654 return "PGMPOOLKIND_PAE_PDPT";
5655 case PGMPOOLKIND_PAE_PDPT_PHYS:
5656 return "PGMPOOLKIND_PAE_PDPT_PHYS";
5657 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
5658 return "PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT";
5659 case PGMPOOLKIND_64BIT_PDPT_FOR_PHYS:
5660 return "PGMPOOLKIND_64BIT_PDPT_FOR_PHYS";
5661 case PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD:
5662 return "PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD";
5663 case PGMPOOLKIND_64BIT_PD_FOR_PHYS:
5664 return "PGMPOOLKIND_64BIT_PD_FOR_PHYS";
5665 case PGMPOOLKIND_64BIT_PML4:
5666 return "PGMPOOLKIND_64BIT_PML4";
5667 case PGMPOOLKIND_EPT_PDPT_FOR_PHYS:
5668 return "PGMPOOLKIND_EPT_PDPT_FOR_PHYS";
5669 case PGMPOOLKIND_EPT_PD_FOR_PHYS:
5670 return "PGMPOOLKIND_EPT_PD_FOR_PHYS";
5671 case PGMPOOLKIND_EPT_PT_FOR_PHYS:
5672 return "PGMPOOLKIND_EPT_PT_FOR_PHYS";
5673 case PGMPOOLKIND_ROOT_NESTED:
5674 return "PGMPOOLKIND_ROOT_NESTED";
5675 }
5676 return "Unknown kind!";
5677}
5678#endif /* LOG_ENABLED || VBOX_STRICT */
5679
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