VirtualBox

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

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

More logging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 81.1 KB
Line 
1/* $Id: PGMAll.cpp 18729 2009-04-06 08:15:12Z 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
961 Assert((pPdpe->u & X86_PDPE_PG_MASK) == pShwPage->Core.Key);
962 }
963 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
964 return VINF_SUCCESS;
965}
966
967
968/**
969 * Gets the pointer to the shadow page directory entry for an address, PAE.
970 *
971 * @returns Pointer to the PDE.
972 * @param pPGM Pointer to the PGM instance data.
973 * @param GCPtr The address.
974 * @param ppShwPde Receives the address of the pgm pool page for the shadow page directory
975 */
976DECLINLINE(int) pgmShwGetPaePoolPagePD(PPGM pPGM, RTGCPTR GCPtr, PPGMPOOLPAGE *ppShwPde)
977{
978 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
979 PX86PDPT pPdpt = pgmShwGetPaePDPTPtr(pPGM);
980 AssertReturn(pPdpt, VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT); /* can't happen */
981 if (!pPdpt->a[iPdPt].n.u1Present)
982 {
983 LogFlow(("pgmShwGetPaePoolPagePD: PD %d not present (%RX64)\n", iPdPt, pPdpt->a[iPdPt].u));
984 return VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT;
985 }
986 AssertMsg(pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK, ("GCPtr=%RGv\n", GCPtr));
987
988 /* Fetch the pgm pool shadow descriptor. */
989 PPGMPOOLPAGE pShwPde = pgmPoolGetPageByHCPhys(PGM2VM(pPGM), pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK);
990 AssertReturn(pShwPde, VERR_INTERNAL_ERROR);
991
992 *ppShwPde = pShwPde;
993 return VINF_SUCCESS;
994}
995
996#ifndef IN_RC
997
998/**
999 * Syncs the SHADOW page directory pointer for the specified address.
1000 *
1001 * Allocates backing pages in case the PDPT or PML4 entry is missing.
1002 *
1003 * The caller is responsible for making sure the guest has a valid PD before
1004 * calling this function.
1005 *
1006 * @returns VBox status.
1007 * @param pVM VM handle.
1008 * @param GCPtr The address.
1009 * @param pGstPml4e Guest PML4 entry
1010 * @param pGstPdpe Guest PDPT entry
1011 * @param ppPD Receives address of page directory
1012 */
1013int pgmShwSyncLongModePDPtr(PVM pVM, RTGCPTR64 GCPtr, PX86PML4E pGstPml4e, PX86PDPE pGstPdpe, PX86PDPAE *ppPD)
1014{
1015 PPGM pPGM = &pVM->pgm.s;
1016 PPGMPOOL pPool = pPGM->CTX_SUFF(pPool);
1017 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1018 PX86PML4E pPml4e = pgmShwGetLongModePML4EPtr(pPGM, iPml4);
1019 bool fNestedPaging = HWACCMIsNestedPagingActive(pVM);
1020 bool fPaging = !!(CPUMGetGuestCR0(pVM) & X86_CR0_PG);
1021 PPGMPOOLPAGE pShwPage;
1022 int rc;
1023
1024 /* Allocate page directory pointer table if not present. */
1025 if ( !pPml4e->n.u1Present
1026 && !(pPml4e->u & X86_PML4E_PG_MASK))
1027 {
1028 RTGCPTR64 GCPml4;
1029 PGMPOOLKIND enmKind;
1030
1031 Assert(pVM->pgm.s.CTX_SUFF(pShwPageCR3));
1032
1033 if (fNestedPaging || !fPaging)
1034 {
1035 /* AMD-V nested paging or real/protected mode without paging */
1036 GCPml4 = (RTGCPTR64)iPml4 << X86_PML4_SHIFT;
1037 enmKind = PGMPOOLKIND_64BIT_PDPT_FOR_PHYS;
1038 }
1039 else
1040 {
1041 Assert(pGstPml4e && pGstPdpe);
1042
1043 GCPml4 = pGstPml4e->u & X86_PML4E_PG_MASK;
1044 enmKind = PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT;
1045 }
1046
1047 /* Create a reference back to the PDPT by using the index in its shadow page. */
1048 rc = pgmPoolAlloc(pVM, GCPml4, enmKind, pVM->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iPml4, &pShwPage);
1049 AssertRCReturn(rc, rc);
1050 }
1051 else
1052 {
1053 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & X86_PML4E_PG_MASK);
1054 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1055 }
1056 /* The PDPT was cached or created; hook it up now. */
1057 pPml4e->u |= pShwPage->Core.Key
1058 | (pGstPml4e->u & ~(X86_PML4E_PG_MASK | X86_PML4E_AVL_MASK | X86_PML4E_PCD | X86_PML4E_PWT));
1059
1060 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1061 PX86PDPT pPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1062 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
1063
1064 /* Allocate page directory if not present. */
1065 if ( !pPdpe->n.u1Present
1066 && !(pPdpe->u & X86_PDPE_PG_MASK))
1067 {
1068 RTGCPTR64 GCPdPt;
1069 PGMPOOLKIND enmKind;
1070
1071 if (fNestedPaging || !fPaging)
1072 {
1073 /* AMD-V nested paging or real/protected mode without paging */
1074 GCPdPt = (RTGCPTR64)iPdPt << X86_PDPT_SHIFT;
1075 enmKind = PGMPOOLKIND_64BIT_PD_FOR_PHYS;
1076 }
1077 else
1078 {
1079 Assert(pGstPdpe);
1080
1081 GCPdPt = pGstPdpe->u & X86_PDPE_PG_MASK;
1082 enmKind = PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD;
1083 }
1084
1085 /* Create a reference back to the PDPT by using the index in its shadow page. */
1086 rc = pgmPoolAlloc(pVM, GCPdPt, enmKind, pShwPage->idx, iPdPt, &pShwPage);
1087 AssertRCReturn(rc, rc);
1088 }
1089 else
1090 {
1091 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
1092 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1093 }
1094 /* The PD was cached or created; hook it up now. */
1095 pPdpe->u |= pShwPage->Core.Key
1096 | (pGstPdpe->u & ~(X86_PDPE_PG_MASK | X86_PDPE_AVL_MASK | X86_PDPE_PCD | X86_PDPE_PWT));
1097
1098 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1099 return VINF_SUCCESS;
1100}
1101
1102
1103/**
1104 * Gets the SHADOW page directory pointer for the specified address (long mode).
1105 *
1106 * @returns VBox status.
1107 * @param pVM VM handle.
1108 * @param GCPtr The address.
1109 * @param ppPdpt Receives address of pdpt
1110 * @param ppPD Receives address of page directory
1111 */
1112DECLINLINE(int) pgmShwGetLongModePDPtr(PVM pVM, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPT *ppPdpt, PX86PDPAE *ppPD)
1113{
1114 PPGM pPGM = &pVM->pgm.s;
1115 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1116 PCX86PML4E pPml4e = pgmShwGetLongModePML4EPtr(pPGM, iPml4);
1117 AssertReturn(pPml4e, VERR_INTERNAL_ERROR);
1118 if (ppPml4e)
1119 *ppPml4e = (PX86PML4E)pPml4e;
1120
1121 Log4(("pgmShwGetLongModePDPtr %VGv (%VHv) %RX64\n", GCPtr, pPml4e, pPml4e->u));
1122
1123 if (!pPml4e->n.u1Present)
1124 return VERR_PAGE_MAP_LEVEL4_NOT_PRESENT;
1125
1126 PPGMPOOL pPool = pPGM->CTX_SUFF(pPool);
1127 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, pPml4e->u & X86_PML4E_PG_MASK);
1128 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1129
1130 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1131 PCX86PDPT pPdpt = *ppPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1132 if (!pPdpt->a[iPdPt].n.u1Present)
1133 return VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT;
1134
1135 pShwPage = pgmPoolGetPage(pPool, pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK);
1136 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1137
1138 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1139 return VINF_SUCCESS;
1140}
1141
1142
1143/**
1144 * Syncs the SHADOW EPT page directory pointer for the specified address. Allocates
1145 * backing pages in case the PDPT or PML4 entry is missing.
1146 *
1147 * @returns VBox status.
1148 * @param pVM VM handle.
1149 * @param GCPtr The address.
1150 * @param ppPdpt Receives address of pdpt
1151 * @param ppPD Receives address of page directory
1152 */
1153int pgmShwGetEPTPDPtr(PVM pVM, RTGCPTR64 GCPtr, PEPTPDPT *ppPdpt, PEPTPD *ppPD)
1154{
1155 PPGM pPGM = &pVM->pgm.s;
1156 const unsigned iPml4 = (GCPtr >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
1157 PPGMPOOL pPool = pPGM->CTX_SUFF(pPool);
1158 PEPTPML4 pPml4;
1159 PEPTPML4E pPml4e;
1160 PPGMPOOLPAGE pShwPage;
1161 int rc;
1162
1163 Assert(HWACCMIsNestedPagingActive(pVM));
1164
1165 pPml4 = (PEPTPML4)PGMPOOL_PAGE_2_PTR_BY_PGM(pPGM, pPGM->CTX_SUFF(pShwPageCR3));
1166 Assert(pPml4);
1167
1168 /* Allocate page directory pointer table if not present. */
1169 pPml4e = &pPml4->a[iPml4];
1170 if ( !pPml4e->n.u1Present
1171 && !(pPml4e->u & EPT_PML4E_PG_MASK))
1172 {
1173 Assert(!(pPml4e->u & EPT_PML4E_PG_MASK));
1174 RTGCPTR64 GCPml4 = (RTGCPTR64)iPml4 << EPT_PML4_SHIFT;
1175
1176 rc = pgmPoolAlloc(pVM, GCPml4, PGMPOOLKIND_EPT_PDPT_FOR_PHYS, PGMPOOL_IDX_NESTED_ROOT, iPml4, &pShwPage);
1177 AssertRCReturn(rc, rc);
1178 }
1179 else
1180 {
1181 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & EPT_PML4E_PG_MASK);
1182 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1183 }
1184 /* The PDPT was cached or created; hook it up now and fill with the default value. */
1185 pPml4e->u = pShwPage->Core.Key;
1186 pPml4e->n.u1Present = 1;
1187 pPml4e->n.u1Write = 1;
1188 pPml4e->n.u1Execute = 1;
1189
1190 const unsigned iPdPt = (GCPtr >> EPT_PDPT_SHIFT) & EPT_PDPT_MASK;
1191 PEPTPDPT pPdpt = (PEPTPDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1192 PEPTPDPTE pPdpe = &pPdpt->a[iPdPt];
1193
1194 if (ppPdpt)
1195 *ppPdpt = pPdpt;
1196
1197 /* Allocate page directory if not present. */
1198 if ( !pPdpe->n.u1Present
1199 && !(pPdpe->u & EPT_PDPTE_PG_MASK))
1200 {
1201 RTGCPTR64 GCPdPt = (RTGCPTR64)iPdPt << EPT_PDPT_SHIFT;
1202
1203 rc = pgmPoolAlloc(pVM, GCPdPt, PGMPOOLKIND_64BIT_PD_FOR_PHYS, pShwPage->idx, iPdPt, &pShwPage);
1204 AssertRCReturn(rc, rc);
1205 }
1206 else
1207 {
1208 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & EPT_PDPTE_PG_MASK);
1209 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1210 }
1211 /* The PD was cached or created; hook it up now and fill with the default value. */
1212 pPdpe->u = pShwPage->Core.Key;
1213 pPdpe->n.u1Present = 1;
1214 pPdpe->n.u1Write = 1;
1215 pPdpe->n.u1Execute = 1;
1216
1217 *ppPD = (PEPTPD)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1218 return VINF_SUCCESS;
1219}
1220
1221#endif /* IN_RC */
1222
1223/**
1224 * Gets effective Guest OS page information.
1225 *
1226 * When GCPtr is in a big page, the function will return as if it was a normal
1227 * 4KB page. If the need for distinguishing between big and normal page becomes
1228 * necessary at a later point, a PGMGstGetPage() will be created for that
1229 * purpose.
1230 *
1231 * @returns VBox status.
1232 * @param pVM VM Handle.
1233 * @param GCPtr Guest Context virtual address of the page.
1234 * @param pfFlags Where to store the flags. These are X86_PTE_*, even for big pages.
1235 * @param pGCPhys Where to store the GC physical address of the page.
1236 * This is page aligned. The fact that the
1237 */
1238VMMDECL(int) PGMGstGetPage(PVM pVM, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys)
1239{
1240 return PGM_GST_PFN(GetPage,pVM)(pVM, GCPtr, pfFlags, pGCPhys);
1241}
1242
1243
1244/**
1245 * Checks if the page is present.
1246 *
1247 * @returns true if the page is present.
1248 * @returns false if the page is not present.
1249 * @param pVM The VM handle.
1250 * @param GCPtr Address within the page.
1251 */
1252VMMDECL(bool) PGMGstIsPagePresent(PVM pVM, RTGCPTR GCPtr)
1253{
1254 int rc = PGMGstGetPage(pVM, GCPtr, NULL, NULL);
1255 return RT_SUCCESS(rc);
1256}
1257
1258
1259/**
1260 * Sets (replaces) the page flags for a range of pages in the guest's tables.
1261 *
1262 * @returns VBox status.
1263 * @param pVM VM handle.
1264 * @param GCPtr The address of the first page.
1265 * @param cb The size of the range in bytes.
1266 * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
1267 */
1268VMMDECL(int) PGMGstSetPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags)
1269{
1270 return PGMGstModifyPage(pVM, GCPtr, cb, fFlags, 0);
1271}
1272
1273
1274/**
1275 * Modify page flags for a range of pages in the guest's tables
1276 *
1277 * The existing flags are ANDed with the fMask and ORed with the fFlags.
1278 *
1279 * @returns VBox status code.
1280 * @param pVM VM handle.
1281 * @param GCPtr Virtual address of the first page in the range.
1282 * @param cb Size (in bytes) of the range to apply the modification to.
1283 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
1284 * @param fMask The AND mask - page flags X86_PTE_*, excluding the page mask of course.
1285 * Be very CAREFUL when ~'ing constants which could be 32-bit!
1286 */
1287VMMDECL(int) PGMGstModifyPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
1288{
1289 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,GstModifyPage), a);
1290
1291 /*
1292 * Validate input.
1293 */
1294 AssertMsg(!(fFlags & X86_PTE_PAE_PG_MASK), ("fFlags=%#llx\n", fFlags));
1295 Assert(cb);
1296
1297 LogFlow(("PGMGstModifyPage %RGv %d bytes fFlags=%08llx fMask=%08llx\n", GCPtr, cb, fFlags, fMask));
1298
1299 /*
1300 * Adjust input.
1301 */
1302 cb += GCPtr & PAGE_OFFSET_MASK;
1303 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
1304 GCPtr = (GCPtr & PAGE_BASE_GC_MASK);
1305
1306 /*
1307 * Call worker.
1308 */
1309 int rc = PGM_GST_PFN(ModifyPage, pVM)(pVM, GCPtr, cb, fFlags, fMask);
1310
1311 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,GstModifyPage), a);
1312 return rc;
1313}
1314
1315#ifdef IN_RING3
1316
1317/**
1318 * Performs the lazy mapping of the 32-bit guest PD.
1319 *
1320 * @returns Pointer to the mapping.
1321 * @param pPGM The PGM instance data.
1322 */
1323PX86PD pgmGstLazyMap32BitPD(PPGM pPGM)
1324{
1325 Assert(!pPGM->CTX_SUFF(pGst32BitPd));
1326 PVM pVM = PGM2VM(pPGM);
1327 pgmLock(pVM);
1328
1329 PPGMPAGE pPage = pgmPhysGetPage(pPGM, pPGM->GCPhysCR3);
1330 AssertReturn(pPage, NULL);
1331
1332 RTHCPTR HCPtrGuestCR3;
1333 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_PAGE_MASK, (void **)&HCPtrGuestCR3);
1334 AssertRCReturn(rc, NULL);
1335
1336 pPGM->pGst32BitPdR3 = (R3PTRTYPE(PX86PD))HCPtrGuestCR3;
1337# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1338 pPGM->pGst32BitPdR0 = (R0PTRTYPE(PX86PD))HCPtrGuestCR3;
1339# endif
1340
1341 pgmUnlock(pVM);
1342 return pPGM->CTX_SUFF(pGst32BitPd);
1343}
1344
1345
1346/**
1347 * Performs the lazy mapping of the PAE guest PDPT.
1348 *
1349 * @returns Pointer to the mapping.
1350 * @param pPGM The PGM instance data.
1351 */
1352PX86PDPT pgmGstLazyMapPaePDPT(PPGM pPGM)
1353{
1354 Assert(!pPGM->CTX_SUFF(pGstPaePdpt));
1355 PVM pVM = PGM2VM(pPGM);
1356 pgmLock(pVM);
1357
1358 PPGMPAGE pPage = pgmPhysGetPage(pPGM, pPGM->GCPhysCR3);
1359 AssertReturn(pPage, NULL);
1360
1361 RTHCPTR HCPtrGuestCR3;
1362 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_PAE_PAGE_MASK, (void **)&HCPtrGuestCR3);
1363 AssertRCReturn(rc, NULL);
1364
1365 pPGM->pGstPaePdptR3 = (R3PTRTYPE(PX86PDPT))HCPtrGuestCR3;
1366# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1367 pPGM->pGstPaePdptR0 = (R0PTRTYPE(PX86PDPT))HCPtrGuestCR3;
1368# endif
1369
1370 pgmUnlock(pVM);
1371 return pPGM->CTX_SUFF(pGstPaePdpt);
1372}
1373
1374#endif /* IN_RING3 */
1375
1376#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
1377/**
1378 * Performs the lazy mapping / updating of a PAE guest PD.
1379 *
1380 * @returns Pointer to the mapping.
1381 * @param pPGM The PGM instance data.
1382 * @param iPdpt Which PD entry to map (0..3).
1383 */
1384PX86PDPAE pgmGstLazyMapPaePD(PPGM pPGM, uint32_t iPdpt)
1385{
1386 PVM pVM = PGM2VM(pPGM);
1387 pgmLock(pVM);
1388
1389 PX86PDPT pGuestPDPT = pPGM->CTX_SUFF(pGstPaePdpt);
1390 Assert(pGuestPDPT);
1391 Assert(pGuestPDPT->a[iPdpt].n.u1Present);
1392 RTGCPHYS GCPhys = pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK;
1393 bool const fChanged = pPGM->aGCPhysGstPaePDs[iPdpt] != GCPhys;
1394
1395 PPGMPAGE pPage = pgmPhysGetPage(pPGM, GCPhys);
1396 if (RT_LIKELY(pPage))
1397 {
1398 int rc = VINF_SUCCESS;
1399 RTRCPTR RCPtr = NIL_RTRCPTR;
1400 RTHCPTR HCPtr = NIL_RTHCPTR;
1401#if !defined(IN_RC) && !defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
1402 rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &HCPtr);
1403 AssertRC(rc);
1404#endif
1405 if (RT_SUCCESS(rc) && fChanged)
1406 {
1407 RCPtr = (RTRCPTR)(RTRCUINTPTR)(pPGM->GCPtrCR3Mapping + (1 + iPdpt) * PAGE_SIZE);
1408 rc = PGMMap(pVM, (RTRCUINTPTR)RCPtr, PGM_PAGE_GET_HCPHYS(pPage), PAGE_SIZE, 0);
1409 }
1410 if (RT_SUCCESS(rc))
1411 {
1412 pPGM->apGstPaePDsR3[iPdpt] = (R3PTRTYPE(PX86PDPAE))HCPtr;
1413# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1414 pPGM->apGstPaePDsR0[iPdpt] = (R0PTRTYPE(PX86PDPAE))HCPtr;
1415# endif
1416 if (fChanged)
1417 {
1418 pPGM->aGCPhysGstPaePDs[iPdpt] = GCPhys;
1419 pPGM->apGstPaePDsRC[iPdpt] = (RCPTRTYPE(PX86PDPAE))RCPtr;
1420 }
1421
1422 pgmUnlock(pVM);
1423 return pPGM->CTX_SUFF(apGstPaePDs)[iPdpt];
1424 }
1425 }
1426
1427 /* Invalid page or some failure, invalidate the entry. */
1428 pPGM->aGCPhysGstPaePDs[iPdpt] = NIL_RTGCPHYS;
1429 pPGM->apGstPaePDsR3[iPdpt] = 0;
1430# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1431 pPGM->apGstPaePDsR0[iPdpt] = 0;
1432# endif
1433 pPGM->apGstPaePDsRC[iPdpt] = 0;
1434
1435 pgmUnlock(pVM);
1436 return NULL;
1437}
1438#endif /* !VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
1439
1440
1441#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R3
1442/**
1443 * Performs the lazy mapping of the 32-bit guest PD.
1444 *
1445 * @returns Pointer to the mapping.
1446 * @param pPGM The PGM instance data.
1447 */
1448PX86PML4 pgmGstLazyMapPml4(PPGM pPGM)
1449{
1450 Assert(!pPGM->CTX_SUFF(pGstAmd64Pml4));
1451 PVM pVM = PGM2VM(pPGM);
1452 pgmLock(pVM);
1453
1454 PPGMPAGE pPage = pgmPhysGetPage(pPGM, pPGM->GCPhysCR3);
1455 AssertReturn(pPage, NULL);
1456
1457 RTHCPTR HCPtrGuestCR3;
1458 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pPGM->GCPhysCR3 & X86_CR3_AMD64_PAGE_MASK, (void **)&HCPtrGuestCR3);
1459 AssertRCReturn(rc, NULL);
1460
1461 pPGM->pGstAmd64Pml4R3 = (R3PTRTYPE(PX86PML4))HCPtrGuestCR3;
1462# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
1463 pPGM->pGstAmd64Pml4R0 = (R0PTRTYPE(PX86PML4))HCPtrGuestCR3;
1464# endif
1465
1466 pgmUnlock(pVM);
1467 return pPGM->CTX_SUFF(pGstAmd64Pml4);
1468}
1469#endif /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R3 */
1470
1471
1472/**
1473 * Gets the specified page directory pointer table entry.
1474 *
1475 * @returns PDP entry
1476 * @param pPGM Pointer to the PGM instance data.
1477 * @param iPdpt PDPT index
1478 */
1479VMMDECL(X86PDPE) PGMGstGetPaePDPtr(PVM pVM, unsigned iPdpt)
1480{
1481 Assert(iPdpt <= 3);
1482 return pgmGstGetPaePDPTPtr(&pVM->pgm.s)->a[iPdpt & 3];
1483}
1484
1485
1486/**
1487 * Gets the current CR3 register value for the shadow memory context.
1488 * @returns CR3 value.
1489 * @param pVM The VM handle.
1490 */
1491VMMDECL(RTHCPHYS) PGMGetHyperCR3(PVM pVM)
1492{
1493 PPGMPOOLPAGE pPoolPage = pVM->pgm.s.CTX_SUFF(pShwPageCR3);
1494 AssertPtrReturn(pPoolPage, 0);
1495 return pPoolPage->Core.Key;
1496}
1497
1498
1499/**
1500 * Gets the current CR3 register value for the nested memory context.
1501 * @returns CR3 value.
1502 * @param pVM The VM handle.
1503 */
1504VMMDECL(RTHCPHYS) PGMGetNestedCR3(PVM pVM, PGMMODE enmShadowMode)
1505{
1506 Assert(pVM->pgm.s.CTX_SUFF(pShwPageCR3));
1507 return pVM->pgm.s.CTX_SUFF(pShwPageCR3)->Core.Key;
1508}
1509
1510
1511/**
1512 * Gets the CR3 register value for the 32-Bit shadow memory context.
1513 * @returns CR3 value.
1514 * @param pVM The VM handle.
1515 */
1516VMMDECL(RTHCPHYS) PGMGetHyper32BitCR3(PVM pVM)
1517{
1518 Assert(pVM->pgm.s.CTX_SUFF(pShwPageCR3));
1519 return pVM->pgm.s.CTX_SUFF(pShwPageCR3)->Core.Key;
1520}
1521
1522
1523/**
1524 * Gets the CR3 register value for the PAE shadow memory context.
1525 * @returns CR3 value.
1526 * @param pVM The VM handle.
1527 */
1528VMMDECL(RTHCPHYS) PGMGetHyperPaeCR3(PVM pVM)
1529{
1530 Assert(pVM->pgm.s.CTX_SUFF(pShwPageCR3));
1531 return pVM->pgm.s.CTX_SUFF(pShwPageCR3)->Core.Key;
1532}
1533
1534
1535/**
1536 * Gets the CR3 register value for the AMD64 shadow memory context.
1537 * @returns CR3 value.
1538 * @param pVM The VM handle.
1539 */
1540VMMDECL(RTHCPHYS) PGMGetHyperAmd64CR3(PVM pVM)
1541{
1542 Assert(pVM->pgm.s.CTX_SUFF(pShwPageCR3));
1543 return pVM->pgm.s.CTX_SUFF(pShwPageCR3)->Core.Key;
1544}
1545
1546
1547/**
1548 * Gets the current CR3 register value for the HC intermediate memory context.
1549 * @returns CR3 value.
1550 * @param pVM The VM handle.
1551 */
1552VMMDECL(RTHCPHYS) PGMGetInterHCCR3(PVM pVM)
1553{
1554 switch (pVM->pgm.s.enmHostMode)
1555 {
1556 case SUPPAGINGMODE_32_BIT:
1557 case SUPPAGINGMODE_32_BIT_GLOBAL:
1558 return pVM->pgm.s.HCPhysInterPD;
1559
1560 case SUPPAGINGMODE_PAE:
1561 case SUPPAGINGMODE_PAE_GLOBAL:
1562 case SUPPAGINGMODE_PAE_NX:
1563 case SUPPAGINGMODE_PAE_GLOBAL_NX:
1564 return pVM->pgm.s.HCPhysInterPaePDPT;
1565
1566 case SUPPAGINGMODE_AMD64:
1567 case SUPPAGINGMODE_AMD64_GLOBAL:
1568 case SUPPAGINGMODE_AMD64_NX:
1569 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
1570 return pVM->pgm.s.HCPhysInterPaePDPT;
1571
1572 default:
1573 AssertMsgFailed(("enmHostMode=%d\n", pVM->pgm.s.enmHostMode));
1574 return ~0;
1575 }
1576}
1577
1578
1579/**
1580 * Gets the current CR3 register value for the RC intermediate memory context.
1581 * @returns CR3 value.
1582 * @param pVM The VM handle.
1583 */
1584VMMDECL(RTHCPHYS) PGMGetInterRCCR3(PVM pVM)
1585{
1586 switch (pVM->pgm.s.enmShadowMode)
1587 {
1588 case PGMMODE_32_BIT:
1589 return pVM->pgm.s.HCPhysInterPD;
1590
1591 case PGMMODE_PAE:
1592 case PGMMODE_PAE_NX:
1593 return pVM->pgm.s.HCPhysInterPaePDPT;
1594
1595 case PGMMODE_AMD64:
1596 case PGMMODE_AMD64_NX:
1597 return pVM->pgm.s.HCPhysInterPaePML4;
1598
1599 case PGMMODE_EPT:
1600 case PGMMODE_NESTED:
1601 return 0; /* not relevant */
1602
1603 default:
1604 AssertMsgFailed(("enmShadowMode=%d\n", pVM->pgm.s.enmShadowMode));
1605 return ~0;
1606 }
1607}
1608
1609
1610/**
1611 * Gets the CR3 register value for the 32-Bit intermediate memory context.
1612 * @returns CR3 value.
1613 * @param pVM The VM handle.
1614 */
1615VMMDECL(RTHCPHYS) PGMGetInter32BitCR3(PVM pVM)
1616{
1617 return pVM->pgm.s.HCPhysInterPD;
1618}
1619
1620
1621/**
1622 * Gets the CR3 register value for the PAE intermediate memory context.
1623 * @returns CR3 value.
1624 * @param pVM The VM handle.
1625 */
1626VMMDECL(RTHCPHYS) PGMGetInterPaeCR3(PVM pVM)
1627{
1628 return pVM->pgm.s.HCPhysInterPaePDPT;
1629}
1630
1631
1632/**
1633 * Gets the CR3 register value for the AMD64 intermediate memory context.
1634 * @returns CR3 value.
1635 * @param pVM The VM handle.
1636 */
1637VMMDECL(RTHCPHYS) PGMGetInterAmd64CR3(PVM pVM)
1638{
1639 return pVM->pgm.s.HCPhysInterPaePML4;
1640}
1641
1642
1643/**
1644 * Performs and schedules necessary updates following a CR3 load or reload.
1645 *
1646 * This will normally involve mapping the guest PD or nPDPT
1647 *
1648 * @returns VBox status code.
1649 * @retval VINF_PGM_SYNC_CR3 if monitoring requires a CR3 sync. This can
1650 * safely be ignored and overridden since the FF will be set too then.
1651 * @param pVM VM handle.
1652 * @param cr3 The new cr3.
1653 * @param fGlobal Indicates whether this is a global flush or not.
1654 */
1655VMMDECL(int) PGMFlushTLB(PVM pVM, uint64_t cr3, bool fGlobal)
1656{
1657 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLB), a);
1658
1659 /*
1660 * Always flag the necessary updates; necessary for hardware acceleration
1661 */
1662 /** @todo optimize this, it shouldn't always be necessary. */
1663 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL);
1664 if (fGlobal)
1665 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
1666 LogFlow(("PGMFlushTLB: cr3=%RX64 OldCr3=%RX64 fGlobal=%d\n", cr3, pVM->pgm.s.GCPhysCR3, fGlobal));
1667
1668 /*
1669 * Remap the CR3 content and adjust the monitoring if CR3 was actually changed.
1670 */
1671 int rc = VINF_SUCCESS;
1672 RTGCPHYS GCPhysCR3;
1673 switch (pVM->pgm.s.enmGuestMode)
1674 {
1675 case PGMMODE_PAE:
1676 case PGMMODE_PAE_NX:
1677 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
1678 break;
1679 case PGMMODE_AMD64:
1680 case PGMMODE_AMD64_NX:
1681 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
1682 break;
1683 default:
1684 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
1685 break;
1686 }
1687
1688 if (pVM->pgm.s.GCPhysCR3 != GCPhysCR3)
1689 {
1690 RTGCPHYS GCPhysOldCR3 = pVM->pgm.s.GCPhysCR3;
1691 pVM->pgm.s.GCPhysCR3 = GCPhysCR3;
1692 rc = PGM_BTH_PFN(MapCR3, pVM)(pVM, GCPhysCR3);
1693 if (RT_LIKELY(rc == VINF_SUCCESS))
1694 {
1695 if (!pVM->pgm.s.fMappingsFixed)
1696 {
1697 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1698 }
1699 }
1700 else
1701 {
1702 AssertMsg(rc == VINF_PGM_SYNC_CR3, ("%Rrc\n", rc));
1703 Assert(VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL | VM_FF_PGM_SYNC_CR3));
1704 pVM->pgm.s.GCPhysCR3 = GCPhysOldCR3;
1705 pVM->pgm.s.fSyncFlags |= PGM_SYNC_MAP_CR3;
1706 if (!pVM->pgm.s.fMappingsFixed)
1707 pVM->pgm.s.fSyncFlags |= PGM_SYNC_MONITOR_CR3;
1708 }
1709
1710 if (fGlobal)
1711 STAM_COUNTER_INC(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLBNewCR3Global));
1712 else
1713 STAM_COUNTER_INC(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLBNewCR3));
1714 }
1715 else
1716 {
1717 /*
1718 * Check if we have a pending update of the CR3 monitoring.
1719 */
1720 if (pVM->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
1721 {
1722 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1723 Assert(!pVM->pgm.s.fMappingsFixed);
1724 }
1725 if (fGlobal)
1726 STAM_COUNTER_INC(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLBSameCR3Global));
1727 else
1728 STAM_COUNTER_INC(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLBSameCR3));
1729 }
1730
1731 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLB), a);
1732 return rc;
1733}
1734
1735
1736/**
1737 * Performs and schedules necessary updates following a CR3 load or reload when
1738 * using nested or extended paging.
1739 *
1740 * This API is an alterantive to PDMFlushTLB that avoids actually flushing the
1741 * TLB and triggering a SyncCR3.
1742 *
1743 * This will normally involve mapping the guest PD or nPDPT
1744 *
1745 * @returns VBox status code.
1746 * @retval VINF_SUCCESS.
1747 * @retval (If applied when not in nested mode: VINF_PGM_SYNC_CR3 if monitoring
1748 * requires a CR3 sync. This can safely be ignored and overridden since
1749 * the FF will be set too then.)
1750 * @param pVM VM handle.
1751 * @param cr3 The new cr3.
1752 */
1753VMMDECL(int) PGMUpdateCR3(PVM pVM, uint64_t cr3)
1754{
1755 LogFlow(("PGMUpdateCR3: cr3=%RX64 OldCr3=%RX64\n", cr3, pVM->pgm.s.GCPhysCR3));
1756
1757 /* We assume we're only called in nested paging mode. */
1758 Assert(pVM->pgm.s.fMappingsFixed);
1759 Assert(!(pVM->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3));
1760 Assert(HWACCMIsNestedPagingActive(pVM) || pVM->pgm.s.enmShadowMode == PGMMODE_EPT);
1761
1762 /*
1763 * Remap the CR3 content and adjust the monitoring if CR3 was actually changed.
1764 */
1765 int rc = VINF_SUCCESS;
1766 RTGCPHYS GCPhysCR3;
1767 switch (pVM->pgm.s.enmGuestMode)
1768 {
1769 case PGMMODE_PAE:
1770 case PGMMODE_PAE_NX:
1771 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
1772 break;
1773 case PGMMODE_AMD64:
1774 case PGMMODE_AMD64_NX:
1775 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
1776 break;
1777 default:
1778 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
1779 break;
1780 }
1781 if (pVM->pgm.s.GCPhysCR3 != GCPhysCR3)
1782 {
1783 pVM->pgm.s.GCPhysCR3 = GCPhysCR3;
1784 rc = PGM_BTH_PFN(MapCR3, pVM)(pVM, GCPhysCR3);
1785 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. */
1786 }
1787 return rc;
1788}
1789
1790
1791/**
1792 * Synchronize the paging structures.
1793 *
1794 * This function is called in response to the VM_FF_PGM_SYNC_CR3 and
1795 * VM_FF_PGM_SYNC_CR3_NONGLOBAL. Those two force action flags are set
1796 * in several places, most importantly whenever the CR3 is loaded.
1797 *
1798 * @returns VBox status code.
1799 * @param pVM The virtual machine.
1800 * @param cr0 Guest context CR0 register
1801 * @param cr3 Guest context CR3 register
1802 * @param cr4 Guest context CR4 register
1803 * @param fGlobal Including global page directories or not
1804 */
1805VMMDECL(int) PGMSyncCR3(PVM pVM, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal)
1806{
1807 int rc;
1808
1809 /*
1810 * We might be called when we shouldn't.
1811 *
1812 * The mode switching will ensure that the PD is resynced
1813 * after every mode switch. So, if we find ourselves here
1814 * when in protected or real mode we can safely disable the
1815 * FF and return immediately.
1816 */
1817 if (pVM->pgm.s.enmGuestMode <= PGMMODE_PROTECTED)
1818 {
1819 Assert((cr0 & (X86_CR0_PG | X86_CR0_PE)) != (X86_CR0_PG | X86_CR0_PE));
1820 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3);
1821 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL);
1822 return VINF_SUCCESS;
1823 }
1824
1825 /* If global pages are not supported, then all flushes are global. */
1826 if (!(cr4 & X86_CR4_PGE))
1827 fGlobal = true;
1828 LogFlow(("PGMSyncCR3: cr0=%RX64 cr3=%RX64 cr4=%RX64 fGlobal=%d[%d,%d]\n", cr0, cr3, cr4, fGlobal,
1829 VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3), VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL)));
1830
1831#ifdef PGMPOOL_WITH_MONITORING
1832 /*
1833 * The pool may have pending stuff and even require a return to ring-3 to
1834 * clear the whole thing.
1835 */
1836 rc = pgmPoolSyncCR3(pVM);
1837 if (rc != VINF_SUCCESS)
1838 return rc;
1839#endif
1840
1841 /*
1842 * Check if we need to finish an aborted MapCR3 call (see PGMFlushTLB).
1843 * This should be done before SyncCR3.
1844 */
1845 if (pVM->pgm.s.fSyncFlags & PGM_SYNC_MAP_CR3)
1846 {
1847 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MAP_CR3;
1848
1849 RTGCPHYS GCPhysCR3Old = pVM->pgm.s.GCPhysCR3;
1850 RTGCPHYS GCPhysCR3;
1851 switch (pVM->pgm.s.enmGuestMode)
1852 {
1853 case PGMMODE_PAE:
1854 case PGMMODE_PAE_NX:
1855 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
1856 break;
1857 case PGMMODE_AMD64:
1858 case PGMMODE_AMD64_NX:
1859 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
1860 break;
1861 default:
1862 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
1863 break;
1864 }
1865
1866 if (pVM->pgm.s.GCPhysCR3 != GCPhysCR3)
1867 {
1868 pVM->pgm.s.GCPhysCR3 = GCPhysCR3;
1869 rc = PGM_BTH_PFN(MapCR3, pVM)(pVM, GCPhysCR3);
1870 }
1871#ifdef IN_RING3
1872 if (rc == VINF_PGM_SYNC_CR3)
1873 rc = pgmPoolSyncCR3(pVM);
1874#else
1875 if (rc == VINF_PGM_SYNC_CR3)
1876 {
1877 pVM->pgm.s.GCPhysCR3 = GCPhysCR3Old;
1878 return rc;
1879 }
1880#endif
1881 AssertRCReturn(rc, rc);
1882 AssertRCSuccessReturn(rc, VERR_INTERNAL_ERROR);
1883 }
1884
1885 /*
1886 * Let the 'Bth' function do the work and we'll just keep track of the flags.
1887 */
1888 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
1889 rc = PGM_BTH_PFN(SyncCR3, pVM)(pVM, cr0, cr3, cr4, fGlobal);
1890 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
1891 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 || RT_FAILURE(rc), ("rc=%Rrc\n", rc));
1892 if (rc == VINF_SUCCESS)
1893 {
1894 if (!(pVM->pgm.s.fSyncFlags & PGM_SYNC_ALWAYS))
1895 {
1896 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3);
1897 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL);
1898 }
1899
1900 /*
1901 * Check if we have a pending update of the CR3 monitoring.
1902 */
1903 if (pVM->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
1904 {
1905 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1906 Assert(!pVM->pgm.s.fMappingsFixed);
1907 }
1908 }
1909
1910 /*
1911 * Now flush the CR3 (guest context).
1912 */
1913 if (rc == VINF_SUCCESS)
1914 PGM_INVL_GUEST_TLBS();
1915 return rc;
1916}
1917
1918
1919/**
1920 * Called whenever CR0 or CR4 in a way which may change
1921 * the paging mode.
1922 *
1923 * @returns VBox status code, with the following informational code for
1924 * VM scheduling.
1925 * @retval VINF_SUCCESS if the was no change, or it was successfully dealt with.
1926 * @retval VINF_PGM_CHANGE_MODE if we're in RC or R0 and the mode changes.
1927 * (I.e. not in R3.)
1928 * @retval VINF_EM_SUSPEND or VINF_EM_OFF on a fatal runtime error. (R3 only)
1929 *
1930 * @param pVM VM handle.
1931 * @param cr0 The new cr0.
1932 * @param cr4 The new cr4.
1933 * @param efer The new extended feature enable register.
1934 */
1935VMMDECL(int) PGMChangeMode(PVM pVM, uint64_t cr0, uint64_t cr4, uint64_t efer)
1936{
1937 PGMMODE enmGuestMode;
1938
1939 /*
1940 * Calc the new guest mode.
1941 */
1942 if (!(cr0 & X86_CR0_PE))
1943 enmGuestMode = PGMMODE_REAL;
1944 else if (!(cr0 & X86_CR0_PG))
1945 enmGuestMode = PGMMODE_PROTECTED;
1946 else if (!(cr4 & X86_CR4_PAE))
1947 enmGuestMode = PGMMODE_32_BIT;
1948 else if (!(efer & MSR_K6_EFER_LME))
1949 {
1950 if (!(efer & MSR_K6_EFER_NXE))
1951 enmGuestMode = PGMMODE_PAE;
1952 else
1953 enmGuestMode = PGMMODE_PAE_NX;
1954 }
1955 else
1956 {
1957 if (!(efer & MSR_K6_EFER_NXE))
1958 enmGuestMode = PGMMODE_AMD64;
1959 else
1960 enmGuestMode = PGMMODE_AMD64_NX;
1961 }
1962
1963 /*
1964 * Did it change?
1965 */
1966 if (pVM->pgm.s.enmGuestMode == enmGuestMode)
1967 return VINF_SUCCESS;
1968
1969 /* Flush the TLB */
1970 PGM_INVL_GUEST_TLBS();
1971
1972#ifdef IN_RING3
1973 return PGMR3ChangeMode(pVM, enmGuestMode);
1974#else
1975 LogFlow(("PGMChangeMode: returns VINF_PGM_CHANGE_MODE.\n"));
1976 return VINF_PGM_CHANGE_MODE;
1977#endif
1978}
1979
1980
1981/**
1982 * Gets the current guest paging mode.
1983 *
1984 * If you just need the CPU mode (real/protected/long), use CPUMGetGuestMode().
1985 *
1986 * @returns The current paging mode.
1987 * @param pVM The VM handle.
1988 */
1989VMMDECL(PGMMODE) PGMGetGuestMode(PVM pVM)
1990{
1991 return pVM->pgm.s.enmGuestMode;
1992}
1993
1994
1995/**
1996 * Gets the current shadow paging mode.
1997 *
1998 * @returns The current paging mode.
1999 * @param pVM The VM handle.
2000 */
2001VMMDECL(PGMMODE) PGMGetShadowMode(PVM pVM)
2002{
2003 return pVM->pgm.s.enmShadowMode;
2004}
2005
2006/**
2007 * Gets the current host paging mode.
2008 *
2009 * @returns The current paging mode.
2010 * @param pVM The VM handle.
2011 */
2012VMMDECL(PGMMODE) PGMGetHostMode(PVM pVM)
2013{
2014 switch (pVM->pgm.s.enmHostMode)
2015 {
2016 case SUPPAGINGMODE_32_BIT:
2017 case SUPPAGINGMODE_32_BIT_GLOBAL:
2018 return PGMMODE_32_BIT;
2019
2020 case SUPPAGINGMODE_PAE:
2021 case SUPPAGINGMODE_PAE_GLOBAL:
2022 return PGMMODE_PAE;
2023
2024 case SUPPAGINGMODE_PAE_NX:
2025 case SUPPAGINGMODE_PAE_GLOBAL_NX:
2026 return PGMMODE_PAE_NX;
2027
2028 case SUPPAGINGMODE_AMD64:
2029 case SUPPAGINGMODE_AMD64_GLOBAL:
2030 return PGMMODE_AMD64;
2031
2032 case SUPPAGINGMODE_AMD64_NX:
2033 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
2034 return PGMMODE_AMD64_NX;
2035
2036 default: AssertMsgFailed(("enmHostMode=%d\n", pVM->pgm.s.enmHostMode)); break;
2037 }
2038
2039 return PGMMODE_INVALID;
2040}
2041
2042
2043/**
2044 * Get mode name.
2045 *
2046 * @returns read-only name string.
2047 * @param enmMode The mode which name is desired.
2048 */
2049VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode)
2050{
2051 switch (enmMode)
2052 {
2053 case PGMMODE_REAL: return "Real";
2054 case PGMMODE_PROTECTED: return "Protected";
2055 case PGMMODE_32_BIT: return "32-bit";
2056 case PGMMODE_PAE: return "PAE";
2057 case PGMMODE_PAE_NX: return "PAE+NX";
2058 case PGMMODE_AMD64: return "AMD64";
2059 case PGMMODE_AMD64_NX: return "AMD64+NX";
2060 case PGMMODE_NESTED: return "Nested";
2061 case PGMMODE_EPT: return "EPT";
2062 default: return "unknown mode value";
2063 }
2064}
2065
2066
2067/**
2068 * Acquire the PGM lock.
2069 *
2070 * @returns VBox status code
2071 * @param pVM The VM to operate on.
2072 */
2073int pgmLock(PVM pVM)
2074{
2075 int rc = PDMCritSectEnter(&pVM->pgm.s.CritSect, VERR_SEM_BUSY);
2076#ifdef IN_RC
2077 if (rc == VERR_SEM_BUSY)
2078 rc = VMMGCCallHost(pVM, VMMCALLHOST_PGM_LOCK, 0);
2079#elif defined(IN_RING0)
2080 if (rc == VERR_SEM_BUSY)
2081 rc = VMMR0CallHost(pVM, VMMCALLHOST_PGM_LOCK, 0);
2082#endif
2083 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
2084 return rc;
2085}
2086
2087
2088/**
2089 * Release the PGM lock.
2090 *
2091 * @returns VBox status code
2092 * @param pVM The VM to operate on.
2093 */
2094void pgmUnlock(PVM pVM)
2095{
2096 PDMCritSectLeave(&pVM->pgm.s.CritSect);
2097}
2098
2099#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
2100
2101/**
2102 * Temporarily maps one guest page specified by GC physical address.
2103 * These pages must have a physical mapping in HC, i.e. they cannot be MMIO pages.
2104 *
2105 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
2106 * reused after 8 mappings (or perhaps a few more if you score with the cache).
2107 *
2108 * @returns VBox status.
2109 * @param pVM VM handle.
2110 * @param GCPhys GC Physical address of the page.
2111 * @param ppv Where to store the address of the mapping.
2112 */
2113VMMDECL(int) PGMDynMapGCPage(PVM pVM, RTGCPHYS GCPhys, void **ppv)
2114{
2115 AssertMsg(!(GCPhys & PAGE_OFFSET_MASK), ("GCPhys=%RGp\n", GCPhys));
2116
2117 /*
2118 * Get the ram range.
2119 */
2120 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
2121 while (pRam && GCPhys - pRam->GCPhys >= pRam->cb)
2122 pRam = pRam->CTX_SUFF(pNext);
2123 if (!pRam)
2124 {
2125 AssertMsgFailed(("Invalid physical address %RGp!\n", GCPhys));
2126 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
2127 }
2128
2129 /*
2130 * Pass it on to PGMDynMapHCPage.
2131 */
2132 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT]);
2133 //Log(("PGMDynMapGCPage: GCPhys=%RGp HCPhys=%RHp\n", GCPhys, HCPhys));
2134#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2135 pgmR0DynMapHCPageInlined(&pVM->pgm.s, HCPhys, ppv);
2136#else
2137 PGMDynMapHCPage(pVM, HCPhys, ppv);
2138#endif
2139 return VINF_SUCCESS;
2140}
2141
2142
2143/**
2144 * Temporarily maps one guest page specified by unaligned GC physical address.
2145 * These pages must have a physical mapping in HC, i.e. they cannot be MMIO pages.
2146 *
2147 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
2148 * reused after 8 mappings (or perhaps a few more if you score with the cache).
2149 *
2150 * The caller is aware that only the speicifed page is mapped and that really bad things
2151 * will happen if writing beyond the page!
2152 *
2153 * @returns VBox status.
2154 * @param pVM VM handle.
2155 * @param GCPhys GC Physical address within the page to be mapped.
2156 * @param ppv Where to store the address of the mapping address corresponding to GCPhys.
2157 */
2158VMMDECL(int) PGMDynMapGCPageOff(PVM pVM, RTGCPHYS GCPhys, void **ppv)
2159{
2160 /*
2161 * Get the ram range.
2162 */
2163 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
2164 while (pRam && GCPhys - pRam->GCPhys >= pRam->cb)
2165 pRam = pRam->CTX_SUFF(pNext);
2166 if (!pRam)
2167 {
2168 AssertMsgFailed(("Invalid physical address %RGp!\n", GCPhys));
2169 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
2170 }
2171
2172 /*
2173 * Pass it on to PGMDynMapHCPage.
2174 */
2175 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT]);
2176#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2177 pgmR0DynMapHCPageInlined(&pVM->pgm.s, HCPhys, ppv);
2178#else
2179 PGMDynMapHCPage(pVM, HCPhys, ppv);
2180#endif
2181 *ppv = (void *)((uintptr_t)*ppv | (GCPhys & PAGE_OFFSET_MASK));
2182 return VINF_SUCCESS;
2183}
2184
2185# ifdef IN_RC
2186
2187/**
2188 * Temporarily maps one host page specified by HC physical address.
2189 *
2190 * Be WARNED that the dynamic page mapping area is small, 16 pages, thus the space is
2191 * reused after 16 mappings (or perhaps a few more if you score with the cache).
2192 *
2193 * @returns VINF_SUCCESS, will bail out to ring-3 on failure.
2194 * @param pVM VM handle.
2195 * @param HCPhys HC Physical address of the page.
2196 * @param ppv Where to store the address of the mapping. This is the
2197 * address of the PAGE not the exact address corresponding
2198 * to HCPhys. Use PGMDynMapHCPageOff if you care for the
2199 * page offset.
2200 */
2201VMMDECL(int) PGMDynMapHCPage(PVM pVM, RTHCPHYS HCPhys, void **ppv)
2202{
2203 AssertMsg(!(HCPhys & PAGE_OFFSET_MASK), ("HCPhys=%RHp\n", HCPhys));
2204
2205 /*
2206 * Check the cache.
2207 */
2208 register unsigned iCache;
2209 for (iCache = 0;iCache < RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache);iCache++)
2210 {
2211 static const uint8_t au8Trans[MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT][RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache)] =
2212 {
2213 { 0, 9, 10, 11, 12, 13, 14, 15},
2214 { 0, 1, 10, 11, 12, 13, 14, 15},
2215 { 0, 1, 2, 11, 12, 13, 14, 15},
2216 { 0, 1, 2, 3, 12, 13, 14, 15},
2217 { 0, 1, 2, 3, 4, 13, 14, 15},
2218 { 0, 1, 2, 3, 4, 5, 14, 15},
2219 { 0, 1, 2, 3, 4, 5, 6, 15},
2220 { 0, 1, 2, 3, 4, 5, 6, 7},
2221 { 8, 1, 2, 3, 4, 5, 6, 7},
2222 { 8, 9, 2, 3, 4, 5, 6, 7},
2223 { 8, 9, 10, 3, 4, 5, 6, 7},
2224 { 8, 9, 10, 11, 4, 5, 6, 7},
2225 { 8, 9, 10, 11, 12, 5, 6, 7},
2226 { 8, 9, 10, 11, 12, 13, 6, 7},
2227 { 8, 9, 10, 11, 12, 13, 14, 7},
2228 { 8, 9, 10, 11, 12, 13, 14, 15},
2229 };
2230 AssertCompile(RT_ELEMENTS(au8Trans) == 16);
2231 AssertCompile(RT_ELEMENTS(au8Trans[0]) == 8);
2232
2233 if (pVM->pgm.s.aHCPhysDynPageMapCache[iCache] == HCPhys)
2234 {
2235 int iPage = au8Trans[pVM->pgm.s.iDynPageMapLast][iCache];
2236
2237 /* 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) */
2238 if ((pVM->pgm.s.paDynPageMap32BitPTEsGC[iPage].u & X86_PTE_PG_MASK) == HCPhys)
2239 {
2240 void *pv = pVM->pgm.s.pbDynPageMapBaseGC + (iPage << PAGE_SHIFT);
2241 *ppv = pv;
2242 STAM_COUNTER_INC(&pVM->pgm.s.StatRCDynMapCacheHits);
2243 Log4(("PGMGCDynMapHCPage: HCPhys=%RHp pv=%p iPage=%d iCache=%d\n", HCPhys, pv, iPage, iCache));
2244 return VINF_SUCCESS;
2245 }
2246 else
2247 LogFlow(("Out of sync entry %d\n", iPage));
2248 }
2249 }
2250 AssertCompile(RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) == 8);
2251 AssertCompile((MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT) == 16);
2252 STAM_COUNTER_INC(&pVM->pgm.s.StatRCDynMapCacheMisses);
2253
2254 /*
2255 * Update the page tables.
2256 */
2257 register unsigned iPage = pVM->pgm.s.iDynPageMapLast;
2258 unsigned i;
2259 for (i=0;i<(MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT);i++)
2260 {
2261 pVM->pgm.s.iDynPageMapLast = iPage = (iPage + 1) & ((MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT) - 1);
2262 if (!pVM->pgm.s.aLockedDynPageMapCache[iPage])
2263 break;
2264 iPage++;
2265 }
2266 AssertRelease(i != (MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT));
2267
2268 pVM->pgm.s.aHCPhysDynPageMapCache[iPage & (RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) - 1)] = HCPhys;
2269 pVM->pgm.s.paDynPageMap32BitPTEsGC[iPage].u = (uint32_t)HCPhys | X86_PTE_P | X86_PTE_A | X86_PTE_D;
2270 pVM->pgm.s.paDynPageMapPaePTEsGC[iPage].u = HCPhys | X86_PTE_P | X86_PTE_A | X86_PTE_D;
2271 pVM->pgm.s.aLockedDynPageMapCache[iPage] = 0;
2272
2273 void *pv = pVM->pgm.s.pbDynPageMapBaseGC + (iPage << PAGE_SHIFT);
2274 *ppv = pv;
2275 ASMInvalidatePage(pv);
2276 Log4(("PGMGCDynMapHCPage: HCPhys=%RHp pv=%p iPage=%d\n", HCPhys, pv, iPage));
2277 return VINF_SUCCESS;
2278}
2279
2280
2281/**
2282 * Temporarily lock a dynamic page to prevent it from being reused.
2283 *
2284 * @param pVM VM handle.
2285 * @param GCPage GC address of page
2286 */
2287VMMDECL(void) PGMDynLockHCPage(PVM pVM, RCPTRTYPE(uint8_t *) GCPage)
2288{
2289 unsigned iPage;
2290
2291 Assert(GCPage >= pVM->pgm.s.pbDynPageMapBaseGC && GCPage < (pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE));
2292 iPage = ((uintptr_t)(GCPage - pVM->pgm.s.pbDynPageMapBaseGC)) >> PAGE_SHIFT;
2293 ASMAtomicIncU32(&pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2294 Log4(("PGMDynLockHCPage %RRv iPage=%d\n", GCPage, iPage));
2295}
2296
2297
2298/**
2299 * Unlock a dynamic page
2300 *
2301 * @param pVM VM handle.
2302 * @param GCPage GC address of page
2303 */
2304VMMDECL(void) PGMDynUnlockHCPage(PVM pVM, RCPTRTYPE(uint8_t *) GCPage)
2305{
2306 unsigned iPage;
2307
2308 AssertCompile(RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) == RT_ELEMENTS(pVM->pgm.s.aLockedDynPageMapCache));
2309
2310 Assert(GCPage >= pVM->pgm.s.pbDynPageMapBaseGC && GCPage < (pVM->pgm.s.pbDynPageMapBaseGC + MM_HYPER_DYNAMIC_SIZE));
2311 iPage = ((uintptr_t)(GCPage - pVM->pgm.s.pbDynPageMapBaseGC)) >> PAGE_SHIFT;
2312 Assert(pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2313 ASMAtomicDecU32(&pVM->pgm.s.aLockedDynPageMapCache[iPage]);
2314 Log4(("PGMDynUnlockHCPage %RRv iPage=%d\n", GCPage, iPage));
2315}
2316
2317
2318# ifdef VBOX_STRICT
2319/**
2320 * Check for lock leaks.
2321 *
2322 * @param pVM VM handle.
2323 */
2324VMMDECL(void) PGMDynCheckLocks(PVM pVM)
2325{
2326 for (unsigned i=0;i<RT_ELEMENTS(pVM->pgm.s.aLockedDynPageMapCache);i++)
2327 Assert(!pVM->pgm.s.aLockedDynPageMapCache[i]);
2328}
2329# endif /* VBOX_STRICT */
2330
2331# endif /* IN_RC */
2332#endif /* IN_RC || VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
2333
2334#if !defined(IN_R0) || defined(LOG_ENABLED)
2335
2336/** Format handler for PGMPAGE.
2337 * @copydoc FNRTSTRFORMATTYPE */
2338static DECLCALLBACK(size_t) pgmFormatTypeHandlerPage(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2339 const char *pszType, void const *pvValue,
2340 int cchWidth, int cchPrecision, unsigned fFlags,
2341 void *pvUser)
2342{
2343 size_t cch;
2344 PCPGMPAGE pPage = (PCPGMPAGE)pvValue;
2345 if (VALID_PTR(pPage))
2346 {
2347 char szTmp[64+80];
2348
2349 cch = 0;
2350
2351 /* The single char state stuff. */
2352 static const char s_achPageStates[4] = { 'Z', 'A', 'W', 'S' };
2353 szTmp[cch++] = s_achPageStates[PGM_PAGE_GET_STATE(pPage)];
2354
2355#define IS_PART_INCLUDED(lvl) ( !(fFlags & RTSTR_F_PRECISION) || cchPrecision == (lvl) || cchPrecision >= (lvl)+10 )
2356 if (IS_PART_INCLUDED(5))
2357 {
2358 static const char s_achHandlerStates[4] = { '-', 't', 'w', 'a' };
2359 szTmp[cch++] = s_achHandlerStates[PGM_PAGE_GET_HNDL_PHYS_STATE(pPage)];
2360 szTmp[cch++] = s_achHandlerStates[PGM_PAGE_GET_HNDL_VIRT_STATE(pPage)];
2361 }
2362
2363 /* The type. */
2364 if (IS_PART_INCLUDED(4))
2365 {
2366 szTmp[cch++] = ':';
2367 static const char s_achPageTypes[8][4] = { "INV", "RAM", "MI2", "M2A", "SHA", "ROM", "MIO", "BAD" };
2368 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][0];
2369 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][1];
2370 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE(pPage)][2];
2371 }
2372
2373 /* The numbers. */
2374 if (IS_PART_INCLUDED(3))
2375 {
2376 szTmp[cch++] = ':';
2377 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_HCPHYS(pPage), 16, 12, 0, RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
2378 }
2379
2380 if (IS_PART_INCLUDED(2))
2381 {
2382 szTmp[cch++] = ':';
2383 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_PAGEID(pPage), 16, 7, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
2384 }
2385
2386 if (IS_PART_INCLUDED(6))
2387 {
2388 szTmp[cch++] = ':';
2389 static const char s_achRefs[4] = { '-', 'U', '!', 'L' };
2390 szTmp[cch++] = s_achRefs[PGM_PAGE_GET_TD_CREFS(pPage)];
2391 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_TD_IDX(pPage), 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_16BIT);
2392 }
2393#undef IS_PART_INCLUDED
2394
2395 cch = pfnOutput(pvArgOutput, szTmp, cch);
2396 }
2397 else
2398 cch = pfnOutput(pvArgOutput, "<bad-pgmpage-ptr>", sizeof("<bad-pgmpage-ptr>") - 1);
2399 return cch;
2400}
2401
2402
2403/** Format handler for PGMRAMRANGE.
2404 * @copydoc FNRTSTRFORMATTYPE */
2405static DECLCALLBACK(size_t) pgmFormatTypeHandlerRamRange(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
2406 const char *pszType, void const *pvValue,
2407 int cchWidth, int cchPrecision, unsigned fFlags,
2408 void *pvUser)
2409{
2410 size_t cch;
2411 PGMRAMRANGE const *pRam = (PGMRAMRANGE const *)pvValue;
2412 if (VALID_PTR(pRam))
2413 {
2414 char szTmp[80];
2415 cch = RTStrPrintf(szTmp, sizeof(szTmp), "%RGp-%RGp", pRam->GCPhys, pRam->GCPhysLast);
2416 cch = pfnOutput(pvArgOutput, szTmp, cch);
2417 }
2418 else
2419 cch = pfnOutput(pvArgOutput, "<bad-pgmramrange-ptr>", sizeof("<bad-pgmramrange-ptr>") - 1);
2420 return cch;
2421}
2422
2423/** Format type andlers to be registered/deregistered. */
2424static const struct
2425{
2426 char szType[24];
2427 PFNRTSTRFORMATTYPE pfnHandler;
2428} g_aPgmFormatTypes[] =
2429{
2430 { "pgmpage", pgmFormatTypeHandlerPage },
2431 { "pgmramrange", pgmFormatTypeHandlerRamRange }
2432};
2433
2434#endif /* !IN_R0 || LOG_ENABLED */
2435
2436
2437/**
2438 * Registers the global string format types.
2439 *
2440 * This should be called at module load time or in some other manner that ensure
2441 * that it's called exactly one time.
2442 *
2443 * @returns IPRT status code on RTStrFormatTypeRegister failure.
2444 */
2445VMMDECL(int) PGMRegisterStringFormatTypes(void)
2446{
2447#if !defined(IN_R0) || defined(LOG_ENABLED)
2448 int rc = VINF_SUCCESS;
2449 unsigned i;
2450 for (i = 0; RT_SUCCESS(rc) && i < RT_ELEMENTS(g_aPgmFormatTypes); i++)
2451 {
2452 rc = RTStrFormatTypeRegister(g_aPgmFormatTypes[i].szType, g_aPgmFormatTypes[i].pfnHandler, NULL);
2453# ifdef IN_RING0
2454 if (rc == VERR_ALREADY_EXISTS)
2455 {
2456 /* in case of cleanup failure in ring-0 */
2457 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2458 rc = RTStrFormatTypeRegister(g_aPgmFormatTypes[i].szType, g_aPgmFormatTypes[i].pfnHandler, NULL);
2459 }
2460# endif
2461 }
2462 if (RT_FAILURE(rc))
2463 while (i-- > 0)
2464 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2465
2466 return rc;
2467#else
2468 return VINF_SUCCESS;
2469#endif
2470}
2471
2472
2473/**
2474 * Deregisters the global string format types.
2475 *
2476 * This should be called at module unload time or in some other manner that
2477 * ensure that it's called exactly one time.
2478 */
2479VMMDECL(void) PGMDeregisterStringFormatTypes(void)
2480{
2481#if !defined(IN_R0) || defined(LOG_ENABLED)
2482 for (unsigned i = 0; i < RT_ELEMENTS(g_aPgmFormatTypes); i++)
2483 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
2484#endif
2485}
2486
2487#ifdef VBOX_STRICT
2488
2489/**
2490 * Asserts that there are no mapping conflicts.
2491 *
2492 * @returns Number of conflicts.
2493 * @param pVM The VM Handle.
2494 */
2495VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM)
2496{
2497 unsigned cErrors = 0;
2498
2499 /*
2500 * Check for mapping conflicts.
2501 */
2502 for (PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
2503 pMapping;
2504 pMapping = pMapping->CTX_SUFF(pNext))
2505 {
2506 /** @todo This is slow and should be optimized, but since it's just assertions I don't care now. */
2507 for (RTGCPTR GCPtr = pMapping->GCPtr;
2508 GCPtr <= pMapping->GCPtrLast;
2509 GCPtr += PAGE_SIZE)
2510 {
2511 int rc = PGMGstGetPage(pVM, (RTGCPTR)GCPtr, NULL, NULL);
2512 if (rc != VERR_PAGE_TABLE_NOT_PRESENT)
2513 {
2514 AssertMsgFailed(("Conflict at %RGv with %s\n", GCPtr, R3STRING(pMapping->pszDesc)));
2515 cErrors++;
2516 break;
2517 }
2518 }
2519 }
2520
2521 return cErrors;
2522}
2523
2524
2525/**
2526 * Asserts that everything related to the guest CR3 is correctly shadowed.
2527 *
2528 * This will call PGMAssertNoMappingConflicts() and PGMAssertHandlerAndFlagsInSync(),
2529 * and assert the correctness of the guest CR3 mapping before asserting that the
2530 * shadow page tables is in sync with the guest page tables.
2531 *
2532 * @returns Number of conflicts.
2533 * @param pVM The VM Handle.
2534 * @param cr3 The current guest CR3 register value.
2535 * @param cr4 The current guest CR4 register value.
2536 */
2537VMMDECL(unsigned) PGMAssertCR3(PVM pVM, uint64_t cr3, uint64_t cr4)
2538{
2539 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
2540 unsigned cErrors = PGM_BTH_PFN(AssertCR3, pVM)(pVM, cr3, cr4, 0, ~(RTGCPTR)0);
2541 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
2542 return cErrors;
2543}
2544
2545#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