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

« back to all changes in this revision

Viewing changes to src/VBox/VMM/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 $ */
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
 
 */
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
 
#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
 
 */
299
 
DECLINLINE(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
 
 */
337
 
DECLINLINE(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
 
 */
396
 
DECLINLINE(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
 
 */
455
 
DECLINLINE(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
 
 */
482
 
DECLINLINE(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
 
 */
509
 
DECLINLINE(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
 
 */
539
 
DECLINLINE(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
 
 */
564
 
DECLINLINE(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 page directory entry for the specified address (32-bit paging).
575
 
 *
576
 
 * @returns The page directory entry in question.
577
 
 * @param   pPGM        Pointer to the PGM instance data.
578
 
 * @param   GCPtr       The address.
579
 
 */
580
 
DECLINLINE(X86PDE) pgmGstGet32bitPDE(PPGMCPU pPGM, RTGCPTR GCPtr)
581
 
{
582
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
583
 
    PCX86PD pGuestPD = NULL;
584
 
    int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pPGM->GCPhysCR3, (void **)&pGuestPD);
585
 
    if (RT_FAILURE(rc))
586
 
    {
587
 
        X86PDE ZeroPde = {0};
588
 
        AssertMsgFailedReturn(("%Rrc\n", rc), ZeroPde);
589
 
    }
590
 
#else
591
 
    PX86PD pGuestPD = pPGM->CTX_SUFF(pGst32BitPd);
592
 
# ifdef IN_RING3
593
 
    if (!pGuestPD)
594
 
        pGuestPD = pgmGstLazyMap32BitPD(pPGM);
595
 
# endif
596
 
#endif
597
 
    return pGuestPD->a[GCPtr >> X86_PD_SHIFT];
598
 
}
599
 
 
600
 
 
601
 
/**
602
 
 * Gets the address of a specific page directory entry (32-bit paging).
603
 
 *
604
 
 * @returns Pointer the page directory entry in question.
605
 
 * @param   pPGM        Pointer to the PGM instance data.
606
 
 * @param   GCPtr       The address.
607
 
 */
608
 
DECLINLINE(PX86PDE) pgmGstGet32bitPDEPtr(PPGMCPU pPGM, RTGCPTR GCPtr)
609
 
{
610
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
611
 
    PX86PD  pGuestPD = NULL;
612
 
    int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pPGM->GCPhysCR3, (void **)&pGuestPD);
613
 
    AssertRCReturn(rc, NULL);
614
 
#else
615
 
    PX86PD pGuestPD = pPGM->CTX_SUFF(pGst32BitPd);
616
 
# ifdef IN_RING3
617
 
    if (!pGuestPD)
618
 
        pGuestPD = pgmGstLazyMap32BitPD(pPGM);
619
 
# endif
620
 
#endif
621
 
    return &pGuestPD->a[GCPtr >> X86_PD_SHIFT];
622
 
}
623
 
 
624
 
 
625
 
/**
626
 
 * Gets the address the guest page directory (32-bit paging).
627
 
 *
628
 
 * @returns Pointer the page directory entry in question.
629
 
 * @param   pPGM        Pointer to the PGM instance data.
630
 
 */
631
 
DECLINLINE(PX86PD) pgmGstGet32bitPDPtr(PPGMCPU pPGM)
632
 
{
633
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
634
 
    PX86PD  pGuestPD = NULL;
635
 
    int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pPGM->GCPhysCR3, (void **)&pGuestPD);
636
 
    AssertRCReturn(rc, NULL);
637
 
#else
638
 
    PX86PD pGuestPD = pPGM->CTX_SUFF(pGst32BitPd);
639
 
# ifdef IN_RING3
640
 
    if (!pGuestPD)
641
 
        pGuestPD = pgmGstLazyMap32BitPD(pPGM);
642
 
# endif
643
 
#endif
644
 
    return pGuestPD;
645
 
}
646
 
 
647
 
 
648
 
/**
649
 
 * Gets the guest page directory pointer table.
650
 
 *
651
 
 * @returns Pointer to the page directory in question.
652
 
 * @returns NULL if the page directory is not present or on an invalid page.
653
 
 * @param   pPGM        Pointer to the PGM instance data.
654
 
 */
655
 
DECLINLINE(PX86PDPT) pgmGstGetPaePDPTPtr(PPGMCPU pPGM)
656
 
{
657
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
658
 
    PX86PDPT pGuestPDPT = NULL;
659
 
    int rc = pgmR0DynMapGCPageOffInlined(PGMCPU2PGM(pPGM), pPGM->GCPhysCR3, (void **)&pGuestPDPT);
660
 
    AssertRCReturn(rc, NULL);
661
 
#else
662
 
    PX86PDPT pGuestPDPT = pPGM->CTX_SUFF(pGstPaePdpt);
663
 
# ifdef IN_RING3
664
 
    if (!pGuestPDPT)
665
 
        pGuestPDPT = pgmGstLazyMapPaePDPT(pPGM);
666
 
# endif
667
 
#endif
668
 
    return pGuestPDPT;
669
 
}
670
 
 
671
 
 
672
 
/**
673
 
 * Gets the guest page directory pointer table entry for the specified address.
674
 
 *
675
 
 * @returns Pointer to the page directory in question.
676
 
 * @returns NULL if the page directory is not present or on an invalid page.
677
 
 * @param   pPGM        Pointer to the PGM instance data.
678
 
 * @param   GCPtr       The address.
679
 
 */
680
 
DECLINLINE(PX86PDPE) pgmGstGetPaePDPEPtr(PPGMCPU pPGM, RTGCPTR GCPtr)
681
 
{
682
 
    AssertGCPtr32(GCPtr);
683
 
 
684
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
685
 
    PX86PDPT pGuestPDPT = 0;
686
 
    int rc = pgmR0DynMapGCPageOffInlined(PGMCPU2PGM(pPGM), pPGM->GCPhysCR3, (void **)&pGuestPDPT);
687
 
    AssertRCReturn(rc, 0);
688
 
#else
689
 
    PX86PDPT pGuestPDPT = pPGM->CTX_SUFF(pGstPaePdpt);
690
 
# ifdef IN_RING3
691
 
    if (!pGuestPDPT)
692
 
        pGuestPDPT = pgmGstLazyMapPaePDPT(pPGM);
693
 
# endif
694
 
#endif
695
 
    return &pGuestPDPT->a[(GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE];
696
 
}
697
 
 
698
 
 
699
 
/**
700
 
 * Gets the page directory for the specified address.
701
 
 *
702
 
 * @returns Pointer to the page directory in question.
703
 
 * @returns NULL if the page directory is not present or on an invalid page.
704
 
 * @param   pPGM        Pointer to the PGM instance data.
705
 
 * @param   GCPtr       The address.
706
 
 */
707
 
DECLINLINE(PX86PDPAE) pgmGstGetPaePD(PPGMCPU pPGM, RTGCPTR GCPtr)
708
 
{
709
 
    AssertGCPtr32(GCPtr);
710
 
 
711
 
    PX86PDPT        pGuestPDPT = pgmGstGetPaePDPTPtr(pPGM);
712
 
    AssertReturn(pGuestPDPT, NULL);
713
 
    const unsigned  iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
714
 
    if (pGuestPDPT->a[iPdpt].n.u1Present)
715
 
    {
716
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
717
 
        PX86PDPAE   pGuestPD = NULL;
718
 
        int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK, (void **)&pGuestPD);
719
 
        AssertRCReturn(rc, NULL);
720
 
#else
721
 
        PX86PDPAE   pGuestPD = pPGM->CTX_SUFF(apGstPaePDs)[iPdpt];
722
 
        if (    !pGuestPD
723
 
            ||  (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pPGM->aGCPhysGstPaePDs[iPdpt])
724
 
            pGuestPD = pgmGstLazyMapPaePD(pPGM, iPdpt);
725
 
#endif
726
 
        return pGuestPD;
727
 
        /* returning NULL is ok if we assume it's just an invalid page of some kind emulated as all 0s. (not quite true) */
728
 
    }
729
 
    return NULL;
730
 
}
731
 
 
732
 
 
733
 
/**
734
 
 * Gets the page directory entry for the specified address.
735
 
 *
736
 
 * @returns Pointer to the page directory entry in question.
737
 
 * @returns NULL if the page directory is not present or on an invalid page.
738
 
 * @param   pPGM        Pointer to the PGM instance data.
739
 
 * @param   GCPtr       The address.
740
 
 */
741
 
DECLINLINE(PX86PDEPAE) pgmGstGetPaePDEPtr(PPGMCPU pPGM, RTGCPTR GCPtr)
742
 
{
743
 
    AssertGCPtr32(GCPtr);
744
 
 
745
 
    PX86PDPT        pGuestPDPT = pgmGstGetPaePDPTPtr(pPGM);
746
 
    AssertReturn(pGuestPDPT, NULL);
747
 
    const unsigned  iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
748
 
    if (pGuestPDPT->a[iPdpt].n.u1Present)
749
 
    {
750
 
        const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
751
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
752
 
        PX86PDPAE   pGuestPD = NULL;
753
 
        int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK, (void **)&pGuestPD);
754
 
        AssertRCReturn(rc, NULL);
755
 
#else
756
 
        PX86PDPAE   pGuestPD = pPGM->CTX_SUFF(apGstPaePDs)[iPdpt];
757
 
        if (    !pGuestPD
758
 
            ||  (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pPGM->aGCPhysGstPaePDs[iPdpt])
759
 
            pGuestPD = pgmGstLazyMapPaePD(pPGM, iPdpt);
760
 
#endif
761
 
        return &pGuestPD->a[iPD];
762
 
        /* returning NIL_RTGCPHYS is ok if we assume it's just an invalid page or something which we'll emulate as all 0s. (not quite true) */
763
 
    }
764
 
    return NULL;
765
 
}
766
 
 
767
 
 
768
 
/**
769
 
 * Gets the page directory entry for the specified address.
770
 
 *
771
 
 * @returns The page directory entry in question.
772
 
 * @returns A non-present entry if the page directory is not present or on an invalid page.
773
 
 * @param   pPGM        Pointer to the PGM instance data.
774
 
 * @param   GCPtr       The address.
775
 
 */
776
 
DECLINLINE(X86PDEPAE) pgmGstGetPaePDE(PPGMCPU pPGM, RTGCPTR GCPtr)
777
 
{
778
 
    AssertGCPtr32(GCPtr);
779
 
    X86PDEPAE   ZeroPde = {0};
780
 
    PX86PDPT    pGuestPDPT = pgmGstGetPaePDPTPtr(pPGM);
781
 
    if (RT_LIKELY(pGuestPDPT))
782
 
    {
783
 
        const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
784
 
        if (pGuestPDPT->a[iPdpt].n.u1Present)
785
 
        {
786
 
            const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
787
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
788
 
            PX86PDPAE   pGuestPD = NULL;
789
 
            int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK, (void **)&pGuestPD);
790
 
            AssertRCReturn(rc, ZeroPde);
791
 
#else
792
 
            PX86PDPAE   pGuestPD = pPGM->CTX_SUFF(apGstPaePDs)[iPdpt];
793
 
            if (    !pGuestPD
794
 
                ||  (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pPGM->aGCPhysGstPaePDs[iPdpt])
795
 
                pGuestPD = pgmGstLazyMapPaePD(pPGM, iPdpt);
796
 
#endif
797
 
            return pGuestPD->a[iPD];
798
 
        }
799
 
    }
800
 
    return ZeroPde;
801
 
}
802
 
 
803
 
 
804
 
/**
805
 
 * Gets the page directory pointer table entry for the specified address
806
 
 * and returns the index into the page directory
807
 
 *
808
 
 * @returns Pointer to the page directory in question.
809
 
 * @returns NULL if the page directory is not present or on an invalid page.
810
 
 * @param   pPGM        Pointer to the PGM instance data.
811
 
 * @param   GCPtr       The address.
812
 
 * @param   piPD        Receives the index into the returned page directory
813
 
 * @param   pPdpe       Receives the page directory pointer entry. Optional.
814
 
 */
815
 
DECLINLINE(PX86PDPAE) pgmGstGetPaePDPtr(PPGMCPU pPGM, RTGCPTR GCPtr, unsigned *piPD, PX86PDPE pPdpe)
816
 
{
817
 
    AssertGCPtr32(GCPtr);
818
 
 
819
 
    PX86PDPT        pGuestPDPT = pgmGstGetPaePDPTPtr(pPGM);
820
 
    AssertReturn(pGuestPDPT, NULL);
821
 
    const unsigned  iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
822
 
    if (pPdpe)
823
 
        *pPdpe = pGuestPDPT->a[iPdpt];
824
 
    if (pGuestPDPT->a[iPdpt].n.u1Present)
825
 
    {
826
 
        const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
827
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
828
 
        PX86PDPAE   pGuestPD = NULL;
829
 
        int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK, (void **)&pGuestPD);
830
 
        AssertRCReturn(rc, NULL);
831
 
#else
832
 
        PX86PDPAE   pGuestPD = pPGM->CTX_SUFF(apGstPaePDs)[iPdpt];
833
 
        if (    !pGuestPD
834
 
            ||  (pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK) != pPGM->aGCPhysGstPaePDs[iPdpt])
835
 
            pGuestPD = pgmGstLazyMapPaePD(pPGM, iPdpt);
836
 
#endif
837
 
        *piPD = iPD;
838
 
        return pGuestPD;
839
 
        /* returning NIL_RTGCPHYS is ok if we assume it's just an invalid page of some kind emulated as all 0s. */
840
 
    }
841
 
    return NULL;
842
 
}
843
 
 
844
 
#ifndef IN_RC
845
 
 
846
 
/**
847
 
 * Gets the page map level-4 pointer for the guest.
848
 
 *
849
 
 * @returns Pointer to the PML4 page.
850
 
 * @param   pPGM        Pointer to the PGM instance data.
851
 
 */
852
 
DECLINLINE(PX86PML4) pgmGstGetLongModePML4Ptr(PPGMCPU pPGM)
853
 
{
854
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
855
 
    PX86PML4 pGuestPml4;
856
 
    int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pPGM->GCPhysCR3, (void **)&pGuestPml4);
857
 
    AssertRCReturn(rc, NULL);
858
 
#else
859
 
    PX86PML4 pGuestPml4 = pPGM->CTX_SUFF(pGstAmd64Pml4);
860
 
# ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R3
861
 
    if (!pGuestPml4)
862
 
        pGuestPml4 = pgmGstLazyMapPml4(pPGM);
863
 
# endif
864
 
    Assert(pGuestPml4);
865
 
#endif
866
 
    return pGuestPml4;
867
 
}
868
 
 
869
 
 
870
 
/**
871
 
 * Gets the pointer to a page map level-4 entry.
872
 
 *
873
 
 * @returns Pointer to the PML4 entry.
874
 
 * @param   pPGM        Pointer to the PGM instance data.
875
 
 * @param   iPml4       The index.
876
 
 */
877
 
DECLINLINE(PX86PML4E) pgmGstGetLongModePML4EPtr(PPGMCPU pPGM, unsigned int iPml4)
878
 
{
879
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
880
 
    PX86PML4 pGuestPml4;
881
 
    int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pPGM->GCPhysCR3, (void **)&pGuestPml4);
882
 
    AssertRCReturn(rc, NULL);
883
 
#else
884
 
    PX86PML4 pGuestPml4 = pPGM->CTX_SUFF(pGstAmd64Pml4);
885
 
# ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R3
886
 
    if (!pGuestPml4)
887
 
        pGuestPml4 = pgmGstLazyMapPml4(pPGM);
888
 
# endif
889
 
    Assert(pGuestPml4);
890
 
#endif
891
 
    return &pGuestPml4->a[iPml4];
892
 
}
893
 
 
894
 
 
895
 
/**
896
 
 * Gets a page map level-4 entry.
897
 
 *
898
 
 * @returns The PML4 entry.
899
 
 * @param   pPGM        Pointer to the PGM instance data.
900
 
 * @param   iPml4       The index.
901
 
 */
902
 
DECLINLINE(X86PML4E) pgmGstGetLongModePML4E(PPGMCPU pPGM, unsigned int iPml4)
903
 
{
904
 
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
905
 
    PX86PML4 pGuestPml4;
906
 
    int rc = pgmR0DynMapGCPageInlined(PGMCPU2PGM(pPGM), pPGM->GCPhysCR3, (void **)&pGuestPml4);
907
 
    if (RT_FAILURE(rc))
908
 
    {
909
 
        X86PML4E ZeroPml4e = {0};
910
 
        AssertMsgFailedReturn(("%Rrc\n", rc), ZeroPml4e);
911
 
    }
912
 
#else
913
 
    PX86PML4 pGuestPml4 = pPGM->CTX_SUFF(pGstAmd64Pml4);
914
 
# ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R3
915
 
    if (!pGuestPml4)
916
 
        pGuestPml4 = pgmGstLazyMapPml4(pPGM);
917
 
# endif
918
 
    Assert(pGuestPml4);
919
 
#endif
920
 
    return pGuestPml4->a[iPml4];
921
 
}
922
 
 
923
 
 
924
 
/**
925
 
 * Gets the page directory pointer entry for the specified address.
926
 
 *
927
 
 * @returns Pointer to the page directory pointer entry in question.
928
 
 * @returns NULL if the page directory is not present or on an invalid page.
929
 
 * @param   pPGM        Pointer to the PGM instance data.
930
 
 * @param   GCPtr       The address.
931
 
 * @param   ppPml4e     Page Map Level-4 Entry (out)
932
 
 */
933
 
DECLINLINE(PX86PDPE) pgmGstGetLongModePDPTPtr(PPGMCPU pPGM, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e)
934
 
{
935
 
    PX86PML4        pGuestPml4 = pgmGstGetLongModePML4Ptr(pPGM);
936
 
    const unsigned  iPml4  = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
937
 
    PCX86PML4E      pPml4e = *ppPml4e = &pGuestPml4->a[iPml4];
938
 
    if (pPml4e->n.u1Present)
939
 
    {
940
 
        PX86PDPT pPdpt;
941
 
        int rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pPml4e->u & X86_PML4E_PG_MASK, &pPdpt);
942
 
        AssertRCReturn(rc, NULL);
943
 
 
944
 
        const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
945
 
        return &pPdpt->a[iPdpt];
946
 
    }
947
 
    return NULL;
948
 
}
949
 
 
950
 
 
951
 
/**
952
 
 * Gets the page directory entry for the specified address.
953
 
 *
954
 
 * @returns The page directory entry in question.
955
 
 * @returns A non-present entry if the page directory is not present or on an invalid page.
956
 
 * @param   pPGM        Pointer to the PGM instance data.
957
 
 * @param   GCPtr       The address.
958
 
 * @param   ppPml4e     Page Map Level-4 Entry (out)
959
 
 * @param   pPdpe       Page directory pointer table entry (out)
960
 
 */
961
 
DECLINLINE(X86PDEPAE) pgmGstGetLongModePDEEx(PPGMCPU pPGM, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPE pPdpe)
962
 
{
963
 
    X86PDEPAE       ZeroPde = {0};
964
 
    PX86PML4        pGuestPml4 = pgmGstGetLongModePML4Ptr(pPGM);
965
 
    const unsigned  iPml4  = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
966
 
    PCX86PML4E      pPml4e = *ppPml4e = &pGuestPml4->a[iPml4];
967
 
    if (pPml4e->n.u1Present)
968
 
    {
969
 
        PCX86PDPT   pPdptTemp;
970
 
        int rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pPml4e->u & X86_PML4E_PG_MASK, &pPdptTemp);
971
 
        AssertRCReturn(rc, ZeroPde);
972
 
 
973
 
        const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
974
 
        *pPdpe = pPdptTemp->a[iPdpt];
975
 
        if (pPdptTemp->a[iPdpt].n.u1Present)
976
 
        {
977
 
            PCX86PDPAE pPD;
978
 
            rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
979
 
            AssertRCReturn(rc, ZeroPde);
980
 
 
981
 
            const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
982
 
            return pPD->a[iPD];
983
 
        }
984
 
    }
985
 
 
986
 
    return ZeroPde;
987
 
}
988
 
 
989
 
 
990
 
/**
991
 
 * Gets the page directory entry for the specified address.
992
 
 *
993
 
 * @returns The page directory entry in question.
994
 
 * @returns A non-present entry if the page directory is not present or on an invalid page.
995
 
 * @param   pPGM        Pointer to the PGM instance data.
996
 
 * @param   GCPtr       The address.
997
 
 */
998
 
DECLINLINE(X86PDEPAE) pgmGstGetLongModePDE(PPGMCPU pPGM, RTGCPTR64 GCPtr)
999
 
{
1000
 
    X86PDEPAE       ZeroPde = {0};
1001
 
    PCX86PML4       pGuestPml4 = pgmGstGetLongModePML4Ptr(pPGM);
1002
 
    const unsigned  iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1003
 
    if (pGuestPml4->a[iPml4].n.u1Present)
1004
 
    {
1005
 
        PCX86PDPT   pPdptTemp;
1006
 
        int rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pGuestPml4->a[iPml4].u & X86_PML4E_PG_MASK, &pPdptTemp);
1007
 
        AssertRCReturn(rc, ZeroPde);
1008
 
 
1009
 
        const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1010
 
        if (pPdptTemp->a[iPdpt].n.u1Present)
1011
 
        {
1012
 
            PCX86PDPAE pPD;
1013
 
            rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
1014
 
            AssertRCReturn(rc, ZeroPde);
1015
 
 
1016
 
            const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
1017
 
            return pPD->a[iPD];
1018
 
        }
1019
 
    }
1020
 
    return ZeroPde;
1021
 
}
1022
 
 
1023
 
 
1024
 
/**
1025
 
 * Gets the page directory entry for the specified address.
1026
 
 *
1027
 
 * @returns Pointer to the page directory entry in question.
1028
 
 * @returns NULL if the page directory is not present or on an invalid page.
1029
 
 * @param   pPGM        Pointer to the PGM instance data.
1030
 
 * @param   GCPtr       The address.
1031
 
 */
1032
 
DECLINLINE(PX86PDEPAE) pgmGstGetLongModePDEPtr(PPGMCPU pPGM, RTGCPTR64 GCPtr)
1033
 
{
1034
 
    PCX86PML4       pGuestPml4 = pgmGstGetLongModePML4Ptr(pPGM);
1035
 
    const unsigned  iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1036
 
    if (pGuestPml4->a[iPml4].n.u1Present)
1037
 
    {
1038
 
        PCX86PDPT   pPdptTemp;
1039
 
        int rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pGuestPml4->a[iPml4].u & X86_PML4E_PG_MASK, &pPdptTemp);
1040
 
        AssertRCReturn(rc, NULL);
1041
 
 
1042
 
        const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1043
 
        if (pPdptTemp->a[iPdpt].n.u1Present)
1044
 
        {
1045
 
            PX86PDPAE pPD;
1046
 
            rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
1047
 
            AssertRCReturn(rc, NULL);
1048
 
 
1049
 
            const unsigned iPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
1050
 
            return &pPD->a[iPD];
1051
 
        }
1052
 
    }
