~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/VMM/include/PGMInline.h

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: PGMInline.h 35346 2010-12-27 16:13:13Z 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/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/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
 */
 
62
DECLINLINE(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
 */
 
92
DECLINLINE(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
 */
 
126
DECLINLINE(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
 */
 
168
DECLINLINE(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
 */
 
207
DECLINLINE(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
 */
 
240
DECLINLINE(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
 */
 
278
DECLINLINE(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
#if defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) || defined(IN_RC)
 
289
 
 
290
/**
 
291
 * Inlined version of the ring-0 version of the host page mapping code
 
292
 * that optimizes access to pages already in the set.
 
293
 *
 
294
 * @returns VINF_SUCCESS. Will bail out to ring-3 on failure.
 
295
 * @param   pVCpu       The current CPU.
 
296
 * @param   HCPhys      The physical address of the page.
 
297
 * @param   ppv         Where to store the mapping address.
 
298
 */
 
299
DECLINLINE(int) pgmRZDynMapHCPageInlined(PVMCPU pVCpu, RTHCPHYS HCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
 
300
{
 
301
    PPGMMAPSET  pSet    = &pVCpu->pgm.s.AutoSet;
 
302
 
 
303
    STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapHCPageInl, a);
 
304
    Assert(!(HCPhys & PAGE_OFFSET_MASK));
 
305
    Assert(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries));
 
306
 
 
307
    unsigned    iHash   = PGMMAPSET_HASH(HCPhys);
 
308
    unsigned    iEntry  = pSet->aiHashTable[iHash];
 
309
    if (    iEntry < pSet->cEntries
 
310
        &&  pSet->aEntries[iEntry].HCPhys == HCPhys
 
311
        &&  pSet->aEntries[iEntry].cInlinedRefs < UINT16_MAX - 1)
 
312
    {
 
313
        pSet->aEntries[iEntry].cInlinedRefs++;
 
314
        *ppv = pSet->aEntries[iEntry].pvPage;
 
315
        STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapHCPageInlHits);
 
316
    }
 
317
    else
 
318
    {
 
319
        STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapHCPageInlMisses);
 
320
        pgmRZDynMapHCPageCommon(pSet, HCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
 
321
    }
 
322
 
 
323
    STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapHCPageInl, a);
 
324
    return VINF_SUCCESS;
 
325
}
 
326
 
 
327
 
 
328
/**
 
329
 * Inlined version of the guest page mapping code that optimizes access to pages
 
330
 * already in the set.
 
331
 *
 
332
 * @returns VBox status code, see pgmRZDynMapGCPageCommon for details.
 
333
 * @param   pVM         The VM handle.
 
334
 * @param   pVCpu       The current CPU.
 
335
 * @param   GCPhys      The guest physical address of the page.
 
336
 * @param   ppv         Where to store the mapping address.
 
337
 */
 
338
DECLINLINE(int) pgmRZDynMapGCPageV2Inlined(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
 
339
{
 
340
    STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInl, a);
 
341
    AssertMsg(!(GCPhys & PAGE_OFFSET_MASK), ("%RGp\n", GCPhys));
 
342
 
 
343
    /*
 
344
     * Get the ram range.
 
345
     */
 
346
    PPGMRAMRANGE    pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
 
347
    RTGCPHYS        off  = GCPhys - pRam->GCPhys;
 
348
    if (RT_UNLIKELY(off >= pRam->cb
 
349
        /** @todo   || page state stuff */))
 
350
    {
 
351
        /* This case is not counted into StatRZDynMapGCPageInl. */
 
352
        STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlRamMisses);
 
353
        return pgmRZDynMapGCPageCommon(pVM, pVCpu, GCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
 
354
    }
 
355
 
 
356
    RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[off >> PAGE_SHIFT]);
 
357
    STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlRamHits);
 
358
 
 
359
    /*
 
360
     * pgmRZDynMapHCPageInlined with out stats.
 
361
     */
 
362
    PPGMMAPSET pSet = &pVCpu->pgm.s.AutoSet;
 
363
    Assert(!(HCPhys & PAGE_OFFSET_MASK));
 
364
    Assert(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries));
 
365
 
 
366
    unsigned    iHash   = PGMMAPSET_HASH(HCPhys);
 
367
    unsigned    iEntry  = pSet->aiHashTable[iHash];
 
368
    if (    iEntry < pSet->cEntries
 
369
        &&  pSet->aEntries[iEntry].HCPhys == HCPhys
 
370
        &&  pSet->aEntries[iEntry].cInlinedRefs < UINT16_MAX - 1)
 
371
    {
 
372
        pSet->aEntries[iEntry].cInlinedRefs++;
 
373
        *ppv = pSet->aEntries[iEntry].pvPage;
 
374
        STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlHits);
 
375
    }
 
376
    else
 
377
    {
 
378
        STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlMisses);
 
379
        pgmRZDynMapHCPageCommon(pSet, HCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
 
380
    }
 
381
 
 
382
    STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInl, a);
 
383
    return VINF_SUCCESS;
 
384
}
 
385
 
 
386
 
 
387
/**
 
388
 * Inlined version of the ring-0 version of guest page mapping that optimizes
 
389
 * access to pages already in the set.
 
390
 *
 
391
 * @returns VBox status code, see pgmRZDynMapGCPageCommon for details.
 
392
 * @param   pVCpu       The current CPU.
 
393
 * @param   GCPhys      The guest physical address of the page.
 
394
 * @param   ppv         Where to store the mapping address.
 
395
 */
 
396
DECLINLINE(int) pgmRZDynMapGCPageInlined(PVMCPU pVCpu, RTGCPHYS GCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
 
397
{
 
398
    return pgmRZDynMapGCPageV2Inlined(pVCpu->CTX_SUFF(pVM), pVCpu, GCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
 
399
}
 
400
 
 
401
 
 
402
/**
 
403
 * Inlined version of the ring-0 version of the guest byte mapping code
 
404
 * that optimizes access to pages already in the set.
 
405
 *
 
406
 * @returns VBox status code, see pgmRZDynMapGCPageCommon for details.
 
407
 * @param   pVCpu       The current CPU.
 
408
 * @param   HCPhys      The physical address of the page.
 
409
 * @param   ppv         Where to store the mapping address. The offset is
 
410
 *                      preserved.
 
411
 */
 
412
DECLINLINE(int) pgmRZDynMapGCPageOffInlined(PVMCPU pVCpu, RTGCPHYS GCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
 
413
{
 
414
    STAM_PROFILE_START(&pVCpu->pgm.s.StatRZDynMapGCPageInl, a);
 
415
 
 
416
    /*
 
417
     * Get the ram range.
 
418
     */
 
419
    PVM             pVM  = pVCpu->CTX_SUFF(pVM);
 
420
    PPGMRAMRANGE    pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
 
421
    RTGCPHYS        off  = GCPhys - pRam->GCPhys;
 
422
    if (RT_UNLIKELY(off >= pRam->cb
 
423
        /** @todo   || page state stuff */))
 
424
    {
 
425
        /* This case is not counted into StatRZDynMapGCPageInl. */
 
426
        STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlRamMisses);
 
427
        return pgmRZDynMapGCPageCommon(pVM, pVCpu, GCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
 
428
    }
 
429
 
 
430
    RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[off >> PAGE_SHIFT]);
 
431
    STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlRamHits);
 
432
 
 
433
    /*
 
434
     * pgmRZDynMapHCPageInlined with out stats.
 
435
     */
 
436
    PPGMMAPSET pSet = &pVCpu->pgm.s.AutoSet;
 
437
    Assert(!(HCPhys & PAGE_OFFSET_MASK));
 
438
    Assert(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries));
 
439
 
 
440
    unsigned    iHash   = PGMMAPSET_HASH(HCPhys);
 
441
    unsigned    iEntry  = pSet->aiHashTable[iHash];
 
442
    if (    iEntry < pSet->cEntries
 
443
        &&  pSet->aEntries[iEntry].HCPhys == HCPhys
 
444
        &&  pSet->aEntries[iEntry].cInlinedRefs < UINT16_MAX - 1)
 
445
    {
 
446
        STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlHits);
 
447
        pSet->aEntries[iEntry].cInlinedRefs++;
 
448
        *ppv = (void *)((uintptr_t)pSet->aEntries[iEntry].pvPage | (PAGE_OFFSET_MASK & (uintptr_t)GCPhys));
 
449
    }
 
