VirtualBox

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

Last change on this file since 1382 was 1359, checked in by vboxsync, 18 years ago

SELM function changes for v86 mode code.
CPL check fixes for V86 mode code.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette