VirtualBox

source: vbox/trunk/src/VBox/VMM/include/PGMInline.h@ 92489

Last change on this file since 92489 was 92383, checked in by vboxsync, 3 years ago

VMM/PGM: Tweaking pgmR0PhysAllocateLargePage a bit to hope to speed it up a little bit. bugref:10093

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 35.9 KB
Line 
1/* $Id: PGMInline.h 92383 2021-11-11 22:44:05Z vboxsync $ */
2/** @file
3 * PGM - Inlined functions.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef VMM_INCLUDED_SRC_include_PGMInline_h
19#define VMM_INCLUDED_SRC_include_PGMInline_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24#include <VBox/cdefs.h>
25#include <VBox/types.h>
26#include <VBox/err.h>
27#include <VBox/vmm/stam.h>
28#include <VBox/param.h>
29#include <VBox/vmm/vmm.h>
30#include <VBox/vmm/mm.h>
31#include <VBox/vmm/pdmcritsect.h>
32#include <VBox/vmm/pdmapi.h>
33#include <VBox/dis.h>
34#include <VBox/vmm/dbgf.h>
35#include <VBox/log.h>
36#include <VBox/vmm/gmm.h>
37#include <VBox/vmm/hm.h>
38#include <VBox/vmm/nem.h>
39#include <iprt/asm.h>
40#include <iprt/assert.h>
41#include <iprt/avl.h>
42#include <iprt/critsect.h>
43#include <iprt/sha.h>
44
45
46
47/** @addtogroup grp_pgm_int Internals
48 * @internal
49 * @{
50 */
51
52/**
53 * Gets the PGMRAMRANGE structure for a guest page.
54 *
55 * @returns Pointer to the RAM range on success.
56 * @returns NULL on a VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS condition.
57 *
58 * @param pVM The cross context VM structure.
59 * @param GCPhys The GC physical address.
60 */
61DECLINLINE(PPGMRAMRANGE) pgmPhysGetRange(PVMCC pVM, RTGCPHYS GCPhys)
62{
63 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
64 if (!pRam || GCPhys - pRam->GCPhys >= pRam->cb)
65 return pgmPhysGetRangeSlow(pVM, GCPhys);
66 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbHits));
67 return pRam;
68}
69
70
71/**
72 * Gets the PGMRAMRANGE structure for a guest page, if unassigned get the ram
73 * range above it.
74 *
75 * @returns Pointer to the RAM range on success.
76 * @returns NULL if the address is located after the last range.
77 *
78 * @param pVM The cross context VM structure.
79 * @param GCPhys The GC physical address.
80 */
81DECLINLINE(PPGMRAMRANGE) pgmPhysGetRangeAtOrAbove(PVMCC pVM, RTGCPHYS GCPhys)
82{
83 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
84 if ( !pRam
85 || (GCPhys - pRam->GCPhys) >= pRam->cb)
86 return pgmPhysGetRangeAtOrAboveSlow(pVM, GCPhys);
87 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbHits));
88 return pRam;
89}
90
91
92/**
93 * Gets the PGMPAGE structure for a guest page.
94 *
95 * @returns Pointer to the page on success.
96 * @returns NULL on a VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS condition.
97 *
98 * @param pVM The cross context VM structure.
99 * @param GCPhys The GC physical address.
100 */
101DECLINLINE(PPGMPAGE) pgmPhysGetPage(PVMCC pVM, RTGCPHYS GCPhys)
102{
103 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
104 RTGCPHYS off;
105 if ( pRam
106 && (off = GCPhys - pRam->GCPhys) < pRam->cb)
107 {
108 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbHits));
109 return &pRam->aPages[off >> PAGE_SHIFT];
110 }
111 return pgmPhysGetPageSlow(pVM, GCPhys);
112}
113
114
115/**
116 * Gets the PGMPAGE structure for a guest page.
117 *
118 * Old Phys code: Will make sure the page is present.
119 *
120 * @returns VBox status code.
121 * @retval VINF_SUCCESS and a valid *ppPage on success.
122 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if the address isn't valid.
123 *
124 * @param pVM The cross context VM structure.
125 * @param GCPhys The GC physical address.
126 * @param ppPage Where to store the page pointer on success.
127 */
128DECLINLINE(int) pgmPhysGetPageEx(PVMCC pVM, RTGCPHYS GCPhys, PPPGMPAGE ppPage)
129{
130 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
131 RTGCPHYS off;
132 if ( !pRam
133 || (off = GCPhys - pRam->GCPhys) >= pRam->cb)
134 return pgmPhysGetPageExSlow(pVM, GCPhys, ppPage);
135 *ppPage = &pRam->aPages[off >> PAGE_SHIFT];
136 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbHits));
137 return VINF_SUCCESS;
138}
139
140
141/**
142 * Gets the PGMPAGE structure for a guest page.
143 *
144 * Old Phys code: Will make sure the page is present.
145 *
146 * @returns VBox status code.
147 * @retval VINF_SUCCESS and a valid *ppPage on success.
148 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if the address isn't valid.
149 *
150 * @param pVM The cross context VM structure.
151 * @param GCPhys The GC physical address.
152 * @param ppPage Where to store the page pointer on success.
153 * @param ppRamHint Where to read and store the ram list hint.
154 * The caller initializes this to NULL before the call.
155 */
156DECLINLINE(int) pgmPhysGetPageWithHintEx(PVMCC pVM, RTGCPHYS GCPhys, PPPGMPAGE ppPage, PPGMRAMRANGE *ppRamHint)
157{
158 RTGCPHYS off;
159 PPGMRAMRANGE pRam = *ppRamHint;
160 if ( !pRam
161 || RT_UNLIKELY((off = GCPhys - pRam->GCPhys) >= pRam->cb))
162 {
163 pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
164 if ( !pRam
165 || (off = GCPhys - pRam->GCPhys) >= pRam->cb)
166 return pgmPhysGetPageAndRangeExSlow(pVM, GCPhys, ppPage, ppRamHint);
167
168 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbHits));
169 *ppRamHint = pRam;
170 }
171 *ppPage = &pRam->aPages[off >> PAGE_SHIFT];
172 return VINF_SUCCESS;
173}
174
175
176/**
177 * Gets the PGMPAGE structure for a guest page together with the PGMRAMRANGE.
178 *
179 * @returns Pointer to the page on success.
180 * @returns NULL on a VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS condition.
181 *
182 * @param pVM The cross context VM structure.
183 * @param GCPhys The GC physical address.
184 * @param ppPage Where to store the pointer to the PGMPAGE structure.
185 * @param ppRam Where to store the pointer to the PGMRAMRANGE structure.
186 */
187DECLINLINE(int) pgmPhysGetPageAndRangeEx(PVMCC pVM, RTGCPHYS GCPhys, PPPGMPAGE ppPage, PPGMRAMRANGE *ppRam)
188{
189 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
190 RTGCPHYS off;
191 if ( !pRam
192 || (off = GCPhys - pRam->GCPhys) >= pRam->cb)
193 return pgmPhysGetPageAndRangeExSlow(pVM, GCPhys, ppPage, ppRam);
194
195 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbHits));
196 *ppRam = pRam;
197 *ppPage = &pRam->aPages[off >> PAGE_SHIFT];
198 return VINF_SUCCESS;
199}
200
201
202/**
203 * Convert GC Phys to HC Phys.
204 *
205 * @returns VBox status code.
206 * @param pVM The cross context VM structure.
207 * @param GCPhys The GC physical address.
208 * @param pHCPhys Where to store the corresponding HC physical address.
209 *
210 * @deprecated Doesn't deal with zero, shared or write monitored pages.
211 * Avoid when writing new code!
212 */
213DECLINLINE(int) pgmRamGCPhys2HCPhys(PVMCC pVM, RTGCPHYS GCPhys, PRTHCPHYS pHCPhys)
214{
215 PPGMPAGE pPage;
216 int rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage);
217 if (RT_FAILURE(rc))
218 return rc;
219 *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage) | (GCPhys & PAGE_OFFSET_MASK);
220 return VINF_SUCCESS;
221}
222
223
224/**
225 * Queries the Physical TLB entry for a physical guest page,
226 * attempting to load the TLB entry if necessary.
227 *
228 * @returns VBox status code.
229 * @retval VINF_SUCCESS on success
230 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
231 *
232 * @param pVM The cross context VM structure.
233 * @param GCPhys The address of the guest page.
234 * @param ppTlbe Where to store the pointer to the TLB entry.
235 */
236DECLINLINE(int) pgmPhysPageQueryTlbe(PVMCC pVM, RTGCPHYS GCPhys, PPPGMPAGEMAPTLBE ppTlbe)
237{
238 int rc;
239 PPGMPAGEMAPTLBE pTlbe = &pVM->pgm.s.CTX_SUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
240 if (pTlbe->GCPhys == (GCPhys & X86_PTE_PAE_PG_MASK))
241 {
242 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PageMapTlbHits));
243 rc = VINF_SUCCESS;
244 }
245 else
246 rc = pgmPhysPageLoadIntoTlb(pVM, GCPhys);
247 *ppTlbe = pTlbe;
248 return rc;
249}
250
251
252/**
253 * Queries the Physical TLB entry for a physical guest page,
254 * attempting to load the TLB entry if necessary.
255 *
256 * @returns VBox status code.
257 * @retval VINF_SUCCESS on success
258 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
259 *
260 * @param pVM The cross context VM structure.
261 * @param pPage Pointer to the PGMPAGE structure corresponding to
262 * GCPhys.
263 * @param GCPhys The address of the guest page.
264 * @param ppTlbe Where to store the pointer to the TLB entry.
265 */
266DECLINLINE(int) pgmPhysPageQueryTlbeWithPage(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMPAGEMAPTLBE ppTlbe)
267{
268 int rc;
269 PPGMPAGEMAPTLBE pTlbe = &pVM->pgm.s.CTX_SUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
270 if (pTlbe->GCPhys == (GCPhys & X86_PTE_PAE_PG_MASK))
271 {
272 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PageMapTlbHits));
273 rc = VINF_SUCCESS;
274 AssertPtr(pTlbe->pv);
275#ifdef IN_RING3
276 Assert(!pTlbe->pMap || RT_VALID_PTR(pTlbe->pMap->pv));
277#endif
278 }
279 else
280 rc = pgmPhysPageLoadIntoTlbWithPage(pVM, pPage, GCPhys);
281 *ppTlbe = pTlbe;
282 return rc;
283}
284
285
286/**
287 * Calculates NEM page protection flags.
288 */
289DECL_FORCE_INLINE(uint32_t) pgmPhysPageCalcNemProtection(PPGMPAGE pPage, PGMPAGETYPE enmType)
290{
291 /*
292 * Deal with potentially writable pages first.
293 */
294 if (PGMPAGETYPE_IS_RWX(enmType))
295 {
296 if (!PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
297 {
298 if (PGM_PAGE_IS_ALLOCATED(pPage))
299 return NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE | NEM_PAGE_PROT_WRITE;
300 return NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE;
301 }
302 if (!PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
303 return NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE;
304 }
305 /*
306 * Potentially readable & executable pages.
307 */
308 else if ( PGMPAGETYPE_IS_ROX(enmType)
309 && !PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
310 return NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE;
311
312 /*
313 * The rest is needs special access handling.
314 */
315 return NEM_PAGE_PROT_NONE;
316}
317
318
319/**
320 * Enables write monitoring for an allocated page.
321 *
322 * The caller is responsible for updating the shadow page tables.
323 *
324 * @param pVM The cross context VM structure.
325 * @param pPage The page to write monitor.
326 * @param GCPhysPage The address of the page.
327 */
328DECLINLINE(void) pgmPhysPageWriteMonitor(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhysPage)
329{
330 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED);
331 PGM_LOCK_ASSERT_OWNER(pVM);
332
333 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_WRITE_MONITORED);
334 pVM->pgm.s.cMonitoredPages++;
335
336 /* Large pages must disabled. */
337 if (PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE)
338 {
339 PPGMPAGE pFirstPage = pgmPhysGetPage(pVM, GCPhysPage & X86_PDE2M_PAE_PG_MASK);
340 AssertFatal(pFirstPage);
341 if (PGM_PAGE_GET_PDE_TYPE(pFirstPage) == PGM_PAGE_PDE_TYPE_PDE)
342 {
343 PGM_PAGE_SET_PDE_TYPE(pVM, pFirstPage, PGM_PAGE_PDE_TYPE_PDE_DISABLED);
344 pVM->pgm.s.cLargePagesDisabled++;
345 }
346 else
347 Assert(PGM_PAGE_GET_PDE_TYPE(pFirstPage) == PGM_PAGE_PDE_TYPE_PDE_DISABLED);
348 }
349
350#ifdef VBOX_WITH_NATIVE_NEM
351 /* Tell NEM. */
352 if (VM_IS_NEM_ENABLED(pVM))
353 {
354 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
355 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
356 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhysPage);
357 NEMHCNotifyPhysPageProtChanged(pVM, GCPhysPage, PGM_PAGE_GET_HCPHYS(pPage),
358 pRam ? PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysPage) : NULL,
359 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
360 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
361 }
362#endif
363}
364
365
366/**
367 * Checks if the no-execute (NX) feature is active (EFER.NXE=1).
368 *
369 * Only used when the guest is in PAE or long mode. This is inlined so that we
370 * can perform consistency checks in debug builds.
371 *
372 * @returns true if it is, false if it isn't.
373 * @param pVCpu The cross context virtual CPU structure.
374 */
375DECL_FORCE_INLINE(bool) pgmGstIsNoExecuteActive(PVMCPUCC pVCpu)
376{
377 Assert(pVCpu->pgm.s.fNoExecuteEnabled == CPUMIsGuestNXEnabled(pVCpu));
378 Assert(CPUMIsGuestInPAEMode(pVCpu) || CPUMIsGuestInLongMode(pVCpu));
379 return pVCpu->pgm.s.fNoExecuteEnabled;
380}
381
382
383/**
384 * Checks if the page size extension (PSE) is currently enabled (CR4.PSE=1).
385 *
386 * Only used when the guest is in paged 32-bit mode. This is inlined so that
387 * we can perform consistency checks in debug builds.
388 *
389 * @returns true if it is, false if it isn't.
390 * @param pVCpu The cross context virtual CPU structure.
391 */
392DECL_FORCE_INLINE(bool) pgmGst32BitIsPageSizeExtActive(PVMCPUCC pVCpu)
393{
394 Assert(pVCpu->pgm.s.fGst32BitPageSizeExtension == CPUMIsGuestPageSizeExtEnabled(pVCpu));
395 Assert(!CPUMIsGuestInPAEMode(pVCpu));
396 Assert(!CPUMIsGuestInLongMode(pVCpu));
397 return pVCpu->pgm.s.fGst32BitPageSizeExtension;
398}
399
400
401/**
402 * Calculated the guest physical address of the large (4 MB) page in 32 bits paging mode.
403 * Takes PSE-36 into account.
404 *
405 * @returns guest physical address
406 * @param pVM The cross context VM structure.
407 * @param Pde Guest Pde
408 */
409DECLINLINE(RTGCPHYS) pgmGstGet4MBPhysPage(PVMCC pVM, X86PDE Pde)
410{
411 RTGCPHYS GCPhys = Pde.u & X86_PDE4M_PG_MASK;
412 GCPhys |= (RTGCPHYS)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT;
413
414 return GCPhys & pVM->pgm.s.GCPhys4MBPSEMask;
415}
416
417
418/**
419 * Gets the address the guest page directory (32-bit paging).
420 *
421 * @returns VBox status code.
422 * @param pVCpu The cross context virtual CPU structure.
423 * @param ppPd Where to return the mapping. This is always set.
424 */
425DECLINLINE(int) pgmGstGet32bitPDPtrEx(PVMCPUCC pVCpu, PX86PD *ppPd)
426{
427 *ppPd = pVCpu->pgm.s.CTX_SUFF(pGst32BitPd);
428 if (RT_UNLIKELY(!*ppPd))
429 return pgmGstLazyMap32BitPD(pVCpu, ppPd);
430 return VINF_SUCCESS;
431}
432
433
434/**
435 * Gets the address the guest page directory (32-bit paging).
436 *
437 * @returns Pointer to the page directory entry in question.
438 * @param pVCpu The cross context virtual CPU structure.
439 */
440DECLINLINE(PX86PD) pgmGstGet32bitPDPtr(PVMCPUCC pVCpu)
441{
442 PX86PD pGuestPD = pVCpu->pgm.s.CTX_SUFF(pGst32BitPd);
443 if (RT_UNLIKELY(!pGuestPD))
444 {
445 int rc = pgmGstLazyMap32BitPD(pVCpu, &pGuestPD);
446 if (RT_FAILURE(rc))
447 return NULL;
448 }
449 return pGuestPD;
450}
451
452
453/**
454 * Gets the guest page directory pointer table.
455 *
456 * @returns VBox status code.
457 * @param pVCpu The cross context virtual CPU structure.
458 * @param ppPdpt Where to return the mapping. This is always set.
459 */
460DECLINLINE(int) pgmGstGetPaePDPTPtrEx(PVMCPUCC pVCpu, PX86PDPT *ppPdpt)
461{
462 *ppPdpt = pVCpu->pgm.s.CTX_SUFF(pGstPaePdpt);
463 if (RT_UNLIKELY(!*ppPdpt))
464 return pgmGstLazyMapPaePDPT(pVCpu, ppPdpt);
465 return VINF_SUCCESS;
466}
467
468
469/**
470 * Gets the guest page directory pointer table.
471 *
472 * @returns Pointer to the page directory in question.
473 * @returns NULL if the page directory is not present or on an invalid page.
474 * @param pVCpu The cross context virtual CPU structure.
475 */
476DECLINLINE(PX86PDPT) pgmGstGetPaePDPTPtr(PVMCPUCC pVCpu)
477{
478 PX86PDPT pGuestPdpt;
479 int rc = pgmGstGetPaePDPTPtrEx(pVCpu, &pGuestPdpt);
480 AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc);
481 return pGuestPdpt;
482}
483
484
485/**
486 * Gets the guest page directory pointer table entry for the specified address.
487 *
488 * @returns Pointer to the page directory in question.
489 * @returns NULL if the page directory is not present or on an invalid page.
490 * @param pVCpu The cross context virtual CPU structure.
491 * @param GCPtr The address.
492 */
493DECLINLINE(PX86PDPE) pgmGstGetPaePDPEPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
494{
495 AssertGCPtr32(GCPtr);
496
497 PX86PDPT pGuestPDPT = pVCpu->pgm.s.CTX_SUFF(pGstPaePdpt);
498 if (RT_UNLIKELY(!pGuestPDPT))
499 {
500 int rc = pgmGstLazyMapPaePDPT(pVCpu, &pGuestPDPT);
501 if (RT_FAILURE(rc))
502 return NULL;
503 }
504 return &pGuestPDPT->a[(uint32_t)GCPtr >> X86_PDPT_SHIFT];
505}
506
507
508/**
509 * Gets the page directory entry for the specified address.
510 *
511 * @returns The page directory entry in question.
512 * @returns A non-present entry if the page directory is not present or on an invalid page.
513 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
514 * @param GCPtr The address.
515 */
516DECLINLINE(X86PDEPAE) pgmGstGetPaePDE(PVMCPUCC pVCpu, RTGCPTR GCPtr)
517{
518 AssertGCPtr32(GCPtr);
519 PX86PDPT pGuestPDPT = pgmGstGetPaePDPTPtr(pVCpu);
520 if (RT_LIKELY(pGuestPDPT))
521 {
522 const unsigned iPdpt = (uint32_t)GCPtr >> X86_PDPT_SHIFT;
523 if ((pGuestPDPT->a[iPdpt].u & (pVCpu->pgm.s.fGstPaeMbzPdpeMask | X86_PDPE_P)) == X86_PDPE_P)
524 {
525 const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
526 PX86PDPAE pGuestPD = pVCpu->pgm.s.CTX_SUFF(apGstPaePDs)[iPdpt];
527 if ( !pGuestPD
528 || (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt])
529 pgmGstLazyMapPaePD(pVCpu, iPdpt, &pGuestPD);
530 if (pGuestPD)
531 return pGuestPD->a[iPD];
532 }
533 }
534
535 X86PDEPAE ZeroPde = {0};
536 return ZeroPde;
537}
538
539
540/**
541 * Gets the page directory pointer table entry for the specified address
542 * and returns the index into the page directory
543 *
544 * @returns Pointer to the page directory in question.
545 * @returns NULL if the page directory is not present or on an invalid page.
546 * @param pVCpu The cross context virtual CPU structure.
547 * @param GCPtr The address.
548 * @param piPD Receives the index into the returned page directory
549 * @param pPdpe Receives the page directory pointer entry. Optional.
550 */
551DECLINLINE(PX86PDPAE) pgmGstGetPaePDPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr, unsigned *piPD, PX86PDPE pPdpe)
552{
553 AssertGCPtr32(GCPtr);
554
555 /* The PDPE. */
556 PX86PDPT pGuestPDPT = pgmGstGetPaePDPTPtr(pVCpu);
557 if (pGuestPDPT)
558 {
559 const unsigned iPdpt = (uint32_t)GCPtr >> X86_PDPT_SHIFT;
560 X86PGPAEUINT const uPdpe = pGuestPDPT->a[iPdpt].u;
561 if (pPdpe)
562 pPdpe->u = uPdpe;
563 if ((uPdpe & (pVCpu->pgm.s.fGstPaeMbzPdpeMask | X86_PDPE_P)) == X86_PDPE_P)
564 {
565
566 /* The PDE. */
567 PX86PDPAE pGuestPD = pVCpu->pgm.s.CTX_SUFF(apGstPaePDs)[iPdpt];
568 if ( !pGuestPD
569 || (uPdpe & X86_PDPE_PG_MASK) != pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt])
570 pgmGstLazyMapPaePD(pVCpu, iPdpt, &pGuestPD);
571 *piPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
572 return pGuestPD;
573 }
574 }
575 return NULL;
576}
577
578
579/**
580 * Gets the page map level-4 pointer for the guest.
581 *
582 * @returns VBox status code.
583 * @param pVCpu The cross context virtual CPU structure.
584 * @param ppPml4 Where to return the mapping. Always set.
585 */
586DECLINLINE(int) pgmGstGetLongModePML4PtrEx(PVMCPUCC pVCpu, PX86PML4 *ppPml4)
587{
588 *ppPml4 = pVCpu->pgm.s.CTX_SUFF(pGstAmd64Pml4);
589 if (RT_UNLIKELY(!*ppPml4))
590 return pgmGstLazyMapPml4(pVCpu, ppPml4);
591 return VINF_SUCCESS;
592}
593
594
595/**
596 * Gets the page map level-4 pointer for the guest.
597 *
598 * @returns Pointer to the PML4 page.
599 * @param pVCpu The cross context virtual CPU structure.
600 */
601DECLINLINE(PX86PML4) pgmGstGetLongModePML4Ptr(PVMCPUCC pVCpu)
602{
603 PX86PML4 pGuestPml4;
604 int rc = pgmGstGetLongModePML4PtrEx(pVCpu, &pGuestPml4);
605 AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc);
606 return pGuestPml4;
607}
608
609
610/**
611 * Gets the pointer to a page map level-4 entry.
612 *
613 * @returns Pointer to the PML4 entry.
614 * @param pVCpu The cross context virtual CPU structure.
615 * @param iPml4 The index.
616 * @remarks Only used by AssertCR3.
617 */
618DECLINLINE(PX86PML4E) pgmGstGetLongModePML4EPtr(PVMCPUCC pVCpu, unsigned int iPml4)
619{
620 PX86PML4 pGuestPml4 = pVCpu->pgm.s.CTX_SUFF(pGstAmd64Pml4);
621 if (pGuestPml4)
622 { /* likely */ }
623 else
624 {
625 int rc = pgmGstLazyMapPml4(pVCpu, &pGuestPml4);
626 AssertRCReturn(rc, NULL);
627 }
628 return &pGuestPml4->a[iPml4];
629}
630
631
632/**
633 * Gets the page directory entry for the specified address.
634 *
635 * @returns The page directory entry in question.
636 * @returns A non-present entry if the page directory is not present or on an invalid page.
637 * @param pVCpu The cross context virtual CPU structure.
638 * @param GCPtr The address.
639 */
640DECLINLINE(X86PDEPAE) pgmGstGetLongModePDE(PVMCPUCC pVCpu, RTGCPTR64 GCPtr)
641{
642 /*
643 * Note! To keep things simple, ASSUME invalid physical addresses will
644 * cause X86_TRAP_PF_RSVD. This isn't a problem until we start
645 * supporting 52-bit wide physical guest addresses.
646 */
647 PCX86PML4 pGuestPml4 = pgmGstGetLongModePML4Ptr(pVCpu);
648 if (RT_LIKELY(pGuestPml4))
649 {
650 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
651 X86PGPAEUINT const uPml4e = pGuestPml4->a[iPml4].u;
652 if ((uPml4e & (pVCpu->pgm.s.fGstAmd64MbzPml4eMask | X86_PML4E_P)) == X86_PML4E_P)
653 {
654 PCX86PDPT pPdptTemp;
655 int rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, uPml4e & X86_PML4E_PG_MASK, &pPdptTemp);
656 if (RT_SUCCESS(rc))
657 {
658 const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
659 X86PGPAEUINT const uPdpte = pPdptTemp->a[iPdpt].u;
660 if ((uPdpte & (pVCpu->pgm.s.fGstAmd64MbzPdpeMask | X86_PDPE_P)) == X86_PDPE_P)
661 {
662 PCX86PDPAE pPD;
663 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, uPdpte & X86_PDPE_PG_MASK, &pPD);
664 if (RT_SUCCESS(rc))
665 {
666 const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
667 return pPD->a[iPD];
668 }
669 }
670 }
671 AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
672 }
673 }
674
675 X86PDEPAE ZeroPde = {0};
676 return ZeroPde;
677}
678
679
680/**
681 * Gets the GUEST page directory pointer for the specified address.
682 *
683 * @returns The page directory in question.
684 * @returns NULL if the page directory is not present or on an invalid page.
685 * @param pVCpu The cross context virtual CPU structure.
686 * @param GCPtr The address.
687 * @param ppPml4e Page Map Level-4 Entry (out)
688 * @param pPdpe Page directory pointer table entry (out)
689 * @param piPD Receives the index into the returned page directory
690 */
691DECLINLINE(PX86PDPAE) pgmGstGetLongModePDPtr(PVMCPUCC pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPE pPdpe, unsigned *piPD)
692{
693 /* The PMLE4. */
694 PX86PML4 pGuestPml4 = pgmGstGetLongModePML4Ptr(pVCpu);
695 if (pGuestPml4)
696 {
697 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
698 *ppPml4e = &pGuestPml4->a[iPml4];
699 X86PGPAEUINT const uPml4e = pGuestPml4->a[iPml4].u;
700 if ((uPml4e & (pVCpu->pgm.s.fGstAmd64MbzPml4eMask | X86_PML4E_P)) == X86_PML4E_P)
701 {
702 /* The PDPE. */
703 PCX86PDPT pPdptTemp;
704 int rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, uPml4e & X86_PML4E_PG_MASK, &pPdptTemp);
705 if (RT_SUCCESS(rc))
706 {
707 const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
708 X86PGPAEUINT const uPdpe = pPdptTemp->a[iPdpt].u;
709 pPdpe->u = uPdpe;
710 if ((uPdpe & (pVCpu->pgm.s.fGstAmd64MbzPdpeMask | X86_PDPE_P)) == X86_PDPE_P)
711 {
712 /* The PDE. */
713 PX86PDPAE pPD;
714 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, uPdpe & X86_PDPE_PG_MASK, &pPD);
715 if (RT_SUCCESS(rc))
716 {
717 *piPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
718 return pPD;
719 }
720 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
721 }
722 }
723 else
724 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
725 }
726 }
727 return NULL;
728}
729
730
731#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT
732/**
733 * Gets the pointer to a page map level-4 entry when the guest using EPT paging.
734 *
735 * @returns Pointer to the PML4 entry.
736 * @param pVCpu The cross context virtual CPU structure.
737 * @param iPml4 The index.
738 * @remarks Only used by AssertCR3.
739 */
740DECLINLINE(PEPTPML4E) pgmGstGetEptPML4EPtr(PVMCPUCC pVCpu, unsigned int iPml4)
741{
742 PEPTPML4 pEptPml4 = pVCpu->pgm.s.CTX_SUFF(pGstEptPml4);
743 if (pEptPml4)
744 { /* likely */ }
745 else
746 {
747 int const rc = pgmGstLazyMapEptPml4(pVCpu, &pEptPml4);
748 AssertRCReturn(rc, NULL);
749 }
750 return &pEptPml4->a[iPml4];
751}
752
753
754/**
755 * Gets the page map level-4 pointer for the guest when the guest is using EPT
756 * paging.
757 *
758 * @returns VBox status code.
759 * @param pVCpu The cross context virtual CPU structure.
760 * @param ppEptPml4 Where to return the mapping. Always set.
761 */
762DECLINLINE(int) pgmGstGetEptPML4PtrEx(PVMCPUCC pVCpu, PEPTPML4 *ppEptPml4)
763{
764 *ppEptPml4 = pVCpu->pgm.s.CTX_SUFF(pGstEptPml4);
765 if (RT_UNLIKELY(!*ppEptPml4))
766 return pgmGstLazyMapEptPml4(pVCpu, ppEptPml4);
767 return VINF_SUCCESS;
768}
769
770
771/**
772 * Gets the page map level-4 pointer for the guest when the guest is using EPT
773 * paging.
774 *
775 * @returns Pointer to the EPT PML4 page.
776 * @param pVCpu The cross context virtual CPU structure.
777 */
778DECLINLINE(PEPTPML4) pgmGstGetEptPML4Ptr(PVMCPUCC pVCpu)
779{
780 PEPTPML4 pEptPml4;
781 int rc = pgmGstGetEptPML4PtrEx(pVCpu, &pEptPml4);
782 AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc);
783 return pEptPml4;
784}
785#endif /* VBOX_WITH_NESTED_HWVIRT_VMX_EPT */
786
787
788/**
789 * Gets the shadow page directory, 32-bit.
790 *
791 * @returns Pointer to the shadow 32-bit PD.
792 * @param pVCpu The cross context virtual CPU structure.
793 */
794DECLINLINE(PX86PD) pgmShwGet32BitPDPtr(PVMCPUCC pVCpu)
795{
796 return (PX86PD)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
797}
798
799
800/**
801 * Gets the shadow page directory entry for the specified address, 32-bit.
802 *
803 * @returns Shadow 32-bit PDE.
804 * @param pVCpu The cross context virtual CPU structure.
805 * @param GCPtr The address.
806 */
807DECLINLINE(X86PDE) pgmShwGet32BitPDE(PVMCPUCC pVCpu, RTGCPTR GCPtr)
808{
809 PX86PD pShwPde = pgmShwGet32BitPDPtr(pVCpu);
810 if (!pShwPde)
811 {
812 X86PDE ZeroPde = {0};
813 return ZeroPde;
814 }
815 return pShwPde->a[(uint32_t)GCPtr >> X86_PD_SHIFT];
816}
817
818
819/**
820 * Gets the pointer to the shadow page directory entry for the specified
821 * address, 32-bit.
822 *
823 * @returns Pointer to the shadow 32-bit PDE.
824 * @param pVCpu The cross context virtual CPU structure.
825 * @param GCPtr The address.
826 */
827DECLINLINE(PX86PDE) pgmShwGet32BitPDEPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
828{
829 PX86PD pPde = pgmShwGet32BitPDPtr(pVCpu);
830 AssertReturn(pPde, NULL);
831 return &pPde->a[(uint32_t)GCPtr >> X86_PD_SHIFT];
832}
833
834
835/**
836 * Gets the shadow page pointer table, PAE.
837 *
838 * @returns Pointer to the shadow PAE PDPT.
839 * @param pVCpu The cross context virtual CPU structure.
840 */
841DECLINLINE(PX86PDPT) pgmShwGetPaePDPTPtr(PVMCPUCC pVCpu)
842{
843 return (PX86PDPT)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
844}
845
846
847/**
848 * Gets the shadow page directory for the specified address, PAE.
849 *
850 * @returns Pointer to the shadow PD.
851 * @param pVCpu The cross context virtual CPU structure.
852 * @param pPdpt Pointer to the page directory pointer table.
853 * @param GCPtr The address.
854 */
855DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PVMCPUCC pVCpu, PX86PDPT pPdpt, RTGCPTR GCPtr)
856{
857 const unsigned iPdpt = (uint32_t)GCPtr >> X86_PDPT_SHIFT;
858 if (pPdpt->a[iPdpt].u & X86_PDPE_P)
859 {
860 /* Fetch the pgm pool shadow descriptor. */
861 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
862 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pVM->pgm.s.CTX_SUFF(pPool), pPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
863 AssertReturn(pShwPde, NULL);
864
865 return (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPde);
866 }
867 return NULL;
868}
869
870
871/**
872 * Gets the shadow page directory for the specified address, PAE.
873 *
874 * @returns Pointer to the shadow PD.
875 * @param pVCpu The cross context virtual CPU structure.
876 * @param GCPtr The address.
877 */
878DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
879{
880 return pgmShwGetPaePDPtr(pVCpu, pgmShwGetPaePDPTPtr(pVCpu), GCPtr);
881}
882
883
884/**
885 * Gets the shadow page directory entry, PAE.
886 *
887 * @returns PDE.
888 * @param pVCpu The cross context virtual CPU structure.
889 * @param GCPtr The address.
890 */
891DECLINLINE(X86PDEPAE) pgmShwGetPaePDE(PVMCPUCC pVCpu, RTGCPTR GCPtr)
892{
893 const unsigned iPd = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
894 PX86PDPAE pShwPde = pgmShwGetPaePDPtr(pVCpu, GCPtr);
895 if (pShwPde)
896 return pShwPde->a[iPd];
897
898 X86PDEPAE ZeroPde = {0};
899 return ZeroPde;
900}
901
902
903/**
904 * Gets the pointer to the shadow page directory entry for an address, PAE.
905 *
906 * @returns Pointer to the PDE.
907 * @param pVCpu The cross context virtual CPU structure.
908 * @param GCPtr The address.
909 * @remarks Only used by AssertCR3.
910 */
911DECLINLINE(PX86PDEPAE) pgmShwGetPaePDEPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
912{
913 const unsigned iPd = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
914 PX86PDPAE pShwPde = pgmShwGetPaePDPtr(pVCpu, GCPtr);
915 AssertReturn(pShwPde, NULL);
916 return &pShwPde->a[iPd];
917}
918
919
920/**
921 * Gets the shadow page map level-4 pointer.
922 *
923 * @returns Pointer to the shadow PML4.
924 * @param pVCpu The cross context virtual CPU structure.
925 */
926DECLINLINE(PX86PML4) pgmShwGetLongModePML4Ptr(PVMCPUCC pVCpu)
927{
928 return (PX86PML4)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
929}
930
931
932/**
933 * Gets the shadow page map level-4 entry for the specified address.
934 *
935 * @returns The entry.
936 * @param pVCpu The cross context virtual CPU structure.
937 * @param GCPtr The address.
938 */
939DECLINLINE(X86PML4E) pgmShwGetLongModePML4E(PVMCPUCC pVCpu, RTGCPTR GCPtr)
940{
941 const unsigned iPml4 = ((RTGCUINTPTR64)GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
942 PX86PML4 pShwPml4 = pgmShwGetLongModePML4Ptr(pVCpu);
943 if (pShwPml4)
944 return pShwPml4->a[iPml4];
945
946 X86PML4E ZeroPml4e = {0};
947 return ZeroPml4e;
948}
949
950
951/**
952 * Gets the pointer to the specified shadow page map level-4 entry.
953 *
954 * @returns The entry.
955 * @param pVCpu The cross context virtual CPU structure.
956 * @param iPml4 The PML4 index.
957 */
958DECLINLINE(PX86PML4E) pgmShwGetLongModePML4EPtr(PVMCPUCC pVCpu, unsigned int iPml4)
959{
960 PX86PML4 pShwPml4 = pgmShwGetLongModePML4Ptr(pVCpu);
961 if (pShwPml4)
962 return &pShwPml4->a[iPml4];
963 return NULL;
964}
965
966
967/**
968 * Cached physical handler lookup.
969 *
970 * @returns Physical handler covering @a GCPhys.
971 * @param pVM The cross context VM structure.
972 * @param GCPhys The lookup address.
973 */
974DECLINLINE(PPGMPHYSHANDLER) pgmHandlerPhysicalLookup(PVMCC pVM, RTGCPHYS GCPhys)
975{
976 PPGMPHYSHANDLER pHandler = pVM->pgm.s.CTX_SUFF(pLastPhysHandler);
977 if ( pHandler
978 && GCPhys >= pHandler->Core.Key
979 && GCPhys < pHandler->Core.KeyLast)
980 {
981 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysHandlerLookupHits));
982 return pHandler;
983 }
984
985 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysHandlerLookupMisses));
986 pHandler = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
987 if (pHandler)
988 pVM->pgm.s.CTX_SUFF(pLastPhysHandler) = pHandler;
989 return pHandler;
990}
991
992
993/**
994 * Internal worker for finding a 'in-use' shadow page give by it's physical address.
995 *
996 * @returns Pointer to the shadow page structure.
997 * @param pPool The pool.
998 * @param idx The pool page index.
999 */
1000DECLINLINE(PPGMPOOLPAGE) pgmPoolGetPageByIdx(PPGMPOOL pPool, unsigned idx)
1001{
1002 AssertFatalMsg(idx >= PGMPOOL_IDX_FIRST && idx < pPool->cCurPages, ("idx=%d\n", idx));
1003 return &pPool->aPages[idx];
1004}
1005
1006
1007/**
1008 * Clear references to guest physical memory.
1009 *
1010 * @param pPool The pool.
1011 * @param pPoolPage The pool page.
1012 * @param pPhysPage The physical guest page tracking structure.
1013 * @param iPte Shadow PTE index
1014 */
1015DECLINLINE(void) pgmTrackDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPoolPage, PPGMPAGE pPhysPage, uint16_t iPte)
1016{
1017 /*
1018 * Just deal with the simple case here.
1019 */
1020#ifdef VBOX_STRICT
1021 PVMCC pVM = pPool->CTX_SUFF(pVM); NOREF(pVM);
1022#endif
1023#ifdef LOG_ENABLED
1024 const unsigned uOrg = PGM_PAGE_GET_TRACKING(pPhysPage);
1025#endif
1026 const unsigned cRefs = PGM_PAGE_GET_TD_CREFS(pPhysPage);
1027 if (cRefs == 1)
1028 {
1029 Assert(pPoolPage->idx == PGM_PAGE_GET_TD_IDX(pPhysPage));
1030 Assert(iPte == PGM_PAGE_GET_PTE_INDEX(pPhysPage));
1031 /* Invalidate the tracking data. */
1032 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, 0);
1033 }
1034 else
1035 pgmPoolTrackPhysExtDerefGCPhys(pPool, pPoolPage, pPhysPage, iPte);
1036 Log2(("pgmTrackDerefGCPhys: %x -> %x pPhysPage=%R[pgmpage]\n", uOrg, PGM_PAGE_GET_TRACKING(pPhysPage), pPhysPage ));
1037}
1038
1039
1040/**
1041 * Moves the page to the head of the age list.
1042 *
1043 * This is done when the cached page is used in one way or another.
1044 *
1045 * @param pPool The pool.
1046 * @param pPage The cached page.
1047 */
1048DECLINLINE(void) pgmPoolCacheUsed(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1049{
1050 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM));
1051
1052 /*
1053 * Move to the head of the age list.
1054 */
1055 if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
1056 {
1057 /* unlink */
1058 pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
1059 if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
1060 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
1061 else
1062 pPool->iAgeTail = pPage->iAgePrev;
1063
1064 /* insert at head */
1065 pPage->iAgePrev = NIL_PGMPOOL_IDX;
1066 pPage->iAgeNext = pPool->iAgeHead;
1067 Assert(pPage->iAgeNext != NIL_PGMPOOL_IDX); /* we would've already been head then */
1068 pPool->iAgeHead = pPage->idx;
1069 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->idx;
1070 }
1071}
1072
1073
1074/**
1075 * Locks a page to prevent flushing (important for cr3 root pages or shadow pae pd pages).
1076 *
1077 * @param pPool The pool.
1078 * @param pPage PGM pool page
1079 */
1080DECLINLINE(void) pgmPoolLockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1081{
1082 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM)); NOREF(pPool);
1083 ASMAtomicIncU32(&pPage->cLocked);
1084}
1085
1086
1087/**
1088 * Unlocks a page to allow flushing again
1089 *
1090 * @param pPool The pool.
1091 * @param pPage PGM pool page
1092 */
1093DECLINLINE(void) pgmPoolUnlockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1094{
1095 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM)); NOREF(pPool);
1096 Assert(pPage->cLocked);
1097 ASMAtomicDecU32(&pPage->cLocked);
1098}
1099
1100
1101/**
1102 * Checks if the page is locked (e.g. the active CR3 or one of the four PDs of a PAE PDPT)
1103 *
1104 * @returns VBox status code.
1105 * @param pPage PGM pool page
1106 */
1107DECLINLINE(bool) pgmPoolIsPageLocked(PPGMPOOLPAGE pPage)
1108{
1109 if (pPage->cLocked)
1110 {
1111 LogFlow(("pgmPoolIsPageLocked found root page %d\n", pPage->enmKind));
1112 if (pPage->cModifications)
1113 pPage->cModifications = 1; /* reset counter (can't use 0, or else it will be reinserted in the modified list) */
1114 return true;
1115 }
1116 return false;
1117}
1118
1119
1120/**
1121 * Check if the specified page is dirty (not write monitored)
1122 *
1123 * @return dirty or not
1124 * @param pVM The cross context VM structure.
1125 * @param GCPhys Guest physical address
1126 */
1127DECLINLINE(bool) pgmPoolIsDirtyPage(PVMCC pVM, RTGCPHYS GCPhys)
1128{
1129 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1130 PGM_LOCK_ASSERT_OWNER(pVM);
1131 if (!pPool->cDirtyPages)
1132 return false;
1133 return pgmPoolIsDirtyPageSlow(pVM, GCPhys);
1134}
1135
1136
1137/** @} */
1138
1139#endif /* !VMM_INCLUDED_SRC_include_PGMInline_h */
1140
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