1053
 
    return NULL;
1054
 
}
1055
 
 
1056
 
 
1057
 
/**
1058
 
 * Gets the GUEST page directory pointer for the specified address.
1059
 
 *
1060
 
 * @returns The page directory in question.
1061
 
 * @returns NULL if the page directory is not present or on an invalid page.
1062
 
 * @param   pPGM        Pointer to the PGM instance data.
1063
 
 * @param   GCPtr       The address.
1064
 
 * @param   ppPml4e     Page Map Level-4 Entry (out)
1065
 
 * @param   pPdpe       Page directory pointer table entry (out)
1066
 
 * @param   piPD        Receives the index into the returned page directory
1067
 
 */
1068
 
DECLINLINE(PX86PDPAE) pgmGstGetLongModePDPtr(PPGMCPU pPGM, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPE pPdpe, unsigned *piPD)
1069
 
{
1070
 
    PX86PML4        pGuestPml4 = pgmGstGetLongModePML4Ptr(pPGM);
1071
 
    const unsigned  iPml4  = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1072
 
    PCX86PML4E      pPml4e = *ppPml4e = &pGuestPml4->a[iPml4];
1073
 
    if (pPml4e->n.u1Present)
1074
 
    {
1075
 
        PCX86PDPT   pPdptTemp;
1076
 
        int rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pPml4e->u & X86_PML4E_PG_MASK, &pPdptTemp);
1077
 
        AssertRCReturn(rc, NULL);
1078
 
 
1079
 
        const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1080
 
        *pPdpe = pPdptTemp->a[iPdpt];
1081
 
        if (pPdptTemp->a[iPdpt].n.u1Present)
1082
 
        {
1083
 
            PX86PDPAE pPD;
1084
 
            rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
1085
 
            AssertRCReturn(rc, NULL);
1086
 
 
1087
 
            *piPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
1088
 
            return pPD;
1089
 
        }
1090
 
    }