450
    else
 
451
    {
 
452
        STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInlMisses);
 
453
        pgmRZDynMapHCPageCommon(pSet, HCPhys, ppv RTLOG_COMMA_SRC_POS_ARGS);
 
454
        *ppv = (void *)((uintptr_t)*ppv | (PAGE_OFFSET_MASK & (uintptr_t)GCPhys));
 
455
    }
 
456
 
 
457
    STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZDynMapGCPageInl, a);
 
458
    return VINF_SUCCESS;
 
459
}
 
460
 
 
461
#endif /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
 
462
#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
 
463
 
 
464
/**
 
465
 * Maps the page into current context (RC and maybe R0).
 
466
 *
 
467
 * @returns pointer to the mapping.
 
468
 * @param   pVM         Pointer to the PGM instance data.
 
469
 * @param   pPage       The page.
 
470
 */
 
471
DECLINLINE(void *) pgmPoolMapPageInlined(PVM pVM, PPGMPOOLPAGE pPage RTLOG_COMMA_SRC_POS_DECL)
 
472
{
 
473
    if (pPage->idx >= PGMPOOL_IDX_FIRST)
 
474
    {
 
475
        Assert(pPage->idx < pVM->pgm.s.CTX_SUFF(pPool)->cCurPages);
 
476
        void *pv;
 
477
        pgmRZDynMapHCPageInlined(VMMGetCpu(pVM), pPage->Core.Key, &pv RTLOG_COMMA_SRC_POS_ARGS);
 
478
        return pv;
 
479
    }
 
480
    AssertFatalMsgFailed(("pgmPoolMapPageInlined invalid page index %x\n", pPage->idx));
 
481
}
 
482
 
 
483
/**
 
484
 * Maps the page into current context (RC and maybe R0).
 
485
 *
 
486
 * @returns pointer to the mapping.
 
487
 * @param   pVM         Pointer to the PGM instance data.
 
488
 * @param   pVCpu       The current CPU.
 
489
 * @param   pPage       The page.
 
490
 */
 
491
DECLINLINE(void *) pgmPoolMapPageV2Inlined(PVM pVM, PVMCPU pVCpu, PPGMPOOLPAGE pPage RTLOG_COMMA_SRC_POS_DECL)
 
492
{
 
493
    if (pPage->idx >= PGMPOOL_IDX_FIRST)
 
494
    {
 
495
        Assert(pPage->idx < pVM->pgm.s.CTX_SUFF(pPool)->cCurPages);
 
496
        void *pv;
 
497
        Assert(pVCpu == VMMGetCpu(pVM));
 
498
        pgmRZDynMapHCPageInlined(pVCpu, pPage->Core.Key, &pv RTLOG_COMMA_SRC_POS_ARGS);
 
499
        return pv;
 
500
    }
 
501
    AssertFatalMsgFailed(("pgmPoolMapPageV2Inlined invalid page index %x\n", pPage->idx));
 
502
}
 
503
 
 
504
#endif /*  VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 || IN_RC */
 
505
#ifndef IN_RC
 
506
 
 
507
/**
 
508
 * Queries the Physical TLB entry for a physical guest page,
 
509
 * attempting to load the TLB entry if necessary.
 
510
 *
 
511
 * @returns VBox status code.
 
512
 * @retval  VINF_SUCCESS on success
 
513
 * @retval  VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
 
514
 *
 
515
 * @param   pPGM        The PGM instance handle.
 
516
 * @param   GCPhys      The address of the guest page.
 
517
 * @param   ppTlbe      Where to store the pointer to the TLB entry.
 
518
 */
 
519
DECLINLINE(int) pgmPhysPageQueryTlbe(PPGM pPGM, RTGCPHYS GCPhys, PPPGMPAGEMAPTLBE ppTlbe)
 
520
{
 
521
    int rc;
 
522
    PPGMPAGEMAPTLBE pTlbe = &pPGM->CTXSUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
 
523
    if (pTlbe->GCPhys == (GCPhys & X86_PTE_PAE_PG_MASK))
 
524
    {
 
525
        STAM_COUNTER_INC(&pPGM->CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageMapTlbHits));
 
526
        rc = VINF_SUCCESS;
 
527
    }
 
528
    else
 
529
        rc = pgmPhysPageLoadIntoTlb(pPGM, GCPhys);
 
530
    *ppTlbe = pTlbe;
 
531
    return rc;
 
532
}
 
533
 
 
534
 
 
535
/**
 
536
 * Queries the Physical TLB entry for a physical guest page,
 
537
 * attempting to load the TLB entry if necessary.
 
538
 *
 
539
 * @returns VBox status code.
 
540
 * @retval  VINF_SUCCESS on success
 
541
 * @retval  VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
 
542
 *
 
543
 * @param   pPGM        The PGM instance handle.
 
544
 * @param   pPage       Pointer to the PGMPAGE structure corresponding to
 
545
 *                      GCPhys.
 
546
 * @param   GCPhys      The address of the guest page.
 
547
 * @param   ppTlbe      Where to store the pointer to the TLB entry.
 
548
 */
 
549
DECLINLINE(int) pgmPhysPageQueryTlbeWithPage(PPGM pPGM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMPAGEMAPTLBE ppTlbe)
 
550
{
 
551
    int rc;
 
552
    PPGMPAGEMAPTLBE pTlbe = &pPGM->CTXSUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
 
553
    if (pTlbe->GCPhys == (GCPhys & X86_PTE_PAE_PG_MASK))
 
554
    {
 
555
        STAM_COUNTER_INC(&pPGM->CTX_SUFF(pStats)->CTX_MID_Z(Stat,PageMapTlbHits));
 
556
        rc = VINF_SUCCESS;
 
557
    }
 
558
    else
 
559
        rc = pgmPhysPageLoadIntoTlbWithPage(pPGM, pPage, GCPhys);
 
560
    *ppTlbe = pTlbe;
 
561
    return rc;
 
562
}
 
563
 
 
564
#endif /* !IN_RC */
 
565
 
 
566
 
 
567
/**
 
568
 * Checks if the no-execute (NX) feature is active (EFER.NXE=1).
 
569
 *
 
570
 * Only used when the guest is in PAE or long mode.  This is inlined so that we
 
571
 * can perform consistency checks in debug builds.
 
572
 *
 
573
 * @returns true if it is, false if it isn't.
 
574
 * @param   pVCpu       The current CPU.
 
575
 */
 
576
DECL_FORCE_INLINE(bool) pgmGstIsNoExecuteActive(PVMCPU pVCpu)
 
