VirtualBox

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

Last change on this file since 30934 was 30895, checked in by vboxsync, 14 years ago

build fixes.

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