1091
 
    return 0;
1092
 
}
1093
 
 
1094
 
#endif /* !IN_RC */
1095
 
 
1096
 
/**
1097
 
 * Gets the shadow page directory, 32-bit.
1098
 
 *
1099
 
 * @returns Pointer to the shadow 32-bit PD.
1100
 
 * @param   pPGM        Pointer to the PGM instance data.
1101
 
 */
1102
 
DECLINLINE(PX86PD) pgmShwGet32BitPDPtr(PPGMCPU pPGM)
1103
 
{
1104
 
    return (PX86PD)PGMPOOL_PAGE_2_PTR_BY_PGMCPU(pPGM, pPGM->CTX_SUFF(pShwPageCR3));
1105
 
}
1106
 
 
1107
 
 
1108
 
/**
1109
 
 * Gets the shadow page directory entry for the specified address, 32-bit.
1110
 
 *
1111
 
 * @returns Shadow 32-bit PDE.
1112
 
 * @param   pPGM        Pointer to the PGM instance data.
1113
 
 * @param   GCPtr       The address.
1114
 
 */
1115
 
DECLINLINE(X86PDE) pgmShwGet32BitPDE(PPGMCPU pPGM, RTGCPTR GCPtr)
1116
 
{
1117
 
    const unsigned iPd = (GCPtr >> X86_PD_SHIFT) & X86_PD_MASK;
1118
 
 
1119
 
    PX86PD pShwPde = pgmShwGet32BitPDPtr(pPGM);
1120
 
    if (!pShwPde)
1121
 
    {
1122
 
        X86PDE ZeroPde = {0};
1123
 
        return ZeroPde;
1124
 
    }
1125
 
    return pShwPde->a[iPd];
1126
 
}
1127
 
 
1128
 
 
1129
 
