VirtualBox

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

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

Action flags breakup.
Fixed PGM saved state loading of 2.2.2 images.
Reduced hacks in PATM state loading (fixups).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 80.8 KB
Line 
1/* $Id: PGMAll.cpp 19141 2009-04-23 13:52:18Z 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 = pgmPoolGetPageByHCPhys(PGMCPU2VM(pPGM), 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 /*
1763 * We might be called when we shouldn't.
1764 *
1765 * The mode switching will ensure that the PD is resynced
1766 * after every mode switch. So, if we find ourselves here
1767 * when in protected or real mode we can safely disable the
1768 * FF and return immediately.
1769 */
1770 if (pVCpu->pgm.s.enmGuestMode <= PGMMODE_PROTECTED)
1771 {
1772 Assert((cr0 & (X86_CR0_PG | X86_CR0_PE)) != (X86_CR0_PG | X86_CR0_PE));
1773 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
1774 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
1775 return VINF_SUCCESS;
1776 }
1777
1778 /* If global pages are not supported, then all flushes are global. */
1779 if (!(cr4 & X86_CR4_PGE))
1780 fGlobal = true;
1781 LogFlow(("PGMSyncCR3: cr0=%RX64 cr3=%RX64 cr4=%RX64 fGlobal=%d[%d,%d]\n", cr0, cr3, cr4, fGlobal,
1782 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3), VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL)));
1783
1784#ifdef PGMPOOL_WITH_MONITORING
1785 /*
1786 * The pool may have pending stuff and even require a return to ring-3 to
1787 * clear the whole thing.
1788 */
1789 rc = pgmPoolSyncCR3(pVM);
1790 if (rc != VINF_SUCCESS)
1791 return rc;
1792#endif
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 * Acquire the PGM lock.
2023 *
2024 * @returns VBox status code
2025 * @param pVM The VM to operate on.
2026 */
2027int pgmLock(PVM pVM)
2028{
2029 int rc = PDMCritSectEnter(&pVM->pgm.s.CritSect, VERR_SEM_BUSY);
2030#ifdef IN_RC
2031 if (rc == VERR_SEM_BUSY)
2032 rc = VMMGCCallHost(pVM, VMMCALLHOST_PGM_LOCK, 0);
2033#elif defined(IN_RING0)
2034 if (rc == VERR_SEM_BUSY)
2035 rc = VMMR0CallHost(pVM, VMMCALLHOST_PGM_LOCK, 0);
2036#endif
2037 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
2038 return rc;
2039}
2040
2041
2042/**
2043 * Release the PGM lock.
2044 *
2045 * @returns VBox status code
2046 * @param pVM The VM to operate on.
2047 */
2048void pgmUnlock(PVM pVM)
2049{
2050 PDMCritSectLeave(&pVM->pgm.s.CritSect);
2051}
2052
2053#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
2054
2055/**
2056 * Temporarily maps one guest page specified by GC physical address.
2057 * These pages must have a physical mapping in HC, i.e. they cannot be MMIO pages.
2058 *
2059 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
2060 * reused after 8 mappings (or perhaps a few more if you score with the cache).
2061 *
2062 * @returns VBox status.
2063 * @param pVM VM handle.
2064 * @param GCPhys GC Physical address of the page.
2065 * @param ppv Where to store the address of the mapping.
2066 */
2067VMMDECL(int) PGMDynMapGCPage(PVM pVM, RTGCPHYS GCPhys, void **ppv)
2068{
2069 AssertMsg(!(GCPhys & PAGE_OFFSET_MASK), ("GCPhys=%RGp\n", GCPhys));
2070
2071 /*
2072 * Get the ram range.
2073 */
2074 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
2075 while (pRam && GCPhys - pRam->GCPhys >= pRam->cb)
2076 pRam = pRam->CTX_SUFF(pNext);
2077 if (!pRam)
2078 {
2079 AssertMsgFailed(("Invalid physical address %RGp!\n", GCPhys));
2080 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
2081 }
2082
2083 /*
2084 * Pass it on to PGMDynMapHCPage.
2085 */
2086 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT]);
2087 //Log(("PGMDynMapGCPage: GCPhys=%RGp HCPhys=%RHp\n", GCPhys, HCPhys));
2088#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2089 pgmR0DynMapHCPageInlined(&pVM->pgm.s, HCPhys, ppv);
2090#else
2091 PGMDynMapHCPage(pVM, HCPhys, ppv);
2092#endif
2093 return VINF_SUCCESS;
2094}
2095
2096
2097/**
2098 * Temporarily maps one guest page specified by unaligned GC physical address.
2099 * These pages must have a physical mapping in HC, i.e. they cannot be MMIO pages.
2100 *
2101 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
2102 * reused after 8 mappings (or perhaps a few more if you score with the cache).
2103 *
2104 * The caller is aware that only the speicifed page is mapped and that really bad things
2105 * will happen if writing beyond the page!
2106 *
2107 * @returns VBox status.
2108 * @param pVM VM handle.
2109 * @param GCPhys GC Physical address within the page to be mapped.
2110 * @param ppv Where to store the address of the mapping address corresponding to GCPhys.
2111 */
2112VMMDECL(int) PGMDynMapGCPageOff(PVM pVM, RTGCPHYS GCPhys, void **ppv)
2113{
2114 /*
2115 * Get the ram range.
2116 */
2117 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
2118 while (pRam && GCPhys - pRam->GCPhys >= pRam->cb)
2119 pRam = pRam->CTX_SUFF(pNext);
2120 if (!pRam)
2121 {
2122 AssertMsgFailed(("Invalid physical address %RGp!\n", GCPhys));
2123 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
2124 }
2125
2126 /*
2127 * Pass it on to PGMDynMapHCPage.
2128 */
2129 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT]);
2130#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2131 pgmR0DynMapHCPageInlined(&pVM->pgm.s, HCPhys, ppv);
2132#else
2133 PGMDynMapHCPage(pVM, HCPhys, ppv);
2134#endif
2135 *ppv = (void *)((uintptr_t)*ppv | (GCPhys & PAGE_OFFSET_MASK));
2136 return VINF_SUCCESS;
2137}
2138
2139# ifdef IN_RC
2140
2141/**
2142 * Temporarily maps one host page specified by HC physical address.
2143 *
2144 * Be WARNED that the dynamic page mapping area is small, 16 pages, thus the space is
2145 * reused after 16 mappings (or perhaps a few more if you score with the cache).
2146 *
2147 * @returns VINF_SUCCESS, will bail out to ring-3 on failure.
2148 * @param pVM VM handle.
2149 * @param HCPhys HC Physical address of the page.
2150 * @param ppv Where to store the address of the mapping. This is the
2151 * address of the PAGE not the exact address corresponding
2152 * to HCPhys. Use PGMDynMapHCPageOff if you care for the
2153 * page offset.
2154 */
2155VMMDECL(int) PGMDynMapHCPage(PVM pVM, RTHCPHYS HCPhys, void **ppv)
2156{
2157 AssertMsg(!(HCPhys & PAGE_OFFSET_MASK), ("HCPhys=%RHp\n", HCPhys));
2158
2159 /*
2160 * Check the cache.
2161 */
2162 register unsigned iCache;
2163 for (iCache = 0;iCache < RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache);iCache++)
2164 {
2165 static const uint8_t au8Trans[MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT][RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache)] =
2166 {
2167 { 0, 9, 10, 11, 12, 13, 14, 15},
2168 { 0, 1, 10, 11, 12, 13, 14, 15},
2169 { 0, 1, 2, 11, 12, 13, 14, 15},
2170 { 0, 1, 2, 3, 12, 13, 14, 15},
2171 { 0, 1, 2, 3, 4, 13, 14, 15},
2172 { 0, 1, 2, 3, 4, 5, 14, 15},
2173 { 0, 1, 2, 3, 4, 5, 6, 15},
2174 { 0, 1, 2, 3, 4, 5, 6, 7},
2175 { 8, 1, 2, 3, 4, 5, 6, 7},
2176 { 8, 9, 2, 3, 4, 5, 6, 7},
2177 { 8, 9, 10, 3, 4, 5, 6, 7},
2178 { 8, 9, 10, 11, 4, 5, 6, 7},
2179 { 8, 9, 10, 11, 12, 5, 6, 7},
2180 { 8, 9, 10, 11, 12, 13, 6, 7},
2181 { 8, 9, 10, 11, 12, 13, 14, 7},
2182 { 8, 9, 10, 11, 12, 13, 14, 15},
2183 };
2184 AssertCompile(RT_ELEMENTS(au8Trans) == 16);
2185 AssertCompile(RT_ELEMENTS(au8Trans[0]) == 8);
2186
2187 if (pVM->pgm.s.aHCPhysDynPageMapCache[iCache] == HCPhys)
2188 {
2189 int iPage = au8Trans[pVM->pgm.s.iDynPageMapLast][iCache];
2190
2191 /* 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) */
2192 if ((pVM->pgm.s.paDynPageMap32BitPTEsGC[iPage].u & X86_PTE_PG_MASK) == HCPhys)
2193 {
2194 void *pv = pVM->pgm.s.pbDynPageMapBaseGC + (iPage << PAGE_SHIFT);
2195 *ppv = pv;
2196 STAM_COUNTER_INC(&pVM->pgm.s.StatRCDynMapCacheHits);
2197 Log4(("PGMGCDynMapHCPage: HCPhys=%RHp pv=%p iPage=%d iCache=%d\n", HCPhys, pv, iPage, iCache));
2198 return VINF_SUCCESS;
2199 }
2200 else
2201 LogFlow(("Out of sync entry %d\n", iPage));
2202 }
2203 }
2204 AssertCompile(RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) == 8);
2205 AssertCompile((MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT) == 16);
2206 STAM_COUNTER_INC(&pVM->pgm.s.StatRCDynMapCacheMisses);
2207
2208 /*
2209 * Update the page tables.
2210 */
2211 register unsigned iPage = pVM->pgm.s.iDynPageMapLast;
2212 unsigned i;
2213 for (i=0;i<(MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT);i++)
2214 {
2215 pVM->pgm.s.iDynPageMapLast = iPage = (iPage + 1) & ((MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT) - 1);
2216 if (!pVM->pgm.s.aLockedDynPageMapCache[iPage])
2217 break;
2218 iPage++;
2219 }
2220 AssertRelease(i != (MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT));
2221
2222 pVM->pgm.s.aHCPhysDynPageMapCache[iPage & (RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) - 1)] = HCPhys;
2223 pVM->pgm.s.paDynPageMap32BitPTEsGC[iPage].u = (uint32_t)HCPhys | X86_PTE_P | X86_PTE_A | X86_PTE_D;
2224 pVM->pgm.s.paDynPageMapPaePTEsGC[iPage].u = HCPhys | X86_PTE_P | X86_PTE_A | X86_PTE_D;
2225 pVM->pgm.s.aLockedDynPageMapCache[iPage] = 0;
2226
2227 void *pv = pVM->pgm.s.pbDynPageMapBaseGC + (iPage << PAGE_SHIFT);
2228 *ppv = pv;
2229 ASMInvalidatePage(pv);
2230 Log4(("PGMGCDynMapHCPage: HCPhys=%RHp pv=%p iPage=%d\n", HCPhys, pv, iPage));
2231 return VINF_SUCCESS;
2232}
2233
2234
2235/**
2236 * Temporarily lock a dynamic page to prevent it from being reused.
2237 *
2238 * @param pVM VM handle.
2239 * @param GCPage GC address of page
2240 */
2241VMMDECL(void) PGMDynLockHCPage(PVM pVM, RCPTRTYPE(uint8_t *) GCPage)
2242{
2243 unsigned iPage;
2244
2245 Assert(GCPage >= pVM->pgm.s.pbDynPageMapBaseGC && GCPage < (pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE));
2246 iPage = ((uintptr_t)(GCPage - pVM->pgm.s.pbDynPageMapBaseGC)) >> PAGE_SHIFT;
2247 ASMAtomicIncU32(&pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2248 Log4(("PGMDynLockHCPage %RRv iPage=%d\n", GCPage, iPage));
2249}
2250
2251
2252/**
2253 * Unlock a dynamic page
2254 *
2255 * @param pVM VM handle.
2256 * @param GCPage GC address of page
2257 */
2258VMMDECL(void) PGMDynUnlockHCPage(PVM pVM, RCPTRTYPE(uint8_t *) GCPage)
2259{
2260 unsigned iPage;
2261
2262 AssertCompile(RT_ELEMENTS(pVM->pgm.s.aLockedDynPageMapCache) == 2* RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache));
2263 AssertCompileMemberSize(VM, pgm.s.aLockedDynPageMapCache, sizeof(uint32_t) * (MM_HYPER_DYNAMIC_SIZE >> (PAGE_SHIFT)));
2264
2265 Assert(GCPage >= pVM->pgm.s.pbDynPageMapBaseGC && GCPage < (pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE));
2266 iPage = ((uintptr_t)(GCPage - pVM->pgm.s.pbDynPageMapBaseGC)) >> PAGE_SHIFT;
2267 Assert(pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2268 ASMAtomicDecU32(&pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2269 Log4(("PGMDynUnlockHCPage %RRv iPage=%d\n", GCPage, iPage));
2270}
2271
2272
2273# ifdef VBOX_STRICT
2274/**
2275 * Check for lock leaks.
2276 *
2277 * @param pVM VM handle.
2278 */
2279VMMDECL(void) PGMDynCheckLocks(PVM pVM)
2280{
2281 for (unsigned i=0;i<RT_ELEMENTS(pVM->pgm.s.aLockedDynPageMapCache);i++)
2282 Assert(!pVM->pgm.s.aLockedDynPageMapCache[i]);
2283}
2284# endif /* VBOX_STRICT */
2285
2286# endif /* IN_RC */
2287#endif /* IN_RC || VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
2288
2289#if !defined(IN_R0) || defined(LOG_ENABLED)
2290
2291/** Format handler for PGMPAGE.
2292 * @copydoc FNRTSTRFORMATTYPE */
2293static DECLCALLBACK(size_t) pgmFormatTypeHandlerPage(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2294 const char *pszType, void const *pvValue,
2295 int cchWidth, int cchPrecision, unsigned fFlags,
2296 void *pvUser)
2297{
2298 size_t cch;
2299 PCPGMPAGE pPage = (PCPGMPAGE)pvValue;
2300 if (VALID_PTR(pPage))
2301 {
2302 char szTmp[64+80];
2303
2304 cch = 0;
2305
2306 /* The single char state stuff. */
2307 static const char s_achPageStates[4] = { 'Z', 'A', 'W', 'S' };
2308 szTmp[cch++] = s_achPageStates[PGM_PAGE_GET_STATE(pPage)];
2309
2310#define IS_PART_INCLUDED(lvl) ( !(fFlags & RTSTR_F_PRECISION) || cchPrecision == (lvl) || cchPrecision >= (lvl)+10 )
2311 if (IS_PART_INCLUDED(5))
2312 {
2313 static const char s_achHandlerStates[4] = { '-', 't', 'w', 'a' };
2314 szTmp[cch++] = s_achHandlerStates[PGM_PAGE_GET_HNDL_PHYS_STATE(pPage)];
2315 szTmp[cch++] = s_achHandlerStates[PGM_PAGE_GET_HNDL_VIRT_STATE(pPage)];
2316 }
2317
2318 /* The type. */
2319 if (IS_PART_INCLUDED(4))
2320 {
2321 szTmp[cch++] = ':';
2322 static const char s_achPageTypes[8][4] = { "INV", "RAM", "MI2", "M2A", "SHA", "ROM", "MIO", "BAD" };
2323 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][0];
2324 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][1];
2325 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][2];
2326 }
2327
2328 /* The numbers. */
2329 if (IS_PART_INCLUDED(3))
2330 {
2331 szTmp[cch++] = ':';
2332 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_HCPHYS(pPage), 16, 12, 0, RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
2333 }
2334
2335 if (IS_PART_INCLUDED(2))
2336 {
2337 szTmp[cch++] = ':';
2338 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_PAGEID(pPage), 16, 7, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
2339 }
2340
2341 if (IS_PART_INCLUDED(6))
2342 {
2343 szTmp[cch++] = ':';
2344 static const char s_achRefs[4] = { '-', 'U', '!', 'L' };
2345 szTmp[cch++] = s_achRefs[PGM_PAGE_GET_TD_CREFS(pPage)];
2346 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_TD_IDX(pPage), 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_16BIT);
2347 }
2348#undef IS_PART_INCLUDED
2349
2350 cch = pfnOutput(pvArgOutput, szTmp, cch);
2351 }
2352 else
2353 cch = pfnOutput(pvArgOutput, "<bad-pgmpage-ptr>", sizeof("<bad-pgmpage-ptr>") - 1);
2354 return cch;
2355}
2356
2357
2358/** Format handler for PGMRAMRANGE.
2359 * @copydoc FNRTSTRFORMATTYPE */
2360static DECLCALLBACK(size_t) pgmFormatTypeHandlerRamRange(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2361 const char *pszType, void const *pvValue,
2362 int cchWidth, int cchPrecision, unsigned fFlags,
2363 void *pvUser)
2364{
2365 size_t cch;
2366 PGMRAMRANGE const *pRam = (PGMRAMRANGE const *)pvValue;
2367 if (VALID_PTR(pRam))
2368 {
2369 char szTmp[80];
2370 cch = RTStrPrintf(szTmp, sizeof(szTmp), "%RGp-%RGp", pRam->GCPhys, pRam->GCPhysLast);
2371 cch = pfnOutput(pvArgOutput, szTmp, cch);
2372 }
2373 else
2374 cch = pfnOutput(pvArgOutput, "<bad-pgmramrange-ptr>", sizeof("<bad-pgmramrange-ptr>") - 1);
2375 return cch;
2376}
2377
2378/** Format type andlers to be registered/deregistered. */
2379static const struct
2380{
2381 char szType[24];
2382 PFNRTSTRFORMATTYPE pfnHandler;
2383} g_aPgmFormatTypes[] =
2384{
2385 { "pgmpage", pgmFormatTypeHandlerPage },
2386 { "pgmramrange", pgmFormatTypeHandlerRamRange }
2387};
2388
2389#endif /* !IN_R0 || LOG_ENABLED */
2390
2391
2392/**
2393 * Registers the global string format types.
2394 *
2395 * This should be called at module load time or in some other manner that ensure
2396 * that it's called exactly one time.
2397 *
2398 * @returns IPRT status code on RTStrFormatTypeRegister failure.
2399 */
2400VMMDECL(int) PGMRegisterStringFormatTypes(void)
2401{
2402#if !defined(IN_R0) || defined(LOG_ENABLED)
2403 int rc = VINF_SUCCESS;
2404 unsigned i;
2405 for (i = 0; RT_SUCCESS(rc) && i < RT_ELEMENTS(g_aPgmFormatTypes); i++)
2406 {
2407 rc = RTStrFormatTypeRegister(g_aPgmFormatTypes[i].szType, g_aPgmFormatTypes[i].pfnHandler, NULL);
2408# ifdef IN_RING0
2409 if (rc == VERR_ALREADY_EXISTS)
2410 {
2411 /* in case of cleanup failure in ring-0 */
2412 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2413 rc = RTStrFormatTypeRegister(g_aPgmFormatTypes[i].szType, g_aPgmFormatTypes[i].pfnHandler, NULL);
2414 }
2415# endif
2416 }
2417 if (RT_FAILURE(rc))
2418 while (i-- > 0)
2419 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2420
2421 return rc;
2422#else
2423 return VINF_SUCCESS;
2424#endif
2425}
2426
2427
2428/**
2429 * Deregisters the global string format types.
2430 *
2431 * This should be called at module unload time or in some other manner that
2432 * ensure that it's called exactly one time.
2433 */
2434VMMDECL(void) PGMDeregisterStringFormatTypes(void)
2435{
2436#if !defined(IN_R0) || defined(LOG_ENABLED)
2437 for (unsigned i = 0; i < RT_ELEMENTS(g_aPgmFormatTypes); i++)
2438 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2439#endif
2440}
2441
2442#ifdef VBOX_STRICT
2443
2444/**
2445 * Asserts that there are no mapping conflicts.
2446 *
2447 * @returns Number of conflicts.
2448 * @param pVM The VM Handle.
2449 */
2450VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM)
2451{
2452 unsigned cErrors = 0;
2453
2454 /* Only applies to raw mode -> 1 VPCU */
2455 Assert(pVM->cCPUs == 1);
2456 PVMCPU pVCpu = &pVM->aCpus[0];
2457
2458 /*
2459 * Check for mapping conflicts.
2460 */
2461 for (PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
2462 pMapping;
2463 pMapping = pMapping->CTX_SUFF(pNext))
2464 {
2465 /** @todo This is slow and should be optimized, but since it's just assertions I don't care now. */
2466 for (RTGCPTR GCPtr = pMapping->GCPtr;
2467 GCPtr <= pMapping->GCPtrLast;
2468 GCPtr += PAGE_SIZE)
2469 {
2470 int rc = PGMGstGetPage(pVCpu, (RTGCPTR)GCPtr, NULL, NULL);
2471 if (rc != VERR_PAGE_TABLE_NOT_PRESENT)
2472 {
2473 AssertMsgFailed(("Conflict at %RGv with %s\n", GCPtr, R3STRING(pMapping->pszDesc)));
2474 cErrors++;
2475 break;
2476 }
2477 }
2478 }
2479
2480 return cErrors;
2481}
2482
2483
2484/**
2485 * Asserts that everything related to the guest CR3 is correctly shadowed.
2486 *
2487 * This will call PGMAssertNoMappingConflicts() and PGMAssertHandlerAndFlagsInSync(),
2488 * and assert the correctness of the guest CR3 mapping before asserting that the
2489 * shadow page tables is in sync with the guest page tables.
2490 *
2491 * @returns Number of conflicts.
2492 * @param pVM The VM Handle.
2493 * @param pVCpu VMCPU handle.
2494 * @param cr3 The current guest CR3 register value.
2495 * @param cr4 The current guest CR4 register value.
2496 */
2497VMMDECL(unsigned) PGMAssertCR3(PVM pVM, PVMCPU pVCpu, uint64_t cr3, uint64_t cr4)
2498{
2499 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
2500 unsigned cErrors = PGM_BTH_PFN(AssertCR3, pVCpu)(pVCpu, cr3, cr4, 0, ~(RTGCPTR)0);
2501 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
2502 return cErrors;
2503}
2504
2505#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