VirtualBox

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

Last change on this file since 9026 was 9008, checked in by vboxsync, 17 years ago

Changes for proper flushing of the TLB for physical registration changes.

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