/**
1130
 
 * Gets the pointer to the shadow page directory entry for the specified
1131
 
 * address, 32-bit.
1132
 
 *
1133
 
 * @returns Pointer to the shadow 32-bit PDE.
1134
 
 * @param   pPGM        Pointer to the PGM instance data.
1135
 
 * @param   GCPtr       The address.
1136
 
 */
1137
 
DECLINLINE(PX86PDE) pgmShwGet32BitPDEPtr(PPGMCPU pPGM, RTGCPTR GCPtr)
1138
 
{
1139
 
    const unsigned iPd = (GCPtr >> X86_PD_SHIFT) & X86_PD_MASK;
1140
 
 
1141
 
    PX86PD pPde = pgmShwGet32BitPDPtr(pPGM);
1142
 
    AssertReturn(pPde, NULL);
1143
 
    return &pPde->a[iPd];
1144
 
}
1145
 
 
1146
 
 
1147
 
/**
1148
 
 * Gets the shadow page pointer table, PAE.
1149
 
 *
1150
 
 * @returns Pointer to the shadow PAE PDPT.
1151
 
 * @param   pPGM        Pointer to the PGM instance data.
1152
 
 */
1153
 
DECLINLINE(PX86PDPT) pgmShwGetPaePDPTPtr(PPGMCPU pPGM)
1154
 
{
1155
 
    return (PX86PDPT)PGMPOOL_PAGE_2_PTR_BY_PGMCPU(pPGM, pPGM->CTX_SUFF(pShwPageCR3));
1156
 
}
1157
 
 
1158
 
 
1159
 
/**
1160
 
 * Gets the shadow page directory for the specified address, PAE.
1161
 
 *
1162
 
 * @returns Pointer to the shadow PD.
1163
 
 * @param   pPGM        Pointer to the PGM instance data.
1164
 
 * @param   GCPtr       The address.
1165
 
 */
1166
 
DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PPGMCPU pPGM, RTGCPTR GCPtr)
1167
 
