VirtualBox

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

Last change on this file since 70948 was 70948, checked in by vboxsync, 7 years ago

VMM: Added a bMainExecutionEngine member to the VM structure for use instead of fHMEnabled and fNEMEnabled. Changed a lot of HMIsEnabled invocations to use the new macros VM_IS_RAW_MODE_ENABLED and VM_IS_HM_OR_NEM_ENABLED. Eliminated fHMEnabledFixed. Fixed inverted test for raw-mode debug register sanity checking. Some other minor cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 50.4 KB
Line 
1/* $Id: PGMInline.h 70948 2018-02-10 15:38:12Z vboxsync $ */
2/** @file
3 * PGM - Inlined functions.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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 ___PGMInline_h
19#define ___PGMInline_h
20
21#include <VBox/cdefs.h>
22#include <VBox/types.h>
23#include <VBox/err.h>
24#include <VBox/vmm/stam.h>
25#include <VBox/param.h>
26#include <VBox/vmm/vmm.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/vmm/pdmcritsect.h>
29#include <VBox/vmm/pdmapi.h>
30#include <VBox/dis.h>
31#include <VBox/vmm/dbgf.h>
32#include <VBox/log.h>
33#include <VBox/vmm/gmm.h>
34#include <VBox/vmm/hm.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/avl.h>
38#include <iprt/critsect.h>
39#include <iprt/sha.h>
40
41
42
43/** @addtogroup grp_pgm_int Internals
44 * @internal
45 * @{
46 */
47
48/**
49 * Gets the PGMRAMRANGE structure for a guest page.
50 *
51 * @returns Pointer to the RAM range on success.
52 * @returns NULL on a VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS condition.
53 *
54 * @param pVM The cross context VM structure.
55 * @param GCPhys The GC physical address.
56 */
57DECLINLINE(PPGMRAMRANGE) pgmPhysGetRange(PVM pVM, RTGCPHYS GCPhys)
58{
59 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
60 if (!pRam || GCPhys - pRam->GCPhys >= pRam->cb)
61 return pgmPhysGetRangeSlow(pVM, GCPhys);
62 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,RamRangeTlbHits));
63 return pRam;
64}
65
66
67/**
68 * Gets the PGMRAMRANGE structure for a guest page, if unassigned get the ram
69 * range above it.
70 *
71 * @returns Pointer to the RAM range on success.
72 * @returns NULL if the address is located after the last range.
73 *
74 * @param pVM The cross context VM structure.
75 * @param GCPhys The GC physical address.
76 */
77DECLINLINE(PPGMRAMRANGE) pgmPhysGetRangeAtOrAbove(PVM pVM, RTGCPHYS GCPhys)
78{
79 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
80 if ( !pRam
81 || (GCPhys - pRam->GCPhys) >= pRam->cb)
82 return pgmPhysGetRangeAtOrAboveSlow(pVM, GCPhys);
83 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,RamRangeTlbHits));
84 return pRam;
85}
86
87
88/**
89 * Gets the PGMPAGE structure for a guest page.
90 *
91 * @returns Pointer to the page on success.
92 * @returns NULL on a VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS condition.
93 *
94 * @param pVM The cross context VM structure.
95 * @param GCPhys The GC physical address.
96 */
97DECLINLINE(PPGMPAGE) pgmPhysGetPage(PVM pVM, RTGCPHYS GCPhys)
98{
99 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
100 RTGCPHYS off;
101 if ( !pRam
102 || (off = GCPhys - pRam->GCPhys) >= pRam->cb)
103 return pgmPhysGetPageSlow(pVM, GCPhys);
104 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,RamRangeTlbHits));
105 return &pRam->aPages[off >> PAGE_SHIFT];
106}
107
108
109/**
110 * Gets the PGMPAGE structure for a guest page.
111 *
112 * Old Phys code: Will make sure the page is present.
113 *
114 * @returns VBox status code.
115 * @retval VINF_SUCCESS and a valid *ppPage on success.
116 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if the address isn't valid.
117 *
118 * @param pVM The cross context VM structure.
119 * @param GCPhys The GC physical address.
120 * @param ppPage Where to store the page pointer on success.
121 */
122DECLINLINE(int) pgmPhysGetPageEx(PVM pVM, RTGCPHYS GCPhys, PPPGMPAGE ppPage)
123{
124 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
125 RTGCPHYS off;
126 if ( !pRam
127 || (off = GCPhys - pRam->GCPhys) >= pRam->cb)
128 return pgmPhysGetPageExSlow(pVM, GCPhys, ppPage);
129 *ppPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
130 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,RamRangeTlbHits));
131 return VINF_SUCCESS;
132}
133
134
135/**
136 * Gets the PGMPAGE structure for a guest page.
137 *
138 * Old Phys code: Will make sure the page is present.
139 *
140 * @returns VBox status code.
141 * @retval VINF_SUCCESS and a valid *ppPage on success.
142 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if the address isn't valid.
143 *
144 * @param pVM The cross context VM structure.
145 * @param GCPhys The GC physical address.
146 * @param ppPage Where to store the page pointer on success.
147 * @param ppRamHint Where to read and store the ram list hint.
148 * The caller initializes this to NULL before the call.
149 */
150DECLINLINE(int) pgmPhysGetPageWithHintEx(PVM pVM, RTGCPHYS GCPhys, PPPGMPAGE ppPage, PPGMRAMRANGE *ppRamHint)
151{
152 RTGCPHYS off;
153 PPGMRAMRANGE pRam = *ppRamHint;
154 if ( !pRam
155 || RT_UNLIKELY((off = GCPhys - pRam->GCPhys) >= pRam->cb))
156 {
157 pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
158 if ( !pRam
159 || (off = GCPhys - pRam->GCPhys) >= pRam->cb)
160 return pgmPhysGetPageAndRangeExSlow(pVM, GCPhys, ppPage, ppRamHint);
161
162 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,RamRangeTlbHits));
163 *ppRamHint = pRam;
164 }
165 *ppPage = &pRam->aPages[off >> PAGE_SHIFT];
166 return VINF_SUCCESS;
167}
168
169
170/**
171 * Gets the PGMPAGE structure for a guest page together with the PGMRAMRANGE.
172 *
173 * @returns Pointer to the page on success.
174 * @returns NULL on a VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS condition.
175 *
176 * @param pVM The cross context VM structure.
177 * @param GCPhys The GC physical address.
178 * @param ppPage Where to store the pointer to the PGMPAGE structure.
179 * @param ppRam Where to store the pointer to the PGMRAMRANGE structure.
180 */
181DECLINLINE(int) pgmPhysGetPageAndRangeEx(PVM pVM, RTGCPHYS GCPhys, PPPGMPAGE ppPage, PPGMRAMRANGE *ppRam)
182{
183 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
184 RTGCPHYS off;
185 if ( !pRam
186 || (off = GCPhys - pRam->GCPhys) >= pRam->cb)
187 return pgmPhysGetPageAndRangeExSlow(pVM, GCPhys, ppPage, ppRam);
188
189 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,RamRangeTlbHits));
190 *ppRam = pRam;
191 *ppPage = &pRam->aPages[off >> PAGE_SHIFT];
192 return VINF_SUCCESS;
193}
194
195
196/**
197 * Convert GC Phys to HC Phys.
198 *
199 * @returns VBox status code.
200 * @param pVM The cross context VM structure.
201 * @param GCPhys The GC physical address.
202 * @param pHCPhys Where to store the corresponding HC physical address.
203 *
204 * @deprecated Doesn't deal with zero, shared or write monitored pages.
205 * Avoid when writing new code!
206 */
207DECLINLINE(int) pgmRamGCPhys2HCPhys(PVM pVM, RTGCPHYS GCPhys, PRTHCPHYS pHCPhys)
208{
209 PPGMPAGE pPage;
210 int rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage);
211 if (RT_FAILURE(rc))
212 return rc;
213 *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage) | (GCPhys & PAGE_OFFSET_MASK);
214 return VINF_SUCCESS;
215}
216
217#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
218
219/**
220 * Inlined version of the ring-0 version of the host page mapping code
221 * that optimizes access to pages already in the set.
222 *
223 * @returns VINF_SUCCESS. Will bail out to ring-3 on failure.
224 * @param pVCpu The cross context virtual CPU structure.
225 * @param HCPhys The physical address of the page.
226 * @param ppv Where to store the mapping address.
227 * @param SRC_POS The source location of the caller.
228 */
229DECLINLINE(int) pgmRZDynMapHCPageInlined(PVMCPU pVCpu, RTHCPHYS HCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
230{
231 PPGMMAPSET pSet = &pVCpu->pgm.s.AutoSet;
232
233 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapHCPageInl, a);
234 Assert(!(HCPhys & PAGE_OFFSET_MASK));
235 Assert(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries));
236
237 unsigned iHash = PGMMAPSET_HASH(HCPhys);
238 unsigned iEntry = pSet->aiHashTable[iHash];
239 if ( iEntry < pSet->cEntries
240 && pSet->aEntries[iEntry].HCPhys == HCPhys
241 && pSet->aEntries[iEntry].cInlinedRefs < UINT16_MAX - 1)
242 {
243 pSet->aEntries[iEntry].cInlinedRefs++;
244 *ppv = pSet->aEntries[iEntry].pvPage;
245 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapHCPageInlHits);
246 }
247 else
248 {
249 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapHCPageInlMisses);
250 pgmRZDynMapHCPageCommon(pSet, HCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
251 }
252
253 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapHCPageInl, a);
254 return VINF_SUCCESS;
255}
256
257
258/**
259 * Inlined version of the guest page mapping code that optimizes access to pages
260 * already in the set.
261 *
262 * @returns VBox status code, see pgmRZDynMapGCPageCommon for details.
263 * @param pVM The cross context VM structure.
264 * @param pVCpu The cross context virtual CPU structure.
265 * @param GCPhys The guest physical address of the page.
266 * @param ppv Where to store the mapping address.
267 * @param SRC_POS The source location of the caller.
268 */
269DECLINLINE(int) pgmRZDynMapGCPageV2Inlined(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
270{
271 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInl, a);
272 AssertMsg(!(GCPhys & PAGE_OFFSET_MASK), ("%RGp\n", GCPhys));
273
274 /*
275 * Get the ram range.
276 */
277 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
278 RTGCPHYS off;
279 if ( !pRam
280 || (off = GCPhys - pRam->GCPhys) >= pRam->cb
281 /** @todo || page state stuff */
282 )
283 {
284 /* This case is not counted into StatRZDynMapGCPageInl. */
285 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlRamMisses);
286 return pgmRZDynMapGCPageCommon(pVM, pVCpu, GCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
287 }
288
289 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[off >> PAGE_SHIFT]);
290 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlRamHits);
291
292 /*
293 * pgmRZDynMapHCPageInlined with out stats.
294 */
295 PPGMMAPSET pSet = &pVCpu->pgm.s.AutoSet;
296 Assert(!(HCPhys & PAGE_OFFSET_MASK));
297 Assert(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries));
298
299 unsigned iHash = PGMMAPSET_HASH(HCPhys);
300 unsigned iEntry = pSet->aiHashTable[iHash];
301 if ( iEntry < pSet->cEntries
302 && pSet->aEntries[iEntry].HCPhys == HCPhys
303 && pSet->aEntries[iEntry].cInlinedRefs < UINT16_MAX - 1)
304 {
305 pSet->aEntries[iEntry].cInlinedRefs++;
306 *ppv = pSet->aEntries[iEntry].pvPage;
307 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlHits);
308 }
309 else
310 {
311 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlMisses);
312 pgmRZDynMapHCPageCommon(pSet, HCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
313 }
314
315 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInl, a);
316 return VINF_SUCCESS;
317}
318
319
320/**
321 * Inlined version of the ring-0 version of guest page mapping that optimizes
322 * access to pages already in the set.
323 *
324 * @returns VBox status code, see pgmRZDynMapGCPageCommon for details.
325 * @param pVCpu The cross context virtual CPU structure.
326 * @param GCPhys The guest physical address of the page.
327 * @param ppv Where to store the mapping address.
328 * @param SRC_POS The source location of the caller.
329 */
330DECLINLINE(int) pgmRZDynMapGCPageInlined(PVMCPU pVCpu, RTGCPHYS GCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
331{
332 return pgmRZDynMapGCPageV2Inlined(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
333}
334
335
336/**
337 * Inlined version of the ring-0 version of the guest byte mapping code
338 * that optimizes access to pages already in the set.
339 *
340 * @returns VBox status code, see pgmRZDynMapGCPageCommon for details.
341 * @param pVCpu The cross context virtual CPU structure.
342 * @param GCPhys The guest physical address of the page.
343 * @param ppv Where to store the mapping address. The offset is
344 * preserved.
345 * @param SRC_POS The source location of the caller.
346 */
347DECLINLINE(int) pgmRZDynMapGCPageOffInlined(PVMCPU pVCpu, RTGCPHYS GCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
348{
349 STAM_PROFILE_START(&pVCpu->pgm.s.StatRZDynMapGCPageInl, a);
350
351 /*
352 * Get the ram range.
353 */
354 PVM pVM = pVCpu->CTX_SUFF(pVM);
355 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)];
356 RTGCPHYS off;
357 if ( !pRam
358 || (off = GCPhys - pRam->GCPhys) >= pRam->cb
359 /** @todo || page state stuff */
360 )
361 {
362 /* This case is not counted into StatRZDynMapGCPageInl. */
363 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlRamMisses);
364 return pgmRZDynMapGCPageCommon(pVM, pVCpu, GCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
365 }
366
367 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[off >> PAGE_SHIFT]);
368 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlRamHits);
369
370 /*
371 * pgmRZDynMapHCPageInlined with out stats.
372 */
373 PPGMMAPSET pSet = &pVCpu->pgm.s.AutoSet;
374 Assert(!(HCPhys & PAGE_OFFSET_MASK));
375 Assert(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries));
376
377 unsigned iHash = PGMMAPSET_HASH(HCPhys);
378 unsigned iEntry = pSet->aiHashTable[iHash];
379 if ( iEntry < pSet->cEntries
380 && pSet->aEntries[iEntry].HCPhys == HCPhys
381 && pSet->aEntries[iEntry].cInlinedRefs < UINT16_MAX - 1)
382 {
383 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlHits);
384 pSet->aEntries[iEntry].cInlinedRefs++;
385 *ppv = (void *)((uintptr_t)pSet->aEntries[iEntry].pvPage | (PAGE_OFFSET_MASK & (uintptr_t)GCPhys));
386 }
387 else
388 {
389 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlMisses);
390 pgmRZDynMapHCPageCommon(pSet, HCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
391 *ppv = (void *)((uintptr_t)*ppv | (PAGE_OFFSET_MASK & (uintptr_t)GCPhys));
392 }
393
394 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInl, a);
395 return VINF_SUCCESS;
396}
397
398#endif /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
399#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
400
401/**
402 * Maps the page into current context (RC and maybe R0).
403 *
404 * @returns pointer to the mapping.
405 * @param pVM The cross context VM structure.
406 * @param pPage The page.
407 * @param SRC_POS The source location of the caller.
408 */
409DECLINLINE(void *) pgmPoolMapPageInlined(PVM pVM, PPGMPOOLPAGE pPage RTLOG_COMMA_SRC_POS_DECL)
410{
411 if (pPage->idx >= PGMPOOL_IDX_FIRST)
412 {
413 Assert(pPage->idx < pVM->pgm.s.CTX_SUFF(pPool)->cCurPages);
414 void *pv;
415 pgmRZDynMapHCPageInlined(VMMGetCpu(pVM), pPage->Core.Key, &pv RTLOG_COMMA_SRC_POS_ARGS);
416 return pv;
417 }
418 AssertFatalMsgFailed(("pgmPoolMapPageInlined invalid page index %x\n", pPage->idx));
419}
420
421
422/**
423 * Maps the page into current context (RC and maybe R0).
424 *
425 * @returns pointer to the mapping.
426 * @param pVM The cross context VM structure.
427 * @param pVCpu The cross context virtual CPU structure.
428 * @param pPage The page.
429 * @param SRC_POS The source location of the caller.
430 */
431DECLINLINE(void *) pgmPoolMapPageV2Inlined(PVM pVM, PVMCPU pVCpu, PPGMPOOLPAGE pPage RTLOG_COMMA_SRC_POS_DECL)
432{
433 if (pPage->idx >= PGMPOOL_IDX_FIRST)
434 {
435 Assert(pPage->idx < pVM->pgm.s.CTX_SUFF(pPool)->cCurPages);
436 void *pv;
437 Assert(pVCpu == VMMGetCpu(pVM)); RT_NOREF_PV(pVM);
438 pgmRZDynMapHCPageInlined(pVCpu, pPage->Core.Key, &pv RTLOG_COMMA_SRC_POS_ARGS);
439 return pv;
440 }
441 AssertFatalMsgFailed(("pgmPoolMapPageV2Inlined invalid page index %x\n", pPage->idx));
442}
443
444#endif /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 || IN_RC */
445#ifndef IN_RC
446
447/**
448 * Queries the Physical TLB entry for a physical guest page,
449 * attempting to load the TLB entry if necessary.
450 *
451 * @returns VBox status code.
452 * @retval VINF_SUCCESS on success
453 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
454 *
455 * @param pVM The cross context VM structure.
456 * @param GCPhys The address of the guest page.
457 * @param ppTlbe Where to store the pointer to the TLB entry.
458 */
459DECLINLINE(int) pgmPhysPageQueryTlbe(PVM pVM, RTGCPHYS GCPhys, PPPGMPAGEMAPTLBE ppTlbe)
460{
461 int rc;
462 PPGMPAGEMAPTLBE pTlbe = &pVM->pgm.s.CTXSUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
463 if (pTlbe->GCPhys == (GCPhys & X86_PTE_PAE_PG_MASK))
464 {
465 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageMapTlbHits));
466 rc = VINF_SUCCESS;
467 }
468 else
469 rc = pgmPhysPageLoadIntoTlb(pVM, GCPhys);
470 *ppTlbe = pTlbe;
471 return rc;
472}
473
474
475/**
476 * Queries the Physical TLB entry for a physical guest page,
477 * attempting to load the TLB entry if necessary.
478 *
479 * @returns VBox status code.
480 * @retval VINF_SUCCESS on success
481 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
482 *
483 * @param pVM The cross context VM structure.
484 * @param pPage Pointer to the PGMPAGE structure corresponding to
485 * GCPhys.
486 * @param GCPhys The address of the guest page.
487 * @param ppTlbe Where to store the pointer to the TLB entry.
488 */
489DECLINLINE(int) pgmPhysPageQueryTlbeWithPage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMPAGEMAPTLBE ppTlbe)
490{
491 int rc;
492 PPGMPAGEMAPTLBE pTlbe = &pVM->pgm.s.CTXSUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
493 if (pTlbe->GCPhys == (GCPhys & X86_PTE_PAE_PG_MASK))
494 {
495 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageMapTlbHits));
496 rc = VINF_SUCCESS;
497# if 0 //def VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
498# ifdef IN_RING3
499 if (pTlbe->pv == (void *)pVM->pgm.s.pvZeroPgR0)
500# else
501 if (pTlbe->pv == (void *)pVM->pgm.s.pvZeroPgR3)
502# endif
503 pTlbe->pv = pVM->pgm.s.CTX_SUFF(pvZeroPg);
504# endif
505 AssertPtr(pTlbe->pv);
506# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
507 Assert(!pTlbe->pMap || RT_VALID_PTR(pTlbe->pMap->pv));
508# endif
509 }
510 else
511 rc = pgmPhysPageLoadIntoTlbWithPage(pVM, pPage, GCPhys);
512 *ppTlbe = pTlbe;
513 return rc;
514}
515
516#endif /* !IN_RC */
517
518/**
519 * Enables write monitoring for an allocated page.
520 *
521 * The caller is responsible for updating the shadow page tables.
522 *
523 * @param pVM The cross context VM structure.
524 * @param pPage The page to write monitor.
525 * @param GCPhysPage The address of the page.
526 */
527DECLINLINE(void) pgmPhysPageWriteMonitor(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhysPage)
528{
529 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED);
530 PGM_LOCK_ASSERT_OWNER(pVM);
531
532 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_WRITE_MONITORED);
533 pVM->pgm.s.cMonitoredPages++;
534
535 /* Large pages must disabled. */
536 if (PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE)
537 {
538 PPGMPAGE pFirstPage = pgmPhysGetPage(pVM, GCPhysPage & X86_PDE2M_PAE_PG_MASK);
539 AssertFatal(pFirstPage);
540 if (PGM_PAGE_GET_PDE_TYPE(pFirstPage) == PGM_PAGE_PDE_TYPE_PDE)
541 {
542 PGM_PAGE_SET_PDE_TYPE(pVM, pFirstPage, PGM_PAGE_PDE_TYPE_PDE_DISABLED);
543 pVM->pgm.s.cLargePagesDisabled++;
544 }
545 else
546 Assert(PGM_PAGE_GET_PDE_TYPE(pFirstPage) == PGM_PAGE_PDE_TYPE_PDE_DISABLED);
547 }
548}
549
550
551/**
552 * Checks if the no-execute (NX) feature is active (EFER.NXE=1).
553 *
554 * Only used when the guest is in PAE or long mode. This is inlined so that we
555 * can perform consistency checks in debug builds.
556 *
557 * @returns true if it is, false if it isn't.
558 * @param pVCpu The cross context virtual CPU structure.
559 */
560DECL_FORCE_INLINE(bool) pgmGstIsNoExecuteActive(PVMCPU pVCpu)
561{
562 Assert(pVCpu->pgm.s.fNoExecuteEnabled == CPUMIsGuestNXEnabled(pVCpu));
563 Assert(CPUMIsGuestInPAEMode(pVCpu) || CPUMIsGuestInLongMode(pVCpu));
564 return pVCpu->pgm.s.fNoExecuteEnabled;
565}
566
567
568/**
569 * Checks if the page size extension (PSE) is currently enabled (CR4.PSE=1).
570 *
571 * Only used when the guest is in paged 32-bit mode. This is inlined so that
572 * we can perform consistency checks in debug builds.
573 *
574 * @returns true if it is, false if it isn't.
575 * @param pVCpu The cross context virtual CPU structure.
576 */
577DECL_FORCE_INLINE(bool) pgmGst32BitIsPageSizeExtActive(PVMCPU pVCpu)
578{
579 Assert(pVCpu->pgm.s.fGst32BitPageSizeExtension == CPUMIsGuestPageSizeExtEnabled(pVCpu));
580 Assert(!CPUMIsGuestInPAEMode(pVCpu));
581 Assert(!CPUMIsGuestInLongMode(pVCpu));
582 return pVCpu->pgm.s.fGst32BitPageSizeExtension;
583}
584
585
586/**
587 * Calculated the guest physical address of the large (4 MB) page in 32 bits paging mode.
588 * Takes PSE-36 into account.
589 *
590 * @returns guest physical address
591 * @param pVM The cross context VM structure.
592 * @param Pde Guest Pde
593 */
594DECLINLINE(RTGCPHYS) pgmGstGet4MBPhysPage(PVM pVM, X86PDE Pde)
595{
596 RTGCPHYS GCPhys = Pde.u & X86_PDE4M_PG_MASK;
597 GCPhys |= (RTGCPHYS)Pde.b.u8PageNoHigh << 32;
598
599 return GCPhys & pVM->pgm.s.GCPhys4MBPSEMask;
600}
601
602
603/**
604 * Gets the address the guest page directory (32-bit paging).
605 *
606 * @returns VBox status code.
607 * @param pVCpu The cross context virtual CPU structure.
608 * @param ppPd Where to return the mapping. This is always set.
609 */
610DECLINLINE(int) pgmGstGet32bitPDPtrEx(PVMCPU pVCpu, PX86PD *ppPd)
611{
612#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
613 int rc = pgmRZDynMapGCPageInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)ppPd RTLOG_COMMA_SRC_POS);
614 if (RT_FAILURE(rc))
615 {
616 *ppPd = NULL;
617 return rc;
618 }
619#else
620 *ppPd = pVCpu->pgm.s.CTX_SUFF(pGst32BitPd);
621 if (RT_UNLIKELY(!*ppPd))
622 return pgmGstLazyMap32BitPD(pVCpu, ppPd);
623#endif
624 return VINF_SUCCESS;
625}
626
627
628/**
629 * Gets the address the guest page directory (32-bit paging).
630 *
631 * @returns Pointer to the page directory entry in question.
632 * @param pVCpu The cross context virtual CPU structure.
633 */
634DECLINLINE(PX86PD) pgmGstGet32bitPDPtr(PVMCPU pVCpu)
635{
636#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
637 PX86PD pGuestPD = NULL;
638 int rc = pgmRZDynMapGCPageInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)&pGuestPD RTLOG_COMMA_SRC_POS);
639 if (RT_FAILURE(rc))
640 {
641 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
642 return NULL;
643 }
644#else
645 PX86PD pGuestPD = pVCpu->pgm.s.CTX_SUFF(pGst32BitPd);
646 if (RT_UNLIKELY(!pGuestPD))
647 {
648 int rc = pgmGstLazyMap32BitPD(pVCpu, &pGuestPD);
649 if (RT_FAILURE(rc))
650 return NULL;
651 }
652#endif
653 return pGuestPD;
654}
655
656
657/**
658 * Gets the guest page directory pointer table.
659 *
660 * @returns VBox status code.
661 * @param pVCpu The cross context virtual CPU structure.
662 * @param ppPdpt Where to return the mapping. This is always set.
663 */
664DECLINLINE(int) pgmGstGetPaePDPTPtrEx(PVMCPU pVCpu, PX86PDPT *ppPdpt)
665{
666#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
667 int rc = pgmRZDynMapGCPageOffInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)ppPdpt RTLOG_COMMA_SRC_POS);
668 if (RT_FAILURE(rc))
669 {
670 *ppPdpt = NULL;
671 return rc;
672 }
673#else
674 *ppPdpt = pVCpu->pgm.s.CTX_SUFF(pGstPaePdpt);
675 if (RT_UNLIKELY(!*ppPdpt))
676 return pgmGstLazyMapPaePDPT(pVCpu, ppPdpt);
677#endif
678 return VINF_SUCCESS;
679}
680
681
682/**
683 * Gets the guest page directory pointer table.
684 *
685 * @returns Pointer to the page directory in question.
686 * @returns NULL if the page directory is not present or on an invalid page.
687 * @param pVCpu The cross context virtual CPU structure.
688 */
689DECLINLINE(PX86PDPT) pgmGstGetPaePDPTPtr(PVMCPU pVCpu)
690{
691 PX86PDPT pGuestPdpt;
692 int rc = pgmGstGetPaePDPTPtrEx(pVCpu, &pGuestPdpt);
693 AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc);
694 return pGuestPdpt;
695}
696
697
698/**
699 * Gets the guest page directory pointer table entry for the specified address.
700 *
701 * @returns Pointer to the page directory in question.
702 * @returns NULL if the page directory is not present or on an invalid page.
703 * @param pVCpu The cross context virtual CPU structure.
704 * @param GCPtr The address.
705 */
706DECLINLINE(PX86PDPE) pgmGstGetPaePDPEPtr(PVMCPU pVCpu, RTGCPTR GCPtr)
707{
708 AssertGCPtr32(GCPtr);
709
710#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
711 PX86PDPT pGuestPDPT = NULL;
712 int rc = pgmRZDynMapGCPageOffInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)&pGuestPDPT RTLOG_COMMA_SRC_POS);
713 AssertRCReturn(rc, NULL);
714#else
715 PX86PDPT pGuestPDPT = pVCpu->pgm.s.CTX_SUFF(pGstPaePdpt);
716 if (RT_UNLIKELY(!pGuestPDPT))
717 {
718 int rc = pgmGstLazyMapPaePDPT(pVCpu, &pGuestPDPT);
719 if (RT_FAILURE(rc))
720 return NULL;
721 }
722#endif
723 return &pGuestPDPT->a[(uint32_t)GCPtr >> X86_PDPT_SHIFT];
724}
725
726
727/**
728 * Gets the page directory entry for the specified address.
729 *
730 * @returns The page directory entry in question.
731 * @returns A non-present entry if the page directory is not present or on an invalid page.
732 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
733 * @param GCPtr The address.
734 */
735DECLINLINE(X86PDEPAE) pgmGstGetPaePDE(PVMCPU pVCpu, RTGCPTR GCPtr)
736{
737 AssertGCPtr32(GCPtr);
738 PX86PDPT pGuestPDPT = pgmGstGetPaePDPTPtr(pVCpu);
739 if (RT_LIKELY(pGuestPDPT))
740 {
741 const unsigned iPdpt = (uint32_t)GCPtr >> X86_PDPT_SHIFT;
742 if ( pGuestPDPT->a[iPdpt].n.u1Present
743 && !(pGuestPDPT->a[iPdpt].u & pVCpu->pgm.s.fGstPaeMbzPdpeMask) )
744 {
745 const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
746#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
747 PX86PDPAE pGuestPD = NULL;
748 int rc = pgmRZDynMapGCPageInlined(pVCpu,
749 pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK,
750 (void **)&pGuestPD
751 RTLOG_COMMA_SRC_POS);
752 if (RT_SUCCESS(rc))
753 return pGuestPD->a[iPD];
754 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
755#else
756 PX86PDPAE pGuestPD = pVCpu->pgm.s.CTX_SUFF(apGstPaePDs)[iPdpt];
757 if ( !pGuestPD
758 || (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt])
759 pgmGstLazyMapPaePD(pVCpu, iPdpt, &pGuestPD);
760 if (pGuestPD)
761 return pGuestPD->a[iPD];
762#endif
763 }
764 }
765
766 X86PDEPAE ZeroPde = {0};
767 return ZeroPde;
768}
769
770
771/**
772 * Gets the page directory pointer table entry for the specified address
773 * and returns the index into the page directory
774 *
775 * @returns Pointer to the page directory in question.
776 * @returns NULL if the page directory is not present or on an invalid page.
777 * @param pVCpu The cross context virtual CPU structure.
778 * @param GCPtr The address.
779 * @param piPD Receives the index into the returned page directory
780 * @param pPdpe Receives the page directory pointer entry. Optional.
781 */
782DECLINLINE(PX86PDPAE) pgmGstGetPaePDPtr(PVMCPU pVCpu, RTGCPTR GCPtr, unsigned *piPD, PX86PDPE pPdpe)
783{
784 AssertGCPtr32(GCPtr);
785
786 /* The PDPE. */
787 PX86PDPT pGuestPDPT = pgmGstGetPaePDPTPtr(pVCpu);
788 if (RT_UNLIKELY(!pGuestPDPT))
789 return NULL;
790 const unsigned iPdpt = (uint32_t)GCPtr >> X86_PDPT_SHIFT;
791 if (pPdpe)
792 *pPdpe = pGuestPDPT->a[iPdpt];
793 if (!pGuestPDPT->a[iPdpt].n.u1Present)
794 return NULL;
795 if (RT_UNLIKELY(pVCpu->pgm.s.fGstPaeMbzPdpeMask & pGuestPDPT->a[iPdpt].u))
796 return NULL;
797
798 /* The PDE. */
799#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
800 PX86PDPAE pGuestPD = NULL;
801 int rc = pgmRZDynMapGCPageInlined(pVCpu,
802 pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK,
803 (void **)&pGuestPD
804 RTLOG_COMMA_SRC_POS);
805 if (RT_FAILURE(rc))
806 {
807 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
808 return NULL;
809 }
810#else
811 PX86PDPAE pGuestPD = pVCpu->pgm.s.CTX_SUFF(apGstPaePDs)[iPdpt];
812 if ( !pGuestPD
813 || (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt])
814 pgmGstLazyMapPaePD(pVCpu, iPdpt, &pGuestPD);
815#endif
816
817 *piPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
818 return pGuestPD;
819}
820
821#ifndef IN_RC
822
823/**
824 * Gets the page map level-4 pointer for the guest.
825 *
826 * @returns VBox status code.
827 * @param pVCpu The cross context virtual CPU structure.
828 * @param ppPml4 Where to return the mapping. Always set.
829 */
830DECLINLINE(int) pgmGstGetLongModePML4PtrEx(PVMCPU pVCpu, PX86PML4 *ppPml4)
831{
832#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
833 int rc = pgmRZDynMapGCPageInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)ppPml4 RTLOG_COMMA_SRC_POS);
834 if (RT_FAILURE(rc))
835 {
836 *ppPml4 = NULL;
837 return rc;
838 }
839#else
840 *ppPml4 = pVCpu->pgm.s.CTX_SUFF(pGstAmd64Pml4);
841 if (RT_UNLIKELY(!*ppPml4))
842 return pgmGstLazyMapPml4(pVCpu, ppPml4);
843#endif
844 return VINF_SUCCESS;
845}
846
847
848/**
849 * Gets the page map level-4 pointer for the guest.
850 *
851 * @returns Pointer to the PML4 page.
852 * @param pVCpu The cross context virtual CPU structure.
853 */
854DECLINLINE(PX86PML4) pgmGstGetLongModePML4Ptr(PVMCPU pVCpu)
855{
856 PX86PML4 pGuestPml4;
857 int rc = pgmGstGetLongModePML4PtrEx(pVCpu, &pGuestPml4);
858 AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc);
859 return pGuestPml4;
860}
861
862
863/**
864 * Gets the pointer to a page map level-4 entry.
865 *
866 * @returns Pointer to the PML4 entry.
867 * @param pVCpu The cross context virtual CPU structure.
868 * @param iPml4 The index.
869 * @remarks Only used by AssertCR3.
870 */
871DECLINLINE(PX86PML4E) pgmGstGetLongModePML4EPtr(PVMCPU pVCpu, unsigned int iPml4)
872{
873#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
874 PX86PML4 pGuestPml4;
875 int rc = pgmRZDynMapGCPageInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)&pGuestPml4 RTLOG_COMMA_SRC_POS);
876 AssertRCReturn(rc, NULL);
877#else
878 PX86PML4 pGuestPml4 = pVCpu->pgm.s.CTX_SUFF(pGstAmd64Pml4);
879 if (RT_UNLIKELY(!pGuestPml4))
880 {
881 int rc = pgmGstLazyMapPml4(pVCpu, &pGuestPml4);
882 AssertRCReturn(rc, NULL);
883 }
884#endif
885 return &pGuestPml4->a[iPml4];
886}
887
888
889/**
890 * Gets the page directory entry for the specified address.
891 *
892 * @returns The page directory entry in question.
893 * @returns A non-present entry if the page directory is not present or on an invalid page.
894 * @param pVCpu The cross context virtual CPU structure.
895 * @param GCPtr The address.
896 */
897DECLINLINE(X86PDEPAE) pgmGstGetLongModePDE(PVMCPU pVCpu, RTGCPTR64 GCPtr)
898{
899 /*
900 * Note! To keep things simple, ASSUME invalid physical addresses will
901 * cause X86_TRAP_PF_RSVD. This isn't a problem until we start
902 * supporting 52-bit wide physical guest addresses.
903 */
904 PCX86PML4 pGuestPml4 = pgmGstGetLongModePML4Ptr(pVCpu);
905 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
906 if ( RT_LIKELY(pGuestPml4)
907 && pGuestPml4->a[iPml4].n.u1Present
908 && !(pGuestPml4->a[iPml4].u & pVCpu->pgm.s.fGstAmd64MbzPml4eMask) )
909 {
910 PCX86PDPT pPdptTemp;
911 int rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, pGuestPml4->a[iPml4].u & X86_PML4E_PG_MASK, &pPdptTemp);
912 if (RT_SUCCESS(rc))
913 {
914 const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
915 if ( pPdptTemp->a[iPdpt].n.u1Present
916 && !(pPdptTemp->a[iPdpt].u & pVCpu->pgm.s.fGstAmd64MbzPdpeMask) )
917 {
918 PCX86PDPAE pPD;
919 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
920 if (RT_SUCCESS(rc))
921 {
922 const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
923 return pPD->a[iPD];
924 }
925 }
926 }
927 AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
928 }
929
930 X86PDEPAE ZeroPde = {0};
931 return ZeroPde;
932}
933
934
935/**
936 * Gets the GUEST page directory pointer for the specified address.
937 *
938 * @returns The page directory in question.
939 * @returns NULL if the page directory is not present or on an invalid page.
940 * @param pVCpu The cross context virtual CPU structure.
941 * @param GCPtr The address.
942 * @param ppPml4e Page Map Level-4 Entry (out)
943 * @param pPdpe Page directory pointer table entry (out)
944 * @param piPD Receives the index into the returned page directory
945 */
946DECLINLINE(PX86PDPAE) pgmGstGetLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPE pPdpe, unsigned *piPD)
947{
948 /* The PMLE4. */
949 PX86PML4 pGuestPml4 = pgmGstGetLongModePML4Ptr(pVCpu);
950 if (RT_UNLIKELY(!pGuestPml4))
951 return NULL;
952 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
953 PCX86PML4E pPml4e = *ppPml4e = &pGuestPml4->a[iPml4];
954 if (!pPml4e->n.u1Present)
955 return NULL;
956 if (RT_UNLIKELY(pPml4e->u & pVCpu->pgm.s.fGstAmd64MbzPml4eMask))
957 return NULL;
958
959 /* The PDPE. */
960 PCX86PDPT pPdptTemp;
961 int rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, pPml4e->u & X86_PML4E_PG_MASK, &pPdptTemp);
962 if (RT_FAILURE(rc))
963 {
964 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
965 return NULL;
966 }
967 const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
968 *pPdpe = pPdptTemp->a[iPdpt];
969 if (!pPdpe->n.u1Present)
970 return NULL;
971 if (RT_UNLIKELY(pPdpe->u & pVCpu->pgm.s.fGstAmd64MbzPdpeMask))
972 return NULL;
973
974 /* The PDE. */
975 PX86PDPAE pPD;
976 rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
977 if (RT_FAILURE(rc))
978 {
979 AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
980 return NULL;
981 }
982
983 *piPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
984 return pPD;
985}
986
987#endif /* !IN_RC */
988
989/**
990 * Gets the shadow page directory, 32-bit.
991 *
992 * @returns Pointer to the shadow 32-bit PD.
993 * @param pVCpu The cross context virtual CPU structure.
994 */
995DECLINLINE(PX86PD) pgmShwGet32BitPDPtr(PVMCPU pVCpu)
996{
997 return (PX86PD)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
998}
999
1000
1001/**
1002 * Gets the shadow page directory entry for the specified address, 32-bit.
1003 *
1004 * @returns Shadow 32-bit PDE.
1005 * @param pVCpu The cross context virtual CPU structure.
1006 * @param GCPtr The address.
1007 */
1008DECLINLINE(X86PDE) pgmShwGet32BitPDE(PVMCPU pVCpu, RTGCPTR GCPtr)
1009{
1010 PX86PD pShwPde = pgmShwGet32BitPDPtr(pVCpu);
1011 if (!pShwPde)
1012 {
1013 X86PDE ZeroPde = {0};
1014 return ZeroPde;
1015 }
1016 return pShwPde->a[(uint32_t)GCPtr >> X86_PD_SHIFT];
1017}
1018
1019
1020/**
1021 * Gets the pointer to the shadow page directory entry for the specified
1022 * address, 32-bit.
1023 *
1024 * @returns Pointer to the shadow 32-bit PDE.
1025 * @param pVCpu The cross context virtual CPU structure.
1026 * @param GCPtr The address.
1027 */
1028DECLINLINE(PX86PDE) pgmShwGet32BitPDEPtr(PVMCPU pVCpu, RTGCPTR GCPtr)
1029{
1030 PX86PD pPde = pgmShwGet32BitPDPtr(pVCpu);
1031 AssertReturn(pPde, NULL);
1032 return &pPde->a[(uint32_t)GCPtr >> X86_PD_SHIFT];
1033}
1034
1035
1036/**
1037 * Gets the shadow page pointer table, PAE.
1038 *
1039 * @returns Pointer to the shadow PAE PDPT.
1040 * @param pVCpu The cross context virtual CPU structure.
1041 */
1042DECLINLINE(PX86PDPT) pgmShwGetPaePDPTPtr(PVMCPU pVCpu)
1043{
1044 return (PX86PDPT)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
1045}
1046
1047
1048/**
1049 * Gets the shadow page directory for the specified address, PAE.
1050 *
1051 * @returns Pointer to the shadow PD.
1052 * @param pVCpu The cross context virtual CPU structure.
1053 * @param GCPtr The address.
1054 */
1055DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PVMCPU pVCpu, RTGCPTR GCPtr)
1056{
1057 const unsigned iPdpt = (uint32_t)GCPtr >> X86_PDPT_SHIFT;
1058 PX86PDPT pPdpt = pgmShwGetPaePDPTPtr(pVCpu);
1059
1060 if (!pPdpt->a[iPdpt].n.u1Present)
1061 return NULL;
1062
1063 /* Fetch the pgm pool shadow descriptor. */
1064 PVM pVM = pVCpu->CTX_SUFF(pVM);
1065 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pVM->pgm.s.CTX_SUFF(pPool), pPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
1066 AssertReturn(pShwPde, NULL);
1067
1068 return (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPde);
1069}
1070
1071
1072/**
1073 * Gets the shadow page directory for the specified address, PAE.
1074 *
1075 * @returns Pointer to the shadow PD.
1076 * @param pVCpu The cross context virtual CPU structure.
1077 * @param pPdpt Pointer to the page directory pointer table.
1078 * @param GCPtr The address.
1079 */
1080DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PVMCPU pVCpu, PX86PDPT pPdpt, RTGCPTR GCPtr)
1081{
1082 const unsigned iPdpt = (uint32_t)GCPtr >> X86_PDPT_SHIFT;
1083
1084 if (!pPdpt->a[iPdpt].n.u1Present)
1085 return NULL;
1086
1087 /* Fetch the pgm pool shadow descriptor. */
1088 PVM pVM = pVCpu->CTX_SUFF(pVM);
1089 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pVM->pgm.s.CTX_SUFF(pPool), pPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
1090 AssertReturn(pShwPde, NULL);
1091
1092 return (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPde);
1093}
1094
1095
1096/**
1097 * Gets the shadow page directory entry, PAE.
1098 *
1099 * @returns PDE.
1100 * @param pVCpu The cross context virtual CPU structure.
1101 * @param GCPtr The address.
1102 */
1103DECLINLINE(X86PDEPAE) pgmShwGetPaePDE(PVMCPU pVCpu, RTGCPTR GCPtr)
1104{
1105 const unsigned iPd = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
1106
1107 PX86PDPAE pShwPde = pgmShwGetPaePDPtr(pVCpu, GCPtr);
1108 if (!pShwPde)
1109 {
1110 X86PDEPAE ZeroPde = {0};
1111 return ZeroPde;
1112 }
1113 return pShwPde->a[iPd];
1114}
1115
1116
1117/**
1118 * Gets the pointer to the shadow page directory entry for an address, PAE.
1119 *
1120 * @returns Pointer to the PDE.
1121 * @param pVCpu The cross context virtual CPU structure.
1122 * @param GCPtr The address.
1123 * @remarks Only used by AssertCR3.
1124 */
1125DECLINLINE(PX86PDEPAE) pgmShwGetPaePDEPtr(PVMCPU pVCpu, RTGCPTR GCPtr)
1126{
1127 const unsigned iPd = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
1128
1129 PX86PDPAE pPde = pgmShwGetPaePDPtr(pVCpu, GCPtr);
1130 AssertReturn(pPde, NULL);
1131 return &pPde->a[iPd];
1132}
1133
1134#ifndef IN_RC
1135
1136/**
1137 * Gets the shadow page map level-4 pointer.
1138 *
1139 * @returns Pointer to the shadow PML4.
1140 * @param pVCpu The cross context virtual CPU structure.
1141 */
1142DECLINLINE(PX86PML4) pgmShwGetLongModePML4Ptr(PVMCPU pVCpu)
1143{
1144 return (PX86PML4)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
1145}
1146
1147
1148/**
1149 * Gets the shadow page map level-4 entry for the specified address.
1150 *
1151 * @returns The entry.
1152 * @param pVCpu The cross context virtual CPU structure.
1153 * @param GCPtr The address.
1154 */
1155DECLINLINE(X86PML4E) pgmShwGetLongModePML4E(PVMCPU pVCpu, RTGCPTR GCPtr)
1156{
1157 const unsigned iPml4 = ((RTGCUINTPTR64)GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1158 PX86PML4 pShwPml4 = pgmShwGetLongModePML4Ptr(pVCpu);
1159
1160 if (!pShwPml4)
1161 {
1162 X86PML4E ZeroPml4e = {0};
1163 return ZeroPml4e;
1164 }
1165 return pShwPml4->a[iPml4];
1166}
1167
1168
1169/**
1170 * Gets the pointer to the specified shadow page map level-4 entry.
1171 *
1172 * @returns The entry.
1173 * @param pVCpu The cross context virtual CPU structure.
1174 * @param iPml4 The PML4 index.
1175 */
1176DECLINLINE(PX86PML4E) pgmShwGetLongModePML4EPtr(PVMCPU pVCpu, unsigned int iPml4)
1177{
1178 PX86PML4 pShwPml4 = pgmShwGetLongModePML4Ptr(pVCpu);
1179 if (!pShwPml4)
1180 return NULL;
1181 return &pShwPml4->a[iPml4];
1182}
1183
1184#endif /* !IN_RC */
1185
1186/**
1187 * Cached physical handler lookup.
1188 *
1189 * @returns Physical handler covering @a GCPhys.
1190 * @param pVM The cross context VM structure.
1191 * @param GCPhys The lookup address.
1192 */
1193DECLINLINE(PPGMPHYSHANDLER) pgmHandlerPhysicalLookup(PVM pVM, RTGCPHYS GCPhys)
1194{
1195 PPGMPHYSHANDLER pHandler = pVM->pgm.s.CTX_SUFF(pLastPhysHandler);
1196 if ( pHandler
1197 && GCPhys >= pHandler->Core.Key
1198 && GCPhys < pHandler->Core.KeyLast)
1199 {
1200 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PhysHandlerLookupHits));
1201 return pHandler;
1202 }
1203
1204 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PhysHandlerLookupMisses));
1205 pHandler = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
1206 if (pHandler)
1207 pVM->pgm.s.CTX_SUFF(pLastPhysHandler) = pHandler;
1208 return pHandler;
1209}
1210
1211
1212#ifdef VBOX_WITH_RAW_MODE
1213/**
1214 * Clears one physical page of a virtual handler.
1215 *
1216 * @param pVM The cross context VM structure.
1217 * @param pCur Virtual handler structure.
1218 * @param iPage Physical page index.
1219 *
1220 * @remark Only used when PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL is being set, so no
1221 * need to care about other handlers in the same page.
1222 */
1223DECLINLINE(void) pgmHandlerVirtualClearPage(PVM pVM, PPGMVIRTHANDLER pCur, unsigned iPage)
1224{
1225 const PPGMPHYS2VIRTHANDLER pPhys2Virt = &pCur->aPhysToVirt[iPage];
1226
1227 /*
1228 * Remove the node from the tree (it's supposed to be in the tree if we get here!).
1229 */
1230# ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1231 AssertReleaseMsg(pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE,
1232 ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
1233 pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias));
1234# endif
1235 if (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_IS_HEAD)
1236 {
1237 /* We're the head of the alias chain. */
1238 PPGMPHYS2VIRTHANDLER pRemove = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key); NOREF(pRemove);
1239# ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1240 AssertReleaseMsg(pRemove != NULL,
1241 ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
1242 pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias));
1243 AssertReleaseMsg(pRemove == pPhys2Virt,
1244 ("wanted: pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n"
1245 " got: pRemove=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
1246 pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias,
1247 pRemove, pRemove->Core.Key, pRemove->Core.KeyLast, pRemove->offVirtHandler, pRemove->offNextAlias));
1248# endif
1249 if (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK)
1250 {
1251 /* Insert the next list in the alias chain into the tree. */
1252 PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
1253# ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1254 AssertReleaseMsg(pNext->offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE,
1255 ("pNext=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
1256 pNext, pNext->Core.Key, pNext->Core.KeyLast, pNext->offVirtHandler, pNext->offNextAlias));
1257# endif
1258 pNext->offNextAlias |= PGMPHYS2VIRTHANDLER_IS_HEAD;
1259 bool fRc = RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, &pNext->Core);
1260 AssertRelease(fRc);
1261 }
1262 }
1263 else
1264 {
1265 /* Locate the previous node in the alias chain. */
1266 PPGMPHYS2VIRTHANDLER pPrev = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key);
1267# ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1268 AssertReleaseMsg(pPrev != pPhys2Virt,
1269 ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} pPrev=%p\n",
1270 pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias, pPrev));
1271# endif
1272 for (;;)
1273 {
1274 PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPrev + (pPrev->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
1275 if (pNext == pPhys2Virt)
1276 {
1277 /* unlink. */
1278 LogFlow(("pgmHandlerVirtualClearPage: removed %p:{.offNextAlias=%#RX32} from alias chain. prev %p:{.offNextAlias=%#RX32} [%RGp-%RGp]\n",
1279 pPhys2Virt, pPhys2Virt->offNextAlias, pPrev, pPrev->offNextAlias, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast));
1280 if (!(pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK))
1281 pPrev->offNextAlias &= ~PGMPHYS2VIRTHANDLER_OFF_MASK;
1282 else
1283 {
1284 PPGMPHYS2VIRTHANDLER pNewNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
1285 pPrev->offNextAlias = ((intptr_t)pNewNext - (intptr_t)pPrev)
1286 | (pPrev->offNextAlias & ~PGMPHYS2VIRTHANDLER_OFF_MASK);
1287 }
1288 break;
1289 }
1290
1291 /* next */
1292 if (pNext == pPrev)
1293 {
1294# ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1295 AssertReleaseMsg(pNext != pPrev,
1296 ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} pPrev=%p\n",
1297 pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias, pPrev));
1298# endif
1299 break;
1300 }
1301 pPrev = pNext;
1302 }
1303 }
1304 Log2(("PHYS2VIRT: Removing %RGp-%RGp %#RX32 %s\n",
1305 pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias, R3STRING(pCur->pszDesc)));
1306 pPhys2Virt->offNextAlias = 0;
1307 pPhys2Virt->Core.KeyLast = NIL_RTGCPHYS; /* require reinsert */
1308
1309 /*
1310 * Clear the ram flags for this page.
1311 */
1312 PPGMPAGE pPage = pgmPhysGetPage(pVM, pPhys2Virt->Core.Key);
1313 AssertReturnVoid(pPage);
1314 PGM_PAGE_SET_HNDL_VIRT_STATE(pPage, PGM_PAGE_HNDL_VIRT_STATE_NONE);
1315}
1316#endif /* VBOX_WITH_RAW_MODE */
1317
1318
1319/**
1320 * Internal worker for finding a 'in-use' shadow page give by it's physical address.
1321 *
1322 * @returns Pointer to the shadow page structure.
1323 * @param pPool The pool.
1324 * @param idx The pool page index.
1325 */
1326DECLINLINE(PPGMPOOLPAGE) pgmPoolGetPageByIdx(PPGMPOOL pPool, unsigned idx)
1327{
1328 AssertFatalMsg(idx >= PGMPOOL_IDX_FIRST && idx < pPool->cCurPages, ("idx=%d\n", idx));
1329 return &pPool->aPages[idx];
1330}
1331
1332
1333/**
1334 * Clear references to guest physical memory.
1335 *
1336 * @param pPool The pool.
1337 * @param pPoolPage The pool page.
1338 * @param pPhysPage The physical guest page tracking structure.
1339 * @param iPte Shadow PTE index
1340 */
1341DECLINLINE(void) pgmTrackDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPoolPage, PPGMPAGE pPhysPage, uint16_t iPte)
1342{
1343 /*
1344 * Just deal with the simple case here.
1345 */
1346# ifdef VBOX_STRICT
1347 PVM pVM = pPool->CTX_SUFF(pVM); NOREF(pVM);
1348# endif
1349# ifdef LOG_ENABLED
1350 const unsigned uOrg = PGM_PAGE_GET_TRACKING(pPhysPage);
1351# endif
1352 const unsigned cRefs = PGM_PAGE_GET_TD_CREFS(pPhysPage);
1353 if (cRefs == 1)
1354 {
1355 Assert(pPoolPage->idx == PGM_PAGE_GET_TD_IDX(pPhysPage));
1356 Assert(iPte == PGM_PAGE_GET_PTE_INDEX(pPhysPage));
1357 /* Invalidate the tracking data. */
1358 PGM_PAGE_SET_TRACKING(pVM, pPhysPage, 0);
1359 }
1360 else
1361 pgmPoolTrackPhysExtDerefGCPhys(pPool, pPoolPage, pPhysPage, iPte);
1362 Log2(("pgmTrackDerefGCPhys: %x -> %x pPhysPage=%R[pgmpage]\n", uOrg, PGM_PAGE_GET_TRACKING(pPhysPage), pPhysPage ));
1363}
1364
1365
1366/**
1367 * Moves the page to the head of the age list.
1368 *
1369 * This is done when the cached page is used in one way or another.
1370 *
1371 * @param pPool The pool.
1372 * @param pPage The cached page.
1373 */
1374DECLINLINE(void) pgmPoolCacheUsed(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1375{
1376 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM));
1377
1378 /*
1379 * Move to the head of the age list.
1380 */
1381 if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
1382 {
1383 /* unlink */
1384 pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
1385 if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
1386 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
1387 else
1388 pPool->iAgeTail = pPage->iAgePrev;
1389
1390 /* insert at head */
1391 pPage->iAgePrev = NIL_PGMPOOL_IDX;
1392 pPage->iAgeNext = pPool->iAgeHead;
1393 Assert(pPage->iAgeNext != NIL_PGMPOOL_IDX); /* we would've already been head then */
1394 pPool->iAgeHead = pPage->idx;
1395 pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->idx;
1396 }
1397}
1398
1399
1400/**
1401 * Locks a page to prevent flushing (important for cr3 root pages or shadow pae pd pages).
1402 *
1403 * @param pPool The pool.
1404 * @param pPage PGM pool page
1405 */
1406DECLINLINE(void) pgmPoolLockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1407{
1408 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM)); NOREF(pPool);
1409 ASMAtomicIncU32(&pPage->cLocked);
1410}
1411
1412
1413/**
1414 * Unlocks a page to allow flushing again
1415 *
1416 * @param pPool The pool.
1417 * @param pPage PGM pool page
1418 */
1419DECLINLINE(void) pgmPoolUnlockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1420{
1421 PGM_LOCK_ASSERT_OWNER(pPool->CTX_SUFF(pVM)); NOREF(pPool);
1422 Assert(pPage->cLocked);
1423 ASMAtomicDecU32(&pPage->cLocked);
1424}
1425
1426
1427/**
1428 * Checks if the page is locked (e.g. the active CR3 or one of the four PDs of a PAE PDPT)
1429 *
1430 * @returns VBox status code.
1431 * @param pPage PGM pool page
1432 */
1433DECLINLINE(bool) pgmPoolIsPageLocked(PPGMPOOLPAGE pPage)
1434{
1435 if (pPage->cLocked)
1436 {
1437 LogFlow(("pgmPoolIsPageLocked found root page %d\n", pPage->enmKind));
1438 if (pPage->cModifications)
1439 pPage->cModifications = 1; /* reset counter (can't use 0, or else it will be reinserted in the modified list) */
1440 return true;
1441 }
1442 return false;
1443}
1444
1445
1446/**
1447 * Tells if mappings are to be put into the shadow page table or not.
1448 *
1449 * @returns boolean result
1450 * @param pVM The cross context VM structure.
1451 */
1452DECL_FORCE_INLINE(bool) pgmMapAreMappingsEnabled(PVM pVM)
1453{
1454#ifdef PGM_WITHOUT_MAPPINGS
1455 /* Only raw-mode has mappings. */
1456 Assert(!VM_IS_RAW_MODE_ENABLED(pVM)); NOREF(pVM);
1457 return false;
1458#else
1459 Assert(pVM->cCpus == 1 || !VM_IS_RAW_MODE_ENABLED(pVM));
1460 return VM_IS_RAW_MODE_ENABLED(pVM);
1461#endif
1462}
1463
1464
1465/**
1466 * Checks if the mappings are floating and enabled.
1467 *
1468 * @returns true / false.
1469 * @param pVM The cross context VM structure.
1470 */
1471DECL_FORCE_INLINE(bool) pgmMapAreMappingsFloating(PVM pVM)
1472{
1473#ifdef PGM_WITHOUT_MAPPINGS
1474 /* Only raw-mode has mappings. */
1475 Assert(!VM_IS_RAW_MODE_ENABLED(pVM)); NOREF(pVM);
1476 return false;
1477#else
1478 return !pVM->pgm.s.fMappingsFixed
1479 && pgmMapAreMappingsEnabled(pVM);
1480#endif
1481}
1482
1483/** @} */
1484
1485#endif
1486
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