VirtualBox

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

Last change on this file since 96622 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 38.1 KB
Line 
1/* $Id: PGMInline.h 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * PGM - Inlined functions.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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/**
743 * Gets the pointer to a page map level-4 entry when the guest using EPT paging.
744 *
745 * @returns Pointer to the PML4 entry.
746 * @param pVCpu The cross context virtual CPU structure.
747 * @param iPml4 The index.
748 * @remarks Only used by AssertCR3.
749 */
750DECLINLINE(PEPTPML4E) pgmGstGetEptPML4EPtr(PVMCPUCC pVCpu, unsigned int iPml4)
751{
752 PEPTPML4 pEptPml4 = pVCpu->pgm.s.CTX_SUFF(pGstEptPml4);
753 if (pEptPml4)
754 { /* likely */ }
755 else
756 {
757 int const rc = pgmGstLazyMapEptPml4(pVCpu, &pEptPml4);
758 AssertRCReturn(rc, NULL);
759 }
760 return &pEptPml4->a[iPml4];
761}
762
763
764/**
765 * Gets the page map level-4 pointer for the guest when the guest is using EPT
766 * paging.
767 *
768 * @returns VBox status code.
769 * @param pVCpu The cross context virtual CPU structure.
770 * @param ppEptPml4 Where to return the mapping. Always set.
771 */
772DECLINLINE(int) pgmGstGetEptPML4PtrEx(PVMCPUCC pVCpu, PEPTPML4 *ppEptPml4)
773{
774 *ppEptPml4 = pVCpu->pgm.s.CTX_SUFF(pGstEptPml4);
775 if (RT_UNLIKELY(!*ppEptPml4))
776 return pgmGstLazyMapEptPml4(pVCpu, ppEptPml4);
777 return VINF_SUCCESS;
778}
779
780
781/**
782 * Gets the page map level-4 pointer for the guest when the guest is using EPT
783 * paging.
784 *
785 * @returns Pointer to the EPT PML4 page.
786 * @param pVCpu The cross context virtual CPU structure.
787 */
788DECLINLINE(PEPTPML4) pgmGstGetEptPML4Ptr(PVMCPUCC pVCpu)
789{
790 PEPTPML4 pEptPml4;
791 int rc = pgmGstGetEptPML4PtrEx(pVCpu, &pEptPml4);
792 AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc);
793 return pEptPml4;
794}
795#endif /* VBOX_WITH_NESTED_HWVIRT_VMX_EPT */
796
797
798/**
799 * Gets the shadow page directory, 32-bit.
800 *
801 * @returns Pointer to the shadow 32-bit PD.
802 * @param pVCpu The cross context virtual CPU structure.
803 */
804DECLINLINE(PX86PD) pgmShwGet32BitPDPtr(PVMCPUCC pVCpu)
805{
806 return (PX86PD)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
807}
808
809
810/**
811 * Gets the shadow page directory entry for the specified address, 32-bit.
812 *
813 * @returns Shadow 32-bit PDE.
814 * @param pVCpu The cross context virtual CPU structure.
815 * @param GCPtr The address.
816 */
817DECLINLINE(X86PDE) pgmShwGet32BitPDE(PVMCPUCC pVCpu, RTGCPTR GCPtr)
818{
819 PX86PD pShwPde = pgmShwGet32BitPDPtr(pVCpu);
820 if (!pShwPde)
821 {
822 X86PDE ZeroPde = {0};
823 return ZeroPde;
824 }
825 return pShwPde->a[(uint32_t)GCPtr >> X86_PD_SHIFT];
826}
827
828
829/**
830 * Gets the pointer to the shadow page directory entry for the specified
831 * address, 32-bit.
832 *
833 * @returns Pointer to the shadow 32-bit PDE.
834 * @param pVCpu The cross context virtual CPU structure.
835 * @param GCPtr The address.
836 */
837DECLINLINE(PX86PDE) pgmShwGet32BitPDEPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
838{
839 PX86PD pPde = pgmShwGet32BitPDPtr(pVCpu);
840 AssertReturn(pPde, NULL);
841 return &pPde->a[(uint32_t)GCPtr >> X86_PD_SHIFT];
842}
843
844
845/**
846 * Gets the shadow page pointer table, PAE.
847 *
848 * @returns Pointer to the shadow PAE PDPT.
849 * @param pVCpu The cross context virtual CPU structure.
850 */
851DECLINLINE(PX86PDPT) pgmShwGetPaePDPTPtr(PVMCPUCC pVCpu)
852{
853 return (PX86PDPT)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
854}
855
856
857/**
858 * Gets the shadow page directory for the specified address, PAE.
859 *
860 * @returns Pointer to the shadow PD.
861 * @param pVCpu The cross context virtual CPU structure.
862 * @param pPdpt Pointer to the page directory pointer table.
863 * @param GCPtr The address.
864 */
865DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PVMCPUCC pVCpu, PX86PDPT pPdpt, RTGCPTR GCPtr)
866{
867 const unsigned iPdpt = (uint32_t)GCPtr >> X86_PDPT_SHIFT;
868 if (pPdpt->a[iPdpt].u & X86_PDPE_P)
869 {
870 /* Fetch the pgm pool shadow descriptor. */
871 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
872 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pVM->pgm.s.CTX_SUFF(pPool), pPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
873 AssertReturn(pShwPde, NULL);
874
875 return (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPde);
876 }
877 return NULL;
878}
879
880
881/**
882 * Gets the shadow page directory for the specified address, PAE.
883 *
884 * @returns Pointer to the shadow PD.
885 * @param pVCpu The cross context virtual CPU structure.
886 * @param GCPtr The address.
887 */
888DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
889{
890 return pgmShwGetPaePDPtr(pVCpu, pgmShwGetPaePDPTPtr(pVCpu), GCPtr);
891}
892
893
894/**
895 * Gets the shadow page directory entry, PAE.
896 *
897 * @returns PDE.
898 * @param pVCpu The cross context virtual CPU structure.
899 * @param GCPtr The address.
900 */
901DECLINLINE(X86PDEPAE) pgmShwGetPaePDE(PVMCPUCC pVCpu, RTGCPTR GCPtr)
902{
903 const unsigned iPd = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
904 PX86PDPAE pShwPde = pgmShwGetPaePDPtr(pVCpu, GCPtr);
905 if (pShwPde)
906 return pShwPde->a[iPd];
907
908 X86PDEPAE ZeroPde = {0};
909 return ZeroPde;
910}
911
912
913/**
914 * Gets the pointer to the shadow page directory entry for an address, PAE.
915 *
916 * @returns Pointer to the PDE.
917 * @param pVCpu The cross context virtual CPU structure.
918 * @param GCPtr The address.
919 * @remarks Only used by AssertCR3.
920 */
921DECLINLINE(PX86PDEPAE) pgmShwGetPaePDEPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr)
922{
923 const unsigned iPd = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
924 PX86PDPAE pShwPde = pgmShwGetPaePDPtr(pVCpu, GCPtr);
925 AssertReturn(pShwPde, NULL);
926 return &pShwPde->a[iPd];
927}
928
929
930/**
931 * Gets the shadow page map level-4 pointer.
932 *
933 * @returns Pointer to the shadow PML4.
934 * @param pVCpu The cross context virtual CPU structure.
935 */
936DECLINLINE(PX86PML4) pgmShwGetLongModePML4Ptr(PVMCPUCC pVCpu)
937{
938 return (PX86PML4)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
939}
940
941
942/**
943 * Gets the shadow page map level-4 entry for the specified address.
944 *
945 * @returns The entry.
946 * @param pVCpu The cross context virtual CPU structure.
947 * @param GCPtr The address.
948 */
949DECLINLINE(X86PML4E) pgmShwGetLongModePML4E(PVMCPUCC pVCpu, RTGCPTR GCPtr)
950{
951 const unsigned iPml4 = ((RTGCUINTPTR64)GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
952 PX86PML4 pShwPml4 = pgmShwGetLongModePML4Ptr(pVCpu);
953 if (pShwPml4)
954 return pShwPml4->a[iPml4];
955
956 X86PML4E ZeroPml4e = {0};
957 return ZeroPml4e;
958}
959
960
961/**
962 * Gets the pointer to the specified shadow page map level-4 entry.
963 *
964 * @returns The entry.
965 * @param pVCpu The cross context virtual CPU structure.
966 * @param iPml4 The PML4 index.
967 */
968DECLINLINE(PX86PML4E) pgmShwGetLongModePML4EPtr(PVMCPUCC pVCpu, unsigned int iPml4)
969{
970 PX86PML4 pShwPml4 = pgmShwGetLongModePML4Ptr(pVCpu);
971 if (pShwPml4)
972 return &pShwPml4->a[iPml4];
973 return NULL;
974}
975
976
977/**
978 * Cached physical handler lookup.
979 *
980 * @returns VBox status code.
981 * @retval VERR_NOT_FOUND if no handler.
982 * @param pVM The cross context VM structure.
983 * @param GCPhys The lookup address.
984 * @param ppHandler Where to return the handler pointer.
985 */
986DECLINLINE(int) pgmHandlerPhysicalLookup(PVMCC pVM, RTGCPHYS GCPhys, PPGMPHYSHANDLER *ppHandler)
987{
988 PPGMPHYSHANDLER pHandler = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.ptrFromInt(pVM->pgm.s.idxLastPhysHandler);
989 if ( pHandler
990 && pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.isPtrRetOkay(pHandler)
991 && GCPhys >= pHandler->Key
992 && GCPhys < pHandler->KeyLast
993 && pHandler->hType != NIL_PGMPHYSHANDLERTYPE
994 && pHandler->hType != 0)
995
996 {
997 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysHandlerLookupHits));
998 *ppHandler = pHandler;
999 return VINF_SUCCESS;
1000 }
1001
1002 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysHandlerLookupMisses));
1003 AssertPtrReturn(pVM->VMCC_CTX(pgm).s.pPhysHandlerTree, VERR_PGM_HANDLER_IPE_1);
1004 int rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pHandler);
1005 if (RT_SUCCESS(rc))
1006 {
1007 *ppHandler = pHandler;
1008 pVM->pgm.s.idxLastPhysHandler = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.ptrToInt(pHandler);
1009 return VINF_SUCCESS;
1010 }
1011 *ppHandler = NULL;
1012 return rc;
1013}
1014
1015
1016/**
1017 * Converts a handle to a pointer.
1018 *
1019 * @returns Pointer on success, NULL on failure (asserted).
1020 * @param pVM The cross context VM structure.
1021 * @param hType Physical access handler type handle.
1022 */
1023DECLINLINE(PCPGMPHYSHANDLERTYPEINT) pgmHandlerPhysicalTypeHandleToPtr(PVMCC pVM, PGMPHYSHANDLERTYPE hType)
1024{
1025#ifdef IN_RING0
1026 PPGMPHYSHANDLERTYPEINT pType = &pVM->pgmr0.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK];
1027#elif defined(IN_RING3)
1028 PPGMPHYSHANDLERTYPEINT pType = &pVM->pgm.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK];
1029#else
1030# error "Invalid context"
1031#endif
1032 AssertReturn(pType->hType == hType, NULL);
1033 return pType;
1034}
1035
1036
1037/**
1038 * Converts a handle to a pointer, never returns NULL.
1039 *
1040 * @returns Pointer on success, dummy on failure (asserted).
1041 * @param pVM The cross context VM structure.
1042 * @param hType Physical access handler type handle.
1043 */
1044DECLINLINE(PCPGMPHYSHANDLERTYPEINT) pgmHandlerPhysicalTypeHandleToPtr2(PVMCC pVM, PGMPHYSHANDLERTYPE hType)
1045{
1046#ifdef IN_RING0
1047 PPGMPHYSHANDLERTYPEINT pType = &pVM->pgmr0.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK];
1048#elif defined(IN_RING3)
1049 PPGMPHYSHANDLERTYPEINT pType = &pVM->pgm.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK];
1050#else
1051# error "Invalid context"
1052#endif
1053 AssertReturn(pType->hType == hType, &g_pgmHandlerPhysicalDummyType);
1054 return pType;
1055}
1056
1057
1058/**
1059 * Internal worker for finding a 'in-use' shadow page give by it's physical address.
1060 *
1061 * @returns Pointer to the shadow page structure.
1062 * @param pPool The pool.
1063 * @param idx The pool page index.
1064 */
1065DECLINLINE(PPGMPOOLPAGE) pgmPoolGetPageByIdx(PPGMPOOL pPool, unsigned idx)
1066{
1067 AssertFatalMsg(idx >= PGMPOOL_IDX_FIRST && idx < pPool->cCurPages, ("idx=%d\n", idx));
1068 return &pPool->aPages[idx];
1069}
1070
1071
1072/**
1073 * Clear references to guest physical memory.
1074 *
1075 * @param pPool The pool.
1076 * @param pPoolPage The pool page.
1077 * @param pPhysPage The physical guest page tracking structure.
1078 * @param iPte Shadow PTE index
1079 */
1080DECLINLINE(void) pgmTrackDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPoolPage, PPGMPAGE pPhysPage, uint16_t iPte)
1081{
1082 /*
1083 * Just deal with the simple case here.
1084 */
1085#ifdef VBOX_STRICT
1086 PVMCC pVM = pPool->CTX_SUFF(pVM); NOREF(pVM);
1087#endif
1088#ifdef LOG_ENABLED
1089 const unsigned uOrg = PGM_PAGE_GET_TRACKING(pPhysPage);
1090#endif
1091 const unsigned cRefs = PGM_PAGE_GET_TD_CREFS(pPhysPage);
1092 if (cRefs == 1)
1093 {
1094 Assert(pPoolPage->idx == PGM_PAGE_GET_TD_IDX(pPhysPage));
1095 Assert(iPte == PGM_PAGE_GET_PTE_INDEX(pPhysPage));
1096 /* Invalidate the tracking data. */
1097 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, 0);
1098 }
1099 else
1100 pgmPoolTrackPhysExtDerefGCPhys(pPool, pPoolPage, pPhysPage, iPte);
1101 Log2(("pgmTrackDerefGCPhys: %x -> %x pPhysPage=%R[pgmpage]\n", uOrg, PGM_PAGE_GET_TRACKING(pPhysPage), pPhysPage ));
1102}
1103
1104
1105/**
1106 * Moves the page to the head of the age list.
1107 *
1108 * This is done when the cached page is used in one way or another.
1109 *
1110 * @param pPool The pool.
1111 * @param pPage The cached page.
1112 */
1113DECLINLINE(void) pgmPoolCacheUsed(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1114{
1115 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM));
1116
1117 /*
1118 * Move to the head of the age list.
1119 */
1120 if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
1121 {
1122 /* unlink */
1123 pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
1124 if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
1125 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
1126 else
1127 pPool->iAgeTail = pPage->iAgePrev;
1128
1129 /* insert at head */
1130 pPage->iAgePrev = NIL_PGMPOOL_IDX;
1131 pPage->iAgeNext = pPool->iAgeHead;
1132 Assert(pPage->iAgeNext != NIL_PGMPOOL_IDX); /* we would've already been head then */
1133 pPool->iAgeHead = pPage->idx;
1134 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->idx;
1135 }
1136}
1137
1138
1139/**
1140 * Locks a page to prevent flushing (important for cr3 root pages or shadow pae pd pages).
1141 *
1142 * @param pPool The pool.
1143 * @param pPage PGM pool page
1144 */
1145DECLINLINE(void) pgmPoolLockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1146{
1147 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM)); NOREF(pPool);
1148 ASMAtomicIncU32(&pPage->cLocked);
1149}
1150
1151
1152/**
1153 * Unlocks a page to allow flushing again
1154 *
1155 * @param pPool The pool.
1156 * @param pPage PGM pool page
1157 */
1158DECLINLINE(void) pgmPoolUnlockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1159{
1160 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM)); NOREF(pPool);
1161 Assert(pPage->cLocked);
1162 ASMAtomicDecU32(&pPage->cLocked);
1163}
1164
1165
1166/**
1167 * Checks if the page is locked (e.g. the active CR3 or one of the four PDs of a PAE PDPT)
1168 *
1169 * @returns VBox status code.
1170 * @param pPage PGM pool page
1171 */
1172DECLINLINE(bool) pgmPoolIsPageLocked(PPGMPOOLPAGE pPage)
1173{
1174 if (pPage->cLocked)
1175 {
1176 LogFlow(("pgmPoolIsPageLocked found root page %d\n", pPage->enmKind));
1177 if (pPage->cModifications)
1178 pPage->cModifications = 1; /* reset counter (can't use 0, or else it will be reinserted in the modified list) */
1179 return true;
1180 }
1181 return false;
1182}
1183
1184
1185/**
1186 * Check if the specified page is dirty (not write monitored)
1187 *
1188 * @return dirty or not
1189 * @param pVM The cross context VM structure.
1190 * @param GCPhys Guest physical address
1191 */
1192DECLINLINE(bool) pgmPoolIsDirtyPage(PVMCC pVM, RTGCPHYS GCPhys)
1193{
1194 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1195 PGM_LOCK_ASSERT_OWNER(pVM);
1196 if (!pPool->cDirtyPages)
1197 return false;
1198 return pgmPoolIsDirtyPageSlow(pVM, GCPhys);
1199}
1200
1201
1202/** @} */
1203
1204#endif /* !VMM_INCLUDED_SRC_include_PGMInline_h */
1205
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