VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllBth.h@ 8155

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

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 158.1 KB
Line 
1/* $Id: PGMAllBth.h 8155 2008-04-18 15:16:47Z vboxsync $ */
2/** @file
3 * VBox - Page Manager, Shadow+Guest Paging Template - All context code.
4 *
5 * This file is a big challenge!
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24/*******************************************************************************
25* Internal Functions *
26*******************************************************************************/
27__BEGIN_DECLS
28PGM_BTH_DECL(int, Trap0eHandler)(PVM pVM, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault);
29PGM_BTH_DECL(int, InvalidatePage)(PVM pVM, RTGCUINTPTR GCPtrPage);
30PGM_BTH_DECL(int, SyncPage)(PVM pVM, GSTPDE PdeSrc, RTGCUINTPTR GCPtrPage, unsigned cPages, unsigned uErr);
31PGM_BTH_DECL(int, CheckPageFault)(PVM pVM, uint32_t uErr, PSHWPDE pPdeDst, PGSTPDE pPdeSrc, RTGCUINTPTR GCPtrPage);
32PGM_BTH_DECL(int, SyncPT)(PVM pVM, unsigned iPD, PGSTPD pPDSrc, RTGCUINTPTR GCPtrPage);
33PGM_BTH_DECL(int, VerifyAccessSyncPage)(PVM pVM, RTGCUINTPTR Addr, unsigned fPage, unsigned uErr);
34PGM_BTH_DECL(int, PrefetchPage)(PVM pVM, RTGCUINTPTR GCPtrPage);
35PGM_BTH_DECL(int, SyncCR3)(PVM pVM, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal);
36#ifdef VBOX_STRICT
37PGM_BTH_DECL(unsigned, AssertCR3)(PVM pVM, uint64_t cr3, uint64_t cr4, RTGCUINTPTR GCPtr = 0, RTGCUINTPTR cb = ~(RTGCUINTPTR)0);
38#endif
39#ifdef PGMPOOL_WITH_USER_TRACKING
40DECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackDeref)(PVM pVM, PPGMPOOLPAGE pShwPage, RTHCPHYS HCPhys);
41#endif
42__END_DECLS
43
44
45/* Filter out some illegal combinations of guest and shadow paging, so we can remove redundant checks inside functions. */
46#if PGM_GST_TYPE == PGM_TYPE_PAE && PGM_SHW_TYPE != PGM_TYPE_PAE
47# error "Invalid combination; PAE guest implies PAE shadow"
48#endif
49
50#if (PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT) \
51 && !(PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_PAE)
52# error "Invalid combination; real or protected mode without paging implies 32 bits or PAE shadow paging."
53#endif
54
55#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE) \
56 && !(PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_PAE)
57# error "Invalid combination; 32 bits guest paging or PAE implies 32 bits or PAE shadow paging."
58#endif
59
60#if (PGM_GST_TYPE == PGM_TYPE_AMD64 && PGM_SHW_TYPE != PGM_TYPE_AMD64)
61 || (PGM_SHW_TYPE == PGM_TYPE_AMD64 && PGM_GST_TYPE != PGM_TYPE_AMD64)
62# error "Invalid combination; AMD64 guest implies AMD64 shadow and vice versa"
63#endif
64
65#ifdef IN_RING0 /* no mappings in VT-x and AMD-V mode */
66# define PGM_WITHOUT_MAPPINGS
67#endif
68
69/**
70 * #PF Handler for raw-mode guest execution.
71 *
72 * @returns VBox status code (appropriate for trap handling and GC return).
73 * @param pVM VM Handle.
74 * @param uErr The trap error code.
75 * @param pRegFrame Trap register frame.
76 * @param pvFault The fault address.
77 */
78PGM_BTH_DECL(int, Trap0eHandler)(PVM pVM, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
79{
80#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE) && PGM_SHW_TYPE != PGM_TYPE_AMD64
81
82# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE != PGM_TYPE_PAE
83 /*
84 * Hide the instruction fetch trap indicator for now.
85 */
86 /** @todo NXE will change this and we must fix NXE in the switcher too! */
87 if (uErr & X86_TRAP_PF_ID)
88 {
89 uErr &= ~X86_TRAP_PF_ID;
90 TRPMSetErrorCode(pVM, uErr);
91 }
92# endif
93
94 /*
95 * Get PDs.
96 */
97 int rc;
98# if PGM_WITH_PAGING(PGM_GST_TYPE)
99# if PGM_GST_TYPE == PGM_TYPE_32BIT
100 const unsigned iPDSrc = (RTGCUINTPTR)pvFault >> GST_PD_SHIFT;
101 PGSTPD pPDSrc = CTXSUFF(pVM->pgm.s.pGuestPD);
102# else /* PAE */
103 unsigned iPDSrc;
104 PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVM->pgm.s, (RTGCUINTPTR)pvFault, &iPDSrc);
105
106 /* Quick check for a valid guest trap. */
107 if (!pPDSrc)
108 {
109 LogFlow(("Trap0eHandler: guest PDPTR not present CR3=%VGp\n", (uint64_t)(CPUMGetGuestCR3(pVM) & X86_CR3_PAGE_MASK)));
110 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eGuestTrap; });
111 TRPMSetErrorCode(pVM, uErr);
112 return VINF_EM_RAW_GUEST_TRAP;
113 }
114# endif
115# else
116 PGSTPD pPDSrc = NULL;
117 const unsigned iPDSrc = 0;
118# endif
119
120 const unsigned iPDDst = (RTGCUINTPTR)pvFault >> SHW_PD_SHIFT;
121# if PGM_SHW_TYPE == PGM_TYPE_32BIT
122 PX86PD pPDDst = pVM->pgm.s.CTXMID(p,32BitPD);
123# elif PGM_SHW_TYPE == PGM_TYPE_PAE
124 PX86PDPAE pPDDst = pVM->pgm.s.CTXMID(ap,PaePDs)[0]; /* We treat this as a PD with 2048 entries. */
125
126# if PGM_GST_TYPE == PGM_TYPE_PAE
127 /* Did we mark the PDPT as not present in SyncCR3? */
128 unsigned iPDPTE = ((RTGCUINTPTR)pvFault >> SHW_PDPT_SHIFT) & SHW_PDPT_MASK;
129 if (!pVM->pgm.s.CTXMID(p,PaePDPT)->a[iPDPTE].n.u1Present)
130 {
131 pVM->pgm.s.CTXMID(p,PaePDPT)->a[iPDPTE].n.u1Present = 1;
132 }
133# endif
134# else
135 AssertFailed();
136# endif
137
138# if PGM_WITH_PAGING(PGM_GST_TYPE)
139# ifdef PGM_SYNC_DIRTY_BIT
140 /*
141 * If we successfully correct the write protection fault due to dirty bit
142 * tracking, or this page fault is a genuine one, then return immediately.
143 */
144 STAM_PROFILE_START(&pVM->pgm.s.StatCheckPageFault, e);
145 rc = PGM_BTH_NAME(CheckPageFault)(pVM, uErr, &pPDDst->a[iPDDst], &pPDSrc->a[iPDSrc], (RTGCUINTPTR)pvFault);
146 STAM_PROFILE_STOP(&pVM->pgm.s.StatCheckPageFault, e);
147 if ( rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT
148 || rc == VINF_EM_RAW_GUEST_TRAP)
149 {
150 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution)
151 = rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT ? &pVM->pgm.s.StatTrap0eDirtyAndAccessedBits : &pVM->pgm.s.StatTrap0eGuestTrap; });
152 LogBird(("Trap0eHandler: returns %s\n", rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT ? "VINF_SUCCESS" : "VINF_EM_RAW_GUEST_TRAP"));
153 return rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT ? VINF_SUCCESS : rc;
154 }
155# endif
156
157 STAM_COUNTER_INC(&pVM->pgm.s.StatGCTrap0ePD[iPDSrc]);
158# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
159
160 /*
161 * A common case is the not-present error caused by lazy page table syncing.
162 *
163 * It is IMPORTANT that we weed out any access to non-present shadow PDEs here
164 * so we can safely assume that the shadow PT is present when calling SyncPage later.
165 *
166 * On failure, we ASSUME that SyncPT is out of memory or detected some kind
167 * of mapping conflict and defer to SyncCR3 in R3.
168 * (Again, we do NOT support access handlers for non-present guest pages.)
169 *
170 */
171# if PGM_WITH_PAGING(PGM_GST_TYPE)
172 GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
173# else
174 GSTPDE PdeSrc;
175 PdeSrc.au32[0] = 0; /* faked so we don't have to #ifdef everything */
176 PdeSrc.n.u1Present = 1;
177 PdeSrc.n.u1Write = 1;
178 PdeSrc.n.u1Accessed = 1;
179 PdeSrc.n.u1User = 1;
180# endif
181 if ( !(uErr & X86_TRAP_PF_P) /* not set means page not present instead of page protection violation */
182 && !pPDDst->a[iPDDst].n.u1Present
183 && PdeSrc.n.u1Present
184 )
185
186 {
187 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eSyncPT; });
188 STAM_PROFILE_START(&pVM->pgm.s.StatLazySyncPT, f);
189 LogFlow(("=>SyncPT %04x = %08x\n", iPDSrc, PdeSrc.au32[0]));
190 rc = PGM_BTH_NAME(SyncPT)(pVM, iPDSrc, pPDSrc, (RTGCUINTPTR)pvFault);
191 if (VBOX_SUCCESS(rc))
192 {
193 STAM_PROFILE_STOP(&pVM->pgm.s.StatLazySyncPT, f);
194 return rc;
195 }
196 Log(("SyncPT: %d failed!! rc=%d\n", iPDSrc, rc));
197 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3); /** @todo no need to do global sync, right? */
198 STAM_PROFILE_STOP(&pVM->pgm.s.StatLazySyncPT, f);
199 return VINF_PGM_SYNC_CR3;
200 }
201
202# if PGM_WITH_PAGING(PGM_GST_TYPE)
203 /*
204 * Check if this address is within any of our mappings.
205 *
206 * This is *very* fast and it's gonna save us a bit of effort below and prevent
207 * us from screwing ourself with MMIO2 pages which have a GC Mapping (VRam).
208 * (BTW, it's impossible to have physical access handlers in a mapping.)
209 */
210 if (pgmMapAreMappingsEnabled(&pVM->pgm.s))
211 {
212 STAM_PROFILE_START(&pVM->pgm.s.StatMapping, a);
213 PPGMMAPPING pMapping = CTXALLSUFF(pVM->pgm.s.pMappings);
214 for ( ; pMapping; pMapping = CTXALLSUFF(pMapping->pNext))
215 {
216 if ((RTGCUINTPTR)pvFault < (RTGCUINTPTR)pMapping->GCPtr)
217 break;
218 if ((RTGCUINTPTR)pvFault - (RTGCUINTPTR)pMapping->GCPtr < pMapping->cb)
219 {
220 /*
221 * The first thing we check is if we've got an undetected conflict.
222 */
223 if (!pVM->pgm.s.fMappingsFixed)
224 {
225 unsigned iPT = pMapping->cb >> GST_PD_SHIFT;
226 while (iPT-- > 0)
227 if (pPDSrc->a[iPDSrc + iPT].n.u1Present)
228 {
229 STAM_COUNTER_INC(&pVM->pgm.s.StatGCTrap0eConflicts);
230 Log(("Trap0e: Detected Conflict %VGv-%VGv\n", pMapping->GCPtr, pMapping->GCPtrLast));
231 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3); /** @todo no need to do global sync,right? */
232 STAM_PROFILE_STOP(&pVM->pgm.s.StatMapping, a);
233 return VINF_PGM_SYNC_CR3;
234 }
235 }
236
237 /*
238 * Check if the fault address is in a virtual page access handler range.
239 */
240 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&CTXSUFF(pVM->pgm.s.pTrees)->HyperVirtHandlers, pvFault);
241 if ( pCur
242 && (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb
243 && uErr & X86_TRAP_PF_RW)
244 {
245# ifdef IN_GC
246 STAM_PROFILE_START(&pCur->Stat, h);
247 rc = CTXSUFF(pCur->pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->GCPtr, (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr);
248 STAM_PROFILE_STOP(&pCur->Stat, h);
249# else
250 AssertFailed();
251 rc = VINF_EM_RAW_EMULATE_INSTR; /* can't happen with VMX */
252# endif
253 STAM_COUNTER_INC(&pVM->pgm.s.StatTrap0eMapHandler);
254 STAM_PROFILE_STOP(&pVM->pgm.s.StatMapping, a);
255 return rc;
256 }
257
258 /*
259 * Pretend we're not here and let the guest handle the trap.
260 */
261 TRPMSetErrorCode(pVM, uErr & ~X86_TRAP_PF_P);
262 STAM_COUNTER_INC(&pVM->pgm.s.StatGCTrap0eMap);
263 LogFlow(("PGM: Mapping access -> route trap to recompiler!\n"));
264 STAM_PROFILE_STOP(&pVM->pgm.s.StatMapping, a);
265 return VINF_EM_RAW_GUEST_TRAP;
266 }
267 }
268 STAM_PROFILE_STOP(&pVM->pgm.s.StatMapping, a);
269 } /* pgmAreMappingsEnabled(&pVM->pgm.s) */
270# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
271
272 /*
273 * Check if this fault address is flagged for special treatment,
274 * which means we'll have to figure out the physical address and
275 * check flags associated with it.
276 *
277 * ASSUME that we can limit any special access handling to pages
278 * in page tables which the guest believes to be present.
279 */
280 if (PdeSrc.n.u1Present)
281 {
282 RTGCPHYS GCPhys = NIL_RTGCPHYS;
283
284# if PGM_WITH_PAGING(PGM_GST_TYPE)
285 uint32_t cr4 = CPUMGetGuestCR4(pVM);
286 if ( PdeSrc.b.u1Size
287 && (cr4 & X86_CR4_PSE))
288 GCPhys = (PdeSrc.u & GST_PDE_BIG_PG_MASK)
289 | ((RTGCPHYS)pvFault & (GST_BIG_PAGE_OFFSET_MASK ^ PAGE_OFFSET_MASK));
290 else
291 {
292 PGSTPT pPTSrc;
293 rc = PGM_GCPHYS_2_PTR(pVM, PdeSrc.u & GST_PDE_PG_MASK, &pPTSrc);
294 if (VBOX_SUCCESS(rc))
295 {
296 unsigned iPTESrc = ((RTGCUINTPTR)pvFault >> GST_PT_SHIFT) & GST_PT_MASK;
297 if (pPTSrc->a[iPTESrc].n.u1Present)
298 GCPhys = pPTSrc->a[iPTESrc].u & GST_PTE_PG_MASK;
299 }
300 }
301# else
302 /* No paging so the fault address is the physical address */
303 GCPhys = (RTGCPHYS)((RTGCUINTPTR)pvFault & ~PAGE_OFFSET_MASK);
304# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
305
306 /*
307 * If we have a GC address we'll check if it has any flags set.
308 */
309 if (GCPhys != NIL_RTGCPHYS)
310 {
311 STAM_PROFILE_START(&pVM->pgm.s.StatHandlers, b);
312
313 PPGMPAGE pPage;
314 rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhys, &pPage);
315 if (VBOX_SUCCESS(rc))
316 {
317 if (PGM_PAGE_HAS_ANY_HANDLERS(pPage))
318 {
319 if (PGM_PAGE_HAS_ANY_PHYSICAL_HANDLERS(pPage))
320 {
321 /*
322 * Physical page access handler.
323 */
324 const RTGCPHYS GCPhysFault = GCPhys | ((RTGCUINTPTR)pvFault & PAGE_OFFSET_MASK);
325 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&CTXSUFF(pVM->pgm.s.pTrees)->PhysHandlers, GCPhysFault);
326 if (pCur)
327 {
328# ifdef PGM_SYNC_N_PAGES
329 /*
330 * If the region is write protected and we got a page not present fault, then sync
331 * the pages. If the fault was caused by a read, then restart the instruction.
332 * In case of write access continue to the GC write handler.
333 *
334 * ASSUMES that there is only one handler per page or that they have similar write properties.
335 */
336 if ( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE
337 && !(uErr & X86_TRAP_PF_P))
338 {
339 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, PGM_SYNC_NR_PAGES, uErr);
340 if ( VBOX_FAILURE(rc)
341 || !(uErr & X86_TRAP_PF_RW)
342 || rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE)
343 {
344 AssertRC(rc);
345 STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersOutOfSync);
346 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
347 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSyncHndPhys; });
348 return rc;
349 }
350 }
351# endif
352
353 AssertMsg( pCur->enmType != PGMPHYSHANDLERTYPE_PHYSICAL_WRITE
354 || (pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE && (uErr & X86_TRAP_PF_RW)),
355 ("Unexpected trap for physical handler: %08X (phys=%08x) HCPhys=%X uErr=%X, enum=%d\n", pvFault, GCPhys, pPage->HCPhys, uErr, pCur->enmType));
356
357#if defined(IN_GC) || defined(IN_RING0)
358 if (CTXALLSUFF(pCur->pfnHandler))
359 {
360 STAM_PROFILE_START(&pCur->Stat, h);
361 rc = pCur->CTXALLSUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, GCPhysFault, CTXALLSUFF(pCur->pvUser));
362 STAM_PROFILE_STOP(&pCur->Stat, h);
363 }
364 else
365#endif
366 rc = VINF_EM_RAW_EMULATE_INSTR;
367 STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersPhysical);
368 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
369 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndPhys; });
370 return rc;
371 }
372 }
373# if PGM_WITH_PAGING(PGM_GST_TYPE)
374 else
375 {
376# ifdef PGM_SYNC_N_PAGES
377 /*
378 * If the region is write protected and we got a page not present fault, then sync
379 * the pages. If the fault was caused by a read, then restart the instruction.
380 * In case of write access continue to the GC write handler.
381 */
382 if ( PGM_PAGE_GET_HNDL_VIRT_STATE(pPage) < PGM_PAGE_HNDL_PHYS_STATE_ALL
383 && !(uErr & X86_TRAP_PF_P))
384 {
385 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, PGM_SYNC_NR_PAGES, uErr);
386 if ( VBOX_FAILURE(rc)
387 || rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE
388 || !(uErr & X86_TRAP_PF_RW))
389 {
390 AssertRC(rc);
391 STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersOutOfSync);
392 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
393 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSyncHndVirt; });
394 return rc;
395 }
396 }
397# endif
398 /*
399 * Ok, it's an virtual page access handler.
400 *
401 * Since it's faster to search by address, we'll do that first
402 * and then retry by GCPhys if that fails.
403 */
404 /** @todo r=bird: perhaps we should consider looking up by physical address directly now? */
405 /** @note r=svl: true, but lookup on virtual address should remain as a fallback as phys & virt trees might be out of sync, because the
406 * page was changed without us noticing it (not-present -> present without invlpg or mov cr3, xxx)
407 */
408 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&CTXSUFF(pVM->pgm.s.pTrees)->VirtHandlers, pvFault);
409 if (pCur)
410 {
411 AssertMsg(!((RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb)
412 || ( pCur->enmType != PGMVIRTHANDLERTYPE_WRITE
413 || !(uErr & X86_TRAP_PF_P)
414 || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
415 ("Unexpected trap for virtual handler: %VGv (phys=%VGp) HCPhys=%HGp uErr=%X, enum=%d\n", pvFault, GCPhys, pPage->HCPhys, uErr, pCur->enmType));
416
417 if ( (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb
418 && ( uErr & X86_TRAP_PF_RW
419 || pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
420 {
421# ifdef IN_GC
422 STAM_PROFILE_START(&pCur->Stat, h);
423 rc = CTXSUFF(pCur->pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->GCPtr, (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr);
424 STAM_PROFILE_STOP(&pCur->Stat, h);
425# else
426 rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
427# endif
428 STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersVirtual);
429 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
430 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndVirt; });
431 return rc;
432 }
433 /* Unhandled part of a monitored page */
434 }
435 else
436 {
437 /* Check by physical address. */
438 PPGMVIRTHANDLER pCur;
439 unsigned iPage;
440 rc = pgmHandlerVirtualFindByPhysAddr(pVM, GCPhys + ((RTGCUINTPTR)pvFault & PAGE_OFFSET_MASK),
441 &pCur, &iPage);
442 Assert(VBOX_SUCCESS(rc) || !pCur);
443 if ( pCur
444 && ( uErr & X86_TRAP_PF_RW
445 || pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
446 {
447 Assert((pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) == GCPhys);
448# ifdef IN_GC
449 RTGCUINTPTR off = (iPage << PAGE_SHIFT) + ((RTGCUINTPTR)pvFault & PAGE_OFFSET_MASK) - ((RTGCUINTPTR)pCur->GCPtr & PAGE_OFFSET_MASK);
450 Assert(off < pCur->cb);
451 STAM_PROFILE_START(&pCur->Stat, h);
452 rc = CTXSUFF(pCur->pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->GCPtr, off);
453 STAM_PROFILE_STOP(&pCur->Stat, h);
454# else
455 rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
456# endif
457 STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersVirtualByPhys);
458 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
459 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndVirt; });
460 return rc;
461 }
462 }
463 }
464# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
465
466 /*
467 * There is a handled area of the page, but this fault doesn't belong to it.
468 * We must emulate the instruction.
469 *
470 * To avoid crashing (non-fatal) in the interpreter and go back to the recompiler
471 * we first check if this was a page-not-present fault for a page with only
472 * write access handlers. Restart the instruction if it wasn't a write access.
473 */
474 STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersUnhandled);
475
476 if ( !PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)
477 && !(uErr & X86_TRAP_PF_P))
478 {
479 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, PGM_SYNC_NR_PAGES, uErr);
480 if ( VBOX_FAILURE(rc)
481 || rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE
482 || !(uErr & X86_TRAP_PF_RW))
483 {
484 AssertRC(rc);
485 STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersOutOfSync);
486 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
487 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSyncHndPhys; });
488 return rc;
489 }
490 }
491
492 /** @todo This particular case can cause quite a lot of overhead. E.g. early stage of kernel booting in Ubuntu 6.06
493 * It's writing to an unhandled part of the LDT page several million times.
494 */
495 rc = PGMInterpretInstruction(pVM, pRegFrame, pvFault);
496 LogFlow(("PGM: PGMInterpretInstruction -> rc=%d HCPhys=%RHp%s%s\n",
497 rc, pPage->HCPhys,
498 PGM_PAGE_HAS_ANY_PHYSICAL_HANDLERS(pPage) ? " phys" : "",
499 PGM_PAGE_HAS_ANY_VIRTUAL_HANDLERS(pPage) ? " virt" : ""));
500 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
501 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndUnhandled; });
502 return rc;
503 } /* if any kind of handler */
504
505# if PGM_WITH_PAGING(PGM_GST_TYPE)
506 if (uErr & X86_TRAP_PF_P)
507 {
508 /*
509 * The page isn't marked, but it might still be monitored by a virtual page access handler.
510 * (ASSUMES no temporary disabling of virtual handlers.)
511 */
512 /** @todo r=bird: Since the purpose is to catch out of sync pages with virtual handler(s) here,
513 * we should correct both the shadow page table and physical memory flags, and not only check for
514 * accesses within the handler region but for access to pages with virtual handlers. */
515 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&CTXSUFF(pVM->pgm.s.pTrees)->VirtHandlers, pvFault);
516 if (pCur)
517 {
518 AssertMsg( !((RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb)
519 || ( pCur->enmType != PGMVIRTHANDLERTYPE_WRITE
520 || !(uErr & X86_TRAP_PF_P)
521 || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
522 ("Unexpected trap for virtual handler: %08X (phys=%08x) HCPhys=%X uErr=%X, enum=%d\n", pvFault, GCPhys, pPage->HCPhys, uErr, pCur->enmType));
523
524 if ( (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr < pCur->cb
525 && ( uErr & X86_TRAP_PF_RW
526 || pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
527 {
528# ifdef IN_GC
529 STAM_PROFILE_START(&pCur->Stat, h);
530 rc = CTXSUFF(pCur->pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->GCPtr, (RTGCUINTPTR)pvFault - (RTGCUINTPTR)pCur->GCPtr);
531 STAM_PROFILE_STOP(&pCur->Stat, h);
532# else
533 rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
534# endif
535 STAM_COUNTER_INC(&pVM->pgm.s.StatHandlersVirtualUnmarked);
536 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
537 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eHndVirt; });
538 return rc;
539 }
540 }
541 }
542# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
543 }
544 STAM_PROFILE_STOP(&pVM->pgm.s.StatHandlers, b);
545
546# ifdef PGM_OUT_OF_SYNC_IN_GC
547 /*
548 * We are here only if page is present in Guest page tables and trap is not handled
549 * by our handlers.
550 * Check it for page out-of-sync situation.
551 */
552 STAM_PROFILE_START(&pVM->pgm.s.StatOutOfSync, c);
553
554 if (!(uErr & X86_TRAP_PF_P))
555 {
556 /*
557 * Page is not present in our page tables.
558 * Try to sync it!
559 * BTW, fPageShw is invalid in this branch!
560 */
561 if (uErr & X86_TRAP_PF_US)
562 STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncUser);
563 else /* supervisor */
564 STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncSupervisor);
565
566# if defined(LOG_ENABLED) && !defined(IN_RING0)
567 RTGCPHYS GCPhys;
568 uint64_t fPageGst;
569 PGMGstGetPage(pVM, pvFault, &fPageGst, &GCPhys);
570 Log(("Page out of sync: %p eip=%08x PdeSrc.n.u1User=%d fPageGst=%08llx GCPhys=%VGp scan=%d\n",
571 pvFault, pRegFrame->eip, PdeSrc.n.u1User, fPageGst, GCPhys, CSAMDoesPageNeedScanning(pVM, (RTGCPTR)pRegFrame->eip)));
572# endif /* LOG_ENABLED */
573
574# if PGM_WITH_PAGING(PGM_GST_TYPE) && !defined(IN_RING0)
575 if (CPUMGetGuestCPL(pVM, pRegFrame) == 0)
576 {
577 uint64_t fPageGst;
578 rc = PGMGstGetPage(pVM, pvFault, &fPageGst, NULL);
579 if ( VBOX_SUCCESS(rc)
580 && !(fPageGst & X86_PTE_US))
581 {
582 /* Note: can't check for X86_TRAP_ID bit, because that requires execute disable support on the CPU */
583 if ( pvFault == (RTGCPTR)pRegFrame->eip
584 || (RTGCUINTPTR)pvFault - pRegFrame->eip < 8 /* instruction crossing a page boundary */
585# ifdef CSAM_DETECT_NEW_CODE_PAGES
586 || ( !PATMIsPatchGCAddr(pVM, (RTGCPTR)pRegFrame->eip)
587 && CSAMDoesPageNeedScanning(pVM, (RTGCPTR)pRegFrame->eip)) /* any new code we encounter here */
588# endif /* CSAM_DETECT_NEW_CODE_PAGES */
589 )
590 {
591 LogFlow(("CSAMExecFault %VGv\n", pRegFrame->eip));
592 rc = CSAMExecFault(pVM, (RTGCPTR)pRegFrame->eip);
593 if (rc != VINF_SUCCESS)
594 {
595 /*
596 * CSAM needs to perform a job in ring 3.
597 *
598 * Sync the page before going to the host context; otherwise we'll end up in a loop if
599 * CSAM fails (e.g. instruction crosses a page boundary and the next page is not present)
600 */
601 LogFlow(("CSAM ring 3 job\n"));
602 int rc2 = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, 1, uErr);
603 AssertRC(rc2);
604
605 STAM_PROFILE_STOP(&pVM->pgm.s.StatOutOfSync, c);
606 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eCSAM; });
607 return rc;
608 }
609 }
610# ifdef CSAM_DETECT_NEW_CODE_PAGES
611 else
612 if ( uErr == X86_TRAP_PF_RW
613 && pRegFrame->ecx >= 0x100 /* early check for movswd count */
614 && pRegFrame->ecx < 0x10000
615 )
616 {
617 /* In case of a write to a non-present supervisor shadow page, we'll take special precautions
618 * to detect loading of new code pages.
619 */
620
621 /*
622 * Decode the instruction.
623 */
624 RTGCPTR PC;
625 rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
626 if (rc == VINF_SUCCESS)
627 {
628 DISCPUSTATE Cpu;
629 uint32_t cbOp;
630 rc = EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
631
632 /* For now we'll restrict this to rep movsw/d instructions */
633 if ( rc == VINF_SUCCESS
634 && Cpu.pCurInstr->opcode == OP_MOVSWD
635 && (Cpu.prefix & PREFIX_REP))
636 {
637 CSAMMarkPossibleCodePage(pVM, pvFault);
638 }
639 }
640 }
641# endif /* CSAM_DETECT_NEW_CODE_PAGES */
642
643 /*
644 * Mark this page as safe.
645 */
646 /** @todo not correct for pages that contain both code and data!! */
647 Log2(("CSAMMarkPage %p; scanned=%d\n", pvFault, true));
648 CSAMMarkPage(pVM, pvFault, true);
649 }
650 }
651# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) && !defined(IN_RING0) */
652 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, PGM_SYNC_NR_PAGES, uErr);
653 if (VBOX_SUCCESS(rc))
654 {
655 /* The page was successfully synced, return to the guest. */
656 STAM_PROFILE_STOP(&pVM->pgm.s.StatOutOfSync, c);
657 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSync; });
658 return VINF_SUCCESS;
659 }
660 }
661 else
662 {
663 /*
664 * A side effect of not flushing global PDEs are out of sync pages due
665 * to physical monitored regions, that are no longer valid.
666 * Assume for now it only applies to the read/write flag
667 */
668 if (VBOX_SUCCESS(rc) && (uErr & X86_TRAP_PF_RW))
669 {
670 if (uErr & X86_TRAP_PF_US)
671 STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncUser);
672 else /* supervisor */
673 STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncSupervisor);
674
675
676 /*
677 * Note: Do NOT use PGM_SYNC_NR_PAGES here. That only works if the page is not present, which is not true in this case.
678 */
679 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)pvFault, 1, uErr);
680 if (VBOX_SUCCESS(rc))
681 {
682 /*
683 * Page was successfully synced, return to guest.
684 */
685# ifdef VBOX_STRICT
686 RTGCPHYS GCPhys;
687 uint64_t fPageGst;
688 rc = PGMGstGetPage(pVM, pvFault, &fPageGst, &GCPhys);
689 Assert(VBOX_SUCCESS(rc) && fPageGst & X86_PTE_RW);
690 LogFlow(("Obsolete physical monitor page out of sync %VGv - phys %VGp flags=%08llx\n", pvFault, GCPhys, (uint64_t)fPageGst));
691
692 uint64_t fPageShw;
693 rc = PGMShwGetPage(pVM, pvFault, &fPageShw, NULL);
694 Assert(VBOX_SUCCESS(rc) && fPageShw & X86_PTE_RW);
695# endif /* VBOX_STRICT */
696 STAM_PROFILE_STOP(&pVM->pgm.s.StatOutOfSync, c);
697 STAM_STATS({ pVM->pgm.s.CTXSUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatTrap0eOutOfSyncObsHnd; });
698 return VINF_SUCCESS;
699 }
700
701 /* Check to see if we need to emulate the instruction as X86_CR0_WP has been cleared. */
702 if ( CPUMGetGuestCPL(pVM, pRegFrame) == 0
703 && ((CPUMGetGuestCR0(pVM) & (X86_CR0_WP|X86_CR0_PG)) == X86_CR0_PG)
704 && (uErr & (X86_TRAP_PF_RW | X86_TRAP_PF_P)) == (X86_TRAP_PF_RW | X86_TRAP_PF_P))
705 {
706 uint64_t fPageGst;
707 rc = PGMGstGetPage(pVM, pvFault, &fPageGst, NULL);
708 if ( VBOX_SUCCESS(rc)
709 && !(fPageGst & X86_PTE_RW))
710 {
711 rc = PGMInterpretInstruction(pVM, pRegFrame, pvFault);
712 if (VBOX_SUCCESS(rc))
713 STAM_COUNTER_INC(&pVM->pgm.s.StatTrap0eWPEmulGC);
714 else
715 STAM_COUNTER_INC(&pVM->pgm.s.StatTrap0eWPEmulR3);
716 return rc;
717 }
718 else
719 AssertMsgFailed(("Unexpected r/w page %x flag=%x\n", pvFault, (uint32_t)fPageGst));
720 }
721
722 }
723
724# if PGM_WITH_PAGING(PGM_GST_TYPE)
725# ifdef VBOX_STRICT
726 /*
727 * Check for VMM page flags vs. Guest page flags consistency.
728 * Currently only for debug purposes.
729 */
730 if (VBOX_SUCCESS(rc))
731 {
732 /* Get guest page flags. */
733 uint64_t fPageGst;
734 rc = PGMGstGetPage(pVM, pvFault, &fPageGst, NULL);
735 if (VBOX_SUCCESS(rc))
736 {
737 uint64_t fPageShw;
738 rc = PGMShwGetPage(pVM, pvFault, &fPageShw, NULL);
739
740 /*
741 * Compare page flags.
742 * Note: we have AVL, A, D bits desynched.
743 */
744 AssertMsg((fPageShw & ~(X86_PTE_A | X86_PTE_D | X86_PTE_AVL_MASK)) == (fPageGst & ~(X86_PTE_A | X86_PTE_D | X86_PTE_AVL_MASK)),
745 ("Page flags mismatch! pvFault=%p GCPhys=%VGp fPageShw=%08llx fPageGst=%08llx\n", pvFault, GCPhys, fPageShw, fPageGst));
746 }
747 else
748 AssertMsgFailed(("PGMGstGetPage rc=%Vrc\n", rc));
749 }
750 else
751 AssertMsgFailed(("PGMGCGetPage rc=%Vrc\n", rc));
752# endif /* VBOX_STRICT */
753# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
754 }
755 STAM_PROFILE_STOP(&pVM->pgm.s.StatOutOfSync, c);
756# endif /* PGM_OUT_OF_SYNC_IN_GC */
757 }
758 else
759 {
760 /*
761 * Page not present in Guest OS or invalid page table address.
762 * This is potential virtual page access handler food.
763 *
764 * For the present we'll say that our access handlers don't
765 * work for this case - we've already discarded the page table
766 * not present case which is identical to this.
767 *
768 * When we perchance find we need this, we will probably have AVL
769 * trees (offset based) to operate on and we can measure their speed
770 * agains mapping a page table and probably rearrange this handling
771 * a bit. (Like, searching virtual ranges before checking the
772 * physical address.)
773 */
774 }
775 }
776
777
778# if PGM_WITH_PAGING(PGM_GST_TYPE)
779 /*
780 * Conclusion, this is a guest trap.
781 */
782 LogFlow(("PGM: Unhandled #PF -> route trap to recompiler!\n"));
783 STAM_COUNTER_INC(&pVM->pgm.s.StatGCTrap0eUnhandled);
784 return VINF_EM_RAW_GUEST_TRAP;
785# else
786 /* present, but not a monitored page; perhaps the guest is probing physical memory */
787 return VINF_EM_RAW_EMULATE_INSTR;
788# endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
789
790
791#else /* PGM_GST_TYPE != PGM_TYPE_32BIT */
792
793 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
794 return VERR_INTERNAL_ERROR;
795#endif /* PGM_GST_TYPE != PGM_TYPE_32BIT */
796}
797
798
799/**
800 * Emulation of the invlpg instruction.
801 *
802 *
803 * @returns VBox status code.
804 *
805 * @param pVM VM handle.
806 * @param GCPtrPage Page to invalidate.
807 *
808 * @remark ASSUMES that the guest is updating before invalidating. This order
809 * isn't required by the CPU, so this is speculative and could cause
810 * trouble.
811 *
812 * @todo Flush page or page directory only if necessary!
813 * @todo Add a #define for simply invalidating the page.
814 */
815PGM_BTH_DECL(int, InvalidatePage)(PVM pVM, RTGCUINTPTR GCPtrPage)
816{
817#if PGM_GST_TYPE == PGM_TYPE_32BIT \
818 || PGM_GST_TYPE == PGM_TYPE_PAE
819
820 LogFlow(("InvalidatePage %x\n", GCPtrPage));
821 /*
822 * Get the shadow PD entry and skip out if this PD isn't present.
823 * (Guessing that it is frequent for a shadow PDE to not be present, do this first.)
824 */
825 const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT;
826# if PGM_SHW_TYPE == PGM_TYPE_32BIT
827 PX86PDE pPdeDst = &pVM->pgm.s.CTXMID(p,32BitPD)->a[iPDDst];
828# else
829 PX86PDEPAE pPdeDst = &pVM->pgm.s.CTXMID(ap,PaePDs[0])->a[iPDDst];
830# endif
831 const SHWPDE PdeDst = *pPdeDst;
832 if (!PdeDst.n.u1Present)
833 {
834 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePageSkipped));
835 return VINF_SUCCESS;
836 }
837
838 /*
839 * Get the guest PD entry and calc big page.
840 */
841# if PGM_GST_TYPE == PGM_TYPE_32BIT
842 PX86PD pPDSrc = CTXSUFF(pVM->pgm.s.pGuestPD);
843 const unsigned iPDSrc = GCPtrPage >> GST_PD_SHIFT;
844 GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
845# else /* PAE */
846 unsigned iPDSrc;
847 PX86PDPAE pPDSrc = pgmGstGetPaePDPtr(&pVM->pgm.s, GCPtrPage, &iPDSrc);
848 GSTPDE PdeSrc;
849
850 if (pPDSrc)
851 PdeSrc = pPDSrc->a[iPDSrc];
852 else
853 PdeSrc.u = 0;
854# endif
855
856 const uint32_t cr4 = CPUMGetGuestCR4(pVM);
857 const bool fIsBigPage = PdeSrc.b.u1Size && (cr4 & X86_CR4_PSE);
858
859# ifdef IN_RING3
860 /*
861 * If a CR3 Sync is pending we may ignore the invalidate page operation
862 * depending on the kind of sync and if it's a global page or not.
863 * This doesn't make sense in GC/R0 so we'll skip it entirely there.
864 */
865# ifdef PGM_SKIP_GLOBAL_PAGEDIRS_ON_NONGLOBAL_FLUSH
866 if ( VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3)
867 || ( VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL)
868 && fIsBigPage
869 && PdeSrc.b.u1Global
870 && (cr4 & X86_CR4_PGE)
871 )
872 )
873# else
874 if (VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL) )
875# endif
876 {
877 STAM_COUNTER_INC(&pVM->pgm.s.StatHCInvalidatePageSkipped);
878 return VINF_SUCCESS;
879 }
880# endif /* IN_RING3 */
881
882
883 /*
884 * Deal with the Guest PDE.
885 */
886 int rc = VINF_SUCCESS;
887 if (PdeSrc.n.u1Present)
888 {
889 if (PdeDst.u & PGM_PDFLAGS_MAPPING)
890 {
891 /*
892 * Conflict - Let SyncPT deal with it to avoid duplicate code.
893 */
894 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
895 Assert(PGMGetGuestMode(pVM) <= PGMMODE_32_BIT);
896 rc = PGM_BTH_NAME(SyncPT)(pVM, iPDSrc, pPDSrc, GCPtrPage);
897 }
898 else if ( PdeSrc.n.u1User != PdeDst.n.u1User
899 || (!PdeSrc.n.u1Write && PdeDst.n.u1Write))
900 {
901 /*
902 * Mark not present so we can resync the PDE when it's used.
903 */
904 LogFlow(("InvalidatePage: Out-of-sync at %VGp PdeSrc=%RX64 PdeDst=%RX64\n",
905 GCPtrPage, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
906 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
907 pPdeDst->u = 0;
908 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDOutOfSync));
909 PGM_INVL_GUEST_TLBS();
910 }
911# ifdef PGM_SYNC_ACCESSED_BIT
912 else if (!PdeSrc.n.u1Accessed)
913 {
914 /*
915 * Mark not present so we can set the accessed bit.
916 */
917 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
918 pPdeDst->u = 0;
919 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDNAs));
920 PGM_INVL_GUEST_TLBS();
921 }
922# endif
923 else if (!fIsBigPage)
924 {
925 /*
926 * 4KB - page.
927 */
928 PPGMPOOLPAGE pShwPage = pgmPoolGetPageByHCPhys(pVM, PdeDst.u & SHW_PDE_PG_MASK);
929 RTGCPHYS GCPhys = PdeSrc.u & GST_PDE_PG_MASK;
930# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
931 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
932 GCPhys |= (iPDDst & 1) * (PAGE_SIZE/2);
933# endif
934 if (pShwPage->GCPhys == GCPhys)
935 {
936# if 0 /* likely cause of a major performance regression; must be SyncPageWorkerTrackDeref then */
937 const unsigned iPTEDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
938 PSHWPT pPT = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
939 if (pPT->a[iPTEDst].n.u1Present)
940 {
941# ifdef PGMPOOL_WITH_USER_TRACKING
942 /* This is very unlikely with caching/monitoring enabled. */
943 PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVM, pShwPage, pPT->a[iPTEDst].u & SHW_PTE_PG_MASK);
944# endif
945 pPT->a[iPTEDst].u = 0;
946 }
947# else /* Syncing it here isn't 100% safe and it's probably not worth spending time syncing it. */
948 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, GCPtrPage, 1, 0);
949 if (VBOX_SUCCESS(rc))
950 rc = VINF_SUCCESS;
951# endif
952 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePage4KBPages));
953 PGM_INVL_PG(GCPtrPage);
954 }
955 else
956 {
957 /*
958 * The page table address changed.
959 */
960 LogFlow(("InvalidatePage: Out-of-sync at %VGp PdeSrc=%RX64 PdeDst=%RX64 ShwGCPhys=%VGp iPDDst=%#x\n",
961 GCPtrPage, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u, pShwPage->GCPhys, iPDDst));
962 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
963 pPdeDst->u = 0;
964 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDOutOfSync));
965 PGM_INVL_GUEST_TLBS();
966 }
967 }
968 else
969 {
970 /*
971 * 2/4MB - page.
972 */
973 /* Before freeing the page, check if anything really changed. */
974 PPGMPOOLPAGE pShwPage = pgmPoolGetPageByHCPhys(pVM, PdeDst.u & SHW_PDE_PG_MASK);
975 RTGCPHYS GCPhys = PdeSrc.u & GST_PDE_BIG_PG_MASK;
976# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
977 /* Select the right PDE as we're emulating a 4MB page directory with two 2 MB shadow PDEs.*/
978 GCPhys |= GCPtrPage & (1 << X86_PD_PAE_SHIFT);
979# endif
980 if ( pShwPage->GCPhys == GCPhys
981 && pShwPage->enmKind == BTH_PGMPOOLKIND_PT_FOR_BIG)
982 {
983 /* ASSUMES a the given bits are identical for 4M and normal PDEs */
984 /** @todo PAT */
985# ifdef PGM_SYNC_DIRTY_BIT
986 if ( (PdeSrc.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD))
987 == (PdeDst.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD))
988 && ( PdeSrc.b.u1Dirty /** @todo rainy day: What about read-only 4M pages? not very common, but still... */
989 || (PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY)))
990# else
991 if ( (PdeSrc.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD))
992 == (PdeDst.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD)))
993# endif
994 {
995 LogFlow(("Skipping flush for big page containing %VGv (PD=%X .u=%VX64)-> nothing has changed!\n", GCPtrPage, iPDSrc, PdeSrc.u));
996 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePage4MBPagesSkip));
997 return VINF_SUCCESS;
998 }
999 }
1000
1001 /*
1002 * Ok, the page table is present and it's been changed in the guest.
1003 * If we're in host context, we'll just mark it as not present taking the lazy approach.
1004 * We could do this for some flushes in GC too, but we need an algorithm for
1005 * deciding which 4MB pages containing code likely to be executed very soon.
1006 */
1007 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
1008 pPdeDst->u = 0;
1009 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePage4MBPages));
1010 PGM_INVL_BIG_PG(GCPtrPage);
1011 }
1012 }
1013 else
1014 {
1015 /*
1016 * Page directory is not present, mark shadow PDE not present.
1017 */
1018 if (!(PdeDst.u & PGM_PDFLAGS_MAPPING))
1019 {
1020 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
1021 pPdeDst->u = 0;
1022 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDNPs));
1023 PGM_INVL_PG(GCPtrPage);
1024 }
1025 else
1026 {
1027 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
1028 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,InvalidatePagePDMappings));
1029 }
1030 }
1031
1032 return rc;
1033
1034#elif PGM_GST_TYPE == PGM_TYPE_AMD64
1035//# error not implemented
1036 return VERR_INTERNAL_ERROR;
1037
1038#else /* guest real and protected mode */
1039 /* There's no such thing as InvalidatePage when paging is disabled, so just ignore. */
1040 return VINF_SUCCESS;
1041#endif
1042}
1043
1044
1045#ifdef PGMPOOL_WITH_USER_TRACKING
1046/**
1047 * Update the tracking of shadowed pages.
1048 *
1049 * @param pVM The VM handle.
1050 * @param pShwPage The shadow page.
1051 * @param HCPhys The physical page we is being dereferenced.
1052 */
1053DECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackDeref)(PVM pVM, PPGMPOOLPAGE pShwPage, RTHCPHYS HCPhys)
1054{
1055# ifdef PGMPOOL_WITH_GCPHYS_TRACKING
1056 STAM_PROFILE_START(&pVM->pgm.s.StatTrackDeref, a);
1057 LogFlow(("SyncPageWorkerTrackDeref: Damn HCPhys=%VHp pShwPage->idx=%#x!!!\n", HCPhys, pShwPage->idx));
1058
1059 /** @todo If this turns out to be a bottle neck (*very* likely) two things can be done:
1060 * 1. have a medium sized HCPhys -> GCPhys TLB (hash?)
1061 * 2. write protect all shadowed pages. I.e. implement caching.
1062 */
1063 /*
1064 * Find the guest address.
1065 */
1066 for (PPGMRAMRANGE pRam = CTXALLSUFF(pVM->pgm.s.pRamRanges);
1067 pRam;
1068 pRam = CTXALLSUFF(pRam->pNext))
1069 {
1070 unsigned iPage = pRam->cb >> PAGE_SHIFT;
1071 while (iPage-- > 0)
1072 {
1073 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
1074 {
1075 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
1076 pgmTrackDerefGCPhys(pPool, pShwPage, &pRam->aPages[iPage]);
1077 pShwPage->cPresent--;
1078 pPool->cPresent--;
1079 STAM_PROFILE_STOP(&pVM->pgm.s.StatTrackDeref, a);
1080 return;
1081 }
1082 }
1083 }
1084
1085 for (;;)
1086 AssertReleaseMsgFailed(("HCPhys=%VHp wasn't found!\n", HCPhys));
1087# else /* !PGMPOOL_WITH_GCPHYS_TRACKING */
1088 pShwPage->cPresent--;
1089 pVM->pgm.s.CTXSUFF(pPool)->cPresent--;
1090# endif /* !PGMPOOL_WITH_GCPHYS_TRACKING */
1091}
1092
1093
1094/**
1095 * Update the tracking of shadowed pages.
1096 *
1097 * @param pVM The VM handle.
1098 * @param pShwPage The shadow page.
1099 * @param u16 The top 16-bit of the pPage->HCPhys.
1100 * @param pPage Pointer to the guest page. this will be modified.
1101 * @param iPTDst The index into the shadow table.
1102 */
1103DECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackAddref)(PVM pVM, PPGMPOOLPAGE pShwPage, uint16_t u16, PPGMPAGE pPage, const unsigned iPTDst)
1104{
1105# ifdef PGMPOOL_WITH_GCPHYS_TRACKING
1106 /*
1107 * We're making certain assumptions about the placement of cRef and idx.
1108 */
1109 Assert(MM_RAM_FLAGS_IDX_SHIFT == 48);
1110 Assert(MM_RAM_FLAGS_CREFS_SHIFT > MM_RAM_FLAGS_IDX_SHIFT);
1111
1112 /*
1113 * Just deal with the simple first time here.
1114 */
1115 if (!u16)
1116 {
1117 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackVirgin);
1118 u16 = (1 << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT)) | pShwPage->idx;
1119 }
1120 else
1121 u16 = pgmPoolTrackPhysExtAddref(pVM, u16, pShwPage->idx);
1122
1123 /* write back, trying to be clever... */
1124 Log2(("SyncPageWorkerTrackAddRef: u16=%#x pPage->HCPhys=%VHp->%VHp iPTDst=%#x\n",
1125 u16, pPage->HCPhys, (pPage->HCPhys & MM_RAM_FLAGS_NO_REFS_MASK) | ((uint64_t)u16 << MM_RAM_FLAGS_CREFS_SHIFT), iPTDst));
1126 *((uint16_t *)&pPage->HCPhys + 3) = u16; /** @todo PAGE FLAGS */
1127# endif /* PGMPOOL_WITH_GCPHYS_TRACKING */
1128
1129 /* update statistics. */
1130 pVM->pgm.s.CTXSUFF(pPool)->cPresent++;
1131 pShwPage->cPresent++;
1132 if (pShwPage->iFirstPresent > iPTDst)
1133 pShwPage->iFirstPresent = iPTDst;
1134}
1135#endif /* PGMPOOL_WITH_USER_TRACKING */
1136
1137
1138/**
1139 * Creates a 4K shadow page for a guest page.
1140 *
1141 * For 4M pages the caller must convert the PDE4M to a PTE, this includes adjusting the
1142 * physical address. The PdeSrc argument only the flags are used. No page structured
1143 * will be mapped in this function.
1144 *
1145 * @param pVM VM handle.
1146 * @param pPteDst Destination page table entry.
1147 * @param PdeSrc Source page directory entry (i.e. Guest OS page directory entry).
1148 * Can safely assume that only the flags are being used.
1149 * @param PteSrc Source page table entry (i.e. Guest OS page table entry).
1150 * @param pShwPage Pointer to the shadow page.
1151 * @param iPTDst The index into the shadow table.
1152 *
1153 * @remark Not used for 2/4MB pages!
1154 */
1155DECLINLINE(void) PGM_BTH_NAME(SyncPageWorker)(PVM pVM, PSHWPTE pPteDst, GSTPDE PdeSrc, GSTPTE PteSrc, PPGMPOOLPAGE pShwPage, unsigned iPTDst)
1156{
1157 if (PteSrc.n.u1Present)
1158 {
1159 /*
1160 * Find the ram range.
1161 */
1162 PPGMPAGE pPage;
1163 int rc = pgmPhysGetPageEx(&pVM->pgm.s, PteSrc.u & GST_PTE_PG_MASK, &pPage);
1164 if (VBOX_SUCCESS(rc))
1165 {
1166 /** @todo investiage PWT, PCD and PAT. */
1167 /*
1168 * Make page table entry.
1169 */
1170 const RTHCPHYS HCPhys = pPage->HCPhys; /** @todo FLAGS */
1171 SHWPTE PteDst;
1172 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
1173 {
1174 /** @todo r=bird: Are we actually handling dirty and access bits for pages with access handlers correctly? No. */
1175 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
1176 PteDst.u = (PteSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT | X86_PTE_RW))
1177 | (HCPhys & X86_PTE_PAE_PG_MASK);
1178 else
1179 {
1180 LogFlow(("SyncPageWorker: monitored page (%VGp) -> mark not present\n", HCPhys));
1181 PteDst.u = 0;
1182 }
1183 /** @todo count these two kinds. */
1184 }
1185 else
1186 {
1187#ifdef PGM_SYNC_DIRTY_BIT
1188# ifdef PGM_SYNC_ACCESSED_BIT
1189 /*
1190 * If the page or page directory entry is not marked accessed,
1191 * we mark the page not present.
1192 */
1193 if (!PteSrc.n.u1Accessed || !PdeSrc.n.u1Accessed)
1194 {
1195 LogFlow(("SyncPageWorker: page and or page directory not accessed -> mark not present\n"));
1196 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,AccessedPage));
1197 PteDst.u = 0;
1198 }
1199 else
1200# endif
1201 /*
1202 * If the page is not flagged as dirty and is writable, then make it read-only, so we can set the dirty bit
1203 * when the page is modified.
1204 */
1205 if (!PteSrc.n.u1Dirty && (PdeSrc.n.u1Write & PteSrc.n.u1Write))
1206 {
1207 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPage));
1208 PteDst.u = (PteSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT | X86_PTE_RW))
1209 | (HCPhys & X86_PTE_PAE_PG_MASK)
1210 | PGM_PTFLAGS_TRACK_DIRTY;
1211 }
1212 else
1213 {
1214 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPageSkipped));
1215 PteDst.u = (PteSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT))
1216 | (HCPhys & X86_PTE_PAE_PG_MASK);
1217 }
1218#endif
1219 }
1220
1221#ifdef PGMPOOL_WITH_USER_TRACKING
1222 /*
1223 * Keep user track up to date.
1224 */
1225 if (PteDst.n.u1Present)
1226 {
1227 if (!pPteDst->n.u1Present)
1228 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVM, pShwPage, HCPhys >> MM_RAM_FLAGS_IDX_SHIFT, pPage, iPTDst);
1229 else if ((pPteDst->u & SHW_PTE_PG_MASK) != (PteDst.u & SHW_PTE_PG_MASK))
1230 {
1231 Log2(("SyncPageWorker: deref! *pPteDst=%RX64 PteDst=%RX64\n", (uint64_t)pPteDst->u, (uint64_t)PteDst.u));
1232 PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVM, pShwPage, pPteDst->u & SHW_PTE_PG_MASK);
1233 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVM, pShwPage, HCPhys >> MM_RAM_FLAGS_IDX_SHIFT, pPage, iPTDst);
1234 }
1235 }
1236 else if (pPteDst->n.u1Present)
1237 {
1238 Log2(("SyncPageWorker: deref! *pPteDst=%RX64\n", (uint64_t)pPteDst->u));
1239 PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVM, pShwPage, pPteDst->u & SHW_PTE_PG_MASK);
1240 }
1241#endif /* PGMPOOL_WITH_USER_TRACKING */
1242
1243 /*
1244 * Update statistics and commit the entry.
1245 */
1246 if (!PteSrc.n.u1Global)
1247 pShwPage->fSeenNonGlobal = true;
1248 *pPteDst = PteDst;
1249 }
1250 /* else MMIO or invalid page, we must handle them manually in the #PF handler. */
1251 /** @todo count these. */
1252 }
1253 else
1254 {
1255 /*
1256 * Page not-present.
1257 */
1258 LogFlow(("SyncPageWorker: page not present in Pte\n"));
1259#ifdef PGMPOOL_WITH_USER_TRACKING
1260 /* Keep user track up to date. */
1261 if (pPteDst->n.u1Present)
1262 {
1263 Log2(("SyncPageWorker: deref! *pPteDst=%RX64\n", (uint64_t)pPteDst->u));
1264 PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVM, pShwPage, pPteDst->u & SHW_PTE_PG_MASK);
1265 }
1266#endif /* PGMPOOL_WITH_USER_TRACKING */
1267 pPteDst->u = 0;
1268 /** @todo count these. */
1269 }
1270}
1271
1272
1273/**
1274 * Syncs a guest OS page.
1275 *
1276 * There are no conflicts at this point, neither is there any need for
1277 * page table allocations.
1278 *
1279 * @returns VBox status code.
1280 * @returns VINF_PGM_SYNCPAGE_MODIFIED_PDE if it modifies the PDE in any way.
1281 * @param pVM VM handle.
1282 * @param PdeSrc Page directory entry of the guest.
1283 * @param GCPtrPage Guest context page address.
1284 * @param cPages Number of pages to sync (PGM_SYNC_N_PAGES) (default=1).
1285 * @param uErr Fault error (X86_TRAP_PF_*).
1286 */
1287PGM_BTH_DECL(int, SyncPage)(PVM pVM, GSTPDE PdeSrc, RTGCUINTPTR GCPtrPage, unsigned cPages, unsigned uErr)
1288{
1289# if PGM_WITH_NX(PGM_GST_TYPE)
1290 bool fNoExecuteBitValid = !!(CPUMGetGuestEFER(pVM) & MSR_K6_EFER_NXE);
1291# endif
1292 LogFlow(("SyncPage: GCPtrPage=%VGv cPages=%d uErr=%#x\n", GCPtrPage, cPages, uErr));
1293
1294#if PGM_GST_TYPE == PGM_TYPE_32BIT \
1295 || PGM_GST_TYPE == PGM_TYPE_PAE
1296
1297 /*
1298 * Assert preconditions.
1299 */
1300 STAM_COUNTER_INC(&pVM->pgm.s.StatGCSyncPagePD[(GCPtrPage >> GST_PD_SHIFT) & GST_PD_MASK]);
1301 Assert(PdeSrc.n.u1Present);
1302 Assert(cPages);
1303
1304 /*
1305 * Get the shadow PDE, find the shadow page table in the pool.
1306 */
1307 const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT;
1308# if PGM_SHW_TYPE == PGM_TYPE_32BIT
1309 X86PDE PdeDst = pVM->pgm.s.CTXMID(p,32BitPD)->a[iPDDst];
1310# else /* PAE */
1311 X86PDEPAE PdeDst = pVM->pgm.s.CTXMID(ap,PaePDs)[0]->a[iPDDst];
1312# endif
1313 Assert(PdeDst.n.u1Present);
1314 PPGMPOOLPAGE pShwPage = pgmPoolGetPageByHCPhys(pVM, PdeDst.u & SHW_PDE_PG_MASK);
1315
1316 /*
1317 * Check that the page is present and that the shadow PDE isn't out of sync.
1318 */
1319 const bool fBigPage = PdeSrc.b.u1Size && (CPUMGetGuestCR4(pVM) & X86_CR4_PSE);
1320 RTGCPHYS GCPhys;
1321 if (!fBigPage)
1322 {
1323 GCPhys = PdeSrc.u & GST_PDE_PG_MASK;
1324# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
1325 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
1326 GCPhys |= (iPDDst & 1) * (PAGE_SIZE/2);
1327# endif
1328 }
1329 else
1330 {
1331 GCPhys = PdeSrc.u & GST_PDE_BIG_PG_MASK;
1332# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
1333 /* Select the right PDE as we're emulating a 4MB page directory with two 2 MB shadow PDEs.*/
1334 GCPhys |= GCPtrPage & (1 << X86_PD_PAE_SHIFT);
1335# endif
1336 }
1337 if ( pShwPage->GCPhys == GCPhys
1338 && PdeSrc.n.u1Present
1339 && (PdeSrc.n.u1User == PdeDst.n.u1User)
1340 && (PdeSrc.n.u1Write == PdeDst.n.u1Write || !PdeDst.n.u1Write)
1341# if PGM_WITH_NX(PGM_GST_TYPE)
1342 && (!fNoExecuteBitValid || PdeSrc.n.u1NoExecute == PdeDst.n.u1NoExecute)
1343# endif
1344 )
1345 {
1346# ifdef PGM_SYNC_ACCESSED_BIT
1347 /*
1348 * Check that the PDE is marked accessed already.
1349 * Since we set the accessed bit *before* getting here on a #PF, this
1350 * check is only meant for dealing with non-#PF'ing paths.
1351 */
1352 if (PdeSrc.n.u1Accessed)
1353# endif
1354 {
1355 PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1356 if (!fBigPage)
1357 {
1358 /*
1359 * 4KB Page - Map the guest page table.
1360 */
1361 PGSTPT pPTSrc;
1362 int rc = PGM_GCPHYS_2_PTR(pVM, PdeSrc.u & GST_PDE_PG_MASK, &pPTSrc);
1363 if (VBOX_SUCCESS(rc))
1364 {
1365# ifdef PGM_SYNC_N_PAGES
1366 Assert(cPages == 1 || !(uErr & X86_TRAP_PF_P));
1367 if (cPages > 1 && !(uErr & X86_TRAP_PF_P))
1368 {
1369 /*
1370 * This code path is currently only taken when the caller is PGMTrap0eHandler
1371 * for non-present pages!
1372 *
1373 * We're setting PGM_SYNC_NR_PAGES pages around the faulting page to sync it and
1374 * deal with locality.
1375 */
1376 unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1377# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
1378 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
1379 const unsigned offPTSrc = ((GCPtrPage >> SHW_PD_SHIFT) & 1) * 512;
1380# else
1381 const unsigned offPTSrc = 0;
1382# endif
1383 const unsigned iPTDstEnd = RT_MIN(iPTDst + PGM_SYNC_NR_PAGES / 2, ELEMENTS(pPTDst->a));
1384 if (iPTDst < PGM_SYNC_NR_PAGES / 2)
1385 iPTDst = 0;
1386 else
1387 iPTDst -= PGM_SYNC_NR_PAGES / 2;
1388 for (; iPTDst < iPTDstEnd; iPTDst++)
1389 {
1390 if (!pPTDst->a[iPTDst].n.u1Present)
1391 {
1392 GSTPTE PteSrc = pPTSrc->a[offPTSrc + iPTDst];
1393 RTGCUINTPTR GCPtrCurPage = ((RTGCUINTPTR)GCPtrPage & ~(RTGCUINTPTR)(GST_PT_MASK << GST_PT_SHIFT)) | ((offPTSrc + iPTDst) << PAGE_SHIFT);
1394 NOREF(GCPtrCurPage);
1395#ifndef IN_RING0
1396 /*
1397 * Assuming kernel code will be marked as supervisor - and not as user level
1398 * and executed using a conforming code selector - And marked as readonly.
1399 * Also assume that if we're monitoring a page, it's of no interest to CSAM.
1400 */
1401 PPGMPAGE pPage;
1402 if ( ((PdeSrc.u & PteSrc.u) & (X86_PTE_RW | X86_PTE_US))
1403 || iPTDst == ((GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK) /* always sync GCPtrPage */
1404 || !CSAMDoesPageNeedScanning(pVM, (RTGCPTR)GCPtrCurPage)
1405 || ( (pPage = pgmPhysGetPage(&pVM->pgm.s, PteSrc.u & GST_PTE_PG_MASK))
1406 && PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
1407 )
1408#endif /* else: CSAM not active */
1409 PGM_BTH_NAME(SyncPageWorker)(pVM, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
1410 Log2(("SyncPage: 4K+ %VGv PteSrc:{P=%d RW=%d U=%d raw=%08llx} PteDst=%08llx%s\n",
1411 GCPtrCurPage, PteSrc.n.u1Present,
1412 PteSrc.n.u1Write & PdeSrc.n.u1Write,
1413 PteSrc.n.u1User & PdeSrc.n.u1User,
1414 (uint64_t)PteSrc.u,
1415 (uint64_t)pPTDst->a[iPTDst].u,
1416 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
1417 }
1418 }
1419 }
1420 else
1421# endif /* PGM_SYNC_N_PAGES */
1422 {
1423 const unsigned iPTSrc = (GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK;
1424 GSTPTE PteSrc = pPTSrc->a[iPTSrc];
1425 const unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1426 PGM_BTH_NAME(SyncPageWorker)(pVM, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
1427 Log2(("SyncPage: 4K %VGv PteSrc:{P=%d RW=%d U=%d raw=%08llx}%s\n",
1428 GCPtrPage, PteSrc.n.u1Present,
1429 PteSrc.n.u1Write & PdeSrc.n.u1Write,
1430 PteSrc.n.u1User & PdeSrc.n.u1User,
1431 (uint64_t)PteSrc.u,
1432 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
1433 }
1434 }
1435 else /* MMIO or invalid page: emulated in #PF handler. */
1436 {
1437 LogFlow(("PGM_GCPHYS_2_PTR %VGp failed with %Vrc\n", GCPhys, rc));
1438 Assert(!pPTDst->a[(GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK].n.u1Present);
1439 }
1440 }
1441 else
1442 {
1443 /*
1444 * 4/2MB page - lazy syncing shadow 4K pages.
1445 * (There are many causes of getting here, it's no longer only CSAM.)
1446 */
1447 /* Calculate the GC physical address of this 4KB shadow page. */
1448 RTGCPHYS GCPhys = (PdeSrc.u & GST_PDE_BIG_PG_MASK) | ((RTGCUINTPTR)GCPtrPage & GST_BIG_PAGE_OFFSET_MASK);
1449 /* Find ram range. */
1450 PPGMPAGE pPage;
1451 int rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhys, &pPage);
1452 if (VBOX_SUCCESS(rc))
1453 {
1454 /*
1455 * Make shadow PTE entry.
1456 */
1457 const RTHCPHYS HCPhys = pPage->HCPhys; /** @todo PAGE FLAGS */
1458 SHWPTE PteDst;
1459 PteDst.u = (PdeSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT))
1460 | (HCPhys & X86_PTE_PAE_PG_MASK);
1461 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
1462 {
1463 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
1464 PteDst.n.u1Write = 0;
1465 else
1466 PteDst.u = 0;
1467 }
1468 const unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1469# ifdef PGMPOOL_WITH_USER_TRACKING
1470 if (PteDst.n.u1Present && !pPTDst->a[iPTDst].n.u1Present)
1471 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVM, pShwPage, HCPhys >> MM_RAM_FLAGS_IDX_SHIFT, pPage, iPTDst);
1472# endif
1473 pPTDst->a[iPTDst] = PteDst;
1474
1475
1476# ifdef PGM_SYNC_DIRTY_BIT
1477 /*
1478 * If the page is not flagged as dirty and is writable, then make it read-only
1479 * at PD level, so we can set the dirty bit when the page is modified.
1480 *
1481 * ASSUMES that page access handlers are implemented on page table entry level.
1482 * Thus we will first catch the dirty access and set PDE.D and restart. If
1483 * there is an access handler, we'll trap again and let it work on the problem.
1484 */
1485 /** @todo r=bird: figure out why we need this here, SyncPT should've taken care of this already.
1486 * As for invlpg, it simply frees the whole shadow PT.
1487 * ...It's possibly because the guest clears it and the guest doesn't really tell us... */
1488 if (!PdeSrc.b.u1Dirty && PdeSrc.b.u1Write)
1489 {
1490 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPageBig));
1491 PdeDst.u |= PGM_PDFLAGS_TRACK_DIRTY;
1492 PdeDst.n.u1Write = 0;
1493 }
1494 else
1495 {
1496 PdeDst.au32[0] &= ~PGM_PDFLAGS_TRACK_DIRTY;
1497 PdeDst.n.u1Write = PdeSrc.n.u1Write;
1498 }
1499# if PGM_SHW_TYPE == PGM_TYPE_32BIT
1500 pVM->pgm.s.CTXMID(p,32BitPD)->a[iPDDst] = PdeDst;
1501# else /* PAE */
1502 pVM->pgm.s.CTXMID(ap,PaePDs)[0]->a[iPDDst] = PdeDst;
1503# endif
1504# endif /* PGM_SYNC_DIRTY_BIT */
1505 Log2(("SyncPage: BIG %VGv PdeSrc:{P=%d RW=%d U=%d raw=%08llx} GCPhys=%VGp%s\n",
1506 GCPtrPage, PdeSrc.n.u1Present, PdeSrc.n.u1Write, PdeSrc.n.u1User, (uint64_t)PdeSrc.u, GCPhys,
1507 PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
1508 }
1509 else
1510 LogFlow(("PGM_GCPHYS_2_PTR %VGp (big) failed with %Vrc\n", GCPhys, rc));
1511 }
1512 return VINF_SUCCESS;
1513 }
1514# ifdef PGM_SYNC_ACCESSED_BIT
1515 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncPagePDNAs));
1516#endif
1517 }
1518 else
1519 {
1520 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncPagePDOutOfSync));
1521 Log2(("SyncPage: Out-Of-Sync PDE at %VGp PdeSrc=%RX64 PdeDst=%RX64\n",
1522 GCPtrPage, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
1523 }
1524
1525 /*
1526 * Mark the PDE not present. Restart the instruction and let #PF call SyncPT.
1527 * Yea, I'm lazy.
1528 */
1529 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, SHW_POOL_ROOT_IDX, iPDDst);
1530# if PGM_SHW_TYPE == PGM_TYPE_32BIT
1531 pVM->pgm.s.CTXMID(p,32BitPD)->a[iPDDst].u = 0;
1532# else /* PAE */
1533 pVM->pgm.s.CTXMID(ap,PaePDs)[0]->a[iPDDst].u = 0;
1534# endif
1535 PGM_INVL_GUEST_TLBS();
1536 return VINF_PGM_SYNCPAGE_MODIFIED_PDE;
1537
1538#elif PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT
1539
1540# ifdef PGM_SYNC_N_PAGES
1541 /*
1542 * Get the shadow PDE, find the shadow page table in the pool.
1543 */
1544 const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT;
1545# if PGM_SHW_TYPE == PGM_TYPE_32BIT
1546 X86PDE PdeDst = pVM->pgm.s.CTXMID(p,32BitPD)->a[iPDDst];
1547# else /* PAE */
1548 X86PDEPAE PdeDst = pVM->pgm.s.CTXMID(ap,PaePDs)[0]->a[iPDDst];
1549# endif
1550 Assert(PdeDst.n.u1Present);
1551 PPGMPOOLPAGE pShwPage = pgmPoolGetPageByHCPhys(pVM, PdeDst.u & SHW_PDE_PG_MASK);
1552 PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1553
1554# if PGM_SHW_TYPE == PGM_TYPE_PAE
1555 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
1556 const unsigned offPTSrc = ((GCPtrPage >> SHW_PD_SHIFT) & 1) * 512;
1557# else
1558 const unsigned offPTSrc = 0;
1559# endif
1560
1561 Assert(cPages == 1 || !(uErr & X86_TRAP_PF_P));
1562 if (cPages > 1 && !(uErr & X86_TRAP_PF_P))
1563 {
1564 /*
1565 * This code path is currently only taken when the caller is PGMTrap0eHandler
1566 * for non-present pages!
1567 *
1568 * We're setting PGM_SYNC_NR_PAGES pages around the faulting page to sync it and
1569 * deal with locality.
1570 */
1571 unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1572 const unsigned iPTDstEnd = RT_MIN(iPTDst + PGM_SYNC_NR_PAGES / 2, ELEMENTS(pPTDst->a));
1573 if (iPTDst < PGM_SYNC_NR_PAGES / 2)
1574 iPTDst = 0;
1575 else
1576 iPTDst -= PGM_SYNC_NR_PAGES / 2;
1577 for (; iPTDst < iPTDstEnd; iPTDst++)
1578 {
1579 if (!pPTDst->a[iPTDst].n.u1Present)
1580 {
1581 GSTPTE PteSrc;
1582
1583 RTGCUINTPTR GCPtrCurPage = ((RTGCUINTPTR)GCPtrPage & ~(RTGCUINTPTR)(GST_PT_MASK << GST_PT_SHIFT)) | ((offPTSrc + iPTDst) << PAGE_SHIFT);
1584
1585 /* Fake the page table entry */
1586 PteSrc.u = GCPtrCurPage;
1587 PteSrc.n.u1Present = 1;
1588 PteSrc.n.u1Dirty = 1;
1589 PteSrc.n.u1Accessed = 1;
1590 PteSrc.n.u1Write = 1;
1591 PteSrc.n.u1User = 1;
1592
1593 PGM_BTH_NAME(SyncPageWorker)(pVM, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
1594
1595 Log2(("SyncPage: 4K+ %VGv PteSrc:{P=%d RW=%d U=%d raw=%08llx} PteDst=%08llx%s\n",
1596 GCPtrCurPage, PteSrc.n.u1Present,
1597 PteSrc.n.u1Write & PdeSrc.n.u1Write,
1598 PteSrc.n.u1User & PdeSrc.n.u1User,
1599 (uint64_t)PteSrc.u,
1600 (uint64_t)pPTDst->a[iPTDst].u,
1601 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
1602 }
1603 }
1604 }
1605 else
1606# endif /* PGM_SYNC_N_PAGES */
1607 {
1608 GSTPTE PteSrc;
1609 const unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1610 RTGCUINTPTR GCPtrCurPage = ((RTGCUINTPTR)GCPtrPage & ~(RTGCUINTPTR)(GST_PT_MASK << GST_PT_SHIFT)) | ((offPTSrc + iPTDst) << PAGE_SHIFT);
1611
1612 /* Fake the page table entry */
1613 PteSrc.u = GCPtrCurPage;
1614 PteSrc.n.u1Present = 1;
1615 PteSrc.n.u1Dirty = 1;
1616 PteSrc.n.u1Accessed = 1;
1617 PteSrc.n.u1Write = 1;
1618 PteSrc.n.u1User = 1;
1619 PGM_BTH_NAME(SyncPageWorker)(pVM, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
1620
1621 Log2(("SyncPage: 4K %VGv PteSrc:{P=%d RW=%d U=%d raw=%08llx}%s\n",
1622 GCPtrPage, PteSrc.n.u1Present,
1623 PteSrc.n.u1Write & PdeSrc.n.u1Write,
1624 PteSrc.n.u1User & PdeSrc.n.u1User,
1625 (uint64_t)PteSrc.u,
1626 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
1627 }
1628 return VINF_SUCCESS;
1629
1630#else /* PGM_GST_TYPE == PGM_TYPE_AMD64 */
1631 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
1632 return VERR_INTERNAL_ERROR;
1633#endif /* PGM_GST_TYPE == PGM_TYPE_AMD64 */
1634}
1635
1636
1637
1638#if PGM_WITH_PAGING(PGM_GST_TYPE)
1639
1640# ifdef PGM_SYNC_DIRTY_BIT
1641
1642/**
1643 * Investigate page fault and handle write protection page faults caused by
1644 * dirty bit tracking.
1645 *
1646 * @returns VBox status code.
1647 * @param pVM VM handle.
1648 * @param uErr Page fault error code.
1649 * @param pPdeDst Shadow page directory entry.
1650 * @param pPdeSrc Guest page directory entry.
1651 * @param GCPtrPage Guest context page address.
1652 */
1653PGM_BTH_DECL(int, CheckPageFault)(PVM pVM, uint32_t uErr, PSHWPDE pPdeDst, PGSTPDE pPdeSrc, RTGCUINTPTR GCPtrPage)
1654{
1655 bool fWriteProtect = !!(CPUMGetGuestCR0(pVM) & X86_CR0_WP);
1656 bool fUserLevelFault = !!(uErr & X86_TRAP_PF_US);
1657 bool fWriteFault = !!(uErr & X86_TRAP_PF_RW);
1658# if PGM_WITH_NX(PGM_GST_TYPE)
1659 bool fNoExecuteBitValid = !!(CPUMGetGuestEFER(pVM) & MSR_K6_EFER_NXE);
1660# endif
1661
1662 STAM_PROFILE_START(&pVM->pgm.s.CTXMID(Stat, DirtyBitTracking), a);
1663 LogFlow(("CheckPageFault: GCPtrPage=%VGv uErr=%#x PdeSrc=%08x\n", GCPtrPage, uErr, pPdeSrc->u));
1664
1665# if PGM_GST_TYPE == PGM_TYPE_AMD64
1666 AssertFailed();
1667# elif PGM_GST_TYPE == PGM_TYPE_PAE
1668 PX86PDPE pPdpeSrc = &pVM->pgm.s.CTXSUFF(pGstPaePDPT)->a[(GCPtrPage >> GST_PDPT_SHIFT) & GST_PDPT_MASK];
1669
1670 /*
1671 * Real page fault?
1672 */
1673 if ( (uErr & X86_TRAP_PF_RSVD)
1674 || !pPdpeSrc->n.u1Present
1675# if PGM_GST_TYPE == PGM_TYPE_AMD64 /* NX, r/w, u/s bits in the PDPE are long mode only */
1676 || (fNoExecuteBitValid && (uErr & X86_TRAP_PF_ID) && pPdpeSrc->n.u1NoExecute)
1677 || (fWriteFault && !pPdpeSrc->n.u1Write && (fUserLevelFault || fWriteProtect))
1678 || (fUserLevelFault && !pPdpeSrc->n.u1User)
1679# endif
1680 )
1681 {
1682# ifdef IN_GC
1683 STAM_COUNTER_INC(&pVM->pgm.s.StatGCDirtyTrackRealPF);
1684# endif
1685 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat, DirtyBitTracking), a);
1686 LogFlow(("CheckPageFault: real page fault at %VGv (0)\n", GCPtrPage));
1687
1688 if ( pPdpeSrc->n.u1Present
1689 && pPdeSrc->n.u1Present)
1690 {
1691 /* Check the present bit as the shadow tables can cause different error codes by being out of sync.
1692 * See the 2nd case below as well.
1693 */
1694 if (pPdeSrc->b.u1Size && (CPUMGetGuestCR4(pVM) & X86_CR4_PSE))
1695 {
1696 TRPMSetErrorCode(pVM, uErr | X86_TRAP_PF_P); /* page-level protection violation */
1697 }
1698 else
1699 {
1700 /*
1701 * Map the guest page table.
1702 */
1703 PGSTPT pPTSrc;
1704 int rc = PGM_GCPHYS_2_PTR(pVM, pPdeSrc->u & GST_PDE_PG_MASK, &pPTSrc);
1705 if (VBOX_SUCCESS(rc))
1706 {
1707 PGSTPTE pPteSrc = &pPTSrc->a[(GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK];
1708 const GSTPTE PteSrc = *pPteSrc;
1709 if (pPteSrc->n.u1Present)
1710 TRPMSetErrorCode(pVM, uErr | X86_TRAP_PF_P); /* page-level protection violation */
1711 }
1712 AssertRC(rc);
1713 }
1714 }
1715 return VINF_EM_RAW_GUEST_TRAP;
1716 }
1717# endif
1718
1719 /*
1720 * Real page fault?
1721 */
1722 if ( (uErr & X86_TRAP_PF_RSVD)
1723 || !pPdeSrc->n.u1Present
1724# if PGM_WITH_NX(PGM_GST_TYPE)
1725 || (fNoExecuteBitValid && (uErr & X86_TRAP_PF_ID) && pPdeSrc->n.u1NoExecute)
1726# endif
1727 || (fWriteFault && !pPdeSrc->n.u1Write && (fUserLevelFault || fWriteProtect))
1728 || (fUserLevelFault && !pPdeSrc->n.u1User) )
1729 {
1730# ifdef IN_GC
1731 STAM_COUNTER_INC(&pVM->pgm.s.StatGCDirtyTrackRealPF);
1732# endif
1733 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat, DirtyBitTracking), a);
1734 LogFlow(("CheckPageFault: real page fault at %VGv (1)\n", GCPtrPage));
1735
1736 if (pPdeSrc->n.u1Present)
1737 {
1738 /* Check the present bit as the shadow tables can cause different error codes by being out of sync.
1739 * See the 2nd case below as well.
1740 */
1741 if (pPdeSrc->b.u1Size && (CPUMGetGuestCR4(pVM) & X86_CR4_PSE))
1742 {
1743 TRPMSetErrorCode(pVM, uErr | X86_TRAP_PF_P); /* page-level protection violation */
1744 }
1745 else
1746 {
1747 /*
1748 * Map the guest page table.
1749 */
1750 PGSTPT pPTSrc;
1751 int rc = PGM_GCPHYS_2_PTR(pVM, pPdeSrc->u & GST_PDE_PG_MASK, &pPTSrc);
1752 if (VBOX_SUCCESS(rc))
1753 {
1754 PGSTPTE pPteSrc = &pPTSrc->a[(GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK];
1755 const GSTPTE PteSrc = *pPteSrc;
1756 if (pPteSrc->n.u1Present)
1757 TRPMSetErrorCode(pVM, uErr | X86_TRAP_PF_P); /* page-level protection violation */
1758 }
1759 AssertRC(rc);
1760 }
1761 }
1762 return VINF_EM_RAW_GUEST_TRAP;
1763 }
1764
1765 /*
1766 * First check the easy case where the page directory has been marked read-only to track
1767 * the dirty bit of an emulated BIG page
1768 */
1769 if (pPdeSrc->b.u1Size && (CPUMGetGuestCR4(pVM) & X86_CR4_PSE))
1770 {
1771 /* Mark guest page directory as accessed */
1772 pPdeSrc->b.u1Accessed = 1;
1773
1774 /*
1775 * Only write protection page faults are relevant here.
1776 */
1777 if (fWriteFault)
1778 {
1779 /* Mark guest page directory as dirty (BIG page only). */
1780 pPdeSrc->b.u1Dirty = 1;
1781
1782 if (pPdeDst->n.u1Present && (pPdeDst->u & PGM_PDFLAGS_TRACK_DIRTY))
1783 {
1784 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPageTrap));
1785
1786 Assert(pPdeSrc->b.u1Write);
1787
1788 pPdeDst->n.u1Write = 1;
1789 pPdeDst->n.u1Accessed = 1;
1790 pPdeDst->au32[0] &= ~PGM_PDFLAGS_TRACK_DIRTY;
1791 PGM_INVL_BIG_PG(GCPtrPage);
1792 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,DirtyBitTracking), a);
1793 return VINF_PGM_HANDLED_DIRTY_BIT_FAULT;
1794 }
1795 }
1796 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,DirtyBitTracking), a);
1797 return VINF_PGM_NO_DIRTY_BIT_TRACKING;
1798 }
1799 /* else: 4KB page table */
1800
1801 /*
1802 * Map the guest page table.
1803 */
1804 PGSTPT pPTSrc;
1805 int rc = PGM_GCPHYS_2_PTR(pVM, pPdeSrc->u & GST_PDE_PG_MASK, &pPTSrc);
1806 if (VBOX_SUCCESS(rc))
1807 {
1808 /*
1809 * Real page fault?
1810 */
1811 PGSTPTE pPteSrc = &pPTSrc->a[(GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK];
1812 const GSTPTE PteSrc = *pPteSrc;
1813 if ( !PteSrc.n.u1Present
1814# if PGM_WITH_NX(PGM_GST_TYPE)
1815 || (fNoExecuteBitValid && (uErr & X86_TRAP_PF_ID) && PteSrc.n.u1NoExecute)
1816# endif
1817 || (fWriteFault && !PteSrc.n.u1Write && (fUserLevelFault || fWriteProtect))
1818 || (fUserLevelFault && !PteSrc.n.u1User)
1819 )
1820 {
1821# ifdef IN_GC
1822 STAM_COUNTER_INC(&pVM->pgm.s.StatGCDirtyTrackRealPF);
1823# endif
1824 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,DirtyBitTracking), a);
1825 LogFlow(("CheckPageFault: real page fault at %VGv PteSrc.u=%08x (2)\n", GCPtrPage, PteSrc.u));
1826
1827 /* Check the present bit as the shadow tables can cause different error codes by being out of sync.
1828 * See the 2nd case above as well.
1829 */
1830 if (pPdeSrc->n.u1Present && pPteSrc->n.u1Present)
1831 TRPMSetErrorCode(pVM, uErr | X86_TRAP_PF_P); /* page-level protection violation */
1832
1833 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,DirtyBitTracking), a);
1834 return VINF_EM_RAW_GUEST_TRAP;
1835 }
1836 LogFlow(("CheckPageFault: page fault at %VGv PteSrc.u=%08x\n", GCPtrPage, PteSrc.u));
1837
1838 /*
1839 * Set the accessed bits in the page directory and the page table.
1840 */
1841 pPdeSrc->n.u1Accessed = 1;
1842 pPteSrc->n.u1Accessed = 1;
1843
1844 /*
1845 * Only write protection page faults are relevant here.
1846 */
1847 if (fWriteFault)
1848 {
1849 /* Write access, so mark guest entry as dirty. */
1850# if defined(IN_GC) && defined(VBOX_WITH_STATISTICS)
1851 if (!pPteSrc->n.u1Dirty)
1852 STAM_COUNTER_INC(&pVM->pgm.s.StatGCDirtiedPage);
1853 else
1854 STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageAlreadyDirty);
1855# endif
1856 pPteSrc->n.u1Dirty = 1;
1857
1858 if (pPdeDst->n.u1Present)
1859 {
1860 /* Bail out here as pgmPoolGetPageByHCPhys will return NULL and we'll crash below.
1861 * Our individual shadow handlers will provide more information and force a fatal exit.
1862 */
1863 if (MMHyperIsInsideArea(pVM, (RTGCPTR)GCPtrPage))
1864 {
1865 LogRel(("CheckPageFault: write to hypervisor region %VGv\n", GCPtrPage));
1866 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,DirtyBitTracking), a);
1867 return VINF_SUCCESS;
1868 }
1869
1870 /*
1871 * Map shadow page table.
1872 */
1873 PPGMPOOLPAGE pShwPage = pgmPoolGetPageByHCPhys(pVM, pPdeDst->u & SHW_PDE_PG_MASK);
1874 if (pShwPage)
1875 {
1876 PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1877 PSHWPTE pPteDst = &pPTDst->a[(GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK];
1878 if ( pPteDst->n.u1Present /** @todo Optimize accessed bit emulation? */
1879 && (pPteDst->u & PGM_PTFLAGS_TRACK_DIRTY))
1880 {
1881 LogFlow(("DIRTY page trap addr=%VGv\n", GCPtrPage));
1882# ifdef VBOX_STRICT
1883 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, pPteSrc->u & GST_PTE_PG_MASK);
1884 if (pPage)
1885 AssertMsg(!PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage),
1886 ("Unexpected dirty bit tracking on monitored page %VGv (phys %VGp)!!!!!!\n", GCPtrPage, pPteSrc->u & X86_PTE_PAE_PG_MASK));
1887# endif
1888 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPageTrap));
1889
1890 Assert(pPteSrc->n.u1Write);
1891
1892 pPteDst->n.u1Write = 1;
1893 pPteDst->n.u1Dirty = 1;
1894 pPteDst->n.u1Accessed = 1;
1895 pPteDst->au32[0] &= ~PGM_PTFLAGS_TRACK_DIRTY;
1896 PGM_INVL_PG(GCPtrPage);
1897
1898 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,DirtyBitTracking), a);
1899 return VINF_PGM_HANDLED_DIRTY_BIT_FAULT;
1900 }
1901 }
1902 else
1903 AssertMsgFailed(("pgmPoolGetPageByHCPhys %VGp failed!\n", pPdeDst->u & SHW_PDE_PG_MASK));
1904 }
1905 }
1906/** @todo Optimize accessed bit emulation? */
1907# ifdef VBOX_STRICT
1908 /*
1909 * Sanity check.
1910 */
1911 else if ( !pPteSrc->n.u1Dirty
1912 && (pPdeSrc->n.u1Write & pPteSrc->n.u1Write)
1913 && pPdeDst->n.u1Present)
1914 {
1915 PPGMPOOLPAGE pShwPage = pgmPoolGetPageByHCPhys(pVM, pPdeDst->u & SHW_PDE_PG_MASK);
1916 PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1917 PSHWPTE pPteDst = &pPTDst->a[(GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK];
1918 if ( pPteDst->n.u1Present
1919 && pPteDst->n.u1Write)
1920 LogFlow(("Writable present page %VGv not marked for dirty bit tracking!!!\n", GCPtrPage));
1921 }
1922# endif /* VBOX_STRICT */
1923 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,DirtyBitTracking), a);
1924 return VINF_PGM_NO_DIRTY_BIT_TRACKING;
1925 }
1926 AssertRC(rc);
1927 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,DirtyBitTracking), a);
1928 return rc;
1929}
1930
1931# endif
1932
1933#endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
1934
1935
1936/**
1937 * Sync a shadow page table.
1938 *
1939 * The shadow page table is not present. This includes the case where
1940 * there is a conflict with a mapping.
1941 *
1942 * @returns VBox status code.
1943 * @param pVM VM handle.
1944 * @param iPD Page directory index.
1945 * @param pPDSrc Source page directory (i.e. Guest OS page directory).
1946 * Assume this is a temporary mapping.
1947 * @param GCPtrPage GC Pointer of the page that caused the fault
1948 */
1949PGM_BTH_DECL(int, SyncPT)(PVM pVM, unsigned iPDSrc, PGSTPD pPDSrc, RTGCUINTPTR GCPtrPage)
1950{
1951 STAM_PROFILE_START(&pVM->pgm.s.CTXMID(Stat,SyncPT), a);
1952 STAM_COUNTER_INC(&pVM->pgm.s.StatGCSyncPtPD[iPDSrc]);
1953 LogFlow(("SyncPT: GCPtrPage=%VGv\n", GCPtrPage));
1954
1955#if PGM_GST_TYPE == PGM_TYPE_32BIT \
1956 || PGM_GST_TYPE == PGM_TYPE_PAE
1957
1958 /*
1959 * Validate input a little bit.
1960 */
1961 AssertMsg(iPDSrc == ((GCPtrPage >> GST_PD_SHIFT) & GST_PD_MASK), ("iPDSrc=%x GCPtrPage=%VGv\n", iPDSrc, GCPtrPage));
1962# if PGM_SHW_TYPE == PGM_TYPE_32BIT
1963 PX86PD pPDDst = pVM->pgm.s.CTXMID(p,32BitPD);
1964# else
1965 PX86PDPAE pPDDst = pVM->pgm.s.CTXMID(ap,PaePDs)[0];
1966# endif
1967 const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT;
1968 PSHWPDE pPdeDst = &pPDDst->a[iPDDst];
1969 SHWPDE PdeDst = *pPdeDst;
1970
1971# ifndef PGM_WITHOUT_MAPPINGS
1972 /*
1973 * Check for conflicts.
1974 * GC: In case of a conflict we'll go to Ring-3 and do a full SyncCR3.
1975 * HC: Simply resolve the conflict.
1976 */
1977 if (PdeDst.u & PGM_PDFLAGS_MAPPING)
1978 {
1979 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
1980# ifndef IN_RING3
1981 Log(("SyncPT: Conflict at %VGv\n", GCPtrPage));
1982 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,SyncPT), a);
1983 return VERR_ADDRESS_CONFLICT;
1984# else
1985 PPGMMAPPING pMapping = pgmGetMapping(pVM, (RTGCPTR)GCPtrPage);
1986 Assert(pMapping);
1987# if PGM_GST_TYPE == PGM_TYPE_32BIT
1988 int rc = pgmR3SyncPTResolveConflict(pVM, pMapping, pPDSrc, GCPtrPage & (GST_PD_MASK << GST_PD_SHIFT));
1989# elif PGM_GST_TYPE == PGM_TYPE_PAE
1990 int rc = pgmR3SyncPTResolveConflictPAE(pVM, pMapping, GCPtrPage & (GST_PD_MASK << GST_PD_SHIFT));
1991# endif
1992 if (VBOX_FAILURE(rc))
1993 {
1994 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,SyncPT), a);
1995 return rc;
1996 }
1997 PdeDst = *pPdeDst;
1998# endif
1999 }
2000# else /* PGM_WITHOUT_MAPPINGS */
2001 Assert(!pgmMapAreMappingsEnabled(&pVM->pgm.s));
2002# endif /* PGM_WITHOUT_MAPPINGS */
2003 Assert(!PdeDst.n.u1Present); /* We're only supposed to call SyncPT on PDE!P and conflicts.*/
2004
2005 /*
2006 * Sync page directory entry.
2007 */
2008 int rc = VINF_SUCCESS;
2009 GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
2010 if (PdeSrc.n.u1Present)
2011 {
2012 /*
2013 * Allocate & map the page table.
2014 */
2015 PSHWPT pPTDst;
2016 const bool fPageTable = !PdeSrc.b.u1Size || !(CPUMGetGuestCR4(pVM) & X86_CR4_PSE);
2017 PPGMPOOLPAGE pShwPage;
2018 RTGCPHYS GCPhys;
2019 if (fPageTable)
2020 {
2021 GCPhys = PdeSrc.u & GST_PDE_PG_MASK;
2022# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2023 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
2024 GCPhys |= (iPDDst & 1) * (PAGE_SIZE / 2);
2025# endif
2026 rc = pgmPoolAlloc(pVM, GCPhys, BTH_PGMPOOLKIND_PT_FOR_PT, SHW_POOL_ROOT_IDX, iPDDst, &pShwPage);
2027 }
2028 else
2029 {
2030 GCPhys = PdeSrc.u & GST_PDE_BIG_PG_MASK;
2031# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2032 /* Select the right PDE as we're emulating a 4MB page directory with two 2 MB shadow PDEs.*/
2033 GCPhys |= GCPtrPage & (1 << X86_PD_PAE_SHIFT);
2034# endif
2035 rc = pgmPoolAlloc(pVM, GCPhys, BTH_PGMPOOLKIND_PT_FOR_BIG, SHW_POOL_ROOT_IDX, iPDDst, &pShwPage);
2036 }
2037 if (rc == VINF_SUCCESS)
2038 pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
2039 else if (rc == VINF_PGM_CACHED_PAGE)
2040 {
2041 /*
2042 * The PT was cached, just hook it up.
2043 */
2044 if (fPageTable)
2045 PdeDst.u = pShwPage->Core.Key
2046 | (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
2047 else
2048 {
2049 PdeDst.u = pShwPage->Core.Key
2050 | (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
2051# ifdef PGM_SYNC_DIRTY_BIT /* (see explanation and assumptions further down.) */
2052 if (!PdeSrc.b.u1Dirty && PdeSrc.b.u1Write)
2053 {
2054 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPageBig));
2055 PdeDst.u |= PGM_PDFLAGS_TRACK_DIRTY;
2056 PdeDst.b.u1Write = 0;
2057 }
2058# endif
2059 }
2060 *pPdeDst = PdeDst;
2061 return VINF_SUCCESS;
2062 }
2063 else if (rc == VERR_PGM_POOL_FLUSHED)
2064 return VINF_PGM_SYNC_CR3;
2065 else
2066 AssertMsgFailedReturn(("rc=%Vrc\n", rc), VERR_INTERNAL_ERROR);
2067 PdeDst.u &= X86_PDE_AVL_MASK;
2068 PdeDst.u |= pShwPage->Core.Key;
2069
2070# ifdef PGM_SYNC_DIRTY_BIT
2071 /*
2072 * Page directory has been accessed (this is a fault situation, remember).
2073 */
2074 pPDSrc->a[iPDSrc].n.u1Accessed = 1;
2075# endif
2076 if (fPageTable)
2077 {
2078 /*
2079 * Page table - 4KB.
2080 *
2081 * Sync all or just a few entries depending on PGM_SYNC_N_PAGES.
2082 */
2083 Log2(("SyncPT: 4K %VGv PdeSrc:{P=%d RW=%d U=%d raw=%08llx}\n",
2084 GCPtrPage, PdeSrc.b.u1Present, PdeSrc.b.u1Write, PdeSrc.b.u1User, (uint64_t)PdeSrc.u));
2085 PGSTPT pPTSrc;
2086 rc = PGM_GCPHYS_2_PTR(pVM, PdeSrc.u & GST_PDE_PG_MASK, &pPTSrc);
2087 if (VBOX_SUCCESS(rc))
2088 {
2089 /*
2090 * Start by syncing the page directory entry so CSAM's TLB trick works.
2091 */
2092 PdeDst.u = (PdeDst.u & (SHW_PDE_PG_MASK | X86_PDE_AVL_MASK))
2093 | (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
2094 *pPdeDst = PdeDst;
2095
2096 /*
2097 * Directory/page user or supervisor privilege: (same goes for read/write)
2098 *
2099 * Directory Page Combined
2100 * U/S U/S U/S
2101 * 0 0 0
2102 * 0 1 0
2103 * 1 0 0
2104 * 1 1 1
2105 *
2106 * Simple AND operation. Table listed for completeness.
2107 *
2108 */
2109 STAM_COUNTER_INC(CTXSUFF(&pVM->pgm.s.StatSynPT4k));
2110# ifdef PGM_SYNC_N_PAGES
2111 unsigned iPTBase = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
2112 unsigned iPTDst = iPTBase;
2113 const unsigned iPTDstEnd = RT_MIN(iPTDst + PGM_SYNC_NR_PAGES / 2, ELEMENTS(pPTDst->a));
2114 if (iPTDst <= PGM_SYNC_NR_PAGES / 2)
2115 iPTDst = 0;
2116 else
2117 iPTDst -= PGM_SYNC_NR_PAGES / 2;
2118# else /* !PGM_SYNC_N_PAGES */
2119 unsigned iPTDst = 0;
2120 const unsigned iPTDstEnd = ELEMENTS(pPTDst->a);
2121# endif /* !PGM_SYNC_N_PAGES */
2122# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2123 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
2124 const unsigned offPTSrc = ((GCPtrPage >> SHW_PD_SHIFT) & 1) * 512;
2125# else
2126 const unsigned offPTSrc = 0;
2127# endif
2128 for (; iPTDst < iPTDstEnd; iPTDst++)
2129 {
2130 const unsigned iPTSrc = iPTDst + offPTSrc;
2131 const GSTPTE PteSrc = pPTSrc->a[iPTSrc];
2132
2133 if (PteSrc.n.u1Present) /* we've already cleared it above */
2134 {
2135# ifndef IN_RING0
2136 /*
2137 * Assuming kernel code will be marked as supervisor - and not as user level
2138 * and executed using a conforming code selector - And marked as readonly.
2139 * Also assume that if we're monitoring a page, it's of no interest to CSAM.
2140 */
2141 PPGMPAGE pPage;
2142 if ( ((PdeSrc.u & pPTSrc->a[iPTSrc].u) & (X86_PTE_RW | X86_PTE_US))
2143 || !CSAMDoesPageNeedScanning(pVM, (RTGCPTR)((iPDSrc << GST_PD_SHIFT) | (iPTSrc << PAGE_SHIFT)))
2144 || ( (pPage = pgmPhysGetPage(&pVM->pgm.s, PteSrc.u & GST_PTE_PG_MASK))
2145 && PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
2146 )
2147# endif
2148 PGM_BTH_NAME(SyncPageWorker)(pVM, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
2149 Log2(("SyncPT: 4K+ %VGv PteSrc:{P=%d RW=%d U=%d raw=%08llx}%s dst.raw=%08llx iPTSrc=%x PdeSrc.u=%x physpte=%VGp\n",
2150 (RTGCPTR)((iPDSrc << GST_PD_SHIFT) | (iPTSrc << PAGE_SHIFT)),
2151 PteSrc.n.u1Present,
2152 PteSrc.n.u1Write & PdeSrc.n.u1Write,
2153 PteSrc.n.u1User & PdeSrc.n.u1User,
2154 (uint64_t)PteSrc.u,
2155 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : "", pPTDst->a[iPTDst].u, iPTSrc, PdeSrc.au32[0],
2156 (PdeSrc.u & GST_PDE_PG_MASK) + iPTSrc*sizeof(PteSrc)));
2157 }
2158 } /* for PTEs */
2159 }
2160 }
2161 else
2162 {
2163 /*
2164 * Big page - 2/4MB.
2165 *
2166 * We'll walk the ram range list in parallel and optimize lookups.
2167 * We will only sync on shadow page table at a time.
2168 */
2169 STAM_COUNTER_INC(CTXSUFF(&pVM->pgm.s.StatSynPT4M));
2170
2171 /**
2172 * @todo It might be more efficient to sync only a part of the 4MB page (similar to what we do for 4kb PDs).
2173 */
2174
2175 /*
2176 * Start by syncing the page directory entry.
2177 */
2178 PdeDst.u = (PdeDst.u & (SHW_PDE_PG_MASK | (X86_PDE_AVL_MASK & ~PGM_PDFLAGS_TRACK_DIRTY)))
2179 | (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
2180
2181# ifdef PGM_SYNC_DIRTY_BIT
2182 /*
2183 * If the page is not flagged as dirty and is writable, then make it read-only
2184 * at PD level, so we can set the dirty bit when the page is modified.
2185 *
2186 * ASSUMES that page access handlers are implemented on page table entry level.
2187 * Thus we will first catch the dirty access and set PDE.D and restart. If
2188 * there is an access handler, we'll trap again and let it work on the problem.
2189 */
2190 /** @todo move the above stuff to a section in the PGM documentation. */
2191 Assert(!(PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY));
2192 if (!PdeSrc.b.u1Dirty && PdeSrc.b.u1Write)
2193 {
2194 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,DirtyPageBig));
2195 PdeDst.u |= PGM_PDFLAGS_TRACK_DIRTY;
2196 PdeDst.b.u1Write = 0;
2197 }
2198# endif /* PGM_SYNC_DIRTY_BIT */
2199 *pPdeDst = PdeDst;
2200
2201 /*
2202 * Fill the shadow page table.
2203 */
2204 /* Get address and flags from the source PDE. */
2205 SHWPTE PteDstBase;
2206 PteDstBase.u = PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT);
2207
2208 /* Loop thru the entries in the shadow PT. */
2209 const RTGCUINTPTR GCPtr = (GCPtrPage >> SHW_PD_SHIFT) << SHW_PD_SHIFT; NOREF(GCPtr);
2210 Log2(("SyncPT: BIG %VGv PdeSrc:{P=%d RW=%d U=%d raw=%08llx} Shw=%VGv GCPhys=%VGp %s\n",
2211 GCPtrPage, PdeSrc.b.u1Present, PdeSrc.b.u1Write, PdeSrc.b.u1User, (uint64_t)PdeSrc.u, GCPtr,
2212 GCPhys, PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
2213 PPGMRAMRANGE pRam = CTXALLSUFF(pVM->pgm.s.pRamRanges);
2214 unsigned iPTDst = 0;
2215 while (iPTDst < ELEMENTS(pPTDst->a))
2216 {
2217 /* Advance ram range list. */
2218 while (pRam && GCPhys > pRam->GCPhysLast)
2219 pRam = CTXALLSUFF(pRam->pNext);
2220 if (pRam && GCPhys >= pRam->GCPhys)
2221 {
2222 unsigned iHCPage = (GCPhys - pRam->GCPhys) >> PAGE_SHIFT;
2223 do
2224 {
2225 /* Make shadow PTE. */
2226 PPGMPAGE pPage = &pRam->aPages[iHCPage];
2227 SHWPTE PteDst;
2228
2229 /* Make sure the RAM has already been allocated. */
2230 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC) /** @todo PAGE FLAGS */
2231 {
2232 if (RT_UNLIKELY(!PGM_PAGE_GET_HCPHYS(pPage)))
2233 {
2234# ifdef IN_RING3
2235 int rc = pgmr3PhysGrowRange(pVM, GCPhys);
2236# else
2237 int rc = CTXALLMID(VMM, CallHost)(pVM, VMMCALLHOST_PGM_RAM_GROW_RANGE, GCPhys);
2238# endif
2239 if (rc != VINF_SUCCESS)
2240 return rc;
2241 }
2242 }
2243
2244 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
2245 {
2246 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
2247 {
2248 PteDst.u = PGM_PAGE_GET_HCPHYS(pPage) | PteDstBase.u;
2249 PteDst.n.u1Write = 0;
2250 }
2251 else
2252 PteDst.u = 0;
2253 }
2254# ifndef IN_RING0
2255 /*
2256 * Assuming kernel code will be marked as supervisor and not as user level and executed
2257 * using a conforming code selector. Don't check for readonly, as that implies the whole
2258 * 4MB can be code or readonly data. Linux enables write access for its large pages.
2259 */
2260 else if ( !PdeSrc.n.u1User
2261 && CSAMDoesPageNeedScanning(pVM, (RTGCPTR)(GCPtr | (iPTDst << SHW_PT_SHIFT))))
2262 PteDst.u = 0;
2263# endif
2264 else
2265 PteDst.u = PGM_PAGE_GET_HCPHYS(pPage) | PteDstBase.u;
2266# ifdef PGMPOOL_WITH_USER_TRACKING
2267 if (PteDst.n.u1Present)
2268 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVM, pShwPage, pPage->HCPhys >> MM_RAM_FLAGS_IDX_SHIFT, pPage, iPTDst); /** @todo PAGE FLAGS */
2269# endif
2270 /* commit it */
2271 pPTDst->a[iPTDst] = PteDst;
2272 Log4(("SyncPT: BIG %VGv PteDst:{P=%d RW=%d U=%d raw=%08llx}%s\n",
2273 (RTGCPTR)(GCPtr | (iPTDst << SHW_PT_SHIFT)), PteDst.n.u1Present, PteDst.n.u1Write, PteDst.n.u1User, (uint64_t)PteDst.u,
2274 PteDst.u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
2275
2276 /* advance */
2277 GCPhys += PAGE_SIZE;
2278 iHCPage++;
2279 iPTDst++;
2280 } while ( iPTDst < ELEMENTS(pPTDst->a)
2281 && GCPhys <= pRam->GCPhysLast);
2282 }
2283 else if (pRam)
2284 {
2285 Log(("Invalid pages at %VGp\n", GCPhys));
2286 do
2287 {
2288 pPTDst->a[iPTDst].u = 0; /* MMIO or invalid page, we must handle them manually. */
2289 GCPhys += PAGE_SIZE;
2290 iPTDst++;
2291 } while ( iPTDst < ELEMENTS(pPTDst->a)
2292 && GCPhys < pRam->GCPhys);
2293 }
2294 else
2295 {
2296 Log(("Invalid pages at %VGp (2)\n", GCPhys));
2297 for ( ; iPTDst < ELEMENTS(pPTDst->a); iPTDst++)
2298 pPTDst->a[iPTDst].u = 0; /* MMIO or invalid page, we must handle them manually. */
2299 }
2300 } /* while more PTEs */
2301 } /* 4KB / 4MB */
2302 }
2303 else
2304 AssertRelease(!PdeDst.n.u1Present);
2305
2306 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,SyncPT), a);
2307# ifdef IN_GC
2308 if (VBOX_FAILURE(rc))
2309 STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncPTFailed));
2310# endif
2311 return rc;
2312
2313#elif PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT
2314
2315 int rc = VINF_SUCCESS;
2316
2317 /*
2318 * Validate input a little bit.
2319 */
2320# if PGM_SHW_TYPE == PGM_TYPE_32BIT
2321 PX86PD pPDDst = pVM->pgm.s.CTXMID(p,32BitPD);
2322# else
2323 PX86PDPAE pPDDst = pVM->pgm.s.CTXMID(ap,PaePDs)[0];
2324# endif
2325 const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT;
2326 PSHWPDE pPdeDst = &pPDDst->a[iPDDst];
2327 SHWPDE PdeDst = *pPdeDst;
2328
2329 Assert(!(PdeDst.u & PGM_PDFLAGS_MAPPING));
2330 Assert(!PdeDst.n.u1Present); /* We're only supposed to call SyncPT on PDE!P and conflicts.*/
2331
2332 GSTPDE PdeSrc;
2333 PdeSrc.au32[0] = 0; /* faked so we don't have to #ifdef everything */
2334 PdeSrc.n.u1Present = 1;
2335 PdeSrc.n.u1Write = 1;
2336 PdeSrc.n.u1Accessed = 1;
2337 PdeSrc.n.u1User = 1;
2338
2339 /*
2340 * Allocate & map the page table.
2341 */
2342 PSHWPT pPTDst;
2343 PPGMPOOLPAGE pShwPage;
2344 RTGCPHYS GCPhys;
2345
2346 /* Virtual address = physical address */
2347 GCPhys = GCPtrPage & X86_PAGE_4K_BASE_MASK_32;
2348 rc = pgmPoolAlloc(pVM, GCPhys, BTH_PGMPOOLKIND_PT_FOR_PT, SHW_POOL_ROOT_IDX, iPDDst, &pShwPage);
2349
2350 if ( rc == VINF_SUCCESS
2351 || rc == VINF_PGM_CACHED_PAGE)
2352 pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
2353 else
2354 AssertMsgFailedReturn(("rc=%Vrc\n", rc), VERR_INTERNAL_ERROR);
2355
2356 PdeDst.u &= X86_PDE_AVL_MASK;
2357 PdeDst.u |= pShwPage->Core.Key;
2358 PdeDst.n.u1Present = 1;
2359 *pPdeDst = PdeDst;
2360
2361 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, (RTGCUINTPTR)GCPtrPage, PGM_SYNC_NR_PAGES, 0 /* page not present */);
2362 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,SyncPT), a);
2363 return rc;
2364
2365#else /* PGM_GST_TYPE == PGM_TYPE_AMD64 */
2366 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
2367 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,SyncPT), a);
2368 return VERR_INTERNAL_ERROR;
2369#endif /* PGM_GST_TYPE == PGM_TYPE_AMD64 */
2370}
2371
2372
2373
2374/**
2375 * Prefetch a page/set of pages.
2376 *
2377 * Typically used to sync commonly used pages before entering raw mode
2378 * after a CR3 reload.
2379 *
2380 * @returns VBox status code.
2381 * @param pVM VM handle.
2382 * @param GCPtrPage Page to invalidate.
2383 */
2384PGM_BTH_DECL(int, PrefetchPage)(PVM pVM, RTGCUINTPTR GCPtrPage)
2385{
2386#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE) && PGM_SHW_TYPE != PGM_TYPE_AMD64
2387 /*
2388 * Check that all Guest levels thru the PDE are present, getting the
2389 * PD and PDE in the processes.
2390 */
2391 int rc = VINF_SUCCESS;
2392# if PGM_WITH_PAGING(PGM_GST_TYPE)
2393# if PGM_GST_TYPE == PGM_TYPE_32BIT
2394 const unsigned iPDSrc = (RTGCUINTPTR)GCPtrPage >> GST_PD_SHIFT;
2395 PGSTPD pPDSrc = CTXSUFF(pVM->pgm.s.pGuestPD);
2396# else /* PAE */
2397 unsigned iPDSrc;
2398 PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVM->pgm.s, GCPtrPage, &iPDSrc);
2399 if (!pPDSrc)
2400 return VINF_SUCCESS; /* not present */
2401# endif
2402 const GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
2403# else
2404 PGSTPD pPDSrc = NULL;
2405 const unsigned iPDSrc = 0;
2406 GSTPDE PdeSrc;
2407
2408 PdeSrc.au32[0] = 0; /* faked so we don't have to #ifdef everything */
2409 PdeSrc.n.u1Present = 1;
2410 PdeSrc.n.u1Write = 1;
2411 PdeSrc.n.u1Accessed = 1;
2412 PdeSrc.n.u1User = 1;
2413# endif
2414
2415# ifdef PGM_SYNC_ACCESSED_BIT
2416 if (PdeSrc.n.u1Present && PdeSrc.n.u1Accessed)
2417# else
2418 if (PdeSrc.n.u1Present)
2419# endif
2420 {
2421# if PGM_SHW_TYPE == PGM_TYPE_32BIT
2422 const X86PDE PdeDst = pVM->pgm.s.CTXMID(p,32BitPD)->a[GCPtrPage >> SHW_PD_SHIFT];
2423# else
2424 const X86PDEPAE PdeDst = pVM->pgm.s.CTXMID(ap,PaePDs)[0]->a[GCPtrPage >> SHW_PD_SHIFT];
2425# endif
2426 if (!(PdeDst.u & PGM_PDFLAGS_MAPPING))
2427 {
2428 if (!PdeDst.n.u1Present)
2429 /** r=bird: This guy will set the A bit on the PDE, probably harmless. */
2430 rc = PGM_BTH_NAME(SyncPT)(pVM, iPDSrc, pPDSrc, GCPtrPage);
2431 else
2432 {
2433 /** @note We used to sync PGM_SYNC_NR_PAGES pages, which triggered assertions in CSAM, because
2434 * R/W attributes of nearby pages were reset. Not sure how that could happen. Anyway, it
2435 * makes no sense to prefetch more than one page.
2436 */
2437 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, GCPtrPage, 1, 0);
2438 if (VBOX_SUCCESS(rc))
2439 rc = VINF_SUCCESS;
2440 }
2441 }
2442 }
2443 return rc;
2444
2445#else /* PGM_GST_TYPE == PGM_TYPE_AMD64 */
2446
2447 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_SHW_TYPE, PGM_GST_TYPE));
2448 return VERR_INTERNAL_ERROR;
2449#endif /* PGM_GST_TYPE == PGM_TYPE_AMD64 */
2450}
2451
2452
2453
2454
2455/**
2456 * Syncs a page during a PGMVerifyAccess() call.
2457 *
2458 * @returns VBox status code (informational included).
2459 * @param GCPtrPage The address of the page to sync.
2460 * @param fPage The effective guest page flags.
2461 * @param uErr The trap error code.
2462 */
2463PGM_BTH_DECL(int, VerifyAccessSyncPage)(PVM pVM, RTGCUINTPTR GCPtrPage, unsigned fPage, unsigned uErr)
2464{
2465 LogFlow(("VerifyAccessSyncPage: GCPtrPage=%VGv fPage=%#x uErr=%#x\n", GCPtrPage, fPage, uErr));
2466
2467#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE) && PGM_SHW_TYPE != PGM_TYPE_AMD64
2468
2469# ifndef IN_RING0
2470 if (!(fPage & X86_PTE_US))
2471 {
2472 /*
2473 * Mark this page as safe.
2474 */
2475 /** @todo not correct for pages that contain both code and data!! */
2476 Log(("CSAMMarkPage %VGv; scanned=%d\n", GCPtrPage, true));
2477 CSAMMarkPage(pVM, (RTGCPTR)GCPtrPage, true);
2478 }
2479# endif
2480 /*
2481 * Get guest PD and index.
2482 */
2483
2484# if PGM_WITH_PAGING(PGM_GST_TYPE)
2485# if PGM_GST_TYPE == PGM_TYPE_32BIT
2486 const unsigned iPDSrc = (RTGCUINTPTR)GCPtrPage >> GST_PD_SHIFT;
2487 PGSTPD pPDSrc = CTXSUFF(pVM->pgm.s.pGuestPD);
2488# else /* PAE */
2489 unsigned iPDSrc;
2490 PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVM->pgm.s, GCPtrPage, &iPDSrc);
2491
2492 if (pPDSrc)
2493 {
2494 Log(("PGMVerifyAccess: access violation for %VGv due to non-present PDPTR\n", GCPtrPage));
2495 return VINF_EM_RAW_GUEST_TRAP;
2496 }
2497# endif
2498# else
2499 PGSTPD pPDSrc = NULL;
2500 const unsigned iPDSrc = 0;
2501# endif
2502 int rc = VINF_SUCCESS;
2503
2504 /*
2505 * First check if the shadow pd is present.
2506 */
2507# if PGM_SHW_TYPE == PGM_TYPE_32BIT
2508 PX86PDE pPdeDst = &pVM->pgm.s.CTXMID(p,32BitPD)->a[GCPtrPage >> SHW_PD_SHIFT];
2509# else
2510 PX86PDEPAE pPdeDst = &pVM->pgm.s.CTXMID(ap,PaePDs)[0]->a[GCPtrPage >> SHW_PD_SHIFT];
2511# endif
2512 if (!pPdeDst->n.u1Present)
2513 {
2514 rc = PGM_BTH_NAME(SyncPT)(pVM, iPDSrc, pPDSrc, GCPtrPage);
2515 AssertRC(rc);
2516 if (rc != VINF_SUCCESS)
2517 return rc;
2518 }
2519
2520# if PGM_WITH_PAGING(PGM_GST_TYPE)
2521 /* Check for dirty bit fault */
2522 rc = PGM_BTH_NAME(CheckPageFault)(pVM, uErr, pPdeDst, &pPDSrc->a[iPDSrc], GCPtrPage);
2523 if (rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT)
2524 Log(("PGMVerifyAccess: success (dirty)\n"));
2525 else
2526 {
2527 GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
2528#else
2529 {
2530 GSTPDE PdeSrc;
2531 PdeSrc.au32[0] = 0; /* faked so we don't have to #ifdef everything */
2532 PdeSrc.n.u1Present = 1;
2533 PdeSrc.n.u1Write = 1;
2534 PdeSrc.n.u1Accessed = 1;
2535 PdeSrc.n.u1User = 1;
2536
2537#endif /* PGM_WITH_PAGING(PGM_GST_TYPE) */
2538 Assert(rc != VINF_EM_RAW_GUEST_TRAP);
2539 if (uErr & X86_TRAP_PF_US)
2540 STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncUser);
2541 else /* supervisor */
2542 STAM_COUNTER_INC(&pVM->pgm.s.StatGCPageOutOfSyncSupervisor);
2543
2544 rc = PGM_BTH_NAME(SyncPage)(pVM, PdeSrc, GCPtrPage, 1, 0);
2545 if (VBOX_SUCCESS(rc))
2546 {
2547 /* Page was successfully synced */
2548 Log2(("PGMVerifyAccess: success (sync)\n"));
2549 rc = VINF_SUCCESS;
2550 }
2551 else
2552 {
2553 Log(("PGMVerifyAccess: access violation for %VGv rc=%d\n", GCPtrPage, rc));
2554 return VINF_EM_RAW_GUEST_TRAP;
2555 }
2556 }
2557 return rc;
2558
2559#else /* PGM_GST_TYPE != PGM_TYPE_32BIT */
2560
2561 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
2562 return VERR_INTERNAL_ERROR;
2563#endif /* PGM_GST_TYPE != PGM_TYPE_32BIT */
2564}
2565
2566
2567#if PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE
2568# if PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_PAE
2569/**
2570 * Figures out which kind of shadow page this guest PDE warrants.
2571 *
2572 * @returns Shadow page kind.
2573 * @param pPdeSrc The guest PDE in question.
2574 * @param cr4 The current guest cr4 value.
2575 */
2576DECLINLINE(PGMPOOLKIND) PGM_BTH_NAME(CalcPageKind)(const GSTPDE *pPdeSrc, uint32_t cr4)
2577{
2578 if (!pPdeSrc->n.u1Size || !(cr4 & X86_CR4_PSE))
2579 return BTH_PGMPOOLKIND_PT_FOR_PT;
2580 //switch (pPdeSrc->u & (X86_PDE4M_RW | X86_PDE4M_US /*| X86_PDE4M_PAE_NX*/))
2581 //{
2582 // case 0:
2583 // return BTH_PGMPOOLKIND_PT_FOR_BIG_RO;
2584 // case X86_PDE4M_RW:
2585 // return BTH_PGMPOOLKIND_PT_FOR_BIG_RW;
2586 // case X86_PDE4M_US:
2587 // return BTH_PGMPOOLKIND_PT_FOR_BIG_US;
2588 // case X86_PDE4M_RW | X86_PDE4M_US:
2589 // return BTH_PGMPOOLKIND_PT_FOR_BIG_RW_US;
2590# if 0
2591 // case X86_PDE4M_PAE_NX:
2592 // return BTH_PGMPOOLKIND_PT_FOR_BIG_NX;
2593 // case X86_PDE4M_RW | X86_PDE4M_PAE_NX:
2594 // return BTH_PGMPOOLKIND_PT_FOR_BIG_RW_NX;
2595 // case X86_PDE4M_US | X86_PDE4M_PAE_NX:
2596 // return BTH_PGMPOOLKIND_PT_FOR_BIG_US_NX;
2597 // case X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PAE_NX:
2598 // return BTH_PGMPOOLKIND_PT_FOR_BIG_RW_US_NX;
2599# endif
2600 return BTH_PGMPOOLKIND_PT_FOR_BIG;
2601 //}
2602}
2603# endif
2604#endif
2605
2606#undef MY_STAM_COUNTER_INC
2607#define MY_STAM_COUNTER_INC(a) do { } while (0)
2608
2609
2610/**
2611 * Syncs the paging hierarchy starting at CR3.
2612 *
2613 * @returns VBox status code, no specials.
2614 * @param pVM The virtual machine.
2615 * @param cr0 Guest context CR0 register
2616 * @param cr3 Guest context CR3 register
2617 * @param cr4 Guest context CR4 register
2618 * @param fGlobal Including global page directories or not
2619 */
2620PGM_BTH_DECL(int, SyncCR3)(PVM pVM, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal)
2621{
2622 if (VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3))
2623 fGlobal = true; /* Change this CR3 reload to be a global one. */
2624
2625 /*
2626 * Update page access handlers.
2627 * The virtual are always flushed, while the physical are only on demand.
2628 * WARNING: We are incorrectly not doing global flushing on Virtual Handler updates. We'll
2629 * have to look into that later because it will have a bad influence on the performance.
2630 * @note SvL: There's no need for that. Just invalidate the virtual range(s).
2631 * bird: Yes, but that won't work for aliases.
2632 */
2633 /** @todo this MUST go away. See #1557. */
2634 STAM_PROFILE_START(&pVM->pgm.s.CTXMID(Stat,SyncCR3Handlers), h);
2635 PGM_GST_NAME(HandlerVirtualUpdate)(pVM, cr4);
2636 STAM_PROFILE_STOP(&pVM->pgm.s.CTXMID(Stat,SyncCR3Handlers), h);
2637
2638#ifdef PGMPOOL_WITH_MONITORING
2639 /*
2640 * When monitoring shadowed pages, we reset the modification counters on CR3 sync.
2641 * Occationally we will have to clear all the shadow page tables because we wanted
2642 * to monitor a page which was mapped by too many shadowed page tables. This operation
2643 * sometimes refered to as a 'lightweight flush'.
2644 */
2645 if (!(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL))
2646 pgmPoolMonitorModifiedClearAll(pVM);
2647 else
2648 {
2649# ifdef IN_RING3
2650 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_CLEAR_PGM_POOL;
2651 pgmPoolClearAll(pVM);
2652# else
2653 LogFlow(("SyncCR3: PGM_SYNC_CLEAR_PGM_POOL is set -> VINF_PGM_SYNC_CR3\n"));
2654 return VINF_PGM_SYNC_CR3;
2655# endif
2656 }
2657#endif
2658
2659 Assert(fGlobal || (cr4 & X86_CR4_PGE));
2660 MY_STAM_COUNTER_INC(fGlobal ? &pVM->pgm.s.CTXMID(Stat,SyncCR3Global) : &pVM->pgm.s.CTXMID(Stat,SyncCR3NotGlobal));
2661
2662#if PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE
2663 /*
2664 * Get page directory addresses.
2665 */
2666# if PGM_SHW_TYPE == PGM_TYPE_32BIT
2667 PX86PDE pPDEDst = &pVM->pgm.s.CTXMID(p,32BitPD)->a[0];
2668# else
2669 PX86PDEPAE pPDEDst = &pVM->pgm.s.CTXMID(ap,PaePDs)[0]->a[0];
2670# endif
2671
2672# if PGM_GST_TYPE == PGM_TYPE_32BIT
2673 PGSTPD pPDSrc = CTXSUFF(pVM->pgm.s.pGuestPD);
2674 Assert(pPDSrc);
2675# ifndef IN_GC
2676 Assert(MMPhysGCPhys2HCVirt(pVM, (RTGCPHYS)(cr3 & GST_CR3_PAGE_MASK), sizeof(*pPDSrc)) == pPDSrc);
2677# endif
2678# endif
2679
2680 /*
2681 * Iterate the page directory.
2682 */
2683 PPGMMAPPING pMapping;
2684 unsigned iPdNoMapping;
2685 const bool fRawR0Enabled = EMIsRawRing0Enabled(pVM);
2686 PPGMPOOL pPool = pVM->pgm.s.CTXSUFF(pPool);
2687
2688 /* Only check mappings if they are supposed to be put into the shadow page table. */
2689 if (pgmMapAreMappingsEnabled(&pVM->pgm.s))
2690 {
2691 pMapping = pVM->pgm.s.CTXALLSUFF(pMappings);
2692 iPdNoMapping = (pMapping) ? (pMapping->GCPtr >> GST_PD_SHIFT) : ~0U;
2693 }
2694 else
2695 {
2696 pMapping = 0;
2697 iPdNoMapping = ~0U;
2698 }
2699# if PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64
2700 for (unsigned iPDPTE = 0; iPDPTE < GST_PDPE_ENTRIES; iPDPTE++)
2701 {
2702 unsigned iPDSrc;
2703# if PGM_SHW_TYPE == PGM_TYPE_PAE
2704 PX86PDPAE pPDPAE = pVM->pgm.s.CTXMID(ap,PaePDs)[0];
2705# else
2706 AssertFailed(); /* @todo */
2707 PX86PDPE pPDPAE = pVM->pgm.s.CTXMID(ap,PaePDs)[iPDPTE * X86_PG_AMD64_ENTRIES];
2708# endif
2709 PX86PDEPAE pPDEDst = &pPDPAE->a[iPDPTE * X86_PG_PAE_ENTRIES];
2710 PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVM->pgm.s, iPDPTE << X86_PDPT_SHIFT, &iPDSrc);
2711
2712 if (pPDSrc == NULL)
2713 {
2714 /* PDPT not present */
2715 if (pVM->pgm.s.CTXMID(p,PaePDPT)->a[iPDPTE].n.u1Present)
2716 {
2717 for (unsigned iPD = 0; iPD < ELEMENTS(pPDSrc->a); iPD++)
2718 {
2719 if ( pPDEDst[iPD].n.u1Present
2720 && !(pPDEDst[iPD].u & PGM_PDFLAGS_MAPPING))
2721 {
2722 pgmPoolFreeByPage(pPool, pgmPoolGetPage(pPool, pPDEDst[iPD].u & SHW_PDE_PG_MASK), SHW_POOL_ROOT_IDX, iPDPTE * X86_PG_PAE_ENTRIES + iPD);
2723 pPDEDst[iPD].u = 0;
2724 }
2725 }
2726 }
2727 if (!(pVM->pgm.s.CTXMID(p,PaePDPT)->a[iPDPTE].u & PGM_PLXFLAGS_MAPPING))
2728 pVM->pgm.s.CTXMID(p,PaePDPT)->a[iPDPTE].n.u1Present = 0;
2729 continue;
2730 }
2731# else /* PGM_GST_TYPE != PGM_TYPE_PAE && PGM_GST_TYPE != PGM_TYPE_AMD64 */
2732 {
2733# endif /* PGM_GST_TYPE != PGM_TYPE_PAE && PGM_GST_TYPE != PGM_TYPE_AMD64 */
2734 for (unsigned iPD = 0; iPD < ELEMENTS(pPDSrc->a); iPD++)
2735 {
2736# if PGM_SHW_TYPE == PGM_TYPE_32BIT
2737 Assert(&pVM->pgm.s.CTXMID(p,32BitPD)->a[iPD] == pPDEDst);
2738# elif PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2739 AssertMsg(&pVM->pgm.s.CTXMID(ap,PaePDs)[iPD * 2 / 512]->a[iPD * 2 % 512] == pPDEDst, ("%p vs %p\n", &pVM->pgm.s.CTXMID(ap,PaePDs)[iPD * 2 / 512]->a[iPD * 2 % 512], pPDEDst));
2740# endif
2741 register GSTPDE PdeSrc = pPDSrc->a[iPD];
2742 if ( PdeSrc.n.u1Present
2743 && (PdeSrc.n.u1User || fRawR0Enabled))
2744 {
2745# if ( PGM_GST_TYPE == PGM_TYPE_32BIT \
2746 || PGM_GST_TYPE == PGM_TYPE_PAE) \
2747 && !defined(PGM_WITHOUT_MAPPINGS)
2748
2749 /*
2750 * Check for conflicts with GC mappings.
2751 */
2752# if PGM_GST_TYPE == PGM_TYPE_PAE
2753 if (iPD + iPDPTE * X86_PG_PAE_ENTRIES == iPdNoMapping)
2754# else
2755 if (iPD == iPdNoMapping)
2756# endif
2757 {
2758 if (pVM->pgm.s.fMappingsFixed)
2759 {
2760 /* It's fixed, just skip the mapping. */
2761 const unsigned cPTs = pMapping->cb >> GST_PD_SHIFT;
2762 iPD += cPTs - 1;
2763 pPDEDst += cPTs + (PGM_GST_TYPE != PGM_SHW_TYPE) * cPTs; /* Only applies to the pae shadow and 32 bits guest case */
2764 pMapping = pMapping->CTXALLSUFF(pNext);
2765 iPdNoMapping = pMapping ? pMapping->GCPtr >> GST_PD_SHIFT : ~0U;
2766 continue;
2767 }
2768# ifdef IN_RING3
2769# if PGM_GST_TYPE == PGM_TYPE_32BIT
2770 int rc = pgmR3SyncPTResolveConflict(pVM, pMapping, pPDSrc, iPD << GST_PD_SHIFT);
2771# elif PGM_GST_TYPE == PGM_TYPE_PAE
2772 int rc = pgmR3SyncPTResolveConflictPAE(pVM, pMapping, (iPDPTE << GST_PDPT_SHIFT) + (iPD << GST_PD_SHIFT));
2773# endif
2774 if (VBOX_FAILURE(rc))
2775 return rc;
2776
2777 /*
2778 * Update iPdNoMapping and pMapping.
2779 */
2780 pMapping = pVM->pgm.s.pMappingsR3;
2781 while (pMapping && pMapping->GCPtr < (iPD << GST_PD_SHIFT))
2782 pMapping = pMapping->pNextR3;
2783 iPdNoMapping = pMapping ? pMapping->GCPtr >> GST_PD_SHIFT : ~0U;
2784# else
2785 LogFlow(("SyncCR3: detected conflict -> VINF_PGM_SYNC_CR3\n"));
2786 return VINF_PGM_SYNC_CR3;
2787# endif
2788 }
2789# else /* (PGM_GST_TYPE != PGM_TYPE_32BIT && PGM_GST_TYPE != PGM_TYPE_PAE) || PGM_WITHOUT_MAPPINGS */
2790 Assert(!pgmMapAreMappingsEnabled(&pVM->pgm.s));
2791# endif /* (PGM_GST_TYPE != PGM_TYPE_32BIT && PGM_GST_TYPE != PGM_TYPE_PAE) || PGM_WITHOUT_MAPPINGS */
2792 /*
2793 * Sync page directory entry.
2794 *
2795 * The current approach is to allocated the page table but to set
2796 * the entry to not-present and postpone the page table synching till
2797 * it's actually used.
2798 */
2799# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2800 for (unsigned i = 0, iPdShw = iPD * 2; i < 2; i++, iPdShw++) /* pray that the compiler unrolls this */
2801# elif PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64
2802 const unsigned iPdShw = iPD + iPDPTE * X86_PG_PAE_ENTRIES; NOREF(iPdShw);
2803# else
2804 const unsigned iPdShw = iPD; NOREF(iPdShw);
2805# endif
2806 {
2807 SHWPDE PdeDst = *pPDEDst;
2808 if (PdeDst.n.u1Present)
2809 {
2810 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, PdeDst.u & SHW_PDE_PG_MASK);
2811 RTGCPHYS GCPhys;
2812 if ( !PdeSrc.b.u1Size
2813 || !(cr4 & X86_CR4_PSE))
2814 {
2815 GCPhys = PdeSrc.u & GST_PDE_PG_MASK;
2816# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2817 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
2818 GCPhys |= i * (PAGE_SIZE / 2);
2819# endif
2820 }
2821 else
2822 {
2823 GCPhys = PdeSrc.u & GST_PDE_BIG_PG_MASK;
2824# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2825 /* Select the right PDE as we're emulating a 4MB page directory with two 2 MB shadow PDEs.*/
2826 GCPhys |= i * X86_PAGE_2M_SIZE;
2827# endif
2828 }
2829
2830 if ( pShwPage->GCPhys == GCPhys
2831 && pShwPage->enmKind == PGM_BTH_NAME(CalcPageKind)(&PdeSrc, cr4)
2832 && ( pShwPage->fCached
2833 || ( !fGlobal
2834 && ( false
2835# ifdef PGM_SKIP_GLOBAL_PAGEDIRS_ON_NONGLOBAL_FLUSH
2836 || ( (PdeSrc.u & (X86_PDE4M_PS | X86_PDE4M_G)) == (X86_PDE4M_PS | X86_PDE4M_G)
2837 && (cr4 & (X86_CR4_PGE | X86_CR4_PSE)) == (X86_CR4_PGE | X86_CR4_PSE)) /* global 2/4MB page. */
2838 || ( !pShwPage->fSeenNonGlobal
2839 && (cr4 & X86_CR4_PGE))
2840# endif
2841 )
2842 )
2843 )
2844 && ( (PdeSrc.u & (X86_PDE_US | X86_PDE_RW)) == (PdeDst.u & (X86_PDE_US | X86_PDE_RW))
2845 || ( (cr4 & X86_CR4_PSE)
2846 && ((PdeSrc.u & (X86_PDE_US | X86_PDE4M_PS | X86_PDE4M_D)) | PGM_PDFLAGS_TRACK_DIRTY)
2847 == ((PdeDst.u & (X86_PDE_US | X86_PDE_RW | PGM_PDFLAGS_TRACK_DIRTY)) | X86_PDE4M_PS))
2848 )
2849 )
2850 {
2851# ifdef VBOX_WITH_STATISTICS
2852 if ( !fGlobal
2853 && (PdeSrc.u & (X86_PDE4M_PS | X86_PDE4M_G)) == (X86_PDE4M_PS | X86_PDE4M_G)
2854 && (cr4 & (X86_CR4_PGE | X86_CR4_PSE)) == (X86_CR4_PGE | X86_CR4_PSE))
2855 MY_STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncCR3DstSkippedGlobalPD));
2856 else if (!fGlobal && !pShwPage->fSeenNonGlobal && (cr4 & X86_CR4_PGE))
2857 MY_STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncCR3DstSkippedGlobalPT));
2858 else
2859 MY_STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncCR3DstCacheHit));
2860# endif /* VBOX_WITH_STATISTICS */
2861 /** @todo a replacement strategy isn't really needed unless we're using a very small pool < 512 pages.
2862 * The whole ageing stuff should be put in yet another set of #ifdefs. For now, let's just skip it. */
2863 //# ifdef PGMPOOL_WITH_CACHE
2864 // pgmPoolCacheUsed(pPool, pShwPage);
2865 //# endif
2866 }
2867 else
2868 {
2869 pgmPoolFreeByPage(pPool, pShwPage, SHW_POOL_ROOT_IDX, iPdShw);
2870 pPDEDst->u = 0;
2871 MY_STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncCR3DstFreed));
2872 }
2873 }
2874 else
2875 MY_STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncCR3DstNotPresent));
2876 pPDEDst++;
2877 }
2878 }
2879# if PGM_GST_TYPE == PGM_TYPE_PAE
2880 else if (iPD + iPDPTE * X86_PG_PAE_ENTRIES != iPdNoMapping)
2881# else
2882 else if (iPD != iPdNoMapping)
2883# endif
2884 {
2885 /*
2886 * Check if there is any page directory to mark not present here.
2887 */
2888# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2889 for (unsigned i = 0, iPdShw = iPD * 2; i < 2; i++, iPdShw++) /* pray that the compiler unrolls this */
2890# elif PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64
2891 const unsigned iPdShw = iPD + iPDPTE * X86_PG_PAE_ENTRIES; NOREF(iPdShw);
2892# else
2893 const unsigned iPdShw = iPD; NOREF(iPdShw);
2894# endif
2895 {
2896 if (pPDEDst->n.u1Present)
2897 {
2898 pgmPoolFreeByPage(pPool, pgmPoolGetPage(pPool, pPDEDst->u & SHW_PDE_PG_MASK), SHW_POOL_ROOT_IDX, iPdShw);
2899 pPDEDst->u = 0;
2900 MY_STAM_COUNTER_INC(&pVM->pgm.s.CTXMID(Stat,SyncCR3DstFreedSrcNP));
2901 }
2902 pPDEDst++;
2903 }
2904 }
2905 else
2906 {
2907# if ( PGM_GST_TYPE == PGM_TYPE_32BIT \
2908 || PGM_GST_TYPE == PGM_TYPE_PAE) \
2909 && !defined(PGM_WITHOUT_MAPPINGS)
2910
2911 const unsigned cPTs = pMapping->cb >> GST_PD_SHIFT;
2912
2913 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
2914 if (pVM->pgm.s.fMappingsFixed)
2915 {
2916 /* It's fixed, just skip the mapping. */
2917 pMapping = pMapping->CTXALLSUFF(pNext);
2918 iPdNoMapping = pMapping ? pMapping->GCPtr >> GST_PD_SHIFT : ~0U;
2919 }
2920 else
2921 {
2922 /*
2923 * Check for conflicts for subsequent pagetables
2924 * and advance to the next mapping.
2925 */
2926 iPdNoMapping = ~0U;
2927 unsigned iPT = cPTs;
2928 while (iPT-- > 1)
2929 {
2930 if ( pPDSrc->a[iPD + iPT].n.u1Present
2931 && (pPDSrc->a[iPD + iPT].n.u1User || fRawR0Enabled))
2932 {
2933# ifdef IN_RING3
2934# if PGM_GST_TYPE == PGM_TYPE_32BIT
2935 int rc = pgmR3SyncPTResolveConflict(pVM, pMapping, pPDSrc, iPD << GST_PD_SHIFT);
2936# elif PGM_GST_TYPE == PGM_TYPE_PAE
2937 int rc = pgmR3SyncPTResolveConflictPAE(pVM, pMapping, (iPDPTE << GST_PDPT_SHIFT) + (iPD << GST_PD_SHIFT));
2938# endif
2939 if (VBOX_FAILURE(rc))
2940 return rc;
2941
2942 /*
2943 * Update iPdNoMapping and pMapping.
2944 */
2945 pMapping = pVM->pgm.s.CTXALLSUFF(pMappings);
2946 while (pMapping && pMapping->GCPtr < (iPD << GST_PD_SHIFT))
2947 pMapping = pMapping->CTXALLSUFF(pNext);
2948 iPdNoMapping = pMapping ? pMapping->GCPtr >> GST_PD_SHIFT : ~0U;
2949 break;
2950# else
2951 LogFlow(("SyncCR3: detected conflict -> VINF_PGM_SYNC_CR3\n"));
2952 return VINF_PGM_SYNC_CR3;
2953# endif
2954 }
2955 }
2956 if (iPdNoMapping == ~0U && pMapping)
2957 {
2958 pMapping = pMapping->CTXALLSUFF(pNext);
2959 if (pMapping)
2960 iPdNoMapping = pMapping->GCPtr >> GST_PD_SHIFT;
2961 }
2962 }
2963
2964 /* advance. */
2965 iPD += cPTs - 1;
2966 pPDEDst += cPTs + (PGM_GST_TYPE != PGM_SHW_TYPE) * cPTs; /* Only applies to the pae shadow and 32 bits guest case */
2967# if PGM_GST_TYPE != PGM_SHW_TYPE
2968 AssertCompile(PGM_GST_TYPE == PGM_TYPE_32BIT && PGM_SHW_TYPE == PGM_TYPE_PAE);
2969# endif
2970# else /* (PGM_GST_TYPE != PGM_TYPE_32BIT && PGM_GST_TYPE != PGM_TYPE_PAE) || PGM_WITHOUT_MAPPINGS */
2971 Assert(!pgmMapAreMappingsEnabled(&pVM->pgm.s));
2972# endif /* (PGM_GST_TYPE != PGM_TYPE_32BIT && PGM_GST_TYPE != PGM_TYPE_PAE) || PGM_WITHOUT_MAPPINGS */
2973 }
2974
2975 } /* for iPD */
2976 } /* for each PDPTE (PAE) */
2977
2978 return VINF_SUCCESS;
2979
2980#elif PGM_GST_TYPE == PGM_TYPE_AMD64
2981//# error not implemented
2982 return VERR_INTERNAL_ERROR;
2983#else /* guest real and protected mode */
2984 return VINF_SUCCESS;
2985#endif
2986}
2987
2988
2989
2990
2991#ifdef VBOX_STRICT
2992#ifdef IN_GC
2993# undef AssertMsgFailed
2994# define AssertMsgFailed Log
2995#endif
2996#ifdef IN_RING3
2997# include <VBox/dbgf.h>
2998
2999/**
3000 * Dumps a page table hierarchy use only physical addresses and cr4/lm flags.
3001 *
3002 * @returns VBox status code (VINF_SUCCESS).
3003 * @param pVM The VM handle.
3004 * @param cr3 The root of the hierarchy.
3005 * @param crr The cr4, only PAE and PSE is currently used.
3006 * @param fLongMode Set if long mode, false if not long mode.
3007 * @param cMaxDepth Number of levels to dump.
3008 * @param pHlp Pointer to the output functions.
3009 */
3010__BEGIN_DECLS
3011PGMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint32_t cr3, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp);
3012__END_DECLS
3013
3014#endif
3015
3016/**
3017 * Checks that the shadow page table is in sync with the guest one.
3018 *
3019 * @returns The number of errors.
3020 * @param pVM The virtual machine.
3021 * @param cr3 Guest context CR3 register
3022 * @param cr4 Guest context CR4 register
3023 * @param GCPtr Where to start. Defaults to 0.
3024 * @param cb How much to check. Defaults to everything.
3025 */
3026PGM_BTH_DECL(unsigned, AssertCR3)(PVM pVM, uint64_t cr3, uint64_t cr4, RTGCUINTPTR GCPtr, RTGCUINTPTR cb)
3027{
3028 unsigned cErrors = 0;
3029
3030#if PGM_GST_TYPE == PGM_TYPE_32BIT \
3031 || PGM_GST_TYPE == PGM_TYPE_PAE
3032
3033 PPGM pPGM = &pVM->pgm.s;
3034 RTGCPHYS GCPhysGst; /* page address derived from the guest page tables. */
3035 RTHCPHYS HCPhysShw; /* page address derived from the shadow page tables. */
3036# ifndef IN_RING0
3037 RTHCPHYS HCPhys; /* general usage. */
3038# endif
3039 int rc;
3040
3041 /*
3042 * Check that the Guest CR3 and all its mappings are correct.
3043 */
3044 AssertMsgReturn(pPGM->GCPhysCR3 == (cr3 & GST_CR3_PAGE_MASK),
3045 ("Invalid GCPhysCR3=%VGp cr3=%VGp\n", pPGM->GCPhysCR3, (RTGCPHYS)cr3),
3046 false);
3047# ifndef IN_RING0
3048# if PGM_GST_TYPE == PGM_TYPE_32BIT
3049 rc = PGMShwGetPage(pVM, pPGM->pGuestPDGC, NULL, &HCPhysShw);
3050# else
3051 rc = PGMShwGetPage(pVM, pPGM->pGstPaePDPTGC, NULL, &HCPhysShw);
3052# endif
3053 AssertRCReturn(rc, 1);
3054 HCPhys = NIL_RTHCPHYS;
3055 rc = pgmRamGCPhys2HCPhys(pPGM, cr3 & GST_CR3_PAGE_MASK, &HCPhys);
3056 AssertMsgReturn(HCPhys == HCPhysShw, ("HCPhys=%VHp HCPhyswShw=%VHp (cr3)\n", HCPhys, HCPhysShw), false);
3057# if PGM_GST_TYPE == PGM_TYPE_32BIT && defined(IN_RING3)
3058 RTGCPHYS GCPhys;
3059 rc = PGMR3DbgHCPtr2GCPhys(pVM, pPGM->pGuestPDHC, &GCPhys);
3060 AssertRCReturn(rc, 1);
3061 AssertMsgReturn((cr3 & GST_CR3_PAGE_MASK) == GCPhys, ("GCPhys=%VGp cr3=%VGp\n", GCPhys, (RTGCPHYS)cr3), false);
3062# endif
3063#endif /* !IN_RING0 */
3064
3065# if PGM_GST_TYPE == PGM_TYPE_32BIT
3066 const GSTPD *pPDSrc = CTXSUFF(pPGM->pGuestPD);
3067# endif
3068
3069 /*
3070 * Get and check the Shadow CR3.
3071 */
3072# if PGM_SHW_TYPE == PGM_TYPE_32BIT
3073 const X86PD *pPDDst = pPGM->CTXMID(p,32BitPD);
3074 unsigned cPDEs = ELEMENTS(pPDDst->a);
3075# else
3076 const X86PDPAE *pPDDst = pPGM->CTXMID(ap,PaePDs[0]); /* use it as a 2048 entry PD */
3077 unsigned cPDEs = ELEMENTS(pPDDst->a) * ELEMENTS(pPGM->apHCPaePDs);
3078# endif
3079 if (cb != ~(RTGCUINTPTR)0)
3080 cPDEs = RT_MIN(cb >> SHW_PD_SHIFT, 1);
3081
3082/** @todo call the other two PGMAssert*() functions. */
3083
3084# if PGM_GST_TYPE == PGM_TYPE_PAE
3085 /*
3086 * Check the 4 PDPTs too.
3087 */
3088 for (unsigned i = 0; i < 4; i++)
3089 {
3090 RTHCPTR HCPtr;
3091 RTHCPHYS HCPhys;
3092 RTGCPHYS GCPhys = pVM->pgm.s.CTXSUFF(pGstPaePDPT)->a[i].u & X86_PDPE_PG_MASK;
3093 int rc2 = pgmRamGCPhys2HCPtrAndHCPhysWithFlags(&pVM->pgm.s, GCPhys, &HCPtr, &HCPhys);
3094 if (VBOX_SUCCESS(rc2))
3095 {
3096 AssertMsg( pVM->pgm.s.apGstPaePDsHC[i] == (R3R0PTRTYPE(PX86PDPAE))HCPtr
3097 && pVM->pgm.s.aGCPhysGstPaePDs[i] == GCPhys,
3098 ("idx %d apGstPaePDsHC %VHv vs %VHv aGCPhysGstPaePDs %VGp vs %VGp\n",
3099 i, pVM->pgm.s.apGstPaePDsHC[i], HCPtr, pVM->pgm.s.aGCPhysGstPaePDs[i], GCPhys));
3100 }
3101 }
3102# endif
3103
3104 /*
3105 * Iterate the shadow page directory.
3106 */
3107 GCPtr = (GCPtr >> SHW_PD_SHIFT) << SHW_PD_SHIFT;
3108 unsigned iPDDst = GCPtr >> SHW_PD_SHIFT;
3109 cPDEs += iPDDst;
3110 for (;
3111 iPDDst < cPDEs;
3112 iPDDst++, GCPtr += _4G / cPDEs)
3113 {
3114# if PGM_GST_TYPE == PGM_TYPE_PAE
3115 uint32_t iPDSrc;
3116 PGSTPD pPDSrc = pgmGstGetPaePDPtr(pPGM, (RTGCUINTPTR)GCPtr, &iPDSrc);
3117 if (!pPDSrc)
3118 {
3119 AssertMsg(!pVM->pgm.s.CTXSUFF(pGstPaePDPT)->a[(GCPtr >> GST_PDPT_SHIFT) & GST_PDPT_MASK].n.u1Present, ("Guest PDTPR not present, shadow PDPTR %VX64\n", pVM->pgm.s.CTXSUFF(pGstPaePDPT)->a[(GCPtr >> GST_PDPT_SHIFT) & GST_PDPT_MASK].u));
3120 continue;
3121 }
3122#endif
3123
3124 const SHWPDE PdeDst = pPDDst->a[iPDDst];
3125 if (PdeDst.u & PGM_PDFLAGS_MAPPING)
3126 {
3127 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
3128 if ((PdeDst.u & X86_PDE_AVL_MASK) != PGM_PDFLAGS_MAPPING)
3129 {
3130 AssertMsgFailed(("Mapping shall only have PGM_PDFLAGS_MAPPING set! PdeDst.u=%#RX64\n", (uint64_t)PdeDst.u));
3131 cErrors++;
3132 continue;
3133 }
3134 }
3135 else if ( (PdeDst.u & X86_PDE_P)
3136 || ((PdeDst.u & (X86_PDE_P | PGM_PDFLAGS_TRACK_DIRTY)) == (X86_PDE_P | PGM_PDFLAGS_TRACK_DIRTY))
3137 )
3138 {
3139 HCPhysShw = PdeDst.u & SHW_PDE_PG_MASK;
3140 PPGMPOOLPAGE pPoolPage = pgmPoolGetPageByHCPhys(pVM, HCPhysShw);
3141 if (!pPoolPage)
3142 {
3143 AssertMsgFailed(("Invalid page table address %VGp at %VGv! PdeDst=%#RX64\n",
3144 HCPhysShw, GCPtr, (uint64_t)PdeDst.u));
3145 cErrors++;
3146 continue;
3147 }
3148 const SHWPT *pPTDst = (const SHWPT *)PGMPOOL_PAGE_2_PTR(pVM, pPoolPage);
3149
3150 if (PdeDst.u & (X86_PDE4M_PWT | X86_PDE4M_PCD))
3151 {
3152 AssertMsgFailed(("PDE flags PWT and/or PCD is set at %VGv! These flags are not virtualized! PdeDst=%#RX64\n",
3153 GCPtr, (uint64_t)PdeDst.u));
3154 cErrors++;
3155 }
3156
3157 if (PdeDst.u & (X86_PDE4M_G | X86_PDE4M_D))
3158 {
3159 AssertMsgFailed(("4K PDE reserved flags at %VGv! PdeDst=%#RX64\n",
3160 GCPtr, (uint64_t)PdeDst.u));
3161 cErrors++;
3162 }
3163
3164 const GSTPDE PdeSrc = pPDSrc->a[(iPDDst >> (GST_PD_SHIFT - SHW_PD_SHIFT)) & GST_PD_MASK];
3165 if (!PdeSrc.n.u1Present)
3166 {
3167 AssertMsgFailed(("Guest PDE at %VGv is not present! PdeDst=%#RX64 PdeSrc=%#RX64\n",
3168 GCPtr, (uint64_t)PdeDst.u, (uint64_t)PdeSrc.u));
3169 cErrors++;
3170 continue;
3171 }
3172
3173 if ( !PdeSrc.b.u1Size
3174 || !(cr4 & X86_CR4_PSE))
3175 {
3176 GCPhysGst = PdeSrc.u & GST_PDE_PG_MASK;
3177# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
3178 GCPhysGst |= (iPDDst & 1) * (PAGE_SIZE / 2);
3179# endif
3180 }
3181 else
3182 {
3183# if PGM_GST_TYPE == PGM_TYPE_32BIT
3184 if (PdeSrc.u & X86_PDE4M_PG_HIGH_MASK)
3185 {
3186 AssertMsgFailed(("Guest PDE at %VGv is using PSE36 or similar! PdeSrc=%#RX64\n",
3187 GCPtr, (uint64_t)PdeSrc.u));
3188 cErrors++;
3189 continue;
3190 }
3191# endif
3192 GCPhysGst = PdeSrc.u & GST_PDE_BIG_PG_MASK;
3193# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
3194 GCPhysGst |= GCPtr & RT_BIT(X86_PAGE_2M_SHIFT);
3195# endif
3196 }
3197
3198 if ( pPoolPage->enmKind
3199 != (!PdeSrc.b.u1Size || !(cr4 & X86_CR4_PSE) ? BTH_PGMPOOLKIND_PT_FOR_PT : BTH_PGMPOOLKIND_PT_FOR_BIG))
3200 {
3201 AssertMsgFailed(("Invalid shadow page table kind %d at %VGv! PdeSrc=%#RX64\n",
3202 pPoolPage->enmKind, GCPtr, (uint64_t)PdeSrc.u));
3203 cErrors++;
3204 }
3205
3206 PPGMPAGE pPhysPage = pgmPhysGetPage(pPGM, GCPhysGst);
3207 if (!pPhysPage)
3208 {
3209 AssertMsgFailed(("Cannot find guest physical address %VGp in the PDE at %VGv! PdeSrc=%#RX64\n",
3210 GCPhysGst, GCPtr, (uint64_t)PdeSrc.u));
3211 cErrors++;
3212 continue;
3213 }
3214
3215 if (GCPhysGst != pPoolPage->GCPhys)
3216 {
3217 AssertMsgFailed(("GCPhysGst=%VGp != pPage->GCPhys=%VGp at %VGv\n",
3218 GCPhysGst, pPoolPage->GCPhys, GCPtr));
3219 cErrors++;
3220 continue;
3221 }
3222
3223 if ( !PdeSrc.b.u1Size
3224 || !(cr4 & X86_CR4_PSE))
3225 {
3226 /*
3227 * Page Table.
3228 */
3229 const GSTPT *pPTSrc;
3230 rc = PGM_GCPHYS_2_PTR(pVM, GCPhysGst & ~(RTGCPHYS)(PAGE_SIZE - 1), &pPTSrc);
3231 if (VBOX_FAILURE(rc))
3232 {
3233 AssertMsgFailed(("Cannot map/convert guest physical address %VGp in the PDE at %VGv! PdeSrc=%#RX64\n",
3234 GCPhysGst, GCPtr, (uint64_t)PdeSrc.u));
3235 cErrors++;
3236 continue;
3237 }
3238 if ( (PdeSrc.u & (X86_PDE_P | X86_PDE_US | X86_PDE_RW/* | X86_PDE_A*/))
3239 != (PdeDst.u & (X86_PDE_P | X86_PDE_US | X86_PDE_RW/* | X86_PDE_A*/)))
3240 {
3241 /// @todo We get here a lot on out-of-sync CR3 entries. The access handler should zap them to avoid false alarms here!
3242 // (This problem will go away when/if we shadow multiple CR3s.)
3243 AssertMsgFailed(("4K PDE flags mismatch at %VGv! PdeSrc=%#RX64 PdeDst=%#RX64\n",
3244 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
3245 cErrors++;
3246 continue;
3247 }
3248 if (PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY)
3249 {
3250 AssertMsgFailed(("4K PDEs cannot have PGM_PDFLAGS_TRACK_DIRTY set! GCPtr=%VGv PdeDst=%#RX64\n",
3251 GCPtr, (uint64_t)PdeDst.u));
3252 cErrors++;
3253 continue;
3254 }
3255
3256 /* iterate the page table. */
3257# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
3258 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
3259 const unsigned offPTSrc = ((GCPtr >> SHW_PD_SHIFT) & 1) * 512;
3260# else
3261 const unsigned offPTSrc = 0;
3262# endif
3263 for (unsigned iPT = 0, off = 0;
3264 iPT < ELEMENTS(pPTDst->a);
3265 iPT++, off += PAGE_SIZE)
3266 {
3267 const SHWPTE PteDst = pPTDst->a[iPT];
3268
3269 /* skip not-present entries. */
3270 if (!(PteDst.u & (X86_PTE_P | PGM_PTFLAGS_TRACK_DIRTY))) /** @todo deal with ALL handlers and CSAM !P pages! */
3271 continue;
3272 Assert(PteDst.n.u1Present);
3273
3274 const GSTPTE PteSrc = pPTSrc->a[iPT + offPTSrc];
3275 if (!PteSrc.n.u1Present)
3276 {
3277#ifdef IN_RING3
3278 PGMAssertHandlerAndFlagsInSync(pVM);
3279 PGMR3DumpHierarchyGC(pVM, cr3, cr4, (PdeSrc.u & GST_PDE_PG_MASK));
3280#endif
3281 AssertMsgFailed(("Out of sync (!P) PTE at %VGv! PteSrc=%#RX64 PteDst=%#RX64 pPTSrc=%VGv iPTSrc=%x PdeSrc=%x physpte=%VGp\n",
3282 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u, pPTSrc, iPT + offPTSrc, PdeSrc.au32[0],
3283 (PdeSrc.u & GST_PDE_PG_MASK) + (iPT + offPTSrc)*sizeof(PteSrc)));
3284 cErrors++;
3285 continue;
3286 }
3287
3288 uint64_t fIgnoreFlags = GST_PTE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_G | X86_PTE_D | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_PAT;
3289# if 1 /** @todo sync accessed bit properly... */
3290 fIgnoreFlags |= X86_PTE_A;
3291# endif
3292
3293 /* match the physical addresses */
3294 HCPhysShw = PteDst.u & SHW_PTE_PG_MASK;
3295 GCPhysGst = PteSrc.u & GST_PTE_PG_MASK;
3296
3297# ifdef IN_RING3
3298 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysGst, &HCPhys);
3299 if (VBOX_FAILURE(rc))
3300 {
3301 if (HCPhysShw != MMR3PageDummyHCPhys(pVM))
3302 {
3303 AssertMsgFailed(("Cannot find guest physical address %VGp at %VGv! PteSrc=%#RX64 PteDst=%#RX64\n",
3304 GCPhysGst, GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3305 cErrors++;
3306 continue;
3307 }
3308 }
3309 else if (HCPhysShw != (HCPhys & SHW_PTE_PG_MASK))
3310 {
3311 AssertMsgFailed(("Out of sync (phys) at %VGv! HCPhysShw=%VHp HCPhys=%VHp GCPhysGst=%VGp PteSrc=%#RX64 PteDst=%#RX64\n",
3312 GCPtr + off, HCPhysShw, HCPhys, GCPhysGst, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3313 cErrors++;
3314 continue;
3315 }
3316# endif
3317
3318 pPhysPage = pgmPhysGetPage(pPGM, GCPhysGst);
3319 if (!pPhysPage)
3320 {
3321# ifdef IN_RING3 /** @todo make MMR3PageDummyHCPhys an 'All' function! */
3322 if (HCPhysShw != MMR3PageDummyHCPhys(pVM))
3323 {
3324 AssertMsgFailed(("Cannot find guest physical address %VGp at %VGv! PteSrc=%#RX64 PteDst=%#RX64\n",
3325 GCPhysGst, GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3326 cErrors++;
3327 continue;
3328 }
3329# endif
3330 if (PteDst.n.u1Write)
3331 {
3332 AssertMsgFailed(("Invalid guest page at %VGv is writable! GCPhysGst=%VGp PteSrc=%#RX64 PteDst=%#RX64\n",
3333 GCPtr + off, GCPhysGst, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3334 cErrors++;
3335 }
3336 fIgnoreFlags |= X86_PTE_RW;
3337 }
3338 else if (HCPhysShw != (PGM_PAGE_GET_HCPHYS(pPhysPage) & SHW_PTE_PG_MASK))
3339 {
3340 AssertMsgFailed(("Out of sync (phys) at %VGv! HCPhysShw=%VHp HCPhys=%VHp GCPhysGst=%VGp PteSrc=%#RX64 PteDst=%#RX64\n",
3341 GCPtr + off, HCPhysShw, pPhysPage->HCPhys, GCPhysGst, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3342 cErrors++;
3343 continue;
3344 }
3345
3346 /* flags */
3347 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPhysPage))
3348 {
3349 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPhysPage))
3350 {
3351 if (PteDst.n.u1Write)
3352 {
3353 AssertMsgFailed(("WRITE access flagged at %VGv but the page is writable! HCPhys=%VGv PteSrc=%#RX64 PteDst=%#RX64\n",
3354 GCPtr + off, pPhysPage->HCPhys, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3355 cErrors++;
3356 continue;
3357 }
3358 fIgnoreFlags |= X86_PTE_RW;
3359 }
3360 else
3361 {
3362 if (PteDst.n.u1Present)
3363 {
3364 AssertMsgFailed(("ALL access flagged at %VGv but the page is present! HCPhys=%VHp PteSrc=%#RX64 PteDst=%#RX64\n",
3365 GCPtr + off, pPhysPage->HCPhys, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3366 cErrors++;
3367 continue;
3368 }
3369 fIgnoreFlags |= X86_PTE_P;
3370 }
3371 }
3372 else
3373 {
3374 if (!PteSrc.n.u1Dirty && PteSrc.n.u1Write)
3375 {
3376 if (PteDst.n.u1Write)
3377 {
3378 AssertMsgFailed(("!DIRTY page at %VGv is writable! PteSrc=%#RX64 PteDst=%#RX64\n",
3379 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3380 cErrors++;
3381 continue;
3382 }
3383 if (!(PteDst.u & PGM_PTFLAGS_TRACK_DIRTY))
3384 {
3385 AssertMsgFailed(("!DIRTY page at %VGv is not marked TRACK_DIRTY! PteSrc=%#RX64 PteDst=%#RX64\n",
3386 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3387 cErrors++;
3388 continue;
3389 }
3390 if (PteDst.n.u1Dirty)
3391 {
3392 AssertMsgFailed(("!DIRTY page at %VGv is marked DIRTY! PteSrc=%#RX64 PteDst=%#RX64\n",
3393 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3394 cErrors++;
3395 }
3396# if 0 /** @todo sync access bit properly... */
3397 if (PteDst.n.u1Accessed != PteSrc.n.u1Accessed)
3398 {
3399 AssertMsgFailed(("!DIRTY page at %VGv is has mismatching accessed bit! PteSrc=%#RX64 PteDst=%#RX64\n",
3400 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3401 cErrors++;
3402 }
3403 fIgnoreFlags |= X86_PTE_RW;
3404# else
3405 fIgnoreFlags |= X86_PTE_RW | X86_PTE_A;
3406# endif
3407 }
3408 else if (PteDst.u & PGM_PTFLAGS_TRACK_DIRTY)
3409 {
3410 /* access bit emulation (not implemented). */
3411 if (PteSrc.n.u1Accessed || PteDst.n.u1Present)
3412 {
3413 AssertMsgFailed(("PGM_PTFLAGS_TRACK_DIRTY set at %VGv but no accessed bit emulation! PteSrc=%#RX64 PteDst=%#RX64\n",
3414 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3415 cErrors++;
3416 continue;
3417 }
3418 if (!PteDst.n.u1Accessed)
3419 {
3420 AssertMsgFailed(("!ACCESSED page at %VGv is has the accessed bit set! PteSrc=%#RX64 PteDst=%#RX64\n",
3421 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3422 cErrors++;
3423 }
3424 fIgnoreFlags |= X86_PTE_P;
3425 }
3426# ifdef DEBUG_sandervl
3427 fIgnoreFlags |= X86_PTE_D | X86_PTE_A;
3428# endif
3429 }
3430
3431 if ( (PteSrc.u & ~fIgnoreFlags) != (PteDst.u & ~fIgnoreFlags)
3432 && (PteSrc.u & ~(fIgnoreFlags | X86_PTE_RW)) != (PteDst.u & ~fIgnoreFlags)
3433 )
3434 {
3435 AssertMsgFailed(("Flags mismatch at %VGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PteSrc=%#RX64 PteDst=%#RX64\n",
3436 GCPtr + off, (uint64_t)PteSrc.u & ~fIgnoreFlags, (uint64_t)PteDst.u & ~fIgnoreFlags,
3437 fIgnoreFlags, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
3438 cErrors++;
3439 continue;
3440 }
3441 } /* foreach PTE */
3442 }
3443 else
3444 {
3445 /*
3446 * Big Page.
3447 */
3448 uint64_t fIgnoreFlags = X86_PDE_AVL_MASK | GST_PDE_PG_MASK | X86_PDE4M_G | X86_PDE4M_D | X86_PDE4M_PS | X86_PDE4M_PWT | X86_PDE4M_PCD;
3449 if (!PdeSrc.b.u1Dirty && PdeSrc.b.u1Write)
3450 {
3451 if (PdeDst.n.u1Write)
3452 {
3453 AssertMsgFailed(("!DIRTY page at %VGv is writable! PdeSrc=%#RX64 PdeDst=%#RX64\n",
3454 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
3455 cErrors++;
3456 continue;
3457 }
3458 if (!(PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY))
3459 {
3460 AssertMsgFailed(("!DIRTY page at %VGv is not marked TRACK_DIRTY! PteSrc=%#RX64 PteDst=%#RX64\n",
3461 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
3462 cErrors++;
3463 continue;
3464 }
3465# if 0 /** @todo sync access bit properly... */
3466 if (PdeDst.n.u1Accessed != PdeSrc.b.u1Accessed)
3467 {
3468 AssertMsgFailed(("!DIRTY page at %VGv is has mismatching accessed bit! PteSrc=%#RX64 PteDst=%#RX64\n",
3469 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
3470 cErrors++;
3471 }
3472 fIgnoreFlags |= X86_PTE_RW;
3473# else
3474 fIgnoreFlags |= X86_PTE_RW | X86_PTE_A;
3475# endif
3476 }
3477 else if (PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY)
3478 {
3479 /* access bit emulation (not implemented). */
3480 if (PdeSrc.b.u1Accessed || PdeDst.n.u1Present)
3481 {
3482 AssertMsgFailed(("PGM_PDFLAGS_TRACK_DIRTY set at %VGv but no accessed bit emulation! PdeSrc=%#RX64 PdeDst=%#RX64\n",
3483 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
3484 cErrors++;
3485 continue;
3486 }
3487 if (!PdeDst.n.u1Accessed)
3488 {
3489 AssertMsgFailed(("!ACCESSED page at %VGv is has the accessed bit set! PdeSrc=%#RX64 PdeDst=%#RX64\n",
3490 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
3491 cErrors++;
3492 }
3493 fIgnoreFlags |= X86_PTE_P;
3494 }
3495
3496 if ((PdeSrc.u & ~fIgnoreFlags) != (PdeDst.u & ~fIgnoreFlags))
3497 {
3498 AssertMsgFailed(("Flags mismatch (B) at %VGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PdeSrc=%#RX64 PdeDst=%#RX64\n",
3499 GCPtr, (uint64_t)PdeSrc.u & ~fIgnoreFlags, (uint64_t)PdeDst.u & ~fIgnoreFlags,
3500 fIgnoreFlags, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
3501 cErrors++;
3502 }
3503
3504 /* iterate the page table. */
3505 for (unsigned iPT = 0, off = 0;
3506 iPT < ELEMENTS(pPTDst->a);
3507 iPT++, off += PAGE_SIZE, GCPhysGst += PAGE_SIZE)
3508 {
3509 const SHWPTE PteDst = pPTDst->a[iPT];
3510
3511 if (PteDst.u & PGM_PTFLAGS_TRACK_DIRTY)
3512 {
3513 AssertMsgFailed(("The PTE at %VGv emulating a 2/4M page is marked TRACK_DIRTY! PdeSrc=%#RX64 PteDst=%#RX64\n",
3514 GCPtr + off, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3515 cErrors++;
3516 }
3517
3518 /* skip not-present entries. */
3519 if (!PteDst.n.u1Present) /** @todo deal with ALL handlers and CSAM !P pages! */
3520 continue;
3521
3522 fIgnoreFlags = X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_PAT;
3523
3524 /* match the physical addresses */
3525 HCPhysShw = PteDst.u & X86_PTE_PAE_PG_MASK;
3526
3527# ifdef IN_RING3
3528 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysGst, &HCPhys);
3529 if (VBOX_FAILURE(rc))
3530 {
3531 if (HCPhysShw != MMR3PageDummyHCPhys(pVM))
3532 {
3533 AssertMsgFailed(("Cannot find guest physical address %VGp at %VGv! PdeSrc=%#RX64 PteDst=%#RX64\n",
3534 GCPhysGst, GCPtr + off, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3535 cErrors++;
3536 }
3537 }
3538 else if (HCPhysShw != (HCPhys & X86_PTE_PAE_PG_MASK))
3539 {
3540 AssertMsgFailed(("Out of sync (phys) at %VGv! HCPhysShw=%VHp HCPhys=%VHp GCPhysGst=%VGp PdeSrc=%#RX64 PteDst=%#RX64\n",
3541 GCPtr + off, HCPhysShw, HCPhys, GCPhysGst, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3542 cErrors++;
3543 continue;
3544 }
3545# endif
3546
3547 pPhysPage = pgmPhysGetPage(pPGM, GCPhysGst);
3548 if (!pPhysPage)
3549 {
3550# ifdef IN_RING3 /** @todo make MMR3PageDummyHCPhys an 'All' function! */
3551 if (HCPhysShw != MMR3PageDummyHCPhys(pVM))
3552 {
3553 AssertMsgFailed(("Cannot find guest physical address %VGp at %VGv! PdeSrc=%#RX64 PteDst=%#RX64\n",
3554 GCPhysGst, GCPtr + off, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3555 cErrors++;
3556 continue;
3557 }
3558# endif
3559 if (PteDst.n.u1Write)
3560 {
3561 AssertMsgFailed(("Invalid guest page at %VGv is writable! GCPhysGst=%VGp PdeSrc=%#RX64 PteDst=%#RX64\n",
3562 GCPtr + off, GCPhysGst, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3563 cErrors++;
3564 }
3565 fIgnoreFlags |= X86_PTE_RW;
3566 }
3567 else if (HCPhysShw != (pPhysPage->HCPhys & X86_PTE_PAE_PG_MASK))
3568 {
3569 AssertMsgFailed(("Out of sync (phys) at %VGv! HCPhysShw=%VHp HCPhys=%VHp GCPhysGst=%VGp PdeSrc=%#RX64 PteDst=%#RX64\n",
3570 GCPtr + off, HCPhysShw, pPhysPage->HCPhys, GCPhysGst, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3571 cErrors++;
3572 continue;
3573 }
3574
3575 /* flags */
3576 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPhysPage))
3577 {
3578 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPhysPage))
3579 {
3580 if (PGM_PAGE_GET_HNDL_PHYS_STATE(pPhysPage) != PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
3581 {
3582 if (PteDst.n.u1Write)
3583 {
3584 AssertMsgFailed(("WRITE access flagged at %VGv but the page is writable! HCPhys=%VGv PdeSrc=%#RX64 PteDst=%#RX64\n",
3585 GCPtr + off, pPhysPage->HCPhys, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3586 cErrors++;
3587 continue;
3588 }
3589 fIgnoreFlags |= X86_PTE_RW;
3590 }
3591 }
3592 else
3593 {
3594 if (PteDst.n.u1Present)
3595 {
3596 AssertMsgFailed(("ALL access flagged at %VGv but the page is present! HCPhys=%VGv PdeSrc=%#RX64 PteDst=%#RX64\n",
3597 GCPtr + off, pPhysPage->HCPhys, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3598 cErrors++;
3599 continue;
3600 }
3601 fIgnoreFlags |= X86_PTE_P;
3602 }
3603 }
3604
3605 if ( (PdeSrc.u & ~fIgnoreFlags) != (PteDst.u & ~fIgnoreFlags)
3606 && (PdeSrc.u & ~(fIgnoreFlags | X86_PTE_RW)) != (PteDst.u & ~fIgnoreFlags) /* lazy phys handler dereg. */
3607 )
3608 {
3609 AssertMsgFailed(("Flags mismatch (BT) at %VGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PdeSrc=%#RX64 PteDst=%#RX64\n",
3610 GCPtr + off, (uint64_t)PdeSrc.u & ~fIgnoreFlags, (uint64_t)PteDst.u & ~fIgnoreFlags,
3611 fIgnoreFlags, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
3612 cErrors++;
3613 continue;
3614 }
3615 } /* foreach PTE */
3616 }
3617 }
3618 /* not present */
3619
3620 } /* forearch PDE */
3621
3622# ifdef DEBUG
3623 if (cErrors)
3624 LogFlow(("AssertCR3: cErrors=%d\n", cErrors));
3625# endif
3626
3627#elif PGM_GST_TYPE == PGM_TYPE_PAE
3628//# error not implemented
3629
3630
3631#elif PGM_GST_TYPE == PGM_TYPE_AMD64
3632//# error not implemented
3633
3634/*#else: guest real and protected mode */
3635#endif
3636 return cErrors;
3637}
3638#endif /* VBOX_STRICT */
3639
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