VirtualBox

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

Last change on this file since 19675 was 19516, checked in by vboxsync, 16 years ago

Always call pgmPoolSyncCR3 from PGMSyncCR3 (regardless of guest paging mode as it's relevant in the nested paging case).

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

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