577
{
 
578
    Assert(pVCpu->pgm.s.fNoExecuteEnabled == CPUMIsGuestNXEnabled(pVCpu));
 
579
    Assert(CPUMIsGuestInPAEMode(pVCpu) || CPUMIsGuestInLongMode(pVCpu));
 
580
    return pVCpu->pgm.s.fNoExecuteEnabled;
 
581
}
 
582
 
 
583
 
 
584
/**
 
585
 * Checks if the page size extension (PSE) is currently enabled (CR4.PSE=1).
 
586
 *
 
587
 * Only used when the guest is in paged 32-bit mode.  This is inlined so that
 
588
 * we can perform consistency checks in debug builds.
 
589
 *
 
590
 * @returns true if it is, false if it isn't.
 
591
 * @param   pVCpu       The current CPU.
 
592
 */
 
593
DECL_FORCE_INLINE(bool) pgmGst32BitIsPageSizeExtActive(PVMCPU pVCpu)
 
594
{
 
595
    Assert(pVCpu->pgm.s.fGst32BitPageSizeExtension == CPUMIsGuestPageSizeExtEnabled(pVCpu));
 
596
    Assert(!CPUMIsGuestInPAEMode(pVCpu));
 
597
    Assert(!CPUMIsGuestInLongMode(pVCpu));
 
598
    return pVCpu->pgm.s.fGst32BitPageSizeExtension;
 
599
}
 
600
 
 
601
 
 
602
/**
 
603
 * Calculated the guest physical address of the large (4 MB) page in 32 bits paging mode.
 
604
 * Takes PSE-36 into account.
 
605
 *
 
606
 * @returns guest physical address
 
607
 * @param   pPGM        Pointer to the PGM instance data.
 
608
 * @param   Pde         Guest Pde
 
609
 */
 
610
DECLINLINE(RTGCPHYS) pgmGstGet4MBPhysPage(PPGM pPGM, X86PDE Pde)
 
611
{
 
612
    RTGCPHYS GCPhys = Pde.u & X86_PDE4M_PG_MASK;
 
613
    GCPhys |= (RTGCPHYS)Pde.b.u8PageNoHigh << 32;
 
614
 
 
615
    return GCPhys & pPGM->GCPhys4MBPSEMask;
 
616
}
 
617
 
 
618
 
 
619
/**
 
620
 * Gets the address the guest page directory (32-bit paging).
 
621
 *
 
622
 * @returns VBox status code.
 
623
 * @param   pVCpu       The current CPU.
 
624
 * @param   ppPd        Where to return the mapping. This is always set.
 
625
 */
 
626
DECLINLINE(int) pgmGstGet32bitPDPtrEx(PVMCPU pVCpu, PX86PD *ppPd)
 
627
{
 
628
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
 
629
    int rc = pgmRZDynMapGCPageInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)ppPd RTLOG_COMMA_SRC_POS);
 
630
    if (RT_FAILURE(rc))
 
631
    {
 
632
        *ppPd = NULL;
 
633
        return rc;
 
634
    }
 
635
#else
 
636
    *ppPd = pVCpu->pgm.s.CTX_SUFF(pGst32BitPd);
 
637
    if (RT_UNLIKELY(!*ppPd))
 
638
        return pgmGstLazyMap32BitPD(pVCpu, ppPd);
 
639
#endif
 
640
    return VINF_SUCCESS;
 
641
}
 
642
 
 
643
 
 
644
/**
 
645
 * Gets the address the guest page directory (32-bit paging).
 
646
 *
 
647
 * @returns Pointer the page directory entry in question.
 
648
 * @param   pVCpu       The current CPU.
 
649
 */
 
650
DECLINLINE(PX86PD) pgmGstGet32bitPDPtr(PVMCPU pVCpu)
 
651
{
 
652
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
 
653
    PX86PD pGuestPD = NULL;
 
654
    int rc = pgmRZDynMapGCPageInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)&pGuestPD RTLOG_COMMA_SRC_POS);
 
655
    if (RT_FAILURE(rc))
 
656
    {
 
657
        AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
 
658
        return NULL;
 
659
    }
 
660
#else
 
661
    PX86PD pGuestPD = pVCpu->pgm.s.CTX_SUFF(pGst32BitPd);
 
662
    if (RT_UNLIKELY(!pGuestPD))
 
663
    {
 
664
        int rc = pgmGstLazyMap32BitPD(pVCpu, &pGuestPD);
 
665
        if (RT_FAILURE(rc))
 
666
            return NULL;
 
667
    }
 
668
#endif
 
669
    return pGuestPD;
 
670
}
 
671
 
 
672
 
 
673
/**
 
674
 * Gets the guest page directory pointer table.
 
675
 *
 
676
 * @returns VBox status code.
 
677
 * @param   pVCpu       The current CPU.
 
678
 * @param   ppPdpt      Where to return the mapping.  This is always set.
 
679
 */
 
680
DECLINLINE(int) pgmGstGetPaePDPTPtrEx(PVMCPU pVCpu, PX86PDPT *ppPdpt)
 
681
{
 
682
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
 
683
    int rc = pgmRZDynMapGCPageOffInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)ppPdpt RTLOG_COMMA_SRC_POS);
 
684
    if (RT_FAILURE(rc))
 
685
    {
 
686
        *ppPdpt = NULL;
 
687
        return rc;
 
688
    }
 
689
#else
 
690
    *ppPdpt = pVCpu->pgm.s.CTX_SUFF(pGstPaePdpt);
 
691
    if (RT_UNLIKELY(!*ppPdpt))
 
692
        return pgmGstLazyMapPaePDPT(pVCpu, ppPdpt);
 
693
#endif
 
694
    return VINF_SUCCESS;
 
695
}
 
696
 
 
697
/**
 
698
 * Gets the guest page directory pointer table.
 
699
 *
 
700
 * @returns Pointer to the page directory in question.
 
701
 * @returns NULL if the page directory is not present or on an invalid page.
 
702
 * @param   pVCpu       The current CPU.
 
703
 */
 
704
DECLINLINE(PX86PDPT) pgmGstGetPaePDPTPtr(PVMCPU pVCpu)
 
705
{
 
706
    PX86PDPT pGuestPdpt;
 
707
    int rc = pgmGstGetPaePDPTPtrEx(pVCpu, &pGuestPdpt);
 
708
    AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
 
709
    return pGuestPdpt;
 
710
}
 
711
 
 
712
 
 
713
/**
 
714
 * Gets the guest page directory pointer table entry for the specified address.
 
715
 *
 
716
 * @returns Pointer to the page directory in question.
 
717
 * @returns NULL if the page directory is not present or on an invalid page.
 
718
 * @param   pVCpu       The current CPU
 
719
 * @param   GCPtr       The address.
 
720
 */
 
721
DECLINLINE(PX86PDPE) pgmGstGetPaePDPEPtr(PVMCPU pVCpu, RTGCPTR GCPtr)
 
722
{
 
723
    AssertGCPtr32(GCPtr);
 
724
 
 
725
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
 
726
    PX86PDPT pGuestPDPT = NULL;
 
727
    int rc = pgmRZDynMapGCPageOffInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)&pGuestPDPT RTLOG_COMMA_SRC_POS);
 
728
    AssertRCReturn(rc, NULL);
 
729
#else
 
730
    PX86PDPT pGuestPDPT = pVCpu->pgm.s.CTX_SUFF(pGstPaePdpt);
 
731
    if (RT_UNLIKELY(!pGuestPDPT))
 
732
    {
 
733
        int rc = pgmGstLazyMapPaePDPT(pVCpu, &pGuestPDPT);
 
734
        if (RT_FAILURE(rc))
 
735
            return NULL;
 
736
    }
 
737
#endif
 
738
    return &pGuestPDPT->a[(GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE];
 
739
}
 
