VirtualBox

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

Last change on this file since 8606 was 8454, checked in by vboxsync, 17 years ago

Long mode changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 125.2 KB
Line 
1/* $Id: PGMAllPool.cpp 8454 2008-04-29 11:31:44Z vboxsync $ */
2/** @file
3 * PGM Shadow Page Pool.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_PGM_POOL
27#include <VBox/pgm.h>
28#include <VBox/mm.h>
29#include <VBox/em.h>
30#include <VBox/cpum.h>
31#ifdef IN_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 Assert(pPool->iAgeHead != pPool->iAgeTail); /* We shouldn't be here if there < 2 cached entries! */
911 STAM_COUNTER_INC(&pPool->StatCacheFreeUpOne);
912
913 /*
914 * Select one page from the tail of the age list.
915 */
916 uint16_t iToFree = pPool->iAgeTail;
917 if (iToFree == iUser)
918 iToFree = pPool->aPages[iToFree].iAgePrev;
919/* This is the alternative to the SyncCR3 pgmPoolCacheUsed calls.
920 if (pPool->aPages[iToFree].iUserHead != NIL_PGMPOOL_USER_INDEX)
921 {
922 uint16_t i = pPool->aPages[iToFree].iAgePrev;
923 for (unsigned j = 0; j < 10 && i != NIL_PGMPOOL_USER_INDEX; j++, i = pPool->aPages[i].iAgePrev)
924 {
925 if (pPool->aPages[iToFree].iUserHead == NIL_PGMPOOL_USER_INDEX)
926 continue;
927 iToFree = i;
928 break;
929 }
930 }
931*/
932 Assert(iToFree != iUser);
933 AssertRelease(iToFree != NIL_PGMPOOL_IDX);
934
935 int rc = pgmPoolFlushPage(pPool, &pPool->aPages[iToFree]);
936 if (rc == VINF_SUCCESS)
937 PGM_INVL_GUEST_TLBS(); /* see PT handler. */
938 return rc;
939}
940
941
942/**
943 * Checks if a kind mismatch is really a page being reused
944 * or if it's just normal remappings.
945 *
946 * @returns true if reused and the cached page (enmKind1) should be flushed
947 * @returns false if not reused.
948 * @param enmKind1 The kind of the cached page.
949 * @param enmKind2 The kind of the requested page.
950 */
951static bool pgmPoolCacheReusedByKind(PGMPOOLKIND enmKind1, PGMPOOLKIND enmKind2)
952{
953 switch (enmKind1)
954 {
955 /*
956 * Never reuse them. There is no remapping in non-paging mode.
957 */
958 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
959 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
960 return true;
961
962 /*
963 * It's perfectly fine to reuse these, except for PAE and non-paging stuff.
964 */
965 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
966 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
967 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
968 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
969 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
970 switch (enmKind2)
971 {
972 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
973 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
974 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
975 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
976 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
977 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
978 return true;
979 default:
980 return false;
981 }
982
983 /*
984 * It's perfectly fine to reuse these, except for PAE and non-paging stuff.
985 */
986 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
987 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
988 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
989 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
990 switch (enmKind2)
991 {
992 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
993 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
994 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
995 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
996 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
997 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
998 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
999 return true;
1000 default:
1001 return false;
1002 }
1003
1004 /*
1005 * These cannot be flushed, and it's common to reuse the PDs as PTs.
1006 */
1007 case PGMPOOLKIND_ROOT_32BIT_PD:
1008 case PGMPOOLKIND_ROOT_PAE_PD:
1009 case PGMPOOLKIND_ROOT_PDPT:
1010 case PGMPOOLKIND_ROOT_PML4:
1011 return false;
1012
1013 default:
1014 AssertFatalMsgFailed(("enmKind1=%d\n", enmKind1));
1015 }
1016}
1017
1018
1019/**
1020 * Attempts to satisfy a pgmPoolAlloc request from the cache.
1021 *
1022 * @returns VBox status code.
1023 * @retval VINF_PGM_CACHED_PAGE on success.
1024 * @retval VERR_FILE_NOT_FOUND if not found.
1025 * @param pPool The pool.
1026 * @param GCPhys The GC physical address of the page we're gonna shadow.
1027 * @param enmKind The kind of mapping.
1028 * @param iUser The shadow page pool index of the user table.
1029 * @param iUserTable The index into the user table (shadowed).
1030 * @param ppPage Where to store the pointer to the page.
1031 */
1032static int pgmPoolCacheAlloc(PPGMPOOL pPool, RTGCPHYS GCPhys, PGMPOOLKIND enmKind, uint16_t iUser, uint16_t iUserTable, PPPGMPOOLPAGE ppPage)
1033{
1034 /*
1035 * Look up the GCPhys in the hash.
1036 */
1037 unsigned i = pPool->aiHash[PGMPOOL_HASH(GCPhys)];
1038 Log3(("pgmPoolCacheAlloc: %VGp kind %d iUser=%d iUserTable=%x SLOT=%d\n", GCPhys, enmKind, iUser, iUserTable, i));
1039 if (i != NIL_PGMPOOL_IDX)
1040 {
1041 do
1042 {
1043 PPGMPOOLPAGE pPage = &pPool->aPages[i];
1044 Log3(("pgmPoolCacheAlloc: slot %d found page %VGp\n", i, pPage->GCPhys));
1045 if (pPage->GCPhys == GCPhys)
1046 {
1047 if ((PGMPOOLKIND)pPage->enmKind == enmKind)
1048 {
1049 int rc = pgmPoolTrackAddUser(pPool, pPage, iUser, iUserTable);
1050 if (VBOX_SUCCESS(rc))
1051 {
1052 *ppPage = pPage;
1053 STAM_COUNTER_INC(&pPool->StatCacheHits);
1054 return VINF_PGM_CACHED_PAGE;
1055 }
1056 return rc;
1057 }
1058
1059 /*
1060 * The kind is different. In some cases we should now flush the page
1061 * as it has been reused, but in most cases this is normal remapping
1062 * of PDs as PT or big pages using the GCPhys field in a slightly
1063 * different way than the other kinds.
1064 */
1065 if (pgmPoolCacheReusedByKind((PGMPOOLKIND)pPage->enmKind, enmKind))
1066 {
1067 STAM_COUNTER_INC(&pPool->StatCacheKindMismatches);
1068 pgmPoolFlushPage(pPool, pPage); /* ASSUMES that VERR_PGM_POOL_CLEARED will be returned by pgmPoolTracInsert. */
1069 PGM_INVL_GUEST_TLBS(); /* see PT handler. */
1070 break;
1071 }
1072 }
1073
1074 /* next */
1075 i = pPage->iNext;
1076 } while (i != NIL_PGMPOOL_IDX);
1077 }
1078
1079 Log3(("pgmPoolCacheAlloc: Missed GCPhys=%RGp enmKind=%d\n", GCPhys, enmKind));
1080 STAM_COUNTER_INC(&pPool->StatCacheMisses);
1081 return VERR_FILE_NOT_FOUND;
1082}
1083
1084
1085/**
1086 * Inserts a page into the cache.
1087 *
1088 * @param pPool The pool.
1089 * @param pPage The cached page.
1090 * @param fCanBeCached Set if the page is fit for caching from the caller's point of view.
1091 */
1092static void pgmPoolCacheInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage, bool fCanBeCached)
1093{
1094 /*
1095 * Insert into the GCPhys hash if the page is fit for that.
1096 */
1097 Assert(!pPage->fCached);
1098 if (fCanBeCached)
1099 {
1100 pPage->fCached = true;
1101 pgmPoolHashInsert(pPool, pPage);
1102 Log3(("pgmPoolCacheInsert: Caching %p:{.Core=%RHp, .idx=%d, .enmKind=%d, GCPhys=%RGp}\n",
1103 pPage, pPage->Core.Key, pPage->idx, pPage->enmKind, pPage->GCPhys));
1104 STAM_COUNTER_INC(&pPool->StatCacheCacheable);
1105 }
1106 else
1107 {
1108 Log3(("pgmPoolCacheInsert: Not 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->StatCacheUncacheable);
1111 }
1112
1113 /*
1114 * Insert at the head of the age list.
1115 */
1116 pPage->iAgePrev = NIL_PGMPOOL_IDX;
1117 pPage->iAgeNext = pPool->iAgeHead;
1118 if (pPool->iAgeHead != NIL_PGMPOOL_IDX)
1119 pPool->aPages[pPool->iAgeHead].iAgePrev = pPage->idx;
1120 else
1121 pPool->iAgeTail = pPage->idx;
1122 pPool->iAgeHead = pPage->idx;
1123}
1124
1125
1126/**
1127 * Flushes a cached page.
1128 *
1129 * @param pPool The pool.
1130 * @param pPage The cached page.
1131 */
1132static void pgmPoolCacheFlushPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1133{
1134 Log3(("pgmPoolCacheFlushPage: %VGp\n", pPage->GCPhys));
1135
1136 /*
1137 * Remove the page from the hash.
1138 */
1139 if (pPage->fCached)
1140 {
1141 pPage->fCached = false;
1142 pgmPoolHashRemove(pPool, pPage);
1143 }
1144 else
1145 Assert(pPage->iNext == NIL_PGMPOOL_IDX);
1146
1147 /*
1148 * Remove it from the age list.
1149 */
1150 if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
1151 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
1152 else
1153 pPool->iAgeTail = pPage->iAgePrev;
1154 if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
1155 pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
1156 else
1157 pPool->iAgeHead = pPage->iAgeNext;
1158 pPage->iAgeNext = NIL_PGMPOOL_IDX;
1159 pPage->iAgePrev = NIL_PGMPOOL_IDX;
1160}
1161#endif /* PGMPOOL_WITH_CACHE */
1162
1163
1164#ifdef PGMPOOL_WITH_MONITORING
1165/**
1166 * Looks for pages sharing the monitor.
1167 *
1168 * @returns Pointer to the head page.
1169 * @returns NULL if not found.
1170 * @param pPool The Pool
1171 * @param pNewPage The page which is going to be monitored.
1172 */
1173static PPGMPOOLPAGE pgmPoolMonitorGetPageByGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pNewPage)
1174{
1175#ifdef PGMPOOL_WITH_CACHE
1176 /*
1177 * Look up the GCPhys in the hash.
1178 */
1179 RTGCPHYS GCPhys = pNewPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1);
1180 unsigned i = pPool->aiHash[PGMPOOL_HASH(GCPhys)];
1181 if (i == NIL_PGMPOOL_IDX)
1182 return NULL;
1183 do
1184 {
1185 PPGMPOOLPAGE pPage = &pPool->aPages[i];
1186 if ( pPage->GCPhys - GCPhys < PAGE_SIZE
1187 && pPage != pNewPage)
1188 {
1189 switch (pPage->enmKind)
1190 {
1191 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1192 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1193 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1194 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
1195 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
1196 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
1197 case PGMPOOLKIND_ROOT_32BIT_PD:
1198 case PGMPOOLKIND_ROOT_PAE_PD:
1199 case PGMPOOLKIND_ROOT_PDPT:
1200 case PGMPOOLKIND_ROOT_PML4:
1201 {
1202 /* find the head */
1203 while (pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
1204 {
1205 Assert(pPage->iMonitoredPrev != pPage->idx);
1206 pPage = &pPool->aPages[pPage->iMonitoredPrev];
1207 }
1208 return pPage;
1209 }
1210
1211 /* ignore, no monitoring. */
1212 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1213 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1214 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1215 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1216 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1217 break;
1218 default:
1219 AssertFatalMsgFailed(("enmKind=%d idx=%d\n", pPage->enmKind, pPage->idx));
1220 }
1221 }
1222
1223 /* next */
1224 i = pPage->iNext;
1225 } while (i != NIL_PGMPOOL_IDX);
1226#endif
1227 return NULL;
1228}
1229
1230/**
1231 * Enabled write monitoring of a guest page.
1232 *
1233 * @returns VBox status code.
1234 * @retval VINF_SUCCESS on success.
1235 * @retval VERR_PGM_POOL_CLEARED if the registration of the physical handler will cause a light weight pool flush.
1236 * @param pPool The pool.
1237 * @param pPage The cached page.
1238 */
1239static int pgmPoolMonitorInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1240{
1241 LogFlow(("pgmPoolMonitorInsert %VGp\n", pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1)));
1242
1243 /*
1244 * Filter out the relevant kinds.
1245 */
1246 switch (pPage->enmKind)
1247 {
1248 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1249 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1250 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
1251 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1252 case PGMPOOLKIND_ROOT_PDPT:
1253 break;
1254
1255 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1256 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1257 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1258 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1259 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1260 /* Nothing to monitor here. */
1261 return VINF_SUCCESS;
1262
1263 case PGMPOOLKIND_ROOT_32BIT_PD:
1264 case PGMPOOLKIND_ROOT_PAE_PD:
1265#ifdef PGMPOOL_WITH_MIXED_PT_CR3
1266 break;
1267#endif
1268 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
1269 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
1270 case PGMPOOLKIND_ROOT_PML4:
1271 default:
1272 AssertFatalMsgFailed(("This can't happen! enmKind=%d\n", pPage->enmKind));
1273 }
1274
1275 /*
1276 * Install handler.
1277 */
1278 int rc;
1279 PPGMPOOLPAGE pPageHead = pgmPoolMonitorGetPageByGCPhys(pPool, pPage);
1280 if (pPageHead)
1281 {
1282 Assert(pPageHead != pPage); Assert(pPageHead->iMonitoredNext != pPage->idx);
1283 Assert(pPageHead->iMonitoredPrev != pPage->idx);
1284 pPage->iMonitoredPrev = pPageHead->idx;
1285 pPage->iMonitoredNext = pPageHead->iMonitoredNext;
1286 if (pPageHead->iMonitoredNext != NIL_PGMPOOL_IDX)
1287 pPool->aPages[pPageHead->iMonitoredNext].iMonitoredPrev = pPage->idx;
1288 pPageHead->iMonitoredNext = pPage->idx;
1289 rc = VINF_SUCCESS;
1290 }
1291 else
1292 {
1293 Assert(pPage->iMonitoredNext == NIL_PGMPOOL_IDX); Assert(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
1294 PVM pVM = pPool->CTXSUFF(pVM);
1295 const RTGCPHYS GCPhysPage = pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1);
1296 rc = PGMHandlerPhysicalRegisterEx(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
1297 GCPhysPage, GCPhysPage + (PAGE_SIZE - 1),
1298 pPool->pfnAccessHandlerR3, MMHyperCCToR3(pVM, pPage),
1299 pPool->pfnAccessHandlerR0, MMHyperCCToR0(pVM, pPage),
1300 pPool->pfnAccessHandlerGC, MMHyperCCToGC(pVM, pPage),
1301 pPool->pszAccessHandler);
1302 /** @todo we should probably deal with out-of-memory conditions here, but for now increasing
1303 * the heap size should suffice. */
1304 AssertFatalRC(rc);
1305 if (pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)
1306 rc = VERR_PGM_POOL_CLEARED;
1307 }
1308 pPage->fMonitored = true;
1309 return rc;
1310}
1311
1312
1313/**
1314 * Disables write monitoring of a guest page.
1315 *
1316 * @returns VBox status code.
1317 * @retval VINF_SUCCESS on success.
1318 * @retval VERR_PGM_POOL_CLEARED if the deregistration of the physical handler will cause a light weight pool flush.
1319 * @param pPool The pool.
1320 * @param pPage The cached page.
1321 */
1322static int pgmPoolMonitorFlush(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1323{
1324 /*
1325 * Filter out the relevant kinds.
1326 */
1327 switch (pPage->enmKind)
1328 {
1329 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1330 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1331 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
1332 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1333 case PGMPOOLKIND_ROOT_PDPT:
1334 break;
1335
1336 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1337 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1338 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1339 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1340 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1341 /* Nothing to monitor here. */
1342 return VINF_SUCCESS;
1343
1344 case PGMPOOLKIND_ROOT_32BIT_PD:
1345 case PGMPOOLKIND_ROOT_PAE_PD:
1346#ifdef PGMPOOL_WITH_MIXED_PT_CR3
1347 break;
1348#endif
1349 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
1350 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
1351 case PGMPOOLKIND_ROOT_PML4:
1352 default:
1353 AssertFatalMsgFailed(("This can't happen! enmKind=%d\n", pPage->enmKind));
1354 }
1355
1356 /*
1357 * Remove the page from the monitored list or uninstall it if last.
1358 */
1359 const PVM pVM = pPool->CTXSUFF(pVM);
1360 int rc;
1361 if ( pPage->iMonitoredNext != NIL_PGMPOOL_IDX
1362 || pPage->iMonitoredPrev != NIL_PGMPOOL_IDX)
1363 {
1364 if (pPage->iMonitoredPrev == NIL_PGMPOOL_IDX)
1365 {
1366 PPGMPOOLPAGE pNewHead = &pPool->aPages[pPage->iMonitoredNext];
1367 pNewHead->iMonitoredPrev = NIL_PGMPOOL_IDX;
1368 pNewHead->fCR3Mix = pPage->fCR3Mix;
1369 rc = PGMHandlerPhysicalChangeCallbacks(pVM, pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1),
1370 pPool->pfnAccessHandlerR3, MMHyperCCToR3(pVM, pNewHead),
1371 pPool->pfnAccessHandlerR0, MMHyperCCToR0(pVM, pNewHead),
1372 pPool->pfnAccessHandlerGC, MMHyperCCToGC(pVM, pNewHead),
1373 pPool->pszAccessHandler);
1374 AssertFatalRCSuccess(rc);
1375 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
1376 }
1377 else
1378 {
1379 pPool->aPages[pPage->iMonitoredPrev].iMonitoredNext = pPage->iMonitoredNext;
1380 if (pPage->iMonitoredNext != NIL_PGMPOOL_IDX)
1381 {
1382 pPool->aPages[pPage->iMonitoredNext].iMonitoredPrev = pPage->iMonitoredPrev;
1383 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
1384 }
1385 pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
1386 rc = VINF_SUCCESS;
1387 }
1388 }
1389 else
1390 {
1391 rc = PGMHandlerPhysicalDeregister(pVM, pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1));
1392 AssertFatalRC(rc);
1393 if (pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)
1394 rc = VERR_PGM_POOL_CLEARED;
1395 }
1396 pPage->fMonitored = false;
1397
1398 /*
1399 * Remove it from the list of modified pages (if in it).
1400 */
1401 pgmPoolMonitorModifiedRemove(pPool, pPage);
1402
1403 return rc;
1404}
1405
1406
1407#ifdef PGMPOOL_WITH_MIXED_PT_CR3
1408/**
1409 * Set or clear the fCR3Mix attribute in a chain of monitored pages.
1410 *
1411 * @param pPool The Pool.
1412 * @param pPage A page in the chain.
1413 * @param fCR3Mix The new fCR3Mix value.
1414 */
1415static void pgmPoolMonitorChainChangeCR3Mix(PPGMPOOL pPool, PPGMPOOLPAGE pPage, bool fCR3Mix)
1416{
1417 /* current */
1418 pPage->fCR3Mix = fCR3Mix;
1419
1420 /* before */
1421 int16_t idx = pPage->iMonitoredPrev;
1422 while (idx != NIL_PGMPOOL_IDX)
1423 {
1424 pPool->aPages[idx].fCR3Mix = fCR3Mix;
1425 idx = pPool->aPages[idx].iMonitoredPrev;
1426 }
1427
1428 /* after */
1429 idx = pPage->iMonitoredNext;
1430 while (idx != NIL_PGMPOOL_IDX)
1431 {
1432 pPool->aPages[idx].fCR3Mix = fCR3Mix;
1433 idx = pPool->aPages[idx].iMonitoredNext;
1434 }
1435}
1436
1437
1438/**
1439 * Installs or modifies monitoring of a CR3 page (special).
1440 *
1441 * We're pretending the CR3 page is shadowed by the pool so we can use the
1442 * generic mechanisms in detecting chained monitoring. (This also gives us a
1443 * tast of what code changes are required to really pool CR3 shadow pages.)
1444 *
1445 * @returns VBox status code.
1446 * @param pPool The pool.
1447 * @param idxRoot The CR3 (root) page index.
1448 * @param GCPhysCR3 The (new) CR3 value.
1449 */
1450int pgmPoolMonitorMonitorCR3(PPGMPOOL pPool, uint16_t idxRoot, RTGCPHYS GCPhysCR3)
1451{
1452 Assert(idxRoot != NIL_PGMPOOL_IDX && idxRoot < PGMPOOL_IDX_FIRST);
1453 PPGMPOOLPAGE pPage = &pPool->aPages[idxRoot];
1454 LogFlow(("pgmPoolMonitorMonitorCR3: idxRoot=%d pPage=%p:{.GCPhys=%VGp, .fMonitored=%d} GCPhysCR3=%VGp\n",
1455 idxRoot, pPage, pPage->GCPhys, pPage->fMonitored, GCPhysCR3));
1456
1457 /*
1458 * The unlikely case where it already matches.
1459 */
1460 if (pPage->GCPhys == GCPhysCR3)
1461 {
1462 Assert(pPage->fMonitored);
1463 return VINF_SUCCESS;
1464 }
1465
1466 /*
1467 * Flush the current monitoring and remove it from the hash.
1468 */
1469 int rc = VINF_SUCCESS;
1470 if (pPage->fMonitored)
1471 {
1472 pgmPoolMonitorChainChangeCR3Mix(pPool, pPage, false);
1473 rc = pgmPoolMonitorFlush(pPool, pPage);
1474 if (rc == VERR_PGM_POOL_CLEARED)
1475 rc = VINF_SUCCESS;
1476 else
1477 AssertFatalRC(rc);
1478 pgmPoolHashRemove(pPool, pPage);
1479 }
1480
1481 /*
1482 * Monitor the page at the new location and insert it into the hash.
1483 */
1484 pPage->GCPhys = GCPhysCR3;
1485 int rc2 = pgmPoolMonitorInsert(pPool, pPage);
1486 if (rc2 != VERR_PGM_POOL_CLEARED)
1487 {
1488 AssertFatalRC(rc2);
1489 if (rc2 != VINF_SUCCESS && rc == VINF_SUCCESS)
1490 rc = rc2;
1491 }
1492 pgmPoolHashInsert(pPool, pPage);
1493 pgmPoolMonitorChainChangeCR3Mix(pPool, pPage, true);
1494 return rc;
1495}
1496
1497
1498/**
1499 * Removes the monitoring of a CR3 page (special).
1500 *
1501 * @returns VBox status code.
1502 * @param pPool The pool.
1503 * @param idxRoot The CR3 (root) page index.
1504 */
1505int pgmPoolMonitorUnmonitorCR3(PPGMPOOL pPool, uint16_t idxRoot)
1506{
1507 Assert(idxRoot != NIL_PGMPOOL_IDX && idxRoot < PGMPOOL_IDX_FIRST);
1508 PPGMPOOLPAGE pPage = &pPool->aPages[idxRoot];
1509 LogFlow(("pgmPoolMonitorUnmonitorCR3: idxRoot=%d pPage=%p:{.GCPhys=%VGp, .fMonitored=%d}\n",
1510 idxRoot, pPage, pPage->GCPhys, pPage->fMonitored));
1511
1512 if (!pPage->fMonitored)
1513 return VINF_SUCCESS;
1514
1515 pgmPoolMonitorChainChangeCR3Mix(pPool, pPage, false);
1516 int rc = pgmPoolMonitorFlush(pPool, pPage);
1517 if (rc != VERR_PGM_POOL_CLEARED)
1518 AssertFatalRC(rc);
1519 else
1520 rc = VINF_SUCCESS;
1521 pgmPoolHashRemove(pPool, pPage);
1522 Assert(!pPage->fMonitored);
1523 pPage->GCPhys = NIL_RTGCPHYS;
1524 return rc;
1525}
1526#endif /* PGMPOOL_WITH_MIXED_PT_CR3 */
1527
1528
1529/**
1530 * Inserts the page into the list of modified pages.
1531 *
1532 * @param pPool The pool.
1533 * @param pPage The page.
1534 */
1535void pgmPoolMonitorModifiedInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1536{
1537 Log3(("pgmPoolMonitorModifiedInsert: idx=%d\n", pPage->idx));
1538 AssertMsg( pPage->iModifiedNext == NIL_PGMPOOL_IDX
1539 && pPage->iModifiedPrev == NIL_PGMPOOL_IDX
1540 && pPool->iModifiedHead != pPage->idx,
1541 ("Next=%d Prev=%d idx=%d cModifications=%d Head=%d cModifiedPages=%d\n",
1542 pPage->iModifiedNext, pPage->iModifiedPrev, pPage->idx, pPage->cModifications,
1543 pPool->iModifiedHead, pPool->cModifiedPages));
1544
1545 pPage->iModifiedNext = pPool->iModifiedHead;
1546 if (pPool->iModifiedHead != NIL_PGMPOOL_IDX)
1547 pPool->aPages[pPool->iModifiedHead].iModifiedPrev = pPage->idx;
1548 pPool->iModifiedHead = pPage->idx;
1549 pPool->cModifiedPages++;
1550#ifdef VBOX_WITH_STATISTICS
1551 if (pPool->cModifiedPages > pPool->cModifiedPagesHigh)
1552 pPool->cModifiedPagesHigh = pPool->cModifiedPages;
1553#endif
1554}
1555
1556
1557/**
1558 * Removes the page from the list of modified pages and resets the
1559 * moficiation counter.
1560 *
1561 * @param pPool The pool.
1562 * @param pPage The page which is believed to be in the list of modified pages.
1563 */
1564static void pgmPoolMonitorModifiedRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1565{
1566 Log3(("pgmPoolMonitorModifiedRemove: idx=%d cModifications=%d\n", pPage->idx, pPage->cModifications));
1567 if (pPool->iModifiedHead == pPage->idx)
1568 {
1569 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX);
1570 pPool->iModifiedHead = pPage->iModifiedNext;
1571 if (pPage->iModifiedNext != NIL_PGMPOOL_IDX)
1572 {
1573 pPool->aPages[pPage->iModifiedNext].iModifiedPrev = NIL_PGMPOOL_IDX;
1574 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1575 }
1576 pPool->cModifiedPages--;
1577 }
1578 else if (pPage->iModifiedPrev != NIL_PGMPOOL_IDX)
1579 {
1580 pPool->aPages[pPage->iModifiedPrev].iModifiedNext = pPage->iModifiedNext;
1581 if (pPage->iModifiedNext != NIL_PGMPOOL_IDX)
1582 {
1583 pPool->aPages[pPage->iModifiedNext].iModifiedPrev = pPage->iModifiedPrev;
1584 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1585 }
1586 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
1587 pPool->cModifiedPages--;
1588 }
1589 else
1590 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX);
1591 pPage->cModifications = 0;
1592}
1593
1594
1595/**
1596 * Zaps the list of modified pages, resetting their modification counters in the process.
1597 *
1598 * @param pVM The VM handle.
1599 */
1600void pgmPoolMonitorModifiedClearAll(PVM pVM)
1601{
1602 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
1603 LogFlow(("pgmPoolMonitorModifiedClearAll: cModifiedPages=%d\n", pPool->cModifiedPages));
1604
1605 unsigned cPages = 0; NOREF(cPages);
1606 uint16_t idx = pPool->iModifiedHead;
1607 pPool->iModifiedHead = NIL_PGMPOOL_IDX;
1608 while (idx != NIL_PGMPOOL_IDX)
1609 {
1610 PPGMPOOLPAGE pPage = &pPool->aPages[idx];
1611 idx = pPage->iModifiedNext;
1612 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1613 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
1614 pPage->cModifications = 0;
1615 Assert(++cPages);
1616 }
1617 AssertMsg(cPages == pPool->cModifiedPages, ("%d != %d\n", cPages, pPool->cModifiedPages));
1618 pPool->cModifiedPages = 0;
1619}
1620
1621
1622/**
1623 * Clear all shadow pages and clear all modification counters.
1624 *
1625 * @param pVM The VM handle.
1626 * @remark Should only be used when monitoring is available, thus placed in
1627 * the PGMPOOL_WITH_MONITORING #ifdef.
1628 */
1629void pgmPoolClearAll(PVM pVM)
1630{
1631 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
1632 STAM_PROFILE_START(&pPool->StatClearAll, c);
1633 LogFlow(("pgmPoolClearAll: cUsedPages=%d\n", pPool->cUsedPages));
1634
1635 /*
1636 * Iterate all the pages until we've encountered all that in use.
1637 * This is simple but not quite optimal solution.
1638 */
1639 unsigned cModifiedPages = 0; NOREF(cModifiedPages);
1640 unsigned cLeft = pPool->cUsedPages;
1641 unsigned iPage = pPool->cCurPages;
1642 while (--iPage >= PGMPOOL_IDX_FIRST)
1643 {
1644 PPGMPOOLPAGE pPage = &pPool->aPages[iPage];
1645 if (pPage->GCPhys != NIL_RTGCPHYS)
1646 {
1647 switch (pPage->enmKind)
1648 {
1649 /*
1650 * We only care about shadow page tables.
1651 */
1652 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
1653 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
1654 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
1655 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
1656 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
1657 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
1658 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
1659 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
1660 {
1661#ifdef PGMPOOL_WITH_USER_TRACKING
1662 if (pPage->cPresent)
1663#endif
1664 {
1665 void *pvShw = PGMPOOL_PAGE_2_PTR(pPool->CTXSUFF(pVM), pPage);
1666 STAM_PROFILE_START(&pPool->StatZeroPage, z);
1667 ASMMemZeroPage(pvShw);
1668 STAM_PROFILE_STOP(&pPool->StatZeroPage, z);
1669#ifdef PGMPOOL_WITH_USER_TRACKING
1670 pPage->cPresent = 0;
1671 pPage->iFirstPresent = ~0;
1672#endif
1673 }
1674 }
1675 /* fall thru */
1676
1677 default:
1678 Assert(!pPage->cModifications || ++cModifiedPages);
1679 Assert(pPage->iModifiedNext == NIL_PGMPOOL_IDX || pPage->cModifications);
1680 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX || pPage->cModifications);
1681 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1682 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
1683 pPage->cModifications = 0;
1684 break;
1685
1686 }
1687 if (!--cLeft)
1688 break;
1689 }
1690 }
1691
1692 /* swipe the special pages too. */
1693 for (iPage = PGMPOOL_IDX_FIRST_SPECIAL; iPage < PGMPOOL_IDX_FIRST; iPage++)
1694 {
1695 PPGMPOOLPAGE pPage = &pPool->aPages[iPage];
1696 if (pPage->GCPhys != NIL_RTGCPHYS)
1697 {
1698 Assert(!pPage->cModifications || ++cModifiedPages);
1699 Assert(pPage->iModifiedNext == NIL_PGMPOOL_IDX || pPage->cModifications);
1700 Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX || pPage->cModifications);
1701 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
1702 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
1703 pPage->cModifications = 0;
1704 }
1705 }
1706
1707 AssertMsg(cModifiedPages == pPool->cModifiedPages, ("%d != %d\n", cModifiedPages, pPool->cModifiedPages));
1708 pPool->iModifiedHead = NIL_PGMPOOL_IDX;
1709 pPool->cModifiedPages = 0;
1710
1711#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
1712 /*
1713 * Clear all the GCPhys links and rebuild the phys ext free list.
1714 */
1715 for (PPGMRAMRANGE pRam = pPool->CTXSUFF(pVM)->pgm.s.CTXALLSUFF(pRamRanges);
1716 pRam;
1717 pRam = CTXALLSUFF(pRam->pNext))
1718 {
1719 unsigned iPage = pRam->cb >> PAGE_SHIFT;
1720 while (iPage-- > 0)
1721 pRam->aPages[iPage].HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
1722 }
1723
1724 pPool->iPhysExtFreeHead = 0;
1725 PPGMPOOLPHYSEXT paPhysExts = pPool->CTXSUFF(paPhysExts);
1726 const unsigned cMaxPhysExts = pPool->cMaxPhysExts;
1727 for (unsigned i = 0; i < cMaxPhysExts; i++)
1728 {
1729 paPhysExts[i].iNext = i + 1;
1730 paPhysExts[i].aidx[0] = NIL_PGMPOOL_IDX;
1731 paPhysExts[i].aidx[1] = NIL_PGMPOOL_IDX;
1732 paPhysExts[i].aidx[2] = NIL_PGMPOOL_IDX;
1733 }
1734 paPhysExts[cMaxPhysExts - 1].iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
1735#endif
1736
1737
1738 pPool->cPresent = 0;
1739 STAM_PROFILE_STOP(&pPool->StatClearAll, c);
1740}
1741#endif /* PGMPOOL_WITH_MONITORING */
1742
1743
1744#ifdef PGMPOOL_WITH_USER_TRACKING
1745/**
1746 * Frees up at least one user entry.
1747 *
1748 * @returns VBox status code.
1749 * @retval VINF_SUCCESS if successfully added.
1750 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
1751 * @param pPool The pool.
1752 * @param iUser The user index.
1753 */
1754static int pgmPoolTrackFreeOneUser(PPGMPOOL pPool, uint16_t iUser)
1755{
1756 STAM_COUNTER_INC(&pPool->StatTrackFreeUpOneUser);
1757#ifdef PGMPOOL_WITH_CACHE
1758 /*
1759 * Just free cached pages in a braindead fashion.
1760 */
1761 /** @todo walk the age list backwards and free the first with usage. */
1762 int rc = VINF_SUCCESS;
1763 do
1764 {
1765 int rc2 = pgmPoolCacheFreeOne(pPool, iUser);
1766 if (VBOX_FAILURE(rc2) && rc == VINF_SUCCESS)
1767 rc = rc2;
1768 } while (pPool->iUserFreeHead == NIL_PGMPOOL_USER_INDEX);
1769 return rc;
1770#else
1771 /*
1772 * Lazy approach.
1773 */
1774 pgmPoolFlushAllInt(pPool);
1775 return VERR_PGM_POOL_FLUSHED;
1776#endif
1777}
1778
1779
1780/**
1781 * Inserts a page into the cache.
1782 *
1783 * This will create user node for the page, insert it into the GCPhys
1784 * hash, and insert it into the age list.
1785 *
1786 * @returns VBox status code.
1787 * @retval VINF_SUCCESS if successfully added.
1788 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
1789 * @retval VERR_PGM_POOL_CLEARED if the deregistration of the physical handler will cause a light weight pool flush.
1790 * @param pPool The pool.
1791 * @param pPage The cached page.
1792 * @param GCPhys The GC physical address of the page we're gonna shadow.
1793 * @param iUser The user index.
1794 * @param iUserTable The user table index.
1795 */
1796DECLINLINE(int) pgmPoolTrackInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTGCPHYS GCPhys, uint16_t iUser, uint16_t iUserTable)
1797{
1798 int rc = VINF_SUCCESS;
1799 PPGMPOOLUSER pUser = pPool->CTXSUFF(paUsers);
1800
1801 LogFlow(("pgmPoolTrackInsert iUser %d iUserTable %d\n", iUser, iUserTable));
1802
1803 /*
1804 * Find free a user node.
1805 */
1806 uint16_t i = pPool->iUserFreeHead;
1807 if (i == NIL_PGMPOOL_USER_INDEX)
1808 {
1809 int rc = pgmPoolTrackFreeOneUser(pPool, iUser);
1810 if (VBOX_FAILURE(rc))
1811 return rc;
1812 i = pPool->iUserFreeHead;
1813 }
1814
1815 /*
1816 * Unlink the user node from the free list,
1817 * initialize and insert it into the user list.
1818 */
1819 pPool->iUserFreeHead = pUser[i].iNext;
1820 pUser[i].iNext = NIL_PGMPOOL_USER_INDEX;
1821 pUser[i].iUser = iUser;
1822 pUser[i].iUserTable = iUserTable;
1823 pPage->iUserHead = i;
1824
1825 /*
1826 * Insert into cache and enable monitoring of the guest page if enabled.
1827 *
1828 * Until we implement caching of all levels, including the CR3 one, we'll
1829 * have to make sure we don't try monitor & cache any recursive reuse of
1830 * a monitored CR3 page. Because all windows versions are doing this we'll
1831 * have to be able to do combined access monitoring, CR3 + PT and
1832 * PD + PT (guest PAE).
1833 *
1834 * Update:
1835 * We're now cooperating with the CR3 monitor if an uncachable page is found.
1836 */
1837#if defined(PGMPOOL_WITH_MONITORING) || defined(PGMPOOL_WITH_CACHE)
1838# ifdef PGMPOOL_WITH_MIXED_PT_CR3
1839 const bool fCanBeMonitored = true;
1840# else
1841 bool fCanBeMonitored = pPool->CTXSUFF(pVM)->pgm.s.GCPhysGstCR3Monitored == NIL_RTGCPHYS
1842 || (GCPhys & X86_PTE_PAE_PG_MASK) != (pPool->CTXSUFF(pVM)->pgm.s.GCPhysGstCR3Monitored & X86_PTE_PAE_PG_MASK)
1843 || pgmPoolIsBigPage((PGMPOOLKIND)pPage->enmKind);
1844# endif
1845# ifdef PGMPOOL_WITH_CACHE
1846 pgmPoolCacheInsert(pPool, pPage, fCanBeMonitored); /* This can be expanded. */
1847# endif
1848 if (fCanBeMonitored)
1849 {
1850# ifdef PGMPOOL_WITH_MONITORING
1851 rc = pgmPoolMonitorInsert(pPool, pPage);
1852 if (rc == VERR_PGM_POOL_CLEARED)
1853 {
1854 /* 'Failed' - free the usage, and keep it in the cache (if enabled). */
1855# ifndef PGMPOOL_WITH_CACHE
1856 pgmPoolMonitorFlush(pPool, pPage);
1857 rc = VERR_PGM_POOL_FLUSHED;
1858# endif
1859 pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
1860 pUser[i].iNext = pPool->iUserFreeHead;
1861 pUser[i].iUser = NIL_PGMPOOL_IDX;
1862 pPool->iUserFreeHead = i;
1863 }
1864 }
1865# endif
1866#endif /* PGMPOOL_WITH_MONITORING */
1867 return rc;
1868}
1869
1870
1871# ifdef PGMPOOL_WITH_CACHE /* (only used when the cache is enabled.) */
1872/**
1873 * Adds a user reference to a page.
1874 *
1875 * This will
1876 * This will move the page to the head of the
1877 *
1878 * @returns VBox status code.
1879 * @retval VINF_SUCCESS if successfully added.
1880 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
1881 * @param pPool The pool.
1882 * @param pPage The cached page.
1883 * @param iUser The user index.
1884 * @param iUserTable The user table.
1885 */
1886static int pgmPoolTrackAddUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint16_t iUserTable)
1887{
1888 PPGMPOOLUSER paUsers = pPool->CTXSUFF(paUsers);
1889
1890 LogFlow(("pgmPoolTrackAddUser iUser %d iUserTable %d\n", iUser, iUserTable));
1891# ifdef VBOX_STRICT
1892 /*
1893 * Check that the entry doesn't already exists.
1894 */
1895 if (pPage->iUserHead != NIL_PGMPOOL_USER_INDEX)
1896 {
1897 uint16_t i = pPage->iUserHead;
1898 do
1899 {
1900 Assert(i < pPool->cMaxUsers);
1901 AssertMsg(paUsers[i].iUser != iUser || paUsers[i].iUserTable != iUserTable, ("%x %x vs new %x %x\n", paUsers[i].iUser, paUsers[i].iUserTable, iUser, iUserTable));
1902 i = paUsers[i].iNext;
1903 } while (i != NIL_PGMPOOL_USER_INDEX);
1904 }
1905# endif
1906
1907 /*
1908 * Allocate a user node.
1909 */
1910 uint16_t i = pPool->iUserFreeHead;
1911 if (i == NIL_PGMPOOL_USER_INDEX)
1912 {
1913 int rc = pgmPoolTrackFreeOneUser(pPool, iUser);
1914 if (VBOX_FAILURE(rc))
1915 return rc;
1916 i = pPool->iUserFreeHead;
1917 }
1918 pPool->iUserFreeHead = paUsers[i].iNext;
1919
1920 /*
1921 * Initialize the user node and insert it.
1922 */
1923 paUsers[i].iNext = pPage->iUserHead;
1924 paUsers[i].iUser = iUser;
1925 paUsers[i].iUserTable = iUserTable;
1926 pPage->iUserHead = i;
1927
1928# ifdef PGMPOOL_WITH_CACHE
1929 /*
1930 * Tell the cache to update its replacement stats for this page.
1931 */
1932 pgmPoolCacheUsed(pPool, pPage);
1933# endif
1934 return VINF_SUCCESS;
1935}
1936# endif /* PGMPOOL_WITH_CACHE */
1937
1938
1939/**
1940 * Frees a user record associated with a page.
1941 *
1942 * This does not clear the entry in the user table, it simply replaces the
1943 * user record to the chain of free records.
1944 *
1945 * @param pPool The pool.
1946 * @param HCPhys The HC physical address of the shadow page.
1947 * @param iUser The shadow page pool index of the user table.
1948 * @param iUserTable The index into the user table (shadowed).
1949 */
1950static void pgmPoolTrackFreeUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint16_t iUserTable)
1951{
1952 /*
1953 * Unlink and free the specified user entry.
1954 */
1955 PPGMPOOLUSER paUsers = pPool->CTXSUFF(paUsers);
1956
1957 /* Special: For PAE and 32-bit paging, there are usually no more than one user. */
1958 uint16_t i = pPage->iUserHead;
1959 if ( i != NIL_PGMPOOL_USER_INDEX
1960 && paUsers[i].iUser == iUser
1961 && paUsers[i].iUserTable == iUserTable)
1962 {
1963 pPage->iUserHead = paUsers[i].iNext;
1964
1965 paUsers[i].iUser = NIL_PGMPOOL_IDX;
1966 paUsers[i].iNext = pPool->iUserFreeHead;
1967 pPool->iUserFreeHead = i;
1968 return;
1969 }
1970
1971 /* General: Linear search. */
1972 uint16_t iPrev = NIL_PGMPOOL_USER_INDEX;
1973 while (i != NIL_PGMPOOL_USER_INDEX)
1974 {
1975 if ( paUsers[i].iUser == iUser
1976 && paUsers[i].iUserTable == iUserTable)
1977 {
1978 if (iPrev != NIL_PGMPOOL_USER_INDEX)
1979 paUsers[iPrev].iNext = paUsers[i].iNext;
1980 else
1981 pPage->iUserHead = paUsers[i].iNext;
1982
1983 paUsers[i].iUser = NIL_PGMPOOL_IDX;
1984 paUsers[i].iNext = pPool->iUserFreeHead;
1985 pPool->iUserFreeHead = i;
1986 return;
1987 }
1988 iPrev = i;
1989 i = paUsers[i].iNext;
1990 }
1991
1992 /* Fatal: didn't find it */
1993 AssertFatalMsgFailed(("Didn't find the user entry! iUser=%#x iUserTable=%#x GCPhys=%VGp\n",
1994 iUser, iUserTable, pPage->GCPhys));
1995}
1996
1997
1998/**
1999 * Gets the entry size of a shadow table.
2000 *
2001 * @param enmKind The kind of page.
2002 *
2003 * @returns The size of the entry in bytes. That is, 4 or 8.
2004 * @returns If the kind is not for a table, an assertion is raised and 0 is
2005 * returned.
2006 */
2007DECLINLINE(unsigned) pgmPoolTrackGetShadowEntrySize(PGMPOOLKIND enmKind)
2008{
2009 switch (enmKind)
2010 {
2011 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2012 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2013 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2014 case PGMPOOLKIND_ROOT_32BIT_PD:
2015 return 4;
2016
2017 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2018 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2019 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2020 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2021 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2022 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
2023 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2024 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2025 case PGMPOOLKIND_ROOT_PAE_PD:
2026 case PGMPOOLKIND_ROOT_PDPT:
2027 case PGMPOOLKIND_ROOT_PML4:
2028 return 8;
2029
2030 default:
2031 AssertFatalMsgFailed(("enmKind=%d\n", enmKind));
2032 }
2033}
2034
2035
2036/**
2037 * Gets the entry size of a guest table.
2038 *
2039 * @param enmKind The kind of page.
2040 *
2041 * @returns The size of the entry in bytes. That is, 0, 4 or 8.
2042 * @returns If the kind is not for a table, an assertion is raised and 0 is
2043 * returned.
2044 */
2045DECLINLINE(unsigned) pgmPoolTrackGetGuestEntrySize(PGMPOOLKIND enmKind)
2046{
2047 switch (enmKind)
2048 {
2049 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2050 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2051 case PGMPOOLKIND_ROOT_32BIT_PD:
2052 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2053 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2054 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
2055 return 4;
2056
2057 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2058 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2059 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2060 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2061 case PGMPOOLKIND_ROOT_PAE_PD:
2062 case PGMPOOLKIND_ROOT_PDPT:
2063 case PGMPOOLKIND_ROOT_PML4:
2064 return 8;
2065
2066 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2067 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2068 /** @todo can we return 0? (nobody is calling this...) */
2069 return 0;
2070
2071 default:
2072 AssertFatalMsgFailed(("enmKind=%d\n", enmKind));
2073 }
2074}
2075
2076
2077#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
2078/**
2079 * Scans one shadow page table for mappings of a physical page.
2080 *
2081 * @param pVM The VM handle.
2082 * @param pPhysPage The guest page in question.
2083 * @param iShw The shadow page table.
2084 * @param cRefs The number of references made in that PT.
2085 */
2086static void pgmPoolTrackFlushGCPhysPTInt(PVM pVM, PCPGMPAGE pPhysPage, uint16_t iShw, uint16_t cRefs)
2087{
2088 LogFlow(("pgmPoolTrackFlushGCPhysPT: HCPhys=%RHp iShw=%d cRefs=%d\n", pPhysPage->HCPhys, iShw, cRefs));
2089 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
2090
2091 /*
2092 * Assert sanity.
2093 */
2094 Assert(cRefs == 1);
2095 AssertFatalMsg(iShw < pPool->cCurPages && iShw != NIL_PGMPOOL_IDX, ("iShw=%d\n", iShw));
2096 PPGMPOOLPAGE pPage = &pPool->aPages[iShw];
2097
2098 /*
2099 * Then, clear the actual mappings to the page in the shadow PT.
2100 */
2101 switch (pPage->enmKind)
2102 {
2103 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2104 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2105 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2106 {
2107 const uint32_t u32 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
2108 PX86PT pPT = (PX86PT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2109 for (unsigned i = pPage->iFirstPresent; i < ELEMENTS(pPT->a); i++)
2110 if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
2111 {
2112 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX32 cRefs=%#x\n", i, pPT->a[i], cRefs));
2113 pPT->a[i].u = 0;
2114 cRefs--;
2115 if (!cRefs)
2116 return;
2117 }
2118#if defined(DEBUG) && !defined(IN_RING0) ///@todo RTLogPrintf is missing in R0.
2119 RTLogPrintf("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent);
2120 for (unsigned i = 0; i < ELEMENTS(pPT->a); i++)
2121 if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
2122 {
2123 RTLogPrintf("i=%d cRefs=%d\n", i, cRefs--);
2124 pPT->a[i].u = 0;
2125 }
2126#endif
2127 AssertFatalMsgFailed(("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent));
2128 break;
2129 }
2130
2131 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2132 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2133 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2134 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2135 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2136 {
2137 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
2138 PX86PTPAE pPT = (PX86PTPAE)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2139 for (unsigned i = pPage->iFirstPresent; i < ELEMENTS(pPT->a); i++)
2140 if ((pPT->a[i].u & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
2141 {
2142 Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX64 cRefs=%#x\n", i, pPT->a[i], cRefs));
2143 pPT->a[i].u = 0;
2144 cRefs--;
2145 if (!cRefs)
2146 return;
2147 }
2148#if defined(DEBUG) && !defined(IN_RING0) ///@todo RTLogPrintf is missing in R0.
2149 RTLogPrintf("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent);
2150 for (unsigned i = 0; i < ELEMENTS(pPT->a); i++)
2151 if ((pPT->a[i].u & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
2152 {
2153 RTLogPrintf("i=%d cRefs=%d\n", i, cRefs--);
2154 pPT->a[i].u = 0;
2155 }
2156#endif
2157 AssertFatalMsgFailed(("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent));
2158 break;
2159 }
2160
2161 default:
2162 AssertFatalMsgFailed(("enmKind=%d iShw=%d\n", pPage->enmKind, iShw));
2163 }
2164}
2165
2166
2167/**
2168 * Scans one shadow page table for mappings of a physical page.
2169 *
2170 * @param pVM The VM handle.
2171 * @param pPhysPage The guest page in question.
2172 * @param iShw The shadow page table.
2173 * @param cRefs The number of references made in that PT.
2174 */
2175void pgmPoolTrackFlushGCPhysPT(PVM pVM, PPGMPAGE pPhysPage, uint16_t iShw, uint16_t cRefs)
2176{
2177 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool); NOREF(pPool);
2178 LogFlow(("pgmPoolTrackFlushGCPhysPT: HCPhys=%RHp iShw=%d cRefs=%d\n", pPhysPage->HCPhys, iShw, cRefs));
2179 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPT, f);
2180 pgmPoolTrackFlushGCPhysPTInt(pVM, pPhysPage, iShw, cRefs);
2181 pPhysPage->HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
2182 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPT, f);
2183}
2184
2185
2186/**
2187 * Flushes a list of shadow page tables mapping the same physical page.
2188 *
2189 * @param pVM The VM handle.
2190 * @param pPhysPage The guest page in question.
2191 * @param iPhysExt The physical cross reference extent list to flush.
2192 */
2193void pgmPoolTrackFlushGCPhysPTs(PVM pVM, PPGMPAGE pPhysPage, uint16_t iPhysExt)
2194{
2195 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
2196 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPTs, f);
2197 LogFlow(("pgmPoolTrackFlushGCPhysPTs: HCPhys=%RHp iPhysExt\n", pPhysPage->HCPhys, iPhysExt));
2198
2199 const uint16_t iPhysExtStart = iPhysExt;
2200 PPGMPOOLPHYSEXT pPhysExt;
2201 do
2202 {
2203 Assert(iPhysExt < pPool->cMaxPhysExts);
2204 pPhysExt = &pPool->CTXSUFF(paPhysExts)[iPhysExt];
2205 for (unsigned i = 0; i < ELEMENTS(pPhysExt->aidx); i++)
2206 if (pPhysExt->aidx[i] != NIL_PGMPOOL_IDX)
2207 {
2208 pgmPoolTrackFlushGCPhysPTInt(pVM, pPhysPage, pPhysExt->aidx[i], 1);
2209 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
2210 }
2211
2212 /* next */
2213 iPhysExt = pPhysExt->iNext;
2214 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
2215
2216 /* insert the list into the free list and clear the ram range entry. */
2217 pPhysExt->iNext = pPool->iPhysExtFreeHead;
2218 pPool->iPhysExtFreeHead = iPhysExtStart;
2219 pPhysPage->HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
2220
2221 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTs, f);
2222}
2223#endif /* PGMPOOL_WITH_GCPHYS_TRACKING */
2224
2225
2226/**
2227 * Scans all shadow page tables for mappings of a physical page.
2228 *
2229 * This may be slow, but it's most likely more efficient than cleaning
2230 * out the entire page pool / cache.
2231 *
2232 * @returns VBox status code.
2233 * @retval VINF_SUCCESS if all references has been successfully cleared.
2234 * @retval VINF_PGM_GCPHYS_ALIASED if we're better off with a CR3 sync and
2235 * a page pool cleaning.
2236 *
2237 * @param pVM The VM handle.
2238 * @param pPhysPage The guest page in question.
2239 */
2240int pgmPoolTrackFlushGCPhysPTsSlow(PVM pVM, PPGMPAGE pPhysPage)
2241{
2242 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
2243 STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPTsSlow, s);
2244 LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: cUsedPages=%d cPresent=%d HCPhys=%RHp\n",
2245 pPool->cUsedPages, pPool->cPresent, pPhysPage->HCPhys));
2246
2247#if 1
2248 /*
2249 * There is a limit to what makes sense.
2250 */
2251 if (pPool->cPresent > 1024)
2252 {
2253 LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: giving up... (cPresent=%d)\n", pPool->cPresent));
2254 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTsSlow, s);
2255 return VINF_PGM_GCPHYS_ALIASED;
2256 }
2257#endif
2258
2259 /*
2260 * Iterate all the pages until we've encountered all that in use.
2261 * This is simple but not quite optimal solution.
2262 */
2263 const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
2264 const uint32_t u32 = u64;
2265 unsigned cLeft = pPool->cUsedPages;
2266 unsigned iPage = pPool->cCurPages;
2267 while (--iPage >= PGMPOOL_IDX_FIRST)
2268 {
2269 PPGMPOOLPAGE pPage = &pPool->aPages[iPage];
2270 if (pPage->GCPhys != NIL_RTGCPHYS)
2271 {
2272 switch (pPage->enmKind)
2273 {
2274 /*
2275 * We only care about shadow page tables.
2276 */
2277 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2278 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2279 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
2280 {
2281 unsigned cPresent = pPage->cPresent;
2282 PX86PT pPT = (PX86PT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2283 for (unsigned i = pPage->iFirstPresent; i < ELEMENTS(pPT->a); i++)
2284 if (pPT->a[i].n.u1Present)
2285 {
2286 if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
2287 {
2288 //Log4(("pgmPoolTrackFlushGCPhysPTsSlow: idx=%d i=%d pte=%RX32\n", iPage, i, pPT->a[i]));
2289 pPT->a[i].u = 0;
2290 }
2291 if (!--cPresent)
2292 break;
2293 }
2294 break;
2295 }
2296
2297 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2298 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
2299 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2300 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
2301 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
2302 {
2303 unsigned cPresent = pPage->cPresent;
2304 PX86PTPAE pPT = (PX86PTPAE)PGMPOOL_PAGE_2_PTR(pVM, pPage);
2305 for (unsigned i = pPage->iFirstPresent; i < ELEMENTS(pPT->a); i++)
2306 if (pPT->a[i].n.u1Present)
2307 {
2308 if ((pPT->a[i].u & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
2309 {
2310 //Log4(("pgmPoolTrackFlushGCPhysPTsSlow: idx=%d i=%d pte=%RX64\n", iPage, i, pPT->a[i]));
2311 pPT->a[i].u = 0;
2312 }
2313 if (!--cPresent)
2314 break;
2315 }
2316 break;
2317 }
2318 }
2319 if (!--cLeft)
2320 break;
2321 }
2322 }
2323
2324 pPhysPage->HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
2325 STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTsSlow, s);
2326 return VINF_SUCCESS;
2327}
2328
2329
2330/**
2331 * Clears the user entry in a user table.
2332 *
2333 * This is used to remove all references to a page when flushing it.
2334 */
2335static void pgmPoolTrackClearPageUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PCPGMPOOLUSER pUser)
2336{
2337 Assert(pUser->iUser != NIL_PGMPOOL_IDX);
2338 Assert(pUser->iUser < pPool->cCurPages);
2339
2340 /*
2341 * Map the user page.
2342 */
2343 PPGMPOOLPAGE pUserPage = &pPool->aPages[pUser->iUser];
2344 union
2345 {
2346 uint64_t *pau64;
2347 uint32_t *pau32;
2348 } u;
2349 u.pau64 = (uint64_t *)PGMPOOL_PAGE_2_PTR(pPool->CTXSUFF(pVM), pUserPage);
2350
2351#ifdef VBOX_STRICT
2352 /*
2353 * Some sanity checks.
2354 */
2355 switch (pUserPage->enmKind)
2356 {
2357 case PGMPOOLKIND_ROOT_32BIT_PD:
2358 Assert(!(u.pau32[pUser->iUser] & PGM_PDFLAGS_MAPPING));
2359 Assert(pUser->iUserTable < X86_PG_ENTRIES);
2360 break;
2361 case PGMPOOLKIND_ROOT_PAE_PD:
2362 Assert(!(u.pau64[pUser->iUser] & PGM_PDFLAGS_MAPPING));
2363 Assert(pUser->iUserTable < 2048 && pUser->iUser == PGMPOOL_IDX_PAE_PD);
2364 break;
2365 case PGMPOOLKIND_ROOT_PDPT:
2366 Assert(!(u.pau64[pUser->iUserTable] & PGM_PLXFLAGS_PERMANENT));
2367 Assert(pUser->iUserTable < 4);
2368 break;
2369 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
2370 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2371 Assert(pUser->iUserTable < X86_PG_PAE_ENTRIES);
2372 break;
2373 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2374 case PGMPOOLKIND_ROOT_PML4:
2375 Assert(!(u.pau64[pUser->iUserTable] & PGM_PLXFLAGS_PERMANENT));
2376 Assert(pUser->iUserTable < X86_PG_PAE_ENTRIES);
2377 break;
2378 default:
2379 AssertMsgFailed(("enmKind=%d\n", pUserPage->enmKind));
2380 break;
2381 }
2382#endif /* VBOX_STRICT */
2383
2384 /*
2385 * Clear the entry in the user page.
2386 */
2387 switch (pUserPage->enmKind)
2388 {
2389 /* 32-bit entries */
2390 case PGMPOOLKIND_ROOT_32BIT_PD:
2391 u.pau32[pUser->iUserTable] = 0;
2392 break;
2393
2394 /* 64-bit entries */
2395 case PGMPOOLKIND_ROOT_PAE_PD:
2396 case PGMPOOLKIND_ROOT_PDPT:
2397 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
2398 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
2399 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
2400 case PGMPOOLKIND_ROOT_PML4:
2401 u.pau64[pUser->iUserTable] = 0;
2402 break;
2403
2404 default:
2405 AssertFatalMsgFailed(("enmKind=%d iUser=%#x iUserTable=%#x\n", pUserPage->enmKind, pUser->iUser, pUser->iUserTable));
2406 }
2407}
2408
2409
2410/**
2411 * Clears all users of a page.
2412 */
2413static void pgmPoolTrackClearPageUsers(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2414{
2415 /*
2416 * Free all the user records.
2417 */
2418 PPGMPOOLUSER paUsers = pPool->CTXSUFF(paUsers);
2419 uint16_t i = pPage->iUserHead;
2420 while (i != NIL_PGMPOOL_USER_INDEX)
2421 {
2422 /* Clear enter in user table. */
2423 pgmPoolTrackClearPageUser(pPool, pPage, &paUsers[i]);
2424
2425 /* Free it. */
2426 const uint16_t iNext = paUsers[i].iNext;
2427 paUsers[i].iUser = NIL_PGMPOOL_IDX;
2428 paUsers[i].iNext = pPool->iUserFreeHead;
2429 pPool->iUserFreeHead = i;
2430
2431 /* Next. */
2432 i = iNext;
2433 }
2434 pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
2435}
2436
2437
2438#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
2439/**
2440 * Allocates a new physical cross reference extent.
2441 *
2442 * @returns Pointer to the allocated extent on success. NULL if we're out of them.
2443 * @param pVM The VM handle.
2444 * @param piPhysExt Where to store the phys ext index.
2445 */
2446PPGMPOOLPHYSEXT pgmPoolTrackPhysExtAlloc(PVM pVM, uint16_t *piPhysExt)
2447{
2448 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
2449 uint16_t iPhysExt = pPool->iPhysExtFreeHead;
2450 if (iPhysExt == NIL_PGMPOOL_PHYSEXT_INDEX)
2451 {
2452 STAM_COUNTER_INC(&pPool->StamTrackPhysExtAllocFailures);
2453 return NULL;
2454 }
2455 PPGMPOOLPHYSEXT pPhysExt = &pPool->CTXSUFF(paPhysExts)[iPhysExt];
2456 pPool->iPhysExtFreeHead = pPhysExt->iNext;
2457 pPhysExt->iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
2458 *piPhysExt = iPhysExt;
2459 return pPhysExt;
2460}
2461
2462
2463/**
2464 * Frees a physical cross reference extent.
2465 *
2466 * @param pVM The VM handle.
2467 * @param iPhysExt The extent to free.
2468 */
2469void pgmPoolTrackPhysExtFree(PVM pVM, uint16_t iPhysExt)
2470{
2471 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
2472 Assert(iPhysExt < pPool->cMaxPhysExts);
2473 PPGMPOOLPHYSEXT pPhysExt = &pPool->CTXSUFF(paPhysExts)[iPhysExt];
2474 for (unsigned i = 0; i < ELEMENTS(pPhysExt->aidx); i++)
2475 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
2476 pPhysExt->iNext = pPool->iPhysExtFreeHead;
2477 pPool->iPhysExtFreeHead = iPhysExt;
2478}
2479
2480
2481/**
2482 * Frees a physical cross reference extent.
2483 *
2484 * @param pVM The VM handle.
2485 * @param iPhysExt The extent to free.
2486 */
2487void pgmPoolTrackPhysExtFreeList(PVM pVM, uint16_t iPhysExt)
2488{
2489 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
2490
2491 const uint16_t iPhysExtStart = iPhysExt;
2492 PPGMPOOLPHYSEXT pPhysExt;
2493 do
2494 {
2495 Assert(iPhysExt < pPool->cMaxPhysExts);
2496 pPhysExt = &pPool->CTXSUFF(paPhysExts)[iPhysExt];
2497 for (unsigned i = 0; i < ELEMENTS(pPhysExt->aidx); i++)
2498 pPhysExt->aidx[i] = NIL_PGMPOOL_IDX;
2499
2500 /* next */
2501 iPhysExt = pPhysExt->iNext;
2502 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
2503
2504 pPhysExt->iNext = pPool->iPhysExtFreeHead;
2505 pPool->iPhysExtFreeHead = iPhysExtStart;
2506}
2507
2508/**
2509 * Insert a reference into a list of physical cross reference extents.
2510 *
2511 * @returns The new ram range flags (top 16-bits).
2512 *
2513 * @param pVM The VM handle.
2514 * @param iPhysExt The physical extent index of the list head.
2515 * @param iShwPT The shadow page table index.
2516 *
2517 */
2518static uint16_t pgmPoolTrackPhysExtInsert(PVM pVM, uint16_t iPhysExt, uint16_t iShwPT)
2519{
2520 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
2521 PPGMPOOLPHYSEXT paPhysExts = pPool->CTXSUFF(paPhysExts);
2522
2523 /* special common case. */
2524 if (paPhysExts[iPhysExt].aidx[2] == NIL_PGMPOOL_IDX)
2525 {
2526 paPhysExts[iPhysExt].aidx[2] = iShwPT;
2527 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackAliasedMany);
2528 LogFlow(("pgmPoolTrackPhysExtAddref: %d:{,,%d}\n", iPhysExt, iShwPT));
2529 return iPhysExt | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
2530 }
2531
2532 /* general treatment. */
2533 const uint16_t iPhysExtStart = iPhysExt;
2534 unsigned cMax = 15;
2535 for (;;)
2536 {
2537 Assert(iPhysExt < pPool->cMaxPhysExts);
2538 for (unsigned i = 0; i < ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
2539 if (paPhysExts[iPhysExt].aidx[i] == NIL_PGMPOOL_IDX)
2540 {
2541 paPhysExts[iPhysExt].aidx[i] = iShwPT;
2542 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackAliasedMany);
2543 LogFlow(("pgmPoolTrackPhysExtAddref: %d:{%d} i=%d cMax=%d\n", iPhysExt, iShwPT, i, cMax));
2544 return iPhysExtStart | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
2545 }
2546 if (!--cMax)
2547 {
2548 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackOverflows);
2549 pgmPoolTrackPhysExtFreeList(pVM, iPhysExtStart);
2550 LogFlow(("pgmPoolTrackPhysExtAddref: overflow (1) iShwPT=%d\n", iShwPT));
2551 return MM_RAM_FLAGS_IDX_OVERFLOWED | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
2552 }
2553 }
2554
2555 /* add another extent to the list. */
2556 PPGMPOOLPHYSEXT pNew = pgmPoolTrackPhysExtAlloc(pVM, &iPhysExt);
2557 if (!pNew)
2558 {
2559 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackOverflows);
2560 pgmPoolTrackPhysExtFreeList(pVM, iPhysExtStart);
2561 return MM_RAM_FLAGS_IDX_OVERFLOWED | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
2562 }
2563 pNew->iNext = iPhysExtStart;
2564 pNew->aidx[0] = iShwPT;
2565 LogFlow(("pgmPoolTrackPhysExtAddref: added new extent %d:{%d}->%d\n", iPhysExt, iShwPT, iPhysExtStart));
2566 return iPhysExt | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
2567}
2568
2569
2570/**
2571 * Add a reference to guest physical page where extents are in use.
2572 *
2573 * @returns The new ram range flags (top 16-bits).
2574 *
2575 * @param pVM The VM handle.
2576 * @param u16 The ram range flags (top 16-bits).
2577 * @param iShwPT The shadow page table index.
2578 */
2579uint16_t pgmPoolTrackPhysExtAddref(PVM pVM, uint16_t u16, uint16_t iShwPT)
2580{
2581 if ((u16 >> (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT)) != MM_RAM_FLAGS_CREFS_PHYSEXT)
2582 {
2583 /*
2584 * Convert to extent list.
2585 */
2586 Assert((u16 >> (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT)) == 1);
2587 uint16_t iPhysExt;
2588 PPGMPOOLPHYSEXT pPhysExt = pgmPoolTrackPhysExtAlloc(pVM, &iPhysExt);
2589 if (pPhysExt)
2590 {
2591 LogFlow(("pgmPoolTrackPhysExtAddref: new extent: %d:{%d, %d}\n", iPhysExt, u16 & MM_RAM_FLAGS_IDX_MASK, iShwPT));
2592 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackAliased);
2593 pPhysExt->aidx[0] = u16 & MM_RAM_FLAGS_IDX_MASK;
2594 pPhysExt->aidx[1] = iShwPT;
2595 u16 = iPhysExt | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
2596 }
2597 else
2598 u16 = MM_RAM_FLAGS_IDX_OVERFLOWED | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
2599 }
2600 else if (u16 != (MM_RAM_FLAGS_IDX_OVERFLOWED | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT))))
2601 {
2602 /*
2603 * Insert into the extent list.
2604 */
2605 u16 = pgmPoolTrackPhysExtInsert(pVM, u16 & MM_RAM_FLAGS_IDX_MASK, iShwPT);
2606 }
2607 else
2608 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackAliasedLots);
2609 return u16;
2610}
2611
2612
2613/**
2614 * Clear references to guest physical memory.
2615 *
2616 * @param pPool The pool.
2617 * @param pPage The page.
2618 * @param pPhysPage Pointer to the aPages entry in the ram range.
2619 */
2620void pgmPoolTrackPhysExtDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PPGMPAGE pPhysPage)
2621{
2622 const unsigned cRefs = pPhysPage->HCPhys >> MM_RAM_FLAGS_CREFS_SHIFT; /** @todo PAGE FLAGS */
2623 AssertFatalMsg(cRefs == MM_RAM_FLAGS_CREFS_PHYSEXT, ("cRefs=%d HCPhys=%RHp pPage=%p:{.idx=%d}\n", cRefs, pPhysPage->HCPhys, pPage, pPage->idx));
2624
2625 uint16_t iPhysExt = (pPhysPage->HCPhys >> MM_RAM_FLAGS_IDX_SHIFT) & MM_RAM_FLAGS_IDX_MASK;
2626 if (iPhysExt != MM_RAM_FLAGS_IDX_OVERFLOWED)
2627 {
2628 uint16_t iPhysExtPrev = NIL_PGMPOOL_PHYSEXT_INDEX;
2629 PPGMPOOLPHYSEXT paPhysExts = pPool->CTXSUFF(paPhysExts);
2630 do
2631 {
2632 Assert(iPhysExt < pPool->cMaxPhysExts);
2633
2634 /*
2635 * Look for the shadow page and check if it's all freed.
2636 */
2637 for (unsigned i = 0; i < ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
2638 {
2639 if (paPhysExts[iPhysExt].aidx[i] == pPage->idx)
2640 {
2641 paPhysExts[iPhysExt].aidx[i] = NIL_PGMPOOL_IDX;
2642
2643 for (i = 0; i < ELEMENTS(paPhysExts[iPhysExt].aidx); i++)
2644 if (paPhysExts[iPhysExt].aidx[i] != NIL_PGMPOOL_IDX)
2645 {
2646 LogFlow(("pgmPoolTrackPhysExtDerefGCPhys: HCPhys=%RX64 idx=%d\n", pPhysPage->HCPhys, pPage->idx));
2647 return;
2648 }
2649
2650 /* we can free the node. */
2651 PVM pVM = pPool->CTXSUFF(pVM);
2652 const uint16_t iPhysExtNext = paPhysExts[iPhysExt].iNext;
2653 if ( iPhysExtPrev == NIL_PGMPOOL_PHYSEXT_INDEX
2654 && iPhysExtNext == NIL_PGMPOOL_PHYSEXT_INDEX)
2655 {
2656 /* lonely node */
2657 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
2658 LogFlow(("pgmPoolTrackPhysExtDerefGCPhys: HCPhys=%RX64 idx=%d lonely\n", pPhysPage->HCPhys, pPage->idx));
2659 pPhysPage->HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
2660 }
2661 else if (iPhysExtPrev == NIL_PGMPOOL_PHYSEXT_INDEX)
2662 {
2663 /* head */
2664 LogFlow(("pgmPoolTrackPhysExtDerefGCPhys: HCPhys=%RX64 idx=%d head\n", pPhysPage->HCPhys, pPage->idx));
2665 pPhysPage->HCPhys = (pPhysPage->HCPhys & MM_RAM_FLAGS_NO_REFS_MASK) /** @todo PAGE FLAGS */
2666 | ((uint64_t)MM_RAM_FLAGS_CREFS_PHYSEXT << MM_RAM_FLAGS_CREFS_SHIFT)
2667 | ((uint64_t)iPhysExtNext << MM_RAM_FLAGS_IDX_SHIFT);
2668 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
2669 }
2670 else
2671 {
2672 /* in list */
2673 LogFlow(("pgmPoolTrackPhysExtDerefGCPhys: HCPhys=%RX64 idx=%d\n", pPhysPage->HCPhys, pPage->idx));
2674 paPhysExts[iPhysExtPrev].iNext = iPhysExtNext;
2675 pgmPoolTrackPhysExtFree(pVM, iPhysExt);
2676 }
2677 iPhysExt = iPhysExtNext;
2678 return;
2679 }
2680 }
2681
2682 /* next */
2683 iPhysExtPrev = iPhysExt;
2684 iPhysExt = paPhysExts[iPhysExt].iNext;
2685 } while (iPhysExt != NIL_PGMPOOL_PHYSEXT_INDEX);
2686
2687 AssertFatalMsgFailed(("not-found! cRefs=%d HCPhys=%RHp pPage=%p:{.idx=%d}\n", cRefs, pPhysPage->HCPhys, pPage, pPage->idx));
2688 }
2689 else /* nothing to do */
2690 LogFlow(("pgmPoolTrackPhysExtDerefGCPhys: HCPhys=%RX64\n", pPhysPage->HCPhys));
2691}
2692
2693
2694
2695/**
2696 * Clear references to guest physical memory.
2697 *
2698 * This is the same as pgmPoolTracDerefGCPhys except that the guest physical address
2699 * is assumed to be correct, so the linear search can be skipped and we can assert
2700 * at an earlier point.
2701 *
2702 * @param pPool The pool.
2703 * @param pPage The page.
2704 * @param HCPhys The host physical address corresponding to the guest page.
2705 * @param GCPhys The guest physical address corresponding to HCPhys.
2706 */
2707static void pgmPoolTracDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhys)
2708{
2709 /*
2710 * Walk range list.
2711 */
2712 PPGMRAMRANGE pRam = pPool->CTXSUFF(pVM)->pgm.s.CTXALLSUFF(pRamRanges);
2713 while (pRam)
2714 {
2715 RTGCPHYS off = GCPhys - pRam->GCPhys;
2716 if (off < pRam->cb)
2717 {
2718 /* does it match? */
2719 const unsigned iPage = off >> PAGE_SHIFT;
2720 Assert(PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]));
2721 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
2722 {
2723 pgmTrackDerefGCPhys(pPool, pPage, &pRam->aPages[iPage]);
2724 return;
2725 }
2726 break;
2727 }
2728 pRam = CTXALLSUFF(pRam->pNext);
2729 }
2730 AssertFatalMsgFailed(("HCPhys=%VHp GCPhys=%VGp\n", HCPhys, GCPhys));
2731}
2732
2733
2734/**
2735 * Clear references to guest physical memory.
2736 *
2737 * @param pPool The pool.
2738 * @param pPage The page.
2739 * @param HCPhys The host physical address corresponding to the guest page.
2740 * @param GCPhysHint The guest physical address which may corresponding to HCPhys.
2741 */
2742static void pgmPoolTracDerefGCPhysHint(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhysHint)
2743{
2744 /*
2745 * Walk range list.
2746 */
2747 PPGMRAMRANGE pRam = pPool->CTXSUFF(pVM)->pgm.s.CTXALLSUFF(pRamRanges);
2748 while (pRam)
2749 {
2750 RTGCPHYS off = GCPhysHint - pRam->GCPhys;
2751 if (off < pRam->cb)
2752 {
2753 /* does it match? */
2754 const unsigned iPage = off >> PAGE_SHIFT;
2755 Assert(PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]));
2756 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
2757 {
2758 pgmTrackDerefGCPhys(pPool, pPage, &pRam->aPages[iPage]);
2759 return;
2760 }
2761 break;
2762 }
2763 pRam = CTXALLSUFF(pRam->pNext);
2764 }
2765
2766 /*
2767 * Damn, the hint didn't work. We'll have to do an expensive linear search.
2768 */
2769 STAM_COUNTER_INC(&pPool->StatTrackLinearRamSearches);
2770 pRam = pPool->CTXSUFF(pVM)->pgm.s.CTXALLSUFF(pRamRanges);
2771 while (pRam)
2772 {
2773 unsigned iPage = pRam->cb >> PAGE_SHIFT;
2774 while (iPage-- > 0)
2775 {
2776 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
2777 {
2778 Log4(("pgmPoolTracDerefGCPhysHint: Linear HCPhys=%VHp GCPhysHint=%VGp GCPhysReal=%VGp\n",
2779 HCPhys, GCPhysHint, pRam->GCPhys + (iPage << PAGE_SHIFT)));
2780 pgmTrackDerefGCPhys(pPool, pPage, &pRam->aPages[iPage]);
2781 return;
2782 }
2783 }
2784 pRam = CTXALLSUFF(pRam->pNext);
2785 }
2786
2787 AssertFatalMsgFailed(("HCPhys=%VHp GCPhysHint=%VGp\n", HCPhys, GCPhysHint));
2788}
2789
2790
2791/**
2792 * Clear references to guest physical memory in a 32-bit / 32-bit page table.
2793 *
2794 * @param pPool The pool.
2795 * @param pPage The page.
2796 * @param pShwPT The shadow page table (mapping of the page).
2797 * @param pGstPT The guest page table.
2798 */
2799DECLINLINE(void) pgmPoolTrackDerefPT32Bit32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PT pShwPT, PCX86PT pGstPT)
2800{
2801 for (unsigned i = pPage->iFirstPresent; i < ELEMENTS(pShwPT->a); i++)
2802 if (pShwPT->a[i].n.u1Present)
2803 {
2804 Log4(("pgmPoolTrackDerefPT32Bit32Bit: i=%d pte=%RX32 hint=%RX32\n",
2805 i, pShwPT->a[i].u & X86_PTE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK));
2806 pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK);
2807 if (!--pPage->cPresent)
2808 break;
2809 }
2810}
2811
2812
2813/**
2814 * Clear references to guest physical memory in a PAE / 32-bit page table.
2815 *
2816 * @param pPool The pool.
2817 * @param pPage The page.
2818 * @param pShwPT The shadow page table (mapping of the page).
2819 * @param pGstPT The guest page table (just a half one).
2820 */
2821DECLINLINE(void) pgmPoolTrackDerefPTPae32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PTPAE pShwPT, PCX86PT pGstPT)
2822{
2823 for (unsigned i = 0; i < ELEMENTS(pShwPT->a); i++)
2824 if (pShwPT->a[i].n.u1Present)
2825 {
2826 Log4(("pgmPoolTrackDerefPTPae32Bit: i=%d pte=%RX32 hint=%RX32\n",
2827 i, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK));
2828 pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK);
2829 }
2830}
2831
2832
2833/**
2834 * Clear references to guest physical memory in a PAE / PAE page table.
2835 *
2836 * @param pPool The pool.
2837 * @param pPage The page.
2838 * @param pShwPT The shadow page table (mapping of the page).
2839 * @param pGstPT The guest page table.
2840 */
2841DECLINLINE(void) pgmPoolTrackDerefPTPaePae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PTPAE pShwPT, PCX86PTPAE pGstPT)
2842{
2843 for (unsigned i = 0; i < ELEMENTS(pShwPT->a); i++)
2844 if (pShwPT->a[i].n.u1Present)
2845 {
2846 Log4(("pgmPoolTrackDerefPTPaePae: i=%d pte=%RX32 hint=%RX32\n",
2847 i, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PAE_PG_MASK));
2848 pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PAE_PG_MASK);
2849 }
2850}
2851
2852
2853/**
2854 * Clear references to guest physical memory in a 32-bit / 4MB page table.
2855 *
2856 * @param pPool The pool.
2857 * @param pPage The page.
2858 * @param pShwPT The shadow page table (mapping of the page).
2859 */
2860DECLINLINE(void) pgmPoolTrackDerefPT32Bit4MB(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PT pShwPT)
2861{
2862 RTGCPHYS GCPhys = pPage->GCPhys;
2863 for (unsigned i = 0; i < ELEMENTS(pShwPT->a); i++, GCPhys += PAGE_SIZE)
2864 if (pShwPT->a[i].n.u1Present)
2865 {
2866 Log4(("pgmPoolTrackDerefPT32Bit4MB: i=%d pte=%RX32 GCPhys=%RGp\n",
2867 i, pShwPT->a[i].u & X86_PTE_PG_MASK, GCPhys));
2868 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPT->a[i].u & X86_PTE_PG_MASK, GCPhys);
2869 }
2870}
2871
2872
2873/**
2874 * Clear references to guest physical memory in a PAE / 2/4MB page table.
2875 *
2876 * @param pPool The pool.
2877 * @param pPage The page.
2878 * @param pShwPT The shadow page table (mapping of the page).
2879 */
2880DECLINLINE(void) pgmPoolTrackDerefPTPaeBig(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PTPAE pShwPT)
2881{
2882 RTGCPHYS GCPhys = pPage->GCPhys;
2883 for (unsigned i = 0; i < ELEMENTS(pShwPT->a); i++, GCPhys += PAGE_SIZE)
2884 if (pShwPT->a[i].n.u1Present)
2885 {
2886 Log4(("pgmPoolTrackDerefPTPae32Bit: i=%d pte=%RX32 hint=%RX32\n",
2887 i, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, GCPhys));
2888 pgmPoolTracDerefGCPhys(pPool, pPage, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, GCPhys);
2889 }
2890}
2891#endif /* PGMPOOL_WITH_GCPHYS_TRACKING */
2892
2893
2894/**
2895 * Clear references to shadowed pages in a PAE page directory.
2896 *
2897 * @param pPool The pool.
2898 * @param pPage The page.
2899 * @param pShwPD The shadow page directory (mapping of the page).
2900 */
2901DECLINLINE(void) pgmPoolTrackDerefPDPae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PDPAE pShwPD)
2902{
2903 for (unsigned i = 0; i < ELEMENTS(pShwPD->a); i++)
2904 {
2905 if (pShwPD->a[i].n.u1Present)
2906 {
2907 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & X86_PDE_PAE_PG_MASK);
2908 if (pSubPage)
2909 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
2910 else
2911 AssertFatalMsgFailed(("%RX64\n", pShwPD->a[i].u & X86_PDE_PAE_PG_MASK));
2912 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
2913 }
2914 }
2915}
2916
2917
2918/**
2919 * Clear references to shadowed pages in a 64-bit page directory pointer table.
2920 *
2921 * @param pPool The pool.
2922 * @param pPage The page.
2923 * @param pShwPDPT The shadow page directory pointer table (mapping of the page).
2924 */
2925DECLINLINE(void) pgmPoolTrackDerefPDPT64Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PDPT pShwPDPT)
2926{
2927 for (unsigned i = 0; i < ELEMENTS(pShwPDPT->a); i++)
2928 {
2929 if (pShwPDPT->a[i].n.u1Present)
2930 {
2931 PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & X86_PDPE_PG_MASK);
2932 if (pSubPage)
2933 pgmPoolTrackFreeUser(pPool, pSubPage, pPage->idx, i);
2934 else
2935 AssertFatalMsgFailed(("%RX64\n", pShwPDPT->a[i].u & X86_PDPE_PG_MASK));
2936 /** @todo 64-bit guests: have to ensure that we're not exhausting the dynamic mappings! */
2937 }
2938 }
2939}
2940
2941
2942/**
2943 * Clears all references made by this page.
2944 *
2945 * This includes other shadow pages and GC physical addresses.
2946 *
2947 * @param pPool The pool.
2948 * @param pPage The page.
2949 */
2950static void pgmPoolTrackDeref(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
2951{
2952 /*
2953 * Map the shadow page and take action according to the page kind.
2954 */
2955 void *pvShw = PGMPOOL_PAGE_2_PTR(pPool->CTXSUFF(pVM), pPage);
2956 switch (pPage->enmKind)
2957 {
2958#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
2959 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
2960 {
2961 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
2962 void *pvGst;
2963 int rc = PGM_GCPHYS_2_PTR(pPool->CTXSUFF(pVM), pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
2964 pgmPoolTrackDerefPT32Bit32Bit(pPool, pPage, (PX86PT)pvShw, (PCX86PT)pvGst);
2965 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
2966 break;
2967 }
2968
2969 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
2970 {
2971 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
2972 void *pvGst;
2973 int rc = PGM_GCPHYS_2_PTR_EX(pPool->CTXSUFF(pVM), pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
2974 pgmPoolTrackDerefPTPae32Bit(pPool, pPage, (PX86PTPAE)pvShw, (PCX86PT)pvGst);
2975 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
2976 break;
2977 }
2978
2979 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
2980 {
2981 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
2982 void *pvGst;
2983 int rc = PGM_GCPHYS_2_PTR(pPool->CTXSUFF(pVM), pPage->GCPhys, &pvGst); AssertReleaseRC(rc);
2984 pgmPoolTrackDerefPTPaePae(pPool, pPage, (PX86PTPAE)pvShw, (PCX86PTPAE)pvGst);
2985 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
2986 break;
2987 }
2988
2989 case PGMPOOLKIND_32BIT_PT_FOR_PHYS: /* treat it like a 4 MB page */
2990 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
2991 {
2992 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
2993 pgmPoolTrackDerefPT32Bit4MB(pPool, pPage, (PX86PT)pvShw);
2994 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
2995 break;
2996 }
2997
2998 case PGMPOOLKIND_PAE_PT_FOR_PHYS: /* treat it like a 4 MB page */
2999 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
3000 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
3001 {
3002 STAM_PROFILE_START(&pPool->StatTrackDerefGCPhys, g);
3003 pgmPoolTrackDerefPTPaeBig(pPool, pPage, (PX86PTPAE)pvShw);
3004 STAM_PROFILE_STOP(&pPool->StatTrackDerefGCPhys, g);
3005 break;
3006 }
3007
3008#else /* !PGMPOOL_WITH_GCPHYS_TRACKING */
3009 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT:
3010 case PGMPOOLKIND_PAE_PT_FOR_32BIT_PT:
3011 case PGMPOOLKIND_PAE_PT_FOR_PAE_PT:
3012 case PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB:
3013 case PGMPOOLKIND_PAE_PT_FOR_PAE_2MB:
3014 case PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB:
3015 case PGMPOOLKIND_32BIT_PT_FOR_PHYS:
3016 case PGMPOOLKIND_PAE_PT_FOR_PHYS:
3017 break;
3018#endif /* !PGMPOOL_WITH_GCPHYS_TRACKING */
3019
3020 case PGMPOOLKIND_PAE_PD_FOR_32BIT_PD:
3021 case PGMPOOLKIND_PAE_PD_FOR_PAE_PD:
3022 pgmPoolTrackDerefPDPae(pPool, pPage, (PX86PDPAE)pvShw);
3023 break;
3024
3025 case PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT:
3026 pgmPoolTrackDerefPDPT64Bit(pPool, pPage, (PX86PDPT)pvShw);
3027 break;
3028
3029 default:
3030 AssertFatalMsgFailed(("enmKind=%d\n", pPage->enmKind));
3031 }
3032
3033 /* paranoia, clear the shadow page. Remove this laser (i.e. let Alloc and ClearAll do it). */
3034 STAM_PROFILE_START(&pPool->StatZeroPage, z);
3035 ASMMemZeroPage(pvShw);
3036 STAM_PROFILE_STOP(&pPool->StatZeroPage, z);
3037 pPage->fZeroed = true;
3038}
3039#endif /* PGMPOOL_WITH_USER_TRACKING */
3040
3041
3042/**
3043 * Flushes all the special root pages as part of a pgmPoolFlushAllInt operation.
3044 *
3045 * @param pPool The pool.
3046 */
3047static void pgmPoolFlushAllSpecialRoots(PPGMPOOL pPool)
3048{
3049 /*
3050 * These special pages are all mapped into the indexes 1..PGMPOOL_IDX_FIRST.
3051 */
3052 Assert(NIL_PGMPOOL_IDX == 0);
3053 for (unsigned i = 1; i < PGMPOOL_IDX_FIRST; i++)
3054 {
3055 /*
3056 * Get the page address.
3057 */
3058 PPGMPOOLPAGE pPage = &pPool->aPages[i];
3059 union
3060 {
3061 uint64_t *pau64;
3062 uint32_t *pau32;
3063 } u;
3064 u.pau64 = (uint64_t *)PGMPOOL_PAGE_2_PTR(pPool->CTXSUFF(pVM), pPage);
3065
3066 /*
3067 * Mark stuff not present.
3068 */
3069 switch (pPage->enmKind)
3070 {
3071 case PGMPOOLKIND_ROOT_32BIT_PD:
3072 for (unsigned iPage = 0; iPage < X86_PG_ENTRIES; iPage++)
3073 if ((u.pau32[iPage] & (PGM_PDFLAGS_MAPPING | X86_PDE_P)) == X86_PDE_P)
3074 u.pau32[iPage] = 0;
3075 break;
3076
3077 case PGMPOOLKIND_ROOT_PAE_PD:
3078 for (unsigned iPage = 0; iPage < X86_PG_PAE_ENTRIES * X86_PG_PAE_PDPE_ENTRIES; iPage++)
3079 if ((u.pau64[iPage] & (PGM_PDFLAGS_MAPPING | X86_PDE_P)) == X86_PDE_P)
3080 u.pau64[iPage] = 0;
3081 break;
3082
3083 case PGMPOOLKIND_ROOT_PML4:
3084 for (unsigned iPage = 0; iPage < X86_PG_PAE_ENTRIES; iPage++)
3085 if ((u.pau64[iPage] & (PGM_PLXFLAGS_PERMANENT | X86_PML4E_P)) == X86_PML4E_P)
3086 u.pau64[iPage] = 0;
3087 break;
3088
3089 case PGMPOOLKIND_ROOT_PDPT:
3090 /* Not root of shadowed pages currently, ignore it. */
3091 break;
3092 }
3093 }
3094
3095 /*
3096 * Paranoia (to be removed), flag a global CR3 sync.
3097 */
3098 VM_FF_SET(pPool->CTXSUFF(pVM), VM_FF_PGM_SYNC_CR3);
3099}
3100
3101
3102/**
3103 * Flushes the entire cache.
3104 *
3105 * It will assert a global CR3 flush (FF) and assumes the caller is aware of this
3106 * and execute this CR3 flush.
3107 *
3108 * @param pPool The pool.
3109 */
3110static void pgmPoolFlushAllInt(PPGMPOOL pPool)
3111{
3112 STAM_PROFILE_START(&pPool->StatFlushAllInt, a);
3113 LogFlow(("pgmPoolFlushAllInt:\n"));
3114
3115 /*
3116 * If there are no pages in the pool, there is nothing to do.
3117 */
3118 if (pPool->cCurPages <= PGMPOOL_IDX_FIRST)
3119 {
3120 STAM_PROFILE_STOP(&pPool->StatFlushAllInt, a);
3121 return;
3122 }
3123
3124 /*
3125 * Nuke the free list and reinsert all pages into it.
3126 */
3127 for (unsigned i = pPool->cCurPages - 1; i >= PGMPOOL_IDX_FIRST; i--)
3128 {
3129 PPGMPOOLPAGE pPage = &pPool->aPages[i];
3130
3131#ifdef IN_RING3
3132 Assert(pPage->Core.Key == MMPage2Phys(pPool->pVMHC, pPage->pvPageHC));
3133#endif
3134#ifdef PGMPOOL_WITH_MONITORING
3135 if (pPage->fMonitored)
3136 pgmPoolMonitorFlush(pPool, pPage);
3137 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
3138 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
3139 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
3140 pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
3141 pPage->cModifications = 0;
3142#endif
3143 pPage->GCPhys = NIL_RTGCPHYS;
3144 pPage->enmKind = PGMPOOLKIND_FREE;
3145 Assert(pPage->idx == i);
3146 pPage->iNext = i + 1;
3147 pPage->fZeroed = false; /* This could probably be optimized, but better safe than sorry. */
3148 pPage->fSeenNonGlobal = false;
3149 pPage->fMonitored= false;
3150 pPage->fCached = false;
3151 pPage->fReusedFlushPending = false;
3152 pPage->fCR3Mix = false;
3153#ifdef PGMPOOL_WITH_USER_TRACKING
3154 pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
3155#endif
3156#ifdef PGMPOOL_WITH_CACHE
3157 pPage->iAgeNext = NIL_PGMPOOL_IDX;
3158 pPage->iAgePrev = NIL_PGMPOOL_IDX;
3159#endif
3160 }
3161 pPool->aPages[pPool->cCurPages - 1].iNext = NIL_PGMPOOL_IDX;
3162 pPool->iFreeHead = PGMPOOL_IDX_FIRST;
3163 pPool->cUsedPages = 0;
3164
3165#ifdef PGMPOOL_WITH_USER_TRACKING
3166 /*
3167 * Zap and reinitialize the user records.
3168 */
3169 pPool->cPresent = 0;
3170 pPool->iUserFreeHead = 0;
3171 PPGMPOOLUSER paUsers = pPool->CTXSUFF(paUsers);
3172 const unsigned cMaxUsers = pPool->cMaxUsers;
3173 for (unsigned i = 0; i < cMaxUsers; i++)
3174 {
3175 paUsers[i].iNext = i + 1;
3176 paUsers[i].iUser = NIL_PGMPOOL_IDX;
3177 paUsers[i].iUserTable = 0xfffe;
3178 }
3179 paUsers[cMaxUsers - 1].iNext = NIL_PGMPOOL_USER_INDEX;
3180#endif
3181
3182#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
3183 /*
3184 * Clear all the GCPhys links and rebuild the phys ext free list.
3185 */
3186 for (PPGMRAMRANGE pRam = pPool->CTXSUFF(pVM)->pgm.s.CTXALLSUFF(pRamRanges);
3187 pRam;
3188 pRam = CTXALLSUFF(pRam->pNext))
3189 {
3190 unsigned iPage = pRam->cb >> PAGE_SHIFT;
3191 while (iPage-- > 0)
3192 pRam->aPages[iPage].HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
3193 }
3194
3195 pPool->iPhysExtFreeHead = 0;
3196 PPGMPOOLPHYSEXT paPhysExts = pPool->CTXSUFF(paPhysExts);
3197 const unsigned cMaxPhysExts = pPool->cMaxPhysExts;
3198 for (unsigned i = 0; i < cMaxPhysExts; i++)
3199 {
3200 paPhysExts[i].iNext = i + 1;
3201 paPhysExts[i].aidx[0] = NIL_PGMPOOL_IDX;
3202 paPhysExts[i].aidx[1] = NIL_PGMPOOL_IDX;
3203 paPhysExts[i].aidx[2] = NIL_PGMPOOL_IDX;
3204 }
3205 paPhysExts[cMaxPhysExts - 1].iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
3206#endif
3207
3208#ifdef PGMPOOL_WITH_MONITORING
3209 /*
3210 * Just zap the modified list.
3211 */
3212 pPool->cModifiedPages = 0;
3213 pPool->iModifiedHead = NIL_PGMPOOL_IDX;
3214#endif
3215
3216#ifdef PGMPOOL_WITH_CACHE
3217 /*
3218 * Clear the GCPhys hash and the age list.
3219 */
3220 for (unsigned i = 0; i < ELEMENTS(pPool->aiHash); i++)
3221 pPool->aiHash[i] = NIL_PGMPOOL_IDX;
3222 pPool->iAgeHead = NIL_PGMPOOL_IDX;
3223 pPool->iAgeTail = NIL_PGMPOOL_IDX;
3224#endif
3225
3226 /*
3227 * Flush all the special root pages.
3228 * Reinsert active pages into the hash and ensure monitoring chains are correct.
3229 */
3230 pgmPoolFlushAllSpecialRoots(pPool);
3231 for (unsigned i = PGMPOOL_IDX_FIRST_SPECIAL; i < PGMPOOL_IDX_FIRST; i++)
3232 {
3233 PPGMPOOLPAGE pPage = &pPool->aPages[i];
3234 pPage->iNext = NIL_PGMPOOL_IDX;
3235#ifdef PGMPOOL_WITH_MONITORING
3236 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
3237 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
3238 pPage->cModifications = 0;
3239 /* ASSUMES that we're not sharing with any of the other special pages (safe for now). */
3240 pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
3241 pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
3242 if (pPage->fMonitored)
3243 {
3244 PVM pVM = pPool->CTXSUFF(pVM);
3245 int rc = PGMHandlerPhysicalChangeCallbacks(pVM, pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1),
3246 pPool->pfnAccessHandlerR3, MMHyperCCToR3(pVM, pPage),
3247 pPool->pfnAccessHandlerR0, MMHyperCCToR0(pVM, pPage),
3248 pPool->pfnAccessHandlerGC, MMHyperCCToGC(pVM, pPage),
3249 pPool->pszAccessHandler);
3250 AssertFatalRCSuccess(rc);
3251# ifdef PGMPOOL_WITH_CACHE
3252 pgmPoolHashInsert(pPool, pPage);
3253# endif
3254 }
3255#endif
3256#ifdef PGMPOOL_WITH_USER_TRACKING
3257 Assert(pPage->iUserHead == NIL_PGMPOOL_USER_INDEX); /* for now */
3258#endif
3259#ifdef PGMPOOL_WITH_CACHE
3260 Assert(pPage->iAgeNext == NIL_PGMPOOL_IDX);
3261 Assert(pPage->iAgePrev == NIL_PGMPOOL_IDX);
3262#endif
3263 }
3264
3265 STAM_PROFILE_STOP(&pPool->StatFlushAllInt, a);
3266}
3267
3268
3269/**
3270 * Flushes a pool page.
3271 *
3272 * This moves the page to the free list after removing all user references to it.
3273 * In GC this will cause a CR3 reload if the page is traced back to an active root page.
3274 *
3275 * @returns VBox status code.
3276 * @retval VINF_SUCCESS on success.
3277 * @retval VERR_PGM_POOL_CLEARED if the deregistration of the physical handler will cause a light weight pool flush.
3278 * @param pPool The pool.
3279 * @param HCPhys The HC physical address of the shadow page.
3280 */
3281int pgmPoolFlushPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
3282{
3283 int rc = VINF_SUCCESS;
3284 STAM_PROFILE_START(&pPool->StatFlushPage, f);
3285 LogFlow(("pgmPoolFlushPage: pPage=%p:{.Key=%VHp, .idx=%d, .enmKind=%d, .GCPhys=%VGp}\n",
3286 pPage, pPage->Core.Key, pPage->idx, pPage->enmKind, pPage->GCPhys));
3287
3288 /*
3289 * Quietly reject any attempts at flushing any of the special root pages.
3290 */
3291 if (pPage->idx < PGMPOOL_IDX_FIRST)
3292 {
3293 Log(("pgmPoolFlushPage: specaial root page, rejected. enmKind=%d idx=%d\n", pPage->enmKind, pPage->idx));
3294 return VINF_SUCCESS;
3295 }
3296
3297 /*
3298 * Mark the page as being in need of a ASMMemZeroPage().
3299 */
3300 pPage->fZeroed = false;
3301
3302#ifdef PGMPOOL_WITH_USER_TRACKING
3303 /*
3304 * Clear the page.
3305 */
3306 pgmPoolTrackClearPageUsers(pPool, pPage);
3307 STAM_PROFILE_START(&pPool->StatTrackDeref,a);
3308 pgmPoolTrackDeref(pPool, pPage);
3309 STAM_PROFILE_STOP(&pPool->StatTrackDeref,a);
3310#endif
3311
3312#ifdef PGMPOOL_WITH_CACHE
3313 /*
3314 * Flush it from the cache.
3315 */
3316 pgmPoolCacheFlushPage(pPool, pPage);
3317#endif /* PGMPOOL_WITH_CACHE */
3318
3319#ifdef PGMPOOL_WITH_MONITORING
3320 /*
3321 * Deregistering the monitoring.
3322 */
3323 if (pPage->fMonitored)
3324 rc = pgmPoolMonitorFlush(pPool, pPage);
3325#endif
3326
3327 /*
3328 * Free the page.
3329 */
3330 Assert(pPage->iNext == NIL_PGMPOOL_IDX);
3331 pPage->iNext = pPool->iFreeHead;
3332 pPool->iFreeHead = pPage->idx;
3333 pPage->enmKind = PGMPOOLKIND_FREE;
3334 pPage->GCPhys = NIL_RTGCPHYS;
3335 pPage->fReusedFlushPending = false;
3336
3337 pPool->cUsedPages--;
3338 STAM_PROFILE_STOP(&pPool->StatFlushPage, f);
3339 return rc;
3340}
3341
3342
3343/**
3344 * Frees a usage of a pool page.
3345 *
3346 * The caller is responsible to updating the user table so that it no longer
3347 * references the shadow page.
3348 *
3349 * @param pPool The pool.
3350 * @param HCPhys The HC physical address of the shadow page.
3351 * @param iUser The shadow page pool index of the user table.
3352 * @param iUserTable The index into the user table (shadowed).
3353 */
3354void pgmPoolFreeByPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint16_t iUserTable)
3355{
3356 STAM_PROFILE_START(&pPool->StatFree, a);
3357 LogFlow(("pgmPoolFreeByPage: pPage=%p:{.Key=%VHp, .idx=%d, enmKind=%d} iUser=%#x iUserTable=%#x\n",
3358 pPage, pPage->Core.Key, pPage->idx, pPage->enmKind, iUser, iUserTable));
3359 Assert(pPage->idx >= PGMPOOL_IDX_FIRST);
3360#ifdef PGMPOOL_WITH_USER_TRACKING
3361 pgmPoolTrackFreeUser(pPool, pPage, iUser, iUserTable);
3362#endif
3363#ifdef PGMPOOL_WITH_CACHE
3364 if (!pPage->fCached)
3365#endif
3366 pgmPoolFlushPage(pPool, pPage); /* ASSUMES that VERR_PGM_POOL_CLEARED can be ignored here. */
3367 STAM_PROFILE_STOP(&pPool->StatFree, a);
3368}
3369
3370
3371/**
3372 * Makes one or more free page free.
3373 *
3374 * @returns VBox status code.
3375 * @retval VINF_SUCCESS on success.
3376 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
3377 *
3378 * @param pPool The pool.
3379 * @param iUser The user of the page.
3380 */
3381static int pgmPoolMakeMoreFreePages(PPGMPOOL pPool, uint16_t iUser)
3382{
3383 LogFlow(("pgmPoolMakeMoreFreePages: iUser=%#x\n", iUser));
3384
3385 /*
3386 * If the pool isn't full grown yet, expand it.
3387 */
3388 if (pPool->cCurPages < pPool->cMaxPages)
3389 {
3390 STAM_PROFILE_ADV_SUSPEND(&pPool->StatAlloc, a);
3391#ifdef IN_RING3
3392 int rc = PGMR3PoolGrow(pPool->pVMHC);
3393#else
3394 int rc = CTXALLMID(VMM, CallHost)(pPool->CTXSUFF(pVM), VMMCALLHOST_PGM_POOL_GROW, 0);
3395#endif
3396 if (VBOX_FAILURE(rc))
3397 return rc;
3398 STAM_PROFILE_ADV_RESUME(&pPool->StatAlloc, a);
3399 if (pPool->iFreeHead != NIL_PGMPOOL_IDX)
3400 return VINF_SUCCESS;
3401 }
3402
3403#ifdef PGMPOOL_WITH_CACHE
3404 /*
3405 * Free one cached page.
3406 */
3407 return pgmPoolCacheFreeOne(pPool, iUser);
3408#else
3409 /*
3410 * Flush the pool.
3411 * If we have tracking enabled, it should be possible to come up with
3412 * a cheap replacement strategy...
3413 */
3414 pgmPoolFlushAllInt(pPool);
3415 return VERR_PGM_POOL_FLUSHED;
3416#endif
3417}
3418
3419
3420/**
3421 * Allocates a page from the pool.
3422 *
3423 * This page may actually be a cached page and not in need of any processing
3424 * on the callers part.
3425 *
3426 * @returns VBox status code.
3427 * @retval VINF_SUCCESS if a NEW page was allocated.
3428 * @retval VINF_PGM_CACHED_PAGE if a CACHED page was returned.
3429 * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
3430 * @param pVM The VM handle.
3431 * @param GCPhys The GC physical address of the page we're gonna shadow.
3432 * For 4MB and 2MB PD entries, it's the first address the
3433 * shadow PT is covering.
3434 * @param enmKind The kind of mapping.
3435 * @param iUser The shadow page pool index of the user table.
3436 * @param iUserTable The index into the user table (shadowed).
3437 * @param ppPage Where to store the pointer to the page. NULL is stored here on failure.
3438 */
3439int pgmPoolAlloc(PVM pVM, RTGCPHYS GCPhys, PGMPOOLKIND enmKind, uint16_t iUser, uint16_t iUserTable, PPPGMPOOLPAGE ppPage)
3440{
3441 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
3442 STAM_PROFILE_ADV_START(&pPool->StatAlloc, a);
3443 LogFlow(("pgmPoolAlloc: GCPhys=%VGp enmKind=%d iUser=%#x iUserTable=%#x\n", GCPhys, enmKind, iUser, iUserTable));
3444 *ppPage = NULL;
3445
3446#ifdef PGMPOOL_WITH_CACHE
3447 if (pPool->fCacheEnabled)
3448 {
3449 int rc2 = pgmPoolCacheAlloc(pPool, GCPhys, enmKind, iUser, iUserTable, ppPage);
3450 if (VBOX_SUCCESS(rc2))
3451 {
3452 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
3453 LogFlow(("pgmPoolAlloc: returns %Vrc *ppPage=%p:{.Key=%VHp, .idx=%d}\n", rc2, *ppPage, (*ppPage)->Core.Key, (*ppPage)->idx));
3454 return rc2;
3455 }
3456 }
3457#endif
3458
3459 /*
3460 * Allocate a new one.
3461 */
3462 int rc = VINF_SUCCESS;
3463 uint16_t iNew = pPool->iFreeHead;
3464 if (iNew == NIL_PGMPOOL_IDX)
3465 {
3466 rc = pgmPoolMakeMoreFreePages(pPool, iUser);
3467 if (VBOX_FAILURE(rc))
3468 {
3469 if (rc != VERR_PGM_POOL_CLEARED)
3470 {
3471 Log(("pgmPoolAlloc: returns %Vrc (Free)\n", rc));
3472 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
3473 return rc;
3474 }
3475 rc = VERR_PGM_POOL_FLUSHED;
3476 }
3477 iNew = pPool->iFreeHead;
3478 AssertReleaseReturn(iNew != NIL_PGMPOOL_IDX, VERR_INTERNAL_ERROR);
3479 }
3480
3481 /* unlink the free head */
3482 PPGMPOOLPAGE pPage = &pPool->aPages[iNew];
3483 pPool->iFreeHead = pPage->iNext;
3484 pPage->iNext = NIL_PGMPOOL_IDX;
3485
3486 /*
3487 * Initialize it.
3488 */
3489 pPool->cUsedPages++; /* physical handler registration / pgmPoolTrackFlushGCPhysPTsSlow requirement. */
3490 pPage->enmKind = enmKind;
3491 pPage->GCPhys = GCPhys;
3492 pPage->fSeenNonGlobal = false; /* Set this to 'true' to disable this feature. */
3493 pPage->fMonitored = false;
3494 pPage->fCached = false;
3495 pPage->fReusedFlushPending = false;
3496 pPage->fCR3Mix = false;
3497#ifdef PGMPOOL_WITH_MONITORING
3498 pPage->cModifications = 0;
3499 pPage->iModifiedNext = NIL_PGMPOOL_IDX;
3500 pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
3501#endif
3502#ifdef PGMPOOL_WITH_USER_TRACKING
3503 pPage->cPresent = 0;
3504 pPage->iFirstPresent = ~0;
3505
3506 /*
3507 * Insert into the tracking and cache. If this fails, free the page.
3508 */
3509 int rc3 = pgmPoolTrackInsert(pPool, pPage, GCPhys, iUser, iUserTable);
3510 if (VBOX_FAILURE(rc3))
3511 {
3512 if (rc3 != VERR_PGM_POOL_CLEARED)
3513 {
3514 pPool->cUsedPages--;
3515 pPage->enmKind = PGMPOOLKIND_FREE;
3516 pPage->GCPhys = NIL_RTGCPHYS;
3517 pPage->iNext = pPool->iFreeHead;
3518 pPool->iFreeHead = pPage->idx;
3519 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
3520 Log(("pgmPoolAlloc: returns %Vrc (Insert)\n", rc3));
3521 return rc3;
3522 }
3523 rc = VERR_PGM_POOL_FLUSHED;
3524 }
3525#endif /* PGMPOOL_WITH_USER_TRACKING */
3526
3527 /*
3528 * Commit the allocation, clear the page and return.
3529 */
3530#ifdef VBOX_WITH_STATISTICS
3531 if (pPool->cUsedPages > pPool->cUsedPagesHigh)
3532 pPool->cUsedPagesHigh = pPool->cUsedPages;
3533#endif
3534
3535 if (!pPage->fZeroed)
3536 {
3537 STAM_PROFILE_START(&pPool->StatZeroPage, z);
3538 void *pv = PGMPOOL_PAGE_2_PTR(pVM, pPage);
3539 ASMMemZeroPage(pv);
3540 STAM_PROFILE_STOP(&pPool->StatZeroPage, z);
3541 }
3542
3543 *ppPage = pPage;
3544 LogFlow(("pgmPoolAlloc: returns %Vrc *ppPage=%p:{.Key=%VHp, .idx=%d, .fCached=%RTbool, .fMonitored=%RTbool}\n",
3545 rc, pPage, pPage->Core.Key, pPage->idx, pPage->fCached, pPage->fMonitored));
3546 STAM_PROFILE_ADV_STOP(&pPool->StatAlloc, a);
3547 return rc;
3548}
3549
3550
3551/**
3552 * Frees a usage of a pool page.
3553 *
3554 * @param pVM The VM handle.
3555 * @param HCPhys The HC physical address of the shadow page.
3556 * @param iUser The shadow page pool index of the user table.
3557 * @param iUserTable The index into the user table (shadowed).
3558 */
3559void pgmPoolFree(PVM pVM, RTHCPHYS HCPhys, uint16_t iUser, uint16_t iUserTable)
3560{
3561 LogFlow(("pgmPoolFree: HCPhys=%VHp iUser=%#x iUserTable=%#x\n", HCPhys, iUser, iUserTable));
3562 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
3563 pgmPoolFreeByPage(pPool, pgmPoolGetPage(pPool, HCPhys), iUser, iUserTable);
3564}
3565
3566
3567/**
3568 * Gets a in-use page in the pool by it's physical address.
3569 *
3570 * @returns Pointer to the page.
3571 * @param pVM The VM handle.
3572 * @param HCPhys The HC physical address of the shadow page.
3573 * @remark This function will NEVER return NULL. It will assert if HCPhys is invalid.
3574 */
3575PPGMPOOLPAGE pgmPoolGetPageByHCPhys(PVM pVM, RTHCPHYS HCPhys)
3576{
3577 /** @todo profile this! */
3578 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
3579 PPGMPOOLPAGE pPage = pgmPoolGetPage(pPool, HCPhys);
3580 Log3(("pgmPoolGetPageByHCPhys: HCPhys=%VHp -> %p:{.idx=%d .GCPhys=%VGp .enmKind=%d}\n",
3581 HCPhys, pPage, pPage->idx, pPage->GCPhys, pPage->enmKind));
3582 return pPage;
3583}
3584
3585
3586/**
3587 * Flushes the entire cache.
3588 *
3589 * It will assert a global CR3 flush (FF) and assumes the caller is aware of this
3590 * and execute this CR3 flush.
3591 *
3592 * @param pPool The pool.
3593 */
3594void pgmPoolFlushAll(PVM pVM)
3595{
3596 LogFlow(("pgmPoolFlushAll:\n"));
3597 pgmPoolFlushAllInt(pVM->pgm.s.CTXSUFF(pPool));
3598}
3599
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