VirtualBox

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

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

Mark shadow pgm pool page as used when syncing one that already exists. (prevent premature flushing)

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