{
1168
 
    const unsigned  iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
1169
 
    PX86PDPT        pPdpt = pgmShwGetPaePDPTPtr(pPGM);
1170
 
 
1171
 
    if (!pPdpt->a[iPdpt].n.u1Present)
1172
 
        return NULL;
1173
 
 
1174
 
    /* Fetch the pgm pool shadow descriptor. */
1175
 
    PPGMPOOLPAGE pShwPde = pgmPoolGetPage(PGMCPU2PGM(pPGM)->CTX_SUFF(pPool), pPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
1176
 
    AssertReturn(pShwPde, NULL);
1177
 
 
1178
 
    return (PX86PDPAE)PGMPOOL_PAGE_2_PTR_BY_PGMCPU(pPGM, pShwPde);
1179
 
}
1180
 
 
1181
 
 
1182
 
/**
1183
 
 * Gets the shadow page directory for the specified address, PAE.
1184
 
 *
1185
 
 * @returns Pointer to the shadow PD.
1186
 
 * @param   pPGM        Pointer to the PGM instance data.
1187
 
 * @param   GCPtr       The address.
1188
 
 */
1189
 
DECLINLINE(PX86PDPAE) pgmShwGetPaePDPtr(PPGMCPU pPGM, PX86PDPT pPdpt, RTGCPTR GCPtr)
1190
 
{
1191
 
    const unsigned  iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
1192
 
 
1193
 
    if (!pPdpt->a[iPdpt].n.u1Present)
1194
 
        return NULL;
1195
 
 
1196
 
    /* Fetch the pgm pool shadow descriptor. */
1197
 
    PPGMPOOLPAGE    pShwPde = pgmPoolGetPage(PGMCPU2PGM(pPGM)->CTX_SUFF(pPool), pPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
1198
 
    AssertReturn(pShwPde, NULL);
1199
 
 
1200
 
    return (PX86PDPAE)PGMPOOL_PAGE_2_PTR_BY_PGMCPU(pPGM, pShwPde);
1201
 
}
1202
 
 
1203
 
 
1204
 
/**
1205
 
 * Gets the shadow page directory entry, PAE.
1206
 
 *
1207
 
 * @returns PDE.
1208
 
 * @param   pPGM        Pointer to the PGM instance data.
1209
 
 * @param   GCPtr       The address.
1210
 
 */
1211
 
DECLINLINE(X86PDEPAE) pgmShwGetPaePDE(PPGMCPU pPGM, RTGCPTR GCPtr)
1212
 
{
1213
 
    const unsigned  iPd   = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
1214
 
 
1215
 
    PX86PDPAE pShwPde = pgmShwGetPaePDPtr(pPGM, GCPtr);
1216
 
    if (!pShwPde)
1217
 
    {
1218
 
        X86PDEPAE ZeroPde = {0};
1219
 
        return ZeroPde;
1220
 
    }
1221
 
    return pShwPde->a[iPd];
1222
 
}
1223
 
 
1224
 
 
1225
 
/**
1226
 
 * Gets the pointer to the shadow page directory entry for an address, PAE.
1227
 
 *
1228
 
 * @returns Pointer to the PDE.
1229
 
 * @param   pPGM        Pointer to the PGM instance data.
1230
 
 * @param   GCPtr       The address.
1231
 
 */
1232
 
DECLINLINE(PX86PDEPAE) pgmShwGetPaePDEPtr(PPGMCPU pPGM, RTGCPTR GCPtr)
1233
 
{
1234
 
    const unsigned  iPd   = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
1235
 
 
1236
 
    PX86PDPAE pPde = pgmShwGetPaePDPtr(pPGM, GCPtr);
1237
 
    AssertReturn(pPde, NULL);
1238
 
    return &pPde->a[iPd];
1239
 
}
1240
 
 
1241
 
#ifndef IN_RC
1242
 
 
1243
 
/**
1244
 
 * Gets the shadow page map level-4 pointer.
1245
 
 *
1246
 
 * @returns Pointer to the shadow PML4.
1247
 
 * @param   pPGM        Pointer to the PGM instance data.
1248
 
 */
1249
 
DECLINLINE(PX86PML4) pgmShwGetLongModePML4Ptr(PPGMCPU pPGM)
1250
 
{
1251
 
    return (PX86PML4)PGMPOOL_PAGE_2_PTR_BY_PGMCPU(pPGM, pPGM->CTX_SUFF(pShwPageCR3));
1252
 
}
1253
 
 
1254
 
 
1255
 
/**
1256
 
 * Gets the shadow page map level-4 entry for the specified address.
1257
 
 *
1258
 
 * @returns The entry.
1259
 
 * @param   pPGM        Pointer to the PGM instance data.
1260
 
 * @param   GCPtr       The address.
1261
 
 */
1262
 
DECLINLINE(X86PML4E) pgmShwGetLongModePML4E(PPGMCPU pPGM, RTGCPTR GCPtr)
1263
 
{
1264
 
    const unsigned  iPml4 = ((RTGCUINTPTR64)GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1265
 
    PX86PML4        pShwPml4 = pgmShwGetLongModePML4Ptr(pPGM);
1266
 
 
1267
 
    if (!pShwPml4)
1268
 
    {
1269
 
        X86PML4E ZeroPml4e = {0};
1270
 
        return ZeroPml4e;
1271
 
    }
1272
 
    return pShwPml4->a[iPml4];
1273
 
}
1274
 
 
1275
 
 
1276
 
/**
1277
 
 * Gets the pointer to the specified shadow page map level-4 entry.
1278
 
 *
1279
 
 * @returns The entry.
1280
 
 * @param   pPGM        Pointer to the PGM instance data.
1281
 
 * @param   iPml4       The PML4 index.
1282
 
 */
1283
 
DECLINLINE(PX86PML4E) pgmShwGetLongModePML4EPtr(PPGMCPU pPGM, unsigned int iPml4)
1284
 
{
1285
 
    PX86PML4 pShwPml4 = pgmShwGetLongModePML4Ptr(pPGM);
1286
 
    if (!pShwPml4)
1287
 
        return NULL;
1288
 
    return &pShwPml4->a[iPml4];
1289
 
}
1290
 
 
1291
 
 
1292
 
/**
1293
 
 * Gets the GUEST page directory pointer for the specified address.
1294
 
 *
1295
 
 * @returns The page directory in question.
1296
 
 * @returns NULL if the page directory is not present or on an invalid page.
1297
 
 * @param   pPGM        Pointer to the PGM instance data.
1298
 
 * @param   GCPtr       The address.
1299
 
 * @param   piPD        Receives the index into the returned page directory
1300
 
 */
1301
 
DECLINLINE(PX86PDPAE) pgmGstGetLongModePDPtr(PPGMCPU pPGM, RTGCPTR64 GCPtr, unsigned *piPD)
1302
 
{
1303
 
    PCX86PML4       pGuestPml4 = pgmGstGetLongModePML4Ptr(pPGM);
1304
 
    const unsigned  iPml4  = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1305
 
    if (pGuestPml4->a[iPml4].n.u1Present)
1306
 
    {
1307
 
        PCX86PDPT   pPdptTemp;
1308
 
        int rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pGuestPml4->a[iPml4].u & X86_PML4E_PG_MASK, &pPdptTemp);
1309
 
        AssertRCReturn(rc, NULL);
1310
 
 
1311
 
        const unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1312
 
        if (pPdptTemp->a[iPdpt].n.u1Present)
1313
 
        {
1314
 
            PX86PDPAE pPD;
1315
 
            rc = PGM_GCPHYS_2_PTR_BY_PGMCPU(pPGM, pPdptTemp->a[iPdpt].u & X86_PDPE_PG_MASK, &pPD);
1316
 
            AssertRCReturn(rc, NULL);
1317
 
 
1318
 
            *piPD = (GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
1319
 
            return pPD;
1320
 
        }
1321
 
    }
1322
 
    return NULL;
1323
 
}
1324
 
 
1325
 
#endif /* !IN_RC */
1326
 
 
1327
 
/**
1328
 
 * Gets the page state for a physical handler.
1329
 
 *
1330
 
 * @returns The physical handler page state.
1331
 
 * @param   pCur    The physical handler in question.
1332
 
 */
1333
 
DECLINLINE(unsigned) pgmHandlerPhysicalCalcState(PPGMPHYSHANDLER pCur)
1334
 
{
1335
 
    switch (pCur->enmType)
1336
 
    {
1337
 
        case PGMPHYSHANDLERTYPE_PHYSICAL_WRITE:
1338
 
            return PGM_PAGE_HNDL_PHYS_STATE_WRITE;
1339
 
 
1340
 
        case PGMPHYSHANDLERTYPE_MMIO:
1341
 
        case PGMPHYSHANDLERTYPE_PHYSICAL_ALL:
1342
 
            return PGM_PAGE_HNDL_PHYS_STATE_ALL;
1343
 
 
1344
 
        default:
1345
 
            AssertFatalMsgFailed(("Invalid type %d\n", pCur->enmType));
1346
 
    }
1347
 
}
1348
 
 
1349
 
 
1350
 
/**
1351
 
 * Gets the page state for a virtual handler.
1352
 
 *
1353
 
 * @returns The virtual handler page state.
1354
 
 * @param   pCur    The virtual handler in question.
1355
 
 * @remarks This should never be used on a hypervisor access handler.
1356
 
 */
1357
 
DECLINLINE(unsigned) pgmHandlerVirtualCalcState(PPGMVIRTHANDLER pCur)
1358
 
{
1359
 
    switch (pCur->enmType)
1360
 
    {
1361
 
        case PGMVIRTHANDLERTYPE_WRITE:
1362
 
            return PGM_PAGE_HNDL_VIRT_STATE_WRITE;
1363
 
        case PGMVIRTHANDLERTYPE_ALL:
1364
 
            return PGM_PAGE_HNDL_VIRT_STATE_ALL;
1365
 
        default:
1366
 
            AssertFatalMsgFailed(("Invalid type %d\n", pCur->enmType));
1367
 
    }
1368
 
}
1369
 
 
1370
 
 
1371
 
/**
1372
 
 * Clears one physical page of a virtual handler
1373
 
 *
1374
 
 * @param   pPGM    Pointer to the PGM instance.
1375
 
 * @param   pCur    Virtual handler structure
1376
 
 * @param   iPage   Physical page index
1377
 
 *
1378
 
 * @remark  Only used when PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL is being set, so no
1379
 
 *          need to care about other handlers in the same page.
1380
 
 */
1381
 
DECLINLINE(void) pgmHandlerVirtualClearPage(PPGM pPGM, PPGMVIRTHANDLER pCur, unsigned iPage)
1382
 
{
1383
 
    const PPGMPHYS2VIRTHANDLER pPhys2Virt = &pCur->aPhysToVirt[iPage];
1384
 
 
1385
 
    /*
1386
 
     * Remove the node from the tree (it's supposed to be in the tree if we get here!).
1387
 
     */
1388
 
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1389
 
    AssertReleaseMsg(pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE,
1390
 
                     ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
1391
 
                      pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias));
1392
 
#endif
1393
 
    if (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_IS_HEAD)
1394
 
    {
1395
 
        /* We're the head of the alias chain. */
1396
 
        PPGMPHYS2VIRTHANDLER pRemove = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysRemove(&pPGM->CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key); NOREF(pRemove);
1397
 
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1398
 
        AssertReleaseMsg(pRemove != NULL,
1399
 
                         ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
1400
 
                          pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias));
1401
 
        AssertReleaseMsg(pRemove == pPhys2Virt,
1402
 
                         ("wanted: pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n"
1403
 
                          "   got:    pRemove=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
1404
 
                          pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias,
1405
 
                          pRemove, pRemove->Core.Key, pRemove->Core.KeyLast, pRemove->offVirtHandler, pRemove->offNextAlias));
1406
 
#endif
1407
 
        if (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK)
1408
 
        {
1409
 
            /* Insert the next list in the alias chain into the tree. */
1410
 
            PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
1411
 
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1412
 
            AssertReleaseMsg(pNext->offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE,
1413
 
                             ("pNext=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
1414
 
                             pNext, pNext->Core.Key, pNext->Core.KeyLast, pNext->offVirtHandler, pNext->offNextAlias));
1415
 
#endif
1416
 
            pNext->offNextAlias |= PGMPHYS2VIRTHANDLER_IS_HEAD;
1417
 
            bool fRc = RTAvlroGCPhysInsert(&pPGM->CTX_SUFF(pTrees)->PhysToVirtHandlers, &pNext->Core);
1418
 
            AssertRelease(fRc);
1419
 
        }
1420
 
    }
1421
 
    else
1422
 
    {
1423
 
        /* Locate the previous node in the alias chain. */
1424
 
        PPGMPHYS2VIRTHANDLER pPrev = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGet(&pPGM->CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key);
1425
 
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1426
 
        AssertReleaseMsg(pPrev != pPhys2Virt,
1427
 
                         ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} pPrev=%p\n",
1428
 
                          pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias, pPrev));
1429
 
#endif
1430
 
        for (;;)
1431
 
        {
1432
 
            PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPrev + (pPrev->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
1433
 
            if (pNext == pPhys2Virt)
1434
 
            {
1435
 
                /* unlink. */
1436
 
                LogFlow(("pgmHandlerVirtualClearPage: removed %p:{.offNextAlias=%#RX32} from alias chain. prev %p:{.offNextAlias=%#RX32} [%RGp-%RGp]\n",
1437
 
                         pPhys2Virt, pPhys2Virt->offNextAlias, pPrev, pPrev->offNextAlias, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast));
1438
 
                if (!(pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK))
1439
 
                    pPrev->offNextAlias &= ~PGMPHYS2VIRTHANDLER_OFF_MASK;
1440
 
                else
1441
 
                {
1442
 
                    PPGMPHYS2VIRTHANDLER pNewNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
1443
 
                    pPrev->offNextAlias = ((intptr_t)pNewNext - (intptr_t)pPrev)
1444
 
                                        | (pPrev->offNextAlias & ~PGMPHYS2VIRTHANDLER_OFF_MASK);
1445
 
                }
1446
 
                break;
1447
 
            }
1448
 
 
1449
 
            /* next */
1450
 
            if (pNext == pPrev)
1451
 
            {
1452
 
#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1453
 
                AssertReleaseMsg(pNext != pPrev,
1454
 
                                 ("pPhys2Virt=%p:{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} pPrev=%p\n",
1455
 
                                  pPhys2Virt, pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler, pPhys2Virt->offNextAlias, pPrev));
1456
 
#endif
1457
 
                break;
1458
 
            }
1459
 
            pPrev = pNext;
1460
 
        }
1461
 
    }
1462
 
    Log2(("PHYS2VIRT: Removing %RGp-%RGp %#RX32 %s\n",
1463
 
          pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias, R3STRING(pCur->pszDesc)));
1464
 
    pPhys2Virt->offNextAlias = 0;
1465
 
    pPhys2Virt->Core.KeyLast = NIL_RTGCPHYS; /* require reinsert */
1466
 
 
1467
 
    /*
1468
 
     * Clear the ram flags for this page.
1469
 
     */
1470
 
    PPGMPAGE pPage = pgmPhysGetPage(pPGM, pPhys2Virt->Core.Key);
1471
 
    AssertReturnVoid(pPage);
1472
 
    PGM_PAGE_SET_HNDL_VIRT_STATE(pPage, PGM_PAGE_HNDL_VIRT_STATE_NONE);
1473
 
}
1474
 
 
1475
 
 
1476
 
