VirtualBox

source: vbox/trunk/src/VBox/VMM/PGM.cpp@ 1507

Last change on this file since 1507 was 1283, checked in by vboxsync, 18 years ago

Added support for the hybrid darwin setup where the kernel is 32-bit but the cpu *might* be running in 64-bit mode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 157.3 KB
Line 
1/* $Id: PGM.cpp 1283 2007-03-07 00:02:11Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor. (Mixing stuff here, not good?)
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/** @page pg_pgm PGM - The Page Manager and Monitor
24 *
25 *
26 *
27 * @section sec_pg_modes Paging Modes
28 *
29 * There are three memory contexts: Host Context (HC), Guest Context (GC)
30 * and intermediate context. When talking about paging HC can also be refered to
31 * as "host paging", and GC refered to as "shadow paging".
32 *
33 * We define three basic paging modes: 32-bit, PAE and AMD64. The host paging mode
34 * is defined by the host operating system. The mode used in the shadow paging mode
35 * depends on the host paging mode and what the mode the guest is currently in. The
36 * following relation between the two is defined:
37 *
38 * @verbatim
39 Host > 32-bit | PAE | AMD64 |
40 Guest | | | |
41 ==v================================
42 32-bit 32-bit PAE PAE
43 -------|--------|--------|--------|
44 PAE PAE PAE PAE
45 -------|--------|--------|--------|
46 AMD64 AMD64 AMD64 AMD64
47 -------|--------|--------|--------| @endverbatim
48 *
49 * All configuration except those in the diagonal (upper left) are expected to
50 * require special effort from the switcher (i.e. a bit slower).
51 *
52 *
53 *
54 *
55 * @section sec_pg_shw The Shadow Memory Context
56 *
57 *
58 * [..]
59 *
60 * Because of guest context mappings requires PDPTR and PML4 entries to allow
61 * writing on AMD64, the two upper levels will have fixed flags whatever the
62 * guest is thinking of using there. So, when shadowing the PD level we will
63 * calculate the effective flags of PD and all the higher levels. In legacy
64 * PAE mode this only applies to the PWT and PCD bits (the rest are
65 * ignored/reserved/MBZ). We will ignore those bits for the present.
66 *
67 *
68 *
69 * @section sec_pg_int The Intermediate Memory Context
70 *
71 * The world switch goes thru an intermediate memory context which purpose it is
72 * to provide different mappings of the switcher code. All guest mappings are also
73 * present in this context.
74 *
75 * The switcher code is mapped at the same location as on the host, at an
76 * identity mapped location (physical equals virtual address), and at the
77 * hypervisor location.
78 *
79 * PGM maintain page tables for 32-bit, PAE and AMD64 paging modes. This
80 * simplifies switching guest CPU mode and consistency at the cost of more
81 * code to do the work. All memory use for those page tables is located below
82 * 4GB (this includes page tables for guest context mappings).
83 *
84 *
85 * @subsection subsec_pg_int_gc Guest Context Mappings
86 *
87 * During assignment and relocation of a guest context mapping the intermediate
88 * memory context is used to verify the new location.
89 *
90 * Guest context mappings are currently restricted to below 4GB, for reasons
91 * of simplicity. This may change when we implement AMD64 support.
92 *
93 *
94 *
95 *
96 * @section sec_pg_misc Misc
97 *
98 * @subsection subsec_pg_misc_diff Differences Between Legacy PAE and Long Mode PAE
99 *
100 * The differences between legacy PAE and long mode PAE are:
101 * -# PDPE bits 1, 2, 5 and 6 are defined differently. In leagcy mode they are
102 * all marked down as must-be-zero, while in long mode 1, 2 and 5 have the
103 * usual meanings while 6 is ignored (AMD). This means that upon switching to
104 * legacy PAE mode we'll have to clear these bits and when going to long mode
105 * they must be set. This applies to both intermediate and shadow contexts,
106 * however we don't need to do it for the intermediate one since we're
107 * executing with CR0.WP at that time.
108 * -# CR3 allows a 32-byte aligned address in legacy mode, while in long mode
109 * a page aligned one is required.
110 */
111
112
113
114/** Saved state data unit version. */
115#define PGM_SAVED_STATE_VERSION 5
116
117/*******************************************************************************
118* Header Files *
119*******************************************************************************/
120#define LOG_GROUP LOG_GROUP_PGM
121#include <VBox/dbgf.h>
122#include <VBox/pgm.h>
123#include <VBox/cpum.h>
124#include <VBox/iom.h>
125#include <VBox/sup.h>
126#include <VBox/mm.h>
127#include <VBox/pdm.h>
128#include <VBox/em.h>
129#include <VBox/stam.h>
130#include <VBox/rem.h>
131#include <VBox/dbgf.h>
132#include <VBox/rem.h>
133#include <VBox/selm.h>
134#include <VBox/ssm.h>
135#include "PGMInternal.h"
136#include <VBox/vm.h>
137#include <VBox/dbg.h>
138#include <VBox/hwaccm.h>
139
140#include <VBox/log.h>
141#include <iprt/assert.h>
142#include <iprt/alloc.h>
143#include <iprt/asm.h>
144#include <iprt/thread.h>
145#include <iprt/string.h>
146#include <VBox/param.h>
147#include <VBox/err.h>
148
149
150
151/*******************************************************************************
152* Internal Functions *
153*******************************************************************************/
154static int pgmR3InitPaging(PVM pVM);
155static DECLCALLBACK(void) pgmR3PhysInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
156static DECLCALLBACK(void) pgmR3InfoMode(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
157static DECLCALLBACK(void) pgmR3InfoCr3(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
158static DECLCALLBACK(int) pgmR3RelocatePhysHandler(PAVLROGCPHYSNODECORE pNode, void *pvUser);
159static DECLCALLBACK(int) pgmR3RelocateVirtHandler(PAVLROGCPTRNODECORE pNode, void *pvUser);
160static DECLCALLBACK(int) pgmR3Save(PVM pVM, PSSMHANDLE pSSM);
161static DECLCALLBACK(int) pgmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
162static int pgmR3ModeDataInit(PVM pVM, bool fResolveGCAndR0);
163static void pgmR3ModeDataSwitch(PVM pVM, PGMMODE enmShw, PGMMODE enmGst);
164static PGMMODE pgmR3CalcShadowMode(PGMMODE enmGuestMode, SUPPAGINGMODE enmHostMode, PGMMODE enmShadowMode, VMMSWITCHER *penmSwitcher);
165
166#ifdef VBOX_WITH_STATISTICS
167static void pgmR3InitStats(PVM pVM);
168#endif
169
170#ifdef VBOX_WITH_DEBUGGER
171/** @todo all but the two last commands must be converted to 'info'. */
172static DECLCALLBACK(int) pgmR3CmdRam(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
173static DECLCALLBACK(int) pgmR3CmdMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
174static DECLCALLBACK(int) pgmR3CmdSync(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
175static DECLCALLBACK(int) pgmR3CmdSyncAlways(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
176#endif
177
178
179/*******************************************************************************
180* Global Variables *
181*******************************************************************************/
182#ifdef VBOX_WITH_DEBUGGER
183/** Command descriptors. */
184static const DBGCCMD g_aCmds[] =
185{
186 /* pszCmd, cArgsMin, cArgsMax, paArgDesc, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
187 { "pgmram", 0, 0, NULL, 0, NULL, 0, pgmR3CmdRam, "", "Display the ram ranges." },
188 { "pgmmap", 0, 0, NULL, 0, NULL, 0, pgmR3CmdMap, "", "Display the mapping ranges." },
189 { "pgmsync", 0, 0, NULL, 0, NULL, 0, pgmR3CmdSync, "", "Sync the CR3 page." },
190 { "pgmsyncalways", 0, 0, NULL, 0, NULL, 0, pgmR3CmdSyncAlways, "", "Toggle permanent CR3 syncing." },
191};
192#endif
193
194
195
196
197#if 1/// @todo ndef __AMD64__
198/*
199 * Shadow - 32-bit mode
200 */
201#define PGM_SHW_TYPE PGM_TYPE_32BIT
202#define PGM_SHW_NAME(name) PGM_SHW_NAME_32BIT(name)
203#define PGM_SHW_NAME_GC_STR(name) PGM_SHW_NAME_GC_32BIT_STR(name)
204#define PGM_SHW_NAME_R0_STR(name) PGM_SHW_NAME_R0_32BIT_STR(name)
205#include "PGMShw.h"
206
207/* Guest - real mode */
208#define PGM_GST_TYPE PGM_TYPE_REAL
209#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
210#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_REAL_STR(name)
211#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_REAL_STR(name)
212#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_REAL(name)
213#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_32BIT_REAL_STR(name)
214#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_32BIT_REAL_STR(name)
215#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
216#include "PGMGst.h"
217#include "PGMBth.h"
218#undef BTH_PGMPOOLKIND_PT_FOR_PT
219#undef PGM_BTH_NAME
220#undef PGM_BTH_NAME_GC_STR
221#undef PGM_BTH_NAME_R0_STR
222#undef PGM_GST_TYPE
223#undef PGM_GST_NAME
224#undef PGM_GST_NAME_GC_STR
225#undef PGM_GST_NAME_R0_STR
226
227/* Guest - protected mode */
228#define PGM_GST_TYPE PGM_TYPE_PROT
229#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
230#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_PROT_STR(name)
231#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_PROT_STR(name)
232#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
233#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_32BIT_PROT_STR(name)
234#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_32BIT_PROT_STR(name)
235#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
236#include "PGMGst.h"
237#include "PGMBth.h"
238#undef BTH_PGMPOOLKIND_PT_FOR_PT
239#undef PGM_BTH_NAME
240#undef PGM_BTH_NAME_GC_STR
241#undef PGM_BTH_NAME_R0_STR
242#undef PGM_GST_TYPE
243#undef PGM_GST_NAME
244#undef PGM_GST_NAME_GC_STR
245#undef PGM_GST_NAME_R0_STR
246
247/* Guest - 32-bit mode */
248#define PGM_GST_TYPE PGM_TYPE_32BIT
249#define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
250#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_32BIT_STR(name)
251#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_32BIT_STR(name)
252#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_32BIT(name)
253#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_32BIT_32BIT_STR(name)
254#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_32BIT_32BIT_STR(name)
255#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT
256#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB
257#include "PGMGst.h"
258#include "PGMBth.h"
259#undef BTH_PGMPOOLKIND_PT_FOR_BIG
260#undef BTH_PGMPOOLKIND_PT_FOR_PT
261#undef PGM_BTH_NAME
262#undef PGM_BTH_NAME_GC_STR
263#undef PGM_BTH_NAME_R0_STR
264#undef PGM_GST_TYPE
265#undef PGM_GST_NAME
266#undef PGM_GST_NAME_GC_STR
267#undef PGM_GST_NAME_R0_STR
268
269#undef PGM_SHW_TYPE
270#undef PGM_SHW_NAME
271#undef PGM_SHW_NAME_GC_STR
272#undef PGM_SHW_NAME_R0_STR
273#endif /* !__AMD64__ */
274
275
276/*
277 * Shadow - PAE mode
278 */
279#define PGM_SHW_TYPE PGM_TYPE_PAE
280#define PGM_SHW_NAME(name) PGM_SHW_NAME_PAE(name)
281#define PGM_SHW_NAME_GC_STR(name) PGM_SHW_NAME_GC_PAE_STR(name)
282#define PGM_SHW_NAME_R0_STR(name) PGM_SHW_NAME_R0_PAE_STR(name)
283#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
284#include "PGMShw.h"
285
286/* Guest - real mode */
287#define PGM_GST_TYPE PGM_TYPE_REAL
288#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
289#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_REAL_STR(name)
290#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_REAL_STR(name)
291#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
292#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_PAE_REAL_STR(name)
293#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_PAE_REAL_STR(name)
294#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
295#include "PGMBth.h"
296#undef BTH_PGMPOOLKIND_PT_FOR_PT
297#undef PGM_BTH_NAME
298#undef PGM_BTH_NAME_GC_STR
299#undef PGM_BTH_NAME_R0_STR
300#undef PGM_GST_TYPE
301#undef PGM_GST_NAME
302#undef PGM_GST_NAME_GC_STR
303#undef PGM_GST_NAME_R0_STR
304
305/* Guest - protected mode */
306#define PGM_GST_TYPE PGM_TYPE_PROT
307#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
308#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_PROT_STR(name)
309#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_PROT_STR(name)
310#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
311#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_PAE_PROT_STR(name)
312#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_PAE_PROT_STR(name)
313#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
314#include "PGMBth.h"
315#undef BTH_PGMPOOLKIND_PT_FOR_PT
316#undef PGM_BTH_NAME
317#undef PGM_BTH_NAME_GC_STR
318#undef PGM_BTH_NAME_R0_STR
319#undef PGM_GST_TYPE
320#undef PGM_GST_NAME
321#undef PGM_GST_NAME_GC_STR
322#undef PGM_GST_NAME_R0_STR
323
324/* Guest - 32-bit mode */
325#define PGM_GST_TYPE PGM_TYPE_32BIT
326#define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
327#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_32BIT_STR(name)
328#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_32BIT_STR(name)
329#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_32BIT(name)
330#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_PAE_32BIT_STR(name)
331#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_PAE_32BIT_STR(name)
332#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_32BIT_PT
333#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB
334#include "PGMBth.h"
335#undef BTH_PGMPOOLKIND_PT_FOR_BIG
336#undef BTH_PGMPOOLKIND_PT_FOR_PT
337#undef PGM_BTH_NAME
338#undef PGM_BTH_NAME_GC_STR
339#undef PGM_BTH_NAME_R0_STR
340#undef PGM_GST_TYPE
341#undef PGM_GST_NAME
342#undef PGM_GST_NAME_GC_STR
343#undef PGM_GST_NAME_R0_STR
344
345/* Guest - PAE mode */
346#define PGM_GST_TYPE PGM_TYPE_PAE
347#define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
348#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_PAE_STR(name)
349#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_PAE_STR(name)
350#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PAE(name)
351#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_PAE_PAE_STR(name)
352#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_PAE_PAE_STR(name)
353#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
354#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
355#include "PGMGst.h"
356#include "PGMBth.h"
357#undef BTH_PGMPOOLKIND_PT_FOR_BIG
358#undef BTH_PGMPOOLKIND_PT_FOR_PT
359#undef PGM_BTH_NAME
360#undef PGM_BTH_NAME_GC_STR
361#undef PGM_BTH_NAME_R0_STR
362#undef PGM_GST_TYPE
363#undef PGM_GST_NAME
364#undef PGM_GST_NAME_GC_STR
365#undef PGM_GST_NAME_R0_STR
366
367#undef PGM_SHW_TYPE
368#undef PGM_SHW_NAME
369#undef PGM_SHW_NAME_GC_STR
370#undef PGM_SHW_NAME_R0_STR
371
372
373/*
374 * Shadow - AMD64 mode
375 */
376#define PGM_SHW_TYPE PGM_TYPE_AMD64
377#define PGM_SHW_NAME(name) PGM_SHW_NAME_AMD64(name)
378#define PGM_SHW_NAME_GC_STR(name) PGM_SHW_NAME_GC_AMD64_STR(name)
379#define PGM_SHW_NAME_R0_STR(name) PGM_SHW_NAME_R0_AMD64_STR(name)
380#include "PGMShw.h"
381
382/* Guest - real mode */
383#define PGM_GST_TYPE PGM_TYPE_REAL
384#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
385#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_REAL_STR(name)
386#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_REAL_STR(name)
387#define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_REAL(name)
388#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_AMD64_REAL_STR(name)
389#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_AMD64_REAL_STR(name)
390#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
391#include "PGMBth.h"
392#undef BTH_PGMPOOLKIND_PT_FOR_PT
393#undef PGM_BTH_NAME
394#undef PGM_BTH_NAME_GC_STR
395#undef PGM_BTH_NAME_R0_STR
396#undef PGM_GST_TYPE
397#undef PGM_GST_NAME
398#undef PGM_GST_NAME_GC_STR
399#undef PGM_GST_NAME_R0_STR
400
401/* Guest - protected mode */
402#define PGM_GST_TYPE PGM_TYPE_PROT
403#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
404#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_PROT_STR(name)
405#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_PROT_STR(name)
406#define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_PROT(name)
407#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_AMD64_PROT_STR(name)
408#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_AMD64_PROT_STR(name)
409#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
410#include "PGMBth.h"
411#undef BTH_PGMPOOLKIND_PT_FOR_PT
412#undef PGM_BTH_NAME
413#undef PGM_BTH_NAME_GC_STR
414#undef PGM_BTH_NAME_R0_STR
415#undef PGM_GST_TYPE
416#undef PGM_GST_NAME
417#undef PGM_GST_NAME_GC_STR
418#undef PGM_GST_NAME_R0_STR
419
420/* Guest - AMD64 mode */
421#define PGM_GST_TYPE PGM_TYPE_AMD64
422#define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
423#define PGM_GST_NAME_GC_STR(name) PGM_GST_NAME_GC_AMD64_STR(name)
424#define PGM_GST_NAME_R0_STR(name) PGM_GST_NAME_R0_AMD64_STR(name)
425#define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_AMD64(name)
426#define PGM_BTH_NAME_GC_STR(name) PGM_BTH_NAME_GC_AMD64_AMD64_STR(name)
427#define PGM_BTH_NAME_R0_STR(name) PGM_BTH_NAME_R0_AMD64_AMD64_STR(name)
428#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
429#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
430#include "PGMGst.h"
431#include "PGMBth.h"
432#undef BTH_PGMPOOLKIND_PT_FOR_BIG
433#undef BTH_PGMPOOLKIND_PT_FOR_PT
434#undef PGM_BTH_NAME
435#undef PGM_BTH_NAME_GC_STR
436#undef PGM_BTH_NAME_R0_STR
437#undef PGM_GST_TYPE
438#undef PGM_GST_NAME
439#undef PGM_GST_NAME_GC_STR
440#undef PGM_GST_NAME_R0_STR
441
442#undef PGM_SHW_TYPE
443#undef PGM_SHW_NAME
444#undef PGM_SHW_NAME_GC_STR
445#undef PGM_SHW_NAME_R0_STR
446
447
448
449
450/**
451 * Initiates the paging of VM.
452 *
453 * @returns VBox status code.
454 * @param pVM Pointer to VM structure.
455 */
456PGMR3DECL(int) PGMR3Init(PVM pVM)
457{
458 LogFlow(("PGMR3Init:\n"));
459
460 /*
461 * Assert alignment and sizes.
462 */
463 AssertRelease(sizeof(pVM->pgm.s) <= sizeof(pVM->pgm.padding));
464
465 /*
466 * Init the structure.
467 */
468 pVM->pgm.s.offVM = RT_OFFSETOF(VM, pgm.s);
469 pVM->pgm.s.enmShadowMode = PGMMODE_INVALID;
470 pVM->pgm.s.enmGuestMode = PGMMODE_INVALID;
471 pVM->pgm.s.enmHostMode = SUPPAGINGMODE_INVALID;
472 pVM->pgm.s.GCPhysCR3 = NIL_RTGCPHYS;
473 pVM->pgm.s.GCPhysGstCR3Monitored = NIL_RTGCPHYS;
474 pVM->pgm.s.fA20Enabled = true;
475 pVM->pgm.s.pGstPaePDPTRHC = NULL;
476 pVM->pgm.s.pGstPaePDPTRGC = 0;
477 for (unsigned i = 0; i < ELEMENTS(pVM->pgm.s.apGstPaePDsHC); i++)
478 {
479 pVM->pgm.s.apGstPaePDsHC[i] = NULL;
480 pVM->pgm.s.apGstPaePDsGC[i] = 0;
481 pVM->pgm.s.aGCPhysGstPaePDs[i] = NIL_RTGCPHYS;
482 }
483
484 /*
485 * Get the configured RAM size - to estimate saved state size.
486 */
487 uint64_t cbRam;
488 int rc = CFGMR3QueryU64(CFGMR3GetRoot(pVM), "RamSize", &cbRam);
489 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
490 cbRam = pVM->pgm.s.cbRamSize = 0;
491 else if (VBOX_SUCCESS(rc))
492 {
493 if (cbRam < PAGE_SIZE)
494 cbRam = 0;
495 cbRam = RT_ALIGN_64(cbRam, PAGE_SIZE);
496 pVM->pgm.s.cbRamSize = (RTUINT)cbRam;
497 }
498 else
499 {
500 AssertMsgFailed(("Configuration error: Failed to query integer \"RamSize\", rc=%Vrc.\n", rc));
501 return rc;
502 }
503
504 /*
505 * Register saved state data unit.
506 */
507 rc = SSMR3RegisterInternal(pVM, "pgm", 1, PGM_SAVED_STATE_VERSION, (size_t)cbRam + sizeof(PGM),
508 NULL, pgmR3Save, NULL,
509 NULL, pgmR3Load, NULL);
510 if (VBOX_FAILURE(rc))
511 return rc;
512
513 /* Initialise PGM critical section. */
514 rc = PDMR3CritSectInit(pVM, &pVM->pgm.s.CritSect, "PGM");
515 AssertRCReturn(rc, rc);
516
517 /*
518 * Trees
519 */
520 rc = MMHyperAlloc(pVM, sizeof(PGMTREES), 0, MM_TAG_PGM, (void **)&pVM->pgm.s.pTreesHC);
521 if (VBOX_SUCCESS(rc))
522 {
523 pVM->pgm.s.pTreesGC = MMHyperHC2GC(pVM, pVM->pgm.s.pTreesHC);
524
525 /*
526 * Init the paging.
527 */
528 rc = pgmR3InitPaging(pVM);
529 }
530 if (VBOX_SUCCESS(rc))
531 {
532 /*
533 * Init the page pool.
534 */
535 rc = pgmR3PoolInit(pVM);
536 }
537 if (VBOX_SUCCESS(rc))
538 {
539 /*
540 * Info & statistics
541 */
542 DBGFR3InfoRegisterInternal(pVM, "mode",
543 "Shows the current paging mode. "
544 "Recognizes 'all', 'guest', 'shadow' and 'host' as arguments, defaulting to 'all' if nothing's given.",
545 pgmR3InfoMode);
546 DBGFR3InfoRegisterInternal(pVM, "pgmcr3",
547 "Dumps all the entries in the top level paging table. No arguments.",
548 pgmR3InfoCr3);
549 DBGFR3InfoRegisterInternal(pVM, "phys",
550 "Dumps all the physical address ranges. No arguments.",
551 pgmR3PhysInfo);
552 DBGFR3InfoRegisterInternal(pVM, "handlers",
553 "Dumps physical and virtual handlers. "
554 "Pass 'phys' or 'virt' as argument if only one kind is wanted.",
555 pgmR3InfoHandlers);
556
557 STAM_REL_REG(pVM, &pVM->pgm.s.cGuestModeChanges, STAMTYPE_COUNTER, "/PGM/cGuestModeChanges", STAMUNIT_OCCURENCES, "Number of guest mode changes.");
558#ifdef VBOX_WITH_STATISTICS
559 pgmR3InitStats(pVM);
560#endif
561#ifdef VBOX_WITH_DEBUGGER
562 /*
563 * Debugger commands.
564 */
565 static bool fRegisteredCmds = false;
566 if (!fRegisteredCmds)
567 {
568 int rc = DBGCRegisterCommands(&g_aCmds[0], ELEMENTS(g_aCmds));
569 if (VBOX_SUCCESS(rc))
570 fRegisteredCmds = true;
571 }
572#endif
573 return VINF_SUCCESS;
574 }
575 /* No cleanup necessary, MM frees all memory. */
576
577 return rc;
578}
579
580
581/**
582 * Init paging.
583 *
584 * Since we need to check what mode the host is operating in before we can choose
585 * the right paging functions for the host we have to delay this until R0 has
586 * been initialized.
587 *
588 * @returns VBox status code.
589 * @param pVM VM handle.
590 */
591static int pgmR3InitPaging(PVM pVM)
592{
593 /*
594 * Force a recalculation of modes and switcher so everyone gets notified.
595 */
596 pVM->pgm.s.enmShadowMode = PGMMODE_INVALID;
597 pVM->pgm.s.enmGuestMode = PGMMODE_INVALID;
598 pVM->pgm.s.enmHostMode = SUPPAGINGMODE_INVALID;
599
600 /*
601 * Allocate static mapping space for whatever the cr3 register
602 * points to and in the case of PAE mode to the 4 PDs.
603 */
604 int rc = MMR3HyperReserve(pVM, PAGE_SIZE * 5, "CR3 mapping", &pVM->pgm.s.GCPtrCR3Mapping);
605 if (VBOX_FAILURE(rc))
606 {
607 AssertMsgFailed(("Failed to reserve two pages for cr mapping in HMA, rc=%Vrc\n", rc));
608 return rc;
609 }
610 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
611
612 /*
613 * Allocate pages for the three possible intermediate contexts
614 * (AMD64, PAE and plain 32-Bit). We maintain all three contexts
615 * for the sake of simplicity. The AMD64 uses the PAE for the
616 * lower levels, making the total number of pages 11 (3 + 7 + 1).
617 *
618 * We assume that two page tables will be enought for the core code
619 * mappings (HC virtual and identity).
620 */
621 pVM->pgm.s.pInterPD = (PX86PD)MMR3PageAllocLow(pVM);
622 pVM->pgm.s.apInterPTs[0] = (PX86PT)MMR3PageAllocLow(pVM);
623 pVM->pgm.s.apInterPTs[1] = (PX86PT)MMR3PageAllocLow(pVM);
624 pVM->pgm.s.apInterPaePTs[0] = (PX86PTPAE)MMR3PageAlloc(pVM);
625 pVM->pgm.s.apInterPaePTs[1] = (PX86PTPAE)MMR3PageAlloc(pVM);
626 pVM->pgm.s.apInterPaePDs[0] = (PX86PDPAE)MMR3PageAlloc(pVM);
627 pVM->pgm.s.apInterPaePDs[1] = (PX86PDPAE)MMR3PageAlloc(pVM);
628 pVM->pgm.s.apInterPaePDs[2] = (PX86PDPAE)MMR3PageAlloc(pVM);
629 pVM->pgm.s.apInterPaePDs[3] = (PX86PDPAE)MMR3PageAlloc(pVM);
630 pVM->pgm.s.pInterPaePDPTR = (PX86PDPTR)MMR3PageAllocLow(pVM);
631 pVM->pgm.s.pInterPaePDPTR64 = (PX86PDPTR)MMR3PageAllocLow(pVM);
632 pVM->pgm.s.pInterPaePML4 = (PX86PML4)MMR3PageAllocLow(pVM);
633 if ( !pVM->pgm.s.pInterPD
634 || !pVM->pgm.s.apInterPTs[0]
635 || !pVM->pgm.s.apInterPTs[1]
636 || !pVM->pgm.s.apInterPaePTs[0]
637 || !pVM->pgm.s.apInterPaePTs[1]
638 || !pVM->pgm.s.apInterPaePDs[0]
639 || !pVM->pgm.s.apInterPaePDs[1]
640 || !pVM->pgm.s.apInterPaePDs[2]
641 || !pVM->pgm.s.apInterPaePDs[3]
642 || !pVM->pgm.s.pInterPaePDPTR
643 || !pVM->pgm.s.pInterPaePDPTR64
644 || !pVM->pgm.s.pInterPaePML4)
645 {
646 AssertMsgFailed(("Failed to allocate pages for the intermediate context!\n"));
647 return VERR_NO_PAGE_MEMORY;
648 }
649
650 pVM->pgm.s.HCPhysInterPD = MMPage2Phys(pVM, pVM->pgm.s.pInterPD);
651 AssertRelease(pVM->pgm.s.HCPhysInterPD != NIL_RTHCPHYS && !(pVM->pgm.s.HCPhysInterPD & PAGE_OFFSET_MASK));
652 pVM->pgm.s.HCPhysInterPaePDPTR = MMPage2Phys(pVM, pVM->pgm.s.pInterPaePDPTR);
653 AssertRelease(pVM->pgm.s.HCPhysInterPaePDPTR != NIL_RTHCPHYS && !(pVM->pgm.s.HCPhysInterPaePDPTR & PAGE_OFFSET_MASK));
654 pVM->pgm.s.HCPhysInterPaePML4 = MMPage2Phys(pVM, pVM->pgm.s.pInterPaePML4);
655 AssertRelease(pVM->pgm.s.HCPhysInterPaePML4 != NIL_RTHCPHYS && !(pVM->pgm.s.HCPhysInterPaePML4 & PAGE_OFFSET_MASK));
656
657 /*
658 * Initialize the pages, setting up the PML4 and PDPTR for repetitive 4GB action.
659 */
660 ASMMemZeroPage(pVM->pgm.s.pInterPD);
661 ASMMemZeroPage(pVM->pgm.s.apInterPTs[0]);
662 ASMMemZeroPage(pVM->pgm.s.apInterPTs[1]);
663
664 ASMMemZeroPage(pVM->pgm.s.apInterPaePTs[0]);
665 ASMMemZeroPage(pVM->pgm.s.apInterPaePTs[1]);
666
667 ASMMemZeroPage(pVM->pgm.s.pInterPaePDPTR);
668 for (unsigned i = 0; i < ELEMENTS(pVM->pgm.s.apInterPaePDs); i++)
669 {
670 ASMMemZeroPage(pVM->pgm.s.apInterPaePDs[i]);
671 pVM->pgm.s.pInterPaePDPTR->a[i].u = X86_PDPE_P | PGM_PLXFLAGS_PERMANENT
672 | MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[i]);
673 }
674
675 for (unsigned i = 0; i < ELEMENTS(pVM->pgm.s.pInterPaePDPTR64->a); i++)
676 {
677 const unsigned iPD = i % ELEMENTS(pVM->pgm.s.apInterPaePDs);
678 pVM->pgm.s.pInterPaePDPTR64->a[i].u = X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A | PGM_PLXFLAGS_PERMANENT
679 | MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[iPD]);
680 }
681
682 RTHCPHYS HCPhysInterPaePDPTR64 = MMPage2Phys(pVM, pVM->pgm.s.pInterPaePDPTR64);
683 for (unsigned i = 0; i < ELEMENTS(pVM->pgm.s.pInterPaePML4->a); i++)
684 pVM->pgm.s.pInterPaePML4->a[i].u = X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_A | PGM_PLXFLAGS_PERMANENT
685 | HCPhysInterPaePDPTR64;
686
687 /*
688 * Allocate pages for the three possible guest contexts (AMD64, PAE and plain 32-Bit).
689 * We allocate pages for all three posibilities to in order to simplify mappings and
690 * avoid resource failure during mode switches. So, we need to cover all levels of the
691 * of the first 4GB down to PD level.
692 * As with the intermediate context, AMD64 uses the PAE PDPTR and PDs.
693 */
694 pVM->pgm.s.pHC32BitPD = (PX86PD)MMR3PageAllocLow(pVM);
695 pVM->pgm.s.apHCPaePDs[0] = (PX86PDPAE)MMR3PageAlloc(pVM);
696 pVM->pgm.s.apHCPaePDs[1] = (PX86PDPAE)MMR3PageAlloc(pVM);
697 AssertRelease((uintptr_t)pVM->pgm.s.apHCPaePDs[0] + PAGE_SIZE == (uintptr_t)pVM->pgm.s.apHCPaePDs[1]);
698 pVM->pgm.s.apHCPaePDs[2] = (PX86PDPAE)MMR3PageAlloc(pVM);
699 AssertRelease((uintptr_t)pVM->pgm.s.apHCPaePDs[1] + PAGE_SIZE == (uintptr_t)pVM->pgm.s.apHCPaePDs[2]);
700 pVM->pgm.s.apHCPaePDs[3] = (PX86PDPAE)MMR3PageAlloc(pVM);
701 AssertRelease((uintptr_t)pVM->pgm.s.apHCPaePDs[2] + PAGE_SIZE == (uintptr_t)pVM->pgm.s.apHCPaePDs[3]);
702 pVM->pgm.s.pHCPaePDPTR = (PX86PDPTR)MMR3PageAllocLow(pVM);
703 pVM->pgm.s.pHCPaePML4 = (PX86PML4)MMR3PageAllocLow(pVM);
704 if ( !pVM->pgm.s.pHC32BitPD
705 || !pVM->pgm.s.apHCPaePDs[0]
706 || !pVM->pgm.s.apHCPaePDs[1]
707 || !pVM->pgm.s.apHCPaePDs[2]
708 || !pVM->pgm.s.apHCPaePDs[3]
709 || !pVM->pgm.s.pHCPaePDPTR
710 || !pVM->pgm.s.pHCPaePML4)
711 {
712 AssertMsgFailed(("Failed to allocate pages for the intermediate context!\n"));
713 return VERR_NO_PAGE_MEMORY;
714 }
715
716 /* get physical addresses. */
717 pVM->pgm.s.HCPhys32BitPD = MMPage2Phys(pVM, pVM->pgm.s.pHC32BitPD);
718 Assert(MMPagePhys2Page(pVM, pVM->pgm.s.HCPhys32BitPD) == pVM->pgm.s.pHC32BitPD);
719 pVM->pgm.s.aHCPhysPaePDs[0] = MMPage2Phys(pVM, pVM->pgm.s.apHCPaePDs[0]);
720 pVM->pgm.s.aHCPhysPaePDs[1] = MMPage2Phys(pVM, pVM->pgm.s.apHCPaePDs[1]);
721 pVM->pgm.s.aHCPhysPaePDs[2] = MMPage2Phys(pVM, pVM->pgm.s.apHCPaePDs[2]);
722 pVM->pgm.s.aHCPhysPaePDs[3] = MMPage2Phys(pVM, pVM->pgm.s.apHCPaePDs[3]);
723 pVM->pgm.s.HCPhysPaePDPTR = MMPage2Phys(pVM, pVM->pgm.s.pHCPaePDPTR);
724 pVM->pgm.s.HCPhysPaePML4 = MMPage2Phys(pVM, pVM->pgm.s.pHCPaePML4);
725
726 /*
727 * Initialize the pages, setting up the PML4 and PDPTR for action below 4GB.
728 */
729 ASMMemZero32(pVM->pgm.s.pHC32BitPD, PAGE_SIZE);
730
731 ASMMemZero32(pVM->pgm.s.pHCPaePDPTR, PAGE_SIZE);
732 for (unsigned i = 0; i < ELEMENTS(pVM->pgm.s.apHCPaePDs); i++)
733 {
734 ASMMemZero32(pVM->pgm.s.apHCPaePDs[i], PAGE_SIZE);
735 pVM->pgm.s.pHCPaePDPTR->a[i].u = X86_PDPE_P | PGM_PLXFLAGS_PERMANENT | pVM->pgm.s.aHCPhysPaePDs[i];
736 /* The flags will be corrected when entering and leaving long mode. */
737 }
738
739 ASMMemZero32(pVM->pgm.s.pHCPaePML4, PAGE_SIZE);
740 pVM->pgm.s.pHCPaePML4->a[0].u = X86_PML4E_P | X86_PML4E_RW | X86_PML4E_A
741 | PGM_PLXFLAGS_PERMANENT | pVM->pgm.s.HCPhysPaePDPTR;
742
743 CPUMSetHyperCR3(pVM, (uint32_t)pVM->pgm.s.HCPhys32BitPD);
744
745 /*
746 * Initialize paging workers and mode from current host mode
747 * and the guest running in real mode.
748 */
749 pVM->pgm.s.enmHostMode = SUPGetPagingMode();
750 switch (pVM->pgm.s.enmHostMode)
751 {
752 case SUPPAGINGMODE_32_BIT:
753 case SUPPAGINGMODE_32_BIT_GLOBAL:
754 case SUPPAGINGMODE_PAE:
755 case SUPPAGINGMODE_PAE_GLOBAL:
756 case SUPPAGINGMODE_PAE_NX:
757 case SUPPAGINGMODE_PAE_GLOBAL_NX:
758 break;
759
760 case SUPPAGINGMODE_AMD64:
761 case SUPPAGINGMODE_AMD64_GLOBAL:
762 case SUPPAGINGMODE_AMD64_NX:
763 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
764#ifndef VBOX_WITH_HYBIRD_32BIT_KERNEL
765 if (ARCH_BITS != 64)
766 {
767 AssertMsgFailed(("Host mode %d (64-bit) is not supported by non-64bit builds\n", pVM->pgm.s.enmHostMode));
768 LogRel(("Host mode %d (64-bit) is not supported by non-64bit builds\n", pVM->pgm.s.enmHostMode));
769 return VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE;
770 }
771#endif
772 break;
773 default:
774 AssertMsgFailed(("Host mode %d is not supported\n", pVM->pgm.s.enmHostMode));
775 return VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE;
776 }
777 rc = pgmR3ModeDataInit(pVM, false /* don't resolve GC and R0 syms yet */);
778 if (VBOX_SUCCESS(rc))
779 rc = pgmR3ChangeMode(pVM, PGMMODE_REAL);
780 if (VBOX_SUCCESS(rc))
781 {
782 LogFlow(("pgmR3InitPaging: returns successfully\n"));
783#if HC_ARCH_BITS == 64
784LogRel(("Debug: HCPhys32BitPD=%VHp aHCPhysPaePDs={%VHp,%VHp,%VHp,%VHp} HCPhysPaePDPTR=%VHp HCPhysPaePML4=%VHp\n",
785 pVM->pgm.s.HCPhys32BitPD, pVM->pgm.s.aHCPhysPaePDs[0], pVM->pgm.s.aHCPhysPaePDs[1], pVM->pgm.s.aHCPhysPaePDs[2], pVM->pgm.s.aHCPhysPaePDs[3],
786 pVM->pgm.s.HCPhysPaePDPTR, pVM->pgm.s.HCPhysPaePML4));
787LogRel(("Debug: HCPhysInterPD=%VHp HCPhysInterPaePDPTR=%VHp HCPhysInterPaePML4=%VHp\n",
788 pVM->pgm.s.HCPhysInterPD, pVM->pgm.s.HCPhysInterPaePDPTR, pVM->pgm.s.HCPhysInterPaePML4));
789LogRel(("Debug: apInterPTs={%VHp,%VHp} apInterPaePTs={%VHp,%VHp} apInterPaePDs={%VHp,%VHp,%VHp,%VHp} pInterPaePDPTR64=%VHp\n",
790 MMPage2Phys(pVM, pVM->pgm.s.apInterPTs[0]), MMPage2Phys(pVM, pVM->pgm.s.apInterPTs[1]),
791 MMPage2Phys(pVM, pVM->pgm.s.apInterPaePTs[0]), MMPage2Phys(pVM, pVM->pgm.s.apInterPaePTs[1]),
792 MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[0]), MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[1]), MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[2]), MMPage2Phys(pVM, pVM->pgm.s.apInterPaePDs[3]),
793 MMPage2Phys(pVM, pVM->pgm.s.pInterPaePDPTR64)));
794#endif
795
796 return VINF_SUCCESS;
797 }
798
799 LogFlow(("pgmR3InitPaging: returns %Vrc\n", rc));
800 return rc;
801}
802
803
804#ifdef VBOX_WITH_STATISTICS
805/**
806 * Init statistics
807 */
808static void pgmR3InitStats(PVM pVM)
809{
810 PPGM pPGM = &pVM->pgm.s;
811 STAM_REG(pVM, &pPGM->StatGCInvalidatePage, STAMTYPE_PROFILE, "/PGM/GC/InvalidatePage", STAMUNIT_TICKS_PER_CALL, "PGMGCInvalidatePage() profiling.");
812 STAM_REG(pVM, &pPGM->StatGCInvalidatePage4KBPages, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/4KBPages", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a 4KB page.");
813 STAM_REG(pVM, &pPGM->StatGCInvalidatePage4MBPages, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/4MBPages", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a 4MB page.");
814 STAM_REG(pVM, &pPGM->StatGCInvalidatePage4MBPagesSkip, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/4MBPagesSkip",STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() skipped a 4MB page.");
815 STAM_REG(pVM, &pPGM->StatGCInvalidatePagePDMappings, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/PDMappings", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a page directory containing mappings (no conflict).");
816 STAM_REG(pVM, &pPGM->StatGCInvalidatePagePDNAs, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/PDNAs", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a not accessed page directory.");
817 STAM_REG(pVM, &pPGM->StatGCInvalidatePagePDNPs, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/PDNPs", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for a not present page directory.");
818 STAM_REG(pVM, &pPGM->StatGCInvalidatePagePDOutOfSync, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/PDOutOfSync", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for an out of sync page directory.");
819 STAM_REG(pVM, &pPGM->StatGCInvalidatePageSkipped, STAMTYPE_COUNTER, "/PGM/GC/InvalidatePage/Skipped", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was skipped due to not present shw or pending pending SyncCR3.");
820 STAM_REG(pVM, &pPGM->StatGCSyncPT, STAMTYPE_PROFILE, "/PGM/GC/SyncPT", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMGCSyncPT() body.");
821 STAM_REG(pVM, &pPGM->StatGCAccessedPage, STAMTYPE_COUNTER, "/PGM/GC/AccessedPage", STAMUNIT_OCCURENCES, "The number of pages marked not present for accessed bit emulation.");
822 STAM_REG(pVM, &pPGM->StatGCDirtyPage, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/Mark", STAMUNIT_OCCURENCES, "The number of pages marked read-only for dirty bit tracking.");
823 STAM_REG(pVM, &pPGM->StatGCDirtyPageBig, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/MarkBig", STAMUNIT_OCCURENCES, "The number of 4MB pages marked read-only for dirty bit tracking.");
824 STAM_REG(pVM, &pPGM->StatGCDirtyPageTrap, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/Trap", STAMUNIT_OCCURENCES, "The number of traps generated for dirty bit tracking.");
825 STAM_REG(pVM, &pPGM->StatGCDirtyPageSkipped, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/Skipped", STAMUNIT_OCCURENCES, "The number of pages already dirty or readonly.");
826 STAM_REG(pVM, &pPGM->StatGCDirtiedPage, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/SetDirty", STAMUNIT_OCCURENCES, "The number of pages marked dirty because of write accesses.");
827 STAM_REG(pVM, &pPGM->StatGCDirtyTrackRealPF, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/RealPF", STAMUNIT_OCCURENCES, "The number of real pages faults during dirty bit tracking.");
828 STAM_REG(pVM, &pPGM->StatGCPageAlreadyDirty, STAMTYPE_COUNTER, "/PGM/GC/DirtyPage/AlreadySet", STAMUNIT_OCCURENCES, "The number of pages already marked dirty because of write accesses.");
829 STAM_REG(pVM, &pPGM->StatGCDirtyBitTracking, STAMTYPE_PROFILE, "/PGM/GC/DirtyPage", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMTrackDirtyBit() body.");
830 STAM_REG(pVM, &pPGM->StatGCSyncPTAlloc, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/Alloc", STAMUNIT_OCCURENCES, "The number of times PGMGCSyncPT() needed to allocate page tables.");
831 STAM_REG(pVM, &pPGM->StatGCSyncPTConflict, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/Conflicts", STAMUNIT_OCCURENCES, "The number of times PGMGCSyncPT() detected conflicts.");
832 STAM_REG(pVM, &pPGM->StatGCSyncPTFailed, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/Failed", STAMUNIT_OCCURENCES, "The number of times PGMGCSyncPT() failed.");
833
834 STAM_REG(pVM, &pPGM->StatGCTrap0e, STAMTYPE_PROFILE, "/PGM/GC/Trap0e", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMGCTrap0eHandler() body.");
835 STAM_REG(pVM, &pPGM->StatCheckPageFault, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/CheckPageFault", STAMUNIT_TICKS_PER_CALL, "Profiling of checking for dirty/access emulation faults.");
836 STAM_REG(pVM, &pPGM->StatLazySyncPT, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/SyncPT", STAMUNIT_TICKS_PER_CALL, "Profiling of lazy page table syncing.");
837 STAM_REG(pVM, &pPGM->StatMapping, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/Mapping", STAMUNIT_TICKS_PER_CALL, "Profiling of checking virtual mappings.");
838 STAM_REG(pVM, &pPGM->StatOutOfSync, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/OutOfSync", STAMUNIT_TICKS_PER_CALL, "Profiling of out of sync page handling.");
839 STAM_REG(pVM, &pPGM->StatHandlers, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/Handlers", STAMUNIT_TICKS_PER_CALL, "Profiling of checking handlers.");
840 STAM_REG(pVM, &pPGM->StatEIPHandlers, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time/EIPHandlers", STAMUNIT_TICKS_PER_CALL, "Profiling of checking eip handlers.");
841 STAM_REG(pVM, &pPGM->StatTrap0eCSAM, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/CSAM", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is CSAM.");
842 STAM_REG(pVM, &pPGM->StatTrap0eDirtyAndAccessedBits, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/DirtyAndAccessedBits", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is dirty and/or accessed bit emulation.");
843 STAM_REG(pVM, &pPGM->StatTrap0eGuestTrap, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/GuestTrap", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is a guest trap.");
844 STAM_REG(pVM, &pPGM->StatTrap0eHndPhys, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/HandlerPhysical", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is a physical handler.");
845 STAM_REG(pVM, &pPGM->StatTrap0eHndVirt, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/HandlerVirtual",STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is a virtual handler.");
846 STAM_REG(pVM, &pPGM->StatTrap0eHndUnhandled, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/HandlerUnhandled", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is access outside the monitored areas of a monitored page.");
847 STAM_REG(pVM, &pPGM->StatTrap0eMisc, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/Misc", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is not known.");
848 STAM_REG(pVM, &pPGM->StatTrap0eOutOfSync, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/OutOfSync", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is an out-of-sync page.");
849 STAM_REG(pVM, &pPGM->StatTrap0eOutOfSyncHndPhys, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/OutOfSyncHndPhys", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is an out-of-sync physical handler page.");
850 STAM_REG(pVM, &pPGM->StatTrap0eOutOfSyncHndVirt, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/OutOfSyncHndVirt", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is an out-of-sync virtual handler page.");
851 STAM_REG(pVM, &pPGM->StatTrap0eOutOfSyncObsHnd, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/OutOfSyncObsHnd", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is an obsolete handler page.");
852 STAM_REG(pVM, &pPGM->StatTrap0eSyncPT, STAMTYPE_PROFILE, "/PGM/GC/Trap0e/Time2/SyncPT", STAMUNIT_TICKS_PER_CALL, "Profiling of the Trap0eHandler body when the cause is lazy syncing of a PT.");
853
854 STAM_REG(pVM, &pPGM->StatTrap0eMapHandler, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/Mapping", STAMUNIT_OCCURENCES, "Number of traps due to access handlers in mappings.");
855 STAM_REG(pVM, &pPGM->StatHandlersOutOfSync, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/OutOfSync", STAMUNIT_OCCURENCES, "Number of traps due to out-of-sync handled pages.");
856 STAM_REG(pVM, &pPGM->StatHandlersPhysical, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/Physical", STAMUNIT_OCCURENCES, "Number of traps due to physical access handlers.");
857 STAM_REG(pVM, &pPGM->StatHandlersVirtual, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/Virtual", STAMUNIT_OCCURENCES, "Number of traps due to virtual access handlers.");
858 STAM_REG(pVM, &pPGM->StatHandlersVirtualByPhys, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/VirtualByPhys", STAMUNIT_OCCURENCES, "Number of traps due to virtual access handlers by physical address.");
859 STAM_REG(pVM, &pPGM->StatHandlersVirtualUnmarked, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/VirtualUnmarked", STAMUNIT_OCCURENCES,"Number of traps due to virtual access handlers by virtual address (without proper physical flags).");
860 STAM_REG(pVM, &pPGM->StatHandlersUnhandled, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Handlers/Unhandled", STAMUNIT_OCCURENCES, "Number of traps due to access outside range of monitored page(s).");
861
862 STAM_REG(pVM, &pPGM->StatGCTrap0eConflicts, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Conflicts", STAMUNIT_OCCURENCES, "The number of times #PF was caused by an undetected conflict.");
863 STAM_REG(pVM, &pPGM->StatGCTrap0eUSNotPresentRead, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/NPRead", STAMUNIT_OCCURENCES, "Number of user mode not present read page faults.");
864 STAM_REG(pVM, &pPGM->StatGCTrap0eUSNotPresentWrite, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/NPWrite", STAMUNIT_OCCURENCES, "Number of user mode not present write page faults.");
865 STAM_REG(pVM, &pPGM->StatGCTrap0eUSWrite, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/Write", STAMUNIT_OCCURENCES, "Number of user mode write page faults.");
866 STAM_REG(pVM, &pPGM->StatGCTrap0eUSReserved, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/Reserved", STAMUNIT_OCCURENCES, "Number of user mode reserved bit page faults.");
867 STAM_REG(pVM, &pPGM->StatGCTrap0eUSRead, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/User/Read", STAMUNIT_OCCURENCES, "Number of user mode read page faults.");
868
869 STAM_REG(pVM, &pPGM->StatGCTrap0eSVNotPresentRead, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Supervisor/NPRead", STAMUNIT_OCCURENCES, "Number of supervisor mode not present read page faults.");
870 STAM_REG(pVM, &pPGM->StatGCTrap0eSVNotPresentWrite, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Supervisor/NPWrite", STAMUNIT_OCCURENCES, "Number of supervisor mode not present write page faults.");
871 STAM_REG(pVM, &pPGM->StatGCTrap0eSVWrite, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Supervisor/Write", STAMUNIT_OCCURENCES, "Number of supervisor mode write page faults.");
872 STAM_REG(pVM, &pPGM->StatGCTrap0eSVReserved, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/Supervisor/Reserved", STAMUNIT_OCCURENCES, "Number of supervisor mode reserved bit page faults.");
873 STAM_REG(pVM, &pPGM->StatGCTrap0eUnhandled, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/GuestPF/Unhandled", STAMUNIT_OCCURENCES, "Number of guest real page faults.");
874 STAM_REG(pVM, &pPGM->StatGCTrap0eMap, STAMTYPE_COUNTER, "/PGM/GC/Trap0e/GuestPF/Map", STAMUNIT_OCCURENCES, "Number of guest page faults due to map accesses.");
875
876
877 STAM_REG(pVM, &pPGM->StatGCGuestCR3WriteHandled, STAMTYPE_COUNTER, "/PGM/GC/CR3WriteInt", STAMUNIT_OCCURENCES, "The number of times the Guest CR3 change was successfully handled.");
878 STAM_REG(pVM, &pPGM->StatGCGuestCR3WriteUnhandled, STAMTYPE_COUNTER, "/PGM/GC/CR3WriteEmu", STAMUNIT_OCCURENCES, "The number of times the Guest CR3 change was passed back to the recompiler.");
879 STAM_REG(pVM, &pPGM->StatGCGuestCR3WriteConflict, STAMTYPE_COUNTER, "/PGM/GC/CR3WriteConflict", STAMUNIT_OCCURENCES, "The number of times the Guest CR3 monitoring detected a conflict.");
880
881 STAM_REG(pVM, &pPGM->StatGCPageOutOfSyncSupervisor, STAMTYPE_COUNTER, "/PGM/GC/OutOfSync/SuperVisor", STAMUNIT_OCCURENCES, "Number of traps due to pages out of sync.");
882 STAM_REG(pVM, &pPGM->StatGCPageOutOfSyncUser, STAMTYPE_COUNTER, "/PGM/GC/OutOfSync/User", STAMUNIT_OCCURENCES, "Number of traps due to pages out of sync.");
883
884 STAM_REG(pVM, &pPGM->StatGCGuestROMWriteHandled, STAMTYPE_COUNTER, "/PGM/GC/ROMWriteInt", STAMUNIT_OCCURENCES, "The number of times the Guest ROM change was successfully handled.");
885 STAM_REG(pVM, &pPGM->StatGCGuestROMWriteUnhandled, STAMTYPE_COUNTER, "/PGM/GC/ROMWriteEmu", STAMUNIT_OCCURENCES, "The number of times the Guest ROM change was passed back to the recompiler.");
886
887 STAM_REG(pVM, &pPGM->StatDynMapCacheHits, STAMTYPE_COUNTER, "/PGM/GC/DynMapCache/Hits" , STAMUNIT_OCCURENCES, "Number of dynamic page mapping cache hits.");
888 STAM_REG(pVM, &pPGM->StatDynMapCacheMisses, STAMTYPE_COUNTER, "/PGM/GC/DynMapCache/Misses" , STAMUNIT_OCCURENCES, "Number of dynamic page mapping cache misses.");
889
890 STAM_REG(pVM, &pPGM->StatHCDetectedConflicts, STAMTYPE_COUNTER, "/PGM/HC/DetectedConflicts", STAMUNIT_OCCURENCES, "The number of times PGMR3CheckMappingConflicts() detected a conflict.");
891 STAM_REG(pVM, &pPGM->StatHCGuestPDWrite, STAMTYPE_COUNTER, "/PGM/HC/PDWrite", STAMUNIT_OCCURENCES, "The total number of times pgmHCGuestPDWriteHandler() was called.");
892 STAM_REG(pVM, &pPGM->StatHCGuestPDWriteConflict, STAMTYPE_COUNTER, "/PGM/HC/PDWriteConflict", STAMUNIT_OCCURENCES, "The number of times pgmHCGuestPDWriteHandler() detected a conflict.");
893
894 STAM_REG(pVM, &pPGM->StatHCInvalidatePage, STAMTYPE_PROFILE, "/PGM/HC/InvalidatePage", STAMUNIT_TICKS_PER_CALL, "PGMHCInvalidatePage() profiling.");
895 STAM_REG(pVM, &pPGM->StatHCInvalidatePage4KBPages, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/4KBPages", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a 4KB page.");
896 STAM_REG(pVM, &pPGM->StatHCInvalidatePage4MBPages, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/4MBPages", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a 4MB page.");
897 STAM_REG(pVM, &pPGM->StatHCInvalidatePage4MBPagesSkip, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/4MBPagesSkip",STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() skipped a 4MB page.");
898 STAM_REG(pVM, &pPGM->StatHCInvalidatePagePDMappings, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/PDMappings", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a page directory containing mappings (no conflict).");
899 STAM_REG(pVM, &pPGM->StatHCInvalidatePagePDNAs, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/PDNAs", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a not accessed page directory.");
900 STAM_REG(pVM, &pPGM->StatHCInvalidatePagePDNPs, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/PDNPs", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was called for a not present page directory.");
901 STAM_REG(pVM, &pPGM->StatHCInvalidatePagePDOutOfSync, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/PDOutOfSync", STAMUNIT_OCCURENCES, "The number of times PGMGCInvalidatePage() was called for an out of sync page directory.");
902 STAM_REG(pVM, &pPGM->StatHCInvalidatePageSkipped, STAMTYPE_COUNTER, "/PGM/HC/InvalidatePage/Skipped", STAMUNIT_OCCURENCES, "The number of times PGMHCInvalidatePage() was skipped due to not present shw or pending pending SyncCR3.");
903 STAM_REG(pVM, &pPGM->StatHCResolveConflict, STAMTYPE_PROFILE, "/PGM/HC/ResolveConflict", STAMUNIT_TICKS_PER_CALL, "pgmR3SyncPTResolveConflict() profiling (includes the entire relocation).");
904 STAM_REG(pVM, &pPGM->StatHCPrefetch, STAMTYPE_PROFILE, "/PGM/HC/Prefetch", STAMUNIT_TICKS_PER_CALL, "PGMR3PrefetchPage profiling.");
905
906 STAM_REG(pVM, &pPGM->StatHCSyncPT, STAMTYPE_PROFILE, "/PGM/HC/SyncPT", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMR3SyncPT() body.");
907 STAM_REG(pVM, &pPGM->StatHCAccessedPage, STAMTYPE_COUNTER, "/PGM/HC/AccessedPage", STAMUNIT_OCCURENCES, "The number of pages marked not present for accessed bit emulation.");
908 STAM_REG(pVM, &pPGM->StatHCDirtyPage, STAMTYPE_COUNTER, "/PGM/HC/DirtyPage/Mark", STAMUNIT_OCCURENCES, "The number of pages marked read-only for dirty bit tracking.");
909 STAM_REG(pVM, &pPGM->StatHCDirtyPageBig, STAMTYPE_COUNTER, "/PGM/HC/DirtyPage/MarkBig", STAMUNIT_OCCURENCES, "The number of 4MB pages marked read-only for dirty bit tracking.");
910 STAM_REG(pVM, &pPGM->StatHCDirtyPageTrap, STAMTYPE_COUNTER, "/PGM/HC/DirtyPage/Trap", STAMUNIT_OCCURENCES, "The number of traps generated for dirty bit tracking.");
911 STAM_REG(pVM, &pPGM->StatHCDirtyPageSkipped, STAMTYPE_COUNTER, "/PGM/HC/DirtyPage/Skipped", STAMUNIT_OCCURENCES, "The number of pages already dirty or readonly.");
912 STAM_REG(pVM, &pPGM->StatHCDirtyBitTracking, STAMTYPE_PROFILE, "/PGM/HC/DirtyPage", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMTrackDirtyBit() body.");
913
914 STAM_REG(pVM, &pPGM->StatGCSyncPagePDNAs, STAMTYPE_COUNTER, "/PGM/GC/SyncPagePDNAs", STAMUNIT_OCCURENCES, "The number of time we've marked a PD not present from SyncPage to virtualize the accessed bit.");
915 STAM_REG(pVM, &pPGM->StatGCSyncPagePDOutOfSync, STAMTYPE_COUNTER, "/PGM/GC/SyncPagePDOutOfSync", STAMUNIT_OCCURENCES, "The number of time we've encountered an out-of-sync PD in SyncPage.");
916 STAM_REG(pVM, &pPGM->StatHCSyncPagePDNAs, STAMTYPE_COUNTER, "/PGM/HC/SyncPagePDNAs", STAMUNIT_OCCURENCES, "The number of time we've marked a PD not present from SyncPage to virtualize the accessed bit.");
917 STAM_REG(pVM, &pPGM->StatHCSyncPagePDOutOfSync, STAMTYPE_COUNTER, "/PGM/HC/SyncPagePDOutOfSync", STAMUNIT_OCCURENCES, "The number of time we've encountered an out-of-sync PD in SyncPage.");
918
919 STAM_REG(pVM, &pPGM->StatFlushTLB, STAMTYPE_PROFILE, "/PGM/FlushTLB", STAMUNIT_OCCURENCES, "Profiling of the PGMFlushTLB() body.");
920 STAM_REG(pVM, &pPGM->StatFlushTLBNewCR3, STAMTYPE_COUNTER, "/PGM/FlushTLB/NewCR3", STAMUNIT_OCCURENCES, "The number of times PGMFlushTLB was called with a new CR3, non-global. (switch)");
921 STAM_REG(pVM, &pPGM->StatFlushTLBNewCR3Global, STAMTYPE_COUNTER, "/PGM/FlushTLB/NewCR3Global", STAMUNIT_OCCURENCES, "The number of times PGMFlushTLB was called with a new CR3, global. (switch)");
922 STAM_REG(pVM, &pPGM->StatFlushTLBSameCR3, STAMTYPE_COUNTER, "/PGM/FlushTLB/SameCR3", STAMUNIT_OCCURENCES, "The number of times PGMFlushTLB was called with the same CR3, non-global. (flush)");
923 STAM_REG(pVM, &pPGM->StatFlushTLBSameCR3Global, STAMTYPE_COUNTER, "/PGM/FlushTLB/SameCR3Global", STAMUNIT_OCCURENCES, "The number of times PGMFlushTLB was called with the same CR3, global. (flush)");
924
925 STAM_REG(pVM, &pPGM->StatGCSyncCR3, STAMTYPE_PROFILE, "/PGM/GC/SyncCR3", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMSyncCR3() body.");
926 STAM_REG(pVM, &pPGM->StatGCSyncCR3Handlers, STAMTYPE_PROFILE, "/PGM/GC/SyncCR3/Handlers", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMSyncCR3() update handler section.");
927 STAM_REG(pVM, &pPGM->StatGCSyncCR3HandlerVirtualUpdate, STAMTYPE_PROFILE, "/PGM/GC/SyncCR3/Handlers/VirtualUpdate",STAMUNIT_TICKS_PER_CALL, "Profiling of the virtual handler updates.");
928 STAM_REG(pVM, &pPGM->StatGCSyncCR3HandlerVirtualReset, STAMTYPE_PROFILE, "/PGM/GC/SyncCR3/Handlers/VirtualReset", STAMUNIT_TICKS_PER_CALL, "Profiling of the virtual handler resets.");
929 STAM_REG(pVM, &pPGM->StatGCSyncCR3Global, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/Global", STAMUNIT_OCCURENCES, "The number of global CR3 syncs.");
930 STAM_REG(pVM, &pPGM->StatGCSyncCR3NotGlobal, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/NotGlobal", STAMUNIT_OCCURENCES, "The number of non-global CR3 syncs.");
931 STAM_REG(pVM, &pPGM->StatGCSyncCR3DstCacheHit, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstChacheHit", STAMUNIT_OCCURENCES, "The number of times we got some kind of a cache hit.");
932 STAM_REG(pVM, &pPGM->StatGCSyncCR3DstFreed, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstFreed", STAMUNIT_OCCURENCES, "The number of times we've had to free a shadow entry.");
933 STAM_REG(pVM, &pPGM->StatGCSyncCR3DstFreedSrcNP, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstFreedSrcNP", STAMUNIT_OCCURENCES, "The number of times we've had to free a shadow entry for which the source entry was not present.");
934 STAM_REG(pVM, &pPGM->StatGCSyncCR3DstNotPresent, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstNotPresent", STAMUNIT_OCCURENCES, "The number of times we've encountered a not present shadow entry for a present guest entry.");
935 STAM_REG(pVM, &pPGM->StatGCSyncCR3DstSkippedGlobalPD, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstSkippedGlobalPD", STAMUNIT_OCCURENCES, "The number of times a global page directory wasn't flushed.");
936 STAM_REG(pVM, &pPGM->StatGCSyncCR3DstSkippedGlobalPT, STAMTYPE_COUNTER, "/PGM/GC/SyncCR3/DstSkippedGlobalPT", STAMUNIT_OCCURENCES, "The number of times a page table with only global entries wasn't flushed.");
937
938 STAM_REG(pVM, &pPGM->StatHCSyncCR3, STAMTYPE_PROFILE, "/PGM/HC/SyncCR3", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMSyncCR3() body.");
939 STAM_REG(pVM, &pPGM->StatHCSyncCR3Handlers, STAMTYPE_PROFILE, "/PGM/HC/SyncCR3/Handlers", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMSyncCR3() update handler section.");
940 STAM_REG(pVM, &pPGM->StatHCSyncCR3HandlerVirtualUpdate, STAMTYPE_PROFILE, "/PGM/HC/SyncCR3/Handlers/VirtualUpdate",STAMUNIT_TICKS_PER_CALL, "Profiling of the virtual handler updates.");
941 STAM_REG(pVM, &pPGM->StatHCSyncCR3HandlerVirtualReset, STAMTYPE_PROFILE, "/PGM/HC/SyncCR3/Handlers/VirtualReset", STAMUNIT_TICKS_PER_CALL, "Profiling of the virtual handler resets.");
942 STAM_REG(pVM, &pPGM->StatHCSyncCR3Global, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/Global", STAMUNIT_OCCURENCES, "The number of global CR3 syncs.");
943 STAM_REG(pVM, &pPGM->StatHCSyncCR3NotGlobal, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/NotGlobal", STAMUNIT_OCCURENCES, "The number of non-global CR3 syncs.");
944 STAM_REG(pVM, &pPGM->StatHCSyncCR3DstCacheHit, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstChacheHit", STAMUNIT_OCCURENCES, "The number of times we got some kind of a cache hit.");
945 STAM_REG(pVM, &pPGM->StatHCSyncCR3DstFreed, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstFreed", STAMUNIT_OCCURENCES, "The number of times we've had to free a shadow entry.");
946 STAM_REG(pVM, &pPGM->StatHCSyncCR3DstFreedSrcNP, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstFreedSrcNP", STAMUNIT_OCCURENCES, "The number of times we've had to free a shadow entry for which the source entry was not present.");
947 STAM_REG(pVM, &pPGM->StatHCSyncCR3DstNotPresent, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstNotPresent", STAMUNIT_OCCURENCES, "The number of times we've encountered a not present shadow entry for a present guest entry.");
948 STAM_REG(pVM, &pPGM->StatHCSyncCR3DstSkippedGlobalPD, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstSkippedGlobalPD", STAMUNIT_OCCURENCES, "The number of times a global page directory wasn't flushed.");
949 STAM_REG(pVM, &pPGM->StatHCSyncCR3DstSkippedGlobalPT, STAMTYPE_COUNTER, "/PGM/HC/SyncCR3/DstSkippedGlobalPT", STAMUNIT_OCCURENCES, "The number of times a page table with only global entries wasn't flushed.");
950
951 STAM_REG(pVM, &pPGM->StatVirtHandleSearchByPhysGC, STAMTYPE_PROFILE, "/PGM/VirtHandler/SearchByPhys/GC", STAMUNIT_TICKS_PER_CALL, "Profiling of pgmHandlerVirtualFindByPhysAddr in GC.");
952 STAM_REG(pVM, &pPGM->StatVirtHandleSearchByPhysHC, STAMTYPE_PROFILE, "/PGM/VirtHandler/SearchByPhys/HC", STAMUNIT_TICKS_PER_CALL, "Profiling of pgmHandlerVirtualFindByPhysAddr in HC.");
953 STAM_REG(pVM, &pPGM->StatHandlePhysicalReset, STAMTYPE_COUNTER, "/PGM/HC/HandlerPhysicalReset", STAMUNIT_OCCURENCES, "The number of times PGMR3HandlerPhysicalReset is called.");
954
955 STAM_REG(pVM, &pPGM->StatHCGstModifyPage, STAMTYPE_PROFILE, "/PGM/HC/GstModifyPage", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMGstModifyPage() body.");
956 STAM_REG(pVM, &pPGM->StatGCGstModifyPage, STAMTYPE_PROFILE, "/PGM/GC/GstModifyPage", STAMUNIT_TICKS_PER_CALL, "Profiling of the PGMGstModifyPage() body.");
957
958 STAM_REG(pVM, &pPGM->StatSynPT4kGC, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/4k", STAMUNIT_OCCURENCES, "Nr of 4k PT syncs");
959 STAM_REG(pVM, &pPGM->StatSynPT4kHC, STAMTYPE_COUNTER, "/PGM/HC/SyncPT/4k", STAMUNIT_OCCURENCES, "Nr of 4k PT syncs");
960 STAM_REG(pVM, &pPGM->StatSynPT4MGC, STAMTYPE_COUNTER, "/PGM/GC/SyncPT/4M", STAMUNIT_OCCURENCES, "Nr of 4M PT syncs");
961 STAM_REG(pVM, &pPGM->StatSynPT4MHC, STAMTYPE_COUNTER, "/PGM/HC/SyncPT/4M", STAMUNIT_OCCURENCES, "Nr of 4M PT syncs");
962
963 STAM_REG(pVM, &pPGM->StatDynRamTotal, STAMTYPE_COUNTER, "/PGM/RAM/TotalAlloc", STAMUNIT_MEGABYTES, "Allocated mbs of guest ram.");
964 STAM_REG(pVM, &pPGM->StatDynRamGrow, STAMTYPE_COUNTER, "/PGM/RAM/Grow", STAMUNIT_OCCURENCES, "Nr of pgmr3PhysGrowRange calls.");
965
966#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
967 STAM_REG(pVM, &pPGM->StatTrackVirgin, STAMTYPE_COUNTER, "/PGM/Track/Virgin", STAMUNIT_OCCURENCES, "The number of first time shadowings");
968 STAM_REG(pVM, &pPGM->StatTrackAliased, STAMTYPE_COUNTER, "/PGM/Track/Aliased", STAMUNIT_OCCURENCES, "The number of times switching to cRef2, i.e. the page is being shadowed by two PTs.");
969 STAM_REG(pVM, &pPGM->StatTrackAliasedMany, STAMTYPE_COUNTER, "/PGM/Track/AliasedMany", STAMUNIT_OCCURENCES, "The number of times we're tracking using cRef2.");
970 STAM_REG(pVM, &pPGM->StatTrackAliasedLots, STAMTYPE_COUNTER, "/PGM/Track/AliasedLots", STAMUNIT_OCCURENCES, "The number of times we're hitting pages which has overflowed cRef2");
971 STAM_REG(pVM, &pPGM->StatTrackOverflows, STAMTYPE_COUNTER, "/PGM/Track/Overflows", STAMUNIT_OCCURENCES, "The number of times the extent list grows to long.");
972 STAM_REG(pVM, &pPGM->StatTrackDeref, STAMTYPE_PROFILE, "/PGM/Track/Deref", STAMUNIT_OCCURENCES, "Profiling of SyncPageWorkerTrackDeref (expensive).");
973#endif
974
975 for (unsigned i = 0; i < PAGE_ENTRIES; i++)
976 {
977 /** @todo r=bird: We need a STAMR3RegisterF()! */
978 char szName[32];
979
980 RTStrPrintf(szName, sizeof(szName), "/PGM/GC/PD/Trap0e/%04X", i);
981 int rc = STAMR3Register(pVM, &pPGM->StatGCTrap0ePD[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, "The number of traps in page directory n.");
982 AssertRC(rc);
983
984 RTStrPrintf(szName, sizeof(szName), "/PGM/GC/PD/SyncPt/%04X", i);
985 rc = STAMR3Register(pVM, &pPGM->StatGCSyncPtPD[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, "The number of syncs per PD n.");
986 AssertRC(rc);
987
988 RTStrPrintf(szName, sizeof(szName), "/PGM/GC/PD/SyncPage/%04X", i);
989 rc = STAMR3Register(pVM, &pPGM->StatGCSyncPagePD[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, szName, STAMUNIT_OCCURENCES, "The number of out of sync pages per page directory n.");
990 AssertRC(rc);
991 }
992}
993#endif /* VBOX_WITH_STATISTICS */
994
995/**
996 * Init the PGM bits that rely on VMMR0 and MM to be fully initialized.
997 *
998 * The dynamic mapping area will also be allocated and initialized at this
999 * time. We could allocate it during PGMR3Init of course, but the mapping
1000 * wouldn't be allocated at that time preventing us from setting up the
1001 * page table entries with the dummy page.
1002 *
1003 * @returns VBox status code.
1004 * @param pVM VM handle.
1005 */
1006PGMR3DECL(int) PGMR3InitDynMap(PVM pVM)
1007{
1008 /*
1009 * Reserve space for mapping the paging pages into guest context.
1010 */
1011 int rc = MMR3HyperReserve(pVM, PAGE_SIZE * (2 + ELEMENTS(pVM->pgm.s.apHCPaePDs) + 1 + 2 + 2), "Paging", &pVM->pgm.s.pGC32BitPD);
1012 AssertRCReturn(rc, rc);
1013 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
1014
1015 /*
1016 * Reserve space for the dynamic mappings.
1017 */
1018 /** @todo r=bird: Need to verify that the checks for crossing PTs are correct here. They seems to be assuming 4MB PTs.. */
1019 rc = MMR3HyperReserve(pVM, MM_HYPER_DYNAMIC_SIZE, "Dynamic mapping", &pVM->pgm.s.pbDynPageMapBaseGC);
1020 if ( VBOX_SUCCESS(rc)
1021 && (pVM->pgm.s.pbDynPageMapBaseGC >> PGDIR_SHIFT) != ((pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE - 1) >> PGDIR_SHIFT))
1022 rc = MMR3HyperReserve(pVM, MM_HYPER_DYNAMIC_SIZE, "Dynamic mapping not crossing", &pVM->pgm.s.pbDynPageMapBaseGC);
1023 if (VBOX_SUCCESS(rc))
1024 {
1025 AssertRelease((pVM->pgm.s.pbDynPageMapBaseGC >> PGDIR_SHIFT) == ((pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE - 1) >> PGDIR_SHIFT));
1026 MMR3HyperReserve(pVM, PAGE_SIZE, "fence", NULL);
1027 }
1028 return rc;
1029}
1030
1031
1032/**
1033 * Ring-3 init finalizing.
1034 *
1035 * @returns VBox status code.
1036 * @param pVM The VM handle.
1037 */
1038PGMR3DECL(int) PGMR3InitFinalize(PVM pVM)
1039{
1040 /*
1041 * Map the paging pages into the guest context.
1042 */
1043 RTGCPTR GCPtr = pVM->pgm.s.pGC32BitPD;
1044 AssertReleaseReturn(GCPtr, VERR_INTERNAL_ERROR);
1045
1046 int rc = PGMMap(pVM, GCPtr, pVM->pgm.s.HCPhys32BitPD, PAGE_SIZE, 0);
1047 AssertRCReturn(rc, rc);
1048 pVM->pgm.s.pGC32BitPD = GCPtr;
1049 GCPtr += PAGE_SIZE;
1050 GCPtr += PAGE_SIZE; /* reserved page */
1051
1052 for (unsigned i = 0; i < ELEMENTS(pVM->pgm.s.apHCPaePDs); i++)
1053 {
1054 rc = PGMMap(pVM, GCPtr, pVM->pgm.s.aHCPhysPaePDs[i], PAGE_SIZE, 0);
1055 AssertRCReturn(rc, rc);
1056 pVM->pgm.s.apGCPaePDs[i] = GCPtr;
1057 GCPtr += PAGE_SIZE;
1058 }
1059 /* A bit of paranoia is justified. */
1060 AssertRelease((RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[0] + PAGE_SIZE == (RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[1]);
1061 AssertRelease((RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[1] + PAGE_SIZE == (RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[2]);
1062 AssertRelease((RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[2] + PAGE_SIZE == (RTGCUINTPTR)pVM->pgm.s.apGCPaePDs[3]);
1063 GCPtr += PAGE_SIZE; /* reserved page */
1064
1065 rc = PGMMap(pVM, GCPtr, pVM->pgm.s.HCPhysPaePDPTR, PAGE_SIZE, 0);
1066 AssertRCReturn(rc, rc);
1067 pVM->pgm.s.pGCPaePDPTR = GCPtr;
1068 GCPtr += PAGE_SIZE;
1069 GCPtr += PAGE_SIZE; /* reserved page */
1070
1071 rc = PGMMap(pVM, GCPtr, pVM->pgm.s.HCPhysPaePML4, PAGE_SIZE, 0);
1072 AssertRCReturn(rc, rc);
1073 pVM->pgm.s.pGCPaePML4 = GCPtr;
1074 GCPtr += PAGE_SIZE;
1075 GCPtr += PAGE_SIZE; /* reserved page */
1076
1077
1078 /*
1079 * Reserve space for the dynamic mappings.
1080 * Initialize the dynamic mapping pages with dummy pages to simply the cache.
1081 */
1082 /* get the pointer to the page table entries. */
1083 PPGMMAPPING pMapping = pgmGetMapping(pVM, pVM->pgm.s.pbDynPageMapBaseGC);
1084 AssertRelease(pMapping);
1085 const uintptr_t off = pVM->pgm.s.pbDynPageMapBaseGC - pMapping->GCPtr;
1086 const unsigned iPT = off >> X86_PD_SHIFT;
1087 const unsigned iPG = (off >> X86_PT_SHIFT) & X86_PT_MASK;
1088 pVM->pgm.s.paDynPageMap32BitPTEsGC = pMapping->aPTs[iPT].pPTGC + iPG * sizeof(pMapping->aPTs[0].pPTHC->a[0]);
1089 pVM->pgm.s.paDynPageMapPaePTEsGC = pMapping->aPTs[iPT].paPaePTsGC + iPG * sizeof(pMapping->aPTs[0].paPaePTsHC->a[0]);
1090
1091 /* init cache */
1092 RTHCPHYS HCPhysDummy = MMR3PageDummyHCPhys(pVM);
1093 for (unsigned i = 0; i < ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache); i++)
1094 pVM->pgm.s.aHCPhysDynPageMapCache[i] = HCPhysDummy;
1095
1096 for (unsigned i = 0; i < MM_HYPER_DYNAMIC_SIZE; i += PAGE_SIZE)
1097 {
1098 rc = PGMMap(pVM, pVM->pgm.s.pbDynPageMapBaseGC + i, HCPhysDummy, PAGE_SIZE, 0);
1099 AssertRCReturn(rc, rc);
1100 }
1101
1102 return rc;
1103}
1104
1105
1106/**
1107 * Applies relocations to data and code managed by this
1108 * component. This function will be called at init and
1109 * whenever the VMM need to relocate it self inside the GC.
1110 *
1111 * @param pVM The VM.
1112 * @param offDelta Relocation delta relative to old location.
1113 */
1114PGMR3DECL(void) PGMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
1115{
1116 LogFlow(("PGMR3Relocate\n"));
1117
1118 /*
1119 * Paging stuff.
1120 */
1121 pVM->pgm.s.GCPtrCR3Mapping += offDelta;
1122 /** @todo move this into shadow and guest specific relocation functions. */
1123 AssertMsg(pVM->pgm.s.pGC32BitPD, ("Init order, no relocation before paging is initialized!\n"));
1124 pVM->pgm.s.pGC32BitPD += offDelta;
1125 pVM->pgm.s.pGuestPDGC += offDelta;
1126 for (unsigned i = 0; i < ELEMENTS(pVM->pgm.s.apGCPaePDs); i++)
1127 pVM->pgm.s.apGCPaePDs[i] += offDelta;
1128 pVM->pgm.s.pGCPaePDPTR += offDelta;
1129 pVM->pgm.s.pGCPaePML4 += offDelta;
1130
1131 pgmR3ModeDataInit(pVM, true /* resolve GC/R0 symbols */);
1132 pgmR3ModeDataSwitch(pVM, pVM->pgm.s.enmShadowMode, pVM->pgm.s.enmGuestMode);
1133
1134 PGM_SHW_PFN(Relocate, pVM)(pVM, offDelta);
1135 PGM_GST_PFN(Relocate, pVM)(pVM, offDelta);
1136 PGM_BTH_PFN(Relocate, pVM)(pVM, offDelta);
1137
1138 /*
1139 * Trees.
1140 */
1141 pVM->pgm.s.pTreesGC = MMHyperHC2GC(pVM, pVM->pgm.s.pTreesHC);
1142
1143 /*
1144 * Ram ranges.
1145 */
1146 if (pVM->pgm.s.pRamRangesHC)
1147 {
1148 pVM->pgm.s.pRamRangesGC = MMHyperHC2GC(pVM, pVM->pgm.s.pRamRangesHC);
1149 for (PPGMRAMRANGE pCur = pVM->pgm.s.pRamRangesHC; pCur->pNextHC; pCur = pCur->pNextHC)
1150 {
1151 pCur->pNextGC = MMHyperHC2GC(pVM, pCur->pNextHC);
1152 if (pCur->pavHCChunkGC)
1153 pCur->pavHCChunkGC = MMHyperHC2GC(pVM, pCur->pavHCChunkHC);
1154 }
1155 }
1156
1157 /*
1158 * Update the two page directories with all page table mappings.
1159 * (One or more of them have changed, that's why we're here.)
1160 */
1161 pVM->pgm.s.pMappingsGC = MMHyperHC2GC(pVM, pVM->pgm.s.pMappingsHC);
1162 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsHC; pCur->pNextHC; pCur = pCur->pNextHC)
1163 pCur->pNextGC = MMHyperHC2GC(pVM, pCur->pNextHC);
1164
1165 /* Relocate GC addresses of Page Tables. */
1166 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsHC; pCur; pCur = pCur->pNextHC)
1167 {
1168 for (RTHCUINT i = 0; i < pCur->cPTs; i++)
1169 {
1170 pCur->aPTs[i].pPTGC = MMHyperHC2GC(pVM, pCur->aPTs[i].pPTHC);
1171 pCur->aPTs[i].paPaePTsGC = MMHyperHC2GC(pVM, pCur->aPTs[i].paPaePTsHC);
1172 }
1173 }
1174
1175 /*
1176 * Dynamic page mapping area.
1177 */
1178 pVM->pgm.s.paDynPageMap32BitPTEsGC += offDelta;
1179 pVM->pgm.s.paDynPageMapPaePTEsGC += offDelta;
1180 pVM->pgm.s.pbDynPageMapBaseGC += offDelta;
1181
1182 /*
1183 * Physical and virtual handlers.
1184 */
1185 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, true, pgmR3RelocatePhysHandler, &offDelta);
1186 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesHC->VirtHandlers, true, pgmR3RelocateVirtHandler, &offDelta);
1187
1188 /*
1189 * The page pool.
1190 */
1191 pgmR3PoolRelocate(pVM);
1192}
1193
1194
1195/**
1196 * Callback function for relocating a physical access handler.
1197 *
1198 * @returns 0 (continue enum)
1199 * @param pNode Pointer to a PGMPHYSHANDLER node.
1200 * @param pvUser Pointer to the offDelta. This is a pointer to the delta since we're
1201 * not certain the delta will fit in a void pointer for all possible configs.
1202 */
1203static DECLCALLBACK(int) pgmR3RelocatePhysHandler(PAVLROGCPHYSNODECORE pNode, void *pvUser)
1204{
1205 PPGMPHYSHANDLER pHandler = (PPGMPHYSHANDLER)pNode;
1206 RTGCINTPTR offDelta = *(PRTGCINTPTR)pvUser;
1207 Assert(pHandler->pfnHandlerGC);
1208 pHandler->pfnHandlerGC += offDelta;
1209 if (pHandler->pvUserGC)
1210 pHandler->pvUserGC += offDelta;
1211 return 0;
1212}
1213
1214/**
1215 * Callback function for relocating a virtual access handler.
1216 *
1217 * @returns 0 (continue enum)
1218 * @param pNode Pointer to a PGMVIRTHANDLER node.
1219 * @param pvUser Pointer to the offDelta. This is a pointer to the delta since we're
1220 * not certain the delta will fit in a void pointer for all possible configs.
1221 */
1222static DECLCALLBACK(int) pgmR3RelocateVirtHandler(PAVLROGCPTRNODECORE pNode, void *pvUser)
1223{
1224 PPGMVIRTHANDLER pHandler = (PPGMVIRTHANDLER)pNode;
1225 RTGCINTPTR offDelta = *(PRTGCINTPTR)pvUser;
1226 Assert(pHandler->pfnHandlerGC);
1227 pHandler->pfnHandlerGC += offDelta;
1228 return 0;
1229}
1230
1231
1232/**
1233 * The VM is being reset.
1234 *
1235 * For the PGM component this means that any PD write monitors
1236 * needs to be removed.
1237 *
1238 * @param pVM VM handle.
1239 */
1240PGMR3DECL(void) PGMR3Reset(PVM pVM)
1241{
1242 LogFlow(("PGMR3Reset:\n"));
1243 VM_ASSERT_EMT(pVM);
1244
1245 /*
1246 * Unfix any fixed mappings and disable CR3 monitoring.
1247 */
1248 pVM->pgm.s.fMappingsFixed = false;
1249 pVM->pgm.s.GCPtrMappingFixed = 0;
1250 pVM->pgm.s.cbMappingFixed = 0;
1251
1252 int rc = PGM_GST_PFN(UnmonitorCR3, pVM)(pVM);
1253 AssertRC(rc);
1254#ifdef DEBUG
1255 PGMR3DumpMappings(pVM);
1256#endif
1257
1258 /*
1259 * Reset the shadow page pool.
1260 */
1261 pgmR3PoolReset(pVM);
1262
1263 /*
1264 * Re-init other members.
1265 */
1266 pVM->pgm.s.fA20Enabled = true;
1267
1268 /*
1269 * Clear the FFs PGM owns.
1270 */
1271 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3);
1272 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL);
1273
1274 /*
1275 * Zero memory.
1276 */
1277 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesHC; pRam; pRam = pRam->pNextHC)
1278 {
1279 unsigned iPage = pRam->cb >> PAGE_SHIFT;
1280 while (iPage-- > 0)
1281 {
1282 if (pRam->aHCPhys[iPage] & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2))
1283 {
1284 Log4(("PGMR3Reset: not clearing phys page %RGp due to flags %RHp\n", pRam->GCPhys + (iPage << PAGE_SHIFT), pRam->aHCPhys[iPage] & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO)));
1285 continue;
1286 }
1287 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
1288 {
1289 unsigned iChunk = iPage >> (PGM_DYNAMIC_CHUNK_SHIFT - PAGE_SHIFT);
1290 if (pRam->pavHCChunkHC[iChunk])
1291 ASMMemZero32((char *)pRam->pavHCChunkHC[iChunk] + ((iPage << PAGE_SHIFT) & PGM_DYNAMIC_CHUNK_OFFSET_MASK), PAGE_SIZE);
1292 }
1293 else
1294 ASMMemZero32((char *)pRam->pvHC + (iPage << PAGE_SHIFT), PAGE_SIZE);
1295 }
1296 }
1297
1298 /*
1299 * Switch mode back to real mode.
1300 */
1301 rc = pgmR3ChangeMode(pVM, PGMMODE_REAL);
1302 AssertReleaseRC(rc);
1303 STAM_REL_COUNTER_RESET(&pVM->pgm.s.cGuestModeChanges);
1304}
1305
1306
1307/**
1308 * Terminates the PGM.
1309 *
1310 * @returns VBox status code.
1311 * @param pVM Pointer to VM structure.
1312 */
1313PGMR3DECL(int) PGMR3Term(PVM pVM)
1314{
1315 return PDMR3CritSectDelete(&pVM->pgm.s.CritSect);
1316}
1317
1318
1319/**
1320 * Execute state save operation.
1321 *
1322 * @returns VBox status code.
1323 * @param pVM VM Handle.
1324 * @param pSSM SSM operation handle.
1325 */
1326static DECLCALLBACK(int) pgmR3Save(PVM pVM, PSSMHANDLE pSSM)
1327{
1328 PPGM pPGM = &pVM->pgm.s;
1329
1330 /*
1331 * Save basic data (required / unaffected by relocation).
1332 */
1333#if 1
1334 SSMR3PutBool(pSSM, pPGM->fMappingsFixed);
1335#else
1336 SSMR3PutUInt(pSSM, pPGM->fMappingsFixed);
1337#endif
1338 SSMR3PutGCPtr(pSSM, pPGM->GCPtrMappingFixed);
1339 SSMR3PutU32(pSSM, pPGM->cbMappingFixed);
1340 SSMR3PutUInt(pSSM, pPGM->cbRamSize);
1341 SSMR3PutGCPhys(pSSM, pPGM->GCPhysA20Mask);
1342 SSMR3PutUInt(pSSM, pPGM->fA20Enabled);
1343 SSMR3PutUInt(pSSM, pPGM->fSyncFlags);
1344 SSMR3PutUInt(pSSM, pPGM->enmGuestMode);
1345 SSMR3PutU32(pSSM, ~0); /* Separator. */
1346
1347 /*
1348 * The guest mappings.
1349 */
1350 uint32_t i = 0;
1351 for (PPGMMAPPING pMapping = pPGM->pMappingsHC; pMapping; pMapping = pMapping->pNextHC, i++)
1352 {
1353 SSMR3PutU32(pSSM, i);
1354 SSMR3PutStrZ(pSSM, pMapping->pszDesc); /* This is the best unique id we have... */
1355 SSMR3PutGCPtr(pSSM, pMapping->GCPtr);
1356 SSMR3PutGCUIntPtr(pSSM, pMapping->cPTs);
1357 /* flags are done by the mapping owners! */
1358 }
1359 SSMR3PutU32(pSSM, ~0); /* terminator. */
1360
1361 /*
1362 * Ram range flags and bits.
1363 */
1364 i = 0;
1365 for (PPGMRAMRANGE pRam = pPGM->pRamRangesHC; pRam; pRam = pRam->pNextHC, i++)
1366 {
1367 /** @todo MMIO ranges may move (PCI reconfig), we currently assume they don't. */
1368
1369 SSMR3PutU32(pSSM, i);
1370 SSMR3PutGCPhys(pSSM, pRam->GCPhys);
1371 SSMR3PutGCPhys(pSSM, pRam->GCPhysLast);
1372 SSMR3PutGCPhys(pSSM, pRam->cb);
1373 SSMR3PutU8(pSSM, !!pRam->pvHC); /* boolean indicating memory or not. */
1374
1375 /* Flags. */
1376 const unsigned cPages = pRam->cb >> PAGE_SHIFT;
1377 for (unsigned iPage = 0; iPage < cPages; iPage++)
1378 SSMR3PutU16(pSSM, (uint16_t)(pRam->aHCPhys[iPage] & ~X86_PTE_PAE_PG_MASK));
1379
1380 /* any memory associated with the range. */
1381 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
1382 {
1383 for (unsigned iChunk = 0; iChunk < (pRam->cb >> PGM_DYNAMIC_CHUNK_SHIFT); iChunk++)
1384 {
1385 if (pRam->pavHCChunkHC[iChunk])
1386 {
1387 SSMR3PutU8(pSSM, 1); /* chunk present */
1388 SSMR3PutMem(pSSM, pRam->pavHCChunkHC[iChunk], PGM_DYNAMIC_CHUNK_SIZE);
1389 }
1390 else
1391 SSMR3PutU8(pSSM, 0); /* no chunk present */
1392 }
1393 }
1394 else if (pRam->pvHC)
1395 {
1396 int rc = SSMR3PutMem(pSSM, pRam->pvHC, pRam->cb);
1397 if (VBOX_FAILURE(rc))
1398 {
1399 Log(("pgmR3Save: SSMR3PutMem(, %p, %#x) -> %Vrc\n", pRam->pvHC, pRam->cb, rc));
1400 return rc;
1401 }
1402 }
1403 }
1404 return SSMR3PutU32(pSSM, ~0); /* terminator. */
1405}
1406
1407
1408/**
1409 * Execute state load operation.
1410 *
1411 * @returns VBox status code.
1412 * @param pVM VM Handle.
1413 * @param pSSM SSM operation handle.
1414 * @param u32Version Data layout version.
1415 */
1416static DECLCALLBACK(int) pgmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
1417{
1418 /*
1419 * Validate version.
1420 */
1421 if (u32Version != PGM_SAVED_STATE_VERSION)
1422 {
1423 Log(("pgmR3Load: Invalid version u32Version=%d (current %d)!\n", u32Version, PGM_SAVED_STATE_VERSION));
1424 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1425 }
1426
1427 /*
1428 * Call the reset function to make sure all the memory is cleared.
1429 */
1430 PGMR3Reset(pVM);
1431
1432 /*
1433 * Load basic data (required / unaffected by relocation).
1434 */
1435 PPGM pPGM = &pVM->pgm.s;
1436#if 1
1437 SSMR3GetBool(pSSM, &pPGM->fMappingsFixed);
1438#else
1439 uint32_t u;
1440 SSMR3GetU32(pSSM, &u);
1441 pPGM->fMappingsFixed = u;
1442#endif
1443 SSMR3GetGCPtr(pSSM, &pPGM->GCPtrMappingFixed);
1444 SSMR3GetU32(pSSM, &pPGM->cbMappingFixed);
1445
1446 RTUINT cbRamSize;
1447 int rc = SSMR3GetU32(pSSM, &cbRamSize);
1448 if (VBOX_FAILURE(rc))
1449 return rc;
1450 if (cbRamSize != pPGM->cbRamSize)
1451 return VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH;
1452 SSMR3GetGCPhys(pSSM, &pPGM->GCPhysA20Mask);
1453 SSMR3GetUInt(pSSM, &pPGM->fA20Enabled);
1454 SSMR3GetUInt(pSSM, &pPGM->fSyncFlags);
1455 RTUINT uGuestMode;
1456 SSMR3GetUInt(pSSM, &uGuestMode);
1457 pPGM->enmGuestMode = (PGMMODE)uGuestMode;
1458
1459 /* check separator. */
1460 uint32_t u32Sep;
1461 SSMR3GetU32(pSSM, &u32Sep);
1462 if (VBOX_FAILURE(rc))
1463 return rc;
1464 if (u32Sep != (uint32_t)~0)
1465 {
1466 AssertMsgFailed(("u32Sep=%#x (first)\n", u32Sep));
1467 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1468 }
1469
1470 /*
1471 * The guest mappings.
1472 */
1473 uint32_t i = 0;
1474 for (;; i++)
1475 {
1476 /* Check the seqence number / separator. */
1477 rc = SSMR3GetU32(pSSM, &u32Sep);
1478 if (VBOX_FAILURE(rc))
1479 return rc;
1480 if (u32Sep == ~0U)
1481 break;
1482 if (u32Sep != i)
1483 {
1484 AssertMsgFailed(("u32Sep=%#x (last)\n", u32Sep));
1485 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1486 }
1487
1488 /* get the mapping details. */
1489 char szDesc[256];
1490 szDesc[0] = '\0';
1491 rc = SSMR3GetStrZ(pSSM, szDesc, sizeof(szDesc));
1492 if (VBOX_FAILURE(rc))
1493 return rc;
1494 RTGCPTR GCPtr;
1495 SSMR3GetGCPtr(pSSM, &GCPtr);
1496 RTGCUINTPTR cPTs;
1497 rc = SSMR3GetU32(pSSM, &cPTs);
1498 if (VBOX_FAILURE(rc))
1499 return rc;
1500
1501 /* find matching range. */
1502 PPGMMAPPING pMapping;
1503 for (pMapping = pPGM->pMappingsHC; pMapping; pMapping = pMapping->pNextHC)
1504 if ( pMapping->cPTs == cPTs
1505 && !strcmp(pMapping->pszDesc, szDesc))
1506 break;
1507 if (!pMapping)
1508 {
1509 LogRel(("Couldn't find mapping: cPTs=%#x szDesc=%s (GCPtr=%VGv)\n",
1510 cPTs, szDesc, GCPtr));
1511 AssertFailed();
1512 return VERR_SSM_LOAD_CONFIG_MISMATCH;
1513 }
1514
1515 /* relocate it. */
1516 if (pMapping->GCPtr != GCPtr)
1517 {
1518 AssertMsg((GCPtr >> PGDIR_SHIFT << PGDIR_SHIFT) == GCPtr, ("GCPtr=%VGv\n", GCPtr));
1519#if HC_ARCH_BITS == 64
1520LogRel(("Mapping: %VGv -> %VGv %s\n", pMapping->GCPtr, GCPtr, pMapping->pszDesc));
1521#endif
1522 pgmR3MapRelocate(pVM, pMapping, pMapping->GCPtr >> PGDIR_SHIFT, GCPtr >> PGDIR_SHIFT);
1523 }
1524 else
1525 Log(("pgmR3Load: '%s' needed no relocation (%VGv)\n", szDesc, GCPtr));
1526 }
1527
1528 /*
1529 * Ram range flags and bits.
1530 */
1531 i = 0;
1532 for (PPGMRAMRANGE pRam = pPGM->pRamRangesHC; pRam; pRam = pRam->pNextHC, i++)
1533 {
1534 /** @todo MMIO ranges may move (PCI reconfig), we currently assume they don't. */
1535 /* Check the seqence number / separator. */
1536 rc = SSMR3GetU32(pSSM, &u32Sep);
1537 if (VBOX_FAILURE(rc))
1538 return rc;
1539 if (u32Sep == ~0U)
1540 break;
1541 if (u32Sep != i)
1542 {
1543 AssertMsgFailed(("u32Sep=%#x (last)\n", u32Sep));
1544 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1545 }
1546
1547 /* Get the range details. */
1548 RTGCPHYS GCPhys;
1549 SSMR3GetGCPhys(pSSM, &GCPhys);
1550 RTGCPHYS GCPhysLast;
1551 SSMR3GetGCPhys(pSSM, &GCPhysLast);
1552 RTGCPHYS cb;
1553 SSMR3GetGCPhys(pSSM, &cb);
1554 uint8_t fHaveBits;
1555 rc = SSMR3GetU8(pSSM, &fHaveBits);
1556 if (VBOX_FAILURE(rc))
1557 return rc;
1558 if (fHaveBits & ~1)
1559 {
1560 AssertMsgFailed(("u32Sep=%#x (last)\n", u32Sep));
1561 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1562 }
1563
1564 /* Match it up with the current range. */
1565 if ( GCPhys != pRam->GCPhys
1566 || GCPhysLast != pRam->GCPhysLast
1567 || cb != pRam->cb
1568 || fHaveBits != !!pRam->pvHC)
1569 {
1570 LogRel(("Ram range: %VGp-%VGp %VGp bytes %s\n"
1571 "State : %VGp-%VGp %VGp bytes %s\n",
1572 pRam->GCPhys, pRam->GCPhysLast, pRam->cb, pRam->pvHC ? "bits" : "nobits",
1573 GCPhys, GCPhysLast, cb, fHaveBits ? "bits" : "nobits"));
1574 AssertFailed();
1575 return VERR_SSM_LOAD_CONFIG_MISMATCH;
1576 }
1577
1578 /* Flags. */
1579 const unsigned cPages = pRam->cb >> PAGE_SHIFT;
1580 for (unsigned iPage = 0; iPage < cPages; iPage++)
1581 {
1582 uint16_t u16 = 0;
1583 SSMR3GetU16(pSSM, &u16);
1584 u16 &= PAGE_OFFSET_MASK & ~( MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_VIRTUAL_ALL
1585 | MM_RAM_FLAGS_PHYSICAL_HANDLER | MM_RAM_FLAGS_PHYSICAL_WRITE | MM_RAM_FLAGS_PHYSICAL_ALL
1586 | MM_RAM_FLAGS_PHYSICAL_TEMP_OFF );
1587 pRam->aHCPhys[iPage] = (pRam->aHCPhys[iPage] & X86_PTE_PAE_PG_MASK) | (RTHCPHYS)u16;
1588 }
1589
1590 /* any memory associated with the range. */
1591 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
1592 {
1593 for (unsigned iChunk = 0; iChunk < (pRam->cb >> PGM_DYNAMIC_CHUNK_SHIFT); iChunk++)
1594 {
1595 uint8_t fValidChunk;
1596
1597 rc = SSMR3GetU8(pSSM, &fValidChunk);
1598 if (VBOX_FAILURE(rc))
1599 return rc;
1600 if (fValidChunk > 1)
1601 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1602
1603 if (fValidChunk)
1604 {
1605 if (!pRam->pavHCChunkHC[iChunk])
1606 {
1607 rc = pgmr3PhysGrowRange(pVM, pRam->GCPhys + iChunk * PGM_DYNAMIC_CHUNK_SIZE);
1608 if (VBOX_FAILURE(rc))
1609 return rc;
1610 }
1611 Assert(pRam->pavHCChunkHC[iChunk]);
1612
1613 SSMR3GetMem(pSSM, pRam->pavHCChunkHC[iChunk], PGM_DYNAMIC_CHUNK_SIZE);
1614 }
1615 /* else nothing to do */
1616 }
1617 }
1618 else if (pRam->pvHC)
1619 {
1620 int rc = SSMR3GetMem(pSSM, pRam->pvHC, pRam->cb);
1621 if (VBOX_FAILURE(rc))
1622 {
1623 Log(("pgmR3Save: SSMR3GetMem(, %p, %#x) -> %Vrc\n", pRam->pvHC, pRam->cb, rc));
1624 return rc;
1625 }
1626 }
1627 }
1628
1629 /*
1630 * We require a full resync now.
1631 */
1632 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL);
1633 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
1634 pPGM->fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL;
1635 pPGM->fPhysCacheFlushPending = true;
1636 pgmR3HandlerPhysicalUpdateAll(pVM);
1637
1638 /*
1639 * Change the paging mode.
1640 */
1641 return pgmR3ChangeMode(pVM, pPGM->enmGuestMode);
1642}
1643
1644
1645/**
1646 * Show paging mode.
1647 *
1648 * @param pVM VM Handle.
1649 * @param pHlp The info helpers.
1650 * @param pszArgs "all" (default), "guest", "shadow" or "host".
1651 */
1652static DECLCALLBACK(void) pgmR3InfoMode(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1653{
1654 /* digest argument. */
1655 bool fGuest, fShadow, fHost;
1656 if (pszArgs)
1657 pszArgs = RTStrStripL(pszArgs);
1658 if (!pszArgs || !*pszArgs || strstr(pszArgs, "all"))
1659 fShadow = fHost = fGuest = true;
1660 else
1661 {
1662 fShadow = fHost = fGuest = false;
1663 if (strstr(pszArgs, "guest"))
1664 fGuest = true;
1665 if (strstr(pszArgs, "shadow"))
1666 fShadow = true;
1667 if (strstr(pszArgs, "host"))
1668 fHost = true;
1669 }
1670
1671 /* print info. */
1672 if (fGuest)
1673 pHlp->pfnPrintf(pHlp, "Guest paging mode: %s, changed %RU64 times, A20 %s\n",
1674 PGMGetModeName(pVM->pgm.s.enmGuestMode), pVM->pgm.s.cGuestModeChanges.c,
1675 pVM->pgm.s.fA20Enabled ? "enabled" : "disabled");
1676 if (fShadow)
1677 pHlp->pfnPrintf(pHlp, "Shadow paging mode: %s\n", PGMGetModeName(pVM->pgm.s.enmShadowMode));
1678 if (fHost)
1679 {
1680 const char *psz;
1681 switch (pVM->pgm.s.enmHostMode)
1682 {
1683 case SUPPAGINGMODE_INVALID: psz = "invalid"; break;
1684 case SUPPAGINGMODE_32_BIT: psz = "32-bit"; break;
1685 case SUPPAGINGMODE_32_BIT_GLOBAL: psz = "32-bit+G"; break;
1686 case SUPPAGINGMODE_PAE: psz = "PAE"; break;
1687 case SUPPAGINGMODE_PAE_GLOBAL: psz = "PAE+G"; break;
1688 case SUPPAGINGMODE_PAE_NX: psz = "PAE+NX"; break;
1689 case SUPPAGINGMODE_PAE_GLOBAL_NX: psz = "PAE+G+NX"; break;
1690 case SUPPAGINGMODE_AMD64: psz = "AMD64"; break;
1691 case SUPPAGINGMODE_AMD64_GLOBAL: psz = "AMD64+G"; break;
1692 case SUPPAGINGMODE_AMD64_NX: psz = "AMD64+NX"; break;
1693 case SUPPAGINGMODE_AMD64_GLOBAL_NX: psz = "AMD64+G+NX"; break;
1694 default: psz = "unknown"; break;
1695 }
1696 pHlp->pfnPrintf(pHlp, "Host paging mode: %s\n", psz);
1697 }
1698}
1699
1700
1701/**
1702 * Dump registered MMIO ranges to the log.
1703 *
1704 * @param pVM VM Handle.
1705 * @param pHlp The info helpers.
1706 * @param pszArgs Arguments, ignored.
1707 */
1708static DECLCALLBACK(void) pgmR3PhysInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1709{
1710 NOREF(pszArgs);
1711 pHlp->pfnPrintf(pHlp,
1712 "RAM ranges (pVM=%p)\n"
1713 "%.*s %.*s\n",
1714 pVM,
1715 sizeof(RTGCPHYS) * 4 + 1, "GC Phys Range ",
1716 sizeof(RTHCPTR) * 2, "pvHC ");
1717
1718 for (PPGMRAMRANGE pCur = pVM->pgm.s.pRamRangesHC; pCur; pCur = pCur->pNextHC)
1719 pHlp->pfnPrintf(pHlp,
1720 "%VGp-%VGp %VHv\n",
1721 pCur->GCPhys,
1722 pCur->GCPhysLast,
1723 pCur->pvHC);
1724}
1725
1726/**
1727 * Dump the page directory to the log.
1728 *
1729 * @param pVM VM Handle.
1730 * @param pHlp The info helpers.
1731 * @param pszArgs Arguments, ignored.
1732 */
1733static DECLCALLBACK(void) pgmR3InfoCr3(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1734{
1735/** @todo fix this! Convert the PGMR3DumpHierarchyHC functions to do guest stuff. */
1736 /* Big pages supported? */
1737 const bool fPSE = !!(CPUMGetGuestCR4(pVM) & X86_CR4_PSE);
1738 /* Global pages supported? */
1739 const bool fPGE = !!(CPUMGetGuestCR4(pVM) & X86_CR4_PGE);
1740
1741 NOREF(pszArgs);
1742
1743 /*
1744 * Get page directory addresses.
1745 */
1746 PVBOXPD pPDSrc = pVM->pgm.s.pGuestPDHC;
1747 Assert(pPDSrc);
1748 Assert(MMPhysGCPhys2HCVirt(pVM, (RTGCPHYS)(CPUMGetGuestCR3(pVM) & X86_CR3_PAGE_MASK), sizeof(*pPDSrc)) == pPDSrc);
1749
1750 /*
1751 * Iterate the page directory.
1752 */
1753 for (unsigned iPD = 0; iPD < ELEMENTS(pPDSrc->a); iPD++)
1754 {
1755 VBOXPDE PdeSrc = pPDSrc->a[iPD];
1756 if (PdeSrc.n.u1Present)
1757 {
1758 if (PdeSrc.b.u1Size && fPSE)
1759 {
1760 pHlp->pfnPrintf(pHlp,
1761 "%04X - %VGp P=%d U=%d RW=%d G=%d - BIG\n",
1762 iPD,
1763 PdeSrc.u & X86_PDE_PG_MASK,
1764 PdeSrc.b.u1Present, PdeSrc.b.u1User, PdeSrc.b.u1Write, PdeSrc.b.u1Global && fPGE);
1765 }
1766 else
1767 {
1768 pHlp->pfnPrintf(pHlp,
1769 "%04X - %VGp P=%d U=%d RW=%d [G=%d]\n",
1770 iPD,
1771 PdeSrc.u & X86_PDE4M_PG_MASK,
1772 PdeSrc.n.u1Present, PdeSrc.n.u1User, PdeSrc.n.u1Write, PdeSrc.b.u1Global && fPGE);
1773 }
1774 }
1775 }
1776}
1777
1778
1779/**
1780 * Serivce a VMMCALLHOST_PGM_LOCK call.
1781 *
1782 * @returns VBox status code.
1783 * @param pVM The VM handle.
1784 */
1785PDMR3DECL(int) PGMR3LockCall(PVM pVM)
1786{
1787 return pgmLock(pVM);
1788}
1789
1790
1791/**
1792 * Converts a PGMMODE value to a PGM_TYPE_* \#define.
1793 *
1794 * @returns PGM_TYPE_*.
1795 * @param pgmMode The mode value to convert.
1796 */
1797DECLINLINE(unsigned) pgmModeToType(PGMMODE pgmMode)
1798{
1799 switch (pgmMode)
1800 {
1801 case PGMMODE_REAL: return PGM_TYPE_REAL;
1802 case PGMMODE_PROTECTED: return PGM_TYPE_PROT;
1803 case PGMMODE_32_BIT: return PGM_TYPE_32BIT;
1804 case PGMMODE_PAE:
1805 case PGMMODE_PAE_NX: return PGM_TYPE_PAE;
1806 case PGMMODE_AMD64:
1807 case PGMMODE_AMD64_NX: return PGM_TYPE_AMD64;
1808 default:
1809 AssertFatalMsgFailed(("pgmMode=%d\n", pgmMode));
1810 }
1811}
1812
1813
1814/**
1815 * Gets the index into the paging mode data array of a SHW+GST mode.
1816 *
1817 * @returns PGM::paPagingData index.
1818 * @param uShwType The shadow paging mode type.
1819 * @param uGstType The guest paging mode type.
1820 */
1821DECLINLINE(unsigned) pgmModeDataIndex(unsigned uShwType, unsigned uGstType)
1822{
1823 Assert(uShwType >= PGM_TYPE_32BIT && uShwType <= PGM_TYPE_AMD64);
1824 Assert(uGstType >= PGM_TYPE_REAL && uGstType <= PGM_TYPE_AMD64);
1825 return (uShwType - PGM_TYPE_32BIT) * (PGM_TYPE_AMD64 - PGM_TYPE_32BIT + 1)
1826 + (uGstType - PGM_TYPE_REAL);
1827}
1828
1829
1830/**
1831 * Gets the index into the paging mode data array of a SHW+GST mode.
1832 *
1833 * @returns PGM::paPagingData index.
1834 * @param enmShw The shadow paging mode.
1835 * @param enmGst The guest paging mode.
1836 */
1837DECLINLINE(unsigned) pgmModeDataIndexByMode(PGMMODE enmShw, PGMMODE enmGst)
1838{
1839 Assert(enmShw >= PGMMODE_32_BIT && enmShw <= PGMMODE_MAX);
1840 Assert(enmGst > PGMMODE_INVALID && enmGst < PGMMODE_MAX);
1841 return pgmModeDataIndex(pgmModeToType(enmShw), pgmModeToType(enmGst));
1842}
1843
1844
1845/**
1846 * Calculates the max data index.
1847 * @returns The number of entries in the pagaing data array.
1848 */
1849DECLINLINE(unsigned) pgmModeDataMaxIndex(void)
1850{
1851 return pgmModeDataIndex(PGM_TYPE_AMD64, PGM_TYPE_AMD64) + 1;
1852}
1853
1854
1855/**
1856 * Initializes the paging mode data kept in PGM::paModeData.
1857 *
1858 * @param pVM The VM handle.
1859 * @param fResolveGCAndR0 Indicate whether or not GC and Ring-0 symbols can be resolved now.
1860 * This is used early in the init process to avoid trouble with PDM
1861 * not being initialized yet.
1862 */
1863static int pgmR3ModeDataInit(PVM pVM, bool fResolveGCAndR0)
1864{
1865 PPGMMODEDATA pModeData;
1866 int rc;
1867
1868 /*
1869 * Allocate the array on the first call.
1870 */
1871 if (!pVM->pgm.s.paModeData)
1872 {
1873 pVM->pgm.s.paModeData = (PPGMMODEDATA)MMR3HeapAllocZ(pVM, MM_TAG_PGM, sizeof(PGMMODEDATA) * pgmModeDataMaxIndex());
1874 AssertReturn(pVM->pgm.s.paModeData, VERR_NO_MEMORY);
1875 }
1876
1877 /*
1878 * Initialize the array entries.
1879 */
1880 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_32BIT, PGM_TYPE_REAL)];
1881 pModeData->uShwType = PGM_TYPE_32BIT;
1882 pModeData->uGstType = PGM_TYPE_REAL;
1883 rc = PGM_SHW_NAME_32BIT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1884 rc = PGM_GST_NAME_REAL(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1885 rc = PGM_BTH_NAME_32BIT_REAL(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1886
1887 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_32BIT, PGMMODE_PROTECTED)];
1888 pModeData->uShwType = PGM_TYPE_32BIT;
1889 pModeData->uGstType = PGM_TYPE_PROT;
1890 rc = PGM_SHW_NAME_32BIT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1891 rc = PGM_GST_NAME_PROT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1892 rc = PGM_BTH_NAME_32BIT_PROT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1893
1894 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_32BIT, PGM_TYPE_32BIT)];
1895 pModeData->uShwType = PGM_TYPE_32BIT;
1896 pModeData->uGstType = PGM_TYPE_32BIT;
1897 rc = PGM_SHW_NAME_32BIT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1898 rc = PGM_GST_NAME_32BIT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1899 rc = PGM_BTH_NAME_32BIT_32BIT(InitData)(pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1900
1901 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_PAE, PGM_TYPE_REAL)];
1902 pModeData->uShwType = PGM_TYPE_PAE;
1903 pModeData->uGstType = PGM_TYPE_REAL;
1904 rc = PGM_SHW_NAME_PAE(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1905 rc = PGM_GST_NAME_REAL(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1906 rc = PGM_BTH_NAME_PAE_REAL(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1907
1908 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_PAE, PGM_TYPE_PROT)];
1909 pModeData->uShwType = PGM_TYPE_PAE;
1910 pModeData->uGstType = PGM_TYPE_PROT;
1911 rc = PGM_SHW_NAME_PAE(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1912 rc = PGM_GST_NAME_PROT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1913 rc = PGM_BTH_NAME_PAE_PROT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1914
1915 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_PAE, PGM_TYPE_32BIT)];
1916 pModeData->uShwType = PGM_TYPE_PAE;
1917 pModeData->uGstType = PGM_TYPE_32BIT;
1918 rc = PGM_SHW_NAME_PAE(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1919 rc = PGM_GST_NAME_32BIT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1920 rc = PGM_BTH_NAME_PAE_32BIT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1921
1922 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_PAE, PGM_TYPE_PAE)];
1923 pModeData->uShwType = PGM_TYPE_PAE;
1924 pModeData->uGstType = PGM_TYPE_PAE;
1925 rc = PGM_SHW_NAME_PAE(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1926 rc = PGM_GST_NAME_PAE(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1927 rc = PGM_BTH_NAME_PAE_PAE(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1928
1929 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_AMD64, PGM_TYPE_REAL)];
1930 pModeData->uShwType = PGM_TYPE_AMD64;
1931 pModeData->uGstType = PGM_TYPE_REAL;
1932 rc = PGM_SHW_NAME_AMD64(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1933 rc = PGM_GST_NAME_REAL(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1934 rc = PGM_BTH_NAME_AMD64_REAL(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1935
1936 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_AMD64, PGM_TYPE_PROT)];
1937 pModeData->uShwType = PGM_TYPE_AMD64;
1938 pModeData->uGstType = PGM_TYPE_PROT;
1939 rc = PGM_SHW_NAME_AMD64(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1940 rc = PGM_GST_NAME_PROT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1941 rc = PGM_BTH_NAME_AMD64_PROT(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1942
1943 pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(PGM_TYPE_AMD64, PGM_TYPE_AMD64)];
1944 pModeData->uShwType = PGM_TYPE_AMD64;
1945 pModeData->uGstType = PGM_TYPE_AMD64;
1946 rc = PGM_SHW_NAME_AMD64(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1947 rc = PGM_GST_NAME_AMD64(InitData)( pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1948 rc = PGM_BTH_NAME_AMD64_AMD64(InitData)(pVM, pModeData, fResolveGCAndR0); AssertRCReturn(rc, rc);
1949
1950 return VINF_SUCCESS;
1951}
1952
1953
1954/**
1955 * Swtich to different (or relocated in the relocate case) mode data.
1956 *
1957 * @param pVM The VM handle.
1958 * @param enmShw The the shadow paging mode.
1959 * @param enmGst The the guest paging mode.
1960 */
1961static void pgmR3ModeDataSwitch(PVM pVM, PGMMODE enmShw, PGMMODE enmGst)
1962{
1963 PPGMMODEDATA pModeData = &pVM->pgm.s.paModeData[pgmModeDataIndex(enmShw, enmGst)];
1964
1965 Assert(pModeData->uGstType == pgmModeToType(enmGst));
1966 Assert(pModeData->uShwType == pgmModeToType(enmShw));
1967
1968 /* shadow */
1969 pVM->pgm.s.pfnR3ShwRelocate = pModeData->pfnR3ShwRelocate;
1970 pVM->pgm.s.pfnR3ShwExit = pModeData->pfnR3ShwExit;
1971 pVM->pgm.s.pfnR3ShwGetPage = pModeData->pfnR3ShwGetPage;
1972 Assert(pVM->pgm.s.pfnR3ShwGetPage);
1973 pVM->pgm.s.pfnR3ShwModifyPage = pModeData->pfnR3ShwModifyPage;
1974 pVM->pgm.s.pfnR3ShwGetPDEByIndex = pModeData->pfnR3ShwGetPDEByIndex;
1975 pVM->pgm.s.pfnR3ShwSetPDEByIndex = pModeData->pfnR3ShwSetPDEByIndex;
1976 pVM->pgm.s.pfnR3ShwModifyPDEByIndex = pModeData->pfnR3ShwModifyPDEByIndex;
1977
1978 pVM->pgm.s.pfnGCShwGetPage = pModeData->pfnGCShwGetPage;
1979 pVM->pgm.s.pfnGCShwModifyPage = pModeData->pfnGCShwModifyPage;
1980 pVM->pgm.s.pfnGCShwGetPDEByIndex = pModeData->pfnGCShwGetPDEByIndex;
1981 pVM->pgm.s.pfnGCShwSetPDEByIndex = pModeData->pfnGCShwSetPDEByIndex;
1982 pVM->pgm.s.pfnGCShwModifyPDEByIndex = pModeData->pfnGCShwModifyPDEByIndex;
1983
1984 pVM->pgm.s.pfnR0ShwGetPage = pModeData->pfnR0ShwGetPage;
1985 pVM->pgm.s.pfnR0ShwModifyPage = pModeData->pfnR0ShwModifyPage;
1986 pVM->pgm.s.pfnR0ShwGetPDEByIndex = pModeData->pfnR0ShwGetPDEByIndex;
1987 pVM->pgm.s.pfnR0ShwSetPDEByIndex = pModeData->pfnR0ShwSetPDEByIndex;
1988 pVM->pgm.s.pfnR0ShwModifyPDEByIndex = pModeData->pfnR0ShwModifyPDEByIndex;
1989
1990
1991 /* guest */
1992 pVM->pgm.s.pfnR3GstRelocate = pModeData->pfnR3GstRelocate;
1993 pVM->pgm.s.pfnR3GstExit = pModeData->pfnR3GstExit;
1994 pVM->pgm.s.pfnR3GstGetPage = pModeData->pfnR3GstGetPage;
1995 Assert(pVM->pgm.s.pfnR3GstGetPage);
1996 pVM->pgm.s.pfnR3GstModifyPage = pModeData->pfnR3GstModifyPage;
1997 pVM->pgm.s.pfnR3GstGetPDE = pModeData->pfnR3GstGetPDE;
1998 pVM->pgm.s.pfnR3GstMonitorCR3 = pModeData->pfnR3GstMonitorCR3;
1999 pVM->pgm.s.pfnR3GstUnmonitorCR3 = pModeData->pfnR3GstUnmonitorCR3;
2000 pVM->pgm.s.pfnR3GstMapCR3 = pModeData->pfnR3GstMapCR3;
2001 pVM->pgm.s.pfnR3GstUnmapCR3 = pModeData->pfnR3GstUnmapCR3;
2002 pVM->pgm.s.pfnHCGstWriteHandlerCR3 = pModeData->pfnHCGstWriteHandlerCR3;
2003 pVM->pgm.s.pszHCGstWriteHandlerCR3 = pModeData->pszHCGstWriteHandlerCR3;
2004
2005 pVM->pgm.s.pfnGCGstGetPage = pModeData->pfnGCGstGetPage;
2006 pVM->pgm.s.pfnGCGstModifyPage = pModeData->pfnGCGstModifyPage;
2007 pVM->pgm.s.pfnGCGstGetPDE = pModeData->pfnGCGstGetPDE;
2008 pVM->pgm.s.pfnGCGstMonitorCR3 = pModeData->pfnGCGstMonitorCR3;
2009 pVM->pgm.s.pfnGCGstUnmonitorCR3 = pModeData->pfnGCGstUnmonitorCR3;
2010 pVM->pgm.s.pfnGCGstMapCR3 = pModeData->pfnGCGstMapCR3;
2011 pVM->pgm.s.pfnGCGstUnmapCR3 = pModeData->pfnGCGstUnmapCR3;
2012 pVM->pgm.s.pfnGCGstWriteHandlerCR3 = pModeData->pfnGCGstWriteHandlerCR3;
2013
2014 pVM->pgm.s.pfnR0GstGetPage = pModeData->pfnR0GstGetPage;
2015 pVM->pgm.s.pfnR0GstModifyPage = pModeData->pfnR0GstModifyPage;
2016 pVM->pgm.s.pfnR0GstGetPDE = pModeData->pfnR0GstGetPDE;
2017 pVM->pgm.s.pfnR0GstMonitorCR3 = pModeData->pfnR0GstMonitorCR3;
2018 pVM->pgm.s.pfnR0GstUnmonitorCR3 = pModeData->pfnR0GstUnmonitorCR3;
2019 pVM->pgm.s.pfnR0GstMapCR3 = pModeData->pfnR0GstMapCR3;
2020 pVM->pgm.s.pfnR0GstUnmapCR3 = pModeData->pfnR0GstUnmapCR3;
2021 pVM->pgm.s.pfnR0GstWriteHandlerCR3 = pModeData->pfnR0GstWriteHandlerCR3;
2022
2023
2024 /* both */
2025 pVM->pgm.s.pfnR3BthRelocate = pModeData->pfnR3BthRelocate;
2026 pVM->pgm.s.pfnR3BthTrap0eHandler = pModeData->pfnR3BthTrap0eHandler;
2027 pVM->pgm.s.pfnR3BthInvalidatePage = pModeData->pfnR3BthInvalidatePage;
2028 pVM->pgm.s.pfnR3BthSyncCR3 = pModeData->pfnR3BthSyncCR3;
2029 Assert(pVM->pgm.s.pfnR3BthSyncCR3);
2030 pVM->pgm.s.pfnR3BthSyncPage = pModeData->pfnR3BthSyncPage;
2031 pVM->pgm.s.pfnR3BthPrefetchPage = pModeData->pfnR3BthPrefetchPage;
2032 pVM->pgm.s.pfnR3BthVerifyAccessSyncPage = pModeData->pfnR3BthVerifyAccessSyncPage;
2033#ifdef VBOX_STRICT
2034 pVM->pgm.s.pfnR3BthAssertCR3 = pModeData->pfnR3BthAssertCR3;
2035#endif
2036
2037 pVM->pgm.s.pfnGCBthTrap0eHandler = pModeData->pfnGCBthTrap0eHandler;
2038 pVM->pgm.s.pfnGCBthInvalidatePage = pModeData->pfnGCBthInvalidatePage;
2039 pVM->pgm.s.pfnGCBthSyncCR3 = pModeData->pfnGCBthSyncCR3;
2040 pVM->pgm.s.pfnGCBthSyncPage = pModeData->pfnGCBthSyncPage;
2041 pVM->pgm.s.pfnGCBthPrefetchPage = pModeData->pfnGCBthPrefetchPage;
2042 pVM->pgm.s.pfnGCBthVerifyAccessSyncPage = pModeData->pfnGCBthVerifyAccessSyncPage;
2043#ifdef VBOX_STRICT
2044 pVM->pgm.s.pfnGCBthAssertCR3 = pModeData->pfnGCBthAssertCR3;
2045#endif
2046
2047 pVM->pgm.s.pfnR0BthTrap0eHandler = pModeData->pfnR0BthTrap0eHandler;
2048 pVM->pgm.s.pfnR0BthInvalidatePage = pModeData->pfnR0BthInvalidatePage;
2049 pVM->pgm.s.pfnR0BthSyncCR3 = pModeData->pfnR0BthSyncCR3;
2050 pVM->pgm.s.pfnR0BthSyncPage = pModeData->pfnR0BthSyncPage;
2051 pVM->pgm.s.pfnR0BthPrefetchPage = pModeData->pfnR0BthPrefetchPage;
2052 pVM->pgm.s.pfnR0BthVerifyAccessSyncPage = pModeData->pfnR0BthVerifyAccessSyncPage;
2053#ifdef VBOX_STRICT
2054 pVM->pgm.s.pfnR0BthAssertCR3 = pModeData->pfnR0BthAssertCR3;
2055#endif
2056}
2057
2058
2059#ifdef DEBUG_bird
2060#include <stdlib.h> /* getenv() remove me! */
2061#endif
2062
2063/**
2064 * Calculates the shadow paging mode.
2065 *
2066 * @returns The shadow paging mode.
2067 * @param enmGuestMode The guest mode.
2068 * @param enmHostMode The host mode.
2069 * @param enmShadowMode The current shadow mode.
2070 * @param penmSwitcher Where to store the switcher to use.
2071 * VMMSWITCHER_INVALID means no change.
2072 */
2073static PGMMODE pgmR3CalcShadowMode(PGMMODE enmGuestMode, SUPPAGINGMODE enmHostMode, PGMMODE enmShadowMode, VMMSWITCHER *penmSwitcher)
2074{
2075 VMMSWITCHER enmSwitcher = VMMSWITCHER_INVALID;
2076 switch (enmGuestMode)
2077 {
2078 /*
2079 * When switching to real or protected mode we don't change
2080 * anything since it's likely that we'll switch back pretty soon.
2081 *
2082 * During pgmR3InitPaging we'll end up here with PGMMODE_INVALID
2083 * and is supposed to determin which shadow paging and switcher to
2084 * use during init.
2085 */
2086 case PGMMODE_REAL:
2087 case PGMMODE_PROTECTED:
2088 if (enmShadowMode != PGMMODE_INVALID)
2089 break; /* (no change) */
2090 switch (enmHostMode)
2091 {
2092 case SUPPAGINGMODE_32_BIT:
2093 case SUPPAGINGMODE_32_BIT_GLOBAL:
2094 enmShadowMode = PGMMODE_32_BIT;
2095 enmSwitcher = VMMSWITCHER_32_TO_32;
2096 break;
2097
2098 case SUPPAGINGMODE_PAE:
2099 case SUPPAGINGMODE_PAE_NX:
2100 case SUPPAGINGMODE_PAE_GLOBAL:
2101 case SUPPAGINGMODE_PAE_GLOBAL_NX:
2102 enmShadowMode = PGMMODE_PAE;
2103 enmSwitcher = VMMSWITCHER_PAE_TO_PAE;
2104#ifdef DEBUG_bird
2105if (getenv("VBOX_32BIT"))
2106{
2107 enmShadowMode = PGMMODE_32_BIT;
2108 enmSwitcher = VMMSWITCHER_PAE_TO_32;
2109}
2110#endif
2111 break;
2112
2113 case SUPPAGINGMODE_AMD64:
2114 case SUPPAGINGMODE_AMD64_GLOBAL:
2115 case SUPPAGINGMODE_AMD64_NX:
2116 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
2117 enmShadowMode = PGMMODE_PAE;
2118 enmSwitcher = VMMSWITCHER_AMD64_TO_PAE;
2119 break;
2120
2121 default: AssertMsgFailed(("enmHostMode=%d\n", enmHostMode)); break;
2122 }
2123 break;
2124
2125 case PGMMODE_32_BIT:
2126 switch (enmHostMode)
2127 {
2128 case SUPPAGINGMODE_32_BIT:
2129 case SUPPAGINGMODE_32_BIT_GLOBAL:
2130 enmShadowMode = PGMMODE_32_BIT;
2131 enmSwitcher = VMMSWITCHER_32_TO_32;
2132 break;
2133
2134 case SUPPAGINGMODE_PAE:
2135 case SUPPAGINGMODE_PAE_NX:
2136 case SUPPAGINGMODE_PAE_GLOBAL:
2137 case SUPPAGINGMODE_PAE_GLOBAL_NX:
2138 enmShadowMode = PGMMODE_PAE;
2139 enmSwitcher = VMMSWITCHER_PAE_TO_PAE;
2140#ifdef DEBUG_bird
2141if (getenv("VBOX_32BIT"))
2142{
2143 enmShadowMode = PGMMODE_32_BIT;
2144 enmSwitcher = VMMSWITCHER_PAE_TO_32;
2145}
2146#endif
2147 break;
2148
2149 case SUPPAGINGMODE_AMD64:
2150 case SUPPAGINGMODE_AMD64_GLOBAL:
2151 case SUPPAGINGMODE_AMD64_NX:
2152 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
2153 enmShadowMode = PGMMODE_PAE;
2154 enmSwitcher = VMMSWITCHER_AMD64_TO_PAE;
2155 break;
2156
2157 default: AssertMsgFailed(("enmHostMode=%d\n", enmHostMode)); break;
2158 }
2159 break;
2160
2161 case PGMMODE_PAE:
2162 case PGMMODE_PAE_NX: /** @todo This might require more switchers and guest+both modes. */
2163 switch (enmHostMode)
2164 {
2165 case SUPPAGINGMODE_32_BIT:
2166 case SUPPAGINGMODE_32_BIT_GLOBAL:
2167 enmShadowMode = PGMMODE_PAE;
2168 enmSwitcher = VMMSWITCHER_32_TO_PAE;
2169 break;
2170
2171 case SUPPAGINGMODE_PAE:
2172 case SUPPAGINGMODE_PAE_NX:
2173 case SUPPAGINGMODE_PAE_GLOBAL:
2174 case SUPPAGINGMODE_PAE_GLOBAL_NX:
2175 enmShadowMode = PGMMODE_PAE;
2176 enmSwitcher = VMMSWITCHER_PAE_TO_PAE;
2177 break;
2178
2179 case SUPPAGINGMODE_AMD64:
2180 case SUPPAGINGMODE_AMD64_GLOBAL:
2181 case SUPPAGINGMODE_AMD64_NX:
2182 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
2183 enmShadowMode = PGMMODE_PAE;
2184 enmSwitcher = VMMSWITCHER_AMD64_TO_PAE;
2185 break;
2186
2187 default: AssertMsgFailed(("enmHostMode=%d\n", enmHostMode)); break;
2188 }
2189 break;
2190
2191 case PGMMODE_AMD64:
2192 case PGMMODE_AMD64_NX:
2193 switch (enmHostMode)
2194 {
2195 case SUPPAGINGMODE_32_BIT:
2196 case SUPPAGINGMODE_32_BIT_GLOBAL:
2197 enmShadowMode = PGMMODE_PAE;
2198 enmSwitcher = VMMSWITCHER_32_TO_AMD64;
2199 break;
2200
2201 case SUPPAGINGMODE_PAE:
2202 case SUPPAGINGMODE_PAE_NX:
2203 case SUPPAGINGMODE_PAE_GLOBAL:
2204 case SUPPAGINGMODE_PAE_GLOBAL_NX:
2205 enmShadowMode = PGMMODE_PAE;
2206 enmSwitcher = VMMSWITCHER_PAE_TO_AMD64;
2207 break;
2208
2209 case SUPPAGINGMODE_AMD64:
2210 case SUPPAGINGMODE_AMD64_GLOBAL:
2211 case SUPPAGINGMODE_AMD64_NX:
2212 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
2213 enmShadowMode = PGMMODE_PAE;
2214 enmSwitcher = VMMSWITCHER_AMD64_TO_AMD64;
2215 break;
2216
2217 default: AssertMsgFailed(("enmHostMode=%d\n", enmHostMode)); break;
2218 }
2219 break;
2220
2221
2222 default:
2223 AssertReleaseMsgFailed(("enmGuestMode=%d\n", enmGuestMode));
2224 return PGMMODE_INVALID;
2225 }
2226
2227 *penmSwitcher = enmSwitcher;
2228 return enmShadowMode;
2229}
2230
2231
2232/**
2233 * Performs the actual mode change.
2234 * This is called by PGMChangeMode and pgmR3InitPaging().
2235 *
2236 * @returns VBox status code.
2237 * @param pVM VM handle.
2238 * @param enmGuestMode The new guest mode. This is assumed to be different from
2239 * the current mode.
2240 */
2241int pgmR3ChangeMode(PVM pVM, PGMMODE enmGuestMode)
2242{
2243 LogFlow(("pgmR3ChangeMode: Guest mode: %d -> %d\n", pVM->pgm.s.enmGuestMode, enmGuestMode));
2244 STAM_REL_COUNTER_INC(&pVM->pgm.s.cGuestModeChanges);
2245
2246 /*
2247 * Calc the shadow mode and switcher.
2248 */
2249 VMMSWITCHER enmSwitcher;
2250 PGMMODE enmShadowMode = pgmR3CalcShadowMode(enmGuestMode, pVM->pgm.s.enmHostMode, pVM->pgm.s.enmShadowMode, &enmSwitcher);
2251 if (enmSwitcher != VMMSWITCHER_INVALID)
2252 {
2253 /*
2254 * Select new switcher.
2255 */
2256 int rc = VMMR3SelectSwitcher(pVM, enmSwitcher);
2257 if (VBOX_FAILURE(rc))
2258 {
2259 AssertReleaseMsgFailed(("VMMR3SelectSwitcher(%d) -> %Vrc\n", enmSwitcher, rc));
2260 return rc;
2261 }
2262 }
2263
2264 /*
2265 * Exit old mode(s).
2266 */
2267 /* shadow */
2268 if (enmShadowMode != pVM->pgm.s.enmShadowMode)
2269 {
2270 LogFlow(("pgmR3ChangeMode: Shadow mode: %d -> %d\n", pVM->pgm.s.enmShadowMode, enmShadowMode));
2271 if (PGM_SHW_PFN(Exit, pVM))
2272 {
2273 int rc = PGM_SHW_PFN(Exit, pVM)(pVM);
2274 if (VBOX_FAILURE(rc))
2275 {
2276 AssertMsgFailed(("Exit failed for shadow mode %d: %Vrc\n", pVM->pgm.s.enmShadowMode, rc));
2277 return rc;
2278 }
2279 }
2280
2281 }
2282
2283 /* guest */
2284 if (PGM_GST_PFN(Exit, pVM))
2285 {
2286 int rc = PGM_GST_PFN(Exit, pVM)(pVM);
2287 if (VBOX_FAILURE(rc))
2288 {
2289 AssertMsgFailed(("Exit failed for guest mode %d: %Vrc\n", pVM->pgm.s.enmGuestMode, rc));
2290 return rc;
2291 }
2292 }
2293
2294 /*
2295 * Load new paging mode data.
2296 */
2297 pgmR3ModeDataSwitch(pVM, enmShadowMode, enmGuestMode);
2298
2299 /*
2300 * Enter new shadow mode (if changed).
2301 */
2302 if (enmShadowMode != pVM->pgm.s.enmShadowMode)
2303 {
2304 int rc;
2305 pVM->pgm.s.enmShadowMode = enmShadowMode;
2306 switch (enmShadowMode)
2307 {
2308 case PGMMODE_32_BIT:
2309 rc = PGM_SHW_NAME_32BIT(Enter)(pVM);
2310 break;
2311 case PGMMODE_PAE:
2312 case PGMMODE_PAE_NX:
2313 rc = PGM_SHW_NAME_PAE(Enter)(pVM);
2314 break;
2315 case PGMMODE_AMD64:
2316 case PGMMODE_AMD64_NX:
2317 rc = PGM_SHW_NAME_AMD64(Enter)(pVM);
2318 break;
2319 case PGMMODE_REAL:
2320 case PGMMODE_PROTECTED:
2321 default:
2322 AssertReleaseMsgFailed(("enmShadowMode=%d\n", enmShadowMode));
2323 return VERR_INTERNAL_ERROR;
2324 }
2325 if (VBOX_FAILURE(rc))
2326 {
2327 AssertReleaseMsgFailed(("Entering enmShadowMode=%d failed: %Vrc\n", enmShadowMode, rc));
2328 pVM->pgm.s.enmShadowMode = PGMMODE_INVALID;
2329 return rc;
2330 }
2331 }
2332
2333 /*
2334 * Enter the new guest and shadow+guest modes.
2335 */
2336 int rc = -1;
2337 int rc2 = -1;
2338 RTGCPHYS GCPhysCR3 = NIL_RTGCPHYS;
2339 pVM->pgm.s.enmGuestMode = enmGuestMode;
2340 switch (enmGuestMode)
2341 {
2342 case PGMMODE_REAL:
2343 rc = PGM_GST_NAME_REAL(Enter)(pVM, NIL_RTGCPHYS);
2344 switch (pVM->pgm.s.enmShadowMode)
2345 {
2346 case PGMMODE_32_BIT:
2347 rc2 = PGM_BTH_NAME_32BIT_REAL(Enter)(pVM, NIL_RTGCPHYS);
2348 break;
2349 case PGMMODE_PAE:
2350 case PGMMODE_PAE_NX:
2351 rc2 = PGM_BTH_NAME_PAE_REAL(Enter)(pVM, NIL_RTGCPHYS);
2352 break;
2353 case PGMMODE_AMD64:
2354 case PGMMODE_AMD64_NX:
2355 rc2 = PGM_BTH_NAME_AMD64_REAL(Enter)(pVM, NIL_RTGCPHYS);
2356 break;
2357 default: AssertFailed(); break;
2358 }
2359 break;
2360
2361 case PGMMODE_PROTECTED:
2362 rc = PGM_GST_NAME_PROT(Enter)(pVM, NIL_RTGCPHYS);
2363 switch (pVM->pgm.s.enmShadowMode)
2364 {
2365 case PGMMODE_32_BIT:
2366 rc2 = PGM_BTH_NAME_32BIT_PROT(Enter)(pVM, NIL_RTGCPHYS);
2367 break;
2368 case PGMMODE_PAE:
2369 case PGMMODE_PAE_NX:
2370 rc2 = PGM_BTH_NAME_PAE_PROT(Enter)(pVM, NIL_RTGCPHYS);
2371 break;
2372 case PGMMODE_AMD64:
2373 case PGMMODE_AMD64_NX:
2374 rc2 = PGM_BTH_NAME_AMD64_PROT(Enter)(pVM, NIL_RTGCPHYS);
2375 break;
2376 default: AssertFailed(); break;
2377 }
2378 break;
2379
2380 case PGMMODE_32_BIT:
2381 GCPhysCR3 = CPUMGetGuestCR3(pVM) & X86_CR3_PAGE_MASK;
2382 rc = PGM_GST_NAME_32BIT(Enter)(pVM, GCPhysCR3);
2383 switch (pVM->pgm.s.enmShadowMode)
2384 {
2385 case PGMMODE_32_BIT:
2386 rc2 = PGM_BTH_NAME_32BIT_32BIT(Enter)(pVM, GCPhysCR3);
2387 break;
2388 case PGMMODE_PAE:
2389 case PGMMODE_PAE_NX:
2390 rc2 = PGM_BTH_NAME_PAE_32BIT(Enter)(pVM, GCPhysCR3);
2391 break;
2392 case PGMMODE_AMD64:
2393 case PGMMODE_AMD64_NX:
2394 AssertMsgFailed(("Should use PAE shadow mode!\n"));
2395 default: AssertFailed(); break;
2396 }
2397 break;
2398
2399 //case PGMMODE_PAE_NX:
2400 case PGMMODE_PAE:
2401 GCPhysCR3 = CPUMGetGuestCR3(pVM) & X86_CR3_PAE_PAGE_MASK;
2402 rc = PGM_GST_NAME_PAE(Enter)(pVM, GCPhysCR3);
2403 switch (pVM->pgm.s.enmShadowMode)
2404 {
2405 case PGMMODE_PAE:
2406 case PGMMODE_PAE_NX:
2407 rc2 = PGM_BTH_NAME_PAE_PAE(Enter)(pVM, GCPhysCR3);
2408 break;
2409 case PGMMODE_32_BIT:
2410 case PGMMODE_AMD64:
2411 case PGMMODE_AMD64_NX:
2412 AssertMsgFailed(("Should use PAE shadow mode!\n"));
2413 default: AssertFailed(); break;
2414 }
2415 break;
2416
2417 //case PGMMODE_AMD64_NX:
2418 case PGMMODE_AMD64:
2419 GCPhysCR3 = CPUMGetGuestCR3(pVM) & 0xfffffffffffff000ULL; /** @todo define this mask and make CR3 64-bit in this case! */
2420 rc = PGM_GST_NAME_AMD64(Enter)(pVM, GCPhysCR3);
2421 switch (pVM->pgm.s.enmShadowMode)
2422 {
2423 case PGMMODE_AMD64:
2424 case PGMMODE_AMD64_NX:
2425 rc2 = PGM_BTH_NAME_AMD64_AMD64(Enter)(pVM, GCPhysCR3);
2426 break;
2427 case PGMMODE_32_BIT:
2428 case PGMMODE_PAE:
2429 case PGMMODE_PAE_NX:
2430 AssertMsgFailed(("Should use AMD64 shadow mode!\n"));
2431 default: AssertFailed(); break;
2432 }
2433 break;
2434
2435 default:
2436 AssertReleaseMsgFailed(("enmGuestMode=%d\n", enmGuestMode));
2437 rc = VERR_NOT_IMPLEMENTED;
2438 break;
2439 }
2440
2441 /* status codes. */
2442 AssertRC(rc);
2443 AssertRC(rc2);
2444 if (VBOX_SUCCESS(rc))
2445 {
2446 rc = rc2;
2447 if (VBOX_SUCCESS(rc)) /* no informational status codes. */
2448 rc = VINF_SUCCESS;
2449 }
2450
2451 /*
2452 * Notify SELM so it can update the TSSes with correct CR3s.
2453 */
2454 SELMR3PagingModeChanged(pVM);
2455
2456 /* Notify HWACCM as well. */
2457 HWACCMR3PagingModeChanged(pVM, pVM->pgm.s.enmShadowMode);
2458 return rc;
2459}
2460
2461
2462/**
2463 * Dumps a PAE shadow page table.
2464 *
2465 * @returns VBox status code (VINF_SUCCESS).
2466 * @param pVM The VM handle.
2467 * @param pPT Pointer to the page table.
2468 * @param u64Address The virtual address of the page table starts.
2469 * @param fLongMode Set if this a long mode table; clear if it's a legacy mode table.
2470 * @param cMaxDepth The maxium depth.
2471 * @param pHlp Pointer to the output functions.
2472 */
2473static int pgmR3DumpHierarchyHCPaePT(PVM pVM, PX86PTPAE pPT, uint64_t u64Address, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
2474{
2475 for (unsigned i = 0; i < ELEMENTS(pPT->a); i++)
2476 {
2477 X86PTEPAE Pte = pPT->a[i];
2478 if (Pte.n.u1Present)
2479 {
2480 pHlp->pfnPrintf(pHlp,
2481 fLongMode /*P R S A D G WT CD AT NX 4M a p ? */
2482 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx\n"
2483 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx\n",
2484 u64Address + ((uint64_t)i << X86_PT_PAE_SHIFT),
2485 Pte.n.u1Write ? 'W' : 'R',
2486 Pte.n.u1User ? 'U' : 'S',
2487 Pte.n.u1Accessed ? 'A' : '-',
2488 Pte.n.u1Dirty ? 'D' : '-',
2489 Pte.n.u1Global ? 'G' : '-',
2490 Pte.n.u1WriteThru ? "WT" : "--",
2491 Pte.n.u1CacheDisable? "CD" : "--",
2492 Pte.n.u1PAT ? "AT" : "--",
2493 Pte.n.u1NoExecute ? "NX" : "--",
2494 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
2495 Pte.u & BIT(10) ? '1' : '0',
2496 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED? 'v' : '-',
2497 Pte.u & X86_PTE_PAE_PG_MASK);
2498 }
2499 }
2500 return VINF_SUCCESS;
2501}
2502
2503
2504/**
2505 * Dumps a PAE shadow page directory table.
2506 *
2507 * @returns VBox status code (VINF_SUCCESS).
2508 * @param pVM The VM handle.
2509 * @param HCPhys The physical address of the page directory table.
2510 * @param u64Address The virtual address of the page table starts.
2511 * @param cr4 The CR4, PSE is currently used.
2512 * @param fLongMode Set if this a long mode table; clear if it's a legacy mode table.
2513 * @param cMaxDepth The maxium depth.
2514 * @param pHlp Pointer to the output functions.
2515 */
2516static int pgmR3DumpHierarchyHCPaePD(PVM pVM, RTHCPHYS HCPhys, uint64_t u64Address, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
2517{
2518 PX86PDPAE pPD = (PX86PDPAE)MMPagePhys2Page(pVM, HCPhys);
2519 if (!pPD)
2520 {
2521 pHlp->pfnPrintf(pHlp, "%0*llx error! Page directory at HCPhys=%#VHp was not found in the page pool!\n",
2522 fLongMode ? 16 : 8, u64Address, HCPhys);
2523 return VERR_INVALID_PARAMETER;
2524 }
2525 int rc = VINF_SUCCESS;
2526 for (unsigned i = 0; i < ELEMENTS(pPD->a); i++)
2527 {
2528 X86PDEPAE Pde = pPD->a[i];
2529 if (Pde.n.u1Present)
2530 {
2531 if ((cr4 & X86_CR4_PSE) && Pde.b.u1Size)
2532 pHlp->pfnPrintf(pHlp,
2533 fLongMode /*P R S A D G WT CD AT NX 4M a p ? */
2534 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 4M %c%c%c %016llx\n"
2535 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 4M %c%c%c %016llx\n",
2536 u64Address + ((uint64_t)i << X86_PD_PAE_SHIFT),
2537 Pde.b.u1Write ? 'W' : 'R',
2538 Pde.b.u1User ? 'U' : 'S',
2539 Pde.b.u1Accessed ? 'A' : '-',
2540 Pde.b.u1Dirty ? 'D' : '-',
2541 Pde.b.u1Global ? 'G' : '-',
2542 Pde.b.u1WriteThru ? "WT" : "--",
2543 Pde.b.u1CacheDisable? "CD" : "--",
2544 Pde.b.u1PAT ? "AT" : "--",
2545 Pde.b.u1NoExecute ? "NX" : "--",
2546 Pde.u & BIT64(9) ? '1' : '0',
2547 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
2548 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
2549 Pde.u & X86_PDE_PAE_PG_MASK);
2550 else
2551 {
2552 pHlp->pfnPrintf(pHlp,
2553 fLongMode /*P R S A D G WT CD AT NX 4M a p ? */
2554 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s 4K %c%c%c %016llx\n"
2555 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s 4K %c%c%c %016llx\n",
2556 u64Address + ((uint64_t)i << X86_PD_PAE_SHIFT),
2557 Pde.n.u1Write ? 'W' : 'R',
2558 Pde.n.u1User ? 'U' : 'S',
2559 Pde.n.u1Accessed ? 'A' : '-',
2560 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2561 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2562 Pde.n.u1WriteThru ? "WT" : "--",
2563 Pde.n.u1CacheDisable? "CD" : "--",
2564 Pde.n.u1NoExecute ? "NX" : "--",
2565 Pde.u & BIT64(9) ? '1' : '0',
2566 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
2567 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
2568 Pde.u & X86_PDE_PAE_PG_MASK);
2569 if (cMaxDepth >= 1)
2570 {
2571 /** @todo what about using the page pool for mapping PTs? */
2572 uint64_t u64AddressPT = u64Address + ((uint64_t)i << X86_PD_PAE_SHIFT);
2573 RTHCPHYS HCPhysPT = Pde.u & X86_PDE_PAE_PG_MASK;
2574 PX86PTPAE pPT = NULL;
2575 if (!(Pde.u & PGM_PDFLAGS_MAPPING))
2576 pPT = (PX86PTPAE)MMPagePhys2Page(pVM, HCPhysPT);
2577 else
2578 {
2579 for (PPGMMAPPING pMap = pVM->pgm.s.pMappingsHC; pMap; pMap = pMap->pNextHC)
2580 {
2581 uint64_t off = u64AddressPT - pMap->GCPtr;
2582 if (off < pMap->cb)
2583 {
2584 const int iPDE = (uint32_t)(off >> X86_PD_SHIFT);
2585 const int iSub = (int)((off >> X86_PD_PAE_SHIFT) & 1); /* MSC is a pain sometimes */
2586 if ((iSub ? pMap->aPTs[iPDE].HCPhysPaePT1 : pMap->aPTs[iPDE].HCPhysPaePT0) != HCPhysPT)
2587 pHlp->pfnPrintf(pHlp, "%0*llx error! Mapping error! PT %d has HCPhysPT=%VHp not %VHp is in the PD.\n",
2588 fLongMode ? 16 : 8, u64AddressPT, iPDE,
2589 iSub ? pMap->aPTs[iPDE].HCPhysPaePT1 : pMap->aPTs[iPDE].HCPhysPaePT0, HCPhysPT);
2590 pPT = &pMap->aPTs[iPDE].paPaePTsHC[iSub];
2591 }
2592 }
2593 }
2594 int rc2 = VERR_INVALID_PARAMETER;
2595 if (pPT)
2596 rc2 = pgmR3DumpHierarchyHCPaePT(pVM, pPT, u64AddressPT, fLongMode, cMaxDepth - 1, pHlp);
2597 else
2598 pHlp->pfnPrintf(pHlp, "%0*llx error! Page table at HCPhys=%#VHp was not found in the page pool!\n",
2599 fLongMode ? 16 : 8, u64AddressPT, HCPhysPT);
2600 if (rc2 < rc && VBOX_SUCCESS(rc))
2601 rc = rc2;
2602 }
2603 }
2604 }
2605 }
2606 return rc;
2607}
2608
2609
2610/**
2611 * Dumps a PAE shadow page directory pointer table.
2612 *
2613 * @returns VBox status code (VINF_SUCCESS).
2614 * @param pVM The VM handle.
2615 * @param HCPhys The physical address of the page directory pointer table.
2616 * @param u64Address The virtual address of the page table starts.
2617 * @param cr4 The CR4, PSE is currently used.
2618 * @param fLongMode Set if this a long mode table; clear if it's a legacy mode table.
2619 * @param cMaxDepth The maxium depth.
2620 * @param pHlp Pointer to the output functions.
2621 */
2622static int pgmR3DumpHierarchyHCPaePDPTR(PVM pVM, RTHCPHYS HCPhys, uint64_t u64Address, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
2623{
2624 PX86PDPTR pPDPTR = (PX86PDPTR)MMPagePhys2Page(pVM, HCPhys);
2625 if (!pPDPTR)
2626 {
2627 pHlp->pfnPrintf(pHlp, "%0*llx error! Page directory pointer table at HCPhys=%#VHp was not found in the page pool!\n",
2628 fLongMode ? 16 : 8, u64Address, HCPhys);
2629 return VERR_INVALID_PARAMETER;
2630 }
2631
2632 int rc = VINF_SUCCESS;
2633 const unsigned c = fLongMode ? ELEMENTS(pPDPTR->a) : 4;
2634 for (unsigned i = 0; i < c; i++)
2635 {
2636 X86PDPE Pdpe = pPDPTR->a[i];
2637 if (Pdpe.n.u1Present)
2638 {
2639 if (fLongMode)
2640 pHlp->pfnPrintf(pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
2641 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx\n",
2642 u64Address + ((uint64_t)i << X86_PDPTR_SHIFT),
2643 Pdpe.n.u1Write ? 'W' : 'R',
2644 Pdpe.n.u1User ? 'U' : 'S',
2645 Pdpe.n.u1Accessed ? 'A' : '-',
2646 Pdpe.n.u3Reserved & 1? '?' : '.', /* ignored */
2647 Pdpe.n.u3Reserved & 4? '!' : '.', /* mbz */
2648 Pdpe.n.u1WriteThru ? "WT" : "--",
2649 Pdpe.n.u1CacheDisable? "CD" : "--",
2650 Pdpe.n.u3Reserved & 2? "!" : "..",/* mbz */
2651 Pdpe.n.u1NoExecute ? "NX" : "--",
2652 Pdpe.u & BIT(9) ? '1' : '0',
2653 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
2654 Pdpe.u & BIT(11) ? '1' : '0',
2655 Pdpe.u & X86_PDPE_PG_MASK);
2656 else
2657 pHlp->pfnPrintf(pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
2658 "%08x 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx\n",
2659 i << X86_PDPTR_SHIFT,
2660 Pdpe.n.u1Write ? '!' : '.', /* mbz */
2661 Pdpe.n.u1User ? '!' : '.', /* mbz */
2662 Pdpe.n.u1Accessed ? '!' : '.', /* mbz */
2663 Pdpe.n.u3Reserved & 1? '!' : '.', /* mbz */
2664 Pdpe.n.u3Reserved & 4? '!' : '.', /* mbz */
2665 Pdpe.n.u1WriteThru ? "WT" : "--",
2666 Pdpe.n.u1CacheDisable? "CD" : "--",
2667 Pdpe.n.u3Reserved & 2? "!" : "..",/* mbz */
2668 Pdpe.n.u1NoExecute ? "NX" : "--",
2669 Pdpe.u & BIT(9) ? '1' : '0',
2670 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
2671 Pdpe.u & BIT(11) ? '1' : '0',
2672 Pdpe.u & X86_PDPE_PG_MASK);
2673 if (cMaxDepth >= 1)
2674 {
2675 int rc2 = pgmR3DumpHierarchyHCPaePD(pVM, Pdpe.u & X86_PDPE_PG_MASK, u64Address + ((uint64_t)i << X86_PDPTR_SHIFT),
2676 cr4, fLongMode, cMaxDepth - 1, pHlp);
2677 if (rc2 < rc && VBOX_SUCCESS(rc))
2678 rc = rc2;
2679 }
2680 }
2681 }
2682 return rc;
2683}
2684
2685
2686/**
2687 * Dumps a 32-bit shadow page table.
2688 *
2689 * @returns VBox status code (VINF_SUCCESS).
2690 * @param pVM The VM handle.
2691 * @param HCPhys The physical address of the table.
2692 * @param cr4 The CR4, PSE is currently used.
2693 * @param cMaxDepth The maxium depth.
2694 * @param pHlp Pointer to the output functions.
2695 */
2696static int pgmR3DumpHierarchyHcPaePML4(PVM pVM, RTHCPHYS HCPhys, uint32_t cr4, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
2697{
2698 PX86PML4 pPML4 = (PX86PML4)MMPagePhys2Page(pVM, HCPhys);
2699 if (!pPML4)
2700 {
2701 pHlp->pfnPrintf(pHlp, "Page map level 4 at HCPhys=%#VHp was not found in the page pool!\n", HCPhys);
2702 return VERR_INVALID_PARAMETER;
2703 }
2704
2705 int rc = VINF_SUCCESS;
2706 for (unsigned i = 0; i < ELEMENTS(pPML4->a); i++)
2707 {
2708 X86PML4E Pml4e = pPML4->a[i];
2709 if (Pml4e.n.u1Present)
2710 {
2711 uint64_t u64Address = ((uint64_t)i << X86_PML4_SHIFT) | (((uint64_t)i >> (X86_PML4_SHIFT - X86_PDPTR_SHIFT - 1)) * 0xffff000000000000ULL);
2712 pHlp->pfnPrintf(pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
2713 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx\n",
2714 u64Address,
2715 Pml4e.n.u1Write ? 'W' : 'R',
2716 Pml4e.n.u1User ? 'U' : 'S',
2717 Pml4e.n.u1Accessed ? 'A' : '-',
2718 Pml4e.n.u3Reserved & 1? '?' : '.', /* ignored */
2719 Pml4e.n.u3Reserved & 4? '!' : '.', /* mbz */
2720 Pml4e.n.u1WriteThru ? "WT" : "--",
2721 Pml4e.n.u1CacheDisable? "CD" : "--",
2722 Pml4e.n.u3Reserved & 2? "!" : "..",/* mbz */
2723 Pml4e.n.u1NoExecute ? "NX" : "--",
2724 Pml4e.u & BIT(9) ? '1' : '0',
2725 Pml4e.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
2726 Pml4e.u & BIT(11) ? '1' : '0',
2727 Pml4e.u & X86_PML4E_PG_MASK);
2728
2729 if (cMaxDepth >= 1)
2730 {
2731 int rc2 = pgmR3DumpHierarchyHCPaePDPTR(pVM, Pml4e.u & X86_PML4E_PG_MASK, u64Address, cr4, true, cMaxDepth - 1, pHlp);
2732 if (rc2 < rc && VBOX_SUCCESS(rc))
2733 rc = rc2;
2734 }
2735 }
2736 }
2737 return rc;
2738}
2739
2740
2741/**
2742 * Dumps a 32-bit shadow page table.
2743 *
2744 * @returns VBox status code (VINF_SUCCESS).
2745 * @param pVM The VM handle.
2746 * @param pPT Pointer to the page table.
2747 * @param u32Address The virtual address this table starts at.
2748 * @param pHlp Pointer to the output functions.
2749 */
2750int pgmR3DumpHierarchyHC32BitPT(PVM pVM, PX86PT pPT, uint32_t u32Address, PCDBGFINFOHLP pHlp)
2751{
2752 for (unsigned i = 0; i < ELEMENTS(pPT->a); i++)
2753 {
2754 X86PTE Pte = pPT->a[i];
2755 if (Pte.n.u1Present)
2756 {
2757 pHlp->pfnPrintf(pHlp, /*P R S A D G WT CD AT NX 4M a m d */
2758 "%08x 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x\n",
2759 u32Address + (i << X86_PT_SHIFT),
2760 Pte.n.u1Write ? 'W' : 'R',
2761 Pte.n.u1User ? 'U' : 'S',
2762 Pte.n.u1Accessed ? 'A' : '-',
2763 Pte.n.u1Dirty ? 'D' : '-',
2764 Pte.n.u1Global ? 'G' : '-',
2765 Pte.n.u1WriteThru ? "WT" : "--",
2766 Pte.n.u1CacheDisable? "CD" : "--",
2767 Pte.n.u1PAT ? "AT" : "--",
2768 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
2769 Pte.u & BIT(10) ? '1' : '0',
2770 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED ? 'v' : '-',
2771 Pte.u & X86_PDE_PG_MASK);
2772 }
2773 }
2774 return VINF_SUCCESS;
2775}
2776
2777
2778/**
2779 * Dumps a 32-bit shadow page directory and page tables.
2780 *
2781 * @returns VBox status code (VINF_SUCCESS).
2782 * @param pVM The VM handle.
2783 * @param cr3 The root of the hierarchy.
2784 * @param cr4 The CR4, PSE is currently used.
2785 * @param cMaxDepth How deep into the hierarchy the dumper should go.
2786 * @param pHlp Pointer to the output functions.
2787 */
2788int pgmR3DumpHierarchyHC32BitPD(PVM pVM, uint32_t cr3, uint32_t cr4, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
2789{
2790 PX86PD pPD = (PX86PD)MMPagePhys2Page(pVM, cr3 & X86_CR3_PAGE_MASK);
2791 if (!pPD)
2792 {
2793 pHlp->pfnPrintf(pHlp, "Page directory at %#x was not found in the page pool!\n", cr3 & X86_CR3_PAGE_MASK);
2794 return VERR_INVALID_PARAMETER;
2795 }
2796
2797 int rc = VINF_SUCCESS;
2798 for (unsigned i = 0; i < ELEMENTS(pPD->a); i++)
2799 {
2800 X86PDE Pde = pPD->a[i];
2801 if (Pde.n.u1Present)
2802 {
2803 const uint32_t u32Address = i << X86_PD_SHIFT;
2804 if ((cr4 & X86_CR4_PSE) && Pde.b.u1Size)
2805 pHlp->pfnPrintf(pHlp, /*P R S A D G WT CD AT NX 4M a m d */
2806 "%08x 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08x\n",
2807 u32Address,
2808 Pde.b.u1Write ? 'W' : 'R',
2809 Pde.b.u1User ? 'U' : 'S',
2810 Pde.b.u1Accessed ? 'A' : '-',
2811 Pde.b.u1Dirty ? 'D' : '-',
2812 Pde.b.u1Global ? 'G' : '-',
2813 Pde.b.u1WriteThru ? "WT" : "--",
2814 Pde.b.u1CacheDisable? "CD" : "--",
2815 Pde.b.u1PAT ? "AT" : "--",
2816 Pde.u & BIT64(9) ? '1' : '0',
2817 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
2818 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
2819 Pde.u & X86_PDE4M_PG_MASK);
2820 else
2821 {
2822 pHlp->pfnPrintf(pHlp, /*P R S A D G WT CD AT NX 4M a m d */
2823 "%08x 0 | P %c %c %c %c %c %s %s .. .. 4K %c%c%c %08x\n",
2824 u32Address,
2825 Pde.n.u1Write ? 'W' : 'R',
2826 Pde.n.u1User ? 'U' : 'S',
2827 Pde.n.u1Accessed ? 'A' : '-',
2828 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2829 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2830 Pde.n.u1WriteThru ? "WT" : "--",
2831 Pde.n.u1CacheDisable? "CD" : "--",
2832 Pde.u & BIT64(9) ? '1' : '0',
2833 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
2834 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
2835 Pde.u & X86_PDE_PG_MASK);
2836 if (cMaxDepth >= 1)
2837 {
2838 /** @todo what about using the page pool for mapping PTs? */
2839 RTHCPHYS HCPhys = Pde.u & X86_PDE_PG_MASK;
2840 PX86PT pPT = NULL;
2841 if (!(Pde.u & PGM_PDFLAGS_MAPPING))
2842 pPT = (PX86PT)MMPagePhys2Page(pVM, HCPhys);
2843 else
2844 {
2845 for (PPGMMAPPING pMap = pVM->pgm.s.pMappingsHC; pMap; pMap = pMap->pNextHC)
2846 if (u32Address - pMap->GCPtr < pMap->cb)
2847 {
2848 int iPDE = (u32Address - pMap->GCPtr) >> X86_PD_SHIFT;
2849 if (pMap->aPTs[iPDE].HCPhysPT != HCPhys)
2850 pHlp->pfnPrintf(pHlp, "%08x error! Mapping error! PT %d has HCPhysPT=%VHp not %VHp is in the PD.\n",
2851 u32Address, iPDE, pMap->aPTs[iPDE].HCPhysPT, HCPhys);
2852 pPT = pMap->aPTs[iPDE].pPTHC;
2853 }
2854 }
2855 int rc2 = VERR_INVALID_PARAMETER;
2856 if (pPT)
2857 rc2 = pgmR3DumpHierarchyHC32BitPT(pVM, pPT, u32Address, pHlp);
2858 else
2859 pHlp->pfnPrintf(pHlp, "%08x error! Page table at %#x was not found in the page pool!\n", u32Address, HCPhys);
2860 if (rc2 < rc && VBOX_SUCCESS(rc))
2861 rc = rc2;
2862 }
2863 }
2864 }
2865 }
2866
2867 return rc;
2868}
2869
2870
2871/**
2872 * Dumps a 32-bit shadow page table.
2873 *
2874 * @returns VBox status code (VINF_SUCCESS).
2875 * @param pVM The VM handle.
2876 * @param pPT Pointer to the page table.
2877 * @param u32Address The virtual address this table starts at.
2878 * @param PhysSearch Address to search for.
2879 */
2880int pgmR3DumpHierarchyGC32BitPT(PVM pVM, PX86PT pPT, uint32_t u32Address, RTGCPHYS PhysSearch)
2881{
2882 for (unsigned i = 0; i < ELEMENTS(pPT->a); i++)
2883 {
2884 X86PTE Pte = pPT->a[i];
2885 if (Pte.n.u1Present)
2886 {
2887 Log(( /*P R S A D G WT CD AT NX 4M a m d */
2888 "%08x 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x\n",
2889 u32Address + (i << X86_PT_SHIFT),
2890 Pte.n.u1Write ? 'W' : 'R',
2891 Pte.n.u1User ? 'U' : 'S',
2892 Pte.n.u1Accessed ? 'A' : '-',
2893 Pte.n.u1Dirty ? 'D' : '-',
2894 Pte.n.u1Global ? 'G' : '-',
2895 Pte.n.u1WriteThru ? "WT" : "--",
2896 Pte.n.u1CacheDisable? "CD" : "--",
2897 Pte.n.u1PAT ? "AT" : "--",
2898 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
2899 Pte.u & BIT(10) ? '1' : '0',
2900 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED ? 'v' : '-',
2901 Pte.u & X86_PDE_PG_MASK));
2902
2903 if ((Pte.u & X86_PDE_PG_MASK) == PhysSearch)
2904 {
2905 uint64_t fPageShw = 0;
2906 RTHCPHYS pPhysHC = 0;
2907
2908 PGMShwGetPage(pVM, (RTGCPTR)(u32Address + (i << X86_PT_SHIFT)), &fPageShw, &pPhysHC);
2909 Log(("Found %VGp at %VGv -> flags=%llx\n", PhysSearch, (RTGCPTR)(u32Address + (i << X86_PT_SHIFT)), fPageShw));
2910 }
2911 }
2912 }
2913 return VINF_SUCCESS;
2914}
2915
2916
2917/**
2918 * Dumps a 32-bit guest page directory and page tables.
2919 *
2920 * @returns VBox status code (VINF_SUCCESS).
2921 * @param pVM The VM handle.
2922 * @param cr3 The root of the hierarchy.
2923 * @param cr4 The CR4, PSE is currently used.
2924 * @param PhysSearch Address to search for.
2925 */
2926PGMR3DECL(int) PGMR3DumpHierarchyGC(PVM pVM, uint32_t cr3, uint32_t cr4, RTGCPHYS PhysSearch)
2927{
2928 bool fLongMode = false;
2929 const unsigned cch = fLongMode ? 16 : 8; NOREF(cch);
2930 PX86PD pPD = 0;
2931
2932 int rc = PGM_GCPHYS_2_PTR(pVM, cr3 & X86_CR3_PAGE_MASK, &pPD);
2933 if (VBOX_FAILURE(rc) || !pPD)
2934 {
2935 Log(("Page directory at %#x was not found in the page pool!\n", cr3 & X86_CR3_PAGE_MASK));
2936 return VERR_INVALID_PARAMETER;
2937 }
2938
2939 Log(("cr3=%08x cr4=%08x%s\n"
2940 "%-*s P - Present\n"
2941 "%-*s | R/W - Read (0) / Write (1)\n"
2942 "%-*s | | U/S - User (1) / Supervisor (0)\n"
2943 "%-*s | | | A - Accessed\n"
2944 "%-*s | | | | D - Dirty\n"
2945 "%-*s | | | | | G - Global\n"
2946 "%-*s | | | | | | WT - Write thru\n"
2947 "%-*s | | | | | | | CD - Cache disable\n"
2948 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
2949 "%-*s | | | | | | | | | NX - No execute (K8)\n"
2950 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
2951 "%-*s | | | | | | | | | | | AVL - a=allocated; m=mapping; d=track dirty;\n"
2952 "%-*s | | | | | | | | | | | | p=permanent; v=validated;\n"
2953 "%-*s Level | | | | | | | | | | | | Page\n"
2954 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
2955 - W U - - - -- -- -- -- -- 010 */
2956 , cr3, cr4, fLongMode ? " Long Mode" : "",
2957 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
2958 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address"));
2959
2960 for (unsigned i = 0; i < ELEMENTS(pPD->a); i++)
2961 {
2962 X86PDE Pde = pPD->a[i];
2963 if (Pde.n.u1Present)
2964 {
2965 const uint32_t u32Address = i << X86_PD_SHIFT;
2966
2967 if ((cr4 & X86_CR4_PSE) && Pde.b.u1Size)
2968 Log(( /*P R S A D G WT CD AT NX 4M a m d */
2969 "%08x 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08x\n",
2970 u32Address,
2971 Pde.b.u1Write ? 'W' : 'R',
2972 Pde.b.u1User ? 'U' : 'S',
2973 Pde.b.u1Accessed ? 'A' : '-',
2974 Pde.b.u1Dirty ? 'D' : '-',
2975 Pde.b.u1Global ? 'G' : '-',
2976 Pde.b.u1WriteThru ? "WT" : "--",
2977 Pde.b.u1CacheDisable? "CD" : "--",
2978 Pde.b.u1PAT ? "AT" : "--",
2979 Pde.u & BIT(9) ? '1' : '0',
2980 Pde.u & BIT(10) ? '1' : '0',
2981 Pde.u & BIT(11) ? '1' : '0',
2982 Pde.u & X86_PDE4M_PG_MASK));
2983 /** @todo PhysSearch */
2984 else
2985 {
2986 Log(( /*P R S A D G WT CD AT NX 4M a m d */
2987 "%08x 0 | P %c %c %c %c %c %s %s .. .. 4K %c%c%c %08x\n",
2988 u32Address,
2989 Pde.n.u1Write ? 'W' : 'R',
2990 Pde.n.u1User ? 'U' : 'S',
2991 Pde.n.u1Accessed ? 'A' : '-',
2992 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2993 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2994 Pde.n.u1WriteThru ? "WT" : "--",
2995 Pde.n.u1CacheDisable? "CD" : "--",
2996 Pde.u & BIT(9) ? '1' : '0',
2997 Pde.u & BIT(10) ? '1' : '0',
2998 Pde.u & BIT(11) ? '1' : '0',
2999 Pde.u & X86_PDE_PG_MASK));
3000 ////if (cMaxDepth >= 1)
3001 {
3002 /** @todo what about using the page pool for mapping PTs? */
3003 RTGCPHYS GCPhys = Pde.u & X86_PDE_PG_MASK;
3004 PX86PT pPT = NULL;
3005
3006 rc = PGM_GCPHYS_2_PTR(pVM, GCPhys, &pPT);
3007
3008 int rc2 = VERR_INVALID_PARAMETER;
3009 if (pPT)
3010 rc2 = pgmR3DumpHierarchyGC32BitPT(pVM, pPT, u32Address, PhysSearch);
3011 else
3012 Log(("%08x error! Page table at %#x was not found in the page pool!\n", u32Address, GCPhys));
3013 if (rc2 < rc && VBOX_SUCCESS(rc))
3014 rc = rc2;
3015 }
3016 }
3017 }
3018 }
3019
3020 return rc;
3021}
3022
3023
3024/**
3025 * Dumps a page table hierarchy use only physical addresses and cr4/lm flags.
3026 *
3027 * @returns VBox status code (VINF_SUCCESS).
3028 * @param pVM The VM handle.
3029 * @param cr3 The root of the hierarchy.
3030 * @param cr4 The cr4, only PAE and PSE is currently used.
3031 * @param fLongMode Set if long mode, false if not long mode.
3032 * @param cMaxDepth Number of levels to dump.
3033 * @param pHlp Pointer to the output functions.
3034 */
3035PGMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint32_t cr3, uint32_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
3036{
3037 if (!pHlp)
3038 pHlp = DBGFR3InfoLogHlp();
3039 if (!cMaxDepth)
3040 return VINF_SUCCESS;
3041 const unsigned cch = fLongMode ? 16 : 8;
3042 pHlp->pfnPrintf(pHlp,
3043 "cr3=%08x cr4=%08x%s\n"
3044 "%-*s P - Present\n"
3045 "%-*s | R/W - Read (0) / Write (1)\n"
3046 "%-*s | | U/S - User (1) / Supervisor (0)\n"
3047 "%-*s | | | A - Accessed\n"
3048 "%-*s | | | | D - Dirty\n"
3049 "%-*s | | | | | G - Global\n"
3050 "%-*s | | | | | | WT - Write thru\n"
3051 "%-*s | | | | | | | CD - Cache disable\n"
3052 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
3053 "%-*s | | | | | | | | | NX - No execute (K8)\n"
3054 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
3055 "%-*s | | | | | | | | | | | AVL - a=allocated; m=mapping; d=track dirty;\n"
3056 "%-*s | | | | | | | | | | | | p=permanent; v=validated;\n"
3057 "%-*s Level | | | | | | | | | | | | Page\n"
3058 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
3059 - W U - - - -- -- -- -- -- 010 */
3060 , cr3, cr4, fLongMode ? " Long Mode" : "",
3061 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
3062 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
3063 if (cr4 & X86_CR4_PAE)
3064 {
3065 if (fLongMode)
3066 return pgmR3DumpHierarchyHcPaePML4(pVM, cr3 & X86_CR3_PAGE_MASK, cr4, cMaxDepth, pHlp);
3067 return pgmR3DumpHierarchyHCPaePDPTR(pVM, cr3 & X86_CR3_PAE_PAGE_MASK, 0, cr4, false, cMaxDepth, pHlp);
3068 }
3069 return pgmR3DumpHierarchyHC32BitPD(pVM, cr3 & X86_CR3_PAGE_MASK, cr4, cMaxDepth, pHlp);
3070}
3071
3072
3073
3074#ifdef VBOX_WITH_DEBUGGER
3075/**
3076 * The '.pgmram' command.
3077 *
3078 * @returns VBox status.
3079 * @param pCmd Pointer to the command descriptor (as registered).
3080 * @param pCmdHlp Pointer to command helper functions.
3081 * @param pVM Pointer to the current VM (if any).
3082 * @param paArgs Pointer to (readonly) array of arguments.
3083 * @param cArgs Number of arguments in the array.
3084 */
3085static DECLCALLBACK(int) pgmR3CmdRam(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3086{
3087 /*
3088 * Validate input.
3089 */
3090 if (!pVM)
3091 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
3092 if (!pVM->pgm.s.pRamRangesGC)
3093 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Sorry, no Ram is registered.\n");
3094
3095 /*
3096 * Dump the ranges.
3097 */
3098 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "From - To (incl) pvHC\n");
3099 PPGMRAMRANGE pRam;
3100 for (pRam = pVM->pgm.s.pRamRangesHC; pRam; pRam = pRam->pNextHC)
3101 {
3102 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3103 "%VGp - %VGp %p\n",
3104 pRam->GCPhys, pRam->GCPhysLast, pRam->pvHC);
3105 if (VBOX_FAILURE(rc))
3106 return rc;
3107 }
3108
3109 return VINF_SUCCESS;
3110}
3111
3112
3113/**
3114 * The '.pgmmap' command.
3115 *
3116 * @returns VBox status.
3117 * @param pCmd Pointer to the command descriptor (as registered).
3118 * @param pCmdHlp Pointer to command helper functions.
3119 * @param pVM Pointer to the current VM (if any).
3120 * @param paArgs Pointer to (readonly) array of arguments.
3121 * @param cArgs Number of arguments in the array.
3122 */
3123static DECLCALLBACK(int) pgmR3CmdMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3124{
3125 /*
3126 * Validate input.
3127 */
3128 if (!pVM)
3129 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
3130 if (!pVM->pgm.s.pMappingsHC)
3131 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Sorry, no mappings are registered.\n");
3132
3133 /*
3134 * Print message about the fixedness of the mappings.
3135 */
3136 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, pVM->pgm.s.fMappingsFixed ? "The mappings are FIXED.\n" : "The mappings are FLOATING.\n");
3137 if (VBOX_FAILURE(rc))
3138 return rc;
3139
3140 /*
3141 * Dump the ranges.
3142 */
3143 PPGMMAPPING pCur;
3144 for (pCur = pVM->pgm.s.pMappingsHC; pCur; pCur = pCur->pNextHC)
3145 {
3146 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3147 "%08x - %08x %s\n",
3148 pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc);
3149 if (VBOX_FAILURE(rc))
3150 return rc;
3151 }
3152
3153 return VINF_SUCCESS;
3154}
3155
3156
3157/**
3158 * The '.pgmsync' command.
3159 *
3160 * @returns VBox status.
3161 * @param pCmd Pointer to the command descriptor (as registered).
3162 * @param pCmdHlp Pointer to command helper functions.
3163 * @param pVM Pointer to the current VM (if any).
3164 * @param paArgs Pointer to (readonly) array of arguments.
3165 * @param cArgs Number of arguments in the array.
3166 */
3167static DECLCALLBACK(int) pgmR3CmdSync(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3168{
3169 /*
3170 * Validate input.
3171 */
3172 if (!pVM)
3173 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
3174
3175 /*
3176 * Force page directory sync.
3177 */
3178 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
3179
3180 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Forcing page directory sync.\n");
3181 if (VBOX_FAILURE(rc))
3182 return rc;
3183
3184 return VINF_SUCCESS;
3185}
3186
3187
3188/**
3189 * The '.pgmsyncalways' command.
3190 *
3191 * @returns VBox status.
3192 * @param pCmd Pointer to the command descriptor (as registered).
3193 * @param pCmdHlp Pointer to command helper functions.
3194 * @param pVM Pointer to the current VM (if any).
3195 * @param paArgs Pointer to (readonly) array of arguments.
3196 * @param cArgs Number of arguments in the array.
3197 */
3198static DECLCALLBACK(int) pgmR3CmdSyncAlways(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3199{
3200 /*
3201 * Validate input.
3202 */
3203 if (!pVM)
3204 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The command requires VM to be selected.\n");
3205
3206 /*
3207 * Force page directory sync.
3208 */
3209 if (pVM->pgm.s.fSyncFlags & PGM_SYNC_ALWAYS)
3210 {
3211 ASMAtomicAndU32(&pVM->pgm.s.fSyncFlags, ~PGM_SYNC_ALWAYS);
3212 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Disabled permanent forced page directory syncing.\n");
3213 }
3214 else
3215 {
3216 ASMAtomicOrU32(&pVM->pgm.s.fSyncFlags, PGM_SYNC_ALWAYS);
3217 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
3218 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Enabled permanent forced page directory syncing.\n");
3219 }
3220}
3221
3222#endif
3223
3224/**
3225 * pvUser argument of the pgmR3CheckIntegrity*Node callbacks.
3226 */
3227typedef struct PGMCHECKINTARGS
3228{
3229 bool fLeftToRight; /**< true: left-to-right; false: right-to-left. */
3230 PPGMPHYSHANDLER pPrevPhys;
3231 PPGMVIRTHANDLER pPrevVirt;
3232 PPGMPHYS2VIRTHANDLER pPrevPhys2Virt;
3233 PVM pVM;
3234} PGMCHECKINTARGS, *PPGMCHECKINTARGS;
3235
3236/**
3237 * Validate a node in the physical handler tree.
3238 *
3239 * @returns 0 on if ok, other wise 1.
3240 * @param pNode The handler node.
3241 * @param pvUser pVM.
3242 */
3243static DECLCALLBACK(int) pgmR3CheckIntegrityPhysHandlerNode(PAVLROGCPHYSNODECORE pNode, void *pvUser)
3244{
3245 PPGMCHECKINTARGS pArgs = (PPGMCHECKINTARGS)pvUser;
3246 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
3247 AssertReleaseReturn(!((uintptr_t)pCur & 7), 1);
3248 AssertReleaseMsg(pCur->Core.Key <= pCur->Core.KeyLast,("pCur=%p %VGp-%VGp %s\n", pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
3249 AssertReleaseMsg( !pArgs->pPrevPhys
3250 || (pArgs->fLeftToRight ? pArgs->pPrevPhys->Core.KeyLast < pCur->Core.Key : pArgs->pPrevPhys->Core.KeyLast > pCur->Core.Key),
3251 ("pPrevPhys=%p %VGp-%VGp %s\n"
3252 " pCur=%p %VGp-%VGp %s\n",
3253 pArgs->pPrevPhys, pArgs->pPrevPhys->Core.Key, pArgs->pPrevPhys->Core.KeyLast, pArgs->pPrevPhys->pszDesc,
3254 pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
3255 pArgs->pPrevPhys = pCur;
3256 return 0;
3257}
3258
3259
3260/**
3261 * Validate a node in the virtual handler tree.
3262 *
3263 * @returns 0 on if ok, other wise 1.
3264 * @param pNode The handler node.
3265 * @param pvUser pVM.
3266 */
3267static DECLCALLBACK(int) pgmR3CheckIntegrityVirtHandlerNode(PAVLROGCPTRNODECORE pNode, void *pvUser)
3268{
3269 PPGMCHECKINTARGS pArgs = (PPGMCHECKINTARGS)pvUser;
3270 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
3271 AssertReleaseReturn(!((uintptr_t)pCur & 7), 1);
3272 AssertReleaseMsg(pCur->Core.Key <= pCur->Core.KeyLast,("pCur=%p %VGv-%VGv %s\n", pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
3273 AssertReleaseMsg( !pArgs->pPrevVirt
3274 || (pArgs->fLeftToRight ? pArgs->pPrevVirt->Core.KeyLast < pCur->Core.Key : pArgs->pPrevVirt->Core.KeyLast > pCur->Core.Key),
3275 ("pPrevVirt=%p %VGv-%VGv %s\n"
3276 " pCur=%p %VGv-%VGv %s\n",
3277 pArgs->pPrevVirt, pArgs->pPrevVirt->Core.Key, pArgs->pPrevVirt->Core.KeyLast, pArgs->pPrevVirt->pszDesc,
3278 pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
3279 for (unsigned iPage = 0; iPage < pCur->cPages; iPage++)
3280 {
3281 AssertReleaseMsg(pCur->aPhysToVirt[iPage].offVirtHandler == -RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[iPage]),
3282 ("pCur=%p %VGv-%VGv %s\n"
3283 "iPage=%d offVirtHandle=%#x expected %#x\n",
3284 pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc,
3285 iPage, pCur->aPhysToVirt[iPage].offVirtHandler, -RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[iPage])));
3286 }
3287 pArgs->pPrevVirt = pCur;
3288 return 0;
3289}
3290
3291
3292/**
3293 * Validate a node in the virtual handler tree.
3294 *
3295 * @returns 0 on if ok, other wise 1.
3296 * @param pNode The handler node.
3297 * @param pvUser pVM.
3298 */
3299static DECLCALLBACK(int) pgmR3CheckIntegrityPhysToVirtHandlerNode(PAVLROGCPHYSNODECORE pNode, void *pvUser)
3300{
3301 PPGMCHECKINTARGS pArgs = (PPGMCHECKINTARGS)pvUser;
3302 PPGMPHYS2VIRTHANDLER pCur = (PPGMPHYS2VIRTHANDLER)pNode;
3303 AssertReleaseMsgReturn(!((uintptr_t)pCur & 3), ("\n"), 1);
3304 AssertReleaseMsgReturn(!(pCur->offVirtHandler & 3), ("\n"), 1);
3305 AssertReleaseMsg(pCur->Core.Key <= pCur->Core.KeyLast,("pCur=%p %VGp-%VGp\n", pCur, pCur->Core.Key, pCur->Core.KeyLast));
3306 AssertReleaseMsg( !pArgs->pPrevPhys2Virt
3307 || (pArgs->fLeftToRight ? pArgs->pPrevPhys2Virt->Core.KeyLast < pCur->Core.Key : pArgs->pPrevPhys2Virt->Core.KeyLast > pCur->Core.Key),
3308 ("pPrevPhys2Virt=%p %VGp-%VGp\n"
3309 " pCur=%p %VGp-%VGp\n",
3310 pArgs->pPrevPhys2Virt, pArgs->pPrevPhys2Virt->Core.Key, pArgs->pPrevPhys2Virt->Core.KeyLast,
3311 pCur, pCur->Core.Key, pCur->Core.KeyLast));
3312 AssertReleaseMsg( !pArgs->pPrevPhys2Virt
3313 || (pArgs->fLeftToRight ? pArgs->pPrevPhys2Virt->Core.KeyLast < pCur->Core.Key : pArgs->pPrevPhys2Virt->Core.KeyLast > pCur->Core.Key),
3314 ("pPrevPhys2Virt=%p %VGp-%VGp\n"
3315 " pCur=%p %VGp-%VGp\n",
3316 pArgs->pPrevPhys2Virt, pArgs->pPrevPhys2Virt->Core.Key, pArgs->pPrevPhys2Virt->Core.KeyLast,
3317 pCur, pCur->Core.Key, pCur->Core.KeyLast));
3318 AssertReleaseMsg((pCur->offNextAlias & (PGMPHYS2VIRTHANDLER_IN_TREE | PGMPHYS2VIRTHANDLER_IS_HEAD)) == (PGMPHYS2VIRTHANDLER_IN_TREE | PGMPHYS2VIRTHANDLER_IS_HEAD),
3319 ("pCur=%p:{.Core.Key=%VGp, .Core.KeyLast=%VGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
3320 pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->offVirtHandler, pCur->offNextAlias));
3321 if (pCur->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK)
3322 {
3323 PPGMPHYS2VIRTHANDLER pCur2 = pCur;
3324 for (;;)
3325 {
3326 pCur2 = (PPGMPHYS2VIRTHANDLER)((intptr_t)pCur + (pCur->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
3327 AssertReleaseMsg(pCur2 != pCur,
3328 (" pCur=%p:{.Core.Key=%VGp, .Core.KeyLast=%VGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
3329 pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->offVirtHandler, pCur->offNextAlias));
3330 AssertReleaseMsg((pCur2->offNextAlias & (PGMPHYS2VIRTHANDLER_IN_TREE | PGMPHYS2VIRTHANDLER_IS_HEAD)) == PGMPHYS2VIRTHANDLER_IN_TREE,
3331 (" pCur=%p:{.Core.Key=%VGp, .Core.KeyLast=%VGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n"
3332 "pCur2=%p:{.Core.Key=%VGp, .Core.KeyLast=%VGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
3333 pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->offVirtHandler, pCur->offNextAlias,
3334 pCur2, pCur2->Core.Key, pCur2->Core.KeyLast, pCur2->offVirtHandler, pCur2->offNextAlias));
3335 AssertReleaseMsg((pCur2->Core.Key ^ pCur->Core.Key) < PAGE_SIZE,
3336 (" pCur=%p:{.Core.Key=%VGp, .Core.KeyLast=%VGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n"
3337 "pCur2=%p:{.Core.Key=%VGp, .Core.KeyLast=%VGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
3338 pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->offVirtHandler, pCur->offNextAlias,
3339 pCur2, pCur2->Core.Key, pCur2->Core.KeyLast, pCur2->offVirtHandler, pCur2->offNextAlias));
3340 AssertReleaseMsg((pCur2->Core.KeyLast ^ pCur->Core.KeyLast) < PAGE_SIZE,
3341 (" pCur=%p:{.Core.Key=%VGp, .Core.KeyLast=%VGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n"
3342 "pCur2=%p:{.Core.Key=%VGp, .Core.KeyLast=%VGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32}\n",
3343 pCur, pCur->Core.Key, pCur->Core.KeyLast, pCur->offVirtHandler, pCur->offNextAlias,
3344 pCur2, pCur2->Core.Key, pCur2->Core.KeyLast, pCur2->offVirtHandler, pCur2->offNextAlias));
3345 if (!(pCur2->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK))
3346 break;
3347 }
3348 }
3349
3350 pArgs->pPrevPhys2Virt = pCur;
3351 return 0;
3352}
3353
3354
3355/**
3356 * Perform an integrity check on the PGM component.
3357 *
3358 * @returns VINF_SUCCESS if everything is fine.
3359 * @returns VBox error status after asserting on integrity breach.
3360 * @param pVM The VM handle.
3361 */
3362PDMR3DECL(int) PGMR3CheckIntegrity(PVM pVM)
3363{
3364 AssertReleaseReturn(pVM->pgm.s.offVM, VERR_INTERNAL_ERROR);
3365
3366 /*
3367 * Check the trees.
3368 */
3369 int cErrors = 0;
3370 PGMCHECKINTARGS Args = { true, NULL, NULL, NULL, pVM };
3371 cErrors += RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, true, pgmR3CheckIntegrityPhysHandlerNode, &Args);
3372 Args.fLeftToRight = false;
3373 cErrors += RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, false, pgmR3CheckIntegrityPhysHandlerNode, &Args);
3374 Args.fLeftToRight = true;
3375 cErrors += RTAvlroGCPtrDoWithAll( &pVM->pgm.s.pTreesHC->VirtHandlers, true, pgmR3CheckIntegrityVirtHandlerNode, &Args);
3376 Args.fLeftToRight = false;
3377 cErrors += RTAvlroGCPtrDoWithAll( &pVM->pgm.s.pTreesHC->VirtHandlers, false, pgmR3CheckIntegrityVirtHandlerNode, &Args);
3378 Args.fLeftToRight = true;
3379 cErrors += RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysToVirtHandlers, true, pgmR3CheckIntegrityPhysToVirtHandlerNode, &Args);
3380 Args.fLeftToRight = false;
3381 cErrors += RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysToVirtHandlers, false, pgmR3CheckIntegrityPhysToVirtHandlerNode, &Args);
3382
3383 return !cErrors ? VINF_SUCCESS : VERR_INTERNAL_ERROR;
3384}
3385
3386
3387/**
3388 * Inform PGM if we want all mappings to be put into the shadow page table. (necessary for e.g. VMX)
3389 *
3390 * @returns VBox status code.
3391 * @param pVM VM handle.
3392 * @param fEnable Enable or disable shadow mappings
3393 */
3394PGMR3DECL(int) PGMR3ChangeShwPDMappings(PVM pVM, bool fEnable)
3395{
3396 pVM->pgm.s.fDisableMappings = !fEnable;
3397
3398 size_t cb;
3399 int rc = PGMR3MappingsSize(pVM, &cb);
3400 AssertRCReturn(rc, rc);
3401
3402 /* Pretend the mappings are now fixed; to force a refresh of the reserved PDEs. */
3403 rc = PGMR3MappingsFix(pVM, MM_HYPER_AREA_ADDRESS, cb);
3404 AssertRCReturn(rc, rc);
3405
3406 return VINF_SUCCESS;
3407}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette