VirtualBox

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

Last change on this file since 29888 was 29676, checked in by vboxsync, 15 years ago

Too noisy

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 199.9 KB
Line 
1/* $Id: PGMAllBth.h 29676 2010-05-20 09:54:57Z vboxsync $ */
2/** @file
3 * VBox - Page Manager, Shadow+Guest Paging Template - All context code.
4 *
5 * This file is a big challenge!
6 */
7
8/*
9 * Copyright (C) 2006-2007 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/*******************************************************************************
21* Internal Functions *
22*******************************************************************************/
23RT_C_DECLS_BEGIN
24PGM_BTH_DECL(int, Trap0eHandler)(PVMCPU pVCpu, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, bool *pfLockTaken);
25PGM_BTH_DECL(int, InvalidatePage)(PVMCPU pVCpu, RTGCPTR GCPtrPage);
26PGM_BTH_DECL(int, SyncPage)(PVMCPU pVCpu, GSTPDE PdeSrc, RTGCPTR GCPtrPage, unsigned cPages, unsigned uErr);
27PGM_BTH_DECL(int, CheckPageFault)(PVMCPU pVCpu, uint32_t uErr, PGSTPDE pPdeSrc, RTGCPTR GCPtrPage);
28PGM_BTH_DECL(int, CheckDirtyPageFault)(PVMCPU pVCpu, uint32_t uErr, PSHWPDE pPdeDst, PGSTPDE pPdeSrc, RTGCPTR GCPtrPage);
29PGM_BTH_DECL(int, SyncPT)(PVMCPU pVCpu, unsigned iPD, PGSTPD pPDSrc, RTGCPTR GCPtrPage);
30PGM_BTH_DECL(int, VerifyAccessSyncPage)(PVMCPU pVCpu, RTGCPTR Addr, unsigned fPage, unsigned uErr);
31PGM_BTH_DECL(int, PrefetchPage)(PVMCPU pVCpu, RTGCPTR GCPtrPage);
32PGM_BTH_DECL(int, SyncCR3)(PVMCPU pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal);
33#ifdef VBOX_STRICT
34PGM_BTH_DECL(unsigned, AssertCR3)(PVMCPU pVCpu, uint64_t cr3, uint64_t cr4, RTGCPTR GCPtr = 0, RTGCPTR cb = ~(RTGCPTR)0);
35#endif
36DECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackDeref)(PVMCPU pVCpu, PPGMPOOLPAGE pShwPage, RTHCPHYS HCPhys, uint16_t iPte);
37PGM_BTH_DECL(int, MapCR3)(PVMCPU pVCpu, RTGCPHYS GCPhysCR3);
38PGM_BTH_DECL(int, UnmapCR3)(PVMCPU pVCpu);
39RT_C_DECLS_END
40
41
42/* Filter out some illegal combinations of guest and shadow paging, so we can remove redundant checks inside functions. */
43#if PGM_GST_TYPE == PGM_TYPE_PAE && PGM_SHW_TYPE != PGM_TYPE_PAE && PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT
44# error "Invalid combination; PAE guest implies PAE shadow"
45#endif
46
47#if (PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT) \
48 && !(PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_PAE || PGM_SHW_TYPE == PGM_TYPE_AMD64 || PGM_SHW_TYPE == PGM_TYPE_NESTED || PGM_SHW_TYPE == PGM_TYPE_EPT)
49# error "Invalid combination; real or protected mode without paging implies 32 bits or PAE shadow paging."
50#endif
51
52#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_PAE) \
53 && !(PGM_SHW_TYPE == PGM_TYPE_32BIT || PGM_SHW_TYPE == PGM_TYPE_PAE || PGM_SHW_TYPE == PGM_TYPE_NESTED || PGM_SHW_TYPE == PGM_TYPE_EPT)
54# error "Invalid combination; 32 bits guest paging or PAE implies 32 bits or PAE shadow paging."
55#endif
56
57#if (PGM_GST_TYPE == PGM_TYPE_AMD64 && PGM_SHW_TYPE != PGM_TYPE_AMD64 && PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT) \
58 || (PGM_SHW_TYPE == PGM_TYPE_AMD64 && PGM_GST_TYPE != PGM_TYPE_AMD64 && PGM_GST_TYPE != PGM_TYPE_PROT)
59# error "Invalid combination; AMD64 guest implies AMD64 shadow and vice versa"
60#endif
61
62
63#ifndef IN_RING3
64/**
65 * #PF Handler for raw-mode guest execution.
66 *
67 * @returns VBox status code (appropriate for trap handling and GC return).
68 *
69 * @param pVCpu VMCPU Handle.
70 * @param uErr The trap error code.
71 * @param pRegFrame Trap register frame.
72 * @param pvFault The fault address.
73 * @param pfLockTaken PGM lock taken here or not (out)
74 */
75PGM_BTH_DECL(int, Trap0eHandler)(PVMCPU pVCpu, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, bool *pfLockTaken)
76{
77 PVM pVM = pVCpu->CTX_SUFF(pVM);
78
79 *pfLockTaken = false;
80
81# if defined(IN_RC) && defined(VBOX_STRICT)
82 PGMDynCheckLocks(pVM);
83# endif
84
85# if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64) \
86 && PGM_SHW_TYPE != PGM_TYPE_NESTED \
87 && (PGM_SHW_TYPE != PGM_TYPE_EPT || PGM_GST_TYPE == PGM_TYPE_PROT)
88
89# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE != PGM_TYPE_PAE
90 /*
91 * Hide the instruction fetch trap indicator for now.
92 */
93 /** @todo NXE will change this and we must fix NXE in the switcher too! */
94 if (uErr & X86_TRAP_PF_ID)
95 {
96 uErr &= ~X86_TRAP_PF_ID;
97 TRPMSetErrorCode(pVCpu, uErr);
98 }
99# endif
100
101 /*
102 * Get PDs.
103 */
104 int rc;
105# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
106# if PGM_GST_TYPE == PGM_TYPE_32BIT
107 const unsigned iPDSrc = pvFault >> GST_PD_SHIFT;
108 PGSTPD pPDSrc = pgmGstGet32bitPDPtr(&pVCpu->pgm.s);
109
110# elif PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64
111
112# if PGM_GST_TYPE == PGM_TYPE_PAE
113 unsigned iPDSrc = 0; /* initialized to shut up gcc */
114 X86PDPE PdpeSrc;
115 PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVCpu->pgm.s, pvFault, &iPDSrc, &PdpeSrc);
116
117# elif PGM_GST_TYPE == PGM_TYPE_AMD64
118 unsigned iPDSrc = 0; /* initialized to shut up gcc */
119 PX86PML4E pPml4eSrc;
120 X86PDPE PdpeSrc;
121 PGSTPD pPDSrc;
122
123 pPDSrc = pgmGstGetLongModePDPtr(&pVCpu->pgm.s, pvFault, &pPml4eSrc, &PdpeSrc, &iPDSrc);
124 Assert(pPml4eSrc);
125# endif
126
127 /* Quick check for a valid guest trap. (PAE & AMD64) */
128 if (!pPDSrc)
129 {
130# if PGM_GST_TYPE == PGM_TYPE_AMD64 && GC_ARCH_BITS == 64
131 LogFlow(("Trap0eHandler: guest PML4 %d not present CR3=%RGp\n", (int)((pvFault >> X86_PML4_SHIFT) & X86_PML4_MASK), CPUMGetGuestCR3(pVCpu) & X86_CR3_PAGE_MASK));
132# else
133 LogFlow(("Trap0eHandler: guest iPDSrc=%u not present CR3=%RGp\n", iPDSrc, CPUMGetGuestCR3(pVCpu) & X86_CR3_PAGE_MASK));
134# endif
135 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2GuestTrap; });
136 TRPMSetErrorCode(pVCpu, uErr);
137 return VINF_EM_RAW_GUEST_TRAP;
138 }
139# endif
140
141# else /* !PGM_WITH_PAGING */
142 PGSTPD pPDSrc = NULL;
143 const unsigned iPDSrc = 0;
144# endif /* !PGM_WITH_PAGING */
145
146# if !defined(PGM_WITHOUT_MAPPINGS) && ((PGM_GST_TYPE == PGM_TYPE_32BIT) || (PGM_GST_TYPE == PGM_TYPE_PAE))
147 /*
148 * Check for write conflicts with our hypervisor mapping early on. If the guest happens to access a non-present page,
149 * where our hypervisor is currently mapped, then we'll create a #PF storm in the guest.
150 */
151 if ( (uErr & (X86_TRAP_PF_P | X86_TRAP_PF_RW)) == (X86_TRAP_PF_P | X86_TRAP_PF_RW)
152 && MMHyperIsInsideArea(pVM, pvFault))
153 {
154 /* Force a CR3 sync to check for conflicts and emulate the instruction. */
155 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
156 return VINF_EM_RAW_EMULATE_INSTR;
157 }
158# endif
159
160 /* First check for a genuine guest page fault. */
161# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
162 STAM_PROFILE_START(&pVCpu->pgm.s.StatRZTrap0eTimeCheckPageFault, e);
163 rc = PGM_BTH_NAME(CheckPageFault)(pVCpu, uErr, &pPDSrc->a[iPDSrc], pvFault);
164 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeCheckPageFault, e);
165 if (rc == VINF_EM_RAW_GUEST_TRAP)
166 {
167 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution)
168 = &pVCpu->pgm.s.StatRZTrap0eTime2GuestTrap; });
169 return rc;
170 }
171# endif /* PGM_WITH_PAGING */
172
173 /* Take the big lock now. */
174 *pfLockTaken = true;
175 pgmLock(pVM);
176
177 /* Fetch the guest PDE */
178# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
179 GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
180# else
181 GSTPDE PdeSrc;
182 PdeSrc.u = 0; /* faked so we don't have to #ifdef everything */
183 PdeSrc.n.u1Present = 1;
184 PdeSrc.n.u1Write = 1;
185 PdeSrc.n.u1Accessed = 1;
186 PdeSrc.n.u1User = 1;
187# endif
188
189# if PGM_SHW_TYPE == PGM_TYPE_32BIT
190 const unsigned iPDDst = pvFault >> SHW_PD_SHIFT;
191 PX86PD pPDDst = pgmShwGet32BitPDPtr(&pVCpu->pgm.s);
192
193# elif PGM_SHW_TYPE == PGM_TYPE_PAE
194 const unsigned iPDDst = (pvFault >> SHW_PD_SHIFT) & SHW_PD_MASK; /* pPDDst index, not used with the pool. */
195
196 PX86PDPAE pPDDst;
197# if PGM_GST_TYPE != PGM_TYPE_PAE
198 X86PDPE PdpeSrc;
199
200 /* Fake PDPT entry; access control handled on the page table level, so allow everything. */
201 PdpeSrc.u = X86_PDPE_P; /* rw/us are reserved for PAE pdpte's; accessed bit causes invalid VT-x guest state errors */
202# endif
203 rc = pgmShwSyncPaePDPtr(pVCpu, pvFault, &PdpeSrc, &pPDDst);
204 if (rc != VINF_SUCCESS)
205 {
206 AssertRC(rc);
207 return rc;
208 }
209 Assert(pPDDst);
210
211# elif PGM_SHW_TYPE == PGM_TYPE_AMD64
212 const unsigned iPDDst = ((pvFault >> SHW_PD_SHIFT) & SHW_PD_MASK);
213 PX86PDPAE pPDDst;
214# if PGM_GST_TYPE == PGM_TYPE_PROT
215 /* AMD-V nested paging */
216 X86PML4E Pml4eSrc;
217 X86PDPE PdpeSrc;
218 PX86PML4E pPml4eSrc = &Pml4eSrc;
219
220 /* Fake PML4 & PDPT entry; access control handled on the page table level, so allow everything. */
221 Pml4eSrc.u = X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_A;
222 PdpeSrc.u = X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A;
223# endif
224
225 rc = pgmShwSyncLongModePDPtr(pVCpu, pvFault, pPml4eSrc, &PdpeSrc, &pPDDst);
226 if (rc != VINF_SUCCESS)
227 {
228 AssertRC(rc);
229 return rc;
230 }
231 Assert(pPDDst);
232
233# elif PGM_SHW_TYPE == PGM_TYPE_EPT
234 const unsigned iPDDst = ((pvFault >> SHW_PD_SHIFT) & SHW_PD_MASK);
235 PEPTPD pPDDst;
236
237 rc = pgmShwGetEPTPDPtr(pVCpu, pvFault, NULL, &pPDDst);
238 if (rc != VINF_SUCCESS)
239 {
240 AssertRC(rc);
241 return rc;
242 }
243 Assert(pPDDst);
244# endif
245
246# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
247 /* Dirty page handling. */
248 if (uErr & X86_TRAP_PF_RW) /* write fault? */
249 {
250 /*
251 * If we successfully correct the write protection fault due to dirty bit
252 * tracking, then return immediately.
253 */
254 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyBitTracking), a);
255 rc = PGM_BTH_NAME(CheckDirtyPageFault)(pVCpu, uErr, &pPDDst->a[iPDDst], &pPDSrc->a[iPDSrc], pvFault);
256 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyBitTracking), a);
257 if (rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT)
258 {
259 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution)
260 = rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT ? &pVCpu->pgm.s.StatRZTrap0eTime2DirtyAndAccessed : &pVCpu->pgm.s.StatRZTrap0eTime2GuestTrap; });
261 LogBird(("Trap0eHandler: returns VINF_SUCCESS\n"));
262 return VINF_SUCCESS;
263 }
264 }
265
266# if 0 /* rarely useful; leave for debugging. */
267 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0ePD[iPDSrc]);
268# endif
269# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
270
271 /*
272 * A common case is the not-present error caused by lazy page table syncing.
273 *
274 * It is IMPORTANT that we weed out any access to non-present shadow PDEs here
275 * so we can safely assume that the shadow PT is present when calling SyncPage later.
276 *
277 * On failure, we ASSUME that SyncPT is out of memory or detected some kind
278 * of mapping conflict and defer to SyncCR3 in R3.
279 * (Again, we do NOT support access handlers for non-present guest pages.)
280 *
281 */
282 Assert(PdeSrc.n.u1Present);
283 if ( !(uErr & X86_TRAP_PF_P) /* not set means page not present instead of page protection violation */
284 && !pPDDst->a[iPDDst].n.u1Present
285 )
286 {
287 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2SyncPT; });
288 STAM_PROFILE_START(&pVCpu->pgm.s.StatRZTrap0eTimeSyncPT, f);
289 LogFlow(("=>SyncPT %04x = %08x\n", iPDSrc, PdeSrc.au32[0]));
290 rc = PGM_BTH_NAME(SyncPT)(pVCpu, iPDSrc, pPDSrc, pvFault);
291 if (RT_SUCCESS(rc))
292 {
293 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeSyncPT, f);
294 return rc;
295 }
296 Log(("SyncPT: %d failed!! rc=%d\n", iPDSrc, rc));
297 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3); /** @todo no need to do global sync, right? */
298 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeSyncPT, f);
299 return VINF_PGM_SYNC_CR3;
300 }
301
302# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && !defined(PGM_WITHOUT_MAPPINGS)
303 /*
304 * Check if this address is within any of our mappings.
305 *
306 * This is *very* fast and it's gonna save us a bit of effort below and prevent
307 * us from screwing ourself with MMIO2 pages which have a GC Mapping (VRam).
308 * (BTW, it's impossible to have physical access handlers in a mapping.)
309 */
310 if (pgmMapAreMappingsEnabled(&pVM->pgm.s))
311 {
312 STAM_PROFILE_START(&pVCpu->pgm.s.StatRZTrap0eTimeMapping, a);
313 PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
314 for ( ; pMapping; pMapping = pMapping->CTX_SUFF(pNext))
315 {
316 if (pvFault < pMapping->GCPtr)
317 break;
318 if (pvFault - pMapping->GCPtr < pMapping->cb)
319 {
320 /*
321 * The first thing we check is if we've got an undetected conflict.
322 */
323 if (pgmMapAreMappingsFloating(&pVM->pgm.s))
324 {
325 unsigned iPT = pMapping->cb >> GST_PD_SHIFT;
326 while (iPT-- > 0)
327 if (pPDSrc->a[iPDSrc + iPT].n.u1Present)
328 {
329 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eConflicts);
330 Log(("Trap0e: Detected Conflict %RGv-%RGv\n", pMapping->GCPtr, pMapping->GCPtrLast));
331 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3); /** @todo no need to do global sync,right? */
332 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeMapping, a);
333 return VINF_PGM_SYNC_CR3;
334 }
335 }
336
337 /*
338 * Check if the fault address is in a virtual page access handler range.
339 */
340 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers, pvFault);
341 if ( pCur
342 && pvFault - pCur->Core.Key < pCur->cb
343 && uErr & X86_TRAP_PF_RW)
344 {
345# ifdef IN_RC
346 STAM_PROFILE_START(&pCur->Stat, h);
347 pgmUnlock(pVM);
348 rc = pCur->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
349 pgmLock(pVM);
350 STAM_PROFILE_STOP(&pCur->Stat, h);
351# else
352 AssertFailed();
353 rc = VINF_EM_RAW_EMULATE_INSTR; /* can't happen with VMX */
354# endif
355 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersMapping);
356 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeMapping, a);
357 return rc;
358 }
359
360 /*
361 * Pretend we're not here and let the guest handle the trap.
362 */
363 TRPMSetErrorCode(pVCpu, uErr & ~X86_TRAP_PF_P);
364 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eGuestPFMapping);
365 LogFlow(("PGM: Mapping access -> route trap to recompiler!\n"));
366 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeMapping, a);
367 return VINF_EM_RAW_GUEST_TRAP;
368 }
369 }
370 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeMapping, a);
371 } /* pgmAreMappingsEnabled(&pVM->pgm.s) */
372# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
373
374 /*
375 * Check if this fault address is flagged for special treatment,
376 * which means we'll have to figure out the physical address and
377 * check flags associated with it.
378 *
379 * ASSUME that we can limit any special access handling to pages
380 * in page tables which the guest believes to be present.
381 */
382 Assert(PdeSrc.n.u1Present);
383 {
384 RTGCPHYS GCPhys = NIL_RTGCPHYS;
385
386# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
387 if ( PdeSrc.b.u1Size
388# if PGM_GST_TYPE == PGM_TYPE_32BIT
389 && CPUMIsGuestPageSizeExtEnabled(pVCpu)
390# endif
391 )
392 GCPhys = GST_GET_PDE_BIG_PG_GCPHYS(PdeSrc)
393 | ((RTGCPHYS)pvFault & (GST_BIG_PAGE_OFFSET_MASK ^ PAGE_OFFSET_MASK));
394 else
395 {
396 PGSTPT pPTSrc;
397 rc = PGM_GCPHYS_2_PTR(pVM, PdeSrc.u & GST_PDE_PG_MASK, &pPTSrc);
398 if (RT_SUCCESS(rc))
399 {
400 unsigned iPTESrc = (pvFault >> GST_PT_SHIFT) & GST_PT_MASK;
401 if (pPTSrc->a[iPTESrc].n.u1Present)
402 GCPhys = pPTSrc->a[iPTESrc].u & GST_PTE_PG_MASK;
403 }
404 }
405# else
406 /* No paging so the fault address is the physical address */
407 GCPhys = (RTGCPHYS)(pvFault & ~PAGE_OFFSET_MASK);
408# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
409
410 /*
411 * If we have a GC address we'll check if it has any flags set.
412 */
413 if (GCPhys != NIL_RTGCPHYS)
414 {
415 STAM_PROFILE_START(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
416
417 PPGMPAGE pPage;
418 rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhys, &pPage);
419 if (RT_SUCCESS(rc)) /** just handle the failure immediate (it returns) and make things easier to read. */
420 {
421 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
422 {
423 if (PGM_PAGE_HAS_ANY_PHYSICAL_HANDLERS(pPage))
424 {
425 /*
426 * Physical page access handler.
427 */
428 const RTGCPHYS GCPhysFault = GCPhys | (pvFault & PAGE_OFFSET_MASK);
429 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhysFault);
430 if (pCur)
431 {
432# ifdef PGM_SYNC_N_PAGES
433 /*
434 * If the region is write protected and we got a page not present fault, then sync
435 * the pages. If the fault was caused by a read, then restart the instruction.
436 * In case of write access continue to the GC write handler.
437 *
438 * ASSUMES that there is only one handler per page or that they have similar write properties.
439 */
440 if ( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE
441 && !(uErr & X86_TRAP_PF_P))
442 {
443 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, pvFault, PGM_SYNC_NR_PAGES, uErr);
444 if ( RT_FAILURE(rc)
445 || !(uErr & X86_TRAP_PF_RW)
446 || rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE)
447 {
448 AssertRC(rc);
449 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersOutOfSync);
450 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
451 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2OutOfSyncHndPhys; });
452 return rc;
453 }
454 }
455# endif
456
457 AssertMsg( pCur->enmType != PGMPHYSHANDLERTYPE_PHYSICAL_WRITE
458 || (pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE && (uErr & X86_TRAP_PF_RW)),
459 ("Unexpected trap for physical handler: %08X (phys=%08x) pPage=%R[pgmpage] uErr=%X, enum=%d\n", pvFault, GCPhys, pPage, uErr, pCur->enmType));
460
461# if defined(IN_RC) || defined(IN_RING0)
462 if (pCur->CTX_SUFF(pfnHandler))
463 {
464 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
465# ifdef IN_RING0
466 PFNPGMR0PHYSHANDLER pfnHandler = pCur->CTX_SUFF(pfnHandler);
467# else
468 PFNPGMRCPHYSHANDLER pfnHandler = pCur->CTX_SUFF(pfnHandler);
469# endif
470 bool fLeaveLock = (pfnHandler != pPool->CTX_SUFF(pfnAccessHandler));
471 void *pvUser = pCur->CTX_SUFF(pvUser);
472
473 STAM_PROFILE_START(&pCur->Stat, h);
474 if (fLeaveLock)
475 pgmUnlock(pVM); /* @todo: Not entirely safe. */
476
477 rc = pfnHandler(pVM, uErr, pRegFrame, pvFault, GCPhysFault, pvUser);
478 if (fLeaveLock)
479 pgmLock(pVM);
480# ifdef VBOX_WITH_STATISTICS
481 pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhysFault);
482 if (pCur)
483 STAM_PROFILE_STOP(&pCur->Stat, h);
484# else
485 pCur = NULL; /* might be invalid by now. */
486# endif
487
488 }
489 else
490# endif
491 rc = VINF_EM_RAW_EMULATE_INSTR;
492
493 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersPhysical);
494 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
495 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2HndPhys; });
496 return rc;
497 }
498 }
499# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
500 else
501 {
502# ifdef PGM_SYNC_N_PAGES
503 /*
504 * If the region is write protected and we got a page not present fault, then sync
505 * the pages. If the fault was caused by a read, then restart the instruction.
506 * In case of write access continue to the GC write handler.
507 */
508 if ( PGM_PAGE_GET_HNDL_VIRT_STATE(pPage) < PGM_PAGE_HNDL_PHYS_STATE_ALL
509 && !(uErr & X86_TRAP_PF_P))
510 {
511 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, pvFault, PGM_SYNC_NR_PAGES, uErr);
512 if ( RT_FAILURE(rc)
513 || rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE
514 || !(uErr & X86_TRAP_PF_RW))
515 {
516 AssertRC(rc);
517 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersOutOfSync);
518 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
519 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2OutOfSyncHndVirt; });
520 return rc;
521 }
522 }
523# endif
524 /*
525 * Ok, it's an virtual page access handler.
526 *
527 * Since it's faster to search by address, we'll do that first
528 * and then retry by GCPhys if that fails.
529 */
530 /** @todo r=bird: perhaps we should consider looking up by physical address directly now? */
531 /** @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
532 * page was changed without us noticing it (not-present -> present without invlpg or mov cr3, xxx)
533 */
534 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, pvFault);
535 if (pCur)
536 {
537 AssertMsg(!(pvFault - pCur->Core.Key < pCur->cb)
538 || ( pCur->enmType != PGMVIRTHANDLERTYPE_WRITE
539 || !(uErr & X86_TRAP_PF_P)
540 || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
541 ("Unexpected trap for virtual handler: %RGv (phys=%RGp) pPage=%R[pgmpage] uErr=%X, enum=%d\n", pvFault, GCPhys, pPage, uErr, pCur->enmType));
542
543 if ( pvFault - pCur->Core.Key < pCur->cb
544 && ( uErr & X86_TRAP_PF_RW
545 || pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
546 {
547# ifdef IN_RC
548 STAM_PROFILE_START(&pCur->Stat, h);
549 pgmUnlock(pVM);
550 rc = pCur->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
551 pgmLock(pVM);
552 STAM_PROFILE_STOP(&pCur->Stat, h);
553# else
554 rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
555# endif
556 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersVirtual);
557 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
558 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2HndVirt; });
559 return rc;
560 }
561 /* Unhandled part of a monitored page */
562 }
563 else
564 {
565 /* Check by physical address. */
566 unsigned iPage;
567 rc = pgmHandlerVirtualFindByPhysAddr(pVM, GCPhys + (pvFault & PAGE_OFFSET_MASK),
568 &pCur, &iPage);
569 Assert(RT_SUCCESS(rc) || !pCur);
570 if ( pCur
571 && ( uErr & X86_TRAP_PF_RW
572 || pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
573 {
574 Assert((pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) == GCPhys);
575# ifdef IN_RC
576 RTGCPTR off = (iPage << PAGE_SHIFT) + (pvFault & PAGE_OFFSET_MASK) - (pCur->Core.Key & PAGE_OFFSET_MASK);
577 Assert(off < pCur->cb);
578 STAM_PROFILE_START(&pCur->Stat, h);
579 pgmUnlock(pVM);
580 rc = pCur->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, off);
581 pgmLock(pVM);
582 STAM_PROFILE_STOP(&pCur->Stat, h);
583# else
584 rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
585# endif
586 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersVirtualByPhys);
587 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
588 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2HndVirt; });
589 return rc;
590 }
591 }
592 }
593# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
594
595 /*
596 * There is a handled area of the page, but this fault doesn't belong to it.
597 * We must emulate the instruction.
598 *
599 * To avoid crashing (non-fatal) in the interpreter and go back to the recompiler
600 * we first check if this was a page-not-present fault for a page with only
601 * write access handlers. Restart the instruction if it wasn't a write access.
602 */
603 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersUnhandled);
604
605 if ( !PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)
606 && !(uErr & X86_TRAP_PF_P))
607 {
608 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, pvFault, PGM_SYNC_NR_PAGES, uErr);
609 if ( RT_FAILURE(rc)
610 || rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE
611 || !(uErr & X86_TRAP_PF_RW))
612 {
613 AssertRC(rc);
614 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersOutOfSync);
615 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
616 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2OutOfSyncHndPhys; });
617 return rc;
618 }
619 }
620
621 /** @todo This particular case can cause quite a lot of overhead. E.g. early stage of kernel booting in Ubuntu 6.06
622 * It's writing to an unhandled part of the LDT page several million times.
623 */
624 rc = PGMInterpretInstruction(pVM, pVCpu, pRegFrame, pvFault);
625 LogFlow(("PGM: PGMInterpretInstruction -> rc=%d pPage=%R[pgmpage]\n", rc, pPage));
626 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
627 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2HndUnhandled; });
628 return rc;
629 } /* if any kind of handler */
630
631# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
632 if (uErr & X86_TRAP_PF_P)
633 {
634 /*
635 * The page isn't marked, but it might still be monitored by a virtual page access handler.
636 * (ASSUMES no temporary disabling of virtual handlers.)
637 */
638 /** @todo r=bird: Since the purpose is to catch out of sync pages with virtual handler(s) here,
639 * we should correct both the shadow page table and physical memory flags, and not only check for
640 * accesses within the handler region but for access to pages with virtual handlers. */
641 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, pvFault);
642 if (pCur)
643 {
644 AssertMsg( !(pvFault - pCur->Core.Key < pCur->cb)
645 || ( pCur->enmType != PGMVIRTHANDLERTYPE_WRITE
646 || !(uErr & X86_TRAP_PF_P)
647 || (pCur->enmType == PGMVIRTHANDLERTYPE_WRITE && (uErr & X86_TRAP_PF_RW))),
648 ("Unexpected trap for virtual handler: %08X (phys=%08x) %R[pgmpage] uErr=%X, enum=%d\n", pvFault, GCPhys, pPage, uErr, pCur->enmType));
649
650 if ( pvFault - pCur->Core.Key < pCur->cb
651 && ( uErr & X86_TRAP_PF_RW
652 || pCur->enmType != PGMVIRTHANDLERTYPE_WRITE ) )
653 {
654# ifdef IN_RC
655 STAM_PROFILE_START(&pCur->Stat, h);
656 pgmUnlock(pVM);
657 rc = pCur->CTX_SUFF(pfnHandler)(pVM, uErr, pRegFrame, pvFault, pCur->Core.Key, pvFault - pCur->Core.Key);
658 pgmLock(pVM);
659 STAM_PROFILE_STOP(&pCur->Stat, h);
660# else
661 rc = VINF_EM_RAW_EMULATE_INSTR; /** @todo for VMX */
662# endif
663 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersVirtualUnmarked);
664 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
665 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2HndVirt; });
666 return rc;
667 }
668 }
669 }
670# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
671 }
672 else
673 {
674 /*
675 * When the guest accesses invalid physical memory (e.g. probing
676 * of RAM or accessing a remapped MMIO range), then we'll fall
677 * back to the recompiler to emulate the instruction.
678 */
679 LogFlow(("PGM #PF: pgmPhysGetPageEx(%RGp) failed with %Rrc\n", GCPhys, rc));
680 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eHandlersInvalid);
681 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
682 return VINF_EM_RAW_EMULATE_INSTR;
683 }
684
685 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
686
687# ifdef PGM_OUT_OF_SYNC_IN_GC /** @todo remove this bugger. */
688 /*
689 * We are here only if page is present in Guest page tables and
690 * trap is not handled by our handlers.
691 *
692 * Check it for page out-of-sync situation.
693 */
694 STAM_PROFILE_START(&pVCpu->pgm.s.StatRZTrap0eTimeOutOfSync, c);
695
696 if (!(uErr & X86_TRAP_PF_P))
697 {
698 /*
699 * Page is not present in our page tables.
700 * Try to sync it!
701 * BTW, fPageShw is invalid in this branch!
702 */
703 if (uErr & X86_TRAP_PF_US)
704 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,PageOutOfSyncUser));
705 else /* supervisor */
706 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,PageOutOfSyncSupervisor));
707
708 if (PGM_PAGE_IS_BALLOONED(pPage))
709 {
710 /* Emulate reads from ballooned pages as they are not present in our shadow page tables. (required for e.g. Solaris guests; soft ecc, random nr generator) */
711 rc = PGMInterpretInstruction(pVM, pVCpu, pRegFrame, pvFault);
712 LogFlow(("PGM: PGMInterpretInstruction balloon -> rc=%d pPage=%R[pgmpage]\n", rc, pPage));
713 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,PageOutOfSyncBallloon));
714 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeHandlers, b);
715 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2HndUnhandled; });
716 return rc;
717 }
718# if defined(LOG_ENABLED) && !defined(IN_RING0)
719 RTGCPHYS GCPhys2;
720 uint64_t fPageGst2;
721 PGMGstGetPage(pVCpu, pvFault, &fPageGst2, &GCPhys2);
722 Log(("Page out of sync: %RGv eip=%08x PdeSrc.n.u1User=%d fPageGst2=%08llx GCPhys2=%RGp scan=%d\n",
723 pvFault, pRegFrame->eip, PdeSrc.n.u1User, fPageGst2, GCPhys2, CSAMDoesPageNeedScanning(pVM, pRegFrame->eip)));
724# endif /* LOG_ENABLED */
725
726# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && !defined(IN_RING0)
727 if (CPUMGetGuestCPL(pVCpu, pRegFrame) == 0)
728 {
729 uint64_t fPageGst;
730 rc = PGMGstGetPage(pVCpu, pvFault, &fPageGst, NULL);
731 if ( RT_SUCCESS(rc)
732 && !(fPageGst & X86_PTE_US))
733 {
734 /* Note: can't check for X86_TRAP_ID bit, because that requires execute disable support on the CPU */
735 if ( pvFault == (RTGCPTR)pRegFrame->eip
736 || pvFault - pRegFrame->eip < 8 /* instruction crossing a page boundary */
737# ifdef CSAM_DETECT_NEW_CODE_PAGES
738 || ( !PATMIsPatchGCAddr(pVM, pRegFrame->eip)
739 && CSAMDoesPageNeedScanning(pVM, pRegFrame->eip)) /* any new code we encounter here */
740# endif /* CSAM_DETECT_NEW_CODE_PAGES */
741 )
742 {
743 LogFlow(("CSAMExecFault %RX32\n", pRegFrame->eip));
744 rc = CSAMExecFault(pVM, (RTRCPTR)pRegFrame->eip);
745 if (rc != VINF_SUCCESS)
746 {
747 /*
748 * CSAM needs to perform a job in ring 3.
749 *
750 * Sync the page before going to the host context; otherwise we'll end up in a loop if
751 * CSAM fails (e.g. instruction crosses a page boundary and the next page is not present)
752 */
753 LogFlow(("CSAM ring 3 job\n"));
754 int rc2 = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, pvFault, 1, uErr);
755 AssertRC(rc2);
756
757 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeOutOfSync, c);
758 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2CSAM; });
759 return rc;
760 }
761 }
762# ifdef CSAM_DETECT_NEW_CODE_PAGES
763 else if ( uErr == X86_TRAP_PF_RW
764 && pRegFrame->ecx >= 0x100 /* early check for movswd count */
765 && pRegFrame->ecx < 0x10000)
766 {
767 /* In case of a write to a non-present supervisor shadow page, we'll take special precautions
768 * to detect loading of new code pages.
769 */
770
771 /*
772 * Decode the instruction.
773 */
774 RTGCPTR PC;
775 rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
776 if (rc == VINF_SUCCESS)
777 {
778 PDISCPUSTATE pDis = &pVCpu->pgm.s.DisState;
779 uint32_t cbOp;
780 rc = EMInterpretDisasOneEx(pVM, pVCpu, PC, pRegFrame, pDis, &cbOp);
781
782 /* For now we'll restrict this to rep movsw/d instructions */
783 if ( rc == VINF_SUCCESS
784 && pDis->pCurInstr->opcode == OP_MOVSWD
785 && (pDis->prefix & PREFIX_REP))
786 {
787 CSAMMarkPossibleCodePage(pVM, pvFault);
788 }
789 }
790 }
791# endif /* CSAM_DETECT_NEW_CODE_PAGES */
792
793 /*
794 * Mark this page as safe.
795 */
796 /** @todo not correct for pages that contain both code and data!! */
797 Log2(("CSAMMarkPage %RGv; scanned=%d\n", pvFault, true));
798 CSAMMarkPage(pVM, pvFault, true);
799 }
800 }
801# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) && !defined(IN_RING0) */
802 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, pvFault, PGM_SYNC_NR_PAGES, uErr);
803 if (RT_SUCCESS(rc))
804 {
805 /* The page was successfully synced, return to the guest. */
806 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeOutOfSync, c);
807 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2OutOfSync; });
808 return VINF_SUCCESS;
809 }
810 }
811 else /* uErr & X86_TRAP_PF_P: */
812 {
813 /*
814 * Write protected pages are make writable when the guest makes the first
815 * write to it. This happens for pages that are shared, write monitored
816 * and not yet allocated.
817 *
818 * Also, a side effect of not flushing global PDEs are out of sync pages due
819 * to physical monitored regions, that are no longer valid.
820 * Assume for now it only applies to the read/write flag.
821 */
822 if ( RT_SUCCESS(rc)
823 && (uErr & X86_TRAP_PF_RW))
824 {
825 if (PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
826 {
827 Log(("PGM #PF: Make writable: %RGp %R[pgmpage] pvFault=%RGp uErr=%#x\n", GCPhys, pPage, pvFault, uErr));
828 Assert(!PGM_PAGE_IS_ZERO(pPage));
829 AssertFatalMsg(!PGM_PAGE_IS_BALLOONED(pPage), ("Unexpected ballooned page at %RGp\n", GCPhys));
830
831 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
832 if (rc != VINF_SUCCESS)
833 {
834 AssertMsg(rc == VINF_PGM_SYNC_CR3 || RT_FAILURE(rc), ("%Rrc\n", rc));
835 return rc;
836 }
837 if (RT_UNLIKELY(VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)))
838 return VINF_EM_NO_MEMORY;
839 }
840
841# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
842 /* Check to see if we need to emulate the instruction as X86_CR0_WP has been cleared. */
843 if ( CPUMGetGuestCPL(pVCpu, pRegFrame) == 0
844 && ((CPUMGetGuestCR0(pVCpu) & (X86_CR0_WP | X86_CR0_PG)) == X86_CR0_PG))
845 {
846 Assert((uErr & (X86_TRAP_PF_RW | X86_TRAP_PF_P)) == (X86_TRAP_PF_RW | X86_TRAP_PF_P));
847 uint64_t fPageGst;
848 rc = PGMGstGetPage(pVCpu, pvFault, &fPageGst, NULL);
849 if ( RT_SUCCESS(rc)
850 && !(fPageGst & X86_PTE_RW))
851 {
852 rc = PGMInterpretInstruction(pVM, pVCpu, pRegFrame, pvFault);
853 if (RT_SUCCESS(rc))
854 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eWPEmulInRZ);
855 else
856 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eWPEmulToR3);
857 return rc;
858 }
859 AssertMsg(RT_SUCCESS(rc), ("Unexpected r/w page %RGv flag=%x rc=%Rrc\n", pvFault, (uint32_t)fPageGst, rc));
860 }
861# endif
862 /// @todo count the above case; else
863 if (uErr & X86_TRAP_PF_US)
864 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,PageOutOfSyncUserWrite));
865 else /* supervisor */
866 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,PageOutOfSyncSupervisorWrite));
867
868 /*
869 * Note: Do NOT use PGM_SYNC_NR_PAGES here. That only works if the
870 * page is not present, which is not true in this case.
871 */
872 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, pvFault, 1, uErr);
873 if (RT_SUCCESS(rc))
874 {
875 /*
876 * Page was successfully synced, return to guest.
877 * First invalidate the page as it might be in the TLB.
878 */
879# if PGM_SHW_TYPE == PGM_TYPE_EPT
880 HWACCMInvalidatePhysPage(pVM, (RTGCPHYS)pvFault);
881# else
882 PGM_INVL_PG(pVCpu, pvFault);
883# endif
884# ifdef VBOX_STRICT
885 RTGCPHYS GCPhys2;
886 uint64_t fPageGst;
887 if (!HWACCMIsNestedPagingActive(pVM))
888 {
889 rc = PGMGstGetPage(pVCpu, pvFault, &fPageGst, &GCPhys2);
890 AssertMsg(RT_SUCCESS(rc) && (fPageGst & X86_PTE_RW), ("rc=%d fPageGst=%RX64\n"));
891 LogFlow(("Obsolete physical monitor page out of sync %RGv - phys %RGp flags=%08llx\n", pvFault, GCPhys2, (uint64_t)fPageGst));
892 }
893 uint64_t fPageShw;
894 rc = PGMShwGetPage(pVCpu, pvFault, &fPageShw, NULL);
895 AssertMsg((RT_SUCCESS(rc) && (fPageShw & X86_PTE_RW)) || pVM->cCpus > 1 /* new monitor can be installed/page table flushed between the trap exit and PGMTrap0eHandler */, ("rc=%Rrc fPageShw=%RX64\n", rc, fPageShw));
896# endif /* VBOX_STRICT */
897 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeOutOfSync, c);
898 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2OutOfSyncHndObs; });
899 return VINF_SUCCESS;
900 }
901 }
902
903# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
904# ifdef VBOX_STRICT
905 /*
906 * Check for VMM page flags vs. Guest page flags consistency.
907 * Currently only for debug purposes.
908 */
909 if (RT_SUCCESS(rc))
910 {
911 /* Get guest page flags. */
912 uint64_t fPageGst;
913 rc = PGMGstGetPage(pVCpu, pvFault, &fPageGst, NULL);
914 if (RT_SUCCESS(rc))
915 {
916 uint64_t fPageShw;
917 rc = PGMShwGetPage(pVCpu, pvFault, &fPageShw, NULL);
918
919 /*
920 * Compare page flags.
921 * Note: we have AVL, A, D bits desynched.
922 */
923 AssertMsg((fPageShw & ~(X86_PTE_A | X86_PTE_D | X86_PTE_AVL_MASK)) == (fPageGst & ~(X86_PTE_A | X86_PTE_D | X86_PTE_AVL_MASK)),
924 ("Page flags mismatch! pvFault=%RGv uErr=%x GCPhys=%RGp fPageShw=%RX64 fPageGst=%RX64\n", pvFault, (uint32_t)uErr, GCPhys, fPageShw, fPageGst));
925 }
926 else
927 AssertMsgFailed(("PGMGstGetPage rc=%Rrc\n", rc));
928 }
929 else
930 AssertMsgFailed(("PGMGCGetPage rc=%Rrc\n", rc));
931# endif /* VBOX_STRICT */
932# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
933 }
934 STAM_PROFILE_STOP(&pVCpu->pgm.s.StatRZTrap0eTimeOutOfSync, c);
935# endif /* PGM_OUT_OF_SYNC_IN_GC */
936 }
937 else /* GCPhys == NIL_RTGCPHYS */
938 {
939 /*
940 * Page not present in Guest OS or invalid page table address.
941 * This is potential virtual page access handler food.
942 *
943 * For the present we'll say that our access handlers don't
944 * work for this case - we've already discarded the page table
945 * not present case which is identical to this.
946 *
947 * When we perchance find we need this, we will probably have AVL
948 * trees (offset based) to operate on and we can measure their speed
949 * agains mapping a page table and probably rearrange this handling
950 * a bit. (Like, searching virtual ranges before checking the
951 * physical address.)
952 */
953 }
954 }
955
956# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
957 /*
958 * Conclusion, this is a guest trap.
959 */
960 LogFlow(("PGM: Unhandled #PF -> route trap to recompiler!\n"));
961 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eGuestPFUnh);
962 return VINF_EM_RAW_GUEST_TRAP;
963# else
964 /* present, but not a monitored page; perhaps the guest is probing physical memory */
965 return VINF_EM_RAW_EMULATE_INSTR;
966# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
967
968
969# else /* PGM_GST_TYPE != PGM_TYPE_32BIT */
970
971 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
972 return VERR_INTERNAL_ERROR;
973# endif /* PGM_GST_TYPE != PGM_TYPE_32BIT */
974}
975#endif /* !IN_RING3 */
976
977
978/**
979 * Emulation of the invlpg instruction.
980 *
981 *
982 * @returns VBox status code.
983 *
984 * @param pVCpu The VMCPU handle.
985 * @param GCPtrPage Page to invalidate.
986 *
987 * @remark ASSUMES that the guest is updating before invalidating. This order
988 * isn't required by the CPU, so this is speculative and could cause
989 * trouble.
990 * @remark No TLB shootdown is done on any other VCPU as we assume that
991 * invlpg emulation is the *only* reason for calling this function.
992 * (The guest has to shoot down TLB entries on other CPUs itself)
993 * Currently true, but keep in mind!
994 *
995 * @todo Clean this up! Most of it is (or should be) no longer necessary as we catch all page table accesses.
996 */
997PGM_BTH_DECL(int, InvalidatePage)(PVMCPU pVCpu, RTGCPTR GCPtrPage)
998{
999#if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) \
1000 && PGM_SHW_TYPE != PGM_TYPE_NESTED \
1001 && PGM_SHW_TYPE != PGM_TYPE_EPT
1002 int rc;
1003 PVM pVM = pVCpu->CTX_SUFF(pVM);
1004 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1005
1006 Assert(PGMIsLockOwner(pVM));
1007
1008 LogFlow(("InvalidatePage %RGv\n", GCPtrPage));
1009
1010# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
1011 if (pPool->cDirtyPages)
1012 pgmPoolResetDirtyPages(pVM);
1013# endif
1014
1015 /*
1016 * Get the shadow PD entry and skip out if this PD isn't present.
1017 * (Guessing that it is frequent for a shadow PDE to not be present, do this first.)
1018 */
1019# if PGM_SHW_TYPE == PGM_TYPE_32BIT
1020 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
1021 PX86PDE pPdeDst = pgmShwGet32BitPDEPtr(&pVCpu->pgm.s, GCPtrPage);
1022
1023 /* Fetch the pgm pool shadow descriptor. */
1024 PPGMPOOLPAGE pShwPde = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
1025 Assert(pShwPde);
1026
1027# elif PGM_SHW_TYPE == PGM_TYPE_PAE
1028 const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT);
1029 PX86PDPT pPdptDst = pgmShwGetPaePDPTPtr(&pVCpu->pgm.s);
1030
1031 /* If the shadow PDPE isn't present, then skip the invalidate. */
1032 if (!pPdptDst->a[iPdpt].n.u1Present)
1033 {
1034 Assert(!(pPdptDst->a[iPdpt].u & PGM_PLXFLAGS_MAPPING));
1035 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePageSkipped));
1036 return VINF_SUCCESS;
1037 }
1038
1039 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
1040 PPGMPOOLPAGE pShwPde = NULL;
1041 PX86PDPAE pPDDst;
1042
1043 /* Fetch the pgm pool shadow descriptor. */
1044 rc = pgmShwGetPaePoolPagePD(&pVCpu->pgm.s, GCPtrPage, &pShwPde);
1045 AssertRCSuccessReturn(rc, rc);
1046 Assert(pShwPde);
1047
1048 pPDDst = (PX86PDPAE)PGMPOOL_PAGE_2_PTR_BY_PGM(&pVM->pgm.s, pShwPde);
1049 PX86PDEPAE pPdeDst = &pPDDst->a[iPDDst];
1050
1051# else /* PGM_SHW_TYPE == PGM_TYPE_AMD64 */
1052 /* PML4 */
1053 const unsigned iPml4 = (GCPtrPage >> X86_PML4_SHIFT) & X86_PML4_MASK;
1054 const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1055 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
1056 PX86PDPAE pPDDst;
1057 PX86PDPT pPdptDst;
1058 PX86PML4E pPml4eDst;
1059 rc = pgmShwGetLongModePDPtr(pVCpu, GCPtrPage, &pPml4eDst, &pPdptDst, &pPDDst);
1060 if (rc != VINF_SUCCESS)
1061 {
1062 AssertMsg(rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT, ("Unexpected rc=%Rrc\n", rc));
1063 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePageSkipped));
1064 return VINF_SUCCESS;
1065 }
1066 Assert(pPDDst);
1067
1068 PX86PDEPAE pPdeDst = &pPDDst->a[iPDDst];
1069 PX86PDPE pPdpeDst = &pPdptDst->a[iPdpt];
1070
1071 if (!pPdpeDst->n.u1Present)
1072 {
1073 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePageSkipped));
1074 return VINF_SUCCESS;
1075 }
1076
1077 /* Fetch the pgm pool shadow descriptor. */
1078 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pPool, pPdptDst->a[iPdpt].u & SHW_PDPE_PG_MASK);
1079 Assert(pShwPde);
1080
1081# endif /* PGM_SHW_TYPE == PGM_TYPE_AMD64 */
1082
1083 const SHWPDE PdeDst = *pPdeDst;
1084 if (!PdeDst.n.u1Present)
1085 {
1086 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePageSkipped));
1087 return VINF_SUCCESS;
1088 }
1089
1090# if defined(IN_RC)
1091 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
1092 PGMDynLockHCPage(pVM, (uint8_t *)pPdeDst);
1093# endif
1094
1095 /*
1096 * Get the guest PD entry and calc big page.
1097 */
1098# if PGM_GST_TYPE == PGM_TYPE_32BIT
1099 PGSTPD pPDSrc = pgmGstGet32bitPDPtr(&pVCpu->pgm.s);
1100 const unsigned iPDSrc = GCPtrPage >> GST_PD_SHIFT;
1101 GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
1102# else /* PGM_GST_TYPE != PGM_TYPE_32BIT */
1103 unsigned iPDSrc = 0;
1104# if PGM_GST_TYPE == PGM_TYPE_PAE
1105 X86PDPE PdpeSrc;
1106 PX86PDPAE pPDSrc = pgmGstGetPaePDPtr(&pVCpu->pgm.s, GCPtrPage, &iPDSrc, &PdpeSrc);
1107# else /* AMD64 */
1108 PX86PML4E pPml4eSrc;
1109 X86PDPE PdpeSrc;
1110 PX86PDPAE pPDSrc = pgmGstGetLongModePDPtr(&pVCpu->pgm.s, GCPtrPage, &pPml4eSrc, &PdpeSrc, &iPDSrc);
1111# endif
1112 GSTPDE PdeSrc;
1113
1114 if (pPDSrc)
1115 PdeSrc = pPDSrc->a[iPDSrc];
1116 else
1117 PdeSrc.u = 0;
1118# endif /* PGM_GST_TYPE != PGM_TYPE_32BIT */
1119
1120# if PGM_GST_TYPE == PGM_TYPE_32BIT
1121 const bool fIsBigPage = PdeSrc.b.u1Size && CPUMIsGuestPageSizeExtEnabled(pVCpu);
1122# else
1123 const bool fIsBigPage = PdeSrc.b.u1Size;
1124# endif
1125
1126# ifdef IN_RING3
1127 /*
1128 * If a CR3 Sync is pending we may ignore the invalidate page operation
1129 * depending on the kind of sync and if it's a global page or not.
1130 * This doesn't make sense in GC/R0 so we'll skip it entirely there.
1131 */
1132# ifdef PGM_SKIP_GLOBAL_PAGEDIRS_ON_NONGLOBAL_FLUSH
1133 if ( VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3)
1134 || ( VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL)
1135 && fIsBigPage
1136 && PdeSrc.b.u1Global
1137 )
1138 )
1139# else
1140 if (VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL) )
1141# endif
1142 {
1143 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePageSkipped));
1144 return VINF_SUCCESS;
1145 }
1146# endif /* IN_RING3 */
1147
1148 /*
1149 * Deal with the Guest PDE.
1150 */
1151 rc = VINF_SUCCESS;
1152 if (PdeSrc.n.u1Present)
1153 {
1154 Assert( PdeSrc.n.u1User == PdeDst.n.u1User
1155 && (PdeSrc.n.u1Write || !PdeDst.n.u1Write));
1156# ifndef PGM_WITHOUT_MAPPING
1157 if (PdeDst.u & PGM_PDFLAGS_MAPPING)
1158 {
1159 /*
1160 * Conflict - Let SyncPT deal with it to avoid duplicate code.
1161 */
1162 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
1163 Assert(PGMGetGuestMode(pVCpu) <= PGMMODE_PAE);
1164 pgmLock(pVM);
1165 rc = PGM_BTH_NAME(SyncPT)(pVCpu, iPDSrc, pPDSrc, GCPtrPage);
1166 pgmUnlock(pVM);
1167 }
1168 else
1169# endif /* !PGM_WITHOUT_MAPPING */
1170 if (!fIsBigPage)
1171 {
1172 /*
1173 * 4KB - page.
1174 */
1175 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, PdeDst.u & SHW_PDE_PG_MASK);
1176 RTGCPHYS GCPhys = PdeSrc.u & GST_PDE_PG_MASK;
1177
1178# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
1179 /* Reset the modification counter (OpenSolaris trashes tlb entries very often) */
1180 if (pShwPage->cModifications)
1181 pShwPage->cModifications = 1;
1182# endif
1183
1184# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
1185 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
1186 GCPhys |= (iPDDst & 1) * (PAGE_SIZE/2);
1187# endif
1188 if (pShwPage->GCPhys == GCPhys)
1189 {
1190# if 0 /* likely cause of a major performance regression; must be SyncPageWorkerTrackDeref then */
1191 const unsigned iPTEDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1192 PSHWPT pPT = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1193 if (pPT->a[iPTEDst].n.u1Present)
1194 {
1195 /* This is very unlikely with caching/monitoring enabled. */
1196 PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pShwPage, pPT->a[iPTEDst].u & SHW_PTE_PG_MASK, iPTEDst);
1197 ASMAtomicWriteSize(&pPT->a[iPTEDst], 0);
1198 }
1199# else /* Syncing it here isn't 100% safe and it's probably not worth spending time syncing it. */
1200 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, GCPtrPage, 1, 0);
1201 if (RT_SUCCESS(rc))
1202 rc = VINF_SUCCESS;
1203# endif
1204 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePage4KBPages));
1205 PGM_INVL_PG(pVCpu, GCPtrPage);
1206 }
1207 else
1208 {
1209 /*
1210 * The page table address changed.
1211 */
1212 LogFlow(("InvalidatePage: Out-of-sync at %RGp PdeSrc=%RX64 PdeDst=%RX64 ShwGCPhys=%RGp iPDDst=%#x\n",
1213 GCPtrPage, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u, pShwPage->GCPhys, iPDDst));
1214 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, pShwPde->idx, iPDDst);
1215 ASMAtomicWriteSize(pPdeDst, 0);
1216 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePagePDOutOfSync));
1217 PGM_INVL_VCPU_TLBS(pVCpu);
1218 }
1219 }
1220 else
1221 {
1222 /*
1223 * 2/4MB - page.
1224 */
1225 /* Before freeing the page, check if anything really changed. */
1226 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, PdeDst.u & SHW_PDE_PG_MASK);
1227 RTGCPHYS GCPhys = GST_GET_PDE_BIG_PG_GCPHYS(PdeSrc);
1228# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
1229 /* Select the right PDE as we're emulating a 4MB page directory with two 2 MB shadow PDEs.*/
1230 GCPhys |= GCPtrPage & (1 << X86_PD_PAE_SHIFT);
1231# endif
1232 if ( pShwPage->GCPhys == GCPhys
1233 && pShwPage->enmKind == BTH_PGMPOOLKIND_PT_FOR_BIG)
1234 {
1235 /* ASSUMES a the given bits are identical for 4M and normal PDEs */
1236 /** @todo PAT */
1237 if ( (PdeSrc.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD))
1238 == (PdeDst.u & (X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT | X86_PDE_PCD))
1239 && ( PdeSrc.b.u1Dirty /** @todo rainy day: What about read-only 4M pages? not very common, but still... */
1240 || (PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY)))
1241 {
1242 LogFlow(("Skipping flush for big page containing %RGv (PD=%X .u=%RX64)-> nothing has changed!\n", GCPtrPage, iPDSrc, PdeSrc.u));
1243 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePage4MBPagesSkip));
1244# if defined(IN_RC)
1245 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
1246 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
1247# endif
1248 return VINF_SUCCESS;
1249 }
1250 }
1251
1252 /*
1253 * Ok, the page table is present and it's been changed in the guest.
1254 * If we're in host context, we'll just mark it as not present taking the lazy approach.
1255 * We could do this for some flushes in GC too, but we need an algorithm for
1256 * deciding which 4MB pages containing code likely to be executed very soon.
1257 */
1258 LogFlow(("InvalidatePage: Out-of-sync PD at %RGp PdeSrc=%RX64 PdeDst=%RX64\n",
1259 GCPtrPage, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
1260 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, pShwPde->idx, iPDDst);
1261 ASMAtomicWriteSize(pPdeDst, 0);
1262 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePage4MBPages));
1263 PGM_INVL_BIG_PG(pVCpu, GCPtrPage);
1264 }
1265 }
1266 else
1267 {
1268 /*
1269 * Page directory is not present, mark shadow PDE not present.
1270 */
1271 if (!(PdeDst.u & PGM_PDFLAGS_MAPPING))
1272 {
1273 pgmPoolFree(pVM, PdeDst.u & SHW_PDE_PG_MASK, pShwPde->idx, iPDDst);
1274 ASMAtomicWriteSize(pPdeDst, 0);
1275 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePagePDNPs));
1276 PGM_INVL_PG(pVCpu, GCPtrPage);
1277 }
1278 else
1279 {
1280 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
1281 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePagePDMappings));
1282 }
1283 }
1284# if defined(IN_RC)
1285 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
1286 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
1287# endif
1288 return rc;
1289
1290#else /* guest real and protected mode */
1291 /* There's no such thing as InvalidatePage when paging is disabled, so just ignore. */
1292 return VINF_SUCCESS;
1293#endif
1294}
1295
1296
1297/**
1298 * Update the tracking of shadowed pages.
1299 *
1300 * @param pVCpu The VMCPU handle.
1301 * @param pShwPage The shadow page.
1302 * @param HCPhys The physical page we is being dereferenced.
1303 * @param iPte Shadow PTE index
1304 */
1305DECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackDeref)(PVMCPU pVCpu, PPGMPOOLPAGE pShwPage, RTHCPHYS HCPhys, uint16_t iPte)
1306{
1307 PVM pVM = pVCpu->CTX_SUFF(pVM);
1308
1309 STAM_PROFILE_START(&pVM->pgm.s.StatTrackDeref, a);
1310 LogFlow(("SyncPageWorkerTrackDeref: Damn HCPhys=%RHp pShwPage->idx=%#x!!!\n", HCPhys, pShwPage->idx));
1311
1312 /** @todo If this turns out to be a bottle neck (*very* likely) two things can be done:
1313 * 1. have a medium sized HCPhys -> GCPhys TLB (hash?)
1314 * 2. write protect all shadowed pages. I.e. implement caching.
1315 */
1316 /** @todo duplicated in the 2nd half of pgmPoolTracDerefGCPhysHint */
1317
1318 /*
1319 * Find the guest address.
1320 */
1321 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
1322 pRam;
1323 pRam = pRam->CTX_SUFF(pNext))
1324 {
1325 unsigned iPage = pRam->cb >> PAGE_SHIFT;
1326 while (iPage-- > 0)
1327 {
1328 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
1329 {
1330 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1331
1332 Assert(pShwPage->cPresent);
1333 Assert(pPool->cPresent);
1334 pShwPage->cPresent--;
1335 pPool->cPresent--;
1336
1337 pgmTrackDerefGCPhys(pPool, pShwPage, &pRam->aPages[iPage], iPte);
1338 STAM_PROFILE_STOP(&pVM->pgm.s.StatTrackDeref, a);
1339 return;
1340 }
1341 }
1342 }
1343
1344 for (;;)
1345 AssertReleaseMsgFailed(("HCPhys=%RHp wasn't found!\n", HCPhys));
1346}
1347
1348
1349/**
1350 * Update the tracking of shadowed pages.
1351 *
1352 * @param pVCpu The VMCPU handle.
1353 * @param pShwPage The shadow page.
1354 * @param u16 The top 16-bit of the pPage->HCPhys.
1355 * @param pPage Pointer to the guest page. this will be modified.
1356 * @param iPTDst The index into the shadow table.
1357 */
1358DECLINLINE(void) PGM_BTH_NAME(SyncPageWorkerTrackAddref)(PVMCPU pVCpu, PPGMPOOLPAGE pShwPage, uint16_t u16, PPGMPAGE pPage, const unsigned iPTDst)
1359{
1360 PVM pVM = pVCpu->CTX_SUFF(pVM);
1361 /*
1362 * Just deal with the simple first time here.
1363 */
1364 if (!u16)
1365 {
1366 STAM_COUNTER_INC(&pVM->pgm.s.StatTrackVirgin);
1367 u16 = PGMPOOL_TD_MAKE(1, pShwPage->idx);
1368 /* Save the page table index. */
1369 PGM_PAGE_SET_PTE_INDEX(pPage, iPTDst);
1370 }
1371 else
1372 u16 = pgmPoolTrackPhysExtAddref(pVM, pPage, u16, pShwPage->idx, iPTDst);
1373
1374 /* write back */
1375 Log2(("SyncPageWorkerTrackAddRef: u16=%#x->%#x iPTDst=%#x\n", u16, PGM_PAGE_GET_TRACKING(pPage), iPTDst));
1376 PGM_PAGE_SET_TRACKING(pPage, u16);
1377
1378 /* update statistics. */
1379 pVM->pgm.s.CTX_SUFF(pPool)->cPresent++;
1380 pShwPage->cPresent++;
1381 if (pShwPage->iFirstPresent > iPTDst)
1382 pShwPage->iFirstPresent = iPTDst;
1383}
1384
1385
1386/**
1387 * Creates a 4K shadow page for a guest page.
1388 *
1389 * For 4M pages the caller must convert the PDE4M to a PTE, this includes adjusting the
1390 * physical address. The PdeSrc argument only the flags are used. No page structured
1391 * will be mapped in this function.
1392 *
1393 * @param pVCpu The VMCPU handle.
1394 * @param pPteDst Destination page table entry.
1395 * @param PdeSrc Source page directory entry (i.e. Guest OS page directory entry).
1396 * Can safely assume that only the flags are being used.
1397 * @param PteSrc Source page table entry (i.e. Guest OS page table entry).
1398 * @param pShwPage Pointer to the shadow page.
1399 * @param iPTDst The index into the shadow table.
1400 *
1401 * @remark Not used for 2/4MB pages!
1402 */
1403DECLINLINE(void) PGM_BTH_NAME(SyncPageWorker)(PVMCPU pVCpu, PSHWPTE pPteDst, GSTPDE PdeSrc, GSTPTE PteSrc, PPGMPOOLPAGE pShwPage, unsigned iPTDst)
1404{
1405 if (PteSrc.n.u1Present)
1406 {
1407 PVM pVM = pVCpu->CTX_SUFF(pVM);
1408
1409# if defined(PGMPOOL_WITH_OPTIMIZED_DIRTY_PT) \
1410 && PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) \
1411 && (PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64)
1412 if (pShwPage->fDirty)
1413 {
1414 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1415 PX86PTPAE pGstPT;
1416
1417 pGstPT = (PX86PTPAE)&pPool->aDirtyPages[pShwPage->idxDirty][0];
1418 pGstPT->a[iPTDst].u = PteSrc.u;
1419 }
1420# endif
1421 /*
1422 * Find the ram range.
1423 */
1424 PPGMPAGE pPage;
1425 int rc = pgmPhysGetPageEx(&pVM->pgm.s, PteSrc.u & GST_PTE_PG_MASK, &pPage);
1426 if (RT_SUCCESS(rc))
1427 {
1428 /* Ignore ballooned pages. Don't return errors or use a fatal assert here as part of a shadow sync range might included ballooned pages. */
1429 if (PGM_PAGE_IS_BALLOONED(pPage))
1430 return;
1431
1432#ifndef VBOX_WITH_NEW_LAZY_PAGE_ALLOC
1433 /* Try to make the page writable if necessary. */
1434 if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
1435 && ( PGM_PAGE_IS_ZERO(pPage)
1436 || ( PteSrc.n.u1Write
1437 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
1438# ifdef VBOX_WITH_REAL_WRITE_MONITORED_PAGES
1439 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_WRITE_MONITORED
1440# endif
1441# ifdef VBOX_WITH_PAGE_SHARING
1442 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_SHARED
1443# endif
1444 )
1445 )
1446 )
1447 {
1448 rc = pgmPhysPageMakeWritable(pVM, pPage, PteSrc.u & GST_PTE_PG_MASK);
1449 AssertRC(rc);
1450 }
1451#endif
1452
1453 /** @todo investiage PWT, PCD and PAT. */
1454 /*
1455 * Make page table entry.
1456 */
1457 SHWPTE PteDst;
1458 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
1459 {
1460 /** @todo r=bird: Are we actually handling dirty and access bits for pages with access handlers correctly? No. */
1461 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
1462 {
1463#if PGM_SHW_TYPE == PGM_TYPE_EPT
1464 PteDst.u = PGM_PAGE_GET_HCPHYS(pPage);
1465 PteDst.n.u1Present = 1;
1466 PteDst.n.u1Execute = 1;
1467 PteDst.n.u1IgnorePAT = 1;
1468 PteDst.n.u3EMT = VMX_EPT_MEMTYPE_WB;
1469 /* PteDst.n.u1Write = 0 && PteDst.n.u1Size = 0 */
1470#else
1471 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))
1472 | PGM_PAGE_GET_HCPHYS(pPage);
1473#endif
1474 }
1475 else
1476 {
1477 LogFlow(("SyncPageWorker: monitored page (%RHp) -> mark not present\n", PGM_PAGE_GET_HCPHYS(pPage)));
1478 PteDst.u = 0;
1479 }
1480 /** @todo count these two kinds. */
1481 }
1482 else
1483 {
1484#if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
1485 /*
1486 * If the page or page directory entry is not marked accessed,
1487 * we mark the page not present.
1488 */
1489 if (!PteSrc.n.u1Accessed || !PdeSrc.n.u1Accessed)
1490 {
1491 LogFlow(("SyncPageWorker: page and or page directory not accessed -> mark not present\n"));
1492 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,AccessedPage));
1493 PteDst.u = 0;
1494 }
1495 else
1496 /*
1497 * If the page is not flagged as dirty and is writable, then make it read-only, so we can set the dirty bit
1498 * when the page is modified.
1499 */
1500 if (!PteSrc.n.u1Dirty && (PdeSrc.n.u1Write & PteSrc.n.u1Write))
1501 {
1502 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPage));
1503 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))
1504 | PGM_PAGE_GET_HCPHYS(pPage)
1505 | PGM_PTFLAGS_TRACK_DIRTY;
1506 }
1507 else
1508#endif
1509 {
1510 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPageSkipped));
1511#if PGM_SHW_TYPE == PGM_TYPE_EPT
1512 PteDst.u = PGM_PAGE_GET_HCPHYS(pPage);
1513 PteDst.n.u1Present = 1;
1514 PteDst.n.u1Write = 1;
1515 PteDst.n.u1Execute = 1;
1516 PteDst.n.u1IgnorePAT = 1;
1517 PteDst.n.u3EMT = VMX_EPT_MEMTYPE_WB;
1518 /* PteDst.n.u1Size = 0 */
1519#else
1520 PteDst.u = (PteSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT))
1521 | PGM_PAGE_GET_HCPHYS(pPage);
1522#endif
1523 }
1524 }
1525
1526 /*
1527 * Make sure only allocated pages are mapped writable.
1528 */
1529 if ( PteDst.n.u1Write
1530 && PteDst.n.u1Present
1531 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
1532 {
1533 /* Still applies to shared pages. */
1534 Assert(!PGM_PAGE_IS_ZERO(pPage));
1535 PteDst.n.u1Write = 0; /** @todo this isn't quite working yet. */
1536 Log3(("SyncPageWorker: write-protecting %RGp pPage=%R[pgmpage]at iPTDst=%d\n", (RTGCPHYS)(PteSrc.u & X86_PTE_PAE_PG_MASK), pPage, iPTDst));
1537 }
1538
1539 /*
1540 * Keep user track up to date.
1541 */
1542 if (PteDst.n.u1Present)
1543 {
1544 if (!pPteDst->n.u1Present)
1545 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPTDst);
1546 else if ((pPteDst->u & SHW_PTE_PG_MASK) != (PteDst.u & SHW_PTE_PG_MASK))
1547 {
1548 Log2(("SyncPageWorker: deref! *pPteDst=%RX64 PteDst=%RX64\n", (uint64_t)pPteDst->u, (uint64_t)PteDst.u));
1549 PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, pPteDst->u & SHW_PTE_PG_MASK, iPTDst);
1550 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPTDst);
1551 }
1552 }
1553 else if (pPteDst->n.u1Present)
1554 {
1555 Log2(("SyncPageWorker: deref! *pPteDst=%RX64\n", (uint64_t)pPteDst->u));
1556 PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, pPteDst->u & SHW_PTE_PG_MASK, iPTDst);
1557 }
1558
1559 /*
1560 * Update statistics and commit the entry.
1561 */
1562#if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
1563 if (!PteSrc.n.u1Global)
1564 pShwPage->fSeenNonGlobal = true;
1565#endif
1566 ASMAtomicWriteSize(pPteDst, PteDst.u);
1567 }
1568 /* else MMIO or invalid page, we must handle them manually in the #PF handler. */
1569 /** @todo count these. */
1570 }
1571 else
1572 {
1573 /*
1574 * Page not-present.
1575 */
1576 Log2(("SyncPageWorker: page not present in Pte\n"));
1577 /* Keep user track up to date. */
1578 if (pPteDst->n.u1Present)
1579 {
1580 Log2(("SyncPageWorker: deref! *pPteDst=%RX64\n", (uint64_t)pPteDst->u));
1581 PGM_BTH_NAME(SyncPageWorkerTrackDeref)(pVCpu, pShwPage, pPteDst->u & SHW_PTE_PG_MASK, iPTDst);
1582 }
1583 ASMAtomicWriteSize(pPteDst, 0);
1584 /** @todo count these. */
1585 }
1586}
1587
1588
1589/**
1590 * Syncs a guest OS page.
1591 *
1592 * There are no conflicts at this point, neither is there any need for
1593 * page table allocations.
1594 *
1595 * @returns VBox status code.
1596 * @returns VINF_PGM_SYNCPAGE_MODIFIED_PDE if it modifies the PDE in any way.
1597 * @param pVCpu The VMCPU handle.
1598 * @param PdeSrc Page directory entry of the guest.
1599 * @param GCPtrPage Guest context page address.
1600 * @param cPages Number of pages to sync (PGM_SYNC_N_PAGES) (default=1).
1601 * @param uErr Fault error (X86_TRAP_PF_*).
1602 */
1603PGM_BTH_DECL(int, SyncPage)(PVMCPU pVCpu, GSTPDE PdeSrc, RTGCPTR GCPtrPage, unsigned cPages, unsigned uErr)
1604{
1605 PVM pVM = pVCpu->CTX_SUFF(pVM);
1606 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1607 LogFlow(("SyncPage: GCPtrPage=%RGv cPages=%u uErr=%#x\n", GCPtrPage, cPages, uErr));
1608
1609 Assert(PGMIsLockOwner(pVM));
1610
1611#if ( PGM_GST_TYPE == PGM_TYPE_32BIT \
1612 || PGM_GST_TYPE == PGM_TYPE_PAE \
1613 || PGM_GST_TYPE == PGM_TYPE_AMD64) \
1614 && PGM_SHW_TYPE != PGM_TYPE_NESTED \
1615 && PGM_SHW_TYPE != PGM_TYPE_EPT
1616
1617 /*
1618 * Assert preconditions.
1619 */
1620 Assert(PdeSrc.n.u1Present);
1621 Assert(cPages);
1622# if 0 /* rarely useful; leave for debugging. */
1623 STAM_COUNTER_INC(&pVCpu->pgm.s.StatSyncPagePD[(GCPtrPage >> GST_PD_SHIFT) & GST_PD_MASK]);
1624# endif
1625
1626 /*
1627 * Get the shadow PDE, find the shadow page table in the pool.
1628 */
1629# if PGM_SHW_TYPE == PGM_TYPE_32BIT
1630 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
1631 PX86PDE pPdeDst = pgmShwGet32BitPDEPtr(&pVCpu->pgm.s, GCPtrPage);
1632
1633 /* Fetch the pgm pool shadow descriptor. */
1634 PPGMPOOLPAGE pShwPde = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
1635 Assert(pShwPde);
1636
1637# elif PGM_SHW_TYPE == PGM_TYPE_PAE
1638 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
1639 PPGMPOOLPAGE pShwPde = NULL;
1640 PX86PDPAE pPDDst;
1641
1642 /* Fetch the pgm pool shadow descriptor. */
1643 int rc2 = pgmShwGetPaePoolPagePD(&pVCpu->pgm.s, GCPtrPage, &pShwPde);
1644 AssertRCSuccessReturn(rc2, rc2);
1645 Assert(pShwPde);
1646
1647 pPDDst = (PX86PDPAE)PGMPOOL_PAGE_2_PTR_BY_PGM(&pVM->pgm.s, pShwPde);
1648 PX86PDEPAE pPdeDst = &pPDDst->a[iPDDst];
1649
1650# elif PGM_SHW_TYPE == PGM_TYPE_AMD64
1651 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
1652 const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1653 PX86PDPAE pPDDst = NULL; /* initialized to shut up gcc */
1654 PX86PDPT pPdptDst = NULL; /* initialized to shut up gcc */
1655
1656 int rc2 = pgmShwGetLongModePDPtr(pVCpu, GCPtrPage, NULL, &pPdptDst, &pPDDst);
1657 AssertRCSuccessReturn(rc2, rc2);
1658 Assert(pPDDst && pPdptDst);
1659 PX86PDEPAE pPdeDst = &pPDDst->a[iPDDst];
1660# endif
1661 SHWPDE PdeDst = *pPdeDst;
1662
1663 /* In the guest SMP case we could have blocked while another VCPU reused this page table. */
1664 if (!PdeDst.n.u1Present)
1665 {
1666 AssertMsg(pVM->cCpus > 1, ("Unexpected missing PDE p=%p/%RX64\n", pPdeDst, (uint64_t)PdeDst.u));
1667 Log(("CPU%d: SyncPage: Pde at %RGv changed behind our back!\n", pVCpu->idCpu, GCPtrPage));
1668 return VINF_SUCCESS; /* force the instruction to be executed again. */
1669 }
1670
1671 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, PdeDst.u & SHW_PDE_PG_MASK);
1672 Assert(pShwPage);
1673
1674# if PGM_GST_TYPE == PGM_TYPE_AMD64
1675 /* Fetch the pgm pool shadow descriptor. */
1676 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pPool, pPdptDst->a[iPdpt].u & X86_PDPE_PG_MASK);
1677 Assert(pShwPde);
1678# endif
1679
1680# if defined(IN_RC)
1681 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
1682 PGMDynLockHCPage(pVM, (uint8_t *)pPdeDst);
1683# endif
1684
1685 /*
1686 * Check that the page is present and that the shadow PDE isn't out of sync.
1687 */
1688# if PGM_GST_TYPE == PGM_TYPE_32BIT
1689 const bool fBigPage = PdeSrc.b.u1Size && CPUMIsGuestPageSizeExtEnabled(pVCpu);
1690# else
1691 const bool fBigPage = PdeSrc.b.u1Size;
1692# endif
1693 RTGCPHYS GCPhys;
1694 if (!fBigPage)
1695 {
1696 GCPhys = PdeSrc.u & GST_PDE_PG_MASK;
1697# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
1698 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
1699 GCPhys |= (iPDDst & 1) * (PAGE_SIZE / 2);
1700# endif
1701 }
1702 else
1703 {
1704 GCPhys = GST_GET_PDE_BIG_PG_GCPHYS(PdeSrc);
1705# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
1706 /* Select the right PDE as we're emulating a 4MB page directory with two 2 MB shadow PDEs.*/
1707 GCPhys |= GCPtrPage & (1 << X86_PD_PAE_SHIFT);
1708# endif
1709 }
1710 if ( pShwPage->GCPhys == GCPhys
1711 && PdeSrc.n.u1Present
1712 && (PdeSrc.n.u1User == PdeDst.n.u1User)
1713 && (PdeSrc.n.u1Write == PdeDst.n.u1Write || !PdeDst.n.u1Write)
1714# if PGM_WITH_NX(PGM_GST_TYPE, PGM_SHW_TYPE)
1715 && (PdeSrc.n.u1NoExecute == PdeDst.n.u1NoExecute || !CPUMIsGuestNXEnabled(pVCpu))
1716# endif
1717 )
1718 {
1719 /*
1720 * Check that the PDE is marked accessed already.
1721 * Since we set the accessed bit *before* getting here on a #PF, this
1722 * check is only meant for dealing with non-#PF'ing paths.
1723 */
1724 if (PdeSrc.n.u1Accessed)
1725 {
1726 PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1727 if (!fBigPage)
1728 {
1729 /*
1730 * 4KB Page - Map the guest page table.
1731 */
1732 PGSTPT pPTSrc;
1733 int rc = PGM_GCPHYS_2_PTR(pVM, PdeSrc.u & GST_PDE_PG_MASK, &pPTSrc);
1734 if (RT_SUCCESS(rc))
1735 {
1736# ifdef PGM_SYNC_N_PAGES
1737 Assert(cPages == 1 || !(uErr & X86_TRAP_PF_P));
1738 if ( cPages > 1
1739 && !(uErr & X86_TRAP_PF_P)
1740 && !VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
1741 {
1742 /*
1743 * This code path is currently only taken when the caller is PGMTrap0eHandler
1744 * for non-present pages!
1745 *
1746 * We're setting PGM_SYNC_NR_PAGES pages around the faulting page to sync it and
1747 * deal with locality.
1748 */
1749 unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1750# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
1751 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
1752 const unsigned offPTSrc = ((GCPtrPage >> SHW_PD_SHIFT) & 1) * 512;
1753# else
1754 const unsigned offPTSrc = 0;
1755# endif
1756 const unsigned iPTDstEnd = RT_MIN(iPTDst + PGM_SYNC_NR_PAGES / 2, RT_ELEMENTS(pPTDst->a));
1757 if (iPTDst < PGM_SYNC_NR_PAGES / 2)
1758 iPTDst = 0;
1759 else
1760 iPTDst -= PGM_SYNC_NR_PAGES / 2;
1761 for (; iPTDst < iPTDstEnd; iPTDst++)
1762 {
1763 if (!pPTDst->a[iPTDst].n.u1Present)
1764 {
1765 GSTPTE PteSrc = pPTSrc->a[offPTSrc + iPTDst];
1766 RTGCPTR GCPtrCurPage = (GCPtrPage & ~(RTGCPTR)(GST_PT_MASK << GST_PT_SHIFT)) | ((offPTSrc + iPTDst) << PAGE_SHIFT);
1767 NOREF(GCPtrCurPage);
1768#ifndef IN_RING0
1769 /*
1770 * Assuming kernel code will be marked as supervisor - and not as user level
1771 * and executed using a conforming code selector - And marked as readonly.
1772 * Also assume that if we're monitoring a page, it's of no interest to CSAM.
1773 */
1774 PPGMPAGE pPage;
1775 if ( ((PdeSrc.u & PteSrc.u) & (X86_PTE_RW | X86_PTE_US))
1776 || iPTDst == ((GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK) /* always sync GCPtrPage */
1777 || !CSAMDoesPageNeedScanning(pVM, GCPtrCurPage)
1778 || ( (pPage = pgmPhysGetPage(&pVM->pgm.s, PteSrc.u & GST_PTE_PG_MASK))
1779 && PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
1780 )
1781#endif /* else: CSAM not active */
1782 PGM_BTH_NAME(SyncPageWorker)(pVCpu, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
1783 Log2(("SyncPage: 4K+ %RGv PteSrc:{P=%d RW=%d U=%d raw=%08llx} PteDst=%08llx%s\n",
1784 GCPtrCurPage, PteSrc.n.u1Present,
1785 PteSrc.n.u1Write & PdeSrc.n.u1Write,
1786 PteSrc.n.u1User & PdeSrc.n.u1User,
1787 (uint64_t)PteSrc.u,
1788 (uint64_t)pPTDst->a[iPTDst].u,
1789 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
1790 }
1791 }
1792 }
1793 else
1794# endif /* PGM_SYNC_N_PAGES */
1795 {
1796 const unsigned iPTSrc = (GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK;
1797 GSTPTE PteSrc = pPTSrc->a[iPTSrc];
1798 const unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1799 PGM_BTH_NAME(SyncPageWorker)(pVCpu, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
1800 Log2(("SyncPage: 4K %RGv PteSrc:{P=%d RW=%d U=%d raw=%08llx} PteDst=%08llx %s\n",
1801 GCPtrPage, PteSrc.n.u1Present,
1802 PteSrc.n.u1Write & PdeSrc.n.u1Write,
1803 PteSrc.n.u1User & PdeSrc.n.u1User,
1804 (uint64_t)PteSrc.u,
1805 (uint64_t)pPTDst->a[iPTDst].u,
1806 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
1807 }
1808 }
1809 else /* MMIO or invalid page: emulated in #PF handler. */
1810 {
1811 LogFlow(("PGM_GCPHYS_2_PTR %RGp failed with %Rrc\n", GCPhys, rc));
1812 Assert(!pPTDst->a[(GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK].n.u1Present);
1813 }
1814 }
1815 else
1816 {
1817 /*
1818 * 4/2MB page - lazy syncing shadow 4K pages.
1819 * (There are many causes of getting here, it's no longer only CSAM.)
1820 */
1821 /* Calculate the GC physical address of this 4KB shadow page. */
1822 GCPhys = GST_GET_PDE_BIG_PG_GCPHYS(PdeSrc) | (GCPtrPage & GST_BIG_PAGE_OFFSET_MASK);
1823 /* Find ram range. */
1824 PPGMPAGE pPage;
1825 int rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhys, &pPage);
1826 if (RT_SUCCESS(rc))
1827 {
1828 AssertFatalMsg(!PGM_PAGE_IS_BALLOONED(pPage), ("Unexpected ballooned page at %RGp\n", GCPhys));
1829
1830# ifndef VBOX_WITH_NEW_LAZY_PAGE_ALLOC
1831 /* Try to make the page writable if necessary. */
1832 if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
1833 && ( PGM_PAGE_IS_ZERO(pPage)
1834 || ( PdeSrc.n.u1Write
1835 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
1836# ifdef VBOX_WITH_REAL_WRITE_MONITORED_PAGES
1837 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_WRITE_MONITORED
1838# endif
1839# ifdef VBOX_WITH_PAGE_SHARING
1840 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_SHARED
1841# endif
1842 )
1843 )
1844 )
1845 {
1846 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1847 AssertRC(rc);
1848 }
1849# endif
1850
1851 /*
1852 * Make shadow PTE entry.
1853 */
1854 SHWPTE PteDst;
1855 PteDst.u = (PdeSrc.u & ~(X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT))
1856 | PGM_PAGE_GET_HCPHYS(pPage);
1857 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
1858 {
1859 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
1860 PteDst.n.u1Write = 0;
1861 else
1862 PteDst.u = 0;
1863 }
1864
1865 const unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
1866 if ( PteDst.n.u1Present
1867 && !pPTDst->a[iPTDst].n.u1Present)
1868 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPTDst);
1869
1870 /* Make sure only allocated pages are mapped writable. */
1871 if ( PteDst.n.u1Write
1872 && PteDst.n.u1Present
1873 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
1874 {
1875 /* Still applies to shared pages. */
1876 Assert(!PGM_PAGE_IS_ZERO(pPage));
1877 PteDst.n.u1Write = 0; /** @todo this isn't quite working yet... */
1878 Log3(("SyncPage: write-protecting %RGp pPage=%R[pgmpage] at %RGv\n", GCPhys, pPage, GCPtrPage));
1879 }
1880
1881 ASMAtomicWriteSize(&pPTDst->a[iPTDst], PteDst.u);
1882
1883 /*
1884 * If the page is not flagged as dirty and is writable, then make it read-only
1885 * at PD level, so we can set the dirty bit when the page is modified.
1886 *
1887 * ASSUMES that page access handlers are implemented on page table entry level.
1888 * Thus we will first catch the dirty access and set PDE.D and restart. If
1889 * there is an access handler, we'll trap again and let it work on the problem.
1890 */
1891 /** @todo r=bird: figure out why we need this here, SyncPT should've taken care of this already.
1892 * As for invlpg, it simply frees the whole shadow PT.
1893 * ...It's possibly because the guest clears it and the guest doesn't really tell us... */
1894 if ( !PdeSrc.b.u1Dirty
1895 && PdeSrc.b.u1Write)
1896 {
1897 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPageBig));
1898 PdeDst.u |= PGM_PDFLAGS_TRACK_DIRTY;
1899 PdeDst.n.u1Write = 0;
1900 }
1901 else
1902 {
1903 PdeDst.au32[0] &= ~PGM_PDFLAGS_TRACK_DIRTY;
1904 PdeDst.n.u1Write = PdeSrc.n.u1Write;
1905 }
1906 ASMAtomicWriteSize(pPdeDst, PdeDst.u);
1907 Log2(("SyncPage: BIG %RGv PdeSrc:{P=%d RW=%d U=%d raw=%08llx} GCPhys=%RGp%s\n",
1908 GCPtrPage, PdeSrc.n.u1Present, PdeSrc.n.u1Write, PdeSrc.n.u1User, (uint64_t)PdeSrc.u, GCPhys,
1909 PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
1910 }
1911 else
1912 LogFlow(("PGM_GCPHYS_2_PTR %RGp (big) failed with %Rrc\n", GCPhys, rc));
1913 }
1914# if defined(IN_RC)
1915 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
1916 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
1917# endif
1918 return VINF_SUCCESS;
1919 }
1920 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPagePDNAs));
1921 }
1922 else
1923 {
1924 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPagePDOutOfSync));
1925 Log2(("SyncPage: Out-Of-Sync PDE at %RGp PdeSrc=%RX64 PdeDst=%RX64 (GCPhys %RGp vs %RGp)\n",
1926 GCPtrPage, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u, pShwPage->GCPhys, GCPhys));
1927 }
1928
1929 /*
1930 * Mark the PDE not present. Restart the instruction and let #PF call SyncPT.
1931 * Yea, I'm lazy.
1932 */
1933 pgmPoolFreeByPage(pPool, pShwPage, pShwPde->idx, iPDDst);
1934 ASMAtomicWriteSize(pPdeDst, 0);
1935
1936# if defined(IN_RC)
1937 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
1938 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
1939# endif
1940 PGM_INVL_VCPU_TLBS(pVCpu);
1941 return VINF_PGM_SYNCPAGE_MODIFIED_PDE;
1942
1943#elif (PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT) \
1944 && PGM_SHW_TYPE != PGM_TYPE_NESTED \
1945 && (PGM_SHW_TYPE != PGM_TYPE_EPT || PGM_GST_TYPE == PGM_TYPE_PROT) \
1946 && !defined(IN_RC)
1947
1948# ifdef PGM_SYNC_N_PAGES
1949 /*
1950 * Get the shadow PDE, find the shadow page table in the pool.
1951 */
1952# if PGM_SHW_TYPE == PGM_TYPE_32BIT
1953 X86PDE PdeDst = pgmShwGet32BitPDE(&pVCpu->pgm.s, GCPtrPage);
1954
1955# elif PGM_SHW_TYPE == PGM_TYPE_PAE
1956 X86PDEPAE PdeDst = pgmShwGetPaePDE(&pVCpu->pgm.s, GCPtrPage);
1957
1958# elif PGM_SHW_TYPE == PGM_TYPE_AMD64
1959 const unsigned iPDDst = ((GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK);
1960 const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64; NOREF(iPdpt);
1961 PX86PDPAE pPDDst = NULL; /* initialized to shut up gcc */
1962 X86PDEPAE PdeDst;
1963 PX86PDPT pPdptDst = NULL; /* initialized to shut up gcc */
1964
1965 int rc = pgmShwGetLongModePDPtr(pVCpu, GCPtrPage, NULL, &pPdptDst, &pPDDst);
1966 AssertRCSuccessReturn(rc, rc);
1967 Assert(pPDDst && pPdptDst);
1968 PdeDst = pPDDst->a[iPDDst];
1969# elif PGM_SHW_TYPE == PGM_TYPE_EPT
1970 const unsigned iPDDst = ((GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK);
1971 PEPTPD pPDDst;
1972 EPTPDE PdeDst;
1973
1974 int rc = pgmShwGetEPTPDPtr(pVCpu, GCPtrPage, NULL, &pPDDst);
1975 if (rc != VINF_SUCCESS)
1976 {
1977 AssertRC(rc);
1978 return rc;
1979 }
1980 Assert(pPDDst);
1981 PdeDst = pPDDst->a[iPDDst];
1982# endif
1983 /* In the guest SMP case we could have blocked while another VCPU reused this page table. */
1984 if (!PdeDst.n.u1Present)
1985 {
1986 AssertMsg(pVM->cCpus > 1, ("Unexpected missing PDE %RX64\n", (uint64_t)PdeDst.u));
1987 Log(("CPU%d: SyncPage: Pde at %RGv changed behind our back!\n", pVCpu->idCpu, GCPtrPage));
1988 return VINF_SUCCESS; /* force the instruction to be executed again. */
1989 }
1990
1991 /* Can happen in the guest SMP case; other VCPU activated this PDE while we were blocking to handle the page fault. */
1992 if (PdeDst.n.u1Size)
1993 {
1994 Assert(HWACCMIsNestedPagingActive(pVM));
1995 Log(("CPU%d: SyncPage: Pde (big:%RX64) at %RGv changed behind our back!\n", pVCpu->idCpu, PdeDst.u, GCPtrPage));
1996 return VINF_SUCCESS;
1997 }
1998
1999 /* Mask away the page offset. */
2000 GCPtrPage &= ~((RTGCPTR)0xfff);
2001
2002 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, PdeDst.u & SHW_PDE_PG_MASK);
2003 PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
2004
2005 Assert(cPages == 1 || !(uErr & X86_TRAP_PF_P));
2006 if ( cPages > 1
2007 && !(uErr & X86_TRAP_PF_P)
2008 && !VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
2009 {
2010 /*
2011 * This code path is currently only taken when the caller is PGMTrap0eHandler
2012 * for non-present pages!
2013 *
2014 * We're setting PGM_SYNC_NR_PAGES pages around the faulting page to sync it and
2015 * deal with locality.
2016 */
2017 unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
2018 const unsigned iPTDstEnd = RT_MIN(iPTDst + PGM_SYNC_NR_PAGES / 2, RT_ELEMENTS(pPTDst->a));
2019 if (iPTDst < PGM_SYNC_NR_PAGES / 2)
2020 iPTDst = 0;
2021 else
2022 iPTDst -= PGM_SYNC_NR_PAGES / 2;
2023 for (; iPTDst < iPTDstEnd; iPTDst++)
2024 {
2025 if (!pPTDst->a[iPTDst].n.u1Present)
2026 {
2027 GSTPTE PteSrc;
2028
2029 RTGCPTR GCPtrCurPage = (GCPtrPage & ~(RTGCPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT);
2030
2031 /* Fake the page table entry */
2032 PteSrc.u = GCPtrCurPage;
2033 PteSrc.n.u1Present = 1;
2034 PteSrc.n.u1Dirty = 1;
2035 PteSrc.n.u1Accessed = 1;
2036 PteSrc.n.u1Write = 1;
2037 PteSrc.n.u1User = 1;
2038
2039 PGM_BTH_NAME(SyncPageWorker)(pVCpu, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
2040
2041 Log2(("SyncPage: 4K+ %RGv PteSrc:{P=%d RW=%d U=%d raw=%08llx} PteDst=%08llx%s\n",
2042 GCPtrCurPage, PteSrc.n.u1Present,
2043 PteSrc.n.u1Write & PdeSrc.n.u1Write,
2044 PteSrc.n.u1User & PdeSrc.n.u1User,
2045 (uint64_t)PteSrc.u,
2046 (uint64_t)pPTDst->a[iPTDst].u,
2047 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
2048
2049 if (RT_UNLIKELY(VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)))
2050 break;
2051 }
2052 else
2053 Log4(("%RGv iPTDst=%x pPTDst->a[iPTDst] %RX64\n", (GCPtrPage & ~(RTGCPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT), iPTDst, pPTDst->a[iPTDst].u));
2054 }
2055 }
2056 else
2057# endif /* PGM_SYNC_N_PAGES */
2058 {
2059 GSTPTE PteSrc;
2060 const unsigned iPTDst = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
2061 RTGCPTR GCPtrCurPage = (GCPtrPage & ~(RTGCPTR)(SHW_PT_MASK << SHW_PT_SHIFT)) | (iPTDst << PAGE_SHIFT);
2062
2063 /* Fake the page table entry */
2064 PteSrc.u = GCPtrCurPage;
2065 PteSrc.n.u1Present = 1;
2066 PteSrc.n.u1Dirty = 1;
2067 PteSrc.n.u1Accessed = 1;
2068 PteSrc.n.u1Write = 1;
2069 PteSrc.n.u1User = 1;
2070 PGM_BTH_NAME(SyncPageWorker)(pVCpu, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
2071
2072 Log2(("SyncPage: 4K %RGv PteSrc:{P=%d RW=%d U=%d raw=%08llx}PteDst=%08llx%s\n",
2073 GCPtrPage, PteSrc.n.u1Present,
2074 PteSrc.n.u1Write & PdeSrc.n.u1Write,
2075 PteSrc.n.u1User & PdeSrc.n.u1User,
2076 (uint64_t)PteSrc.u,
2077 (uint64_t)pPTDst->a[iPTDst].u,
2078 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
2079 }
2080 return VINF_SUCCESS;
2081
2082#else
2083 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
2084 return VERR_INTERNAL_ERROR;
2085#endif
2086}
2087
2088
2089#if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
2090/**
2091 * Investigate page fault and handle write protection page faults caused by
2092 * dirty bit tracking.
2093 *
2094 * @returns VBox status code.
2095 * @param pVCpu The VMCPU handle.
2096 * @param uErr Page fault error code.
2097 * @param pPdeSrc Guest page directory entry.
2098 * @param GCPtrPage Guest context page address.
2099 */
2100PGM_BTH_DECL(int, CheckPageFault)(PVMCPU pVCpu, uint32_t uErr, PGSTPDE pPdeSrc, RTGCPTR GCPtrPage)
2101{
2102 bool fUserLevelFault = !!(uErr & X86_TRAP_PF_US);
2103 bool fWriteFault = !!(uErr & X86_TRAP_PF_RW);
2104 bool fMaybeWriteProtFault = fWriteFault && (fUserLevelFault || CPUMIsGuestR0WriteProtEnabled(pVCpu));
2105# if PGM_WITH_NX(PGM_GST_TYPE, PGM_SHW_TYPE)
2106 bool fMaybeNXEFault = (uErr & X86_TRAP_PF_ID) && CPUMIsGuestNXEnabled(pVCpu);
2107# endif
2108 unsigned uPageFaultLevel;
2109 int rc;
2110 PVM pVM = pVCpu->CTX_SUFF(pVM);
2111
2112 LogFlow(("CheckPageFault: GCPtrPage=%RGv uErr=%#x PdeSrc=%08x\n", GCPtrPage, uErr, pPdeSrc->u));
2113
2114# if PGM_GST_TYPE == PGM_TYPE_PAE \
2115 || PGM_GST_TYPE == PGM_TYPE_AMD64
2116
2117# if PGM_GST_TYPE == PGM_TYPE_AMD64
2118 PX86PML4E pPml4eSrc;
2119 PX86PDPE pPdpeSrc;
2120
2121 pPdpeSrc = pgmGstGetLongModePDPTPtr(&pVCpu->pgm.s, GCPtrPage, &pPml4eSrc);
2122 Assert(pPml4eSrc);
2123
2124 /*
2125 * Real page fault? (PML4E level)
2126 */
2127 if ( (uErr & X86_TRAP_PF_RSVD)
2128 || !pPml4eSrc->n.u1Present
2129 || (fMaybeWriteProtFault && !pPml4eSrc->n.u1Write)
2130 || (fMaybeNXEFault && pPml4eSrc->n.u1NoExecute)
2131 || (fUserLevelFault && !pPml4eSrc->n.u1User)
2132 )
2133 {
2134 uPageFaultLevel = 0;
2135 goto l_UpperLevelPageFault;
2136 }
2137 Assert(pPdpeSrc);
2138
2139# else /* PAE */
2140 PX86PDPE pPdpeSrc = pgmGstGetPaePDPEPtr(&pVCpu->pgm.s, GCPtrPage);
2141# endif /* PAE */
2142
2143 /*
2144 * Real page fault? (PDPE level)
2145 */
2146 if ( (uErr & X86_TRAP_PF_RSVD)
2147 || !pPdpeSrc->n.u1Present
2148# if PGM_GST_TYPE == PGM_TYPE_AMD64 /* NX, r/w, u/s bits in the PDPE are long mode only */
2149 || (fMaybeWriteProtFault && !pPdpeSrc->lm.u1Write)
2150 || (fMaybeNXEFault && pPdpeSrc->lm.u1NoExecute)
2151 || (fUserLevelFault && !pPdpeSrc->lm.u1User)
2152# endif
2153 )
2154 {
2155 uPageFaultLevel = 1;
2156 goto l_UpperLevelPageFault;
2157 }
2158# endif
2159
2160 /*
2161 * Real page fault? (PDE level)
2162 */
2163 if ( (uErr & X86_TRAP_PF_RSVD)
2164 || !pPdeSrc->n.u1Present
2165 || (fMaybeWriteProtFault && !pPdeSrc->n.u1Write)
2166# if PGM_WITH_NX(PGM_GST_TYPE, PGM_SHW_TYPE)
2167 || (fMaybeNXEFault && pPdeSrc->n.u1NoExecute)
2168# endif
2169 || (fUserLevelFault && !pPdeSrc->n.u1User) )
2170 {
2171 uPageFaultLevel = 2;
2172 goto l_UpperLevelPageFault;
2173 }
2174
2175 /*
2176 * First check the easy case where the page directory has been marked read-only to track
2177 * the dirty bit of an emulated BIG page
2178 */
2179 if ( pPdeSrc->b.u1Size
2180# if PGM_GST_TYPE == PGM_TYPE_32BIT
2181 && CPUMIsGuestPageSizeExtEnabled(pVCpu)
2182# endif
2183 )
2184 {
2185 /* Mark guest page directory as accessed */
2186# if PGM_GST_TYPE == PGM_TYPE_AMD64
2187 pPml4eSrc->n.u1Accessed = 1;
2188 pPdpeSrc->lm.u1Accessed = 1;
2189# endif
2190 pPdeSrc->b.u1Accessed = 1;
2191
2192 /*
2193 * Only write protection page faults are relevant here.
2194 */
2195 if (fWriteFault)
2196 {
2197 /* Mark guest page directory as dirty (BIG page only). */
2198 pPdeSrc->b.u1Dirty = 1;
2199 }
2200 return VINF_SUCCESS;
2201 }
2202 /* else: 4KB page table */
2203
2204 /*
2205 * Map the guest page table.
2206 */
2207 PGSTPT pPTSrc;
2208 rc = PGM_GCPHYS_2_PTR(pVM, pPdeSrc->u & GST_PDE_PG_MASK, &pPTSrc);
2209 if (RT_SUCCESS(rc))
2210 {
2211 /*
2212 * Real page fault?
2213 */
2214 PGSTPTE pPteSrc = &pPTSrc->a[(GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK];
2215 const GSTPTE PteSrc = *pPteSrc;
2216 if ( !PteSrc.n.u1Present
2217 || (fMaybeWriteProtFault && !PteSrc.n.u1Write)
2218# if PGM_WITH_NX(PGM_GST_TYPE, PGM_SHW_TYPE)
2219 || (fMaybeNXEFault && PteSrc.n.u1NoExecute)
2220# endif
2221 || (fUserLevelFault && !PteSrc.n.u1User)
2222 )
2223 {
2224 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyTrackRealPF));
2225 LogFlow(("CheckPageFault: real page fault at %RGv PteSrc.u=%08x (2)\n", GCPtrPage, PteSrc.u));
2226
2227 /* Check the present bit as the shadow tables can cause different error codes by being out of sync.
2228 * See the 2nd case above as well.
2229 */
2230 if (pPdeSrc->n.u1Present && pPteSrc->n.u1Present)
2231 TRPMSetErrorCode(pVCpu, uErr | X86_TRAP_PF_P); /* page-level protection violation */
2232
2233 return VINF_EM_RAW_GUEST_TRAP;
2234 }
2235 LogFlow(("CheckPageFault: page fault at %RGv PteSrc.u=%08x\n", GCPtrPage, PteSrc.u));
2236
2237 /*
2238 * Set the accessed bits in the page directory and the page table.
2239 */
2240# if PGM_GST_TYPE == PGM_TYPE_AMD64
2241 pPml4eSrc->n.u1Accessed = 1;
2242 pPdpeSrc->lm.u1Accessed = 1;
2243# endif
2244 pPdeSrc->n.u1Accessed = 1;
2245 pPteSrc->n.u1Accessed = 1;
2246
2247 /*
2248 * Only write protection page faults are relevant here.
2249 */
2250 if (fWriteFault)
2251 {
2252 /* Write access, so mark guest entry as dirty. */
2253# ifdef VBOX_WITH_STATISTICS
2254 if (!pPteSrc->n.u1Dirty)
2255 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtiedPage));
2256 else
2257 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,PageAlreadyDirty));
2258# endif
2259
2260 pPteSrc->n.u1Dirty = 1;
2261 }
2262 return VINF_SUCCESS;
2263 }
2264 AssertRC(rc);
2265 return rc;
2266
2267
2268l_UpperLevelPageFault:
2269 /*
2270 * Pagefault detected while checking the PML4E, PDPE or PDE.
2271 * Single exit handler to get rid of duplicate code paths.
2272 */
2273 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyTrackRealPF));
2274 Log(("CheckPageFault: real page fault at %RGv (%d)\n", GCPtrPage, uPageFaultLevel));
2275
2276 if ( 1
2277# if PGM_GST_TYPE == PGM_TYPE_AMD64
2278 && pPml4eSrc->n.u1Present
2279# endif
2280# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
2281 && pPdpeSrc->n.u1Present
2282# endif
2283 && pPdeSrc->n.u1Present)
2284 {
2285 /* Check the present bit as the shadow tables can cause different error codes by being out of sync. */
2286 if ( pPdeSrc->b.u1Size
2287# if PGM_GST_TYPE == PGM_TYPE_32BIT
2288 && CPUMIsGuestPageSizeExtEnabled(pVCpu)
2289# endif
2290 )
2291 {
2292 TRPMSetErrorCode(pVCpu, uErr | X86_TRAP_PF_P); /* page-level protection violation */
2293 }
2294 else
2295 {
2296 /*
2297 * Map the guest page table.
2298 */
2299 PGSTPT pPTSrc2;
2300 rc = PGM_GCPHYS_2_PTR(pVM, pPdeSrc->u & GST_PDE_PG_MASK, &pPTSrc2);
2301 if (RT_SUCCESS(rc))
2302 {
2303 PGSTPTE pPteSrc = &pPTSrc2->a[(GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK];
2304 if (pPteSrc->n.u1Present)
2305 TRPMSetErrorCode(pVCpu, uErr | X86_TRAP_PF_P); /* page-level protection violation */
2306 }
2307 AssertRC(rc);
2308 }
2309 }
2310 return VINF_EM_RAW_GUEST_TRAP;
2311}
2312
2313/**
2314 * Handle dirty bit tracking faults.
2315 *
2316 * @returns VBox status code.
2317 * @param pVCpu The VMCPU handle.
2318 * @param uErr Page fault error code.
2319 * @param pPdeSrc Guest page directory entry.
2320 * @param pPdeDst Shadow page directory entry.
2321 * @param GCPtrPage Guest context page address.
2322 */
2323PGM_BTH_DECL(int, CheckDirtyPageFault)(PVMCPU pVCpu, uint32_t uErr, PSHWPDE pPdeDst, PGSTPDE pPdeSrc, RTGCPTR GCPtrPage)
2324{
2325# if PGM_GST_TYPE == PGM_TYPE_32BIT
2326 const bool fBigPagesSupported = CPUMIsGuestPageSizeExtEnabled(pVCpu);
2327# else
2328 const bool fBigPagesSupported = true;
2329# endif
2330 PVM pVM = pVCpu->CTX_SUFF(pVM);
2331 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2332
2333 Assert(PGMIsLockOwner(pVM));
2334
2335 if (pPdeSrc->b.u1Size && fBigPagesSupported)
2336 {
2337 if ( pPdeDst->n.u1Present
2338 && (pPdeDst->u & PGM_PDFLAGS_TRACK_DIRTY))
2339 {
2340 SHWPDE PdeDst = *pPdeDst;
2341
2342 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPageTrap));
2343 Assert(pPdeSrc->b.u1Write);
2344
2345 /* Note: No need to invalidate this entry on other VCPUs as a stale TLB entry will not harm; write access will simply
2346 * fault again and take this path to only invalidate the entry.
2347 */
2348 PdeDst.n.u1Write = 1;
2349 PdeDst.n.u1Accessed = 1;
2350 PdeDst.au32[0] &= ~PGM_PDFLAGS_TRACK_DIRTY;
2351 ASMAtomicWriteSize(pPdeDst, PdeDst.u);
2352 PGM_INVL_BIG_PG(pVCpu, GCPtrPage);
2353 return VINF_PGM_HANDLED_DIRTY_BIT_FAULT; /* restarts the instruction. */
2354 }
2355# ifdef IN_RING0
2356 else
2357 /* Check for stale TLB entry; only applies to the SMP guest case. */
2358 if ( pVM->cCpus > 1
2359 && pPdeDst->n.u1Write
2360 && pPdeDst->n.u1Accessed)
2361 {
2362 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, pPdeDst->u & SHW_PDE_PG_MASK);
2363 if (pShwPage)
2364 {
2365 PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
2366 PSHWPTE pPteDst = &pPTDst->a[(GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK];
2367 if ( pPteDst->n.u1Present
2368 && pPteDst->n.u1Write)
2369 {
2370 /* Stale TLB entry. */
2371 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPageStale));
2372 PGM_INVL_PG(pVCpu, GCPtrPage);
2373 return VINF_PGM_HANDLED_DIRTY_BIT_FAULT; /* restarts the instruction. */
2374 }
2375 }
2376 }
2377# endif /* IN_RING0 */
2378 return VINF_PGM_NO_DIRTY_BIT_TRACKING;
2379 }
2380
2381 /*
2382 * Map the guest page table.
2383 */
2384 PGSTPT pPTSrc;
2385 int rc = PGM_GCPHYS_2_PTR(pVM, pPdeSrc->u & GST_PDE_PG_MASK, &pPTSrc);
2386 if (RT_SUCCESS(rc))
2387 {
2388 if (pPdeDst->n.u1Present)
2389 {
2390 PGSTPTE pPteSrc = &pPTSrc->a[(GCPtrPage >> GST_PT_SHIFT) & GST_PT_MASK];
2391 const GSTPTE PteSrc = *pPteSrc;
2392#ifndef IN_RING0
2393 /* Bail out here as pgmPoolGetPageByHCPhys will return NULL and we'll crash below.
2394 * Our individual shadow handlers will provide more information and force a fatal exit.
2395 */
2396 if (MMHyperIsInsideArea(pVM, (RTGCPTR)GCPtrPage))
2397 {
2398 LogRel(("CheckPageFault: write to hypervisor region %RGv\n", GCPtrPage));
2399 return VINF_PGM_NO_DIRTY_BIT_TRACKING;
2400 }
2401#endif
2402 /*
2403 * Map shadow page table.
2404 */
2405 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, pPdeDst->u & SHW_PDE_PG_MASK);
2406 if (pShwPage)
2407 {
2408 PSHWPT pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
2409 PSHWPTE pPteDst = &pPTDst->a[(GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK];
2410 if (pPteDst->n.u1Present) /** @todo Optimize accessed bit emulation? */
2411 {
2412 if (pPteDst->u & PGM_PTFLAGS_TRACK_DIRTY)
2413 {
2414 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, pPteSrc->u & GST_PTE_PG_MASK);
2415 SHWPTE PteDst = *pPteDst;
2416
2417 LogFlow(("DIRTY page trap addr=%RGv\n", GCPtrPage));
2418 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPageTrap));
2419
2420 Assert(pPteSrc->n.u1Write);
2421
2422 /* Note: No need to invalidate this entry on other VCPUs as a stale TLB entry will not harm; write access will simply
2423 * fault again and take this path to only invalidate the entry.
2424 */
2425 if (RT_LIKELY(pPage))
2426 {
2427 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
2428 {
2429 /* Assuming write handlers here as the PTE is present (otherwise we wouldn't be here). */
2430 PteDst.n.u1Write = 0;
2431 }
2432 else
2433 {
2434 if ( PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
2435 && PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM)
2436 {
2437 rc = pgmPhysPageMakeWritable(pVM, pPage, pPteSrc->u & GST_PTE_PG_MASK);
2438 AssertRC(rc);
2439 }
2440 if (PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED)
2441 {
2442 PteDst.n.u1Write = 1;
2443 }
2444 else
2445 {
2446 /* Still applies to shared pages. */
2447 Assert(!PGM_PAGE_IS_ZERO(pPage));
2448 PteDst.n.u1Write = 0;
2449 }
2450 }
2451 }
2452 else
2453 PteDst.n.u1Write = 1;
2454
2455 PteDst.n.u1Dirty = 1;
2456 PteDst.n.u1Accessed = 1;
2457 PteDst.au32[0] &= ~PGM_PTFLAGS_TRACK_DIRTY;
2458 ASMAtomicWriteSize(pPteDst, PteDst.u);
2459 PGM_INVL_PG(pVCpu, GCPtrPage);
2460 return VINF_PGM_HANDLED_DIRTY_BIT_FAULT; /* restarts the instruction. */
2461 }
2462# ifdef IN_RING0
2463 else
2464 /* Check for stale TLB entry; only applies to the SMP guest case. */
2465 if ( pVM->cCpus > 1
2466 && pPteDst->n.u1Write == 1
2467 && pPteDst->n.u1Accessed == 1)
2468 {
2469 /* Stale TLB entry. */
2470 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPageStale));
2471 PGM_INVL_PG(pVCpu, GCPtrPage);
2472 return VINF_PGM_HANDLED_DIRTY_BIT_FAULT; /* restarts the instruction. */
2473 }
2474# endif
2475 }
2476 }
2477 else
2478 AssertMsgFailed(("pgmPoolGetPageByHCPhys %RGp failed!\n", pPdeDst->u & SHW_PDE_PG_MASK));
2479 }
2480 return VINF_PGM_NO_DIRTY_BIT_TRACKING;
2481 }
2482 AssertRC(rc);
2483 return rc;
2484}
2485#endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
2486
2487
2488/**
2489 * Sync a shadow page table.
2490 *
2491 * The shadow page table is not present. This includes the case where
2492 * there is a conflict with a mapping.
2493 *
2494 * @returns VBox status code.
2495 * @param pVCpu The VMCPU handle.
2496 * @param iPD Page directory index.
2497 * @param pPDSrc Source page directory (i.e. Guest OS page directory).
2498 * Assume this is a temporary mapping.
2499 * @param GCPtrPage GC Pointer of the page that caused the fault
2500 */
2501PGM_BTH_DECL(int, SyncPT)(PVMCPU pVCpu, unsigned iPDSrc, PGSTPD pPDSrc, RTGCPTR GCPtrPage)
2502{
2503 PVM pVM = pVCpu->CTX_SUFF(pVM);
2504 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2505
2506 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT), a);
2507#if 0 /* rarely useful; leave for debugging. */
2508 STAM_COUNTER_INC(&pVCpu->pgm.s.StatSyncPtPD[iPDSrc]);
2509#endif
2510 LogFlow(("SyncPT: GCPtrPage=%RGv\n", GCPtrPage));
2511
2512 Assert(PGMIsLocked(pVM));
2513
2514#if ( PGM_GST_TYPE == PGM_TYPE_32BIT \
2515 || PGM_GST_TYPE == PGM_TYPE_PAE \
2516 || PGM_GST_TYPE == PGM_TYPE_AMD64) \
2517 && PGM_SHW_TYPE != PGM_TYPE_NESTED \
2518 && PGM_SHW_TYPE != PGM_TYPE_EPT
2519
2520 int rc = VINF_SUCCESS;
2521
2522 /*
2523 * Validate input a little bit.
2524 */
2525 AssertMsg(iPDSrc == ((GCPtrPage >> GST_PD_SHIFT) & GST_PD_MASK), ("iPDSrc=%x GCPtrPage=%RGv\n", iPDSrc, GCPtrPage));
2526# if PGM_SHW_TYPE == PGM_TYPE_32BIT
2527 const unsigned iPDDst = GCPtrPage >> SHW_PD_SHIFT;
2528 PSHWPDE pPdeDst = pgmShwGet32BitPDEPtr(&pVCpu->pgm.s, GCPtrPage);
2529
2530 /* Fetch the pgm pool shadow descriptor. */
2531 PPGMPOOLPAGE pShwPde = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
2532 Assert(pShwPde);
2533
2534# elif PGM_SHW_TYPE == PGM_TYPE_PAE
2535 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
2536 PPGMPOOLPAGE pShwPde = NULL;
2537 PX86PDPAE pPDDst;
2538 PSHWPDE pPdeDst;
2539
2540 /* Fetch the pgm pool shadow descriptor. */
2541 rc = pgmShwGetPaePoolPagePD(&pVCpu->pgm.s, GCPtrPage, &pShwPde);
2542 AssertRCSuccessReturn(rc, rc);
2543 Assert(pShwPde);
2544
2545 pPDDst = (PX86PDPAE)PGMPOOL_PAGE_2_PTR_BY_PGM(&pVM->pgm.s, pShwPde);
2546 pPdeDst = &pPDDst->a[iPDDst];
2547
2548# elif PGM_SHW_TYPE == PGM_TYPE_AMD64
2549 const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
2550 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
2551 PX86PDPAE pPDDst = NULL; /* initialized to shut up gcc */
2552 PX86PDPT pPdptDst = NULL; /* initialized to shut up gcc */
2553 rc = pgmShwGetLongModePDPtr(pVCpu, GCPtrPage, NULL, &pPdptDst, &pPDDst);
2554 AssertRCSuccessReturn(rc, rc);
2555 Assert(pPDDst);
2556 PSHWPDE pPdeDst = &pPDDst->a[iPDDst];
2557# endif
2558 SHWPDE PdeDst = *pPdeDst;
2559
2560# if PGM_GST_TYPE == PGM_TYPE_AMD64
2561 /* Fetch the pgm pool shadow descriptor. */
2562 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pPool, pPdptDst->a[iPdpt].u & X86_PDPE_PG_MASK);
2563 Assert(pShwPde);
2564# endif
2565
2566# ifndef PGM_WITHOUT_MAPPINGS
2567 /*
2568 * Check for conflicts.
2569 * GC: In case of a conflict we'll go to Ring-3 and do a full SyncCR3.
2570 * HC: Simply resolve the conflict.
2571 */
2572 if (PdeDst.u & PGM_PDFLAGS_MAPPING)
2573 {
2574 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
2575# ifndef IN_RING3
2576 Log(("SyncPT: Conflict at %RGv\n", GCPtrPage));
2577 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT), a);
2578 return VERR_ADDRESS_CONFLICT;
2579# else
2580 PPGMMAPPING pMapping = pgmGetMapping(pVM, (RTGCPTR)GCPtrPage);
2581 Assert(pMapping);
2582# if PGM_GST_TYPE == PGM_TYPE_32BIT
2583 rc = pgmR3SyncPTResolveConflict(pVM, pMapping, pPDSrc, GCPtrPage & (GST_PD_MASK << GST_PD_SHIFT));
2584# elif PGM_GST_TYPE == PGM_TYPE_PAE
2585 rc = pgmR3SyncPTResolveConflictPAE(pVM, pMapping, GCPtrPage & (GST_PD_MASK << GST_PD_SHIFT));
2586# else
2587 AssertFailed(); /* can't happen for amd64 */
2588# endif
2589 if (RT_FAILURE(rc))
2590 {
2591 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT), a);
2592 return rc;
2593 }
2594 PdeDst = *pPdeDst;
2595# endif
2596 }
2597# endif /* !PGM_WITHOUT_MAPPINGS */
2598 Assert(!PdeDst.n.u1Present); /* We're only supposed to call SyncPT on PDE!P and conflicts.*/
2599
2600# if defined(IN_RC)
2601 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
2602 PGMDynLockHCPage(pVM, (uint8_t *)pPdeDst);
2603# endif
2604
2605 /*
2606 * Sync page directory entry.
2607 */
2608 GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
2609 if (PdeSrc.n.u1Present)
2610 {
2611 /*
2612 * Allocate & map the page table.
2613 */
2614 PSHWPT pPTDst;
2615# if PGM_GST_TYPE == PGM_TYPE_32BIT
2616 const bool fPageTable = !PdeSrc.b.u1Size || !CPUMIsGuestPageSizeExtEnabled(pVCpu);
2617# else
2618 const bool fPageTable = !PdeSrc.b.u1Size;
2619# endif
2620 PPGMPOOLPAGE pShwPage;
2621 RTGCPHYS GCPhys;
2622 if (fPageTable)
2623 {
2624 GCPhys = PdeSrc.u & GST_PDE_PG_MASK;
2625# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2626 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
2627 GCPhys |= (iPDDst & 1) * (PAGE_SIZE / 2);
2628# endif
2629 rc = pgmPoolAlloc(pVM, GCPhys, BTH_PGMPOOLKIND_PT_FOR_PT, pShwPde->idx, iPDDst, &pShwPage);
2630 }
2631 else
2632 {
2633 PGMPOOLACCESS enmAccess;
2634# if PGM_WITH_NX(PGM_GST_TYPE, PGM_SHW_TYPE)
2635 const bool fNoExecute = PdeSrc.n.u1NoExecute && CPUMIsGuestNXEnabled(pVCpu);
2636# else
2637 const bool fNoExecute = false;
2638# endif
2639
2640 GCPhys = GST_GET_PDE_BIG_PG_GCPHYS(PdeSrc);
2641# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2642 /* Select the right PDE as we're emulating a 4MB page directory with two 2 MB shadow PDEs.*/
2643 GCPhys |= GCPtrPage & (1 << X86_PD_PAE_SHIFT);
2644# endif
2645 /* Determine the right kind of large page to avoid incorrect cached entry reuse. */
2646 if (PdeSrc.n.u1User)
2647 {
2648 if (PdeSrc.n.u1Write)
2649 enmAccess = (fNoExecute) ? PGMPOOLACCESS_USER_RW_NX : PGMPOOLACCESS_USER_RW;
2650 else
2651 enmAccess = (fNoExecute) ? PGMPOOLACCESS_USER_R_NX : PGMPOOLACCESS_USER_R;
2652 }
2653 else
2654 {
2655 if (PdeSrc.n.u1Write)
2656 enmAccess = (fNoExecute) ? PGMPOOLACCESS_SUPERVISOR_RW_NX : PGMPOOLACCESS_SUPERVISOR_RW;
2657 else
2658 enmAccess = (fNoExecute) ? PGMPOOLACCESS_SUPERVISOR_R_NX : PGMPOOLACCESS_SUPERVISOR_R;
2659 }
2660 rc = pgmPoolAllocEx(pVM, GCPhys, BTH_PGMPOOLKIND_PT_FOR_BIG, enmAccess, pShwPde->idx, iPDDst, &pShwPage);
2661 }
2662 if (rc == VINF_SUCCESS)
2663 pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
2664 else if (rc == VINF_PGM_CACHED_PAGE)
2665 {
2666 /*
2667 * The PT was cached, just hook it up.
2668 */
2669 if (fPageTable)
2670 PdeDst.u = pShwPage->Core.Key
2671 | (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
2672 else
2673 {
2674 PdeDst.u = pShwPage->Core.Key
2675 | (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
2676 /* (see explanation and assumptions further down.) */
2677 if ( !PdeSrc.b.u1Dirty
2678 && PdeSrc.b.u1Write)
2679 {
2680 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPageBig));
2681 PdeDst.u |= PGM_PDFLAGS_TRACK_DIRTY;
2682 PdeDst.b.u1Write = 0;
2683 }
2684 }
2685 ASMAtomicWriteSize(pPdeDst, PdeDst.u);
2686# if defined(IN_RC)
2687 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
2688# endif
2689 return VINF_SUCCESS;
2690 }
2691 else if (rc == VERR_PGM_POOL_FLUSHED)
2692 {
2693 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2694# if defined(IN_RC)
2695 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
2696# endif
2697 return VINF_PGM_SYNC_CR3;
2698 }
2699 else
2700 AssertMsgFailedReturn(("rc=%Rrc\n", rc), VERR_INTERNAL_ERROR);
2701 PdeDst.u &= X86_PDE_AVL_MASK;
2702 PdeDst.u |= pShwPage->Core.Key;
2703
2704 /*
2705 * Page directory has been accessed (this is a fault situation, remember).
2706 */
2707 pPDSrc->a[iPDSrc].n.u1Accessed = 1;
2708 if (fPageTable)
2709 {
2710 /*
2711 * Page table - 4KB.
2712 *
2713 * Sync all or just a few entries depending on PGM_SYNC_N_PAGES.
2714 */
2715 Log2(("SyncPT: 4K %RGv PdeSrc:{P=%d RW=%d U=%d raw=%08llx}\n",
2716 GCPtrPage, PdeSrc.b.u1Present, PdeSrc.b.u1Write, PdeSrc.b.u1User, (uint64_t)PdeSrc.u));
2717 PGSTPT pPTSrc;
2718 rc = PGM_GCPHYS_2_PTR(pVM, PdeSrc.u & GST_PDE_PG_MASK, &pPTSrc);
2719 if (RT_SUCCESS(rc))
2720 {
2721 /*
2722 * Start by syncing the page directory entry so CSAM's TLB trick works.
2723 */
2724 PdeDst.u = (PdeDst.u & (SHW_PDE_PG_MASK | X86_PDE_AVL_MASK))
2725 | (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
2726 ASMAtomicWriteSize(pPdeDst, PdeDst.u);
2727# if defined(IN_RC)
2728 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
2729# endif
2730
2731 /*
2732 * Directory/page user or supervisor privilege: (same goes for read/write)
2733 *
2734 * Directory Page Combined
2735 * U/S U/S U/S
2736 * 0 0 0
2737 * 0 1 0
2738 * 1 0 0
2739 * 1 1 1
2740 *
2741 * Simple AND operation. Table listed for completeness.
2742 *
2743 */
2744 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT4K));
2745# ifdef PGM_SYNC_N_PAGES
2746 unsigned iPTBase = (GCPtrPage >> SHW_PT_SHIFT) & SHW_PT_MASK;
2747 unsigned iPTDst = iPTBase;
2748 const unsigned iPTDstEnd = RT_MIN(iPTDst + PGM_SYNC_NR_PAGES / 2, RT_ELEMENTS(pPTDst->a));
2749 if (iPTDst <= PGM_SYNC_NR_PAGES / 2)
2750 iPTDst = 0;
2751 else
2752 iPTDst -= PGM_SYNC_NR_PAGES / 2;
2753# else /* !PGM_SYNC_N_PAGES */
2754 unsigned iPTDst = 0;
2755 const unsigned iPTDstEnd = RT_ELEMENTS(pPTDst->a);
2756# endif /* !PGM_SYNC_N_PAGES */
2757# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
2758 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
2759 const unsigned offPTSrc = ((GCPtrPage >> SHW_PD_SHIFT) & 1) * 512;
2760# else
2761 const unsigned offPTSrc = 0;
2762# endif
2763 for (; iPTDst < iPTDstEnd; iPTDst++)
2764 {
2765 const unsigned iPTSrc = iPTDst + offPTSrc;
2766 const GSTPTE PteSrc = pPTSrc->a[iPTSrc];
2767
2768 if (PteSrc.n.u1Present) /* we've already cleared it above */
2769 {
2770# ifndef IN_RING0
2771 /*
2772 * Assuming kernel code will be marked as supervisor - and not as user level
2773 * and executed using a conforming code selector - And marked as readonly.
2774 * Also assume that if we're monitoring a page, it's of no interest to CSAM.
2775 */
2776 PPGMPAGE pPage;
2777 if ( ((PdeSrc.u & pPTSrc->a[iPTSrc].u) & (X86_PTE_RW | X86_PTE_US))
2778 || !CSAMDoesPageNeedScanning(pVM, (iPDSrc << GST_PD_SHIFT) | (iPTSrc << PAGE_SHIFT))
2779 || ( (pPage = pgmPhysGetPage(&pVM->pgm.s, PteSrc.u & GST_PTE_PG_MASK))
2780 && PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
2781 )
2782# endif
2783 PGM_BTH_NAME(SyncPageWorker)(pVCpu, &pPTDst->a[iPTDst], PdeSrc, PteSrc, pShwPage, iPTDst);
2784 Log2(("SyncPT: 4K+ %RGv PteSrc:{P=%d RW=%d U=%d raw=%08llx}%s dst.raw=%08llx iPTSrc=%x PdeSrc.u=%x physpte=%RGp\n",
2785 (RTGCPTR)(((RTGCPTR)iPDSrc << GST_PD_SHIFT) | ((RTGCPTR)iPTSrc << PAGE_SHIFT)),
2786 PteSrc.n.u1Present,
2787 PteSrc.n.u1Write & PdeSrc.n.u1Write,
2788 PteSrc.n.u1User & PdeSrc.n.u1User,
2789 (uint64_t)PteSrc.u,
2790 pPTDst->a[iPTDst].u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : "", pPTDst->a[iPTDst].u, iPTSrc, PdeSrc.au32[0],
2791 (RTGCPHYS)((PdeSrc.u & GST_PDE_PG_MASK) + iPTSrc*sizeof(PteSrc)) ));
2792 }
2793 } /* for PTEs */
2794 }
2795 }
2796 else
2797 {
2798 /*
2799 * Big page - 2/4MB.
2800 *
2801 * We'll walk the ram range list in parallel and optimize lookups.
2802 * We will only sync on shadow page table at a time.
2803 */
2804 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT4M));
2805
2806 /**
2807 * @todo It might be more efficient to sync only a part of the 4MB page (similar to what we do for 4kb PDs).
2808 */
2809
2810 /*
2811 * Start by syncing the page directory entry.
2812 */
2813 PdeDst.u = (PdeDst.u & (SHW_PDE_PG_MASK | (X86_PDE_AVL_MASK & ~PGM_PDFLAGS_TRACK_DIRTY)))
2814 | (PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PDE_AVL_MASK | X86_PDE_PCD | X86_PDE_PWT | X86_PDE_PS | X86_PDE4M_G | X86_PDE4M_D));
2815
2816 /*
2817 * If the page is not flagged as dirty and is writable, then make it read-only
2818 * at PD level, so we can set the dirty bit when the page is modified.
2819 *
2820 * ASSUMES that page access handlers are implemented on page table entry level.
2821 * Thus we will first catch the dirty access and set PDE.D and restart. If
2822 * there is an access handler, we'll trap again and let it work on the problem.
2823 */
2824 /** @todo move the above stuff to a section in the PGM documentation. */
2825 Assert(!(PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY));
2826 if ( !PdeSrc.b.u1Dirty
2827 && PdeSrc.b.u1Write)
2828 {
2829 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,DirtyPageBig));
2830 PdeDst.u |= PGM_PDFLAGS_TRACK_DIRTY;
2831 PdeDst.b.u1Write = 0;
2832 }
2833 ASMAtomicWriteSize(pPdeDst, PdeDst.u);
2834# if defined(IN_RC)
2835 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
2836# endif
2837
2838 /*
2839 * Fill the shadow page table.
2840 */
2841 /* Get address and flags from the source PDE. */
2842 SHWPTE PteDstBase;
2843 PteDstBase.u = PdeSrc.u & ~(GST_PDE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT);
2844
2845 /* Loop thru the entries in the shadow PT. */
2846 const RTGCPTR GCPtr = (GCPtrPage >> SHW_PD_SHIFT) << SHW_PD_SHIFT; NOREF(GCPtr);
2847 Log2(("SyncPT: BIG %RGv PdeSrc:{P=%d RW=%d U=%d raw=%08llx} Shw=%RGv GCPhys=%RGp %s\n",
2848 GCPtrPage, PdeSrc.b.u1Present, PdeSrc.b.u1Write, PdeSrc.b.u1User, (uint64_t)PdeSrc.u, GCPtr,
2849 GCPhys, PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
2850 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
2851 unsigned iPTDst = 0;
2852 while ( iPTDst < RT_ELEMENTS(pPTDst->a)
2853 && !VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
2854 {
2855 /* Advance ram range list. */
2856 while (pRam && GCPhys > pRam->GCPhysLast)
2857 pRam = pRam->CTX_SUFF(pNext);
2858 if (pRam && GCPhys >= pRam->GCPhys)
2859 {
2860 unsigned iHCPage = (GCPhys - pRam->GCPhys) >> PAGE_SHIFT;
2861 do
2862 {
2863 /* Make shadow PTE. */
2864 PPGMPAGE pPage = &pRam->aPages[iHCPage];
2865 SHWPTE PteDst;
2866
2867# ifndef VBOX_WITH_NEW_LAZY_PAGE_ALLOC
2868 /* Try to make the page writable if necessary. */
2869 if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
2870 && ( PGM_PAGE_IS_ZERO(pPage)
2871 || ( PteDstBase.n.u1Write
2872 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
2873# ifdef VBOX_WITH_REAL_WRITE_MONITORED_PAGES
2874 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_WRITE_MONITORED
2875# endif
2876# ifdef VBOX_WITH_PAGE_SHARING
2877 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_SHARED
2878# endif
2879 && !PGM_PAGE_IS_BALLOONED(pPage))
2880 )
2881 )
2882 {
2883 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
2884 AssertRCReturn(rc, rc);
2885 if (VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY))
2886 break;
2887 }
2888# endif
2889
2890 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
2891 {
2892 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
2893 {
2894 PteDst.u = PGM_PAGE_GET_HCPHYS(pPage) | PteDstBase.u;
2895 PteDst.n.u1Write = 0;
2896 }
2897 else
2898 PteDst.u = 0;
2899 }
2900 else
2901 if (PGM_PAGE_IS_BALLOONED(pPage))
2902 {
2903 /* Skip ballooned pages. */
2904 PteDst.u = 0;
2905 }
2906# ifndef IN_RING0
2907 /*
2908 * Assuming kernel code will be marked as supervisor and not as user level and executed
2909 * using a conforming code selector. Don't check for readonly, as that implies the whole
2910 * 4MB can be code or readonly data. Linux enables write access for its large pages.
2911 */
2912 else if ( !PdeSrc.n.u1User
2913 && CSAMDoesPageNeedScanning(pVM, GCPtr | (iPTDst << SHW_PT_SHIFT)))
2914 PteDst.u = 0;
2915# endif
2916 else
2917 PteDst.u = PGM_PAGE_GET_HCPHYS(pPage) | PteDstBase.u;
2918
2919 /* Only map writable pages writable. */
2920 if ( PteDst.n.u1Write
2921 && PteDst.n.u1Present
2922 && PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
2923 {
2924 /* Still applies to shared pages. */
2925 Assert(!PGM_PAGE_IS_ZERO(pPage));
2926 PteDst.n.u1Write = 0; /** @todo this isn't quite working yet... */
2927 Log3(("SyncPT: write-protecting %RGp pPage=%R[pgmpage] at %RGv\n", GCPhys, pPage, (RTGCPTR)(GCPtr | (iPTDst << SHW_PT_SHIFT))));
2928 }
2929
2930 if (PteDst.n.u1Present)
2931 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPage, PGM_PAGE_GET_TRACKING(pPage), pPage, iPTDst);
2932
2933 /* commit it */
2934 pPTDst->a[iPTDst] = PteDst;
2935 Log4(("SyncPT: BIG %RGv PteDst:{P=%d RW=%d U=%d raw=%08llx}%s\n",
2936 (RTGCPTR)(GCPtr | (iPTDst << SHW_PT_SHIFT)), PteDst.n.u1Present, PteDst.n.u1Write, PteDst.n.u1User, (uint64_t)PteDst.u,
2937 PteDst.u & PGM_PTFLAGS_TRACK_DIRTY ? " Track-Dirty" : ""));
2938
2939 /* advance */
2940 GCPhys += PAGE_SIZE;
2941 iHCPage++;
2942 iPTDst++;
2943 } while ( iPTDst < RT_ELEMENTS(pPTDst->a)
2944 && GCPhys <= pRam->GCPhysLast);
2945 }
2946 else if (pRam)
2947 {
2948 Log(("Invalid pages at %RGp\n", GCPhys));
2949 do
2950 {
2951 pPTDst->a[iPTDst].u = 0; /* MMIO or invalid page, we must handle them manually. */
2952 GCPhys += PAGE_SIZE;
2953 iPTDst++;
2954 } while ( iPTDst < RT_ELEMENTS(pPTDst->a)
2955 && GCPhys < pRam->GCPhys);
2956 }
2957 else
2958 {
2959 Log(("Invalid pages at %RGp (2)\n", GCPhys));
2960 for ( ; iPTDst < RT_ELEMENTS(pPTDst->a); iPTDst++)
2961 pPTDst->a[iPTDst].u = 0; /* MMIO or invalid page, we must handle them manually. */
2962 }
2963 } /* while more PTEs */
2964 } /* 4KB / 4MB */
2965 }
2966 else
2967 AssertRelease(!PdeDst.n.u1Present);
2968
2969 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT), a);
2970 if (RT_FAILURE(rc))
2971 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPTFailed));
2972 return rc;
2973
2974#elif (PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT) \
2975 && PGM_SHW_TYPE != PGM_TYPE_NESTED \
2976 && (PGM_SHW_TYPE != PGM_TYPE_EPT || PGM_GST_TYPE == PGM_TYPE_PROT) \
2977 && !defined(IN_RC)
2978
2979 /*
2980 * Validate input a little bit.
2981 */
2982 int rc = VINF_SUCCESS;
2983# if PGM_SHW_TYPE == PGM_TYPE_32BIT
2984 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
2985 PSHWPDE pPdeDst = pgmShwGet32BitPDEPtr(&pVCpu->pgm.s, GCPtrPage);
2986
2987 /* Fetch the pgm pool shadow descriptor. */
2988 PPGMPOOLPAGE pShwPde = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
2989 Assert(pShwPde);
2990
2991# elif PGM_SHW_TYPE == PGM_TYPE_PAE
2992 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
2993 PPGMPOOLPAGE pShwPde = NULL; /* initialized to shut up gcc */
2994 PX86PDPAE pPDDst;
2995 PSHWPDE pPdeDst;
2996
2997 /* Fetch the pgm pool shadow descriptor. */
2998 rc = pgmShwGetPaePoolPagePD(&pVCpu->pgm.s, GCPtrPage, &pShwPde);
2999 AssertRCSuccessReturn(rc, rc);
3000 Assert(pShwPde);
3001
3002 pPDDst = (PX86PDPAE)PGMPOOL_PAGE_2_PTR_BY_PGM(&pVM->pgm.s, pShwPde);
3003 pPdeDst = &pPDDst->a[iPDDst];
3004
3005# elif PGM_SHW_TYPE == PGM_TYPE_AMD64
3006 const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
3007 const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
3008 PX86PDPAE pPDDst = NULL; /* initialized to shut up gcc */
3009 PX86PDPT pPdptDst= NULL; /* initialized to shut up gcc */
3010 rc = pgmShwGetLongModePDPtr(pVCpu, GCPtrPage, NULL, &pPdptDst, &pPDDst);
3011 AssertRCSuccessReturn(rc, rc);
3012 Assert(pPDDst);
3013 PSHWPDE pPdeDst = &pPDDst->a[iPDDst];
3014
3015 /* Fetch the pgm pool shadow descriptor. */
3016 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pPool, pPdptDst->a[iPdpt].u & X86_PDPE_PG_MASK);
3017 Assert(pShwPde);
3018
3019# elif PGM_SHW_TYPE == PGM_TYPE_EPT
3020 const unsigned iPdpt = (GCPtrPage >> EPT_PDPT_SHIFT) & EPT_PDPT_MASK;
3021 const unsigned iPDDst = ((GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK);
3022 PEPTPD pPDDst;
3023 PEPTPDPT pPdptDst;
3024
3025 rc = pgmShwGetEPTPDPtr(pVCpu, GCPtrPage, &pPdptDst, &pPDDst);
3026 if (rc != VINF_SUCCESS)
3027 {
3028 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT), a);
3029 AssertRC(rc);
3030 return rc;
3031 }
3032 Assert(pPDDst);
3033 PSHWPDE pPdeDst = &pPDDst->a[iPDDst];
3034
3035 /* Fetch the pgm pool shadow descriptor. */
3036 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pPool, pPdptDst->a[iPdpt].u & EPT_PDPTE_PG_MASK);
3037 Assert(pShwPde);
3038# endif
3039 SHWPDE PdeDst = *pPdeDst;
3040
3041 Assert(!(PdeDst.u & PGM_PDFLAGS_MAPPING));
3042 Assert(!PdeDst.n.u1Present); /* We're only supposed to call SyncPT on PDE!P and conflicts.*/
3043
3044# if defined(PGM_WITH_LARGE_PAGES) && (PGM_SHW_TYPE != PGM_TYPE_32BIT && PGM_SHW_TYPE != PGM_TYPE_PAE)
3045# if (PGM_SHW_TYPE != PGM_TYPE_EPT) /* PGM_TYPE_EPT implies nested paging */
3046 if (HWACCMIsNestedPagingActive(pVM))
3047# endif
3048 {
3049 PPGMPAGE pPage;
3050
3051 /* Check if we allocated a big page before for this 2 MB range. */
3052 rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPtrPage & X86_PDE2M_PAE_PG_MASK, &pPage);
3053 if (RT_SUCCESS(rc))
3054 {
3055 RTHCPHYS HCPhys = NIL_RTHCPHYS;
3056
3057 if (PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE)
3058 {
3059 STAM_REL_COUNTER_INC(&pVM->pgm.s.StatLargePageReused);
3060 AssertRelease(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED);
3061 HCPhys = PGM_PAGE_GET_HCPHYS(pPage);
3062 }
3063 else
3064 if (PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE_DISABLED)
3065 {
3066 /* Recheck the entire 2 MB range to see if we can use it again as a large page. */
3067 rc = pgmPhysIsValidLargePage(pVM, GCPtrPage, pPage);
3068 if (RT_SUCCESS(rc))
3069 {
3070 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED);
3071 Assert(PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE);
3072 HCPhys = PGM_PAGE_GET_HCPHYS(pPage);
3073 }
3074 }
3075 else
3076 if (PGMIsUsingLargePages(pVM))
3077 {
3078 rc = pgmPhysAllocLargePage(pVM, GCPtrPage);
3079 if (RT_SUCCESS(rc))
3080 {
3081 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED);
3082 Assert(PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE);
3083 HCPhys = PGM_PAGE_GET_HCPHYS(pPage);
3084 }
3085 else
3086 LogFlow(("pgmPhysAllocLargePage failed with %Rrc\n", rc));
3087 }
3088
3089 if (HCPhys != NIL_RTHCPHYS)
3090 {
3091 PdeDst.u &= X86_PDE_AVL_MASK;
3092 PdeDst.u |= HCPhys;
3093 PdeDst.n.u1Present = 1;
3094 PdeDst.n.u1Write = 1;
3095 PdeDst.b.u1Size = 1;
3096# if PGM_SHW_TYPE == PGM_TYPE_EPT
3097 PdeDst.n.u1Execute = 1;
3098 PdeDst.b.u1IgnorePAT = 1;
3099 PdeDst.b.u3EMT = VMX_EPT_MEMTYPE_WB;
3100# else
3101 PdeDst.n.u1User = 1;
3102# endif
3103 ASMAtomicWriteSize(pPdeDst, PdeDst.u);
3104
3105 Log(("SyncPT: Use large page at %RGp PDE=%RX64\n", GCPtrPage, PdeDst.u));
3106 /* Add a reference to the first page only. */
3107 PGM_BTH_NAME(SyncPageWorkerTrackAddref)(pVCpu, pShwPde, PGM_PAGE_GET_TRACKING(pPage), pPage, iPDDst);
3108
3109 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT), a);
3110 return VINF_SUCCESS;
3111 }
3112 }
3113 }
3114# endif /* HC_ARCH_BITS == 64 */
3115
3116 GSTPDE PdeSrc;
3117 PdeSrc.u = 0; /* faked so we don't have to #ifdef everything */
3118 PdeSrc.n.u1Present = 1;
3119 PdeSrc.n.u1Write = 1;
3120 PdeSrc.n.u1Accessed = 1;
3121 PdeSrc.n.u1User = 1;
3122
3123 /*
3124 * Allocate & map the page table.
3125 */
3126 PSHWPT pPTDst;
3127 PPGMPOOLPAGE pShwPage;
3128 RTGCPHYS GCPhys;
3129
3130 /* Virtual address = physical address */
3131 GCPhys = GCPtrPage & X86_PAGE_4K_BASE_MASK;
3132 rc = pgmPoolAlloc(pVM, GCPhys & ~(RT_BIT_64(SHW_PD_SHIFT) - 1), BTH_PGMPOOLKIND_PT_FOR_PT, pShwPde->idx, iPDDst, &pShwPage);
3133
3134 if ( rc == VINF_SUCCESS
3135 || rc == VINF_PGM_CACHED_PAGE)
3136 pPTDst = (PSHWPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
3137 else
3138 AssertMsgFailedReturn(("rc=%Rrc\n", rc), VERR_INTERNAL_ERROR);
3139
3140 PdeDst.u &= X86_PDE_AVL_MASK;
3141 PdeDst.u |= pShwPage->Core.Key;
3142 PdeDst.n.u1Present = 1;
3143 PdeDst.n.u1Write = 1;
3144# if PGM_SHW_TYPE == PGM_TYPE_EPT
3145 PdeDst.n.u1Execute = 1;
3146# else
3147 PdeDst.n.u1User = 1;
3148 PdeDst.n.u1Accessed = 1;
3149# endif
3150 ASMAtomicWriteSize(pPdeDst, PdeDst.u);
3151
3152 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, GCPtrPage, PGM_SYNC_NR_PAGES, 0 /* page not present */);
3153 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT), a);
3154 return rc;
3155
3156#else
3157 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_SHW_TYPE, PGM_GST_TYPE));
3158 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncPT), a);
3159 return VERR_INTERNAL_ERROR;
3160#endif
3161}
3162
3163
3164
3165/**
3166 * Prefetch a page/set of pages.
3167 *
3168 * Typically used to sync commonly used pages before entering raw mode
3169 * after a CR3 reload.
3170 *
3171 * @returns VBox status code.
3172 * @param pVCpu The VMCPU handle.
3173 * @param GCPtrPage Page to invalidate.
3174 */
3175PGM_BTH_DECL(int, PrefetchPage)(PVMCPU pVCpu, RTGCPTR GCPtrPage)
3176{
3177#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_GST_TYPE == PGM_TYPE_AMD64) \
3178 && PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT
3179 /*
3180 * Check that all Guest levels thru the PDE are present, getting the
3181 * PD and PDE in the processes.
3182 */
3183 int rc = VINF_SUCCESS;
3184# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
3185# if PGM_GST_TYPE == PGM_TYPE_32BIT
3186 const unsigned iPDSrc = GCPtrPage >> GST_PD_SHIFT;
3187 PGSTPD pPDSrc = pgmGstGet32bitPDPtr(&pVCpu->pgm.s);
3188# elif PGM_GST_TYPE == PGM_TYPE_PAE
3189 unsigned iPDSrc;
3190 X86PDPE PdpeSrc;
3191 PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVCpu->pgm.s, GCPtrPage, &iPDSrc, &PdpeSrc);
3192 if (!pPDSrc)
3193 return VINF_SUCCESS; /* not present */
3194# elif PGM_GST_TYPE == PGM_TYPE_AMD64
3195 unsigned iPDSrc;
3196 PX86PML4E pPml4eSrc;
3197 X86PDPE PdpeSrc;
3198 PGSTPD pPDSrc = pgmGstGetLongModePDPtr(&pVCpu->pgm.s, GCPtrPage, &pPml4eSrc, &PdpeSrc, &iPDSrc);
3199 if (!pPDSrc)
3200 return VINF_SUCCESS; /* not present */
3201# endif
3202 const GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
3203# else
3204 PGSTPD pPDSrc = NULL;
3205 const unsigned iPDSrc = 0;
3206 GSTPDE PdeSrc;
3207
3208 PdeSrc.u = 0; /* faked so we don't have to #ifdef everything */
3209 PdeSrc.n.u1Present = 1;
3210 PdeSrc.n.u1Write = 1;
3211 PdeSrc.n.u1Accessed = 1;
3212 PdeSrc.n.u1User = 1;
3213# endif
3214
3215 if (PdeSrc.n.u1Present && PdeSrc.n.u1Accessed)
3216 {
3217 PVM pVM = pVCpu->CTX_SUFF(pVM);
3218 pgmLock(pVM);
3219
3220# if PGM_SHW_TYPE == PGM_TYPE_32BIT
3221 const X86PDE PdeDst = pgmShwGet32BitPDE(&pVCpu->pgm.s, GCPtrPage);
3222# elif PGM_SHW_TYPE == PGM_TYPE_PAE
3223 const unsigned iPDDst = ((GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK);
3224 PX86PDPAE pPDDst;
3225 X86PDEPAE PdeDst;
3226# if PGM_GST_TYPE != PGM_TYPE_PAE
3227 X86PDPE PdpeSrc;
3228
3229 /* Fake PDPT entry; access control handled on the page table level, so allow everything. */
3230 PdpeSrc.u = X86_PDPE_P; /* rw/us are reserved for PAE pdpte's; accessed bit causes invalid VT-x guest state errors */
3231# endif
3232 rc = pgmShwSyncPaePDPtr(pVCpu, GCPtrPage, &PdpeSrc, &pPDDst);
3233 if (rc != VINF_SUCCESS)
3234 {
3235 pgmUnlock(pVM);
3236 AssertRC(rc);
3237 return rc;
3238 }
3239 Assert(pPDDst);
3240 PdeDst = pPDDst->a[iPDDst];
3241
3242# elif PGM_SHW_TYPE == PGM_TYPE_AMD64
3243 const unsigned iPDDst = ((GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK);
3244 PX86PDPAE pPDDst;
3245 X86PDEPAE PdeDst;
3246
3247# if PGM_GST_TYPE == PGM_TYPE_PROT
3248 /* AMD-V nested paging */
3249 X86PML4E Pml4eSrc;
3250 X86PDPE PdpeSrc;
3251 PX86PML4E pPml4eSrc = &Pml4eSrc;
3252
3253 /* Fake PML4 & PDPT entry; access control handled on the page table level, so allow everything. */
3254 Pml4eSrc.u = X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_A;
3255 PdpeSrc.u = X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A;
3256# endif
3257
3258 rc = pgmShwSyncLongModePDPtr(pVCpu, GCPtrPage, pPml4eSrc, &PdpeSrc, &pPDDst);
3259 if (rc != VINF_SUCCESS)
3260 {
3261 pgmUnlock(pVM);
3262 AssertRC(rc);
3263 return rc;
3264 }
3265 Assert(pPDDst);
3266 PdeDst = pPDDst->a[iPDDst];
3267# endif
3268 if (!(PdeDst.u & PGM_PDFLAGS_MAPPING))
3269 {
3270 if (!PdeDst.n.u1Present)
3271 {
3272 /** r=bird: This guy will set the A bit on the PDE, probably harmless. */
3273 rc = PGM_BTH_NAME(SyncPT)(pVCpu, iPDSrc, pPDSrc, GCPtrPage);
3274 }
3275 else
3276 {
3277 /** @note We used to sync PGM_SYNC_NR_PAGES pages, which triggered assertions in CSAM, because
3278 * R/W attributes of nearby pages were reset. Not sure how that could happen. Anyway, it
3279 * makes no sense to prefetch more than one page.
3280 */
3281 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, GCPtrPage, 1, 0);
3282 if (RT_SUCCESS(rc))
3283 rc = VINF_SUCCESS;
3284 }
3285 }
3286 pgmUnlock(pVM);
3287 }
3288 return rc;
3289
3290#elif PGM_SHW_TYPE == PGM_TYPE_NESTED || PGM_SHW_TYPE == PGM_TYPE_EPT
3291 return VINF_SUCCESS; /* ignore */
3292#endif
3293}
3294
3295
3296
3297
3298/**
3299 * Syncs a page during a PGMVerifyAccess() call.
3300 *
3301 * @returns VBox status code (informational included).
3302 * @param pVCpu The VMCPU handle.
3303 * @param GCPtrPage The address of the page to sync.
3304 * @param fPage The effective guest page flags.
3305 * @param uErr The trap error code.
3306 */
3307PGM_BTH_DECL(int, VerifyAccessSyncPage)(PVMCPU pVCpu, RTGCPTR GCPtrPage, unsigned fPage, unsigned uErr)
3308{
3309 PVM pVM = pVCpu->CTX_SUFF(pVM);
3310
3311 LogFlow(("VerifyAccessSyncPage: GCPtrPage=%RGv fPage=%#x uErr=%#x\n", GCPtrPage, fPage, uErr));
3312
3313 Assert(!HWACCMIsNestedPagingActive(pVM));
3314#if (PGM_GST_TYPE == PGM_TYPE_32BIT || PGM_GST_TYPE == PGM_TYPE_REAL || PGM_GST_TYPE == PGM_TYPE_PROT || PGM_GST_TYPE == PGM_TYPE_PAE || PGM_TYPE_AMD64) \
3315 && PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT
3316
3317# ifndef IN_RING0
3318 if (!(fPage & X86_PTE_US))
3319 {
3320 /*
3321 * Mark this page as safe.
3322 */
3323 /** @todo not correct for pages that contain both code and data!! */
3324 Log(("CSAMMarkPage %RGv; scanned=%d\n", GCPtrPage, true));
3325 CSAMMarkPage(pVM, GCPtrPage, true);
3326 }
3327# endif
3328
3329 /*
3330 * Get guest PD and index.
3331 */
3332# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
3333# if PGM_GST_TYPE == PGM_TYPE_32BIT
3334 const unsigned iPDSrc = GCPtrPage >> GST_PD_SHIFT;
3335 PGSTPD pPDSrc = pgmGstGet32bitPDPtr(&pVCpu->pgm.s);
3336# elif PGM_GST_TYPE == PGM_TYPE_PAE
3337 unsigned iPDSrc = 0;
3338 X86PDPE PdpeSrc;
3339 PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVCpu->pgm.s, GCPtrPage, &iPDSrc, &PdpeSrc);
3340
3341 if (pPDSrc)
3342 {
3343 Log(("PGMVerifyAccess: access violation for %RGv due to non-present PDPTR\n", GCPtrPage));
3344 return VINF_EM_RAW_GUEST_TRAP;
3345 }
3346# elif PGM_GST_TYPE == PGM_TYPE_AMD64
3347 unsigned iPDSrc;
3348 PX86PML4E pPml4eSrc;
3349 X86PDPE PdpeSrc;
3350 PGSTPD pPDSrc = pgmGstGetLongModePDPtr(&pVCpu->pgm.s, GCPtrPage, &pPml4eSrc, &PdpeSrc, &iPDSrc);
3351 if (!pPDSrc)
3352 {
3353 Log(("PGMVerifyAccess: access violation for %RGv due to non-present PDPTR\n", GCPtrPage));
3354 return VINF_EM_RAW_GUEST_TRAP;
3355 }
3356# endif
3357# else
3358 PGSTPD pPDSrc = NULL;
3359 const unsigned iPDSrc = 0;
3360# endif
3361 int rc = VINF_SUCCESS;
3362
3363 pgmLock(pVM);
3364
3365 /*
3366 * First check if the shadow pd is present.
3367 */
3368# if PGM_SHW_TYPE == PGM_TYPE_32BIT
3369 PX86PDE pPdeDst = pgmShwGet32BitPDEPtr(&pVCpu->pgm.s, GCPtrPage);
3370# elif PGM_SHW_TYPE == PGM_TYPE_PAE
3371 PX86PDEPAE pPdeDst;
3372 const unsigned iPDDst = ((GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK);
3373 PX86PDPAE pPDDst;
3374# if PGM_GST_TYPE != PGM_TYPE_PAE
3375 X86PDPE PdpeSrc;
3376
3377 /* Fake PDPT entry; access control handled on the page table level, so allow everything. */
3378 PdpeSrc.u = X86_PDPE_P; /* rw/us are reserved for PAE pdpte's; accessed bit causes invalid VT-x guest state errors */
3379# endif
3380 rc = pgmShwSyncPaePDPtr(pVCpu, GCPtrPage, &PdpeSrc, &pPDDst);
3381 if (rc != VINF_SUCCESS)
3382 {
3383 pgmUnlock(pVM);
3384 AssertRC(rc);
3385 return rc;
3386 }
3387 Assert(pPDDst);
3388 pPdeDst = &pPDDst->a[iPDDst];
3389
3390# elif PGM_SHW_TYPE == PGM_TYPE_AMD64
3391 const unsigned iPDDst = ((GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK);
3392 PX86PDPAE pPDDst;
3393 PX86PDEPAE pPdeDst;
3394
3395# if PGM_GST_TYPE == PGM_TYPE_PROT
3396 /* AMD-V nested paging */
3397 X86PML4E Pml4eSrc;
3398 X86PDPE PdpeSrc;
3399 PX86PML4E pPml4eSrc = &Pml4eSrc;
3400
3401 /* Fake PML4 & PDPT entry; access control handled on the page table level, so allow everything. */
3402 Pml4eSrc.u = X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_A;
3403 PdpeSrc.u = X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A;
3404# endif
3405
3406 rc = pgmShwSyncLongModePDPtr(pVCpu, GCPtrPage, pPml4eSrc, &PdpeSrc, &pPDDst);
3407 if (rc != VINF_SUCCESS)
3408 {
3409 pgmUnlock(pVM);
3410 AssertRC(rc);
3411 return rc;
3412 }
3413 Assert(pPDDst);
3414 pPdeDst = &pPDDst->a[iPDDst];
3415# endif
3416
3417# if defined(IN_RC)
3418 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
3419 PGMDynLockHCPage(pVM, (uint8_t *)pPdeDst);
3420# endif
3421
3422 if (!pPdeDst->n.u1Present)
3423 {
3424 rc = PGM_BTH_NAME(SyncPT)(pVCpu, iPDSrc, pPDSrc, GCPtrPage);
3425 if (rc != VINF_SUCCESS)
3426 {
3427# if defined(IN_RC)
3428 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
3429 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
3430# endif
3431 pgmUnlock(pVM);
3432 AssertRC(rc);
3433 return rc;
3434 }
3435 }
3436
3437# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
3438 /* Check for dirty bit fault */
3439 rc = PGM_BTH_NAME(CheckDirtyPageFault)(pVCpu, uErr, pPdeDst, &pPDSrc->a[iPDSrc], GCPtrPage);
3440 if (rc == VINF_PGM_HANDLED_DIRTY_BIT_FAULT)
3441 Log(("PGMVerifyAccess: success (dirty)\n"));
3442 else
3443 {
3444 GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
3445# else
3446 {
3447 GSTPDE PdeSrc;
3448 PdeSrc.u = 0; /* faked so we don't have to #ifdef everything */
3449 PdeSrc.n.u1Present = 1;
3450 PdeSrc.n.u1Write = 1;
3451 PdeSrc.n.u1Accessed = 1;
3452 PdeSrc.n.u1User = 1;
3453
3454# endif /* PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE) */
3455 Assert(rc != VINF_EM_RAW_GUEST_TRAP);
3456 if (uErr & X86_TRAP_PF_US)
3457 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,PageOutOfSyncUser));
3458 else /* supervisor */
3459 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,PageOutOfSyncSupervisor));
3460
3461 rc = PGM_BTH_NAME(SyncPage)(pVCpu, PdeSrc, GCPtrPage, 1, 0);
3462 if (RT_SUCCESS(rc))
3463 {
3464 /* Page was successfully synced */
3465 Log2(("PGMVerifyAccess: success (sync)\n"));
3466 rc = VINF_SUCCESS;
3467 }
3468 else
3469 {
3470 Log(("PGMVerifyAccess: access violation for %RGv rc=%d\n", GCPtrPage, rc));
3471 rc = VINF_EM_RAW_GUEST_TRAP;
3472 }
3473 }
3474# if defined(IN_RC)
3475 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
3476 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdeDst);
3477# endif
3478 pgmUnlock(pVM);
3479 return rc;
3480
3481#else /* PGM_GST_TYPE != PGM_TYPE_32BIT */
3482
3483 AssertReleaseMsgFailed(("Shw=%d Gst=%d is not implemented!\n", PGM_GST_TYPE, PGM_SHW_TYPE));
3484 return VERR_INTERNAL_ERROR;
3485#endif /* PGM_GST_TYPE != PGM_TYPE_32BIT */
3486}
3487
3488
3489/**
3490 * Syncs the paging hierarchy starting at CR3.
3491 *
3492 * @returns VBox status code, no specials.
3493 * @param pVCpu The VMCPU handle.
3494 * @param cr0 Guest context CR0 register
3495 * @param cr3 Guest context CR3 register
3496 * @param cr4 Guest context CR4 register
3497 * @param fGlobal Including global page directories or not
3498 */
3499PGM_BTH_DECL(int, SyncCR3)(PVMCPU pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal)
3500{
3501 PVM pVM = pVCpu->CTX_SUFF(pVM);
3502
3503 LogFlow(("SyncCR3 fGlobal=%d\n", !!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3)));
3504
3505#if PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT
3506
3507 pgmLock(pVM);
3508
3509# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
3510 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
3511 if (pPool->cDirtyPages)
3512 pgmPoolResetDirtyPages(pVM);
3513# endif
3514
3515 /*
3516 * Update page access handlers.
3517 * The virtual are always flushed, while the physical are only on demand.
3518 * WARNING: We are incorrectly not doing global flushing on Virtual Handler updates. We'll
3519 * have to look into that later because it will have a bad influence on the performance.
3520 * @note SvL: There's no need for that. Just invalidate the virtual range(s).
3521 * bird: Yes, but that won't work for aliases.
3522 */
3523 /** @todo this MUST go away. See #1557. */
3524 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncCR3Handlers), h);
3525 PGM_GST_NAME(HandlerVirtualUpdate)(pVM, cr4);
3526 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncCR3Handlers), h);
3527 pgmUnlock(pVM);
3528#endif /* !NESTED && !EPT */
3529
3530#if PGM_SHW_TYPE == PGM_TYPE_NESTED || PGM_SHW_TYPE == PGM_TYPE_EPT
3531 /*
3532 * Nested / EPT - almost no work.
3533 */
3534 Assert(!pgmMapAreMappingsEnabled(&pVM->pgm.s));
3535 return VINF_SUCCESS;
3536
3537#elif PGM_SHW_TYPE == PGM_TYPE_AMD64
3538 /*
3539 * AMD64 (Shw & Gst) - No need to check all paging levels; we zero
3540 * out the shadow parts when the guest modifies its tables.
3541 */
3542 Assert(!pgmMapAreMappingsEnabled(&pVM->pgm.s));
3543 return VINF_SUCCESS;
3544
3545#else /* PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT && PGM_SHW_TYPE != PGM_TYPE_AMD64 */
3546
3547# ifndef PGM_WITHOUT_MAPPINGS
3548 /*
3549 * Check for and resolve conflicts with our guest mappings if they
3550 * are enabled and not fixed.
3551 */
3552 if (pgmMapAreMappingsFloating(&pVM->pgm.s))
3553 {
3554 int rc = pgmMapResolveConflicts(pVM);
3555 Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3);
3556 if (rc == VINF_PGM_SYNC_CR3)
3557 {
3558 LogFlow(("SyncCR3: detected conflict -> VINF_PGM_SYNC_CR3\n"));
3559 return VINF_PGM_SYNC_CR3;
3560 }
3561 }
3562# else
3563 Assert(!pgmMapAreMappingsEnabled(&pVM->pgm.s));
3564# endif
3565 return VINF_SUCCESS;
3566#endif /* PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT && PGM_SHW_TYPE != PGM_TYPE_AMD64 */
3567}
3568
3569
3570
3571
3572#ifdef VBOX_STRICT
3573#ifdef IN_RC
3574# undef AssertMsgFailed
3575# define AssertMsgFailed Log
3576#endif
3577#ifdef IN_RING3
3578# include <VBox/dbgf.h>
3579
3580/**
3581 * Dumps a page table hierarchy use only physical addresses and cr4/lm flags.
3582 *
3583 * @returns VBox status code (VINF_SUCCESS).
3584 * @param cr3 The root of the hierarchy.
3585 * @param crr The cr4, only PAE and PSE is currently used.
3586 * @param fLongMode Set if long mode, false if not long mode.
3587 * @param cMaxDepth Number of levels to dump.
3588 * @param pHlp Pointer to the output functions.
3589 */
3590RT_C_DECLS_BEGIN
3591VMMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint32_t cr3, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp);
3592RT_C_DECLS_END
3593
3594#endif
3595
3596/**
3597 * Checks that the shadow page table is in sync with the guest one.
3598 *
3599 * @returns The number of errors.
3600 * @param pVM The virtual machine.
3601 * @param pVCpu The VMCPU handle.
3602 * @param cr3 Guest context CR3 register
3603 * @param cr4 Guest context CR4 register
3604 * @param GCPtr Where to start. Defaults to 0.
3605 * @param cb How much to check. Defaults to everything.
3606 */
3607PGM_BTH_DECL(unsigned, AssertCR3)(PVMCPU pVCpu, uint64_t cr3, uint64_t cr4, RTGCPTR GCPtr, RTGCPTR cb)
3608{
3609#if PGM_SHW_TYPE == PGM_TYPE_NESTED || PGM_SHW_TYPE == PGM_TYPE_EPT
3610 return 0;
3611#else
3612 unsigned cErrors = 0;
3613 PVM pVM = pVCpu->CTX_SUFF(pVM);
3614 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
3615
3616#if PGM_GST_TYPE == PGM_TYPE_PAE
3617 /** @todo currently broken; crashes below somewhere */
3618 AssertFailed();
3619#endif
3620
3621#if PGM_GST_TYPE == PGM_TYPE_32BIT \
3622 || PGM_GST_TYPE == PGM_TYPE_PAE \
3623 || PGM_GST_TYPE == PGM_TYPE_AMD64
3624
3625# if PGM_GST_TYPE == PGM_TYPE_32BIT
3626 bool fBigPagesSupported = CPUMIsGuestPageSizeExtEnabled(pVCpu);
3627# else
3628 bool fBigPagesSupported = true;
3629# endif
3630 PPGMCPU pPGM = &pVCpu->pgm.s;
3631 RTGCPHYS GCPhysGst; /* page address derived from the guest page tables. */
3632 RTHCPHYS HCPhysShw; /* page address derived from the shadow page tables. */
3633# ifndef IN_RING0
3634 RTHCPHYS HCPhys; /* general usage. */
3635# endif
3636 int rc;
3637
3638 /*
3639 * Check that the Guest CR3 and all its mappings are correct.
3640 */
3641 AssertMsgReturn(pPGM->GCPhysCR3 == (cr3 & GST_CR3_PAGE_MASK),
3642 ("Invalid GCPhysCR3=%RGp cr3=%RGp\n", pPGM->GCPhysCR3, (RTGCPHYS)cr3),
3643 false);
3644# if !defined(IN_RING0) && PGM_GST_TYPE != PGM_TYPE_AMD64
3645# if PGM_GST_TYPE == PGM_TYPE_32BIT
3646 rc = PGMShwGetPage(pVCpu, (RTRCUINTPTR)pPGM->pGst32BitPdRC, NULL, &HCPhysShw);
3647# else
3648 rc = PGMShwGetPage(pVCpu, (RTRCUINTPTR)pPGM->pGstPaePdptRC, NULL, &HCPhysShw);
3649# endif
3650 AssertRCReturn(rc, 1);
3651 HCPhys = NIL_RTHCPHYS;
3652 rc = pgmRamGCPhys2HCPhys(&pVM->pgm.s, cr3 & GST_CR3_PAGE_MASK, &HCPhys);
3653 AssertMsgReturn(HCPhys == HCPhysShw, ("HCPhys=%RHp HCPhyswShw=%RHp (cr3)\n", HCPhys, HCPhysShw), false);
3654# if PGM_GST_TYPE == PGM_TYPE_32BIT && defined(IN_RING3)
3655 pgmGstGet32bitPDPtr(pPGM);
3656 RTGCPHYS GCPhys;
3657 rc = PGMR3DbgR3Ptr2GCPhys(pVM, pPGM->pGst32BitPdR3, &GCPhys);
3658 AssertRCReturn(rc, 1);
3659 AssertMsgReturn((cr3 & GST_CR3_PAGE_MASK) == GCPhys, ("GCPhys=%RGp cr3=%RGp\n", GCPhys, (RTGCPHYS)cr3), false);
3660# endif
3661# endif /* !IN_RING0 */
3662
3663 /*
3664 * Get and check the Shadow CR3.
3665 */
3666# if PGM_SHW_TYPE == PGM_TYPE_32BIT
3667 unsigned cPDEs = X86_PG_ENTRIES;
3668 unsigned cIncrement = X86_PG_ENTRIES * PAGE_SIZE;
3669# elif PGM_SHW_TYPE == PGM_TYPE_PAE
3670# if PGM_GST_TYPE == PGM_TYPE_32BIT
3671 unsigned cPDEs = X86_PG_PAE_ENTRIES * 4; /* treat it as a 2048 entry table. */
3672# else
3673 unsigned cPDEs = X86_PG_PAE_ENTRIES;
3674# endif
3675 unsigned cIncrement = X86_PG_PAE_ENTRIES * PAGE_SIZE;
3676# elif PGM_SHW_TYPE == PGM_TYPE_AMD64
3677 unsigned cPDEs = X86_PG_PAE_ENTRIES;
3678 unsigned cIncrement = X86_PG_PAE_ENTRIES * PAGE_SIZE;
3679# endif
3680 if (cb != ~(RTGCPTR)0)
3681 cPDEs = RT_MIN(cb >> SHW_PD_SHIFT, 1);
3682
3683/** @todo call the other two PGMAssert*() functions. */
3684
3685# if PGM_GST_TYPE == PGM_TYPE_AMD64
3686 unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
3687
3688 for (; iPml4 < X86_PG_PAE_ENTRIES; iPml4++)
3689 {
3690 PPGMPOOLPAGE pShwPdpt = NULL;
3691 PX86PML4E pPml4eSrc;
3692 PX86PML4E pPml4eDst;
3693 RTGCPHYS GCPhysPdptSrc;
3694
3695 pPml4eSrc = pgmGstGetLongModePML4EPtr(&pVCpu->pgm.s, iPml4);
3696 pPml4eDst = pgmShwGetLongModePML4EPtr(&pVCpu->pgm.s, iPml4);
3697
3698 /* Fetch the pgm pool shadow descriptor if the shadow pml4e is present. */
3699 if (!pPml4eDst->n.u1Present)
3700 {
3701 GCPtr += _2M * UINT64_C(512) * UINT64_C(512);
3702 continue;
3703 }
3704
3705 pShwPdpt = pgmPoolGetPage(pPool, pPml4eDst->u & X86_PML4E_PG_MASK);
3706 GCPhysPdptSrc = pPml4eSrc->u & X86_PML4E_PG_MASK_FULL;
3707
3708 if (pPml4eSrc->n.u1Present != pPml4eDst->n.u1Present)
3709 {
3710 AssertMsgFailed(("Present bit doesn't match! pPml4eDst.u=%#RX64 pPml4eSrc.u=%RX64\n", pPml4eDst->u, pPml4eSrc->u));
3711 GCPtr += _2M * UINT64_C(512) * UINT64_C(512);
3712 cErrors++;
3713 continue;
3714 }
3715
3716 if (GCPhysPdptSrc != pShwPdpt->GCPhys)
3717 {
3718 AssertMsgFailed(("Physical address doesn't match! iPml4 %d pPml4eDst.u=%#RX64 pPml4eSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPml4, pPml4eDst->u, pPml4eSrc->u, pShwPdpt->GCPhys, GCPhysPdptSrc));
3719 GCPtr += _2M * UINT64_C(512) * UINT64_C(512);
3720 cErrors++;
3721 continue;
3722 }
3723
3724 if ( pPml4eDst->n.u1User != pPml4eSrc->n.u1User
3725 || pPml4eDst->n.u1Write != pPml4eSrc->n.u1Write
3726 || pPml4eDst->n.u1NoExecute != pPml4eSrc->n.u1NoExecute)
3727 {
3728 AssertMsgFailed(("User/Write/NoExec bits don't match! pPml4eDst.u=%#RX64 pPml4eSrc.u=%RX64\n", pPml4eDst->u, pPml4eSrc->u));
3729 GCPtr += _2M * UINT64_C(512) * UINT64_C(512);
3730 cErrors++;
3731 continue;
3732 }
3733# else /* PGM_GST_TYPE != PGM_TYPE_AMD64 */
3734 {
3735# endif /* PGM_GST_TYPE != PGM_TYPE_AMD64 */
3736
3737# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
3738 /*
3739 * Check the PDPTEs too.
3740 */
3741 unsigned iPdpt = (GCPtr >> SHW_PDPT_SHIFT) & SHW_PDPT_MASK;
3742
3743 for (;iPdpt <= SHW_PDPT_MASK; iPdpt++)
3744 {
3745 unsigned iPDSrc = 0; /* initialized to shut up gcc */
3746 PPGMPOOLPAGE pShwPde = NULL;
3747 PX86PDPE pPdpeDst;
3748 RTGCPHYS GCPhysPdeSrc;
3749# if PGM_GST_TYPE == PGM_TYPE_PAE
3750 X86PDPE PdpeSrc;
3751 PGSTPD pPDSrc = pgmGstGetPaePDPtr(&pVCpu->pgm.s, GCPtr, &iPDSrc, &PdpeSrc);
3752 PX86PDPT pPdptDst = pgmShwGetPaePDPTPtr(&pVCpu->pgm.s);
3753# else
3754 PX86PML4E pPml4eSrcIgn;
3755 X86PDPE PdpeSrc;
3756 PX86PDPT pPdptDst;
3757 PX86PDPAE pPDDst;
3758 PGSTPD pPDSrc = pgmGstGetLongModePDPtr(&pVCpu->pgm.s, GCPtr, &pPml4eSrcIgn, &PdpeSrc, &iPDSrc);
3759
3760 rc = pgmShwGetLongModePDPtr(pVCpu, GCPtr, NULL, &pPdptDst, &pPDDst);
3761 if (rc != VINF_SUCCESS)
3762 {
3763 AssertMsg(rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT, ("Unexpected rc=%Rrc\n", rc));
3764 GCPtr += 512 * _2M;
3765 continue; /* next PDPTE */
3766 }
3767 Assert(pPDDst);
3768# endif
3769 Assert(iPDSrc == 0);
3770
3771 pPdpeDst = &pPdptDst->a[iPdpt];
3772
3773 if (!pPdpeDst->n.u1Present)
3774 {
3775 GCPtr += 512 * _2M;
3776 continue; /* next PDPTE */
3777 }
3778
3779 pShwPde = pgmPoolGetPage(pPool, pPdpeDst->u & X86_PDPE_PG_MASK);
3780 GCPhysPdeSrc = PdpeSrc.u & X86_PDPE_PG_MASK;
3781
3782 if (pPdpeDst->n.u1Present != PdpeSrc.n.u1Present)
3783 {
3784 AssertMsgFailed(("Present bit doesn't match! pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64\n", pPdpeDst->u, PdpeSrc.u));
3785 GCPtr += 512 * _2M;
3786 cErrors++;
3787 continue;
3788 }
3789
3790 if (GCPhysPdeSrc != pShwPde->GCPhys)
3791 {
3792# if PGM_GST_TYPE == PGM_TYPE_AMD64
3793 AssertMsgFailed(("Physical address doesn't match! iPml4 %d iPdpt %d pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPml4, iPdpt, pPdpeDst->u, PdpeSrc.u, pShwPde->GCPhys, GCPhysPdeSrc));
3794# else
3795 AssertMsgFailed(("Physical address doesn't match! iPdpt %d pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64 Phys %RX64 vs %RX64\n", iPdpt, pPdpeDst->u, PdpeSrc.u, pShwPde->GCPhys, GCPhysPdeSrc));
3796# endif
3797 GCPtr += 512 * _2M;
3798 cErrors++;
3799 continue;
3800 }
3801
3802# if PGM_GST_TYPE == PGM_TYPE_AMD64
3803 if ( pPdpeDst->lm.u1User != PdpeSrc.lm.u1User
3804 || pPdpeDst->lm.u1Write != PdpeSrc.lm.u1Write
3805 || pPdpeDst->lm.u1NoExecute != PdpeSrc.lm.u1NoExecute)
3806 {
3807 AssertMsgFailed(("User/Write/NoExec bits don't match! pPdpeDst.u=%#RX64 pPdpeSrc.u=%RX64\n", pPdpeDst->u, PdpeSrc.u));
3808 GCPtr += 512 * _2M;
3809 cErrors++;
3810 continue;
3811 }
3812# endif
3813
3814# else /* PGM_GST_TYPE != PGM_TYPE_AMD64 && PGM_GST_TYPE != PGM_TYPE_PAE */
3815 {
3816# endif /* PGM_GST_TYPE != PGM_TYPE_AMD64 && PGM_GST_TYPE != PGM_TYPE_PAE */
3817# if PGM_GST_TYPE == PGM_TYPE_32BIT
3818 GSTPD const *pPDSrc = pgmGstGet32bitPDPtr(&pVCpu->pgm.s);
3819# if PGM_SHW_TYPE == PGM_TYPE_32BIT
3820 PCX86PD pPDDst = pgmShwGet32BitPDPtr(&pVCpu->pgm.s);
3821# endif
3822# endif /* PGM_GST_TYPE == PGM_TYPE_32BIT */
3823 /*
3824 * Iterate the shadow page directory.
3825 */
3826 GCPtr = (GCPtr >> SHW_PD_SHIFT) << SHW_PD_SHIFT;
3827 unsigned iPDDst = (GCPtr >> SHW_PD_SHIFT) & SHW_PD_MASK;
3828
3829 for (;
3830 iPDDst < cPDEs;
3831 iPDDst++, GCPtr += cIncrement)
3832 {
3833# if PGM_SHW_TYPE == PGM_TYPE_PAE
3834 const SHWPDE PdeDst = *pgmShwGetPaePDEPtr(pPGM, GCPtr);
3835# else
3836 const SHWPDE PdeDst = pPDDst->a[iPDDst];
3837# endif
3838 if (PdeDst.u & PGM_PDFLAGS_MAPPING)
3839 {
3840 Assert(pgmMapAreMappingsEnabled(&pVM->pgm.s));
3841 if ((PdeDst.u & X86_PDE_AVL_MASK) != PGM_PDFLAGS_MAPPING)
3842 {
3843 AssertMsgFailed(("Mapping shall only have PGM_PDFLAGS_MAPPING set! PdeDst.u=%#RX64\n", (uint64_t)PdeDst.u));
3844 cErrors++;
3845 continue;
3846 }
3847 }
3848 else if ( (PdeDst.u & X86_PDE_P)
3849 || ((PdeDst.u & (X86_PDE_P | PGM_PDFLAGS_TRACK_DIRTY)) == (X86_PDE_P | PGM_PDFLAGS_TRACK_DIRTY))
3850 )
3851 {
3852 HCPhysShw = PdeDst.u & SHW_PDE_PG_MASK;
3853 PPGMPOOLPAGE pPoolPage = pgmPoolGetPage(pPool, HCPhysShw);
3854 if (!pPoolPage)
3855 {
3856 AssertMsgFailed(("Invalid page table address %RHp at %RGv! PdeDst=%#RX64\n",
3857 HCPhysShw, GCPtr, (uint64_t)PdeDst.u));
3858 cErrors++;
3859 continue;
3860 }
3861 const SHWPT *pPTDst = (const SHWPT *)PGMPOOL_PAGE_2_PTR(pVM, pPoolPage);
3862
3863 if (PdeDst.u & (X86_PDE4M_PWT | X86_PDE4M_PCD))
3864 {
3865 AssertMsgFailed(("PDE flags PWT and/or PCD is set at %RGv! These flags are not virtualized! PdeDst=%#RX64\n",
3866 GCPtr, (uint64_t)PdeDst.u));
3867 cErrors++;
3868 }
3869
3870 if (PdeDst.u & (X86_PDE4M_G | X86_PDE4M_D))
3871 {
3872 AssertMsgFailed(("4K PDE reserved flags at %RGv! PdeDst=%#RX64\n",
3873 GCPtr, (uint64_t)PdeDst.u));
3874 cErrors++;
3875 }
3876
3877 const GSTPDE PdeSrc = pPDSrc->a[(iPDDst >> (GST_PD_SHIFT - SHW_PD_SHIFT)) & GST_PD_MASK];
3878 if (!PdeSrc.n.u1Present)
3879 {
3880 AssertMsgFailed(("Guest PDE at %RGv is not present! PdeDst=%#RX64 PdeSrc=%#RX64\n",
3881 GCPtr, (uint64_t)PdeDst.u, (uint64_t)PdeSrc.u));
3882 cErrors++;
3883 continue;
3884 }
3885
3886 if ( !PdeSrc.b.u1Size
3887 || !fBigPagesSupported)
3888 {
3889 GCPhysGst = PdeSrc.u & GST_PDE_PG_MASK;
3890# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
3891 GCPhysGst |= (iPDDst & 1) * (PAGE_SIZE / 2);
3892# endif
3893 }
3894 else
3895 {
3896# if PGM_GST_TYPE == PGM_TYPE_32BIT
3897 if (PdeSrc.u & X86_PDE4M_PG_HIGH_MASK)
3898 {
3899 AssertMsgFailed(("Guest PDE at %RGv is using PSE36 or similar! PdeSrc=%#RX64\n",
3900 GCPtr, (uint64_t)PdeSrc.u));
3901 cErrors++;
3902 continue;
3903 }
3904# endif
3905 GCPhysGst = GST_GET_PDE_BIG_PG_GCPHYS(PdeSrc);
3906# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
3907 GCPhysGst |= GCPtr & RT_BIT(X86_PAGE_2M_SHIFT);
3908# endif
3909 }
3910
3911 if ( pPoolPage->enmKind
3912 != (!PdeSrc.b.u1Size || !fBigPagesSupported ? BTH_PGMPOOLKIND_PT_FOR_PT : BTH_PGMPOOLKIND_PT_FOR_BIG))
3913 {
3914 AssertMsgFailed(("Invalid shadow page table kind %d at %RGv! PdeSrc=%#RX64\n",
3915 pPoolPage->enmKind, GCPtr, (uint64_t)PdeSrc.u));
3916 cErrors++;
3917 }
3918
3919 PPGMPAGE pPhysPage = pgmPhysGetPage(&pVM->pgm.s, GCPhysGst);
3920 if (!pPhysPage)
3921 {
3922 AssertMsgFailed(("Cannot find guest physical address %RGp in the PDE at %RGv! PdeSrc=%#RX64\n",
3923 GCPhysGst, GCPtr, (uint64_t)PdeSrc.u));
3924 cErrors++;
3925 continue;
3926 }
3927
3928 if (GCPhysGst != pPoolPage->GCPhys)
3929 {
3930 AssertMsgFailed(("GCPhysGst=%RGp != pPage->GCPhys=%RGp at %RGv\n",
3931 GCPhysGst, pPoolPage->GCPhys, GCPtr));
3932 cErrors++;
3933 continue;
3934 }
3935
3936 if ( !PdeSrc.b.u1Size
3937 || !fBigPagesSupported)
3938 {
3939 /*
3940 * Page Table.
3941 */
3942 const GSTPT *pPTSrc;
3943 rc = PGM_GCPHYS_2_PTR(pVM, GCPhysGst & ~(RTGCPHYS)(PAGE_SIZE - 1), &pPTSrc);
3944 if (RT_FAILURE(rc))
3945 {
3946 AssertMsgFailed(("Cannot map/convert guest physical address %RGp in the PDE at %RGv! PdeSrc=%#RX64\n",
3947 GCPhysGst, GCPtr, (uint64_t)PdeSrc.u));
3948 cErrors++;
3949 continue;
3950 }
3951 if ( (PdeSrc.u & (X86_PDE_P | X86_PDE_US | X86_PDE_RW/* | X86_PDE_A*/))
3952 != (PdeDst.u & (X86_PDE_P | X86_PDE_US | X86_PDE_RW/* | X86_PDE_A*/)))
3953 {
3954 /// @todo We get here a lot on out-of-sync CR3 entries. The access handler should zap them to avoid false alarms here!
3955 // (This problem will go away when/if we shadow multiple CR3s.)
3956 AssertMsgFailed(("4K PDE flags mismatch at %RGv! PdeSrc=%#RX64 PdeDst=%#RX64\n",
3957 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
3958 cErrors++;
3959 continue;
3960 }
3961 if (PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY)
3962 {
3963 AssertMsgFailed(("4K PDEs cannot have PGM_PDFLAGS_TRACK_DIRTY set! GCPtr=%RGv PdeDst=%#RX64\n",
3964 GCPtr, (uint64_t)PdeDst.u));
3965 cErrors++;
3966 continue;
3967 }
3968
3969 /* iterate the page table. */
3970# if PGM_SHW_TYPE == PGM_TYPE_PAE && PGM_GST_TYPE == PGM_TYPE_32BIT
3971 /* Select the right PDE as we're emulating a 4kb page table with 2 shadow page tables. */
3972 const unsigned offPTSrc = ((GCPtr >> SHW_PD_SHIFT) & 1) * 512;
3973# else
3974 const unsigned offPTSrc = 0;
3975# endif
3976 for (unsigned iPT = 0, off = 0;
3977 iPT < RT_ELEMENTS(pPTDst->a);
3978 iPT++, off += PAGE_SIZE)
3979 {
3980 const SHWPTE PteDst = pPTDst->a[iPT];
3981
3982 /* skip not-present entries. */
3983 if (!(PteDst.u & (X86_PTE_P | PGM_PTFLAGS_TRACK_DIRTY))) /** @todo deal with ALL handlers and CSAM !P pages! */
3984 continue;
3985 Assert(PteDst.n.u1Present);
3986
3987 const GSTPTE PteSrc = pPTSrc->a[iPT + offPTSrc];
3988 if (!PteSrc.n.u1Present)
3989 {
3990# ifdef IN_RING3
3991 PGMAssertHandlerAndFlagsInSync(pVM);
3992 PGMR3DumpHierarchyGC(pVM, cr3, cr4, (PdeSrc.u & GST_PDE_PG_MASK));
3993# endif
3994 AssertMsgFailed(("Out of sync (!P) PTE at %RGv! PteSrc=%#RX64 PteDst=%#RX64 pPTSrc=%RGv iPTSrc=%x PdeSrc=%x physpte=%RGp\n",
3995 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u, pPTSrc, iPT + offPTSrc, PdeSrc.au32[0],
3996 (PdeSrc.u & GST_PDE_PG_MASK) + (iPT + offPTSrc)*sizeof(PteSrc)));
3997 cErrors++;
3998 continue;
3999 }
4000
4001 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;
4002# if 1 /** @todo sync accessed bit properly... */
4003 fIgnoreFlags |= X86_PTE_A;
4004# endif
4005
4006 /* match the physical addresses */
4007 HCPhysShw = PteDst.u & SHW_PTE_PG_MASK;
4008 GCPhysGst = PteSrc.u & GST_PTE_PG_MASK;
4009
4010# ifdef IN_RING3
4011 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysGst, &HCPhys);
4012 if (RT_FAILURE(rc))
4013 {
4014 if (HCPhysShw != MMR3PageDummyHCPhys(pVM)) /** @todo this is wrong. */
4015 {
4016 AssertMsgFailed(("Cannot find guest physical address %RGp at %RGv! PteSrc=%#RX64 PteDst=%#RX64\n",
4017 GCPhysGst, GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4018 cErrors++;
4019 continue;
4020 }
4021 }
4022 else if (HCPhysShw != (HCPhys & SHW_PTE_PG_MASK))
4023 {
4024 AssertMsgFailed(("Out of sync (phys) at %RGv! HCPhysShw=%RHp HCPhys=%RHp GCPhysGst=%RGp PteSrc=%#RX64 PteDst=%#RX64\n",
4025 GCPtr + off, HCPhysShw, HCPhys, GCPhysGst, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4026 cErrors++;
4027 continue;
4028 }
4029# endif
4030
4031 pPhysPage = pgmPhysGetPage(&pVM->pgm.s, GCPhysGst);
4032 if (!pPhysPage)
4033 {
4034# ifdef IN_RING3 /** @todo make MMR3PageDummyHCPhys an 'All' function! */
4035 if (HCPhysShw != MMR3PageDummyHCPhys(pVM)) /** @todo this is wrong. */
4036 {
4037 AssertMsgFailed(("Cannot find guest physical address %RGp at %RGv! PteSrc=%#RX64 PteDst=%#RX64\n",
4038 GCPhysGst, GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4039 cErrors++;
4040 continue;
4041 }
4042# endif
4043 if (PteDst.n.u1Write)
4044 {
4045 AssertMsgFailed(("Invalid guest page at %RGv is writable! GCPhysGst=%RGp PteSrc=%#RX64 PteDst=%#RX64\n",
4046 GCPtr + off, GCPhysGst, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4047 cErrors++;
4048 }
4049 fIgnoreFlags |= X86_PTE_RW;
4050 }
4051 else if (HCPhysShw != PGM_PAGE_GET_HCPHYS(pPhysPage))
4052 {
4053 AssertMsgFailed(("Out of sync (phys) at %RGv! HCPhysShw=%RHp pPhysPage:%R[pgmpage] GCPhysGst=%RGp PteSrc=%#RX64 PteDst=%#RX64\n",
4054 GCPtr + off, HCPhysShw, pPhysPage, GCPhysGst, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4055 cErrors++;
4056 continue;
4057 }
4058
4059 /* flags */
4060 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPhysPage))
4061 {
4062 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPhysPage))
4063 {
4064 if (PteDst.n.u1Write)
4065 {
4066 AssertMsgFailed(("WRITE access flagged at %RGv but the page is writable! pPhysPage=%R[pgmpage] PteSrc=%#RX64 PteDst=%#RX64\n",
4067 GCPtr + off, pPhysPage, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4068 cErrors++;
4069 continue;
4070 }
4071 fIgnoreFlags |= X86_PTE_RW;
4072 }
4073 else
4074 {
4075 if (PteDst.n.u1Present)
4076 {
4077 AssertMsgFailed(("ALL access flagged at %RGv but the page is present! pPhysPage=%R[pgmpage] PteSrc=%#RX64 PteDst=%#RX64\n",
4078 GCPtr + off, pPhysPage, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4079 cErrors++;
4080 continue;
4081 }
4082 fIgnoreFlags |= X86_PTE_P;
4083 }
4084 }
4085 else
4086 {
4087 if (!PteSrc.n.u1Dirty && PteSrc.n.u1Write)
4088 {
4089 if (PteDst.n.u1Write)
4090 {
4091 AssertMsgFailed(("!DIRTY page at %RGv is writable! PteSrc=%#RX64 PteDst=%#RX64\n",
4092 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4093 cErrors++;
4094 continue;
4095 }
4096 if (!(PteDst.u & PGM_PTFLAGS_TRACK_DIRTY))
4097 {
4098 AssertMsgFailed(("!DIRTY page at %RGv is not marked TRACK_DIRTY! PteSrc=%#RX64 PteDst=%#RX64\n",
4099 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4100 cErrors++;
4101 continue;
4102 }
4103 if (PteDst.n.u1Dirty)
4104 {
4105 AssertMsgFailed(("!DIRTY page at %RGv is marked DIRTY! PteSrc=%#RX64 PteDst=%#RX64\n",
4106 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4107 cErrors++;
4108 }
4109# if 0 /** @todo sync access bit properly... */
4110 if (PteDst.n.u1Accessed != PteSrc.n.u1Accessed)
4111 {
4112 AssertMsgFailed(("!DIRTY page at %RGv is has mismatching accessed bit! PteSrc=%#RX64 PteDst=%#RX64\n",
4113 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4114 cErrors++;
4115 }
4116 fIgnoreFlags |= X86_PTE_RW;
4117# else
4118 fIgnoreFlags |= X86_PTE_RW | X86_PTE_A;
4119# endif
4120 }
4121 else if (PteDst.u & PGM_PTFLAGS_TRACK_DIRTY)
4122 {
4123 /* access bit emulation (not implemented). */
4124 if (PteSrc.n.u1Accessed || PteDst.n.u1Present)
4125 {
4126 AssertMsgFailed(("PGM_PTFLAGS_TRACK_DIRTY set at %RGv but no accessed bit emulation! PteSrc=%#RX64 PteDst=%#RX64\n",
4127 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4128 cErrors++;
4129 continue;
4130 }
4131 if (!PteDst.n.u1Accessed)
4132 {
4133 AssertMsgFailed(("!ACCESSED page at %RGv is has the accessed bit set! PteSrc=%#RX64 PteDst=%#RX64\n",
4134 GCPtr + off, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4135 cErrors++;
4136 }
4137 fIgnoreFlags |= X86_PTE_P;
4138 }
4139# ifdef DEBUG_sandervl
4140 fIgnoreFlags |= X86_PTE_D | X86_PTE_A;
4141# endif
4142 }
4143
4144 if ( (PteSrc.u & ~fIgnoreFlags) != (PteDst.u & ~fIgnoreFlags)
4145 && (PteSrc.u & ~(fIgnoreFlags | X86_PTE_RW)) != (PteDst.u & ~fIgnoreFlags)
4146 )
4147 {
4148 AssertMsgFailed(("Flags mismatch at %RGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PteSrc=%#RX64 PteDst=%#RX64\n",
4149 GCPtr + off, (uint64_t)PteSrc.u & ~fIgnoreFlags, (uint64_t)PteDst.u & ~fIgnoreFlags,
4150 fIgnoreFlags, (uint64_t)PteSrc.u, (uint64_t)PteDst.u));
4151 cErrors++;
4152 continue;
4153 }
4154 } /* foreach PTE */
4155 }
4156 else
4157 {
4158 /*
4159 * Big Page.
4160 */
4161 uint64_t fIgnoreFlags = X86_PDE_AVL_MASK | GST_PDE_PG_MASK | X86_PDE4M_G | X86_PDE4M_D | X86_PDE4M_PS | X86_PDE4M_PWT | X86_PDE4M_PCD;
4162 if (!PdeSrc.b.u1Dirty && PdeSrc.b.u1Write)
4163 {
4164 if (PdeDst.n.u1Write)
4165 {
4166 AssertMsgFailed(("!DIRTY page at %RGv is writable! PdeSrc=%#RX64 PdeDst=%#RX64\n",
4167 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
4168 cErrors++;
4169 continue;
4170 }
4171 if (!(PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY))
4172 {
4173 AssertMsgFailed(("!DIRTY page at %RGv is not marked TRACK_DIRTY! PteSrc=%#RX64 PteDst=%#RX64\n",
4174 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
4175 cErrors++;
4176 continue;
4177 }
4178# if 0 /** @todo sync access bit properly... */
4179 if (PdeDst.n.u1Accessed != PdeSrc.b.u1Accessed)
4180 {
4181 AssertMsgFailed(("!DIRTY page at %RGv is has mismatching accessed bit! PteSrc=%#RX64 PteDst=%#RX64\n",
4182 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
4183 cErrors++;
4184 }
4185 fIgnoreFlags |= X86_PTE_RW;
4186# else
4187 fIgnoreFlags |= X86_PTE_RW | X86_PTE_A;
4188# endif
4189 }
4190 else if (PdeDst.u & PGM_PDFLAGS_TRACK_DIRTY)
4191 {
4192 /* access bit emulation (not implemented). */
4193 if (PdeSrc.b.u1Accessed || PdeDst.n.u1Present)
4194 {
4195 AssertMsgFailed(("PGM_PDFLAGS_TRACK_DIRTY set at %RGv but no accessed bit emulation! PdeSrc=%#RX64 PdeDst=%#RX64\n",
4196 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
4197 cErrors++;
4198 continue;
4199 }
4200 if (!PdeDst.n.u1Accessed)
4201 {
4202 AssertMsgFailed(("!ACCESSED page at %RGv is has the accessed bit set! PdeSrc=%#RX64 PdeDst=%#RX64\n",
4203 GCPtr, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
4204 cErrors++;
4205 }
4206 fIgnoreFlags |= X86_PTE_P;
4207 }
4208
4209 if ((PdeSrc.u & ~fIgnoreFlags) != (PdeDst.u & ~fIgnoreFlags))
4210 {
4211 AssertMsgFailed(("Flags mismatch (B) at %RGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PdeSrc=%#RX64 PdeDst=%#RX64\n",
4212 GCPtr, (uint64_t)PdeSrc.u & ~fIgnoreFlags, (uint64_t)PdeDst.u & ~fIgnoreFlags,
4213 fIgnoreFlags, (uint64_t)PdeSrc.u, (uint64_t)PdeDst.u));
4214 cErrors++;
4215 }
4216
4217 /* iterate the page table. */
4218 for (unsigned iPT = 0, off = 0;
4219 iPT < RT_ELEMENTS(pPTDst->a);
4220 iPT++, off += PAGE_SIZE, GCPhysGst += PAGE_SIZE)
4221 {
4222 const SHWPTE PteDst = pPTDst->a[iPT];
4223
4224 if (PteDst.u & PGM_PTFLAGS_TRACK_DIRTY)
4225 {
4226 AssertMsgFailed(("The PTE at %RGv emulating a 2/4M page is marked TRACK_DIRTY! PdeSrc=%#RX64 PteDst=%#RX64\n",
4227 GCPtr + off, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4228 cErrors++;
4229 }
4230
4231 /* skip not-present entries. */
4232 if (!PteDst.n.u1Present) /** @todo deal with ALL handlers and CSAM !P pages! */
4233 continue;
4234
4235 fIgnoreFlags = X86_PTE_PAE_PG_MASK | X86_PTE_AVL_MASK | X86_PTE_PWT | X86_PTE_PCD | X86_PTE_PAT | X86_PTE_D | X86_PTE_A | X86_PTE_G | X86_PTE_PAE_NX;
4236
4237 /* match the physical addresses */
4238 HCPhysShw = PteDst.u & X86_PTE_PAE_PG_MASK;
4239
4240# ifdef IN_RING3
4241 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhysGst, &HCPhys);
4242 if (RT_FAILURE(rc))
4243 {
4244 if (HCPhysShw != MMR3PageDummyHCPhys(pVM)) /** @todo this is wrong. */
4245 {
4246 AssertMsgFailed(("Cannot find guest physical address %RGp at %RGv! PdeSrc=%#RX64 PteDst=%#RX64\n",
4247 GCPhysGst, GCPtr + off, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4248 cErrors++;
4249 }
4250 }
4251 else if (HCPhysShw != (HCPhys & X86_PTE_PAE_PG_MASK))
4252 {
4253 AssertMsgFailed(("Out of sync (phys) at %RGv! HCPhysShw=%RHp HCPhys=%RHp GCPhysGst=%RGp PdeSrc=%#RX64 PteDst=%#RX64\n",
4254 GCPtr + off, HCPhysShw, HCPhys, GCPhysGst, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4255 cErrors++;
4256 continue;
4257 }
4258# endif
4259 pPhysPage = pgmPhysGetPage(&pVM->pgm.s, GCPhysGst);
4260 if (!pPhysPage)
4261 {
4262# ifdef IN_RING3 /** @todo make MMR3PageDummyHCPhys an 'All' function! */
4263 if (HCPhysShw != MMR3PageDummyHCPhys(pVM)) /** @todo this is wrong. */
4264 {
4265 AssertMsgFailed(("Cannot find guest physical address %RGp at %RGv! PdeSrc=%#RX64 PteDst=%#RX64\n",
4266 GCPhysGst, GCPtr + off, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4267 cErrors++;
4268 continue;
4269 }
4270# endif
4271 if (PteDst.n.u1Write)
4272 {
4273 AssertMsgFailed(("Invalid guest page at %RGv is writable! GCPhysGst=%RGp PdeSrc=%#RX64 PteDst=%#RX64\n",
4274 GCPtr + off, GCPhysGst, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4275 cErrors++;
4276 }
4277 fIgnoreFlags |= X86_PTE_RW;
4278 }
4279 else if (HCPhysShw != PGM_PAGE_GET_HCPHYS(pPhysPage))
4280 {
4281 AssertMsgFailed(("Out of sync (phys) at %RGv! HCPhysShw=%RHp pPhysPage=%R[pgmpage] GCPhysGst=%RGp PdeSrc=%#RX64 PteDst=%#RX64\n",
4282 GCPtr + off, HCPhysShw, pPhysPage, GCPhysGst, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4283 cErrors++;
4284 continue;
4285 }
4286
4287 /* flags */
4288 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPhysPage))
4289 {
4290 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPhysPage))
4291 {
4292 if (PGM_PAGE_GET_HNDL_PHYS_STATE(pPhysPage) != PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
4293 {
4294 if (PteDst.n.u1Write)
4295 {
4296 AssertMsgFailed(("WRITE access flagged at %RGv but the page is writable! pPhysPage=%R[pgmpage] PdeSrc=%#RX64 PteDst=%#RX64\n",
4297 GCPtr + off, pPhysPage, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4298 cErrors++;
4299 continue;
4300 }
4301 fIgnoreFlags |= X86_PTE_RW;
4302 }
4303 }
4304 else
4305 {
4306 if (PteDst.n.u1Present)
4307 {
4308 AssertMsgFailed(("ALL access flagged at %RGv but the page is present! pPhysPage=%R[pgmpage] PdeSrc=%#RX64 PteDst=%#RX64\n",
4309 GCPtr + off, pPhysPage, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4310 cErrors++;
4311 continue;
4312 }
4313 fIgnoreFlags |= X86_PTE_P;
4314 }
4315 }
4316
4317 if ( (PdeSrc.u & ~fIgnoreFlags) != (PteDst.u & ~fIgnoreFlags)
4318 && (PdeSrc.u & ~(fIgnoreFlags | X86_PTE_RW)) != (PteDst.u & ~fIgnoreFlags) /* lazy phys handler dereg. */
4319 )
4320 {
4321 AssertMsgFailed(("Flags mismatch (BT) at %RGv! %#RX64 != %#RX64 fIgnoreFlags=%#RX64 PdeSrc=%#RX64 PteDst=%#RX64\n",
4322 GCPtr + off, (uint64_t)PdeSrc.u & ~fIgnoreFlags, (uint64_t)PteDst.u & ~fIgnoreFlags,
4323 fIgnoreFlags, (uint64_t)PdeSrc.u, (uint64_t)PteDst.u));
4324 cErrors++;
4325 continue;
4326 }
4327 } /* for each PTE */
4328 }
4329 }
4330 /* not present */
4331
4332 } /* for each PDE */
4333
4334 } /* for each PDPTE */
4335
4336 } /* for each PML4E */
4337
4338# ifdef DEBUG
4339 if (cErrors)
4340 LogFlow(("AssertCR3: cErrors=%d\n", cErrors));
4341# endif
4342
4343#endif /* GST == 32BIT, PAE or AMD64 */
4344 return cErrors;
4345
4346#endif /* PGM_SHW_TYPE != PGM_TYPE_NESTED && PGM_SHW_TYPE != PGM_TYPE_EPT */
4347}
4348#endif /* VBOX_STRICT */
4349
4350
4351/**
4352 * Sets up the CR3 for shadow paging
4353 *
4354 * @returns Strict VBox status code.
4355 * @retval VINF_SUCCESS.
4356 *
4357 * @param pVCpu The VMCPU handle.
4358 * @param GCPhysCR3 The physical address in the CR3 register.
4359 */
4360PGM_BTH_DECL(int, MapCR3)(PVMCPU pVCpu, RTGCPHYS GCPhysCR3)
4361{
4362 PVM pVM = pVCpu->CTX_SUFF(pVM);
4363
4364 /* Update guest paging info. */
4365#if PGM_GST_TYPE == PGM_TYPE_32BIT \
4366 || PGM_GST_TYPE == PGM_TYPE_PAE \
4367 || PGM_GST_TYPE == PGM_TYPE_AMD64
4368
4369 LogFlow(("MapCR3: %RGp\n", GCPhysCR3));
4370
4371 /*
4372 * Map the page CR3 points at.
4373 */
4374 RTHCPTR HCPtrGuestCR3;
4375 RTHCPHYS HCPhysGuestCR3;
4376 pgmLock(pVM);
4377 PPGMPAGE pPageCR3 = pgmPhysGetPage(&pVM->pgm.s, GCPhysCR3);
4378 AssertReturn(pPageCR3, VERR_INTERNAL_ERROR_2);
4379 HCPhysGuestCR3 = PGM_PAGE_GET_HCPHYS(pPageCR3);
4380 /** @todo this needs some reworking wrt. locking. */
4381# if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
4382 HCPtrGuestCR3 = NIL_RTHCPTR;
4383 int rc = VINF_SUCCESS;
4384# else
4385 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPageCR3, GCPhysCR3 & GST_CR3_PAGE_MASK, (void **)&HCPtrGuestCR3); /** @todo r=bird: This GCPhysCR3 masking isn't necessary. */
4386# endif
4387 pgmUnlock(pVM);
4388 if (RT_SUCCESS(rc))
4389 {
4390 rc = PGMMap(pVM, (RTGCPTR)pVM->pgm.s.GCPtrCR3Mapping, HCPhysGuestCR3, PAGE_SIZE, 0);
4391 if (RT_SUCCESS(rc))
4392 {
4393# ifdef IN_RC
4394 PGM_INVL_PG(pVCpu, pVM->pgm.s.GCPtrCR3Mapping);
4395# endif
4396# if PGM_GST_TYPE == PGM_TYPE_32BIT
4397 pVCpu->pgm.s.pGst32BitPdR3 = (R3PTRTYPE(PX86PD))HCPtrGuestCR3;
4398# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4399 pVCpu->pgm.s.pGst32BitPdR0 = (R0PTRTYPE(PX86PD))HCPtrGuestCR3;
4400# endif
4401 pVCpu->pgm.s.pGst32BitPdRC = (RCPTRTYPE(PX86PD))(RTRCUINTPTR)pVM->pgm.s.GCPtrCR3Mapping;
4402
4403# elif PGM_GST_TYPE == PGM_TYPE_PAE
4404 unsigned off = GCPhysCR3 & GST_CR3_PAGE_MASK & PAGE_OFFSET_MASK;
4405 pVCpu->pgm.s.pGstPaePdptR3 = (R3PTRTYPE(PX86PDPT))HCPtrGuestCR3;
4406# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4407 pVCpu->pgm.s.pGstPaePdptR0 = (R0PTRTYPE(PX86PDPT))HCPtrGuestCR3;
4408# endif
4409 pVCpu->pgm.s.pGstPaePdptRC = (RCPTRTYPE(PX86PDPT))((RTRCUINTPTR)pVM->pgm.s.GCPtrCR3Mapping + off);
4410 LogFlow(("Cached mapping %RRv\n", pVCpu->pgm.s.pGstPaePdptRC));
4411
4412 /*
4413 * Map the 4 PDs too.
4414 */
4415 PX86PDPT pGuestPDPT = pgmGstGetPaePDPTPtr(&pVCpu->pgm.s);
4416 RTGCPTR GCPtr = pVM->pgm.s.GCPtrCR3Mapping + PAGE_SIZE;
4417 for (unsigned i = 0; i < X86_PG_PAE_PDPE_ENTRIES; i++, GCPtr += PAGE_SIZE)
4418 {
4419 if (pGuestPDPT->a[i].n.u1Present)
4420 {
4421 RTHCPTR HCPtr;
4422 RTHCPHYS HCPhys;
4423 RTGCPHYS GCPhys = pGuestPDPT->a[i].u & X86_PDPE_PG_MASK;
4424 pgmLock(pVM);
4425 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
4426 AssertReturn(pPage, VERR_INTERNAL_ERROR_2);
4427 HCPhys = PGM_PAGE_GET_HCPHYS(pPage);
4428# if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
4429 HCPtr = NIL_RTHCPTR;
4430 int rc2 = VINF_SUCCESS;
4431# else
4432 int rc2 = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, (void **)&HCPtr);
4433# endif
4434 pgmUnlock(pVM);
4435 if (RT_SUCCESS(rc2))
4436 {
4437 rc = PGMMap(pVM, GCPtr, HCPhys, PAGE_SIZE, 0);
4438 AssertRCReturn(rc, rc);
4439
4440 pVCpu->pgm.s.apGstPaePDsR3[i] = (R3PTRTYPE(PX86PDPAE))HCPtr;
4441# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4442 pVCpu->pgm.s.apGstPaePDsR0[i] = (R0PTRTYPE(PX86PDPAE))HCPtr;
4443# endif
4444 pVCpu->pgm.s.apGstPaePDsRC[i] = (RCPTRTYPE(PX86PDPAE))(RTRCUINTPTR)GCPtr;
4445 pVCpu->pgm.s.aGCPhysGstPaePDs[i] = GCPhys;
4446# ifdef IN_RC
4447 PGM_INVL_PG(pVCpu, GCPtr);
4448# endif
4449 continue;
4450 }
4451 AssertMsgFailed(("pgmR3Gst32BitMapCR3: rc2=%d GCPhys=%RGp i=%d\n", rc2, GCPhys, i));
4452 }
4453
4454 pVCpu->pgm.s.apGstPaePDsR3[i] = 0;
4455# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4456 pVCpu->pgm.s.apGstPaePDsR0[i] = 0;
4457# endif
4458 pVCpu->pgm.s.apGstPaePDsRC[i] = 0;
4459 pVCpu->pgm.s.aGCPhysGstPaePDs[i] = NIL_RTGCPHYS;
4460# ifdef IN_RC
4461 PGM_INVL_PG(pVCpu, GCPtr); /** @todo this shouldn't be necessary? */
4462# endif
4463 }
4464
4465# elif PGM_GST_TYPE == PGM_TYPE_AMD64
4466 pVCpu->pgm.s.pGstAmd64Pml4R3 = (R3PTRTYPE(PX86PML4))HCPtrGuestCR3;
4467# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4468 pVCpu->pgm.s.pGstAmd64Pml4R0 = (R0PTRTYPE(PX86PML4))HCPtrGuestCR3;
4469# endif
4470# endif
4471 }
4472 else
4473 AssertMsgFailed(("rc=%Rrc GCPhysGuestPD=%RGp\n", rc, GCPhysCR3));
4474 }
4475 else
4476 AssertMsgFailed(("rc=%Rrc GCPhysGuestPD=%RGp\n", rc, GCPhysCR3));
4477
4478#else /* prot/real stub */
4479 int rc = VINF_SUCCESS;
4480#endif
4481
4482 /* Update shadow paging info for guest modes with paging (32, pae, 64). */
4483# if ( ( PGM_SHW_TYPE == PGM_TYPE_32BIT \
4484 || PGM_SHW_TYPE == PGM_TYPE_PAE \
4485 || PGM_SHW_TYPE == PGM_TYPE_AMD64) \
4486 && ( PGM_GST_TYPE != PGM_TYPE_REAL \
4487 && PGM_GST_TYPE != PGM_TYPE_PROT))
4488
4489 Assert(!HWACCMIsNestedPagingActive(pVM));
4490
4491 /*
4492 * Update the shadow root page as well since that's not fixed.
4493 */
4494 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4495 PPGMPOOLPAGE pOldShwPageCR3 = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
4496 uint32_t iOldShwUserTable = pVCpu->pgm.s.iShwUserTable;
4497 uint32_t iOldShwUser = pVCpu->pgm.s.iShwUser;
4498 PPGMPOOLPAGE pNewShwPageCR3;
4499
4500 pgmLock(pVM);
4501
4502# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
4503 if (pPool->cDirtyPages)
4504 pgmPoolResetDirtyPages(pVM);
4505# endif
4506
4507 Assert(!(GCPhysCR3 >> (PAGE_SHIFT + 32)));
4508 rc = pgmPoolAlloc(pVM, GCPhysCR3 & GST_CR3_PAGE_MASK, BTH_PGMPOOLKIND_ROOT, SHW_POOL_ROOT_IDX, GCPhysCR3 >> PAGE_SHIFT, &pNewShwPageCR3, true /* lock page */);
4509 AssertFatalRC(rc);
4510 rc = VINF_SUCCESS;
4511
4512# ifdef IN_RC
4513 /*
4514 * WARNING! We can't deal with jumps to ring 3 in the code below as the
4515 * state will be inconsistent! Flush important things now while
4516 * we still can and then make sure there are no ring-3 calls.
4517 */
4518 REMNotifyHandlerPhysicalFlushIfAlmostFull(pVM, pVCpu);
4519 VMMRZCallRing3Disable(pVCpu);
4520# endif
4521
4522 pVCpu->pgm.s.iShwUser = SHW_POOL_ROOT_IDX;
4523 pVCpu->pgm.s.iShwUserTable = GCPhysCR3 >> PAGE_SHIFT;
4524 pVCpu->pgm.s.CTX_SUFF(pShwPageCR3) = pNewShwPageCR3;
4525# ifdef IN_RING0
4526 pVCpu->pgm.s.pShwPageCR3R3 = MMHyperCCToR3(pVM, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
4527 pVCpu->pgm.s.pShwPageCR3RC = MMHyperCCToRC(pVM, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
4528# elif defined(IN_RC)
4529 pVCpu->pgm.s.pShwPageCR3R3 = MMHyperCCToR3(pVM, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
4530 pVCpu->pgm.s.pShwPageCR3R0 = MMHyperCCToR0(pVM, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
4531# else
4532 pVCpu->pgm.s.pShwPageCR3R0 = MMHyperCCToR0(pVM, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
4533 pVCpu->pgm.s.pShwPageCR3RC = MMHyperCCToRC(pVM, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
4534# endif
4535
4536# ifndef PGM_WITHOUT_MAPPINGS
4537 /*
4538 * Apply all hypervisor mappings to the new CR3.
4539 * Note that SyncCR3 will be executed in case CR3 is changed in a guest paging mode; this will
4540 * make sure we check for conflicts in the new CR3 root.
4541 */
4542# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
4543 Assert(VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL) || VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
4544# endif
4545 rc = pgmMapActivateCR3(pVM, pNewShwPageCR3);
4546 AssertRCReturn(rc, rc);
4547# endif
4548
4549 /* Set the current hypervisor CR3. */
4550 CPUMSetHyperCR3(pVCpu, PGMGetHyperCR3(pVCpu));
4551 SELMShadowCR3Changed(pVM, pVCpu);
4552
4553# ifdef IN_RC
4554 /* NOTE: The state is consistent again. */
4555 VMMRZCallRing3Enable(pVCpu);
4556# endif
4557
4558 /* Clean up the old CR3 root. */
4559 if ( pOldShwPageCR3
4560 && pOldShwPageCR3 != pNewShwPageCR3 /* @todo can happen due to incorrect syncing between REM & PGM; find the real cause */)
4561 {
4562 Assert(pOldShwPageCR3->enmKind != PGMPOOLKIND_FREE);
4563# ifndef PGM_WITHOUT_MAPPINGS
4564 /* Remove the hypervisor mappings from the shadow page table. */
4565 pgmMapDeactivateCR3(pVM, pOldShwPageCR3);
4566# endif
4567 /* Mark the page as unlocked; allow flushing again. */
4568 pgmPoolUnlockPage(pPool, pOldShwPageCR3);
4569
4570 pgmPoolFreeByPage(pPool, pOldShwPageCR3, iOldShwUser, iOldShwUserTable);
4571 }
4572 pgmUnlock(pVM);
4573# endif
4574
4575 return rc;
4576}
4577
4578/**
4579 * Unmaps the shadow CR3.
4580 *
4581 * @returns VBox status, no specials.
4582 * @param pVCpu The VMCPU handle.
4583 */
4584PGM_BTH_DECL(int, UnmapCR3)(PVMCPU pVCpu)
4585{
4586 LogFlow(("UnmapCR3\n"));
4587
4588 int rc = VINF_SUCCESS;
4589 PVM pVM = pVCpu->CTX_SUFF(pVM);
4590
4591 /*
4592 * Update guest paging info.
4593 */
4594#if PGM_GST_TYPE == PGM_TYPE_32BIT
4595 pVCpu->pgm.s.pGst32BitPdR3 = 0;
4596# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4597 pVCpu->pgm.s.pGst32BitPdR0 = 0;
4598# endif
4599 pVCpu->pgm.s.pGst32BitPdRC = 0;
4600
4601#elif PGM_GST_TYPE == PGM_TYPE_PAE
4602 pVCpu->pgm.s.pGstPaePdptR3 = 0;
4603# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4604 pVCpu->pgm.s.pGstPaePdptR0 = 0;
4605# endif
4606 pVCpu->pgm.s.pGstPaePdptRC = 0;
4607 for (unsigned i = 0; i < X86_PG_PAE_PDPE_ENTRIES; i++)
4608 {
4609 pVCpu->pgm.s.apGstPaePDsR3[i] = 0;
4610# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4611 pVCpu->pgm.s.apGstPaePDsR0[i] = 0;
4612# endif
4613 pVCpu->pgm.s.apGstPaePDsRC[i] = 0;
4614 pVCpu->pgm.s.aGCPhysGstPaePDs[i] = NIL_RTGCPHYS;
4615 }
4616
4617#elif PGM_GST_TYPE == PGM_TYPE_AMD64
4618 pVCpu->pgm.s.pGstAmd64Pml4R3 = 0;
4619# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
4620 pVCpu->pgm.s.pGstAmd64Pml4R0 = 0;
4621# endif
4622
4623#else /* prot/real mode stub */
4624 /* nothing to do */
4625#endif
4626
4627#if !defined(IN_RC) /* In RC we rely on MapCR3 to do the shadow part for us at a safe time */
4628 /*
4629 * Update shadow paging info.
4630 */
4631# if ( ( PGM_SHW_TYPE == PGM_TYPE_32BIT \
4632 || PGM_SHW_TYPE == PGM_TYPE_PAE \
4633 || PGM_SHW_TYPE == PGM_TYPE_AMD64))
4634
4635# if PGM_GST_TYPE != PGM_TYPE_REAL
4636 Assert(!HWACCMIsNestedPagingActive(pVM));
4637# endif
4638
4639 pgmLock(pVM);
4640
4641# ifndef PGM_WITHOUT_MAPPINGS
4642 if (pVCpu->pgm.s.CTX_SUFF(pShwPageCR3))
4643 /* Remove the hypervisor mappings from the shadow page table. */
4644 pgmMapDeactivateCR3(pVM, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
4645# endif
4646
4647 if (pVCpu->pgm.s.CTX_SUFF(pShwPageCR3))
4648 {
4649 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
4650
4651 Assert(pVCpu->pgm.s.iShwUser != PGMPOOL_IDX_NESTED_ROOT);
4652
4653# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
4654 if (pPool->cDirtyPages)
4655 pgmPoolResetDirtyPages(pVM);
4656# endif
4657
4658 /* Mark the page as unlocked; allow flushing again. */
4659 pgmPoolUnlockPage(pPool, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
4660
4661 pgmPoolFreeByPage(pPool, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3), pVCpu->pgm.s.iShwUser, pVCpu->pgm.s.iShwUserTable);
4662 pVCpu->pgm.s.pShwPageCR3R3 = 0;
4663 pVCpu->pgm.s.pShwPageCR3R0 = 0;
4664 pVCpu->pgm.s.pShwPageCR3RC = 0;
4665 pVCpu->pgm.s.iShwUser = 0;
4666 pVCpu->pgm.s.iShwUserTable = 0;
4667 }
4668 pgmUnlock(pVM);
4669# endif
4670#endif /* !IN_RC*/
4671
4672 return rc;
4673}
Note: See TracBrowser for help on using the repository browser.

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