740
 
 
741
 
 
742
/**
 
743
 * Gets the page directory entry for the specified address.
 
744
 *
 
745
 * @returns The page directory entry in question.
 
746
 * @returns A non-present entry if the page directory is not present or on an invalid page.
 
747
 * @param   pVCpu       The handle of the virtual CPU.
 
748
 * @param   GCPtr       The address.
 
749
 */
 
750
DECLINLINE(X86PDEPAE) pgmGstGetPaePDE(PVMCPU pVCpu, RTGCPTR GCPtr)
 
751
{
 
752
    AssertGCPtr32(GCPtr);
 
753
    PX86PDPT    pGuestPDPT = pgmGstGetPaePDPTPtr(pVCpu);
 
754
    if (RT_LIKELY(pGuestPDPT))
 
755
    {
 
756
        const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
 
757
        if (    pGuestPDPT->a[iPdpt].n.u1Present
 
758
            &&  !(pGuestPDPT->a[iPdpt].u & pVCpu->pgm.s.fGstPaeMbzPdpeMask) )
 
759
        {
 
760
            const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
 
761
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
 
762
            PX86PDPAE   pGuestPD = NULL;
 
763
            int rc = pgmRZDynMapGCPageInlined(pVCpu,
 
764
                                              pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK,
 
765
                                              (void **)&pGuestPD
 
766
                                              RTLOG_COMMA_SRC_POS);
 
767
            if (RT_SUCCESS(rc))
 
768
                return pGuestPD->a[iPD];
 
769
            AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
 
770
#else
 
771
            PX86PDPAE   pGuestPD = pVCpu->pgm.s.CTX_SUFF(apGstPaePDs)[iPdpt];
 
772
            if (    !pGuestPD
 
773
                ||  (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt])
 
774
                pgmGstLazyMapPaePD(pVCpu, iPdpt, &pGuestPD);
 
775
            if (pGuestPD)
 
776
                return pGuestPD->a[iPD];
 
777
#endif
 
778
        }
 
779
    }
 
780
 
 
781
    X86PDEPAE ZeroPde = {0};
 
782
    return ZeroPde;
 
783
}
 
784
 
 
785
 
 
786
/**
 
787
 * Gets the page directory pointer table entry for the specified address
 
788
 * and returns the index into the page directory
 
789
 *
 
790
 * @returns Pointer to the page directory in question.
 
791
 * @returns NULL if the page directory is not present or on an invalid page.
 
792
 * @param   pVCpu       The current CPU.
 
793
 * @param   GCPtr       The address.
 
794
 * @param   piPD        Receives the index into the returned page directory
 
795
 * @param   pPdpe       Receives the page directory pointer entry. Optional.
 
796
 */
 
797
DECLINLINE(PX86PDPAE) pgmGstGetPaePDPtr(PVMCPU pVCpu, RTGCPTR GCPtr, unsigned *piPD, PX86PDPE pPdpe)
 
798
{
 
799
    AssertGCPtr32(GCPtr);
 
800
 
 
801
    /* The PDPE. */
 
802
    PX86PDPT        pGuestPDPT = pgmGstGetPaePDPTPtr(pVCpu);
 
803
    if (RT_UNLIKELY(!pGuestPDPT))
 
804
        return NULL;
 
805
    const unsigned  iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
 
806
    if (pPdpe)
 
807
        *pPdpe = pGuestPDPT->a[iPdpt];
 
808
    if (!pGuestPDPT->a[iPdpt].n.u1Present)
 
809
        return NULL;
 
810
    if (RT_UNLIKELY(pVCpu->pgm.s.fGstPaeMbzPdpeMask & pGuestPDPT->a[iPdpt].u))
 
811
        return NULL;
 
812
 
 
813
    /* The PDE. */
 
814
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
 
815
    PX86PDPAE   pGuestPD = NULL;
 
816
    int rc = pgmRZDynMapGCPageInlined(pVCpu,
 
817
                                      pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK,
 
818
                                      (void **)&pGuestPD
 
819
                                      RTLOG_COMMA_SRC_POS);
 
820
    if (RT_FAILURE(rc))
 
821
    {
 
822
        AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
 
823
        return NULL;
 
824
    }
 
825
#else
 
826
    PX86PDPAE   pGuestPD = pVCpu->pgm.s.CTX_SUFF(apGstPaePDs)[iPdpt];
 
827
    if (    !pGuestPD
 
828
        ||  (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt])
 
829
        pgmGstLazyMapPaePD(pVCpu, iPdpt, &pGuestPD);
 
830
#endif
 
831
 
 
832
    *piPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
 
833
    return pGuestPD;
 
834
}
 
835
 
 
836
#ifndef IN_RC
 
837
 
 
838
/**
 
839
 * Gets the page map level-4 pointer for the guest.
 
840
 *
 
841
 * @returns VBox status code.
 
842
 * @param   pVCpu       The current CPU.
 
843
 * @param   ppPml4      Where to return the mapping.  Always set.
 
844
 */
 
845
DECLINLINE(int) pgmGstGetLongModePML4PtrEx(PVMCPU pVCpu, PX86PML4 *ppPml4)
 
846
{
 
847
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
 
848
    int rc = pgmRZDynMapGCPageInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)ppPml4 RTLOG_COMMA_SRC_POS);
 
849
    if (RT_FAILURE(rc))
 
850
    {
 
851
        *ppPml4 = NULL;
 
852
        return rc;
 
853
    }
 
854
#else
 
855
    *ppPml4 = pVCpu->pgm.s.CTX_SUFF(pGstAmd64Pml4);
 
856
    if (RT_UNLIKELY(!*ppPml4))
 
857
        return pgmGstLazyMapPml4(pVCpu, ppPml4);
 
858
#endif
 
859
    return VINF_SUCCESS;
 
860
}
 
861
 
 
862
 
 
863
/**
 
864
 * Gets the page map level-4 pointer for the guest.
 
865
 *
 
866
 * @returns Pointer to the PML4 page.
 
867
 * @param   pVCpu       The current CPU.
 
868
 */
 
869
DECLINLINE(PX86PML4) pgmGstGetLongModePML4Ptr(PVMCPU pVCpu)
 
870
{
 
871
    PX86PML4 pGuestPml4;
 
872
    int rc = pgmGstGetLongModePML4PtrEx(pVCpu, &pGuestPml4);
 
873
    AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc)); NOREF(rc);
 
874
    return pGuestPml4;
 
875
}
 
876
 
 
877
 
 
878
/**
 
879
 * Gets the pointer to a page map level-4 entry.
 
880
 *
 
881
 * @returns Pointer to the PML4 entry.
 
882
 * @param   pVCpu       The current CPU.
 
883
 * @param   iPml4       The index.
 
884
 * @remarks Only used by AssertCR3.
 
885
 */
 
886
DECLINLINE(PX86PML4E) pgmGstGetLongModePML4EPtr(PVMCPU pVCpu, unsigned int iPml4)
 
887
{
 
888
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
 
889
    PX86PML4 pGuestPml4;
 
890
    int rc = pgmRZDynMapGCPageInlined(pVCpu, pVCpu->pgm.s.GCPhysCR3, (void **)&pGuestPml4 RTLOG_COMMA_SRC_POS);
 
891
    AssertRCReturn(rc, NULL);
 
892
#else
 
893
    PX86PML4 pGuestPml4 = pVCpu->pgm.s.CTX_SUFF(pGstAmd64Pml4);
 
894
    if (RT_UNLIKELY(!pGuestPml4))
 
895
    {
 
896
         int rc = pgmGstLazyMapPml4(pVCpu, &pGuestPml4);
 
897
         AssertRCReturn(rc, NULL);
 
898
    }
 
899
#endif
 
900
    return &pGuestPml4->a[iPml4];
 
901
}
 
