VirtualBox

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

Last change on this file since 98122 was 98103, checked in by vboxsync, 22 months ago

Copyright year updates by scm.

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