/**
1477
 
 * Internal worker for finding a 'in-use' shadow page give by it's physical address.
1478
 
 *
1479
 
 * @returns Pointer to the shadow page structure.
1480
 
 * @param   pPool       The pool.
1481
 
 * @param   idx         The pool page index.
1482
 
 */
1483
 
DECLINLINE(PPGMPOOLPAGE) pgmPoolGetPageByIdx(PPGMPOOL pPool, unsigned idx)
1484
 
{
1485
 
    AssertFatalMsg(idx >= PGMPOOL_IDX_FIRST && idx < pPool->cCurPages, ("idx=%d\n", idx));
1486
 
    return &pPool->aPages[idx];
1487
 
}
1488
 
 
1489
 
 
1490
 
/**
1491
 
 * Clear references to guest physical memory.
1492
 
 *
1493
 
 * @param   pPool       The pool.
1494
 
 * @param   pPoolPage   The pool page.
1495
 
 * @param   pPhysPage   The physical guest page tracking structure.
1496
 
 * @param   iPte        Shadow PTE index
1497
 
 */
1498
 
DECLINLINE(void) pgmTrackDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPoolPage, PPGMPAGE pPhysPage, uint16_t iPte)
1499
 
{
1500
 
    /*
1501
 
     * Just deal with the simple case here.
1502
 
     */
1503
 
# ifdef LOG_ENABLED
1504
 
    const unsigned uOrg = PGM_PAGE_GET_TRACKING(pPhysPage);
1505
 
# endif
1506
 
    const unsigned cRefs = PGM_PAGE_GET_TD_CREFS(pPhysPage);
1507
 
    if (cRefs == 1)
1508
 
    {
1509
 
        Assert(pPoolPage->idx == PGM_PAGE_GET_TD_IDX(pPhysPage));
1510
 
        Assert(iPte == PGM_PAGE_GET_PTE_INDEX(pPhysPage));
1511
 
        /* Invalidate the tracking data. */
1512
 
        PGM_PAGE_SET_TRACKING(pPhysPage, 0);
1513
 
    }
1514
 
    else
1515
 
        pgmPoolTrackPhysExtDerefGCPhys(pPool, pPoolPage, pPhysPage, iPte);
1516
 
    Log2(("pgmTrackDerefGCPhys: %x -> %x pPhysPage=%R[pgmpage]\n", uOrg, PGM_PAGE_GET_TRACKING(pPhysPage), pPhysPage ));
1517
 
}
1518
 
 
1519
 
 
1520
 