902
 
 
903
 
 
904
/**
 
905
 * Gets the page directory entry for the specified address.
 
906
 *
 
907
 * @returns The page directory entry in question.
 
908
 * @returns A non-present entry if the page directory is not present or on an invalid page.
 
909
 * @param   pVCpu       The current CPU.
 
910
 * @param   GCPtr       The address.
 
911
 */
 
912
DECLINLINE(X86PDEPAE) pgmGstGetLongModePDE(PVMCPU pVCpu, RTGCPTR64 GCPtr)
 
913
{
 
914
    /*
 
915
     * Note! To keep things simple, ASSUME invalid physical addresses will
 
916
     *       cause X86_TRAP_PF_RSVD.  This isn't a problem until we start
 
917
     *       supporting 52-bit wide physical guest addresses.
 
918
     */
 
919
    PCX86PML4       pGuestPml4 = pgmGstGetLongModePML4Ptr(pVCpu);
 
920
    const unsigned  iPml4      = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
 
921
    if (    RT_LIKELY(pGuestPml4)
 
922
        &&  pGuestPml4->a[iPml4].n.u1Present
 
923
        &&  !(pGuestPml4->a[iPml4].u & pVCpu->pgm.s.fGstAmd64MbzPml4eMask) )
 
924
    {
 
925
        PCX86PDPT   pPdptTemp;
 
926
        int rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, pGuestPml4->a[iPml4].u & X86_PML4E_PG_MASK, &pPdptTemp);
 
927
        if (RT_SUCCESS(rc))
 
928
        {
 
929
            const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
 
930
            if (    pPdptTemp->a[iPdpt].n.u1Present
 
931
                &&  !(pPdptTemp->a[iPdpt].u & pVCpu->pgm.s.fGstAmd64MbzPdpeMask) )
 
932
            {
 
933
                PCX86PDPAE pPD;
 
934
                rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
 
935
                if (RT_SUCCESS(rc))
 
936
                {
 
937
                    const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
 
938
                    return pPD->a[iPD];
 
939
                }
 
940
            }
 
941
        }
 
942
        AssertMsg(RT_SUCCESS(rc) || rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
 
943
    }
 
944
 
 
945
    X86PDEPAE ZeroPde = {0};
 
946
    return ZeroPde;
 
947
}
 
948
 
 
949
 
 
950
/**
 
951
 * Gets the GUEST page directory pointer for the specified address.
 
952
 *
 
953
 * @returns The page directory in question.
 
954
 * @returns NULL if the page directory is not present or on an invalid page.
 
955
 * @param   pVCpu       The current CPU.
 
956
 * @param   GCPtr       The address.
 
957
 * @param   ppPml4e     Page Map Level-4 Entry (out)
 
958
 * @param   pPdpe       Page directory pointer table entry (out)
 
959
 * @param   piPD        Receives the index into the returned page directory
 
960
 */
 
961
DECLINLINE(PX86PDPAE) pgmGstGetLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPE pPdpe, unsigned *piPD)
 
962
{
 
963
    /* The PMLE4. */
 
964
    PX86PML4        pGuestPml4 = pgmGstGetLongModePML4Ptr(pVCpu);
 
965
    if (RT_UNLIKELY(!pGuestPml4))
 
966
        return NULL;
 
967
    const unsigned  iPml4      = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
 
968
    PCX86PML4E      pPml4e     = *ppPml4e = &pGuestPml4->a[iPml4];
 
969
    if (!pPml4e->n.u1Present)
 
970
        return NULL;
 
971
    if (RT_UNLIKELY(pPml4e->u & pVCpu->pgm.s.fGstAmd64MbzPml4eMask))
 
972
        return NULL;
 
973
 
 
974
    /* The PDPE. */
 
975
    PCX86PDPT       pPdptTemp;
 
976
    int rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, pPml4e->u & X86_PML4E_PG_MASK, &pPdptTemp);
 
977
    if (RT_FAILURE(rc))
 
978
    {
 
979
        AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
 
980
        return NULL;
 
981
    }
 
982
    const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
 
983
    *pPdpe = pPdptTemp->a[iPdpt];
 
984
    if (!pPdpe->n.u1Present)
 
985
        return NULL;
 
986
    if (RT_UNLIKELY(pPdpe->u & pVCpu->pgm.s.fGstAmd64MbzPdpeMask))
 
987
        return NULL;
 
988
 
 
989
    /* The PDE. */
 
990
    PX86PDPAE pPD;
 
991
    rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
 
992
    if (RT_FAILURE(rc))
 
993
    {
 
994
        AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
 
995
        return NULL;
 
996
    }
 
997
 
 
998
    *piPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
 
999
    return pPD;
 
1000
}
 
1001
 
 
1002
#endif /* !IN_RC */
 
1003
 
 
1004
/**
 
1005
 * Gets the shadow page directory, 32-bit.
 
1006
 *
 
1007
 * @returns Pointer to the shadow 32-bit PD.
 
1008
 * @param   pVCpu       The current CPU.
 
1009
 */
 
1010
DECLINLINE(PX86PD) pgmShwGet32BitPDPtr(PVMCPU pVCpu)
 
1011
{
 
1012
    return (PX86PD)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
 
1013
}
 
1014
 
 
1015
 
 
1016
/**
 
1017
 * Gets the shadow page directory entry for the specified address, 32-bit.
 
1018
 *
 
1019
 * @returns Shadow 32-bit PDE.
 
1020
 * @param   pVCpu       The current CPU.
 
1021
 * @param   GCPtr       The address.
 
1022
 */
 
1023
DECLINLINE(X86PDE) pgmShwGet32BitPDE(PVMCPU pVCpu, RTGCPTR GCPtr)
 
1024
{
 
1025
    const unsigned iPd = (GCPtr >> X86_PD_SHIFT) & X86_PD_MASK;
 
1026
 
 
1027
    PX86PD pShwPde = pgmShwGet32BitPDPtr(pVCpu);
 
1028
    if (!pShwPde)
 
1029
    {
 
1030
        X86PDE ZeroPde = {0};
 
1031
        return ZeroPde;
 
1032
    }
 
1033
    return pShwPde->a[iPd];
 
1034
}
 
1035
 
 
1036
 
 
1037
/**
 
1038
 * Gets the pointer to the shadow page directory entry for the specified
 
1039
 * address, 32-bit.
 
1040
 *
 
1041
 * @returns Pointer to the shadow 32-bit PDE.
 
1042
 * @param   pVCpu       The current CPU.
 
1043
 * @param   GCPtr       The address.
 
1044
 */
 
1045
DECLINLINE(PX86PDE) pgmShwGet32BitPDEPtr(PVMCPU pVCpu, RTGCPTR GCPtr)
 
1046
{
 
1047
    const unsigned iPd = (GCPtr >> X86_PD_SHIFT) & X86_PD_MASK;
 
1048
 
 
1049
    PX86PD pPde = pgmShwGet32BitPDPtr(pVCpu);
 
1050
    AssertReturn(pPde, NULL);
 
1051
    return &pPde->a[iPd];
 
1052
}
 
1053
 
 
1054
 
 
1055
/**
 
1056
 * Gets the shadow page pointer table, PAE.
 
1057
 *
 
1058
 * @returns Pointer to the shadow PAE PDPT.
 
1059
 * @param   pVCpu       The current CPU.
 
1060
 */
 
