VirtualBox

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

Last change on this file since 94156 was 93716, checked in by vboxsync, 3 years ago

VMM/PGM: Moved the physical handler allocation off the hyper heap and into its own slab, changing the it to the 'hardened' avl tree code. bugref:10093

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 37.8 KB
Line 
1/* $Id: PGMInline.h 93716 2022-02-14 10:36:21Z vboxsync $ */
2/** @file
3 * PGM - Inlined functions.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 >> GUEST_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 >> GUEST_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 >> GUEST_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 >> GUEST_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 & GUEST_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 VBox status code.
971 * @retval VERR_NOT_FOUND if no handler.
972 * @param pVM The cross context VM structure.
973 * @param GCPhys The lookup address.
974 * @param ppHandler Where to return the handler pointer.
975 */
976DECLINLINE(int) pgmHandlerPhysicalLookup(PVMCC pVM, RTGCPHYS GCPhys, PPGMPHYSHANDLER *ppHandler)
977{
978 PPGMPHYSHANDLER pHandler = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.ptrFromInt(pVM->pgm.s.idxLastPhysHandler);
979 if ( pHandler
980 && pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.isPtrRetOkay(pHandler)
981 && GCPhys >= pHandler->Key
982 && GCPhys < pHandler->KeyLast
983 && pHandler->hType != NIL_PGMPHYSHANDLERTYPE
984 && pHandler->hType != 0)
985
986 {
987 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysHandlerLookupHits));
988 *ppHandler = pHandler;
989 return VINF_SUCCESS;
990 }
991
992 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysHandlerLookupMisses));
993 AssertPtrReturn(pVM->VMCC_CTX(pgm).s.pPhysHandlerTree, VERR_PGM_HANDLER_IPE_1);
994 int rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pHandler);
995 if (RT_SUCCESS(rc))
996 {
997 *ppHandler = pHandler;
998 pVM->pgm.s.idxLastPhysHandler = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.ptrToInt(pHandler);
999 return VINF_SUCCESS;
1000 }
1001 *ppHandler = NULL;
1002 return rc;
1003}
1004
1005
1006/**
1007 * Converts a handle to a pointer.
1008 *
1009 * @returns Pointer on success, NULL on failure (asserted).
1010 * @param pVM The cross context VM structure.
1011 * @param hType Physical access handler type handle.
1012 */
1013DECLINLINE(PCPGMPHYSHANDLERTYPEINT) pgmHandlerPhysicalTypeHandleToPtr(PVMCC pVM, PGMPHYSHANDLERTYPE hType)
1014{
1015#ifdef IN_RING0
1016 PPGMPHYSHANDLERTYPEINT pType = &pVM->pgmr0.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK];
1017#elif defined(IN_RING3)
1018 PPGMPHYSHANDLERTYPEINT pType = &pVM->pgm.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK];
1019#else
1020# error "Invalid context"
1021#endif
1022 AssertReturn(pType->hType == hType, NULL);
1023 return pType;
1024}
1025
1026
1027/**
1028 * Converts a handle to a pointer, never returns NULL.
1029 *
1030 * @returns Pointer on success, dummy on failure (asserted).
1031 * @param pVM The cross context VM structure.
1032 * @param hType Physical access handler type handle.
1033 */
1034DECLINLINE(PCPGMPHYSHANDLERTYPEINT) pgmHandlerPhysicalTypeHandleToPtr2(PVMCC pVM, PGMPHYSHANDLERTYPE hType)
1035{
1036#ifdef IN_RING0
1037 PPGMPHYSHANDLERTYPEINT pType = &pVM->pgmr0.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK];
1038#elif defined(IN_RING3)
1039 PPGMPHYSHANDLERTYPEINT pType = &pVM->pgm.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK];
1040#else
1041# error "Invalid context"
1042#endif
1043 AssertReturn(pType->hType == hType, &g_pgmHandlerPhysicalDummyType);
1044 return pType;
1045}
1046
1047
1048/**
1049 * Internal worker for finding a 'in-use' shadow page give by it's physical address.
1050 *
1051 * @returns Pointer to the shadow page structure.
1052 * @param pPool The pool.
1053 * @param idx The pool page index.
1054 */
1055DECLINLINE(PPGMPOOLPAGE) pgmPoolGetPageByIdx(PPGMPOOL pPool, unsigned idx)
1056{
1057 AssertFatalMsg(idx >= PGMPOOL_IDX_FIRST && idx < pPool->cCurPages, ("idx=%d\n", idx));
1058 return &pPool->aPages[idx];
1059}
1060
1061
1062/**
1063 * Clear references to guest physical memory.
1064 *
1065 * @param pPool The pool.
1066 * @param pPoolPage The pool page.
1067 * @param pPhysPage The physical guest page tracking structure.
1068 * @param iPte Shadow PTE index
1069 */
1070DECLINLINE(void) pgmTrackDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPoolPage, PPGMPAGE pPhysPage, uint16_t iPte)
1071{
1072 /*
1073 * Just deal with the simple case here.
1074 */
1075#ifdef VBOX_STRICT
1076 PVMCC pVM = pPool->CTX_SUFF(pVM); NOREF(pVM);
1077#endif
1078#ifdef LOG_ENABLED
1079 const unsigned uOrg = PGM_PAGE_GET_TRACKING(pPhysPage);
1080#endif
1081 const unsigned cRefs = PGM_PAGE_GET_TD_CREFS(pPhysPage);
1082 if (cRefs == 1)
1083 {
1084 Assert(pPoolPage->idx == PGM_PAGE_GET_TD_IDX(pPhysPage));
1085 Assert(iPte == PGM_PAGE_GET_PTE_INDEX(pPhysPage));
1086 /* Invalidate the tracking data. */
1087 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, 0);
1088 }
1089 else
1090 pgmPoolTrackPhysExtDerefGCPhys(pPool, pPoolPage, pPhysPage, iPte);
1091 Log2(("pgmTrackDerefGCPhys: %x -> %x pPhysPage=%R[pgmpage]\n", uOrg, PGM_PAGE_GET_TRACKING(pPhysPage), pPhysPage ));
1092}
1093
1094
1095/**
1096 * Moves the page to the head of the age list.
1097 *
1098 * This is done when the cached page is used in one way or another.
1099 *
1100 * @param pPool The pool.
1101 * @param pPage The cached page.
1102 */
1103DECLINLINE(void) pgmPoolCacheUsed(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1104{
1105 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM));
1106
1107 /*
1108 * Move to the head of the age list.
1109 */
1110 if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
1111 {
1112 /* unlink */
1113 pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
1114 if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
1115 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
1116 else
1117 pPool->iAgeTail = pPage->iAgePrev;
1118
1119 /* insert at head */
1120 pPage->iAgePrev = NIL_PGMPOOL_IDX;
1121 pPage->iAgeNext = pPool->iAgeHead;
1122 Assert(pPage->iAgeNext != NIL_PGMPOOL_IDX); /* we would've already been head then */
1123 pPool->iAgeHead = pPage->idx;
1124 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->idx;
1125 }
1126}
1127
1128
1129/**
1130 * Locks a page to prevent flushing (important for cr3 root pages or shadow pae pd pages).
1131 *
1132 * @param pPool The pool.
1133 * @param pPage PGM pool page
1134 */
1135DECLINLINE(void) pgmPoolLockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1136{
1137 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM)); NOREF(pPool);
1138 ASMAtomicIncU32(&pPage->cLocked);
1139}
1140
1141
1142/**
1143 * Unlocks a page to allow flushing again
1144 *
1145 * @param pPool The pool.
1146 * @param pPage PGM pool page
1147 */
1148DECLINLINE(void) pgmPoolUnlockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1149{
1150 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM)); NOREF(pPool);
1151 Assert(pPage->cLocked);
1152 ASMAtomicDecU32(&pPage->cLocked);
1153}
1154
1155
1156/**
1157 * Checks if the page is locked (e.g. the active CR3 or one of the four PDs of a PAE PDPT)
1158 *
1159 * @returns VBox status code.
1160 * @param pPage PGM pool page
1161 */
1162DECLINLINE(bool) pgmPoolIsPageLocked(PPGMPOOLPAGE pPage)
1163{
1164 if (pPage->cLocked)
1165 {
1166 LogFlow(("pgmPoolIsPageLocked found root page %d\n", pPage->enmKind));
1167 if (pPage->cModifications)
1168 pPage->cModifications = 1; /* reset counter (can't use 0, or else it will be reinserted in the modified list) */
1169 return true;
1170 }
1171 return false;
1172}
1173
1174
1175/**
1176 * Check if the specified page is dirty (not write monitored)
1177 *
1178 * @return dirty or not
1179 * @param pVM The cross context VM structure.
1180 * @param GCPhys Guest physical address
1181 */
1182DECLINLINE(bool) pgmPoolIsDirtyPage(PVMCC pVM, RTGCPHYS GCPhys)
1183{
1184 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1185 PGM_LOCK_ASSERT_OWNER(pVM);
1186 if (!pPool->cDirtyPages)
1187 return false;
1188 return pgmPoolIsDirtyPageSlow(pVM, GCPhys);
1189}
1190
1191
1192/** @} */
1193
1194#endif /* !VMM_INCLUDED_SRC_include_PGMInline_h */
1195
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