VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAll.cpp@ 23086

Last change on this file since 23086 was 23086, checked in by vboxsync, 15 years ago

Check for more invalid rcs (4064)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 82.5 KB
Line 
1/* $Id: PGMAll.cpp 23086 2009-09-17 11:41:29Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - All context code.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_PGM
26#include <VBox/pgm.h>
27#include <VBox/cpum.h>
28#include <VBox/selm.h>
29#include <VBox/iom.h>
30#include <VBox/sup.h>
31#include <VBox/mm.h>
32#include <VBox/stam.h>
33#include <VBox/csam.h>
34#include <VBox/patm.h>
35#include <VBox/trpm.h>
36#include <VBox/rem.h>
37#include <VBox/em.h>
38#include <VBox/hwaccm.h>
39#include <VBox/hwacc_vmx.h>
40#include "PGMInternal.h"
41#include <VBox/vm.h>
42#include <iprt/assert.h>
43#include <iprt/asm.h>
44#include <iprt/string.h>
45#include <VBox/log.h>
46#include <VBox/param.h>
47#include <VBox/err.h>
48
49
50/*******************************************************************************
51* Structures and Typedefs *
52*******************************************************************************/
53/**
54 * Stated structure for PGM_GST_NAME(HandlerVirtualUpdate) that's
55 * passed to PGM_GST_NAME(VirtHandlerUpdateOne) during enumeration.
56 */
57typedef struct PGMHVUSTATE
58{
59 /** The VM handle. */
60 PVM pVM;
61 /** The VMCPU handle. */
62 PVMCPU pVCpu;
63 /** The todo flags. */
64 RTUINT fTodo;
65 /** The CR4 register value. */
66 uint32_t cr4;
67} PGMHVUSTATE, *PPGMHVUSTATE;
68
69
70/*******************************************************************************
71* Internal Functions *
72*******************************************************************************/
73DECLINLINE(int) pgmShwGetLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPT *ppPdpt, PX86PDPAE *ppPD);
74DECLINLINE(int) pgmShwGetPaePoolPagePD(PPGMCPU pPGM, RTGCPTR GCPtr, PPGMPOOLPAGE *ppShwPde);
75
76/*
77 * Shadow - 32-bit mode
78 */
79#define PGM_SHW_TYPE PGM_TYPE_32BIT
80#define PGM_SHW_NAME(name) PGM_SHW_NAME_32BIT(name)
81#include "PGMAllShw.h"
82
83/* Guest - real mode */
84#define PGM_GST_TYPE PGM_TYPE_REAL
85#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
86#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_REAL(name)
87#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
88#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_32BIT_PD_PHYS
89#include "PGMGstDefs.h"
90#include "PGMAllGst.h"
91#include "PGMAllBth.h"
92#undef BTH_PGMPOOLKIND_PT_FOR_PT
93#undef BTH_PGMPOOLKIND_ROOT
94#undef PGM_BTH_NAME
95#undef PGM_GST_TYPE
96#undef PGM_GST_NAME
97
98/* Guest - protected mode */
99#define PGM_GST_TYPE PGM_TYPE_PROT
100#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
101#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
102#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
103#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_32BIT_PD_PHYS
104#include "PGMGstDefs.h"
105#include "PGMAllGst.h"
106#include "PGMAllBth.h"
107#undef BTH_PGMPOOLKIND_PT_FOR_PT
108#undef BTH_PGMPOOLKIND_ROOT
109#undef PGM_BTH_NAME
110#undef PGM_GST_TYPE
111#undef PGM_GST_NAME
112
113/* Guest - 32-bit mode */
114#define PGM_GST_TYPE PGM_TYPE_32BIT
115#define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
116#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_32BIT(name)
117#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT
118#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB
119#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_32BIT_PD
120#include "PGMGstDefs.h"
121#include "PGMAllGst.h"
122#include "PGMAllBth.h"
123#undef BTH_PGMPOOLKIND_PT_FOR_BIG
124#undef BTH_PGMPOOLKIND_PT_FOR_PT
125#undef BTH_PGMPOOLKIND_ROOT
126#undef PGM_BTH_NAME
127#undef PGM_GST_TYPE
128#undef PGM_GST_NAME
129
130#undef PGM_SHW_TYPE
131#undef PGM_SHW_NAME
132
133
134/*
135 * Shadow - PAE mode
136 */
137#define PGM_SHW_TYPE PGM_TYPE_PAE
138#define PGM_SHW_NAME(name) PGM_SHW_NAME_PAE(name)
139#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
140#include "PGMAllShw.h"
141
142/* Guest - real mode */
143#define PGM_GST_TYPE PGM_TYPE_REAL
144#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
145#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
146#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
147#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_PHYS
148#include "PGMGstDefs.h"
149#include "PGMAllBth.h"
150#undef BTH_PGMPOOLKIND_PT_FOR_PT
151#undef BTH_PGMPOOLKIND_ROOT
152#undef PGM_BTH_NAME
153#undef PGM_GST_TYPE
154#undef PGM_GST_NAME
155
156/* Guest - protected mode */
157#define PGM_GST_TYPE PGM_TYPE_PROT
158#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
159#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
160#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
161#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_PHYS
162#include "PGMGstDefs.h"
163#include "PGMAllBth.h"
164#undef BTH_PGMPOOLKIND_PT_FOR_PT
165#undef BTH_PGMPOOLKIND_ROOT
166#undef PGM_BTH_NAME
167#undef PGM_GST_TYPE
168#undef PGM_GST_NAME
169
170/* Guest - 32-bit mode */
171#define PGM_GST_TYPE PGM_TYPE_32BIT
172#define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
173#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_32BIT(name)
174#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_32BIT_PT
175#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB
176#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_FOR_32BIT
177#include "PGMGstDefs.h"
178#include "PGMAllBth.h"
179#undef BTH_PGMPOOLKIND_PT_FOR_BIG
180#undef BTH_PGMPOOLKIND_PT_FOR_PT
181#undef BTH_PGMPOOLKIND_ROOT
182#undef PGM_BTH_NAME
183#undef PGM_GST_TYPE
184#undef PGM_GST_NAME
185
186
187/* Guest - PAE mode */
188#define PGM_GST_TYPE PGM_TYPE_PAE
189#define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
190#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PAE(name)
191#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
192#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
193#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT
194#include "PGMGstDefs.h"
195#include "PGMAllGst.h"
196#include "PGMAllBth.h"
197#undef BTH_PGMPOOLKIND_PT_FOR_BIG
198#undef BTH_PGMPOOLKIND_PT_FOR_PT
199#undef BTH_PGMPOOLKIND_ROOT
200#undef PGM_BTH_NAME
201#undef PGM_GST_TYPE
202#undef PGM_GST_NAME
203
204#undef PGM_SHW_TYPE
205#undef PGM_SHW_NAME
206
207
208#ifndef IN_RC /* AMD64 implies VT-x/AMD-V */
209/*
210 * Shadow - AMD64 mode
211 */
212# define PGM_SHW_TYPE PGM_TYPE_AMD64
213# define PGM_SHW_NAME(name) PGM_SHW_NAME_AMD64(name)
214# include "PGMAllShw.h"
215
216/* Guest - protected mode (only used for AMD-V nested paging in 64 bits mode) */
217# define PGM_GST_TYPE PGM_TYPE_PROT
218# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
219# define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_PROT(name)
220# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
221# define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PD_PHYS
222# include "PGMGstDefs.h"
223# include "PGMAllBth.h"
224# undef BTH_PGMPOOLKIND_PT_FOR_PT
225# undef BTH_PGMPOOLKIND_ROOT
226# undef PGM_BTH_NAME
227# undef PGM_GST_TYPE
228# undef PGM_GST_NAME
229
230# ifdef VBOX_WITH_64_BITS_GUESTS
231/* Guest - AMD64 mode */
232# define PGM_GST_TYPE PGM_TYPE_AMD64
233# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
234# define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_AMD64(name)
235# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
236# define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
237# define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_64BIT_PML4
238# include "PGMGstDefs.h"
239# include "PGMAllGst.h"
240# include "PGMAllBth.h"
241# undef BTH_PGMPOOLKIND_PT_FOR_BIG
242# undef BTH_PGMPOOLKIND_PT_FOR_PT
243# undef BTH_PGMPOOLKIND_ROOT
244# undef PGM_BTH_NAME
245# undef PGM_GST_TYPE
246# undef PGM_GST_NAME
247# endif /* VBOX_WITH_64_BITS_GUESTS */
248
249# undef PGM_SHW_TYPE
250# undef PGM_SHW_NAME
251
252
253/*
254 * Shadow - Nested paging mode
255 */
256# define PGM_SHW_TYPE PGM_TYPE_NESTED
257# define PGM_SHW_NAME(name) PGM_SHW_NAME_NESTED(name)
258# include "PGMAllShw.h"
259
260/* Guest - real mode */
261# define PGM_GST_TYPE PGM_TYPE_REAL
262# define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
263# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_REAL(name)
264# include "PGMGstDefs.h"
265# include "PGMAllBth.h"
266# undef PGM_BTH_NAME
267# undef PGM_GST_TYPE
268# undef PGM_GST_NAME
269
270/* Guest - protected mode */
271# define PGM_GST_TYPE PGM_TYPE_PROT
272# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
273# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PROT(name)
274# include "PGMGstDefs.h"
275# include "PGMAllBth.h"
276# undef PGM_BTH_NAME
277# undef PGM_GST_TYPE
278# undef PGM_GST_NAME
279
280/* Guest - 32-bit mode */
281# define PGM_GST_TYPE PGM_TYPE_32BIT
282# define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
283# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_32BIT(name)
284# include "PGMGstDefs.h"
285# include "PGMAllBth.h"
286# undef PGM_BTH_NAME
287# undef PGM_GST_TYPE
288# undef PGM_GST_NAME
289
290/* Guest - PAE mode */
291# define PGM_GST_TYPE PGM_TYPE_PAE
292# define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
293# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PAE(name)
294# include "PGMGstDefs.h"
295# include "PGMAllBth.h"
296# undef PGM_BTH_NAME
297# undef PGM_GST_TYPE
298# undef PGM_GST_NAME
299
300# ifdef VBOX_WITH_64_BITS_GUESTS
301/* Guest - AMD64 mode */
302# define PGM_GST_TYPE PGM_TYPE_AMD64
303# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
304# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_AMD64(name)
305# include "PGMGstDefs.h"
306# include "PGMAllBth.h"
307# undef PGM_BTH_NAME
308# undef PGM_GST_TYPE
309# undef PGM_GST_NAME
310# endif /* VBOX_WITH_64_BITS_GUESTS */
311
312# undef PGM_SHW_TYPE
313# undef PGM_SHW_NAME
314
315
316/*
317 * Shadow - EPT
318 */
319# define PGM_SHW_TYPE PGM_TYPE_EPT
320# define PGM_SHW_NAME(name) PGM_SHW_NAME_EPT(name)
321# include "PGMAllShw.h"
322
323/* Guest - real mode */
324# define PGM_GST_TYPE PGM_TYPE_REAL
325# define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
326# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_REAL(name)
327# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
328# include "PGMGstDefs.h"
329# include "PGMAllBth.h"
330# undef BTH_PGMPOOLKIND_PT_FOR_PT
331# undef PGM_BTH_NAME
332# undef PGM_GST_TYPE
333# undef PGM_GST_NAME
334
335/* Guest - protected mode */
336# define PGM_GST_TYPE PGM_TYPE_PROT
337# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
338# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PROT(name)
339# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
340# include "PGMGstDefs.h"
341# include "PGMAllBth.h"
342# undef BTH_PGMPOOLKIND_PT_FOR_PT
343# undef PGM_BTH_NAME
344# undef PGM_GST_TYPE
345# undef PGM_GST_NAME
346
347/* Guest - 32-bit mode */
348# define PGM_GST_TYPE PGM_TYPE_32BIT
349# define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
350# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_32BIT(name)
351# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
352# include "PGMGstDefs.h"
353# include "PGMAllBth.h"
354# undef BTH_PGMPOOLKIND_PT_FOR_PT
355# undef PGM_BTH_NAME
356# undef PGM_GST_TYPE
357# undef PGM_GST_NAME
358
359/* Guest - PAE mode */
360# define PGM_GST_TYPE PGM_TYPE_PAE
361# define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
362# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PAE(name)
363# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
364# include "PGMGstDefs.h"
365# include "PGMAllBth.h"
366# undef BTH_PGMPOOLKIND_PT_FOR_PT
367# undef PGM_BTH_NAME
368# undef PGM_GST_TYPE
369# undef PGM_GST_NAME
370
371# ifdef VBOX_WITH_64_BITS_GUESTS
372/* Guest - AMD64 mode */
373# define PGM_GST_TYPE PGM_TYPE_AMD64
374# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
375# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_AMD64(name)
376# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
377# include "PGMGstDefs.h"
378# include "PGMAllBth.h"
379# undef BTH_PGMPOOLKIND_PT_FOR_PT
380# undef PGM_BTH_NAME
381# undef PGM_GST_TYPE
382# undef PGM_GST_NAME
383# endif /* VBOX_WITH_64_BITS_GUESTS */
384
385# undef PGM_SHW_TYPE
386# undef PGM_SHW_NAME
387
388#endif /* !IN_RC */
389
390
391#ifndef IN_RING3
392/**
393 * #PF Handler.
394 *
395 * @returns VBox status code (appropriate for trap handling and GC return).
396 * @param pVCpu VMCPU handle.
397 * @param uErr The trap error code.
398 * @param pRegFrame Trap register frame.
399 * @param pvFault The fault address.
400 */
401VMMDECL(int) PGMTrap0eHandler(PVMCPU pVCpu, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
402{
403 PVM pVM = pVCpu->CTX_SUFF(pVM);
404
405 Log(("PGMTrap0eHandler: uErr=%RGu pvFault=%RGv eip=%04x:%RGv\n", uErr, pvFault, pRegFrame->cs, (RTGCPTR)pRegFrame->rip));
406 STAM_PROFILE_START(&pVCpu->pgm.s.StatRZTrap0e, a);
407 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = NULL; } );
408
409
410#ifdef VBOX_WITH_STATISTICS
411 /*
412 * Error code stats.
413 */
414 if (uErr & X86_TRAP_PF_US)
415 {
416 if (!(uErr & X86_TRAP_PF_P))
417 {
418 if (uErr & X86_TRAP_PF_RW)
419 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSNotPresentWrite);
420 else
421 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSNotPresentRead);
422 }
423 else if (uErr & X86_TRAP_PF_RW)
424 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSWrite);
425 else if (uErr & X86_TRAP_PF_RSVD)
426 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSReserved);
427 else if (uErr & X86_TRAP_PF_ID)
428 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSNXE);
429 else
430 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSRead);
431 }
432 else
433 { /* Supervisor */
434 if (!(uErr & X86_TRAP_PF_P))
435 {
436 if (uErr & X86_TRAP_PF_RW)
437 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSVNotPresentWrite);
438 else
439 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSVNotPresentRead);
440 }
441 else if (uErr & X86_TRAP_PF_RW)
442 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSVWrite);
443 else if (uErr & X86_TRAP_PF_ID)
444 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSNXE);
445 else if (uErr & X86_TRAP_PF_RSVD)
446 STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSVReserved);
447 }
448#endif /* VBOX_WITH_STATISTICS */
449
450 /*
451 * Call the worker.
452 */
453 pgmLock(pVM);
454 int rc = PGM_BTH_PFN(Trap0eHandler, pVCpu)(pVCpu, uErr, pRegFrame, pvFault);
455 Assert(PGMIsLockOwner(pVM));
456 pgmUnlock(pVM);
457 if (rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE)
458 rc = VINF_SUCCESS;
459
460# ifdef IN_RING0
461 /* Note: hack alert for difficult to reproduce problem. */
462 if ( rc == VERR_PAGE_TABLE_NOT_PRESENT /* seen with UNI & SMP */
463 || rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT /* seen with SMP */
464 || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT) /* precaution */
465 {
466 Log(("WARNING: Unexpected VERR_PAGE_TABLE_NOT_PRESENT (%d) for page fault at %RGv error code %x (rip=%RGv)\n", rc, pvFault, uErr, pRegFrame->rip));
467 rc = VINF_SUCCESS;
468 }
469# endif
470
471 STAM_STATS({ if (rc == VINF_EM_RAW_GUEST_TRAP) STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eGuestPF); });
472 STAM_STATS({ if (!pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution))
473 pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2Misc; });
474 STAM_PROFILE_STOP_EX(&pVCpu->pgm.s.StatRZTrap0e, pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution), a);
475 return rc;
476}
477#endif /* !IN_RING3 */
478
479
480/**
481 * Prefetch a page
482 *
483 * Typically used to sync commonly used pages before entering raw mode
484 * after a CR3 reload.
485 *
486 * @returns VBox status code suitable for scheduling.
487 * @retval VINF_SUCCESS on success.
488 * @retval VINF_PGM_SYNC_CR3 if we're out of shadow pages or something like that.
489 * @param pVCpu VMCPU handle.
490 * @param GCPtrPage Page to invalidate.
491 */
492VMMDECL(int) PGMPrefetchPage(PVMCPU pVCpu, RTGCPTR GCPtrPage)
493{
494 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,Prefetch), a);
495 int rc = PGM_BTH_PFN(PrefetchPage, pVCpu)(pVCpu, GCPtrPage);
496 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,Prefetch), a);
497 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 || RT_FAILURE(rc), ("rc=%Rrc\n", rc));
498 return rc;
499}
500
501
502/**
503 * Gets the mapping corresponding to the specified address (if any).
504 *
505 * @returns Pointer to the mapping.
506 * @returns NULL if not
507 *
508 * @param pVM The virtual machine.
509 * @param GCPtr The guest context pointer.
510 */
511PPGMMAPPING pgmGetMapping(PVM pVM, RTGCPTR GCPtr)
512{
513 PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
514 while (pMapping)
515 {
516 if ((uintptr_t)GCPtr < (uintptr_t)pMapping->GCPtr)
517 break;
518 if ((uintptr_t)GCPtr - (uintptr_t)pMapping->GCPtr < pMapping->cb)
519 return pMapping;
520 pMapping = pMapping->CTX_SUFF(pNext);
521 }
522 return NULL;
523}
524
525
526/**
527 * Verifies a range of pages for read or write access
528 *
529 * Only checks the guest's page tables
530 *
531 * @returns VBox status code.
532 * @param pVCpu VMCPU handle.
533 * @param Addr Guest virtual address to check
534 * @param cbSize Access size
535 * @param fAccess Access type (r/w, user/supervisor (X86_PTE_*))
536 * @remarks Current not in use.
537 */
538VMMDECL(int) PGMIsValidAccess(PVMCPU pVCpu, RTGCPTR Addr, uint32_t cbSize, uint32_t fAccess)
539{
540 /*
541 * Validate input.
542 */
543 if (fAccess & ~(X86_PTE_US | X86_PTE_RW))
544 {
545 AssertMsgFailed(("PGMIsValidAccess: invalid access type %08x\n", fAccess));
546 return VERR_INVALID_PARAMETER;
547 }
548
549 uint64_t fPage;
550 int rc = PGMGstGetPage(pVCpu, (RTGCPTR)Addr, &fPage, NULL);
551 if (RT_FAILURE(rc))
552 {
553 Log(("PGMIsValidAccess: access violation for %RGv rc=%d\n", Addr, rc));
554 return VINF_EM_RAW_GUEST_TRAP;
555 }
556
557 /*
558 * Check if the access would cause a page fault
559 *
560 * Note that hypervisor page directories are not present in the guest's tables, so this check
561 * is sufficient.
562 */
563 bool fWrite = !!(fAccess & X86_PTE_RW);
564 bool fUser = !!(fAccess & X86_PTE_US);
565 if ( !(fPage & X86_PTE_P)
566 || (fWrite && !(fPage & X86_PTE_RW))
567 || (fUser && !(fPage & X86_PTE_US)) )
568 {
569 Log(("PGMIsValidAccess: access violation for %RGv attr %#llx vs %d:%d\n", Addr, fPage, fWrite, fUser));
570 return VINF_EM_RAW_GUEST_TRAP;
571 }
572 if ( RT_SUCCESS(rc)
573 && PAGE_ADDRESS(Addr) != PAGE_ADDRESS(Addr + cbSize))
574 return PGMIsValidAccess(pVCpu, Addr + PAGE_SIZE, (cbSize > PAGE_SIZE) ? cbSize - PAGE_SIZE : 1, fAccess);
575 return rc;
576}
577
578
579/**
580 * Verifies a range of pages for read or write access
581 *
582 * Supports handling of pages marked for dirty bit tracking and CSAM
583 *
584 * @returns VBox status code.
585 * @param pVCpu VMCPU handle.
586 * @param Addr Guest virtual address to check
587 * @param cbSize Access size
588 * @param fAccess Access type (r/w, user/supervisor (X86_PTE_*))
589 */
590VMMDECL(int) PGMVerifyAccess(PVMCPU pVCpu, RTGCPTR Addr, uint32_t cbSize, uint32_t fAccess)
591{
592 PVM pVM = pVCpu->CTX_SUFF(pVM);
593
594 AssertMsg(!(fAccess & ~(X86_PTE_US | X86_PTE_RW)), ("PGMVerifyAccess: invalid access type %08x\n", fAccess));
595
596 /*
597 * Get going.
598 */
599 uint64_t fPageGst;
600 int rc = PGMGstGetPage(pVCpu, (RTGCPTR)Addr, &fPageGst, NULL);
601 if (RT_FAILURE(rc))
602 {
603 Log(("PGMVerifyAccess: access violation for %RGv rc=%d\n", Addr, rc));
604 return VINF_EM_RAW_GUEST_TRAP;
605 }
606
607 /*
608 * Check if the access would cause a page fault
609 *
610 * Note that hypervisor page directories are not present in the guest's tables, so this check
611 * is sufficient.
612 */
613 const bool fWrite = !!(fAccess & X86_PTE_RW);
614 const bool fUser = !!(fAccess & X86_PTE_US);
615 if ( !(fPageGst & X86_PTE_P)
616 || (fWrite && !(fPageGst & X86_PTE_RW))
617 || (fUser && !(fPageGst & X86_PTE_US)) )
618 {
619 Log(("PGMVerifyAccess: access violation for %RGv attr %#llx vs %d:%d\n", Addr, fPageGst, fWrite, fUser));
620 return VINF_EM_RAW_GUEST_TRAP;
621 }
622
623 if (!HWACCMIsNestedPagingActive(pVM))
624 {
625 /*
626 * Next step is to verify if we protected this page for dirty bit tracking or for CSAM scanning
627 */
628 rc = PGMShwGetPage(pVCpu, (RTGCPTR)Addr, NULL, NULL);
629 if ( rc == VERR_PAGE_NOT_PRESENT
630 || rc == VERR_PAGE_TABLE_NOT_PRESENT)
631 {
632 /*
633 * Page is not present in our page tables.
634 * Try to sync it!
635 */
636 Assert(X86_TRAP_PF_RW == X86_PTE_RW && X86_TRAP_PF_US == X86_PTE_US);
637 uint32_t uErr = fAccess & (X86_TRAP_PF_RW | X86_TRAP_PF_US);
638 rc = PGM_BTH_PFN(VerifyAccessSyncPage, pVCpu)(pVCpu, Addr, fPageGst, uErr);
639 if (rc != VINF_SUCCESS)
640 return rc;
641 }
642 else
643 AssertMsg(rc == VINF_SUCCESS, ("PGMShwGetPage %RGv failed with %Rrc\n", Addr, rc));
644 }
645
646#if 0 /* def VBOX_STRICT; triggers too often now */
647 /*
648 * This check is a bit paranoid, but useful.
649 */
650 /** @note this will assert when writing to monitored pages (a bit annoying actually) */
651 uint64_t fPageShw;
652 rc = PGMShwGetPage(pVCpu, (RTGCPTR)Addr, &fPageShw, NULL);
653 if ( (rc == VERR_PAGE_NOT_PRESENT || RT_FAILURE(rc))
654 || (fWrite && !(fPageShw & X86_PTE_RW))
655 || (fUser && !(fPageShw & X86_PTE_US)) )
656 {
657 AssertMsgFailed(("Unexpected access violation for %RGv! rc=%Rrc write=%d user=%d\n",
658 Addr, rc, fWrite && !(fPageShw & X86_PTE_RW), fUser && !(fPageShw & X86_PTE_US)));
659 return VINF_EM_RAW_GUEST_TRAP;
660 }
661#endif
662
663 if ( RT_SUCCESS(rc)
664 && ( PAGE_ADDRESS(Addr) != PAGE_ADDRESS(Addr + cbSize - 1)
665 || Addr + cbSize < Addr))
666 {
667 /* Don't recursively call PGMVerifyAccess as we might run out of stack. */
668 for (;;)
669 {
670 Addr += PAGE_SIZE;
671 if (cbSize > PAGE_SIZE)
672 cbSize -= PAGE_SIZE;
673 else
674 cbSize = 1;
675 rc = PGMVerifyAccess(pVCpu, Addr, 1, fAccess);
676 if (rc != VINF_SUCCESS)
677 break;
678 if (PAGE_ADDRESS(Addr) == PAGE_ADDRESS(Addr + cbSize - 1))
679 break;
680 }
681 }
682 return rc;
683}
684
685
686/**
687 * Emulation of the invlpg instruction (HC only actually).
688 *
689 * @returns VBox status code, special care required.
690 * @retval VINF_PGM_SYNC_CR3 - handled.
691 * @retval VINF_EM_RAW_EMULATE_INSTR - not handled (RC only).
692 * @retval VERR_REM_FLUSHED_PAGES_OVERFLOW - not handled.
693 *
694 * @param pVCpu VMCPU handle.
695 * @param GCPtrPage Page to invalidate.
696 *
697 * @remark ASSUMES the page table entry or page directory is valid. Fairly
698 * safe, but there could be edge cases!
699 *
700 * @todo Flush page or page directory only if necessary!
701 */
702VMMDECL(int) PGMInvalidatePage(PVMCPU pVCpu, RTGCPTR GCPtrPage)
703{
704 PVM pVM = pVCpu->CTX_SUFF(pVM);
705 int rc;
706 Log3(("PGMInvalidatePage: GCPtrPage=%RGv\n", GCPtrPage));
707
708#ifndef IN_RING3
709 /*
710 * Notify the recompiler so it can record this instruction.
711 * Failure happens when it's out of space. We'll return to HC in that case.
712 */
713 rc = REMNotifyInvalidatePage(pVM, GCPtrPage);
714 if (rc != VINF_SUCCESS)
715 return rc;
716#endif /* !IN_RING3 */
717
718
719#ifdef IN_RC
720 /*
721 * Check for conflicts and pending CR3 monitoring updates.
722 */
723 if (!pVM->pgm.s.fMappingsFixed)
724 {
725 if ( pgmGetMapping(pVM, GCPtrPage)
726 && PGMGstGetPage(pVCpu, GCPtrPage, NULL, NULL) != VERR_PAGE_TABLE_NOT_PRESENT)
727 {
728 LogFlow(("PGMGCInvalidatePage: Conflict!\n"));
729 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
730 STAM_COUNTER_INC(&pVM->pgm.s.StatRCInvlPgConflict);
731 return VINF_PGM_SYNC_CR3;
732 }
733
734 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
735 {
736 LogFlow(("PGMGCInvalidatePage: PGM_SYNC_MONITOR_CR3 -> reinterpret instruction in R3\n"));
737 STAM_COUNTER_INC(&pVM->pgm.s.StatRCInvlPgSyncMonCR3);
738 return VINF_EM_RAW_EMULATE_INSTR;
739 }
740 }
741#endif /* IN_RC */
742
743 /*
744 * Call paging mode specific worker.
745 */
746 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePage), a);
747 pgmLock(pVM);
748 rc = PGM_BTH_PFN(InvalidatePage, pVCpu)(pVCpu, GCPtrPage);
749 pgmUnlock(pVM);
750 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,InvalidatePage), a);
751
752#ifdef IN_RING3
753 /*
754 * Check if we have a pending update of the CR3 monitoring.
755 */
756 if ( RT_SUCCESS(rc)
757 && (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3))
758 {
759 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
760 Assert(!pVM->pgm.s.fMappingsFixed);
761 }
762
763 /*
764 * Inform CSAM about the flush
765 *
766 * Note: This is to check if monitored pages have been changed; when we implement
767 * callbacks for virtual handlers, this is no longer required.
768 */
769 CSAMR3FlushPage(pVM, GCPtrPage);
770#endif /* IN_RING3 */
771 return rc;
772}
773
774
775/**
776 * Executes an instruction using the interpreter.
777 *
778 * @returns VBox status code (appropriate for trap handling and GC return).
779 * @param pVM VM handle.
780 * @param pVCpu VMCPU handle.
781 * @param pRegFrame Register frame.
782 * @param pvFault Fault address.
783 */
784VMMDECL(int) PGMInterpretInstruction(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
785{
786 uint32_t cb;
787 int rc = EMInterpretInstruction(pVM, pVCpu, pRegFrame, pvFault, &cb);
788 if (rc == VERR_EM_INTERPRETER)
789 rc = VINF_EM_RAW_EMULATE_INSTR;
790 if (rc != VINF_SUCCESS)
791 Log(("PGMInterpretInstruction: returns %Rrc (pvFault=%RGv)\n", rc, pvFault));
792 return rc;
793}
794
795
796/**
797 * Gets effective page information (from the VMM page directory).
798 *
799 * @returns VBox status.
800 * @param pVCpu VMCPU handle.
801 * @param GCPtr Guest Context virtual address of the page.
802 * @param pfFlags Where to store the flags. These are X86_PTE_*.
803 * @param pHCPhys Where to store the HC physical address of the page.
804 * This is page aligned.
805 * @remark You should use PGMMapGetPage() for pages in a mapping.
806 */
807VMMDECL(int) PGMShwGetPage(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys)
808{
809 pgmLock(pVCpu->CTX_SUFF(pVM));
810 int rc = PGM_SHW_PFN(GetPage, pVCpu)(pVCpu, GCPtr, pfFlags, pHCPhys);
811 pgmUnlock(pVCpu->CTX_SUFF(pVM));
812 return rc;
813}
814
815
816/**
817 * Sets (replaces) the page flags for a range of pages in the shadow context.
818 *
819 * @returns VBox status.
820 * @param pVCpu VMCPU handle.
821 * @param GCPtr The address of the first page.
822 * @param cb The size of the range in bytes.
823 * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
824 * @remark You must use PGMMapSetPage() for pages in a mapping.
825 */
826VMMDECL(int) PGMShwSetPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags)
827{
828 return PGMShwModifyPage(pVCpu, GCPtr, cb, fFlags, 0);
829}
830
831
832/**
833 * Modify page flags for a range of pages in the shadow context.
834 *
835 * The existing flags are ANDed with the fMask and ORed with the fFlags.
836 *
837 * @returns VBox status code.
838 * @param pVCpu VMCPU handle.
839 * @param GCPtr Virtual address of the first page in the range.
840 * @param cb Size (in bytes) of the range to apply the modification to.
841 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
842 * @param fMask The AND mask - page flags X86_PTE_*.
843 * Be very CAREFUL when ~'ing constants which could be 32-bit!
844 * @remark You must use PGMMapModifyPage() for pages in a mapping.
845 */
846VMMDECL(int) PGMShwModifyPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
847{
848 AssertMsg(!(fFlags & X86_PTE_PAE_PG_MASK), ("fFlags=%#llx\n", fFlags));
849 Assert(cb);
850
851 /*
852 * Align the input.
853 */
854 cb += GCPtr & PAGE_OFFSET_MASK;
855 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
856 GCPtr = (GCPtr & PAGE_BASE_GC_MASK); /** @todo this ain't necessary, right... */
857
858 /*
859 * Call worker.
860 */
861 PVM pVM = pVCpu->CTX_SUFF(pVM);
862 pgmLock(pVM);
863 int rc = PGM_SHW_PFN(ModifyPage, pVCpu)(pVCpu, GCPtr, cb, fFlags, fMask);
864 pgmUnlock(pVM);
865 return rc;
866}
867
868/**
869 * Gets the shadow page directory for the specified address, PAE.
870 *
871 * @returns Pointer to the shadow PD.
872 * @param pVCpu The VMCPU handle.
873 * @param GCPtr The address.
874 * @param pGstPdpe Guest PDPT entry
875 * @param ppPD Receives address of page directory
876 */
877int pgmShwSyncPaePDPtr(PVMCPU pVCpu, RTGCPTR GCPtr, PX86PDPE pGstPdpe, PX86PDPAE *ppPD)
878{
879 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
880 PX86PDPT pPdpt = pgmShwGetPaePDPTPtr(&pVCpu->pgm.s);
881 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
882 PVM pVM = pVCpu->CTX_SUFF(pVM);
883 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
884 PPGMPOOLPAGE pShwPage;
885 int rc;
886
887 Assert(PGMIsLockOwner(pVM));
888
889 /* Allocate page directory if not present. */
890 if ( !pPdpe->n.u1Present
891 && !(pPdpe->u & X86_PDPE_PG_MASK))
892 {
893 bool fNestedPaging = HWACCMIsNestedPagingActive(pVM);
894 bool fPaging = !!(CPUMGetGuestCR0(pVCpu) & X86_CR0_PG);
895 RTGCPTR64 GCPdPt;
896 PGMPOOLKIND enmKind;
897
898# if defined(IN_RC)
899 /* Make sure the dynamic pPdeDst mapping will not be reused during this function. */
900 PGMDynLockHCPage(pVM, (uint8_t *)pPdpe);
901# endif
902
903 if (fNestedPaging || !fPaging)
904 {
905 /* AMD-V nested paging or real/protected mode without paging */
906 GCPdPt = (RTGCPTR64)iPdPt << X86_PDPT_SHIFT;
907 enmKind = PGMPOOLKIND_PAE_PD_PHYS;
908 }
909 else
910 {
911 Assert(pGstPdpe);
912
913 if (CPUMGetGuestCR4(pVCpu) & X86_CR4_PAE)
914 {
915 if (!pGstPdpe->n.u1Present)
916 {
917 /* PD not present; guest must reload CR3 to change it.
918 * No need to monitor anything in this case.
919 */
920 Assert(!HWACCMIsEnabled(pVM));
921
922 GCPdPt = pGstPdpe->u & X86_PDPE_PG_MASK;
923 enmKind = PGMPOOLKIND_PAE_PD_PHYS;
924 pGstPdpe->n.u1Present = 1;
925 }
926 else
927 {
928 GCPdPt = pGstPdpe->u & X86_PDPE_PG_MASK;
929 enmKind = PGMPOOLKIND_PAE_PD_FOR_PAE_PD;
930 }
931 }
932 else
933 {
934 GCPdPt = CPUMGetGuestCR3(pVCpu);
935 enmKind = (PGMPOOLKIND)(PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD + iPdPt);
936 }
937 }
938
939 /* Create a reference back to the PDPT by using the index in its shadow page. */
940 rc = pgmPoolAlloc(pVM, GCPdPt, enmKind, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iPdPt, &pShwPage);
941 AssertRCReturn(rc, rc);
942
943 /* The PD was cached or created; hook it up now. */
944 pPdpe->u |= pShwPage->Core.Key
945 | (pGstPdpe->u & ~(X86_PDPE_PG_MASK | X86_PDPE_AVL_MASK | X86_PDPE_PCD | X86_PDPE_PWT));
946
947# if defined(IN_RC)
948 /* In 32 bits PAE mode we *must* invalidate the TLB when changing a PDPT entry; the CPU fetches them only during cr3 load, so any
949 * non-present PDPT will continue to cause page faults.
950 */
951 ASMReloadCR3();
952 PGMDynUnlockHCPage(pVM, (uint8_t *)pPdpe);
953# endif
954 }
955 else
956 {
957 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
958 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
959 Assert((pPdpe->u & X86_PDPE_PG_MASK) == pShwPage->Core.Key);
960
961 pgmPoolCacheUsed(pPool, pShwPage);
962 }
963 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
964 return VINF_SUCCESS;
965}
966
967
968/**
969 * Gets the pointer to the shadow page directory entry for an address, PAE.
970 *
971 * @returns Pointer to the PDE.
972 * @param pPGM Pointer to the PGMCPU instance data.
973 * @param GCPtr The address.
974 * @param ppShwPde Receives the address of the pgm pool page for the shadow page directory
975 */
976DECLINLINE(int) pgmShwGetPaePoolPagePD(PPGMCPU pPGM, RTGCPTR GCPtr, PPGMPOOLPAGE *ppShwPde)
977{
978 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
979 PX86PDPT pPdpt = pgmShwGetPaePDPTPtr(pPGM);
980
981 Assert(PGMIsLockOwner(PGMCPU2VM(pPGM)));
982
983 AssertReturn(pPdpt, VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT); /* can't happen */
984 if (!pPdpt->a[iPdPt].n.u1Present)
985 {
986 LogFlow(("pgmShwGetPaePoolPagePD: PD %d not present (%RX64)\n", iPdPt, pPdpt->a[iPdPt].u));
987 return VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT;
988 }
989 AssertMsg(pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK, ("GCPtr=%RGv\n", GCPtr));
990
991 /* Fetch the pgm pool shadow descriptor. */
992 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(PGMCPU2PGM(pPGM)->CTX_SUFF(pPool), pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK);
993 AssertReturn(pShwPde, VERR_INTERNAL_ERROR);
994
995 *ppShwPde = pShwPde;
996 return VINF_SUCCESS;
997}
998
999#ifndef IN_RC
1000
1001/**
1002 * Syncs the SHADOW page directory pointer for the specified address.
1003 *
1004 * Allocates backing pages in case the PDPT or PML4 entry is missing.
1005 *
1006 * The caller is responsible for making sure the guest has a valid PD before
1007 * calling this function.
1008 *
1009 * @returns VBox status.
1010 * @param pVCpu VMCPU handle.
1011 * @param GCPtr The address.
1012 * @param pGstPml4e Guest PML4 entry
1013 * @param pGstPdpe Guest PDPT entry
1014 * @param ppPD Receives address of page directory
1015 */
1016int pgmShwSyncLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E pGstPml4e, PX86PDPE pGstPdpe, PX86PDPAE *ppPD)
1017{
1018 PPGMCPU pPGM = &pVCpu->pgm.s;
1019 PVM pVM = pVCpu->CTX_SUFF(pVM);
1020 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1021 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1022 PX86PML4E pPml4e = pgmShwGetLongModePML4EPtr(pPGM, iPml4);
1023 bool fNestedPaging = HWACCMIsNestedPagingActive(pVM);
1024 bool fPaging = !!(CPUMGetGuestCR0(pVCpu) & X86_CR0_PG);
1025 PPGMPOOLPAGE pShwPage;
1026 int rc;
1027
1028 Assert(PGMIsLockOwner(pVM));
1029
1030 /* Allocate page directory pointer table if not present. */
1031 if ( !pPml4e->n.u1Present
1032 && !(pPml4e->u & X86_PML4E_PG_MASK))
1033 {
1034 RTGCPTR64 GCPml4;
1035 PGMPOOLKIND enmKind;
1036
1037 Assert(pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
1038
1039 if (fNestedPaging || !fPaging)
1040 {
1041 /* AMD-V nested paging or real/protected mode without paging */
1042 GCPml4 = (RTGCPTR64)iPml4 << X86_PML4_SHIFT;
1043 enmKind = PGMPOOLKIND_64BIT_PDPT_FOR_PHYS;
1044 }
1045 else
1046 {
1047 Assert(pGstPml4e && pGstPdpe);
1048
1049 GCPml4 = pGstPml4e->u & X86_PML4E_PG_MASK;
1050 enmKind = PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT;
1051 }
1052
1053 /* Create a reference back to the PDPT by using the index in its shadow page. */
1054 rc = pgmPoolAlloc(pVM, GCPml4, enmKind, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iPml4, &pShwPage);
1055 AssertRCReturn(rc, rc);
1056 }
1057 else
1058 {
1059 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & X86_PML4E_PG_MASK);
1060 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1061
1062 pgmPoolCacheUsed(pPool, pShwPage);
1063 }
1064 /* The PDPT was cached or created; hook it up now. */
1065 pPml4e->u |= pShwPage->Core.Key
1066 | (pGstPml4e->u & ~(X86_PML4E_PG_MASK | X86_PML4E_AVL_MASK | X86_PML4E_PCD | X86_PML4E_PWT));
1067
1068 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1069 PX86PDPT pPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1070 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
1071
1072 /* Allocate page directory if not present. */
1073 if ( !pPdpe->n.u1Present
1074 && !(pPdpe->u & X86_PDPE_PG_MASK))
1075 {
1076 RTGCPTR64 GCPdPt;
1077 PGMPOOLKIND enmKind;
1078
1079 if (fNestedPaging || !fPaging)
1080 {
1081 /* AMD-V nested paging or real/protected mode without paging */
1082 GCPdPt = (RTGCPTR64)iPdPt << X86_PDPT_SHIFT;
1083 enmKind = PGMPOOLKIND_64BIT_PD_FOR_PHYS;
1084 }
1085 else
1086 {
1087 Assert(pGstPdpe);
1088
1089 GCPdPt = pGstPdpe->u & X86_PDPE_PG_MASK;
1090 enmKind = PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD;
1091 }
1092
1093 /* Create a reference back to the PDPT by using the index in its shadow page. */
1094 rc = pgmPoolAlloc(pVM, GCPdPt, enmKind, pShwPage->idx, iPdPt, &pShwPage);
1095 AssertRCReturn(rc, rc);
1096 }
1097 else
1098 {
1099 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
1100 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1101
1102 pgmPoolCacheUsed(pPool, pShwPage);
1103 }
1104 /* The PD was cached or created; hook it up now. */
1105 pPdpe->u |= pShwPage->Core.Key
1106 | (pGstPdpe->u & ~(X86_PDPE_PG_MASK | X86_PDPE_AVL_MASK | X86_PDPE_PCD | X86_PDPE_PWT));
1107
1108 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1109 return VINF_SUCCESS;
1110}
1111
1112
1113/**
1114 * Gets the SHADOW page directory pointer for the specified address (long mode).
1115 *
1116 * @returns VBox status.
1117 * @param pVCpu VMCPU handle.
1118 * @param GCPtr The address.
1119 * @param ppPdpt Receives address of pdpt
1120 * @param ppPD Receives address of page directory
1121 */
1122DECLINLINE(int) pgmShwGetLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPT *ppPdpt, PX86PDPAE *ppPD)
1123{
1124 PPGMCPU pPGM = &pVCpu->pgm.s;
1125 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1126 PCX86PML4E pPml4e = pgmShwGetLongModePML4EPtr(pPGM, iPml4);
1127
1128 Assert(PGMIsLockOwner(PGMCPU2VM(pPGM)));
1129
1130 AssertReturn(pPml4e, VERR_INTERNAL_ERROR);
1131 if (ppPml4e)
1132 *ppPml4e = (PX86PML4E)pPml4e;
1133
1134 Log4(("pgmShwGetLongModePDPtr %VGv (%VHv) %RX64\n", GCPtr, pPml4e, pPml4e->u));
1135
1136 if (!pPml4e->n.u1Present)
1137 return VERR_PAGE_MAP_LEVEL4_NOT_PRESENT;
1138
1139 PVM pVM = pVCpu->CTX_SUFF(pVM);
1140 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1141 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, pPml4e->u & X86_PML4E_PG_MASK);
1142 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1143
1144 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1145 PCX86PDPT pPdpt = *ppPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1146 if (!pPdpt->a[iPdPt].n.u1Present)
1147 return VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT;
1148
1149 pShwPage = pgmPoolGetPage(pPool, pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK);
1150 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1151
1152 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1153 return VINF_SUCCESS;
1154}
1155
1156
1157/**
1158 * Syncs the SHADOW EPT page directory pointer for the specified address. Allocates
1159 * backing pages in case the PDPT or PML4 entry is missing.
1160 *
1161 * @returns VBox status.
1162 * @param pVCpu VMCPU handle.
1163 * @param GCPtr The address.
1164 * @param ppPdpt Receives address of pdpt
1165 * @param ppPD Receives address of page directory
1166 */
1167int pgmShwGetEPTPDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PEPTPDPT *ppPdpt, PEPTPD *ppPD)
1168{
1169 PPGMCPU pPGM = &pVCpu->pgm.s;
1170 PVM pVM = pVCpu->CTX_SUFF(pVM);
1171 const unsigned iPml4 = (GCPtr >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
1172 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1173 PEPTPML4 pPml4;
1174 PEPTPML4E pPml4e;
1175 PPGMPOOLPAGE pShwPage;
1176 int rc;
1177
1178 Assert(HWACCMIsNestedPagingActive(pVM));
1179 Assert(PGMIsLockOwner(pVM));
1180
1181 pPml4 = (PEPTPML4)PGMPOOL_PAGE_2_PTR_BY_PGMCPU(pPGM, pPGM->CTX_SUFF(pShwPageCR3));
1182 Assert(pPml4);
1183
1184 /* Allocate page directory pointer table if not present. */
1185 pPml4e = &pPml4->a[iPml4];
1186 if ( !pPml4e->n.u1Present
1187 && !(pPml4e->u & EPT_PML4E_PG_MASK))
1188 {
1189 Assert(!(pPml4e->u & EPT_PML4E_PG_MASK));
1190 RTGCPTR64 GCPml4 = (RTGCPTR64)iPml4 << EPT_PML4_SHIFT;
1191
1192 rc = pgmPoolAlloc(pVM, GCPml4, PGMPOOLKIND_EPT_PDPT_FOR_PHYS, PGMPOOL_IDX_NESTED_ROOT, iPml4, &pShwPage);
1193 AssertRCReturn(rc, rc);
1194 }
1195 else
1196 {
1197 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & EPT_PML4E_PG_MASK);
1198 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1199
1200 pgmPoolCacheUsed(pPool, pShwPage);
1201 }
1202 /* The PDPT was cached or created; hook it up now and fill with the default value. */
1203 pPml4e->u = pShwPage->Core.Key;
1204 pPml4e->n.u1Present = 1;
1205 pPml4e->n.u1Write = 1;
1206 pPml4e->n.u1Execute = 1;
1207
1208 const unsigned iPdPt = (GCPtr >> EPT_PDPT_SHIFT) & EPT_PDPT_MASK;
1209 PEPTPDPT pPdpt = (PEPTPDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1210 PEPTPDPTE pPdpe = &pPdpt->a[iPdPt];
1211
1212 if (ppPdpt)
1213 *ppPdpt = pPdpt;
1214
1215 /* Allocate page directory if not present. */
1216 if ( !pPdpe->n.u1Present
1217 && !(pPdpe->u & EPT_PDPTE_PG_MASK))
1218 {
1219 RTGCPTR64 GCPdPt = (RTGCPTR64)iPdPt << EPT_PDPT_SHIFT;
1220
1221 rc = pgmPoolAlloc(pVM, GCPdPt, PGMPOOLKIND_64BIT_PD_FOR_PHYS, pShwPage->idx, iPdPt, &pShwPage);
1222 AssertRCReturn(rc, rc);
1223 }
1224 else
1225 {
1226 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & EPT_PDPTE_PG_MASK);
1227 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1228
1229 pgmPoolCacheUsed(pPool, pShwPage);
1230 }
1231 /* The PD was cached or created; hook it up now and fill with the default value. */
1232 pPdpe->u = pShwPage->Core.Key;
1233 pPdpe->n.u1Present = 1;
1234 pPdpe->n.u1Write = 1;
1235 pPdpe->n.u1Execute = 1;
1236
1237 *ppPD = (PEPTPD)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1238 return VINF_SUCCESS;
1239}
1240
1241#endif /* IN_RC */
1242
1243/**
1244 * Gets effective Guest OS page information.
1245 *
1246 * When GCPtr is in a big page, the function will return as if it was a normal
1247 * 4KB page. If the need for distinguishing between big and normal page becomes
1248 * necessary at a later point, a PGMGstGetPage() will be created for that
1249 * purpose.
1250 *
1251 * @returns VBox status.
1252 * @param pVCpu VMCPU handle.
1253 * @param GCPtr Guest Context virtual address of the page.
1254 * @param pfFlags Where to store the flags. These are X86_PTE_*, even for big pages.
1255 * @param pGCPhys Where to store the GC physical address of the page.
1256 * This is page aligned. The fact that the
1257 */
1258VMMDECL(int) PGMGstGetPage(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys)
1259{
1260 return PGM_GST_PFN(GetPage, pVCpu)(pVCpu, GCPtr, pfFlags, pGCPhys);
1261}
1262
1263
1264/**
1265 * Checks if the page is present.
1266 *
1267 * @returns true if the page is present.
1268 * @returns false if the page is not present.
1269 * @param pVCpu VMCPU handle.
1270 * @param GCPtr Address within the page.
1271 */
1272VMMDECL(bool) PGMGstIsPagePresent(PVMCPU pVCpu, RTGCPTR GCPtr)
1273{
1274 int rc = PGMGstGetPage(pVCpu, GCPtr, NULL, NULL);
1275 return RT_SUCCESS(rc);
1276}
1277
1278
1279/**
1280 * Sets (replaces) the page flags for a range of pages in the guest's tables.
1281 *
1282 * @returns VBox status.
1283 * @param pVCpu VMCPU handle.
1284 * @param GCPtr The address of the first page.
1285 * @param cb The size of the range in bytes.
1286 * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
1287 */
1288VMMDECL(int) PGMGstSetPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags)
1289{
1290 return PGMGstModifyPage(pVCpu, GCPtr, cb, fFlags, 0);
1291}
1292
1293
1294/**
1295 * Modify page flags for a range of pages in the guest's tables
1296 *
1297 * The existing flags are ANDed with the fMask and ORed with the fFlags.
1298 *
1299 * @returns VBox status code.
1300 * @param pVCpu VMCPU handle.
1301 * @param GCPtr Virtual address of the first page in the range.
1302 * @param cb Size (in bytes) of the range to apply the modification to.
1303 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
1304 * @param fMask The AND mask - page flags X86_PTE_*, excluding the page mask of course.
1305 * Be very CAREFUL when ~'ing constants which could be 32-bit!
1306 */
1307VMMDECL(int) PGMGstModifyPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
1308{
1309 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,GstModifyPage), a);
1310
1311 /*
1312 * Validate input.
1313 */
1314 AssertMsg(!(fFlags & X86_PTE_PAE_PG_MASK), ("fFlags=%#llx\n", fFlags));
1315 Assert(cb);
1316
1317 LogFlow(("PGMGstModifyPage %RGv %d bytes fFlags=%08llx fMask=%08llx\n", GCPtr, cb, fFlags, fMask));
1318
1319 /*
1320 * Adjust input.
1321 */
1322 cb += GCPtr & PAGE_OFFSET_MASK;
1323 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
1324 GCPtr = (GCPtr & PAGE_BASE_GC_MASK);
1325
1326 /*
1327 * Call worker.
1328 */
1329 int rc = PGM_GST_PFN(ModifyPage, pVCpu)(pVCpu, GCPtr, cb, fFlags, fMask);
1330
1331 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,GstModifyPage), a);
1332 return rc;
1333}
1334
1335#ifdef IN_RING3
1336
1337/**
1338 * Performs the lazy mapping of the 32-bit guest PD.
1339 *
1340 * @returns Pointer to the mapping.
1341 * @param pPGM The PGM instance data.
1342 */
1343PX86PD pgmGstLazyMap32BitPD(PPGMCPU pPGM)
1344{
1345 Assert(!pPGM->CTX_SUFF(pGst32BitPd));
1346 PVM pVM = PGMCPU2VM(pPGM);
1347 pgmLock(pVM);
1348
1349 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, pPGM->GCPhysCR3);
1350 AssertReturn(pPage, NULL);
1351
1352 RTHCPTR HCPtrGuestCR3;
1353 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_PAGE_MASK, (void **)&HCPtrGuestCR3);
1354 AssertRCReturn(rc, NULL);
1355
1356 pPGM->pGst32BitPdR3 = (R3PTRTYPE(PX86PD))HCPtrGuestCR3;
1357# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1358 pPGM->pGst32BitPdR0 = (R0PTRTYPE(PX86PD))HCPtrGuestCR3;
1359# endif
1360
1361 pgmUnlock(pVM);
1362 return pPGM->CTX_SUFF(pGst32BitPd);
1363}
1364
1365
1366/**
1367 * Performs the lazy mapping of the PAE guest PDPT.
1368 *
1369 * @returns Pointer to the mapping.
1370 * @param pPGM The PGM instance data.
1371 */
1372PX86PDPT pgmGstLazyMapPaePDPT(PPGMCPU pPGM)
1373{
1374 Assert(!pPGM->CTX_SUFF(pGstPaePdpt));
1375 PVM pVM = PGMCPU2VM(pPGM);
1376 pgmLock(pVM);
1377
1378 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, pPGM->GCPhysCR3);
1379 AssertReturn(pPage, NULL);
1380
1381 RTHCPTR HCPtrGuestCR3;
1382 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_PAE_PAGE_MASK, (void **)&HCPtrGuestCR3); /** @todo r=bird: This GCPhysR3 masking isn't necessary. */
1383 AssertRCReturn(rc, NULL);
1384
1385 pPGM->pGstPaePdptR3 = (R3PTRTYPE(PX86PDPT))HCPtrGuestCR3;
1386# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1387 pPGM->pGstPaePdptR0 = (R0PTRTYPE(PX86PDPT))HCPtrGuestCR3;
1388# endif
1389
1390 pgmUnlock(pVM);
1391 return pPGM->CTX_SUFF(pGstPaePdpt);
1392}
1393
1394#endif /* IN_RING3 */
1395
1396#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
1397/**
1398 * Performs the lazy mapping / updating of a PAE guest PD.
1399 *
1400 * @returns Pointer to the mapping.
1401 * @param pPGM The PGM instance data.
1402 * @param iPdpt Which PD entry to map (0..3).
1403 */
1404PX86PDPAE pgmGstLazyMapPaePD(PPGMCPU pPGM, uint32_t iPdpt)
1405{
1406 PVM pVM = PGMCPU2VM(pPGM);
1407 pgmLock(pVM);
1408
1409 PX86PDPT pGuestPDPT = pPGM->CTX_SUFF(pGstPaePdpt);
1410 Assert(pGuestPDPT);
1411 Assert(pGuestPDPT->a[iPdpt].n.u1Present);
1412 RTGCPHYS GCPhys = pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK;
1413 bool const fChanged = pPGM->aGCPhysGstPaePDs[iPdpt] != GCPhys;
1414
1415 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
1416 if (RT_LIKELY(pPage))
1417 {
1418 int rc = VINF_SUCCESS;
1419 RTRCPTR RCPtr = NIL_RTRCPTR;
1420 RTHCPTR HCPtr = NIL_RTHCPTR;
1421#if !defined(IN_RC) && !defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
1422 rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &HCPtr);
1423 AssertRC(rc);
1424#endif
1425 if (RT_SUCCESS(rc) && fChanged)
1426 {
1427 RCPtr = (RTRCPTR)(RTRCUINTPTR)(pVM->pgm.s.GCPtrCR3Mapping + (1 + iPdpt) * PAGE_SIZE);
1428 rc = PGMMap(pVM, (RTRCUINTPTR)RCPtr, PGM_PAGE_GET_HCPHYS(pPage), PAGE_SIZE, 0);
1429 }
1430 if (RT_SUCCESS(rc))
1431 {
1432 pPGM->apGstPaePDsR3[iPdpt] = (R3PTRTYPE(PX86PDPAE))HCPtr;
1433# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1434 pPGM->apGstPaePDsR0[iPdpt] = (R0PTRTYPE(PX86PDPAE))HCPtr;
1435# endif
1436 if (fChanged)
1437 {
1438 pPGM->aGCPhysGstPaePDs[iPdpt] = GCPhys;
1439 pPGM->apGstPaePDsRC[iPdpt] = (RCPTRTYPE(PX86PDPAE))RCPtr;
1440 }
1441
1442 pgmUnlock(pVM);
1443 return pPGM->CTX_SUFF(apGstPaePDs)[iPdpt];
1444 }
1445 }
1446
1447 /* Invalid page or some failure, invalidate the entry. */
1448 pPGM->aGCPhysGstPaePDs[iPdpt] = NIL_RTGCPHYS;
1449 pPGM->apGstPaePDsR3[iPdpt] = 0;
1450# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1451 pPGM->apGstPaePDsR0[iPdpt] = 0;
1452# endif
1453 pPGM->apGstPaePDsRC[iPdpt] = 0;
1454
1455 pgmUnlock(pVM);
1456 return NULL;
1457}
1458#endif /* !VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
1459
1460
1461#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R3
1462/**
1463 * Performs the lazy mapping of the 32-bit guest PD.
1464 *
1465 * @returns Pointer to the mapping.
1466 * @param pPGM The PGM instance data.
1467 */
1468PX86PML4 pgmGstLazyMapPml4(PPGMCPU pPGM)
1469{
1470 Assert(!pPGM->CTX_SUFF(pGstAmd64Pml4));
1471 PVM pVM = PGMCPU2VM(pPGM);
1472 pgmLock(pVM);
1473
1474 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, pPGM->GCPhysCR3);
1475 AssertReturn(pPage, NULL);
1476
1477 RTHCPTR HCPtrGuestCR3;
1478 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_AMD64_PAGE_MASK, (void **)&HCPtrGuestCR3); /** @todo r=bird: This GCPhysCR3 masking isn't necessary. */
1479 AssertRCReturn(rc, NULL);
1480
1481 pPGM->pGstAmd64Pml4R3 = (R3PTRTYPE(PX86PML4))HCPtrGuestCR3;
1482# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1483 pPGM->pGstAmd64Pml4R0 = (R0PTRTYPE(PX86PML4))HCPtrGuestCR3;
1484# endif
1485
1486 pgmUnlock(pVM);
1487 return pPGM->CTX_SUFF(pGstAmd64Pml4);
1488}
1489#endif /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R3 */
1490
1491
1492/**
1493 * Gets the specified page directory pointer table entry.
1494 *
1495 * @returns PDP entry
1496 * @param pVCpu VMCPU handle.
1497 * @param iPdpt PDPT index
1498 */
1499VMMDECL(X86PDPE) PGMGstGetPaePDPtr(PVMCPU pVCpu, unsigned iPdpt)
1500{
1501 Assert(iPdpt <= 3);
1502 return pgmGstGetPaePDPTPtr(&pVCpu->pgm.s)->a[iPdpt & 3];
1503}
1504
1505
1506/**
1507 * Gets the current CR3 register value for the shadow memory context.
1508 * @returns CR3 value.
1509 * @param pVCpu VMCPU handle.
1510 */
1511VMMDECL(RTHCPHYS) PGMGetHyperCR3(PVMCPU pVCpu)
1512{
1513 PPGMPOOLPAGE pPoolPage = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
1514 AssertPtrReturn(pPoolPage, 0);
1515 return pPoolPage->Core.Key;
1516}
1517
1518
1519/**
1520 * Gets the current CR3 register value for the nested memory context.
1521 * @returns CR3 value.
1522 * @param pVCpu VMCPU handle.
1523 */
1524VMMDECL(RTHCPHYS) PGMGetNestedCR3(PVMCPU pVCpu, PGMMODE enmShadowMode)
1525{
1526 Assert(pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
1527 return pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->Core.Key;
1528}
1529
1530
1531/**
1532 * Gets the current CR3 register value for the HC intermediate memory context.
1533 * @returns CR3 value.
1534 * @param pVM The VM handle.
1535 */
1536VMMDECL(RTHCPHYS) PGMGetInterHCCR3(PVM pVM)
1537{
1538 switch (pVM->pgm.s.enmHostMode)
1539 {
1540 case SUPPAGINGMODE_32_BIT:
1541 case SUPPAGINGMODE_32_BIT_GLOBAL:
1542 return pVM->pgm.s.HCPhysInterPD;
1543
1544 case SUPPAGINGMODE_PAE:
1545 case SUPPAGINGMODE_PAE_GLOBAL:
1546 case SUPPAGINGMODE_PAE_NX:
1547 case SUPPAGINGMODE_PAE_GLOBAL_NX:
1548 return pVM->pgm.s.HCPhysInterPaePDPT;
1549
1550 case SUPPAGINGMODE_AMD64:
1551 case SUPPAGINGMODE_AMD64_GLOBAL:
1552 case SUPPAGINGMODE_AMD64_NX:
1553 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
1554 return pVM->pgm.s.HCPhysInterPaePDPT;
1555
1556 default:
1557 AssertMsgFailed(("enmHostMode=%d\n", pVM->pgm.s.enmHostMode));
1558 return ~0;
1559 }
1560}
1561
1562
1563/**
1564 * Gets the current CR3 register value for the RC intermediate memory context.
1565 * @returns CR3 value.
1566 * @param pVM The VM handle.
1567 * @param pVCpu VMCPU handle.
1568 */
1569VMMDECL(RTHCPHYS) PGMGetInterRCCR3(PVM pVM, PVMCPU pVCpu)
1570{
1571 switch (pVCpu->pgm.s.enmShadowMode)
1572 {
1573 case PGMMODE_32_BIT:
1574 return pVM->pgm.s.HCPhysInterPD;
1575
1576 case PGMMODE_PAE:
1577 case PGMMODE_PAE_NX:
1578 return pVM->pgm.s.HCPhysInterPaePDPT;
1579
1580 case PGMMODE_AMD64:
1581 case PGMMODE_AMD64_NX:
1582 return pVM->pgm.s.HCPhysInterPaePML4;
1583
1584 case PGMMODE_EPT:
1585 case PGMMODE_NESTED:
1586 return 0; /* not relevant */
1587
1588 default:
1589 AssertMsgFailed(("enmShadowMode=%d\n", pVCpu->pgm.s.enmShadowMode));
1590 return ~0;
1591 }
1592}
1593
1594
1595/**
1596 * Gets the CR3 register value for the 32-Bit intermediate memory context.
1597 * @returns CR3 value.
1598 * @param pVM The VM handle.
1599 */
1600VMMDECL(RTHCPHYS) PGMGetInter32BitCR3(PVM pVM)
1601{
1602 return pVM->pgm.s.HCPhysInterPD;
1603}
1604
1605
1606/**
1607 * Gets the CR3 register value for the PAE intermediate memory context.
1608 * @returns CR3 value.
1609 * @param pVM The VM handle.
1610 */
1611VMMDECL(RTHCPHYS) PGMGetInterPaeCR3(PVM pVM)
1612{
1613 return pVM->pgm.s.HCPhysInterPaePDPT;
1614}
1615
1616
1617/**
1618 * Gets the CR3 register value for the AMD64 intermediate memory context.
1619 * @returns CR3 value.
1620 * @param pVM The VM handle.
1621 */
1622VMMDECL(RTHCPHYS) PGMGetInterAmd64CR3(PVM pVM)
1623{
1624 return pVM->pgm.s.HCPhysInterPaePML4;
1625}
1626
1627
1628/**
1629 * Performs and schedules necessary updates following a CR3 load or reload.
1630 *
1631 * This will normally involve mapping the guest PD or nPDPT
1632 *
1633 * @returns VBox status code.
1634 * @retval VINF_PGM_SYNC_CR3 if monitoring requires a CR3 sync. This can
1635 * safely be ignored and overridden since the FF will be set too then.
1636 * @param pVCpu VMCPU handle.
1637 * @param cr3 The new cr3.
1638 * @param fGlobal Indicates whether this is a global flush or not.
1639 */
1640VMMDECL(int) PGMFlushTLB(PVMCPU pVCpu, uint64_t cr3, bool fGlobal)
1641{
1642 PVM pVM = pVCpu->CTX_SUFF(pVM);
1643
1644 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,FlushTLB), a);
1645
1646 /*
1647 * Always flag the necessary updates; necessary for hardware acceleration
1648 */
1649 /** @todo optimize this, it shouldn't always be necessary. */
1650 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
1651 if (fGlobal)
1652 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
1653 LogFlow(("PGMFlushTLB: cr3=%RX64 OldCr3=%RX64 fGlobal=%d\n", cr3, pVCpu->pgm.s.GCPhysCR3, fGlobal));
1654
1655 /*
1656 * Remap the CR3 content and adjust the monitoring if CR3 was actually changed.
1657 */
1658 int rc = VINF_SUCCESS;
1659 RTGCPHYS GCPhysCR3;
1660 switch (pVCpu->pgm.s.enmGuestMode)
1661 {
1662 case PGMMODE_PAE:
1663 case PGMMODE_PAE_NX:
1664 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
1665 break;
1666 case PGMMODE_AMD64:
1667 case PGMMODE_AMD64_NX:
1668 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
1669 break;
1670 default:
1671 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
1672 break;
1673 }
1674
1675 if (pVCpu->pgm.s.GCPhysCR3 != GCPhysCR3)
1676 {
1677 RTGCPHYS GCPhysOldCR3 = pVCpu->pgm.s.GCPhysCR3;
1678 pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3;
1679 rc = PGM_BTH_PFN(MapCR3, pVCpu)(pVCpu, GCPhysCR3);
1680 if (RT_LIKELY(rc == VINF_SUCCESS))
1681 {
1682 if (!pVM->pgm.s.fMappingsFixed)
1683 {
1684 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1685 }
1686 }
1687 else
1688 {
1689 AssertMsg(rc == VINF_PGM_SYNC_CR3, ("%Rrc\n", rc));
1690 Assert(VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_PGM_SYNC_CR3));
1691 pVCpu->pgm.s.GCPhysCR3 = GCPhysOldCR3;
1692 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_MAP_CR3;
1693 if (!pVM->pgm.s.fMappingsFixed)
1694 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_MONITOR_CR3;
1695 }
1696
1697 if (fGlobal)
1698 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,FlushTLBNewCR3Global));
1699 else
1700 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,FlushTLBNewCR3));
1701 }
1702 else
1703 {
1704# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
1705 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1706 if (pPool->cDirtyPages)
1707 {
1708 pgmLock(pVM);
1709 pgmPoolResetDirtyPages(pVM);
1710 pgmUnlock(pVM);
1711 }
1712# endif
1713 /*
1714 * Check if we have a pending update of the CR3 monitoring.
1715 */
1716 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
1717 {
1718 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1719 Assert(!pVM->pgm.s.fMappingsFixed);
1720 }
1721 if (fGlobal)
1722 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,FlushTLBSameCR3Global));
1723 else
1724 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_MID_Z(Stat,FlushTLBSameCR3));
1725 }
1726
1727 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,FlushTLB), a);
1728 return rc;
1729}
1730
1731
1732/**
1733 * Performs and schedules necessary updates following a CR3 load or reload when
1734 * using nested or extended paging.
1735 *
1736 * This API is an alterantive to PDMFlushTLB that avoids actually flushing the
1737 * TLB and triggering a SyncCR3.
1738 *
1739 * This will normally involve mapping the guest PD or nPDPT
1740 *
1741 * @returns VBox status code.
1742 * @retval VINF_SUCCESS.
1743 * @retval (If applied when not in nested mode: VINF_PGM_SYNC_CR3 if monitoring
1744 * requires a CR3 sync. This can safely be ignored and overridden since
1745 * the FF will be set too then.)
1746 * @param pVCpu VMCPU handle.
1747 * @param cr3 The new cr3.
1748 */
1749VMMDECL(int) PGMUpdateCR3(PVMCPU pVCpu, uint64_t cr3)
1750{
1751 PVM pVM = pVCpu->CTX_SUFF(pVM);
1752
1753 LogFlow(("PGMUpdateCR3: cr3=%RX64 OldCr3=%RX64\n", cr3, pVCpu->pgm.s.GCPhysCR3));
1754
1755 /* We assume we're only called in nested paging mode. */
1756 Assert(pVM->pgm.s.fMappingsFixed);
1757 Assert(!(pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3));
1758 Assert(HWACCMIsNestedPagingActive(pVM) || pVCpu->pgm.s.enmShadowMode == PGMMODE_EPT);
1759
1760 /*
1761 * Remap the CR3 content and adjust the monitoring if CR3 was actually changed.
1762 */
1763 int rc = VINF_SUCCESS;
1764 RTGCPHYS GCPhysCR3;
1765 switch (pVCpu->pgm.s.enmGuestMode)
1766 {
1767 case PGMMODE_PAE:
1768 case PGMMODE_PAE_NX:
1769 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
1770 break;
1771 case PGMMODE_AMD64:
1772 case PGMMODE_AMD64_NX:
1773 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
1774 break;
1775 default:
1776 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
1777 break;
1778 }
1779 if (pVCpu->pgm.s.GCPhysCR3 != GCPhysCR3)
1780 {
1781 pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3;
1782 rc = PGM_BTH_PFN(MapCR3, pVCpu)(pVCpu, GCPhysCR3);
1783 AssertRCSuccess(rc); /* Assumes VINF_PGM_SYNC_CR3 doesn't apply to nested paging. */ /** @todo this isn't true for the mac, but we need hw to test/fix this. */
1784 }
1785 return rc;
1786}
1787
1788
1789/**
1790 * Synchronize the paging structures.
1791 *
1792 * This function is called in response to the VM_FF_PGM_SYNC_CR3 and
1793 * VM_FF_PGM_SYNC_CR3_NONGLOBAL. Those two force action flags are set
1794 * in several places, most importantly whenever the CR3 is loaded.
1795 *
1796 * @returns VBox status code.
1797 * @param pVCpu VMCPU handle.
1798 * @param cr0 Guest context CR0 register
1799 * @param cr3 Guest context CR3 register
1800 * @param cr4 Guest context CR4 register
1801 * @param fGlobal Including global page directories or not
1802 */
1803VMMDECL(int) PGMSyncCR3(PVMCPU pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal)
1804{
1805 PVM pVM = pVCpu->CTX_SUFF(pVM);
1806 int rc;
1807
1808#ifdef PGMPOOL_WITH_MONITORING
1809 /*
1810 * The pool may have pending stuff and even require a return to ring-3 to
1811 * clear the whole thing.
1812 */
1813 rc = pgmPoolSyncCR3(pVCpu);
1814 if (rc != VINF_SUCCESS)
1815 return rc;
1816#endif
1817
1818 /*
1819 * We might be called when we shouldn't.
1820 *
1821 * The mode switching will ensure that the PD is resynced
1822 * after every mode switch. So, if we find ourselves here
1823 * when in protected or real mode we can safely disable the
1824 * FF and return immediately.
1825 */
1826 if (pVCpu->pgm.s.enmGuestMode <= PGMMODE_PROTECTED)
1827 {
1828 Assert((cr0 & (X86_CR0_PG | X86_CR0_PE)) != (X86_CR0_PG | X86_CR0_PE));
1829 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
1830 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
1831 return VINF_SUCCESS;
1832 }
1833
1834 /* If global pages are not supported, then all flushes are global. */
1835 if (!(cr4 & X86_CR4_PGE))
1836 fGlobal = true;
1837 LogFlow(("PGMSyncCR3: cr0=%RX64 cr3=%RX64 cr4=%RX64 fGlobal=%d[%d,%d]\n", cr0, cr3, cr4, fGlobal,
1838 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3), VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL)));
1839
1840 /*
1841 * Check if we need to finish an aborted MapCR3 call (see PGMFlushTLB).
1842 * This should be done before SyncCR3.
1843 */
1844 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MAP_CR3)
1845 {
1846 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MAP_CR3;
1847
1848 RTGCPHYS GCPhysCR3Old = pVCpu->pgm.s.GCPhysCR3;
1849 RTGCPHYS GCPhysCR3;
1850 switch (pVCpu->pgm.s.enmGuestMode)
1851 {
1852 case PGMMODE_PAE:
1853 case PGMMODE_PAE_NX:
1854 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
1855 break;
1856 case PGMMODE_AMD64:
1857 case PGMMODE_AMD64_NX:
1858 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
1859 break;
1860 default:
1861 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
1862 break;
1863 }
1864
1865 if (pVCpu->pgm.s.GCPhysCR3 != GCPhysCR3)
1866 {
1867 pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3;
1868 rc = PGM_BTH_PFN(MapCR3, pVCpu)(pVCpu, GCPhysCR3);
1869 }
1870#ifdef IN_RING3
1871 if (rc == VINF_PGM_SYNC_CR3)
1872 rc = pgmPoolSyncCR3(pVCpu);
1873#else
1874 if (rc == VINF_PGM_SYNC_CR3)
1875 {
1876 pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3Old;
1877 return rc;
1878 }
1879#endif
1880 AssertRCReturn(rc, rc);
1881 AssertRCSuccessReturn(rc, VERR_INTERNAL_ERROR);
1882 }
1883
1884 /*
1885 * Let the 'Bth' function do the work and we'll just keep track of the flags.
1886 */
1887 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
1888 rc = PGM_BTH_PFN(SyncCR3, pVCpu)(pVCpu, cr0, cr3, cr4, fGlobal);
1889 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
1890 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 || RT_FAILURE(rc), ("rc=%Rrc\n", rc));
1891 if (rc == VINF_SUCCESS)
1892 {
1893 if (!(pVCpu->pgm.s.fSyncFlags & PGM_SYNC_ALWAYS))
1894 {
1895 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
1896 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
1897 }
1898
1899 /*
1900 * Check if we have a pending update of the CR3 monitoring.
1901 */
1902 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
1903 {
1904 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1905 Assert(!pVM->pgm.s.fMappingsFixed);
1906 }
1907 }
1908
1909 /*
1910 * Now flush the CR3 (guest context).
1911 */
1912 if (rc == VINF_SUCCESS)
1913 PGM_INVL_VCPU_TLBS(pVCpu);
1914 return rc;
1915}
1916
1917
1918/**
1919 * Called whenever CR0 or CR4 in a way which may change
1920 * the paging mode.
1921 *
1922 * @returns VBox status code, with the following informational code for
1923 * VM scheduling.
1924 * @retval VINF_SUCCESS if the was no change, or it was successfully dealt with.
1925 * @retval VINF_PGM_CHANGE_MODE if we're in RC or R0 and the mode changes.
1926 * (I.e. not in R3.)
1927 * @retval VINF_EM_SUSPEND or VINF_EM_OFF on a fatal runtime error. (R3 only)
1928 *
1929 * @param pVCpu VMCPU handle.
1930 * @param cr0 The new cr0.
1931 * @param cr4 The new cr4.
1932 * @param efer The new extended feature enable register.
1933 */
1934VMMDECL(int) PGMChangeMode(PVMCPU pVCpu, uint64_t cr0, uint64_t cr4, uint64_t efer)
1935{
1936 PVM pVM = pVCpu->CTX_SUFF(pVM);
1937 PGMMODE enmGuestMode;
1938
1939 /*
1940 * Calc the new guest mode.
1941 */
1942 if (!(cr0 & X86_CR0_PE))
1943 enmGuestMode = PGMMODE_REAL;
1944 else if (!(cr0 & X86_CR0_PG))
1945 enmGuestMode = PGMMODE_PROTECTED;
1946 else if (!(cr4 & X86_CR4_PAE))
1947 enmGuestMode = PGMMODE_32_BIT;
1948 else if (!(efer & MSR_K6_EFER_LME))
1949 {
1950 if (!(efer & MSR_K6_EFER_NXE))
1951 enmGuestMode = PGMMODE_PAE;
1952 else
1953 enmGuestMode = PGMMODE_PAE_NX;
1954 }
1955 else
1956 {
1957 if (!(efer & MSR_K6_EFER_NXE))
1958 enmGuestMode = PGMMODE_AMD64;
1959 else
1960 enmGuestMode = PGMMODE_AMD64_NX;
1961 }
1962
1963 /*
1964 * Did it change?
1965 */
1966 if (pVCpu->pgm.s.enmGuestMode == enmGuestMode)
1967 return VINF_SUCCESS;
1968
1969 /* Flush the TLB */
1970 PGM_INVL_VCPU_TLBS(pVCpu);
1971
1972#ifdef IN_RING3
1973 return PGMR3ChangeMode(pVM, pVCpu, enmGuestMode);
1974#else
1975 LogFlow(("PGMChangeMode: returns VINF_PGM_CHANGE_MODE.\n"));
1976 return VINF_PGM_CHANGE_MODE;
1977#endif
1978}
1979
1980
1981/**
1982 * Gets the current guest paging mode.
1983 *
1984 * If you just need the CPU mode (real/protected/long), use CPUMGetGuestMode().
1985 *
1986 * @returns The current paging mode.
1987 * @param pVCpu VMCPU handle.
1988 */
1989VMMDECL(PGMMODE) PGMGetGuestMode(PVMCPU pVCpu)
1990{
1991 return pVCpu->pgm.s.enmGuestMode;
1992}
1993
1994
1995/**
1996 * Gets the current shadow paging mode.
1997 *
1998 * @returns The current paging mode.
1999 * @param pVCpu VMCPU handle.
2000 */
2001VMMDECL(PGMMODE) PGMGetShadowMode(PVMCPU pVCpu)
2002{
2003 return pVCpu->pgm.s.enmShadowMode;
2004}
2005
2006/**
2007 * Gets the current host paging mode.
2008 *
2009 * @returns The current paging mode.
2010 * @param pVM The VM handle.
2011 */
2012VMMDECL(PGMMODE) PGMGetHostMode(PVM pVM)
2013{
2014 switch (pVM->pgm.s.enmHostMode)
2015 {
2016 case SUPPAGINGMODE_32_BIT:
2017 case SUPPAGINGMODE_32_BIT_GLOBAL:
2018 return PGMMODE_32_BIT;
2019
2020 case SUPPAGINGMODE_PAE:
2021 case SUPPAGINGMODE_PAE_GLOBAL:
2022 return PGMMODE_PAE;
2023
2024 case SUPPAGINGMODE_PAE_NX:
2025 case SUPPAGINGMODE_PAE_GLOBAL_NX:
2026 return PGMMODE_PAE_NX;
2027
2028 case SUPPAGINGMODE_AMD64:
2029 case SUPPAGINGMODE_AMD64_GLOBAL:
2030 return PGMMODE_AMD64;
2031
2032 case SUPPAGINGMODE_AMD64_NX:
2033 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
2034 return PGMMODE_AMD64_NX;
2035
2036 default: AssertMsgFailed(("enmHostMode=%d\n", pVM->pgm.s.enmHostMode)); break;
2037 }
2038
2039 return PGMMODE_INVALID;
2040}
2041
2042
2043/**
2044 * Get mode name.
2045 *
2046 * @returns read-only name string.
2047 * @param enmMode The mode which name is desired.
2048 */
2049VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode)
2050{
2051 switch (enmMode)
2052 {
2053 case PGMMODE_REAL: return "Real";
2054 case PGMMODE_PROTECTED: return "Protected";
2055 case PGMMODE_32_BIT: return "32-bit";
2056 case PGMMODE_PAE: return "PAE";
2057 case PGMMODE_PAE_NX: return "PAE+NX";
2058 case PGMMODE_AMD64: return "AMD64";
2059 case PGMMODE_AMD64_NX: return "AMD64+NX";
2060 case PGMMODE_NESTED: return "Nested";
2061 case PGMMODE_EPT: return "EPT";
2062 default: return "unknown mode value";
2063 }
2064}
2065
2066
2067/**
2068 * Check if the PGM lock is currently taken.
2069 *
2070 * @returns bool locked/not locked
2071 * @param pVM The VM to operate on.
2072 */
2073VMMDECL(bool) PGMIsLocked(PVM pVM)
2074{
2075 return PDMCritSectIsOwned(&pVM->pgm.s.CritSect);
2076}
2077
2078
2079/**
2080 * Check if this VCPU currently owns the PGM lock.
2081 *
2082 * @returns bool owner/not owner
2083 * @param pVM The VM to operate on.
2084 */
2085VMMDECL(bool) PGMIsLockOwner(PVM pVM)
2086{
2087 return PDMCritSectIsOwner(&pVM->pgm.s.CritSect);
2088}
2089
2090
2091/**
2092 * Acquire the PGM lock.
2093 *
2094 * @returns VBox status code
2095 * @param pVM The VM to operate on.
2096 */
2097int pgmLock(PVM pVM)
2098{
2099 int rc = PDMCritSectEnter(&pVM->pgm.s.CritSect, VERR_SEM_BUSY);
2100#if defined(IN_RC) || defined(IN_RING0)
2101 if (rc == VERR_SEM_BUSY)
2102 rc = VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_PGM_LOCK, 0);
2103#endif
2104 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
2105 return rc;
2106}
2107
2108
2109/**
2110 * Release the PGM lock.
2111 *
2112 * @returns VBox status code
2113 * @param pVM The VM to operate on.
2114 */
2115void pgmUnlock(PVM pVM)
2116{
2117 PDMCritSectLeave(&pVM->pgm.s.CritSect);
2118}
2119
2120#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
2121
2122/**
2123 * Temporarily maps one guest page specified by GC physical address.
2124 * These pages must have a physical mapping in HC, i.e. they cannot be MMIO pages.
2125 *
2126 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
2127 * reused after 8 mappings (or perhaps a few more if you score with the cache).
2128 *
2129 * @returns VBox status.
2130 * @param pVM VM handle.
2131 * @param GCPhys GC Physical address of the page.
2132 * @param ppv Where to store the address of the mapping.
2133 */
2134VMMDECL(int) PGMDynMapGCPage(PVM pVM, RTGCPHYS GCPhys, void **ppv)
2135{
2136 AssertMsg(!(GCPhys & PAGE_OFFSET_MASK), ("GCPhys=%RGp\n", GCPhys));
2137
2138 /*
2139 * Get the ram range.
2140 */
2141 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
2142 while (pRam && GCPhys - pRam->GCPhys >= pRam->cb)
2143 pRam = pRam->CTX_SUFF(pNext);
2144 if (!pRam)
2145 {
2146 AssertMsgFailed(("Invalid physical address %RGp!\n", GCPhys));
2147 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
2148 }
2149
2150 /*
2151 * Pass it on to PGMDynMapHCPage.
2152 */
2153 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT]);
2154 //Log(("PGMDynMapGCPage: GCPhys=%RGp HCPhys=%RHp\n", GCPhys, HCPhys));
2155#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2156 pgmR0DynMapHCPageInlined(&pVM->pgm.s, HCPhys, ppv);
2157#else
2158 PGMDynMapHCPage(pVM, HCPhys, ppv);
2159#endif
2160 return VINF_SUCCESS;
2161}
2162
2163
2164/**
2165 * Temporarily maps one guest page specified by unaligned GC physical address.
2166 * These pages must have a physical mapping in HC, i.e. they cannot be MMIO pages.
2167 *
2168 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
2169 * reused after 8 mappings (or perhaps a few more if you score with the cache).
2170 *
2171 * The caller is aware that only the speicifed page is mapped and that really bad things
2172 * will happen if writing beyond the page!
2173 *
2174 * @returns VBox status.
2175 * @param pVM VM handle.
2176 * @param GCPhys GC Physical address within the page to be mapped.
2177 * @param ppv Where to store the address of the mapping address corresponding to GCPhys.
2178 */
2179VMMDECL(int) PGMDynMapGCPageOff(PVM pVM, RTGCPHYS GCPhys, void **ppv)
2180{
2181 /*
2182 * Get the ram range.
2183 */
2184 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
2185 while (pRam && GCPhys - pRam->GCPhys >= pRam->cb)
2186 pRam = pRam->CTX_SUFF(pNext);
2187 if (!pRam)
2188 {
2189 AssertMsgFailed(("Invalid physical address %RGp!\n", GCPhys));
2190 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
2191 }
2192
2193 /*
2194 * Pass it on to PGMDynMapHCPage.
2195 */
2196 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT]);
2197#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2198 pgmR0DynMapHCPageInlined(&pVM->pgm.s, HCPhys, ppv);
2199#else
2200 PGMDynMapHCPage(pVM, HCPhys, ppv);
2201#endif
2202 *ppv = (void *)((uintptr_t)*ppv | (GCPhys & PAGE_OFFSET_MASK));
2203 return VINF_SUCCESS;
2204}
2205
2206# ifdef IN_RC
2207
2208/**
2209 * Temporarily maps one host page specified by HC physical address.
2210 *
2211 * Be WARNED that the dynamic page mapping area is small, 16 pages, thus the space is
2212 * reused after 16 mappings (or perhaps a few more if you score with the cache).
2213 *
2214 * @returns VINF_SUCCESS, will bail out to ring-3 on failure.
2215 * @param pVM VM handle.
2216 * @param HCPhys HC Physical address of the page.
2217 * @param ppv Where to store the address of the mapping. This is the
2218 * address of the PAGE not the exact address corresponding
2219 * to HCPhys. Use PGMDynMapHCPageOff if you care for the
2220 * page offset.
2221 */
2222VMMDECL(int) PGMDynMapHCPage(PVM pVM, RTHCPHYS HCPhys, void **ppv)
2223{
2224 AssertMsg(!(HCPhys & PAGE_OFFSET_MASK), ("HCPhys=%RHp\n", HCPhys));
2225
2226 /*
2227 * Check the cache.
2228 */
2229 register unsigned iCache;
2230 for (iCache = 0;iCache < RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache);iCache++)
2231 {
2232 static const uint8_t au8Trans[MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT][RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache)] =
2233 {
2234 { 0, 9, 10, 11, 12, 13, 14, 15},
2235 { 0, 1, 10, 11, 12, 13, 14, 15},
2236 { 0, 1, 2, 11, 12, 13, 14, 15},
2237 { 0, 1, 2, 3, 12, 13, 14, 15},
2238 { 0, 1, 2, 3, 4, 13, 14, 15},
2239 { 0, 1, 2, 3, 4, 5, 14, 15},
2240 { 0, 1, 2, 3, 4, 5, 6, 15},
2241 { 0, 1, 2, 3, 4, 5, 6, 7},
2242 { 8, 1, 2, 3, 4, 5, 6, 7},
2243 { 8, 9, 2, 3, 4, 5, 6, 7},
2244 { 8, 9, 10, 3, 4, 5, 6, 7},
2245 { 8, 9, 10, 11, 4, 5, 6, 7},
2246 { 8, 9, 10, 11, 12, 5, 6, 7},
2247 { 8, 9, 10, 11, 12, 13, 6, 7},
2248 { 8, 9, 10, 11, 12, 13, 14, 7},
2249 { 8, 9, 10, 11, 12, 13, 14, 15},
2250 };
2251 AssertCompile(RT_ELEMENTS(au8Trans) == 16);
2252 AssertCompile(RT_ELEMENTS(au8Trans[0]) == 8);
2253
2254 if (pVM->pgm.s.aHCPhysDynPageMapCache[iCache] == HCPhys)
2255 {
2256 int iPage = au8Trans[pVM->pgm.s.iDynPageMapLast][iCache];
2257
2258 /* The cache can get out of sync with locked entries. (10 locked, 2 overwrites its cache position, last = 11, lookup 2 -> page 10 instead of 2) */
2259 if ((pVM->pgm.s.paDynPageMap32BitPTEsGC[iPage].u & X86_PTE_PG_MASK) == HCPhys)
2260 {
2261 void *pv = pVM->pgm.s.pbDynPageMapBaseGC + (iPage << PAGE_SHIFT);
2262 *ppv = pv;
2263 STAM_COUNTER_INC(&pVM->pgm.s.StatRCDynMapCacheHits);
2264 Log4(("PGMGCDynMapHCPage: HCPhys=%RHp pv=%p iPage=%d iCache=%d\n", HCPhys, pv, iPage, iCache));
2265 return VINF_SUCCESS;
2266 }
2267 LogFlow(("Out of sync entry %d\n", iPage));
2268 }
2269 }
2270 AssertCompile(RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) == 8);
2271 AssertCompile((MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT) == 16);
2272 STAM_COUNTER_INC(&pVM->pgm.s.StatRCDynMapCacheMisses);
2273
2274 /*
2275 * Update the page tables.
2276 */
2277 unsigned iPage = pVM->pgm.s.iDynPageMapLast;
2278 unsigned i;
2279 for (i = 0; i < (MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT); i++)
2280 {
2281 pVM->pgm.s.iDynPageMapLast = iPage = (iPage + 1) & ((MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT) - 1);
2282 if (!pVM->pgm.s.aLockedDynPageMapCache[iPage])
2283 break;
2284 iPage++;
2285 }
2286 AssertRelease(i != (MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT));
2287
2288 pVM->pgm.s.aHCPhysDynPageMapCache[iPage & (RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) - 1)] = HCPhys;
2289 pVM->pgm.s.paDynPageMap32BitPTEsGC[iPage].u = (uint32_t)HCPhys | X86_PTE_P | X86_PTE_A | X86_PTE_D;
2290 pVM->pgm.s.paDynPageMapPaePTEsGC[iPage].u = HCPhys | X86_PTE_P | X86_PTE_A | X86_PTE_D;
2291 pVM->pgm.s.aLockedDynPageMapCache[iPage] = 0;
2292
2293 void *pv = pVM->pgm.s.pbDynPageMapBaseGC + (iPage << PAGE_SHIFT);
2294 *ppv = pv;
2295 ASMInvalidatePage(pv);
2296 Log4(("PGMGCDynMapHCPage: HCPhys=%RHp pv=%p iPage=%d\n", HCPhys, pv, iPage));
2297 return VINF_SUCCESS;
2298}
2299
2300
2301/**
2302 * Temporarily lock a dynamic page to prevent it from being reused.
2303 *
2304 * @param pVM VM handle.
2305 * @param GCPage GC address of page
2306 */
2307VMMDECL(void) PGMDynLockHCPage(PVM pVM, RCPTRTYPE(uint8_t *) GCPage)
2308{
2309 unsigned iPage;
2310
2311 Assert(GCPage >= pVM->pgm.s.pbDynPageMapBaseGC && GCPage < (pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE));
2312 iPage = ((uintptr_t)(GCPage - pVM->pgm.s.pbDynPageMapBaseGC)) >> PAGE_SHIFT;
2313 ASMAtomicIncU32(&pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2314 Log4(("PGMDynLockHCPage %RRv iPage=%d\n", GCPage, iPage));
2315}
2316
2317
2318/**
2319 * Unlock a dynamic page
2320 *
2321 * @param pVM VM handle.
2322 * @param GCPage GC address of page
2323 */
2324VMMDECL(void) PGMDynUnlockHCPage(PVM pVM, RCPTRTYPE(uint8_t *) GCPage)
2325{
2326 unsigned iPage;
2327
2328 AssertCompile(RT_ELEMENTS(pVM->pgm.s.aLockedDynPageMapCache) == 2* RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache));
2329 AssertCompileMemberSize(VM, pgm.s.aLockedDynPageMapCache, sizeof(uint32_t) * (MM_HYPER_DYNAMIC_SIZE >> (PAGE_SHIFT)));
2330
2331 Assert(GCPage >= pVM->pgm.s.pbDynPageMapBaseGC && GCPage < (pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE));
2332 iPage = ((uintptr_t)(GCPage - pVM->pgm.s.pbDynPageMapBaseGC)) >> PAGE_SHIFT;
2333 Assert(pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2334 ASMAtomicDecU32(&pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2335 Log4(("PGMDynUnlockHCPage %RRv iPage=%d\n", GCPage, iPage));
2336}
2337
2338
2339# ifdef VBOX_STRICT
2340/**
2341 * Check for lock leaks.
2342 *
2343 * @param pVM VM handle.
2344 */
2345VMMDECL(void) PGMDynCheckLocks(PVM pVM)
2346{
2347 for (unsigned i=0;i<RT_ELEMENTS(pVM->pgm.s.aLockedDynPageMapCache);i++)
2348 Assert(!pVM->pgm.s.aLockedDynPageMapCache[i]);
2349}
2350# endif /* VBOX_STRICT */
2351
2352# endif /* IN_RC */
2353#endif /* IN_RC || VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
2354
2355#if !defined(IN_R0) || defined(LOG_ENABLED)
2356
2357/** Format handler for PGMPAGE.
2358 * @copydoc FNRTSTRFORMATTYPE */
2359static DECLCALLBACK(size_t) pgmFormatTypeHandlerPage(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2360 const char *pszType, void const *pvValue,
2361 int cchWidth, int cchPrecision, unsigned fFlags,
2362 void *pvUser)
2363{
2364 size_t cch;
2365 PCPGMPAGE pPage = (PCPGMPAGE)pvValue;
2366 if (VALID_PTR(pPage))
2367 {
2368 char szTmp[64+80];
2369
2370 cch = 0;
2371
2372 /* The single char state stuff. */
2373 static const char s_achPageStates[4] = { 'Z', 'A', 'W', 'S' };
2374 szTmp[cch++] = s_achPageStates[PGM_PAGE_GET_STATE(pPage)];
2375
2376#define IS_PART_INCLUDED(lvl) ( !(fFlags & RTSTR_F_PRECISION) || cchPrecision == (lvl) || cchPrecision >= (lvl)+10 )
2377 if (IS_PART_INCLUDED(5))
2378 {
2379 static const char s_achHandlerStates[4] = { '-', 't', 'w', 'a' };
2380 szTmp[cch++] = s_achHandlerStates[PGM_PAGE_GET_HNDL_PHYS_STATE(pPage)];
2381 szTmp[cch++] = s_achHandlerStates[PGM_PAGE_GET_HNDL_VIRT_STATE(pPage)];
2382 }
2383
2384 /* The type. */
2385 if (IS_PART_INCLUDED(4))
2386 {
2387 szTmp[cch++] = ':';
2388 static const char s_achPageTypes[8][4] = { "INV", "RAM", "MI2", "M2A", "SHA", "ROM", "MIO", "BAD" };
2389 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][0];
2390 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][1];
2391 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][2];
2392 }
2393
2394 /* The numbers. */
2395 if (IS_PART_INCLUDED(3))
2396 {
2397 szTmp[cch++] = ':';
2398 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_HCPHYS(pPage), 16, 12, 0, RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
2399 }
2400
2401 if (IS_PART_INCLUDED(2))
2402 {
2403 szTmp[cch++] = ':';
2404 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_PAGEID(pPage), 16, 7, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
2405 }
2406
2407 if (IS_PART_INCLUDED(6))
2408 {
2409 szTmp[cch++] = ':';
2410 static const char s_achRefs[4] = { '-', 'U', '!', 'L' };
2411 szTmp[cch++] = s_achRefs[PGM_PAGE_GET_TD_CREFS(pPage)];
2412 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_TD_IDX(pPage), 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_16BIT);
2413 }
2414#undef IS_PART_INCLUDED
2415
2416 cch = pfnOutput(pvArgOutput, szTmp, cch);
2417 }
2418 else
2419 cch = pfnOutput(pvArgOutput, "<bad-pgmpage-ptr>", sizeof("<bad-pgmpage-ptr>") - 1);
2420 return cch;
2421}
2422
2423
2424/** Format handler for PGMRAMRANGE.
2425 * @copydoc FNRTSTRFORMATTYPE */
2426static DECLCALLBACK(size_t) pgmFormatTypeHandlerRamRange(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2427 const char *pszType, void const *pvValue,
2428 int cchWidth, int cchPrecision, unsigned fFlags,
2429 void *pvUser)
2430{
2431 size_t cch;
2432 PGMRAMRANGE const *pRam = (PGMRAMRANGE const *)pvValue;
2433 if (VALID_PTR(pRam))
2434 {
2435 char szTmp[80];
2436 cch = RTStrPrintf(szTmp, sizeof(szTmp), "%RGp-%RGp", pRam->GCPhys, pRam->GCPhysLast);
2437 cch = pfnOutput(pvArgOutput, szTmp, cch);
2438 }
2439 else
2440 cch = pfnOutput(pvArgOutput, "<bad-pgmramrange-ptr>", sizeof("<bad-pgmramrange-ptr>") - 1);
2441 return cch;
2442}
2443
2444/** Format type andlers to be registered/deregistered. */
2445static const struct
2446{
2447 char szType[24];
2448 PFNRTSTRFORMATTYPE pfnHandler;
2449} g_aPgmFormatTypes[] =
2450{
2451 { "pgmpage", pgmFormatTypeHandlerPage },
2452 { "pgmramrange", pgmFormatTypeHandlerRamRange }
2453};
2454
2455#endif /* !IN_R0 || LOG_ENABLED */
2456
2457
2458/**
2459 * Registers the global string format types.
2460 *
2461 * This should be called at module load time or in some other manner that ensure
2462 * that it's called exactly one time.
2463 *
2464 * @returns IPRT status code on RTStrFormatTypeRegister failure.
2465 */
2466VMMDECL(int) PGMRegisterStringFormatTypes(void)
2467{
2468#if !defined(IN_R0) || defined(LOG_ENABLED)
2469 int rc = VINF_SUCCESS;
2470 unsigned i;
2471 for (i = 0; RT_SUCCESS(rc) && i < RT_ELEMENTS(g_aPgmFormatTypes); i++)
2472 {
2473 rc = RTStrFormatTypeRegister(g_aPgmFormatTypes[i].szType, g_aPgmFormatTypes[i].pfnHandler, NULL);
2474# ifdef IN_RING0
2475 if (rc == VERR_ALREADY_EXISTS)
2476 {
2477 /* in case of cleanup failure in ring-0 */
2478 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2479 rc = RTStrFormatTypeRegister(g_aPgmFormatTypes[i].szType, g_aPgmFormatTypes[i].pfnHandler, NULL);
2480 }
2481# endif
2482 }
2483 if (RT_FAILURE(rc))
2484 while (i-- > 0)
2485 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2486
2487 return rc;
2488#else
2489 return VINF_SUCCESS;
2490#endif
2491}
2492
2493
2494/**
2495 * Deregisters the global string format types.
2496 *
2497 * This should be called at module unload time or in some other manner that
2498 * ensure that it's called exactly one time.
2499 */
2500VMMDECL(void) PGMDeregisterStringFormatTypes(void)
2501{
2502#if !defined(IN_R0) || defined(LOG_ENABLED)
2503 for (unsigned i = 0; i < RT_ELEMENTS(g_aPgmFormatTypes); i++)
2504 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2505#endif
2506}
2507
2508#ifdef VBOX_STRICT
2509
2510/**
2511 * Asserts that there are no mapping conflicts.
2512 *
2513 * @returns Number of conflicts.
2514 * @param pVM The VM Handle.
2515 */
2516VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM)
2517{
2518 unsigned cErrors = 0;
2519
2520 /* Only applies to raw mode -> 1 VPCU */
2521 Assert(pVM->cCpus == 1);
2522 PVMCPU pVCpu = &pVM->aCpus[0];
2523
2524 /*
2525 * Check for mapping conflicts.
2526 */
2527 for (PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
2528 pMapping;
2529 pMapping = pMapping->CTX_SUFF(pNext))
2530 {
2531 /** @todo This is slow and should be optimized, but since it's just assertions I don't care now. */
2532 for (RTGCPTR GCPtr = pMapping->GCPtr;
2533 GCPtr <= pMapping->GCPtrLast;
2534 GCPtr += PAGE_SIZE)
2535 {
2536 int rc = PGMGstGetPage(pVCpu, (RTGCPTR)GCPtr, NULL, NULL);
2537 if (rc != VERR_PAGE_TABLE_NOT_PRESENT)
2538 {
2539 AssertMsgFailed(("Conflict at %RGv with %s\n", GCPtr, R3STRING(pMapping->pszDesc)));
2540 cErrors++;
2541 break;
2542 }
2543 }
2544 }
2545
2546 return cErrors;
2547}
2548
2549
2550/**
2551 * Asserts that everything related to the guest CR3 is correctly shadowed.
2552 *
2553 * This will call PGMAssertNoMappingConflicts() and PGMAssertHandlerAndFlagsInSync(),
2554 * and assert the correctness of the guest CR3 mapping before asserting that the
2555 * shadow page tables is in sync with the guest page tables.
2556 *
2557 * @returns Number of conflicts.
2558 * @param pVM The VM Handle.
2559 * @param pVCpu VMCPU handle.
2560 * @param cr3 The current guest CR3 register value.
2561 * @param cr4 The current guest CR4 register value.
2562 */
2563VMMDECL(unsigned) PGMAssertCR3(PVM pVM, PVMCPU pVCpu, uint64_t cr3, uint64_t cr4)
2564{
2565 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
2566 pgmLock(pVM);
2567 unsigned cErrors = PGM_BTH_PFN(AssertCR3, pVCpu)(pVCpu, cr3, cr4, 0, ~(RTGCPTR)0);
2568 pgmUnlock(pVM);
2569 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
2570 return cErrors;
2571}
2572
2573#endif /* VBOX_STRICT */
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