1061
DECLINLINE(PX86PDPT) pgmShwGetPaePDPTPtr(PVMCPU pVCpu)
 
1062
{
 
1063
    return (PX86PDPT)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
 
1064
}
 
1065
 
 
1066
 
 
1067
/**
 
1068
 * Gets the shadow page directory for the specified address, PAE.
 
1069
 *
 
1070
 * @returns Pointer to the shadow PD.
 
1071
 * @param   pVCpu       The current CPU.
 
1072
 * @param   GCPtr       The address.
 
1073
 */
 
1074
DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PVMCPU pVCpu, RTGCPTR GCPtr)
 
1075
{
 
1076
    const unsigned  iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
 
1077
    PX86PDPT        pPdpt = pgmShwGetPaePDPTPtr(pVCpu);
 
1078
 
 
1079
    if (!pPdpt->a[iPdpt].n.u1Present)
 
1080
        return NULL;
 
1081
 
 
1082
    /* Fetch the pgm pool shadow descriptor. */
 
1083
    PVM pVM = pVCpu->CTX_SUFF(pVM);
 
1084
    PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pVM->pgm.s.CTX_SUFF(pPool), pPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
 
1085
    AssertReturn(pShwPde, NULL);
 
1086
 
 
1087
    return (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPde);
 
1088
}
 
1089
 
 
1090
 
 
1091
/**
 
1092
 * Gets the shadow page directory for the specified address, PAE.
 
1093
 *
 
1094
 * @returns Pointer to the shadow PD.
 
1095
 * @param   pVCpu       The current CPU.
 
1096
 * @param   GCPtr       The address.
 
1097
 */
 
1098
DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PVMCPU pVCpu, PX86PDPT pPdpt, RTGCPTR GCPtr)
 
1099
{
 
1100
    const unsigned  iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
 
1101
 
 
1102
    if (!pPdpt->a[iPdpt].n.u1Present)
 
1103
        return NULL;
 
1104
 
 
1105
    /* Fetch the pgm pool shadow descriptor. */
 
1106
    PVM             pVM     = pVCpu->CTX_SUFF(pVM);
 
1107
    PPGMPOOLPAGE    pShwPde = pgmPoolGetPage(pVM->pgm.s.CTX_SUFF(pPool), pPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
 
1108
    AssertReturn(pShwPde, NULL);
 
1109
 
 
1110
    return (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPde);
 
1111
}
 
1112
 
 
1113
 
 
1114
/**
 
1115
 * Gets the shadow page directory entry, PAE.
 
1116
 *
 
1117
 * @returns PDE.
 
1118
 * @param   pVCpu       The current CPU.
 
1119
 * @param   GCPtr       The address.
 
1120
 */
 
1121
DECLINLINE(X86PDEPAE) pgmShwGetPaePDE(PVMCPU pVCpu, RTGCPTR GCPtr)
 
1122
{
 
1123
    const unsigned iPd = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
 
1124
 
 
1125
    PX86PDPAE pShwPde = pgmShwGetPaePDPtr(pVCpu, GCPtr);
 
1126
    if (!pShwPde)
 
1127
    {
 
1128
        X86PDEPAE ZeroPde = {0};
 
1129
        return ZeroPde;
 
1130
    }
 
1131
    return pShwPde->a[iPd];
 
1132
}
 
1133
 
 
1134
 
 
1135
/**
 
1136
 * Gets the pointer to the shadow page directory entry for an address, PAE.
 
1137
 *
 
1138
 * @returns Pointer to the PDE.
 
1139
 * @param   pVCpu       The current CPU.
 
1140
 * @param   GCPtr       The address.
 
1141
 * @remarks Only used by AssertCR3.
 
1142
 */
 
1143
DECLINLINE(PX86PDEPAE) pgmShwGetPaePDEPtr(PVMCPU pVCpu, RTGCPTR GCPtr)
 
1144
{
 
1145
    const unsigned iPd = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
 
1146
 
 
1147
    PX86PDPAE pPde = pgmShwGetPaePDPtr(pVCpu, GCPtr);
 
1148
    AssertReturn(pPde, NULL);
 
1149
    return &pPde->a[iPd];
 
1150
}
 
1151
 
 
1152
#ifndef IN_RC
 
1153
 
 
1154
/**
 
1155
 * Gets the shadow page map level-4 pointer.
 
1156
 *
 
1157
 * @returns Pointer to the shadow PML4.
 
1158
 * @param   pVCpu       The current CPU.
 
1159
 */
 
1160
DECLINLINE(PX86PML4) pgmShwGetLongModePML4Ptr(PVMCPU pVCpu)
 
1161
{
 
1162
    return (PX86PML4)PGMPOOL_PAGE_2_PTR_V2(pVCpu->CTX_SUFF(pVM), pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
 
1163
}
 
1164
 
 
1165
 
 
1166
/**
 
1167
 * Gets the shadow page map level-4 entry for the specified address.
 
1168
 *
 
1169
 * @returns The entry.
 
1170
 * @param   pVCpu       The current CPU.
 
1171
 * @param   GCPtr       The address.
 
1172
 */
 
1173
DECLINLINE(X86PML4E) pgmShwGetLongModePML4E(PVMCPU pVCpu, RTGCPTR GCPtr)
 
1174
{
 
1175
    const unsigned  iPml4 = ((RTGCUINTPTR64)GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
 
1176
    PX86PML4        pShwPml4 = pgmShwGetLongModePML4Ptr(pVCpu);
 
1177
 
 
1178
    if (!pShwPml4)
 
1179
    {
 
1180
        X86PML4E ZeroPml4e = {0};
 
1181
        return ZeroPml4e;
 
1182
    }
 
1183
    return pShwPml4->a[iPml4];
 
1184
}
 
1185
 
 
1186
 
 
1187
/**
 
1188
 * Gets the pointer to the specified shadow page map level-4 entry.
 
1189
 *
 
1190
 * @returns The entry.
 
1191
 * @param   pVCpu       The current CPU.
 
1192
 * @param   iPml4       The PML4 index.
 
1193
 */
 
1194
DECLINLINE(PX86PML4E) pgmShwGetLongModePML4EPtr(PVMCPU pVCpu, unsigned int iPml4)
 
1195
{
 
1196
    PX86PML4 pShwPml4 = pgmShwGetLongModePML4Ptr(pVCpu);
 
1197
    if (!pShwPml4)
 
1198
        return NULL;
 
1199
    return &pShwPml4->a[iPml4];
 
1200
}
 
1201
 
 
1202
#endif /* !IN_RC */
 
1203
 
 
1204
 
 
1205
/**
 
1206
 * Cached physical handler lookup.
 
1207
 *
 
1208
 * @returns Physical handler covering @a GCPhys.
 
1209
 * @param   pVM                 The VM handle.
 
1210
 * @param   GCPhys              The lookup address.
 
1211
 */
 
1212
DECLINLINE(PPGMPHYSHANDLER) pgmHandlerPhysicalLookup(PVM pVM, RTGCPHYS GCPhys)
 
1213
{
 
1214
    PPGMPHYSHANDLER pHandler = pVM->pgm.s.CTX_SUFF(pLastPhysHandler);
 
1215
    if (   pHandler
 
1216
        && GCPhys >= pHandler->Core.Key
 
1217
        && GCPhys < pHandler->Core.KeyLast)
 
1218
    {
 
1219
        STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PhysHandlerLookupHits));
 
1220
        return pHandler;
 
1221
    }
 
1222
 
 
1223
    STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PhysHandlerLookupMisses));
 
1224
    pHandler = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
 
1225
    if (pHandler)
 