/**
1521
 
 * Moves the page to the head of the age list.
1522
 
 *
1523
 
 * This is done when the cached page is used in one way or another.
1524
 
 *
1525
 
 * @param   pPool       The pool.
1526
 
 * @param   pPage       The cached page.
1527
 
 */
1528
 
DECLINLINE(void) pgmPoolCacheUsed(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1529
 
{
1530
 
    PVM pVM = pPool->CTX_SUFF(pVM);
1531
 
    pgmLock(pVM);
1532
 
 
1533
 
    /*
1534
 
     * Move to the head of the age list.
1535
 
     */
1536
 
    if (pPage->iAgePrev != NIL_PGMPOOL_IDX)
1537
 
    {
1538
 
        /* unlink */
1539
 
        pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
1540
 
        if (pPage->iAgeNext != NIL_PGMPOOL_IDX)
1541
 
            pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
1542
 
        else
1543
 
            pPool->iAgeTail = pPage->iAgePrev;
1544
 
 
1545
 
        /* insert at head */
1546
 
        pPage->iAgePrev = NIL_PGMPOOL_IDX;
1547
 
        pPage->iAgeNext = pPool->iAgeHead;
1548
 
        Assert(pPage->iAgeNext != NIL_PGMPOOL_IDX); /* we would've already been head then */
1549
 
        pPool->iAgeHead = pPage->idx;
1550
 
        pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->idx;
1551
 
    }
1552
 
    pgmUnlock(pVM);
1553
 
}
1554
 
 
1555
 
/**
1556
 
 * Locks a page to prevent flushing (important for cr3 root pages or shadow pae pd pages).
1557
 
 *
1558
 
 * @param   pVM         VM Handle.
1559
 
 * @param   pPage       PGM pool page
1560
 
 */
1561
 
DECLINLINE(void) pgmPoolLockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1562
 
{
1563
 
    Assert(PGMIsLockOwner(pPool->CTX_SUFF(pVM)));
1564
 
    ASMAtomicIncU32(&pPage->cLocked);
1565
 
}
1566
 
 
1567
 
 
1568
 
/**
1569
 
 * Unlocks a page to allow flushing again
1570
 
 *
1571
 
 * @param   pVM         VM Handle.
1572
 
 * @param   pPage       PGM pool page
1573
 
 */
1574
 
DECLINLINE(void) pgmPoolUnlockPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1575
 
{
1576
 
    Assert(PGMIsLockOwner(pPool->CTX_SUFF(pVM)));
1577
 
    Assert(pPage->cLocked);
1578
 
    ASMAtomicDecU32(&pPage->cLocked);
1579
 
}
1580
 
 
1581
 
 
1582
 
/**
1583
 
 * Checks if the page is locked (e.g. the active CR3 or one of the four PDs of a PAE PDPT)
1584
 
 *
1585
 
 * @returns VBox status code.
1586
 
 * @param   pPage       PGM pool page
1587
 
 */
1588
 
DECLINLINE(bool) pgmPoolIsPageLocked(PPGM pPGM, PPGMPOOLPAGE pPage)
1589
 
{
1590
 
    if (pPage->cLocked)
1591
 
    {
1592
 
        LogFlow(("pgmPoolIsPageLocked found root page %d\n", pPage->enmKind));
1593
 
        if (pPage->cModifications)
1594
 
            pPage->cModifications = 1; /* reset counter (can't use 0, or else it will be reinserted in the modified list) */
1595
 
        return true;
1596
 
    }
1597
 
    return false;
1598
 
}
1599
 
 
1600
 
 
1601
 
/**
1602
 
 * Tells if mappings are to be put into the shadow page table or not.
1603
 
 *
1604
 
 * @returns boolean result
1605
 
 * @param   pVM         VM handle.
1606
 
 */
1607
 
DECL_FORCE_INLINE(bool) pgmMapAreMappingsEnabled(PPGM pPGM)
1608
 
{
1609
 
#ifdef PGM_WITHOUT_MAPPINGS
1610
 
    /* There are no mappings in VT-x and AMD-V mode. */
1611
 
    Assert(pPGM->fMappingsDisabled);
1612
 
    return false;
1613
 
#else
1614
 
    return !pPGM->fMappingsDisabled;
1615
 
#endif
1616
 
}
1617
 
 
1618
 
 
1619
 
/**
1620
 
 * Checks if the mappings are floating and enabled.
1621
 
 *
1622
 
 * @returns true / false.
1623
 
 * @param   pVM         The VM handle.
1624
 
 */
1625
 
DECL_FORCE_INLINE(bool) pgmMapAreMappingsFloating(PPGM pPGM)
1626
 
{
1627
 
#ifdef PGM_WITHOUT_MAPPINGS
1628
 
    /* There are no mappings in VT-x and AMD-V mode. */
1629
 
    Assert(pPGM->fMappingsDisabled);
1630
 
    return false;
1631
 
#else
1632
 
    return !pPGM->fMappingsDisabled
1633
 
        && !pPGM->fMappingsFixed;
1634
 
#endif
1635
 
}
1636
 
 
1637
 
/** @} */
1638
 
 
1639
 
#endif
1640