1226
        pVM->pgm.s.CTX_SUFF(pLastPhysHandler) = pHandler;
 
1227
    return pHandler;
 
1228
}
 
1229
 
 
1230
 
 
1231
/**
 
1232
 * Gets the page state for a physical handler.
 
1233
 *
 
1234
 * @returns The physical handler page state.
 
1235
 * @param   pCur    The physical handler in question.
 
1236
 */
 
1237
DECLINLINE(unsigned) pgmHandlerPhysicalCalcState(PPGMPHYSHANDLER pCur)
 
1238
{
 
1239
    switch (pCur->enmType)
 
1240
    {
 
1241
        case PGMPHYSHANDLERTYPE_PHYSICAL_WRITE:
 
1242
            return PGM_PAGE_HNDL_PHYS_STATE_WRITE;
 
1243
 
 
1244
        case PGMPHYSHANDLERTYPE_MMIO:
 
1245
        case PGMPHYSHANDLERTYPE_PHYSICAL_ALL:
 
1246
            return PGM_PAGE_HNDL_PHYS_STATE_ALL;
 
1247
 
 
1248
        default:
 
1249
            AssertFatalMsgFailed(("Invalid type %d\n", pCur->enmType));
 
1250
    }
 
1251
}
 
1252
 
 
1253
 
 
1254
/**
 
1255
 * Gets the page state for a virtual handler.
 
1256
 *
 
1257
 * @returns The virtual handler page state.
 
1258
 * @param   pCur    The virtual handler in question.
 
1259
 * @remarks This should never be used on a hypervisor access handler.
 
1260
 */
 
1261
DECLINLINE(unsigned) pgmHandlerVirtualCalcState(PPGMVIRTHANDLER pCur)
 
1262
{
 
1263
    switch (pCur->enmType)
 
1264
    {
 
1265
        case PGMVIRTHANDLERTYPE_WRITE:
 
1266
            return PGM_PAGE_HNDL_VIRT_STATE_WRITE;
 
1267
        case PGMVIRTHANDLERTYPE_ALL:
 
1268
            return PGM_PAGE_HNDL_VIRT_STATE_ALL;
 
1269
        default:
 
1270
            AssertFatalMsgFailed(("Invalid type %d\n", pCur->enmType));
 
1271
    }
 
1272
}
 
1273
 
 
1274
 
 
1275
/**
 
1276
 * Clears one physical page of a virtual handler
 
1277
 *
 
1278
 * @param   pPGM    Pointer to the PGM instance.
 
1279
 * @param   pCur    Virtual handler structure
 
1280
 * @param   iPage   Physical page index
 
1281
 *
 
1282
 * @remark  Only used when PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL is being set, so no
 
1283
 *          need to care about other handlers in the same page.
 
1284
 */
 
1285
DECLINLINE(void) pgmHandlerVirtualClearPage(PPGM pPGM, PPGMVIRTHANDLER pCur, unsigned iPage)
 
1286
{
 
1287
    const PPGMPHYS2VIRTHANDLER pPhys2Virt = &pCur->aPhysToVirt[iPage];
 
1288
 
 
1289
    /*
 
1290
     * Remove the node from the tree (it's supposed to be in the tree if we get here!).
 
1291
     */
 
1292
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
 
1293
    AssertReleaseMsg(pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE,
 
1294
                     ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
 
1295
                      pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias));
 
1296
#endif
 
1297
    if (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_IS_HEAD)
 
1298
    {
 
1299
        /* We're the head of the alias chain. */
 
1300
        PPGMPHYS2VIRTHANDLER pRemove = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysRemove(&pPGM->CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key); NOREF(pRemove);
 
1301
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
 
1302
        AssertReleaseMsg(pRemove != NULL,
 
1303
                         ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
 
1304
                          pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias));
 
1305
        AssertReleaseMsg(pRemove == pPhys2Virt,
 
1306
                         ("wanted: pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n"
 
1307
                          "   got:    pRemove=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
 
1308
                          pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias,
 
1309
                          pRemove, pRemove->Core.Key, pRemove->Core.KeyLast, pRemove->offVirtHandler, pRemove->offNextAlias));
 
1310
#endif
 
1311
        if (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK)
 
1312
        {
 
1313
            /* Insert the next list in the alias chain into the tree. */
 
1314
            PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
 
1315
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
 
1316
            AssertReleaseMsg(pNext->offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE,
 
1317
                             ("pNext=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
 
1318
                             pNext, pNext->Core.Key, pNext->Core.KeyLast, pNext->offVirtHandler, pNext->offNextAlias));
 
1319
#endif
 
1320
            pNext->offNextAlias |= PGMPHYS2VIRTHANDLER_IS_HEAD;
 
1321
            bool fRc = RTAvlroGCPhysInsert(&pPGM->CTX_SUFF(pTrees)->PhysToVirtHandlers, &pNext->Core);
 
1322
            AssertRelease(fRc);
 
1323
        }
 
1324
    }
 
1325
    else
 
1326
    {
 
1327
        /* Locate the previous node in the alias chain. */
 
1328
        PPGMPHYS2VIRTHANDLER pPrev = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGet(&pPGM->CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key);
 
1329
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
 
1330
        AssertReleaseMsg(pPrev != pPhys2Virt,
 
1331
                         ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} pPrev=%p\n",
 
1332
                          pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias, pPrev));
 
1333
#endif
 
1334
        for (;;)
 
1335
        {
 
1336
            PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPrev + (pPrev->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
 
1337
            if (pNext == pPhys2Virt)
 
1338
            {
 
1339
                /* unlink. */
 
1340
                LogFlow(("pgmHandlerVirtualClearPage: removed %p:{.offNextAlias=%#RX32} from alias chain. prev %p:{.offNextAlias=%#RX32} [%RGp-%RGp]\n",
 
1341
                         pPhys2Virt, pPhys2Virt->offNextAlias, pPrev, pPrev->offNextAlias, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast));
 
1342
                if (!(pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK))
 
1343
                    pPrev->offNextAlias &= ~PGMPHYS2VIRTHANDLER_OFF_MASK;
 
1344
                else
 
1345
                {
 
1346
                    PPGMPHYS2VIRTHANDLER pNewNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
 
1347
                    pPrev->offNextAlias = ((intptr_t)pNewNext - (intptr_t)pPrev)
 
1348
                                        | (pPrev->offNextAlias & ~PGMPHYS2VIRTHANDLER_OFF_MASK);
 
1349
                }
 
1350
                break;
 
1351
            }
 
1352
 
 
1353
            /* next */
 
1354
            if (pNext == pPrev)
 
1355
            {
 
1356
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
 
1357
                AssertReleaseMsg(pNext != pPrev,
 
1358
                                 ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} pPrev=%p\n",
 
1359
                                  pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias, pPrev));
 
1360
#endif
 
1361
                break;
 
1362
            }
 
1363
            pPrev = pNext;
 
1364
        }
 
1365
    }
 
1366
    Log2(("PHYS2VIRT: Removing %RGp-%RGp %#RX32 %s\n",
 
1367
          pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias, R3STRING(pCur->pszDesc)));
 
1368
    pPhys2Virt->offNextAlias = 0;
 
1369
    pPhys2Virt->Core.KeyLast = NIL_RTGCPHYS; /* require reinsert */
 
1370
 
 
1371
    /*
 
1372
     * Clear the ram flags for this page.
 
1373
     */
 
1374
    PPGMPAGE pPage = pgmPhysGetPage(pPGM, pPhys2Virt->Core.Key);
 
1375
    AssertReturnVoid(pPage);
 
1376
    PGM_PAGE_SET_HNDL_VIRT_STATE(pPage, PGM_PAGE_HNDL_VIRT_STATE_NONE);
 
1377
}
 
1378
 
 
1379
 
 
1380
/**
 
1381
 * Internal worker for finding a 'in-use' shadow page give by it's physical address.
 
1382
 *
 
1383
 * @returns Pointer to the shadow page structure.
 
1384
 * @param   pPool       The pool.
 
1385
 * @param   idx         The pool page index.
 
1386
 */
 
1387
DECLINLINE(PPGMPOOLPAGE) pgmPoolGetPageByIdx(PPGMPOOL pPool, unsigned idx)
 
1388
{
 
1389
    AssertFatalMsg(idx >= PGMPOOL_IDX_FIRST && idx < pPool->cCurPages, ("idx=%d\n", idx));
 
1390
    return &pPool->aPages[idx];
 
1391
}
 
1392
 
 
1393
 
 
1394
/**
 
1395
 * Clear references to guest physical memory.
 
1396
 *
 
1397
 * @param   pPool       The pool.
 
1398
 * @param   pPoolPage   The pool page.
 
1399
 * @param   pPhysPage   The physical guest page tracking structure.
 
1400
 * @param   iPte        Shadow PTE index
 
1401
 */
 
1402
DECLINLINE(void) pgmTrackDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPoolPage, PPGMPAGE pPhysPage, uint16_t iPte)
 
1403
{
 
1404
    /*
 
1405
     * Just deal with the simple case here.
 
1406
     */
 
1407
# ifdef LOG_ENABLED
 
1408
    const unsigned uOrg = PGM_PAGE_GET_TRACKING(pPhysPage);
 
1409
# endif
 
1410
    const unsigned cRefs = PGM_PAGE_GET_TD_CREFS(pPhysPage);
 
1411
    if (cRefs == 1)
 
1412
    {
 
1413
        Assert(pPoolPage->idx == PGM_PAGE_GET_TD_IDX(pPhysPage));
 
1414
        Assert(iPte == PGM_PAGE_GET_PTE_INDEX(pPhysPage));
 
1415
        /* Invalidate the tracking data. */
 
1416
        PGM_PAGE_SET_TRACKING(pPhysPage, 0);
 
1417
    }
 
1418
    else
 
1419
        pgmPoolTrackPhysExtDerefGCPhys(pPool, pPoolPage, pPhysPage, iPte);
 
1420
    Log2(("pgmTrackDerefGCPhys: %x -> %x pPhysPage=%R[pgmpage]\n", uOrg, PGM_PAGE_GET_TRACKING(pPhysPage), pPhysPage ));
 
1421
}
 
1422
 
 
1423
 
 
1424
/**
 
1425
 * Moves the page to the head of the age list.
 
1426
 *
 
1427
 * This is done when the cached page is used in one way or another.
 
1428
 *
 
1429
 * @param   pPool       The pool.
 
1430
 * @param   pPage       The cached page.
 
1431
 */
 
1432
DECLINLINE(void) pgmPoolCacheUsed(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
 
1433
{
 
1434
    Assert(PGMIsLockOwner(pPool->CTX_SUFF(pVM)));
 
1435
 
 
1436
    /*
 
1437
     * Move to the head of the age list.
 
1438
     */
 
1439
    if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
 
1440
    {
 
1441
        /* unlink */
 
1442
        pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
 
1443
        if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
 
1444
            pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
 
1445
        else
 
1446
            pPool->iAgeTail = pPage->iAgePrev;
 
1447
 
 
1448
        /* insert at head */
 
1449
        pPage->iAgePrev = NIL_PGMPOOL_IDX;
 
1450
        pPage->iAgeNext = pPool->iAgeHead;
 
1451
        Assert(pPage->iAgeNext != NIL_PGMPOOL_IDX); /* we would've already been head then */
 
1452
        pPool->iAgeHead = pPage->idx;
 
1453
        pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->idx;
 
1454
    }
 
1455
}
 
1456
 
 
1457
/**
 
1458
 * Locks a page to prevent flushing (important for cr3 root pages or shadow pae pd pages).
 
1459
 *
 
1460
 * @param   pVM         VM Handle.
 
1461
 * @param   pPage       PGM pool page
 
1462
 */
 
1463
DECLINLINE(void) pgmPoolLockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
 
1464
{
 
1465
    Assert(PGMIsLockOwner(pPool->CTX_SUFF(pVM)));
 
1466
    ASMAtomicIncU32(&pPage->cLocked);
 
1467
}
 
1468
 
 
1469
 
 
1470
/**
 
1471
 * Unlocks a page to allow flushing again
 
1472
 *
 
1473
 * @param   pVM         VM Handle.
 
1474
 * @param   pPage       PGM pool page
 
1475
 */
 
1476
DECLINLINE(void) pgmPoolUnlockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
 
1477
{
 
1478
    Assert(PGMIsLockOwner(pPool->CTX_SUFF(pVM)));
 
1479
    Assert(pPage->cLocked);
 
1480
    ASMAtomicDecU32(&pPage->cLocked);
 
1481
}
 
1482
 
 
1483
 
 
1484
/**
 
1485
 * Checks if the page is locked (e.g. the active CR3 or one of the four PDs of a PAE PDPT)
 
1486
 *
 
1487
 * @returns VBox status code.
 
1488
 * @param   pPage       PGM pool page
 
1489
 */
 
1490
DECLINLINE(bool) pgmPoolIsPageLocked(PPGM pPGM, PPGMPOOLPAGE pPage)
 
1491
{
 
1492
    if (pPage->cLocked)
 
1493
    {
 
1494
        LogFlow(("pgmPoolIsPageLocked found root page %d\n", pPage->enmKind));
 
1495
        if (pPage->cModifications)
 
1496
            pPage->cModifications = 1; /* reset counter (can't use 0, or else it will be reinserted in the modified list) */
 
1497
        return true;
 
1498
    }
 
1499
    return false;
 
1500
}
 
1501
 
 
1502
 
 
1503
/**
 
1504
 * Tells if mappings are to be put into the shadow page table or not.
 
1505
 *
 
1506
 * @returns boolean result
 
1507
 * @param   pVM         VM handle.
 
1508
 */
 
1509
DECL_FORCE_INLINE(bool) pgmMapAreMappingsEnabled(PPGM pPGM)
 
1510
{
 
1511
#ifdef PGM_WITHOUT_MAPPINGS
 
1512
    /* There are no mappings in VT-x and AMD-V mode. */
 
1513
    Assert(pPGM->fMappingsDisabled);
 
1514
    return false;
 
1515
#else
 
1516
    return !pPGM->fMappingsDisabled;
 
1517
#endif
 
1518
}
 
1519
 
 
1520
 
 
1521
/**
 
1522
 * Checks if the mappings are floating and enabled.
 
1523
 *
 
1524
 * @returns true / false.
 
1525
 * @param   pVM         The VM handle.
 
1526
 */
 
1527
DECL_FORCE_INLINE(bool) pgmMapAreMappingsFloating(PPGM pPGM)
 
1528
{
 
1529
#ifdef PGM_WITHOUT_MAPPINGS
 
1530
    /* There are no mappings in VT-x and AMD-V mode. */
 
1531
    Assert(pPGM->fMappingsDisabled);
 
1532
    return false;
 
1533
#else
 
1534
    return !pPGM->fMappingsDisabled
 
1535
        && !pPGM->fMappingsFixed;
 
1536
#endif
 
1537
}
 
1538
 
 
1539
/** @} */
 
1540
 
 
1541
#endif
 
1542