VirtualBox

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

Last change on this file since 73246 was 73246, checked in by vboxsync, 6 years ago

PGM: Working on eliminating PGMMODEDATA and the corresponding PGMCPU section so we can do mode switching in ring-0. This second part deals with shadow paging pointers and expands PGM_TYPE_NESTED & PGMMODE_NESTED into 32BIT, PAE and AMD64 variants to better map to reality at the expense of a little bit of more code. bugref:9044

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 109.6 KB
Line 
1/* $Id: PGMAll.cpp 73246 2018-07-19 15:51:20Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - All context code.
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_PGM
23#include <VBox/vmm/pgm.h>
24#include <VBox/vmm/cpum.h>
25#include <VBox/vmm/selm.h>
26#include <VBox/vmm/iem.h>
27#include <VBox/vmm/iom.h>
28#include <VBox/sup.h>
29#include <VBox/vmm/mm.h>
30#include <VBox/vmm/stam.h>
31#include <VBox/vmm/csam.h>
32#include <VBox/vmm/patm.h>
33#include <VBox/vmm/trpm.h>
34#ifdef VBOX_WITH_REM
35# include <VBox/vmm/rem.h>
36#endif
37#include <VBox/vmm/em.h>
38#include <VBox/vmm/hm.h>
39#include <VBox/vmm/hm_vmx.h>
40#include "PGMInternal.h"
41#include <VBox/vmm/vm.h>
42#include "PGMInline.h"
43#include <iprt/assert.h>
44#include <iprt/asm-amd64-x86.h>
45#include <iprt/string.h>
46#include <VBox/log.h>
47#include <VBox/param.h>
48#include <VBox/err.h>
49
50
51/*********************************************************************************************************************************
52* Structures and Typedefs *
53*********************************************************************************************************************************/
54/**
55 * Stated structure for PGM_GST_NAME(HandlerVirtualUpdate) that's
56 * passed to PGM_GST_NAME(VirtHandlerUpdateOne) during enumeration.
57 */
58typedef struct PGMHVUSTATE
59{
60 /** Pointer to the VM. */
61 PVM pVM;
62 /** Pointer to the VMCPU. */
63 PVMCPU pVCpu;
64 /** The todo flags. */
65 RTUINT fTodo;
66 /** The CR4 register value. */
67 uint32_t cr4;
68} PGMHVUSTATE, *PPGMHVUSTATE;
69
70
71/*********************************************************************************************************************************
72* Internal Functions *
73*********************************************************************************************************************************/
74DECLINLINE(int) pgmShwGetLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPT *ppPdpt, PX86PDPAE *ppPD);
75DECLINLINE(int) pgmShwGetPaePoolPagePD(PVMCPU pVCpu, RTGCPTR GCPtr, PPGMPOOLPAGE *ppShwPde);
76#ifndef IN_RC
77static int pgmShwSyncLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, X86PGPAEUINT uGstPml4e, X86PGPAEUINT uGstPdpe, PX86PDPAE *ppPD);
78static int pgmShwGetEPTPDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PEPTPDPT *ppPdpt, PEPTPD *ppPD);
79#endif
80
81
82/*
83 * Shadow - 32-bit mode
84 */
85#define PGM_SHW_TYPE PGM_TYPE_32BIT
86#define PGM_SHW_NAME(name) PGM_SHW_NAME_32BIT(name)
87#include "PGMAllShw.h"
88
89/* Guest - real mode */
90#define PGM_GST_TYPE PGM_TYPE_REAL
91#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
92#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_REAL(name)
93#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
94#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_32BIT_PD_PHYS
95#include "PGMGstDefs.h"
96#include "PGMAllGst.h"
97#include "PGMAllBth.h"
98#undef BTH_PGMPOOLKIND_PT_FOR_PT
99#undef BTH_PGMPOOLKIND_ROOT
100#undef PGM_BTH_NAME
101#undef PGM_GST_TYPE
102#undef PGM_GST_NAME
103
104/* Guest - protected mode */
105#define PGM_GST_TYPE PGM_TYPE_PROT
106#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
107#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
108#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
109#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_32BIT_PD_PHYS
110#include "PGMGstDefs.h"
111#include "PGMAllGst.h"
112#include "PGMAllBth.h"
113#undef BTH_PGMPOOLKIND_PT_FOR_PT
114#undef BTH_PGMPOOLKIND_ROOT
115#undef PGM_BTH_NAME
116#undef PGM_GST_TYPE
117#undef PGM_GST_NAME
118
119/* Guest - 32-bit mode */
120#define PGM_GST_TYPE PGM_TYPE_32BIT
121#define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
122#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_32BIT(name)
123#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT
124#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB
125#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_32BIT_PD
126#include "PGMGstDefs.h"
127#include "PGMAllGst.h"
128#include "PGMAllBth.h"
129#undef BTH_PGMPOOLKIND_PT_FOR_BIG
130#undef BTH_PGMPOOLKIND_PT_FOR_PT
131#undef BTH_PGMPOOLKIND_ROOT
132#undef PGM_BTH_NAME
133#undef PGM_GST_TYPE
134#undef PGM_GST_NAME
135
136#undef PGM_SHW_TYPE
137#undef PGM_SHW_NAME
138
139
140/*
141 * Shadow - PAE mode
142 */
143#define PGM_SHW_TYPE PGM_TYPE_PAE
144#define PGM_SHW_NAME(name) PGM_SHW_NAME_PAE(name)
145#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
146#include "PGMAllShw.h"
147
148/* Guest - real mode */
149#define PGM_GST_TYPE PGM_TYPE_REAL
150#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
151#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
152#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
153#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_PHYS
154#include "PGMGstDefs.h"
155#include "PGMAllBth.h"
156#undef BTH_PGMPOOLKIND_PT_FOR_PT
157#undef BTH_PGMPOOLKIND_ROOT
158#undef PGM_BTH_NAME
159#undef PGM_GST_TYPE
160#undef PGM_GST_NAME
161
162/* Guest - protected mode */
163#define PGM_GST_TYPE PGM_TYPE_PROT
164#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
165#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
166#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
167#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_PHYS
168#include "PGMGstDefs.h"
169#include "PGMAllBth.h"
170#undef BTH_PGMPOOLKIND_PT_FOR_PT
171#undef BTH_PGMPOOLKIND_ROOT
172#undef PGM_BTH_NAME
173#undef PGM_GST_TYPE
174#undef PGM_GST_NAME
175
176/* Guest - 32-bit mode */
177#define PGM_GST_TYPE PGM_TYPE_32BIT
178#define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
179#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_32BIT(name)
180#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_32BIT_PT
181#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB
182#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT_FOR_32BIT
183#include "PGMGstDefs.h"
184#include "PGMAllBth.h"
185#undef BTH_PGMPOOLKIND_PT_FOR_BIG
186#undef BTH_PGMPOOLKIND_PT_FOR_PT
187#undef BTH_PGMPOOLKIND_ROOT
188#undef PGM_BTH_NAME
189#undef PGM_GST_TYPE
190#undef PGM_GST_NAME
191
192
193/* Guest - PAE mode */
194#define PGM_GST_TYPE PGM_TYPE_PAE
195#define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
196#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PAE(name)
197#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
198#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
199#define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PDPT
200#include "PGMGstDefs.h"
201#include "PGMAllGst.h"
202#include "PGMAllBth.h"
203#undef BTH_PGMPOOLKIND_PT_FOR_BIG
204#undef BTH_PGMPOOLKIND_PT_FOR_PT
205#undef BTH_PGMPOOLKIND_ROOT
206#undef PGM_BTH_NAME
207#undef PGM_GST_TYPE
208#undef PGM_GST_NAME
209
210#undef PGM_SHW_TYPE
211#undef PGM_SHW_NAME
212
213
214#ifndef IN_RC /* AMD64 implies VT-x/AMD-V */
215/*
216 * Shadow - AMD64 mode
217 */
218# define PGM_SHW_TYPE PGM_TYPE_AMD64
219# define PGM_SHW_NAME(name) PGM_SHW_NAME_AMD64(name)
220# include "PGMAllShw.h"
221
222/* Guest - protected mode (only used for AMD-V nested paging in 64 bits mode) */
223# define PGM_GST_TYPE PGM_TYPE_PROT
224# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
225# define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_PROT(name)
226# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
227# define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_PAE_PD_PHYS
228# include "PGMGstDefs.h"
229# include "PGMAllBth.h"
230# undef BTH_PGMPOOLKIND_PT_FOR_PT
231# undef BTH_PGMPOOLKIND_ROOT
232# undef PGM_BTH_NAME
233# undef PGM_GST_TYPE
234# undef PGM_GST_NAME
235
236# ifdef VBOX_WITH_64_BITS_GUESTS
237/* Guest - AMD64 mode */
238# define PGM_GST_TYPE PGM_TYPE_AMD64
239# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
240# define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_AMD64(name)
241# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
242# define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
243# define BTH_PGMPOOLKIND_ROOT PGMPOOLKIND_64BIT_PML4
244# include "PGMGstDefs.h"
245# include "PGMAllGst.h"
246# include "PGMAllBth.h"
247# undef BTH_PGMPOOLKIND_PT_FOR_BIG
248# undef BTH_PGMPOOLKIND_PT_FOR_PT
249# undef BTH_PGMPOOLKIND_ROOT
250# undef PGM_BTH_NAME
251# undef PGM_GST_TYPE
252# undef PGM_GST_NAME
253# endif /* VBOX_WITH_64_BITS_GUESTS */
254
255# undef PGM_SHW_TYPE
256# undef PGM_SHW_NAME
257
258
259/*
260 * Shadow - 32-bit nested paging mode.
261 */
262# define PGM_SHW_TYPE PGM_TYPE_NESTED_32BIT
263# define PGM_SHW_NAME(name) PGM_SHW_NAME_NESTED_32BIT(name)
264# include "PGMAllShw.h"
265
266/* Guest - real mode */
267# define PGM_GST_TYPE PGM_TYPE_REAL
268# define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
269# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_32BIT_REAL(name)
270# include "PGMGstDefs.h"
271# include "PGMAllBth.h"
272# undef PGM_BTH_NAME
273# undef PGM_GST_TYPE
274# undef PGM_GST_NAME
275
276/* Guest - protected mode */
277# define PGM_GST_TYPE PGM_TYPE_PROT
278# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
279# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_32BIT_PROT(name)
280# include "PGMGstDefs.h"
281# include "PGMAllBth.h"
282# undef PGM_BTH_NAME
283# undef PGM_GST_TYPE
284# undef PGM_GST_NAME
285
286/* Guest - 32-bit mode */
287# define PGM_GST_TYPE PGM_TYPE_32BIT
288# define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
289# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_32BIT_32BIT(name)
290# include "PGMGstDefs.h"
291# include "PGMAllBth.h"
292# undef PGM_BTH_NAME
293# undef PGM_GST_TYPE
294# undef PGM_GST_NAME
295
296/* Guest - PAE mode */
297# define PGM_GST_TYPE PGM_TYPE_PAE
298# define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
299# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_32BIT_PAE(name)
300# include "PGMGstDefs.h"
301# include "PGMAllBth.h"
302# undef PGM_BTH_NAME
303# undef PGM_GST_TYPE
304# undef PGM_GST_NAME
305
306# ifdef VBOX_WITH_64_BITS_GUESTS
307/* Guest - AMD64 mode */
308# define PGM_GST_TYPE PGM_TYPE_AMD64
309# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
310# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_32BIT_AMD64(name)
311# include "PGMGstDefs.h"
312# include "PGMAllBth.h"
313# undef PGM_BTH_NAME
314# undef PGM_GST_TYPE
315# undef PGM_GST_NAME
316# endif /* VBOX_WITH_64_BITS_GUESTS */
317
318# undef PGM_SHW_TYPE
319# undef PGM_SHW_NAME
320
321
322/*
323 * Shadow - PAE nested paging mode.
324 */
325# define PGM_SHW_TYPE PGM_TYPE_NESTED_PAE
326# define PGM_SHW_NAME(name) PGM_SHW_NAME_NESTED_PAE(name)
327# include "PGMAllShw.h"
328
329/* Guest - real mode */
330# define PGM_GST_TYPE PGM_TYPE_REAL
331# define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
332# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PAE_REAL(name)
333# include "PGMGstDefs.h"
334# include "PGMAllBth.h"
335# undef PGM_BTH_NAME
336# undef PGM_GST_TYPE
337# undef PGM_GST_NAME
338
339/* Guest - protected mode */
340# define PGM_GST_TYPE PGM_TYPE_PROT
341# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
342# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PAE_PROT(name)
343# include "PGMGstDefs.h"
344# include "PGMAllBth.h"
345# undef PGM_BTH_NAME
346# undef PGM_GST_TYPE
347# undef PGM_GST_NAME
348
349/* Guest - 32-bit mode */
350# define PGM_GST_TYPE PGM_TYPE_32BIT
351# define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
352# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PAE_32BIT(name)
353# include "PGMGstDefs.h"
354# include "PGMAllBth.h"
355# undef PGM_BTH_NAME
356# undef PGM_GST_TYPE
357# undef PGM_GST_NAME
358
359/* Guest - PAE mode */
360# define PGM_GST_TYPE PGM_TYPE_PAE
361# define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
362# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PAE_PAE(name)
363# include "PGMGstDefs.h"
364# include "PGMAllBth.h"
365# undef PGM_BTH_NAME
366# undef PGM_GST_TYPE
367# undef PGM_GST_NAME
368
369# ifdef VBOX_WITH_64_BITS_GUESTS
370/* Guest - AMD64 mode */
371# define PGM_GST_TYPE PGM_TYPE_AMD64
372# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
373# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PAE_AMD64(name)
374# include "PGMGstDefs.h"
375# include "PGMAllBth.h"
376# undef PGM_BTH_NAME
377# undef PGM_GST_TYPE
378# undef PGM_GST_NAME
379# endif /* VBOX_WITH_64_BITS_GUESTS */
380
381# undef PGM_SHW_TYPE
382# undef PGM_SHW_NAME
383
384
385/*
386 * Shadow - AMD64 nested paging mode.
387 */
388# define PGM_SHW_TYPE PGM_TYPE_NESTED_AMD64
389# define PGM_SHW_NAME(name) PGM_SHW_NAME_NESTED_AMD64(name)
390# include "PGMAllShw.h"
391
392/* Guest - real mode */
393# define PGM_GST_TYPE PGM_TYPE_REAL
394# define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
395# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_AMD64_REAL(name)
396# include "PGMGstDefs.h"
397# include "PGMAllBth.h"
398# undef PGM_BTH_NAME
399# undef PGM_GST_TYPE
400# undef PGM_GST_NAME
401
402/* Guest - protected mode */
403# define PGM_GST_TYPE PGM_TYPE_PROT
404# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
405# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_AMD64_PROT(name)
406# include "PGMGstDefs.h"
407# include "PGMAllBth.h"
408# undef PGM_BTH_NAME
409# undef PGM_GST_TYPE
410# undef PGM_GST_NAME
411
412/* Guest - 32-bit mode */
413# define PGM_GST_TYPE PGM_TYPE_32BIT
414# define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
415# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_AMD64_32BIT(name)
416# include "PGMGstDefs.h"
417# include "PGMAllBth.h"
418# undef PGM_BTH_NAME
419# undef PGM_GST_TYPE
420# undef PGM_GST_NAME
421
422/* Guest - PAE mode */
423# define PGM_GST_TYPE PGM_TYPE_PAE
424# define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
425# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_AMD64_PAE(name)
426# include "PGMGstDefs.h"
427# include "PGMAllBth.h"
428# undef PGM_BTH_NAME
429# undef PGM_GST_TYPE
430# undef PGM_GST_NAME
431
432# ifdef VBOX_WITH_64_BITS_GUESTS
433/* Guest - AMD64 mode */
434# define PGM_GST_TYPE PGM_TYPE_AMD64
435# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
436# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_AMD64_AMD64(name)
437# include "PGMGstDefs.h"
438# include "PGMAllBth.h"
439# undef PGM_BTH_NAME
440# undef PGM_GST_TYPE
441# undef PGM_GST_NAME
442# endif /* VBOX_WITH_64_BITS_GUESTS */
443
444# undef PGM_SHW_TYPE
445# undef PGM_SHW_NAME
446
447
448/*
449 * Shadow - EPT.
450 */
451# define PGM_SHW_TYPE PGM_TYPE_EPT
452# define PGM_SHW_NAME(name) PGM_SHW_NAME_EPT(name)
453# include "PGMAllShw.h"
454
455/* Guest - real mode */
456# define PGM_GST_TYPE PGM_TYPE_REAL
457# define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
458# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_REAL(name)
459# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
460# include "PGMGstDefs.h"
461# include "PGMAllBth.h"
462# undef BTH_PGMPOOLKIND_PT_FOR_PT
463# undef PGM_BTH_NAME
464# undef PGM_GST_TYPE
465# undef PGM_GST_NAME
466
467/* Guest - protected mode */
468# define PGM_GST_TYPE PGM_TYPE_PROT
469# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
470# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PROT(name)
471# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
472# include "PGMGstDefs.h"
473# include "PGMAllBth.h"
474# undef BTH_PGMPOOLKIND_PT_FOR_PT
475# undef PGM_BTH_NAME
476# undef PGM_GST_TYPE
477# undef PGM_GST_NAME
478
479/* Guest - 32-bit mode */
480# define PGM_GST_TYPE PGM_TYPE_32BIT
481# define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
482# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_32BIT(name)
483# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
484# include "PGMGstDefs.h"
485# include "PGMAllBth.h"
486# undef BTH_PGMPOOLKIND_PT_FOR_PT
487# undef PGM_BTH_NAME
488# undef PGM_GST_TYPE
489# undef PGM_GST_NAME
490
491/* Guest - PAE mode */
492# define PGM_GST_TYPE PGM_TYPE_PAE
493# define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
494# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PAE(name)
495# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
496# include "PGMGstDefs.h"
497# include "PGMAllBth.h"
498# undef BTH_PGMPOOLKIND_PT_FOR_PT
499# undef PGM_BTH_NAME
500# undef PGM_GST_TYPE
501# undef PGM_GST_NAME
502
503# ifdef VBOX_WITH_64_BITS_GUESTS
504/* Guest - AMD64 mode */
505# define PGM_GST_TYPE PGM_TYPE_AMD64
506# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
507# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_AMD64(name)
508# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
509# include "PGMGstDefs.h"
510# include "PGMAllBth.h"
511# undef BTH_PGMPOOLKIND_PT_FOR_PT
512# undef PGM_BTH_NAME
513# undef PGM_GST_TYPE
514# undef PGM_GST_NAME
515# endif /* VBOX_WITH_64_BITS_GUESTS */
516
517# undef PGM_SHW_TYPE
518# undef PGM_SHW_NAME
519
520#endif /* !IN_RC */
521
522
523/**
524 * Guest mode data array.
525 */
526PGMMODEDATAGST const g_aPgmGuestModeData[PGM_GUEST_MODE_DATA_ARRAY_SIZE] =
527{
528 { UINT32_MAX, NULL, NULL, NULL, NULL, NULL }, /* 0 */
529 {
530 PGM_TYPE_REAL,
531 PGM_GST_NAME_REAL(GetPage),
532 PGM_GST_NAME_REAL(ModifyPage),
533 PGM_GST_NAME_REAL(GetPDE),
534#ifdef IN_RING3
535 PGM_GST_NAME_REAL(Enter),
536 PGM_GST_NAME_REAL(Exit),
537 PGM_GST_NAME_REAL(Relocate),
538#else
539 NULL, NULL, NULL,
540#endif
541 },
542 {
543 PGM_TYPE_PROT,
544 PGM_GST_NAME_PROT(GetPage),
545 PGM_GST_NAME_PROT(ModifyPage),
546 PGM_GST_NAME_PROT(GetPDE),
547#ifdef IN_RING3
548 PGM_GST_NAME_PROT(Enter),
549 PGM_GST_NAME_PROT(Exit),
550 PGM_GST_NAME_PROT(Relocate),
551#else
552 NULL, NULL, NULL,
553#endif
554 },
555 {
556 PGM_TYPE_32BIT,
557 PGM_GST_NAME_32BIT(GetPage),
558 PGM_GST_NAME_32BIT(ModifyPage),
559 PGM_GST_NAME_32BIT(GetPDE),
560#ifdef IN_RING3
561 PGM_GST_NAME_32BIT(Enter),
562 PGM_GST_NAME_32BIT(Exit),
563 PGM_GST_NAME_32BIT(Relocate),
564#else
565 NULL, NULL, NULL,
566#endif
567 },
568 {
569 PGM_TYPE_PAE,
570 PGM_GST_NAME_PAE(GetPage),
571 PGM_GST_NAME_PAE(ModifyPage),
572 PGM_GST_NAME_PAE(GetPDE),
573#ifdef IN_RING3
574 PGM_GST_NAME_PAE(Enter),
575 PGM_GST_NAME_PAE(Exit),
576 PGM_GST_NAME_PAE(Relocate),
577#else
578 NULL, NULL, NULL,
579#endif
580 },
581#if defined(VBOX_WITH_64_BITS_GUESTS) && !defined(IN_RC)
582 {
583 PGM_TYPE_AMD64,
584 PGM_GST_NAME_AMD64(GetPage),
585 PGM_GST_NAME_AMD64(ModifyPage),
586 PGM_GST_NAME_AMD64(GetPDE),
587# ifdef IN_RING3
588 PGM_GST_NAME_AMD64(Enter),
589 PGM_GST_NAME_AMD64(Exit),
590 PGM_GST_NAME_AMD64(Relocate),
591# else
592 NULL, NULL, NULL,
593# endif
594 },
595#endif
596};
597
598
599/** The shadow mode data array. */
600PGMMODEDATASHW const g_aPgmShadowModeData[PGM_SHADOW_MODE_DATA_ARRAY_SIZE] =
601{
602 { UINT8_MAX, NULL, NULL, NULL, NULL, NULL }, /* 0 */
603 { UINT8_MAX, NULL, NULL, NULL, NULL, NULL }, /* PGM_TYPE_REAL */
604 { UINT8_MAX, NULL, NULL, NULL, NULL, NULL }, /* PGM_TYPE_PROT */
605 {
606 PGM_TYPE_32BIT,
607 PGM_SHW_NAME_32BIT(GetPage),
608 PGM_SHW_NAME_32BIT(ModifyPage),
609#ifdef IN_RING3
610 PGM_SHW_NAME_32BIT(Enter),
611 PGM_SHW_NAME_32BIT(Exit),
612 PGM_SHW_NAME_32BIT(Relocate),
613#else
614 NULL, NULL, NULL,
615#endif
616 },
617 {
618 PGM_TYPE_PAE,
619 PGM_SHW_NAME_PAE(GetPage),
620 PGM_SHW_NAME_PAE(ModifyPage),
621#ifdef IN_RING3
622 PGM_SHW_NAME_PAE(Enter),
623 PGM_SHW_NAME_PAE(Exit),
624 PGM_SHW_NAME_PAE(Relocate),
625#else
626 NULL, NULL, NULL,
627#endif
628 },
629#ifndef IN_RC
630 {
631 PGM_TYPE_AMD64,
632 PGM_SHW_NAME_AMD64(GetPage),
633 PGM_SHW_NAME_AMD64(ModifyPage),
634# ifdef IN_RING3
635 PGM_SHW_NAME_AMD64(Enter),
636 PGM_SHW_NAME_AMD64(Exit),
637 PGM_SHW_NAME_AMD64(Relocate),
638# else
639 NULL, NULL, NULL,
640# endif
641 },
642 {
643 PGM_TYPE_NESTED_32BIT,
644 PGM_SHW_NAME_NESTED_32BIT(GetPage),
645 PGM_SHW_NAME_NESTED_32BIT(ModifyPage),
646# ifdef IN_RING3
647 PGM_SHW_NAME_NESTED_32BIT(Enter),
648 PGM_SHW_NAME_NESTED_32BIT(Exit),
649 PGM_SHW_NAME_NESTED_32BIT(Relocate),
650# else
651 NULL, NULL, NULL,
652# endif
653 },
654 {
655 PGM_TYPE_NESTED_PAE,
656 PGM_SHW_NAME_NESTED_PAE(GetPage),
657 PGM_SHW_NAME_NESTED_PAE(ModifyPage),
658# ifdef IN_RING3
659 PGM_SHW_NAME_NESTED_PAE(Enter),
660 PGM_SHW_NAME_NESTED_PAE(Exit),
661 PGM_SHW_NAME_NESTED_PAE(Relocate),
662# else
663 NULL, NULL, NULL,
664# endif
665 },
666 {
667 PGM_TYPE_NESTED_AMD64,
668 PGM_SHW_NAME_NESTED_AMD64(GetPage),
669 PGM_SHW_NAME_NESTED_AMD64(ModifyPage),
670# ifdef IN_RING3
671 PGM_SHW_NAME_NESTED_AMD64(Enter),
672 PGM_SHW_NAME_NESTED_AMD64(Exit),
673 PGM_SHW_NAME_NESTED_AMD64(Relocate),
674# else
675 NULL, NULL, NULL,
676# endif
677 },
678 {
679 PGM_TYPE_EPT,
680 PGM_SHW_NAME_EPT(GetPage),
681 PGM_SHW_NAME_EPT(ModifyPage),
682# ifdef IN_RING3
683 PGM_SHW_NAME_EPT(Enter),
684 PGM_SHW_NAME_EPT(Exit),
685 PGM_SHW_NAME_EPT(Relocate),
686# else
687 NULL, NULL, NULL,
688# endif
689 },
690#endif /* IN_RC */
691};
692
693
694#ifndef IN_RING3
695/**
696 * #PF Handler.
697 *
698 * @returns VBox status code (appropriate for trap handling and GC return).
699 * @param pVCpu The cross context virtual CPU structure.
700 * @param uErr The trap error code.
701 * @param pRegFrame Trap register frame.
702 * @param pvFault The fault address.
703 */
704VMMDECL(int) PGMTrap0eHandler(PVMCPU pVCpu, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
705{
706 PVM pVM = pVCpu->CTX_SUFF(pVM);
707
708 Log(("PGMTrap0eHandler: uErr=%RGx pvFault=%RGv eip=%04x:%RGv cr3=%RGp\n", uErr, pvFault, pRegFrame->cs.Sel, (RTGCPTR)pRegFrame->rip, (RTGCPHYS)CPUMGetGuestCR3(pVCpu)));
709 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0e, a);
710 STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = NULL; } );
711
712
713#ifdef VBOX_WITH_STATISTICS
714 /*
715 * Error code stats.
716 */
717 if (uErr & X86_TRAP_PF_US)
718 {
719 if (!(uErr & X86_TRAP_PF_P))
720 {
721 if (uErr & X86_TRAP_PF_RW)
722 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNotPresentWrite);
723 else
724 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNotPresentRead);
725 }
726 else if (uErr & X86_TRAP_PF_RW)
727 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSWrite);
728 else if (uErr & X86_TRAP_PF_RSVD)
729 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSReserved);
730 else if (uErr & X86_TRAP_PF_ID)
731 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNXE);
732 else
733 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSRead);
734 }
735 else
736 { /* Supervisor */
737 if (!(uErr & X86_TRAP_PF_P))
738 {
739 if (uErr & X86_TRAP_PF_RW)
740 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVNotPresentWrite);
741 else
742 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVNotPresentRead);
743 }
744 else if (uErr & X86_TRAP_PF_RW)
745 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVWrite);
746 else if (uErr & X86_TRAP_PF_ID)
747 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSNXE);
748 else if (uErr & X86_TRAP_PF_RSVD)
749 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVReserved);
750 }
751#endif /* VBOX_WITH_STATISTICS */
752
753 /*
754 * Call the worker.
755 */
756 bool fLockTaken = false;
757 int rc = PGM_BTH_PFN(Trap0eHandler, pVCpu)(pVCpu, uErr, pRegFrame, pvFault, &fLockTaken);
758 if (fLockTaken)
759 {
760 PGM_LOCK_ASSERT_OWNER(pVM);
761 pgmUnlock(pVM);
762 }
763 LogFlow(("PGMTrap0eHandler: uErr=%RGx pvFault=%RGv rc=%Rrc\n", uErr, pvFault, rc));
764
765 /*
766 * Return code tweaks.
767 */
768 if (rc != VINF_SUCCESS)
769 {
770 if (rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE)
771 rc = VINF_SUCCESS;
772
773# ifdef IN_RING0
774 /* Note: hack alert for difficult to reproduce problem. */
775 if ( rc == VERR_PAGE_NOT_PRESENT /* SMP only ; disassembly might fail. */
776 || rc == VERR_PAGE_TABLE_NOT_PRESENT /* seen with UNI & SMP */
777 || rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT /* seen with SMP */
778 || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT) /* precaution */
779 {
780 Log(("WARNING: Unexpected VERR_PAGE_TABLE_NOT_PRESENT (%d) for page fault at %RGv error code %x (rip=%RGv)\n", rc, pvFault, uErr, pRegFrame->rip));
781 /* Some kind of inconsistency in the SMP case; it's safe to just execute the instruction again; not sure about single VCPU VMs though. */
782 rc = VINF_SUCCESS;
783 }
784# endif
785 }
786
787 STAM_STATS({ if (rc == VINF_EM_RAW_GUEST_TRAP) STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eGuestPF); });
788 STAM_STATS({ if (!pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution))
789 pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Misc; });
790 STAM_PROFILE_STOP_EX(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0e, pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution), a);
791 return rc;
792}
793#endif /* !IN_RING3 */
794
795
796/**
797 * Prefetch a page
798 *
799 * Typically used to sync commonly used pages before entering raw mode
800 * after a CR3 reload.
801 *
802 * @returns VBox status code suitable for scheduling.
803 * @retval VINF_SUCCESS on success.
804 * @retval VINF_PGM_SYNC_CR3 if we're out of shadow pages or something like that.
805 * @param pVCpu The cross context virtual CPU structure.
806 * @param GCPtrPage Page to invalidate.
807 */
808VMMDECL(int) PGMPrefetchPage(PVMCPU pVCpu, RTGCPTR GCPtrPage)
809{
810 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Prefetch), a);
811 int rc = PGM_BTH_PFN(PrefetchPage, pVCpu)(pVCpu, GCPtrPage);
812 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,Prefetch), a);
813 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 || RT_FAILURE(rc), ("rc=%Rrc\n", rc));
814 return rc;
815}
816
817
818/**
819 * Gets the mapping corresponding to the specified address (if any).
820 *
821 * @returns Pointer to the mapping.
822 * @returns NULL if not
823 *
824 * @param pVM The cross context VM structure.
825 * @param GCPtr The guest context pointer.
826 */
827PPGMMAPPING pgmGetMapping(PVM pVM, RTGCPTR GCPtr)
828{
829 PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
830 while (pMapping)
831 {
832 if ((uintptr_t)GCPtr < (uintptr_t)pMapping->GCPtr)
833 break;
834 if ((uintptr_t)GCPtr - (uintptr_t)pMapping->GCPtr < pMapping->cb)
835 return pMapping;
836 pMapping = pMapping->CTX_SUFF(pNext);
837 }
838 return NULL;
839}
840
841
842/**
843 * Verifies a range of pages for read or write access
844 *
845 * Only checks the guest's page tables
846 *
847 * @returns VBox status code.
848 * @param pVCpu The cross context virtual CPU structure.
849 * @param Addr Guest virtual address to check
850 * @param cbSize Access size
851 * @param fAccess Access type (r/w, user/supervisor (X86_PTE_*))
852 * @remarks Current not in use.
853 */
854VMMDECL(int) PGMIsValidAccess(PVMCPU pVCpu, RTGCPTR Addr, uint32_t cbSize, uint32_t fAccess)
855{
856 /*
857 * Validate input.
858 */
859 if (fAccess & ~(X86_PTE_US | X86_PTE_RW))
860 {
861 AssertMsgFailed(("PGMIsValidAccess: invalid access type %08x\n", fAccess));
862 return VERR_INVALID_PARAMETER;
863 }
864
865 uint64_t fPage;
866 int rc = PGMGstGetPage(pVCpu, (RTGCPTR)Addr, &fPage, NULL);
867 if (RT_FAILURE(rc))
868 {
869 Log(("PGMIsValidAccess: access violation for %RGv rc=%d\n", Addr, rc));
870 return VINF_EM_RAW_GUEST_TRAP;
871 }
872
873 /*
874 * Check if the access would cause a page fault
875 *
876 * Note that hypervisor page directories are not present in the guest's tables, so this check
877 * is sufficient.
878 */
879 bool fWrite = !!(fAccess & X86_PTE_RW);
880 bool fUser = !!(fAccess & X86_PTE_US);
881 if ( !(fPage & X86_PTE_P)
882 || (fWrite && !(fPage & X86_PTE_RW))
883 || (fUser && !(fPage & X86_PTE_US)) )
884 {
885 Log(("PGMIsValidAccess: access violation for %RGv attr %#llx vs %d:%d\n", Addr, fPage, fWrite, fUser));
886 return VINF_EM_RAW_GUEST_TRAP;
887 }
888 if ( RT_SUCCESS(rc)
889 && PAGE_ADDRESS(Addr) != PAGE_ADDRESS(Addr + cbSize))
890 return PGMIsValidAccess(pVCpu, Addr + PAGE_SIZE, (cbSize > PAGE_SIZE) ? cbSize - PAGE_SIZE : 1, fAccess);
891 return rc;
892}
893
894
895/**
896 * Verifies a range of pages for read or write access
897 *
898 * Supports handling of pages marked for dirty bit tracking and CSAM
899 *
900 * @returns VBox status code.
901 * @param pVCpu The cross context virtual CPU structure.
902 * @param Addr Guest virtual address to check
903 * @param cbSize Access size
904 * @param fAccess Access type (r/w, user/supervisor (X86_PTE_*))
905 */
906VMMDECL(int) PGMVerifyAccess(PVMCPU pVCpu, RTGCPTR Addr, uint32_t cbSize, uint32_t fAccess)
907{
908 PVM pVM = pVCpu->CTX_SUFF(pVM);
909
910 AssertMsg(!(fAccess & ~(X86_PTE_US | X86_PTE_RW)), ("PGMVerifyAccess: invalid access type %08x\n", fAccess));
911
912 /*
913 * Get going.
914 */
915 uint64_t fPageGst;
916 int rc = PGMGstGetPage(pVCpu, (RTGCPTR)Addr, &fPageGst, NULL);
917 if (RT_FAILURE(rc))
918 {
919 Log(("PGMVerifyAccess: access violation for %RGv rc=%d\n", Addr, rc));
920 return VINF_EM_RAW_GUEST_TRAP;
921 }
922
923 /*
924 * Check if the access would cause a page fault
925 *
926 * Note that hypervisor page directories are not present in the guest's tables, so this check
927 * is sufficient.
928 */
929 const bool fWrite = !!(fAccess & X86_PTE_RW);
930 const bool fUser = !!(fAccess & X86_PTE_US);
931 if ( !(fPageGst & X86_PTE_P)
932 || (fWrite && !(fPageGst & X86_PTE_RW))
933 || (fUser && !(fPageGst & X86_PTE_US)) )
934 {
935 Log(("PGMVerifyAccess: access violation for %RGv attr %#llx vs %d:%d\n", Addr, fPageGst, fWrite, fUser));
936 return VINF_EM_RAW_GUEST_TRAP;
937 }
938
939 if (!pVM->pgm.s.fNestedPaging)
940 {
941 /*
942 * Next step is to verify if we protected this page for dirty bit tracking or for CSAM scanning
943 */
944 rc = PGMShwGetPage(pVCpu, (RTGCPTR)Addr, NULL, NULL);
945 if ( rc == VERR_PAGE_NOT_PRESENT
946 || rc == VERR_PAGE_TABLE_NOT_PRESENT)
947 {
948 /*
949 * Page is not present in our page tables.
950 * Try to sync it!
951 */
952 Assert(X86_TRAP_PF_RW == X86_PTE_RW && X86_TRAP_PF_US == X86_PTE_US);
953 uint32_t uErr = fAccess & (X86_TRAP_PF_RW | X86_TRAP_PF_US);
954 rc = PGM_BTH_PFN(VerifyAccessSyncPage, pVCpu)(pVCpu, Addr, fPageGst, uErr);
955 if (rc != VINF_SUCCESS)
956 return rc;
957 }
958 else
959 AssertMsg(rc == VINF_SUCCESS, ("PGMShwGetPage %RGv failed with %Rrc\n", Addr, rc));
960 }
961
962#if 0 /* def VBOX_STRICT; triggers too often now */
963 /*
964 * This check is a bit paranoid, but useful.
965 */
966 /* Note! This will assert when writing to monitored pages (a bit annoying actually). */
967 uint64_t fPageShw;
968 rc = PGMShwGetPage(pVCpu, (RTGCPTR)Addr, &fPageShw, NULL);
969 if ( (rc == VERR_PAGE_NOT_PRESENT || RT_FAILURE(rc))
970 || (fWrite && !(fPageShw & X86_PTE_RW))
971 || (fUser && !(fPageShw & X86_PTE_US)) )
972 {
973 AssertMsgFailed(("Unexpected access violation for %RGv! rc=%Rrc write=%d user=%d\n",
974 Addr, rc, fWrite && !(fPageShw & X86_PTE_RW), fUser && !(fPageShw & X86_PTE_US)));
975 return VINF_EM_RAW_GUEST_TRAP;
976 }
977#endif
978
979 if ( RT_SUCCESS(rc)
980 && ( PAGE_ADDRESS(Addr) != PAGE_ADDRESS(Addr + cbSize - 1)
981 || Addr + cbSize < Addr))
982 {
983 /* Don't recursively call PGMVerifyAccess as we might run out of stack. */
984 for (;;)
985 {
986 Addr += PAGE_SIZE;
987 if (cbSize > PAGE_SIZE)
988 cbSize -= PAGE_SIZE;
989 else
990 cbSize = 1;
991 rc = PGMVerifyAccess(pVCpu, Addr, 1, fAccess);
992 if (rc != VINF_SUCCESS)
993 break;
994 if (PAGE_ADDRESS(Addr) == PAGE_ADDRESS(Addr + cbSize - 1))
995 break;
996 }
997 }
998 return rc;
999}
1000
1001
1002/**
1003 * Emulation of the invlpg instruction (HC only actually).
1004 *
1005 * @returns Strict VBox status code, special care required.
1006 * @retval VINF_PGM_SYNC_CR3 - handled.
1007 * @retval VINF_EM_RAW_EMULATE_INSTR - not handled (RC only).
1008 * @retval VERR_REM_FLUSHED_PAGES_OVERFLOW - not handled.
1009 *
1010 * @param pVCpu The cross context virtual CPU structure.
1011 * @param GCPtrPage Page to invalidate.
1012 *
1013 * @remark ASSUMES the page table entry or page directory is valid. Fairly
1014 * safe, but there could be edge cases!
1015 *
1016 * @todo Flush page or page directory only if necessary!
1017 * @todo VBOXSTRICTRC
1018 */
1019VMMDECL(int) PGMInvalidatePage(PVMCPU pVCpu, RTGCPTR GCPtrPage)
1020{
1021 PVM pVM = pVCpu->CTX_SUFF(pVM);
1022 int rc;
1023 Log3(("PGMInvalidatePage: GCPtrPage=%RGv\n", GCPtrPage));
1024
1025#if !defined(IN_RING3) && defined(VBOX_WITH_REM)
1026 /*
1027 * Notify the recompiler so it can record this instruction.
1028 */
1029 REMNotifyInvalidatePage(pVM, GCPtrPage);
1030#endif /* !IN_RING3 */
1031 IEMTlbInvalidatePage(pVCpu, GCPtrPage);
1032
1033
1034#ifdef IN_RC
1035 /*
1036 * Check for conflicts and pending CR3 monitoring updates.
1037 */
1038 if (pgmMapAreMappingsFloating(pVM))
1039 {
1040 if ( pgmGetMapping(pVM, GCPtrPage)
1041 && PGMGstGetPage(pVCpu, GCPtrPage, NULL, NULL) != VERR_PAGE_TABLE_NOT_PRESENT)
1042 {
1043 LogFlow(("PGMGCInvalidatePage: Conflict!\n"));
1044 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
1045 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatRCInvlPgConflict);
1046 return VINF_PGM_SYNC_CR3;
1047 }
1048
1049 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
1050 {
1051 LogFlow(("PGMGCInvalidatePage: PGM_SYNC_MONITOR_CR3 -> reinterpret instruction in R3\n"));
1052 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatRCInvlPgSyncMonCR3);
1053 return VINF_EM_RAW_EMULATE_INSTR;
1054 }
1055 }
1056#endif /* IN_RC */
1057
1058 /*
1059 * Call paging mode specific worker.
1060 */
1061 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePage), a);
1062 pgmLock(pVM);
1063 rc = PGM_BTH_PFN(InvalidatePage, pVCpu)(pVCpu, GCPtrPage);
1064 pgmUnlock(pVM);
1065 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePage), a);
1066
1067#ifdef IN_RING3
1068 /*
1069 * Check if we have a pending update of the CR3 monitoring.
1070 */
1071 if ( RT_SUCCESS(rc)
1072 && (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3))
1073 {
1074 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1075 Assert(!pVM->pgm.s.fMappingsFixed); Assert(pgmMapAreMappingsEnabled(pVM));
1076 }
1077
1078# ifdef VBOX_WITH_RAW_MODE
1079 /*
1080 * Inform CSAM about the flush
1081 *
1082 * Note: This is to check if monitored pages have been changed; when we implement
1083 * callbacks for virtual handlers, this is no longer required.
1084 */
1085 CSAMR3FlushPage(pVM, GCPtrPage);
1086# endif
1087#endif /* IN_RING3 */
1088
1089 /* Ignore all irrelevant error codes. */
1090 if ( rc == VERR_PAGE_NOT_PRESENT
1091 || rc == VERR_PAGE_TABLE_NOT_PRESENT
1092 || rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT
1093 || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT)
1094 rc = VINF_SUCCESS;
1095
1096 return rc;
1097}
1098
1099
1100/**
1101 * Executes an instruction using the interpreter.
1102 *
1103 * @returns VBox status code (appropriate for trap handling and GC return).
1104 * @param pVM The cross context VM structure.
1105 * @param pVCpu The cross context virtual CPU structure.
1106 * @param pRegFrame Register frame.
1107 * @param pvFault Fault address.
1108 */
1109VMMDECL(VBOXSTRICTRC) PGMInterpretInstruction(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
1110{
1111 NOREF(pVM);
1112 VBOXSTRICTRC rc = EMInterpretInstruction(pVCpu, pRegFrame, pvFault);
1113 if (rc == VERR_EM_INTERPRETER)
1114 rc = VINF_EM_RAW_EMULATE_INSTR;
1115 if (rc != VINF_SUCCESS)
1116 Log(("PGMInterpretInstruction: returns %Rrc (pvFault=%RGv)\n", VBOXSTRICTRC_VAL(rc), pvFault));
1117 return rc;
1118}
1119
1120
1121/**
1122 * Gets effective page information (from the VMM page directory).
1123 *
1124 * @returns VBox status code.
1125 * @param pVCpu The cross context virtual CPU structure.
1126 * @param GCPtr Guest Context virtual address of the page.
1127 * @param pfFlags Where to store the flags. These are X86_PTE_*.
1128 * @param pHCPhys Where to store the HC physical address of the page.
1129 * This is page aligned.
1130 * @remark You should use PGMMapGetPage() for pages in a mapping.
1131 */
1132VMMDECL(int) PGMShwGetPage(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys)
1133{
1134 PVM pVM = pVCpu->CTX_SUFF(pVM);
1135 pgmLock(pVM);
1136
1137 uintptr_t idxShw = pVCpu->pgm.s.idxShadowModeData;
1138 AssertReturn(idxShw < RT_ELEMENTS(g_aPgmShadowModeData), VERR_PGM_MODE_IPE);
1139 AssertReturn(g_aPgmShadowModeData[idxShw].pfnGetPage, VERR_PGM_MODE_IPE);
1140 int rc = g_aPgmShadowModeData[idxShw].pfnGetPage(pVCpu, GCPtr, pfFlags, pHCPhys);
1141
1142 pgmUnlock(pVM);
1143 return rc;
1144}
1145
1146
1147/**
1148 * Modify page flags for a range of pages in the shadow context.
1149 *
1150 * The existing flags are ANDed with the fMask and ORed with the fFlags.
1151 *
1152 * @returns VBox status code.
1153 * @param pVCpu The cross context virtual CPU structure.
1154 * @param GCPtr Virtual address of the first page in the range.
1155 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
1156 * @param fMask The AND mask - page flags X86_PTE_*.
1157 * Be very CAREFUL when ~'ing constants which could be 32-bit!
1158 * @param fOpFlags A combination of the PGM_MK_PK_XXX flags.
1159 * @remark You must use PGMMapModifyPage() for pages in a mapping.
1160 */
1161DECLINLINE(int) pdmShwModifyPage(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t fFlags, uint64_t fMask, uint32_t fOpFlags)
1162{
1163 AssertMsg(!(fFlags & X86_PTE_PAE_PG_MASK), ("fFlags=%#llx\n", fFlags));
1164 Assert(!(fOpFlags & ~(PGM_MK_PG_IS_MMIO2 | PGM_MK_PG_IS_WRITE_FAULT)));
1165
1166 GCPtr &= PAGE_BASE_GC_MASK; /** @todo this ain't necessary, right... */
1167
1168 PVM pVM = pVCpu->CTX_SUFF(pVM);
1169 pgmLock(pVM);
1170
1171 uintptr_t idxShw = pVCpu->pgm.s.idxShadowModeData;
1172 AssertReturn(idxShw < RT_ELEMENTS(g_aPgmShadowModeData), VERR_PGM_MODE_IPE);
1173 AssertReturn(g_aPgmShadowModeData[idxShw].pfnModifyPage, VERR_PGM_MODE_IPE);
1174 int rc = g_aPgmShadowModeData[idxShw].pfnModifyPage(pVCpu, GCPtr, PAGE_SIZE, fFlags, fMask, fOpFlags);
1175
1176 pgmUnlock(pVM);
1177 return rc;
1178}
1179
1180
1181/**
1182 * Changing the page flags for a single page in the shadow page tables so as to
1183 * make it read-only.
1184 *
1185 * @returns VBox status code.
1186 * @param pVCpu The cross context virtual CPU structure.
1187 * @param GCPtr Virtual address of the first page in the range.
1188 * @param fOpFlags A combination of the PGM_MK_PK_XXX flags.
1189 */
1190VMMDECL(int) PGMShwMakePageReadonly(PVMCPU pVCpu, RTGCPTR GCPtr, uint32_t fOpFlags)
1191{
1192 return pdmShwModifyPage(pVCpu, GCPtr, 0, ~(uint64_t)X86_PTE_RW, fOpFlags);
1193}
1194
1195
1196/**
1197 * Changing the page flags for a single page in the shadow page tables so as to
1198 * make it writable.
1199 *
1200 * The call must know with 101% certainty that the guest page tables maps this
1201 * as writable too. This function will deal shared, zero and write monitored
1202 * pages.
1203 *
1204 * @returns VBox status code.
1205 * @param pVCpu The cross context virtual CPU structure.
1206 * @param GCPtr Virtual address of the first page in the range.
1207 * @param fOpFlags A combination of the PGM_MK_PK_XXX flags.
1208 */
1209VMMDECL(int) PGMShwMakePageWritable(PVMCPU pVCpu, RTGCPTR GCPtr, uint32_t fOpFlags)
1210{
1211 return pdmShwModifyPage(pVCpu, GCPtr, X86_PTE_RW, ~(uint64_t)0, fOpFlags);
1212}
1213
1214
1215/**
1216 * Changing the page flags for a single page in the shadow page tables so as to
1217 * make it not present.
1218 *
1219 * @returns VBox status code.
1220 * @param pVCpu The cross context virtual CPU structure.
1221 * @param GCPtr Virtual address of the first page in the range.
1222 * @param fOpFlags A combination of the PGM_MK_PG_XXX flags.
1223 */
1224VMMDECL(int) PGMShwMakePageNotPresent(PVMCPU pVCpu, RTGCPTR GCPtr, uint32_t fOpFlags)
1225{
1226 return pdmShwModifyPage(pVCpu, GCPtr, 0, 0, fOpFlags);
1227}
1228
1229
1230/**
1231 * Changing the page flags for a single page in the shadow page tables so as to
1232 * make it supervisor and writable.
1233 *
1234 * This if for dealing with CR0.WP=0 and readonly user pages.
1235 *
1236 * @returns VBox status code.
1237 * @param pVCpu The cross context virtual CPU structure.
1238 * @param GCPtr Virtual address of the first page in the range.
1239 * @param fBigPage Whether or not this is a big page. If it is, we have to
1240 * change the shadow PDE as well. If it isn't, the caller
1241 * has checked that the shadow PDE doesn't need changing.
1242 * We ASSUME 4KB pages backing the big page here!
1243 * @param fOpFlags A combination of the PGM_MK_PG_XXX flags.
1244 */
1245int pgmShwMakePageSupervisorAndWritable(PVMCPU pVCpu, RTGCPTR GCPtr, bool fBigPage, uint32_t fOpFlags)
1246{
1247 int rc = pdmShwModifyPage(pVCpu, GCPtr, X86_PTE_RW, ~(uint64_t)X86_PTE_US, fOpFlags);
1248 if (rc == VINF_SUCCESS && fBigPage)
1249 {
1250 /* this is a bit ugly... */
1251 switch (pVCpu->pgm.s.enmShadowMode)
1252 {
1253 case PGMMODE_32_BIT:
1254 {
1255 PX86PDE pPde = pgmShwGet32BitPDEPtr(pVCpu, GCPtr);
1256 AssertReturn(pPde, VERR_INTERNAL_ERROR_3);
1257 Log(("pgmShwMakePageSupervisorAndWritable: PDE=%#llx", pPde->u));
1258 pPde->n.u1Write = 1;
1259 Log(("-> PDE=%#llx (32)\n", pPde->u));
1260 break;
1261 }
1262 case PGMMODE_PAE:
1263 case PGMMODE_PAE_NX:
1264 {
1265 PX86PDEPAE pPde = pgmShwGetPaePDEPtr(pVCpu, GCPtr);
1266 AssertReturn(pPde, VERR_INTERNAL_ERROR_3);
1267 Log(("pgmShwMakePageSupervisorAndWritable: PDE=%#llx", pPde->u));
1268 pPde->n.u1Write = 1;
1269 Log(("-> PDE=%#llx (PAE)\n", pPde->u));
1270 break;
1271 }
1272 default:
1273 AssertFailedReturn(VERR_INTERNAL_ERROR_4);
1274 }
1275 }
1276 return rc;
1277}
1278
1279
1280/**
1281 * Gets the shadow page directory for the specified address, PAE.
1282 *
1283 * @returns Pointer to the shadow PD.
1284 * @param pVCpu The cross context virtual CPU structure.
1285 * @param GCPtr The address.
1286 * @param uGstPdpe Guest PDPT entry. Valid.
1287 * @param ppPD Receives address of page directory
1288 */
1289int pgmShwSyncPaePDPtr(PVMCPU pVCpu, RTGCPTR GCPtr, X86PGPAEUINT uGstPdpe, PX86PDPAE *ppPD)
1290{
1291 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
1292 PX86PDPT pPdpt = pgmShwGetPaePDPTPtr(pVCpu);
1293 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
1294 PVM pVM = pVCpu->CTX_SUFF(pVM);
1295 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1296 PPGMPOOLPAGE pShwPage;
1297 int rc;
1298
1299 PGM_LOCK_ASSERT_OWNER(pVM);
1300
1301 /* Allocate page directory if not present. */
1302 if ( !pPdpe->n.u1Present
1303 && !(pPdpe->u & X86_PDPE_PG_MASK))
1304 {
1305 RTGCPTR64 GCPdPt;
1306 PGMPOOLKIND enmKind;
1307
1308 if (pVM->pgm.s.fNestedPaging || !CPUMIsGuestPagingEnabled(pVCpu))
1309 {
1310 /* AMD-V nested paging or real/protected mode without paging. */
1311 GCPdPt = (RTGCPTR64)iPdPt << X86_PDPT_SHIFT;
1312 enmKind = PGMPOOLKIND_PAE_PD_PHYS;
1313 }
1314 else
1315 {
1316 if (CPUMGetGuestCR4(pVCpu) & X86_CR4_PAE)
1317 {
1318 if (!(uGstPdpe & X86_PDPE_P))
1319 {
1320 /* PD not present; guest must reload CR3 to change it.
1321 * No need to monitor anything in this case.
1322 */
1323 Assert(VM_IS_RAW_MODE_ENABLED(pVM));
1324
1325 GCPdPt = uGstPdpe & X86_PDPE_PG_MASK;
1326 enmKind = PGMPOOLKIND_PAE_PD_PHYS;
1327 uGstPdpe |= X86_PDPE_P;
1328 }
1329 else
1330 {
1331 GCPdPt = uGstPdpe & X86_PDPE_PG_MASK;
1332 enmKind = PGMPOOLKIND_PAE_PD_FOR_PAE_PD;
1333 }
1334 }
1335 else
1336 {
1337 GCPdPt = CPUMGetGuestCR3(pVCpu);
1338 enmKind = (PGMPOOLKIND)(PGMPOOLKIND_PAE_PD0_FOR_32BIT_PD + iPdPt);
1339 }
1340 }
1341
1342 /* Create a reference back to the PDPT by using the index in its shadow page. */
1343 rc = pgmPoolAlloc(pVM, GCPdPt, enmKind, PGMPOOLACCESS_DONTCARE, PGM_A20_IS_ENABLED(pVCpu),
1344 pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iPdPt, false /*fLockPage*/,
1345 &pShwPage);
1346 AssertRCReturn(rc, rc);
1347
1348 /* The PD was cached or created; hook it up now. */
1349 pPdpe->u |= pShwPage->Core.Key | (uGstPdpe & (X86_PDPE_P | X86_PDPE_A));
1350
1351# if defined(IN_RC)
1352 /*
1353 * In 32 bits PAE mode we *must* invalidate the TLB when changing a
1354 * PDPT entry; the CPU fetches them only during cr3 load, so any
1355 * non-present PDPT will continue to cause page faults.
1356 */
1357 ASMReloadCR3();
1358# endif
1359 PGM_DYNMAP_UNUSED_HINT(pVCpu, pPdpe);
1360 }
1361 else
1362 {
1363 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
1364 AssertReturn(pShwPage, VERR_PGM_POOL_GET_PAGE_FAILED);
1365 Assert((pPdpe->u & X86_PDPE_PG_MASK) == pShwPage->Core.Key);
1366
1367 pgmPoolCacheUsed(pPool, pShwPage);
1368 }
1369 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPage);
1370 return VINF_SUCCESS;
1371}
1372
1373
1374/**
1375 * Gets the pointer to the shadow page directory entry for an address, PAE.
1376 *
1377 * @returns Pointer to the PDE.
1378 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1379 * @param GCPtr The address.
1380 * @param ppShwPde Receives the address of the pgm pool page for the shadow page directory
1381 */
1382DECLINLINE(int) pgmShwGetPaePoolPagePD(PVMCPU pVCpu, RTGCPTR GCPtr, PPGMPOOLPAGE *ppShwPde)
1383{
1384 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
1385 PX86PDPT pPdpt = pgmShwGetPaePDPTPtr(pVCpu);
1386 PVM pVM = pVCpu->CTX_SUFF(pVM);
1387
1388 PGM_LOCK_ASSERT_OWNER(pVM);
1389
1390 AssertReturn(pPdpt, VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT); /* can't happen */
1391 if (!pPdpt->a[iPdPt].n.u1Present)
1392 {
1393 LogFlow(("pgmShwGetPaePoolPagePD: PD %d not present (%RX64)\n", iPdPt, pPdpt->a[iPdPt].u));
1394 return VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT;
1395 }
1396 AssertMsg(pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK, ("GCPtr=%RGv\n", GCPtr));
1397
1398 /* Fetch the pgm pool shadow descriptor. */
1399 PPGMPOOLPAGE pShwPde = pgmPoolGetPage(pVM->pgm.s.CTX_SUFF(pPool), pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK);
1400 AssertReturn(pShwPde, VERR_PGM_POOL_GET_PAGE_FAILED);
1401
1402 *ppShwPde = pShwPde;
1403 return VINF_SUCCESS;
1404}
1405
1406#ifndef IN_RC
1407
1408/**
1409 * Syncs the SHADOW page directory pointer for the specified address.
1410 *
1411 * Allocates backing pages in case the PDPT or PML4 entry is missing.
1412 *
1413 * The caller is responsible for making sure the guest has a valid PD before
1414 * calling this function.
1415 *
1416 * @returns VBox status code.
1417 * @param pVCpu The cross context virtual CPU structure.
1418 * @param GCPtr The address.
1419 * @param uGstPml4e Guest PML4 entry (valid).
1420 * @param uGstPdpe Guest PDPT entry (valid).
1421 * @param ppPD Receives address of page directory
1422 */
1423static int pgmShwSyncLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, X86PGPAEUINT uGstPml4e, X86PGPAEUINT uGstPdpe, PX86PDPAE *ppPD)
1424{
1425 PVM pVM = pVCpu->CTX_SUFF(pVM);
1426 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1427 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1428 PX86PML4E pPml4e = pgmShwGetLongModePML4EPtr(pVCpu, iPml4);
1429 bool fNestedPagingOrNoGstPaging = pVM->pgm.s.fNestedPaging || !CPUMIsGuestPagingEnabled(pVCpu);
1430 PPGMPOOLPAGE pShwPage;
1431 int rc;
1432
1433 PGM_LOCK_ASSERT_OWNER(pVM);
1434
1435 /* Allocate page directory pointer table if not present. */
1436 if ( !pPml4e->n.u1Present
1437 && !(pPml4e->u & X86_PML4E_PG_MASK))
1438 {
1439 RTGCPTR64 GCPml4;
1440 PGMPOOLKIND enmKind;
1441
1442 Assert(pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
1443
1444 if (fNestedPagingOrNoGstPaging)
1445 {
1446 /* AMD-V nested paging or real/protected mode without paging */
1447 GCPml4 = (RTGCPTR64)iPml4 << X86_PML4_SHIFT;
1448 enmKind = PGMPOOLKIND_64BIT_PDPT_FOR_PHYS;
1449 }
1450 else
1451 {
1452 GCPml4 = uGstPml4e & X86_PML4E_PG_MASK;
1453 enmKind = PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT;
1454 }
1455
1456 /* Create a reference back to the PDPT by using the index in its shadow page. */
1457 rc = pgmPoolAlloc(pVM, GCPml4, enmKind, PGMPOOLACCESS_DONTCARE, PGM_A20_IS_ENABLED(pVCpu),
1458 pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iPml4, false /*fLockPage*/,
1459 &pShwPage);
1460 AssertRCReturn(rc, rc);
1461 }
1462 else
1463 {
1464 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & X86_PML4E_PG_MASK);
1465 AssertReturn(pShwPage, VERR_PGM_POOL_GET_PAGE_FAILED);
1466
1467 pgmPoolCacheUsed(pPool, pShwPage);
1468 }
1469 /* The PDPT was cached or created; hook it up now. */
1470 pPml4e->u |= pShwPage->Core.Key | (uGstPml4e & pVCpu->pgm.s.fGstAmd64ShadowedPml4eMask);
1471
1472 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1473 PX86PDPT pPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPage);
1474 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
1475
1476 /* Allocate page directory if not present. */
1477 if ( !pPdpe->n.u1Present
1478 && !(pPdpe->u & X86_PDPE_PG_MASK))
1479 {
1480 RTGCPTR64 GCPdPt;
1481 PGMPOOLKIND enmKind;
1482
1483 if (fNestedPagingOrNoGstPaging)
1484 {
1485 /* AMD-V nested paging or real/protected mode without paging */
1486 GCPdPt = (RTGCPTR64)iPdPt << X86_PDPT_SHIFT;
1487 enmKind = PGMPOOLKIND_64BIT_PD_FOR_PHYS;
1488 }
1489 else
1490 {
1491 GCPdPt = uGstPdpe & X86_PDPE_PG_MASK;
1492 enmKind = PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD;
1493 }
1494
1495 /* Create a reference back to the PDPT by using the index in its shadow page. */
1496 rc = pgmPoolAlloc(pVM, GCPdPt, enmKind, PGMPOOLACCESS_DONTCARE, PGM_A20_IS_ENABLED(pVCpu),
1497 pShwPage->idx, iPdPt, false /*fLockPage*/,
1498 &pShwPage);
1499 AssertRCReturn(rc, rc);
1500 }
1501 else
1502 {
1503 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
1504 AssertReturn(pShwPage, VERR_PGM_POOL_GET_PAGE_FAILED);
1505
1506 pgmPoolCacheUsed(pPool, pShwPage);
1507 }
1508 /* The PD was cached or created; hook it up now. */
1509 pPdpe->u |= pShwPage->Core.Key | (uGstPdpe & pVCpu->pgm.s.fGstAmd64ShadowedPdpeMask);
1510
1511 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPage);
1512 return VINF_SUCCESS;
1513}
1514
1515
1516/**
1517 * Gets the SHADOW page directory pointer for the specified address (long mode).
1518 *
1519 * @returns VBox status code.
1520 * @param pVCpu The cross context virtual CPU structure.
1521 * @param GCPtr The address.
1522 * @param ppPdpt Receives address of pdpt
1523 * @param ppPD Receives address of page directory
1524 */
1525DECLINLINE(int) pgmShwGetLongModePDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PX86PML4E *ppPml4e, PX86PDPT *ppPdpt, PX86PDPAE *ppPD)
1526{
1527 const unsigned iPml4 = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
1528 PCX86PML4E pPml4e = pgmShwGetLongModePML4EPtr(pVCpu, iPml4);
1529
1530 PGM_LOCK_ASSERT_OWNER(pVCpu->CTX_SUFF(pVM));
1531
1532 AssertReturn(pPml4e, VERR_PGM_PML4_MAPPING);
1533 if (ppPml4e)
1534 *ppPml4e = (PX86PML4E)pPml4e;
1535
1536 Log4(("pgmShwGetLongModePDPtr %RGv (%RHv) %RX64\n", GCPtr, pPml4e, pPml4e->u));
1537
1538 if (!pPml4e->n.u1Present)
1539 return VERR_PAGE_MAP_LEVEL4_NOT_PRESENT;
1540
1541 PVM pVM = pVCpu->CTX_SUFF(pVM);
1542 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1543 PPGMPOOLPAGE pShwPage = pgmPoolGetPage(pPool, pPml4e->u & X86_PML4E_PG_MASK);
1544 AssertReturn(pShwPage, VERR_PGM_POOL_GET_PAGE_FAILED);
1545
1546 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1547 PCX86PDPT pPdpt = *ppPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPage);
1548 if (!pPdpt->a[iPdPt].n.u1Present)
1549 return VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT;
1550
1551 pShwPage = pgmPoolGetPage(pPool, pPdpt->a[iPdPt].u & X86_PDPE_PG_MASK);
1552 AssertReturn(pShwPage, VERR_PGM_POOL_GET_PAGE_FAILED);
1553
1554 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPage);
1555 Log4(("pgmShwGetLongModePDPtr %RGv -> *ppPD=%p PDE=%p/%RX64\n", GCPtr, *ppPD, &(*ppPD)->a[(GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK], (*ppPD)->a[(GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK].u));
1556 return VINF_SUCCESS;
1557}
1558
1559
1560/**
1561 * Syncs the SHADOW EPT page directory pointer for the specified address. Allocates
1562 * backing pages in case the PDPT or PML4 entry is missing.
1563 *
1564 * @returns VBox status code.
1565 * @param pVCpu The cross context virtual CPU structure.
1566 * @param GCPtr The address.
1567 * @param ppPdpt Receives address of pdpt
1568 * @param ppPD Receives address of page directory
1569 */
1570static int pgmShwGetEPTPDPtr(PVMCPU pVCpu, RTGCPTR64 GCPtr, PEPTPDPT *ppPdpt, PEPTPD *ppPD)
1571{
1572 PVM pVM = pVCpu->CTX_SUFF(pVM);
1573 const unsigned iPml4 = (GCPtr >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
1574 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
1575 PEPTPML4 pPml4;
1576 PEPTPML4E pPml4e;
1577 PPGMPOOLPAGE pShwPage;
1578 int rc;
1579
1580 Assert(pVM->pgm.s.fNestedPaging);
1581 PGM_LOCK_ASSERT_OWNER(pVM);
1582
1583 pPml4 = (PEPTPML4)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
1584 Assert(pPml4);
1585
1586 /* Allocate page directory pointer table if not present. */
1587 pPml4e = &pPml4->a[iPml4];
1588 if ( !pPml4e->n.u1Present
1589 && !(pPml4e->u & EPT_PML4E_PG_MASK))
1590 {
1591 Assert(!(pPml4e->u & EPT_PML4E_PG_MASK));
1592 RTGCPTR64 GCPml4 = (RTGCPTR64)iPml4 << EPT_PML4_SHIFT;
1593
1594 rc = pgmPoolAlloc(pVM, GCPml4, PGMPOOLKIND_EPT_PDPT_FOR_PHYS, PGMPOOLACCESS_DONTCARE, PGM_A20_IS_ENABLED(pVCpu),
1595 pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iPml4, false /*fLockPage*/,
1596 &pShwPage);
1597 AssertRCReturn(rc, rc);
1598 }
1599 else
1600 {
1601 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & EPT_PML4E_PG_MASK);
1602 AssertReturn(pShwPage, VERR_PGM_POOL_GET_PAGE_FAILED);
1603
1604 pgmPoolCacheUsed(pPool, pShwPage);
1605 }
1606 /* The PDPT was cached or created; hook it up now and fill with the default value. */
1607 pPml4e->u = pShwPage->Core.Key;
1608 pPml4e->n.u1Present = 1;
1609 pPml4e->n.u1Write = 1;
1610 pPml4e->n.u1Execute = 1;
1611
1612 const unsigned iPdPt = (GCPtr >> EPT_PDPT_SHIFT) & EPT_PDPT_MASK;
1613 PEPTPDPT pPdpt = (PEPTPDPT)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPage);
1614 PEPTPDPTE pPdpe = &pPdpt->a[iPdPt];
1615
1616 if (ppPdpt)
1617 *ppPdpt = pPdpt;
1618
1619 /* Allocate page directory if not present. */
1620 if ( !pPdpe->n.u1Present
1621 && !(pPdpe->u & EPT_PDPTE_PG_MASK))
1622 {
1623 RTGCPTR64 GCPdPt = (RTGCPTR64)iPdPt << EPT_PDPT_SHIFT;
1624 rc = pgmPoolAlloc(pVM, GCPdPt, PGMPOOLKIND_EPT_PD_FOR_PHYS, PGMPOOLACCESS_DONTCARE, PGM_A20_IS_ENABLED(pVCpu),
1625 pShwPage->idx, iPdPt, false /*fLockPage*/,
1626 &pShwPage);
1627 AssertRCReturn(rc, rc);
1628 }
1629 else
1630 {
1631 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & EPT_PDPTE_PG_MASK);
1632 AssertReturn(pShwPage, VERR_PGM_POOL_GET_PAGE_FAILED);
1633
1634 pgmPoolCacheUsed(pPool, pShwPage);
1635 }
1636 /* The PD was cached or created; hook it up now and fill with the default value. */
1637 pPdpe->u = pShwPage->Core.Key;
1638 pPdpe->n.u1Present = 1;
1639 pPdpe->n.u1Write = 1;
1640 pPdpe->n.u1Execute = 1;
1641
1642 *ppPD = (PEPTPD)PGMPOOL_PAGE_2_PTR_V2(pVM, pVCpu, pShwPage);
1643 return VINF_SUCCESS;
1644}
1645
1646#endif /* IN_RC */
1647
1648#ifdef IN_RING0
1649/**
1650 * Synchronizes a range of nested page table entries.
1651 *
1652 * The caller must own the PGM lock.
1653 *
1654 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1655 * @param GCPhys Where to start.
1656 * @param cPages How many pages which entries should be synced.
1657 * @param enmShwPagingMode The shadow paging mode (PGMMODE_EPT for VT-x,
1658 * host paging mode for AMD-V).
1659 */
1660int pgmShwSyncNestedPageLocked(PVMCPU pVCpu, RTGCPHYS GCPhys, uint32_t cPages, PGMMODE enmShwPagingMode)
1661{
1662 PGM_LOCK_ASSERT_OWNER(pVCpu->CTX_SUFF(pVM));
1663
1664 int rc;
1665 switch (enmShwPagingMode)
1666 {
1667 case PGMMODE_32_BIT:
1668 {
1669 X86PDE PdeDummy = { X86_PDE_P | X86_PDE_US | X86_PDE_RW | X86_PDE_A };
1670 rc = PGM_BTH_NAME_32BIT_PROT(SyncPage)(pVCpu, PdeDummy, GCPhys, cPages, ~0U /*uErr*/);
1671 break;
1672 }
1673
1674 case PGMMODE_PAE:
1675 case PGMMODE_PAE_NX:
1676 {
1677 X86PDEPAE PdeDummy = { X86_PDE_P | X86_PDE_US | X86_PDE_RW | X86_PDE_A };
1678 rc = PGM_BTH_NAME_PAE_PROT(SyncPage)(pVCpu, PdeDummy, GCPhys, cPages, ~0U /*uErr*/);
1679 break;
1680 }
1681
1682 case PGMMODE_AMD64:
1683 case PGMMODE_AMD64_NX:
1684 {
1685 X86PDEPAE PdeDummy = { X86_PDE_P | X86_PDE_US | X86_PDE_RW | X86_PDE_A };
1686 rc = PGM_BTH_NAME_AMD64_PROT(SyncPage)(pVCpu, PdeDummy, GCPhys, cPages, ~0U /*uErr*/);
1687 break;
1688 }
1689
1690 case PGMMODE_EPT:
1691 {
1692 X86PDEPAE PdeDummy = { X86_PDE_P | X86_PDE_US | X86_PDE_RW | X86_PDE_A };
1693 rc = PGM_BTH_NAME_EPT_PROT(SyncPage)(pVCpu, PdeDummy, GCPhys, cPages, ~0U /*uErr*/);
1694 break;
1695 }
1696
1697 default:
1698 AssertMsgFailedReturn(("%d\n", enmShwPagingMode), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
1699 }
1700 return rc;
1701}
1702#endif /* IN_RING0 */
1703
1704
1705/**
1706 * Gets effective Guest OS page information.
1707 *
1708 * When GCPtr is in a big page, the function will return as if it was a normal
1709 * 4KB page. If the need for distinguishing between big and normal page becomes
1710 * necessary at a later point, a PGMGstGetPage() will be created for that
1711 * purpose.
1712 *
1713 * @returns VBox status code.
1714 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1715 * @param GCPtr Guest Context virtual address of the page.
1716 * @param pfFlags Where to store the flags. These are X86_PTE_*, even for big pages.
1717 * @param pGCPhys Where to store the GC physical address of the page.
1718 * This is page aligned. The fact that the
1719 */
1720VMMDECL(int) PGMGstGetPage(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys)
1721{
1722 VMCPU_ASSERT_EMT(pVCpu);
1723 uintptr_t idx = pVCpu->pgm.s.idxGuestModeData;
1724 AssertReturn(idx < RT_ELEMENTS(g_aPgmGuestModeData), VERR_PGM_MODE_IPE);
1725 AssertReturn(g_aPgmGuestModeData[idx].pfnGetPage, VERR_PGM_MODE_IPE);
1726 return g_aPgmGuestModeData[idx].pfnGetPage(pVCpu, GCPtr, pfFlags, pGCPhys);
1727}
1728
1729
1730/**
1731 * Performs a guest page table walk.
1732 *
1733 * The guest should be in paged protect mode or long mode when making a call to
1734 * this function.
1735 *
1736 * @returns VBox status code.
1737 * @retval VINF_SUCCESS on success.
1738 * @retval VERR_PAGE_TABLE_NOT_PRESENT on failure. Check pWalk for details.
1739 * @retval VERR_PGM_NOT_USED_IN_MODE if not paging isn't enabled. @a pWalk is
1740 * not valid, except enmType is PGMPTWALKGSTTYPE_INVALID.
1741 *
1742 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1743 * @param GCPtr The guest virtual address to walk by.
1744 * @param pWalk Where to return the walk result. This is valid for some
1745 * error codes as well.
1746 */
1747int pgmGstPtWalk(PVMCPU pVCpu, RTGCPTR GCPtr, PPGMPTWALKGST pWalk)
1748{
1749 VMCPU_ASSERT_EMT(pVCpu);
1750 switch (pVCpu->pgm.s.enmGuestMode)
1751 {
1752 case PGMMODE_32_BIT:
1753 pWalk->enmType = PGMPTWALKGSTTYPE_32BIT;
1754 return PGM_GST_NAME_32BIT(Walk)(pVCpu, GCPtr, &pWalk->u.Legacy);
1755
1756 case PGMMODE_PAE:
1757 case PGMMODE_PAE_NX:
1758 pWalk->enmType = PGMPTWALKGSTTYPE_PAE;
1759 return PGM_GST_NAME_PAE(Walk)(pVCpu, GCPtr, &pWalk->u.Pae);
1760
1761#if !defined(IN_RC)
1762 case PGMMODE_AMD64:
1763 case PGMMODE_AMD64_NX:
1764 pWalk->enmType = PGMPTWALKGSTTYPE_AMD64;
1765 return PGM_GST_NAME_AMD64(Walk)(pVCpu, GCPtr, &pWalk->u.Amd64);
1766#endif
1767
1768 case PGMMODE_REAL:
1769 case PGMMODE_PROTECTED:
1770 pWalk->enmType = PGMPTWALKGSTTYPE_INVALID;
1771 return VERR_PGM_NOT_USED_IN_MODE;
1772
1773#if defined(IN_RC)
1774 case PGMMODE_AMD64:
1775 case PGMMODE_AMD64_NX:
1776#endif
1777 case PGMMODE_NESTED_32BIT:
1778 case PGMMODE_NESTED_PAE:
1779 case PGMMODE_NESTED_AMD64:
1780 case PGMMODE_EPT:
1781 default:
1782 AssertFailed();
1783 pWalk->enmType = PGMPTWALKGSTTYPE_INVALID;
1784 return VERR_PGM_NOT_USED_IN_MODE;
1785 }
1786}
1787
1788
1789/**
1790 * Tries to continue the previous walk.
1791 *
1792 * @note Requires the caller to hold the PGM lock from the first
1793 * pgmGstPtWalk() call to the last pgmGstPtWalkNext() call. Otherwise
1794 * we cannot use the pointers.
1795 *
1796 * @returns VBox status code.
1797 * @retval VINF_SUCCESS on success.
1798 * @retval VERR_PAGE_TABLE_NOT_PRESENT on failure. Check pWalk for details.
1799 * @retval VERR_PGM_NOT_USED_IN_MODE if not paging isn't enabled. @a pWalk is
1800 * not valid, except enmType is PGMPTWALKGSTTYPE_INVALID.
1801 *
1802 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1803 * @param GCPtr The guest virtual address to walk by.
1804 * @param pWalk Pointer to the previous walk result and where to return
1805 * the result of this walk. This is valid for some error
1806 * codes as well.
1807 */
1808int pgmGstPtWalkNext(PVMCPU pVCpu, RTGCPTR GCPtr, PPGMPTWALKGST pWalk)
1809{
1810 /*
1811 * We can only handle successfully walks.
1812 * We also limit ourselves to the next page.
1813 */
1814 if ( pWalk->u.Core.fSucceeded
1815 && GCPtr - pWalk->u.Core.GCPtr == PAGE_SIZE)
1816 {
1817 Assert(pWalk->u.Core.uLevel == 0);
1818 if (pWalk->enmType == PGMPTWALKGSTTYPE_AMD64)
1819 {
1820 /*
1821 * AMD64
1822 */
1823 if (!pWalk->u.Core.fGigantPage && !pWalk->u.Core.fBigPage)
1824 {
1825 /*
1826 * We fall back to full walk if the PDE table changes, if any
1827 * reserved bits are set, or if the effective page access changes.
1828 */
1829 const uint64_t fPteSame = X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_PWT
1830 | X86_PTE_PCD | X86_PTE_A | X86_PTE_PAE_NX;
1831 const uint64_t fPdeSame = X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_PWT
1832 | X86_PDE_PCD | X86_PDE_A | X86_PDE_PAE_NX | X86_PDE_PS;
1833
1834 if ((GCPtr >> X86_PD_PAE_SHIFT) == (pWalk->u.Core.GCPtr >> X86_PD_PAE_SHIFT))
1835 {
1836 if (pWalk->u.Amd64.pPte)
1837 {
1838 X86PTEPAE Pte;
1839 Pte.u = pWalk->u.Amd64.pPte[1].u;
1840 if ( (Pte.u & fPteSame) == (pWalk->u.Amd64.Pte.u & fPteSame)
1841 && !(Pte.u & (pVCpu)->pgm.s.fGstAmd64MbzPteMask))
1842 {
1843
1844 pWalk->u.Core.GCPtr = GCPtr;
1845 pWalk->u.Core.GCPhys = Pte.u & X86_PTE_PAE_PG_MASK;
1846 pWalk->u.Amd64.Pte.u = Pte.u;
1847 pWalk->u.Amd64.pPte++;
1848 return VINF_SUCCESS;
1849 }
1850 }
1851 }
1852 else if ((GCPtr >> X86_PDPT_SHIFT) == (pWalk->u.Core.GCPtr >> X86_PDPT_SHIFT))
1853 {
1854 Assert(!((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK)); /* Must be first PT entry. */
1855 if (pWalk->u.Amd64.pPde)
1856 {
1857 X86PDEPAE Pde;
1858 Pde.u = pWalk->u.Amd64.pPde[1].u;
1859 if ( (Pde.u & fPdeSame) == (pWalk->u.Amd64.Pde.u & fPdeSame)
1860 && !(Pde.u & (pVCpu)->pgm.s.fGstAmd64MbzPdeMask))
1861 {
1862 /* Get the new PTE and check out the first entry. */
1863 int rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, PGM_A20_APPLY(pVCpu, (Pde.u & X86_PDE_PAE_PG_MASK)),
1864 &pWalk->u.Amd64.pPt);
1865 if (RT_SUCCESS(rc))
1866 {
1867 pWalk->u.Amd64.pPte = &pWalk->u.Amd64.pPt->a[0];
1868 X86PTEPAE Pte;
1869 Pte.u = pWalk->u.Amd64.pPte->u;
1870 if ( (Pte.u & fPteSame) == (pWalk->u.Amd64.Pte.u & fPteSame)
1871 && !(Pte.u & (pVCpu)->pgm.s.fGstAmd64MbzPteMask))
1872 {
1873 pWalk->u.Core.GCPtr = GCPtr;
1874 pWalk->u.Core.GCPhys = Pte.u & X86_PTE_PAE_PG_MASK;
1875 pWalk->u.Amd64.Pte.u = Pte.u;
1876 pWalk->u.Amd64.Pde.u = Pde.u;
1877 pWalk->u.Amd64.pPde++;
1878 return VINF_SUCCESS;
1879 }
1880 }
1881 }
1882 }
1883 }
1884 }
1885 else if (!pWalk->u.Core.fGigantPage)
1886 {
1887 if ((GCPtr & X86_PAGE_2M_BASE_MASK) == (pWalk->u.Core.GCPtr & X86_PAGE_2M_BASE_MASK))
1888 {
1889 pWalk->u.Core.GCPtr = GCPtr;
1890 pWalk->u.Core.GCPhys += PAGE_SIZE;
1891 return VINF_SUCCESS;
1892 }
1893 }
1894 else
1895 {
1896 if ((GCPtr & X86_PAGE_1G_BASE_MASK) == (pWalk->u.Core.GCPtr & X86_PAGE_1G_BASE_MASK))
1897 {
1898 pWalk->u.Core.GCPtr = GCPtr;
1899 pWalk->u.Core.GCPhys += PAGE_SIZE;
1900 return VINF_SUCCESS;
1901 }
1902 }
1903 }
1904 }
1905 /* Case we don't handle. Do full walk. */
1906 return pgmGstPtWalk(pVCpu, GCPtr, pWalk);
1907}
1908
1909
1910/**
1911 * Checks if the page is present.
1912 *
1913 * @returns true if the page is present.
1914 * @returns false if the page is not present.
1915 * @param pVCpu The cross context virtual CPU structure.
1916 * @param GCPtr Address within the page.
1917 */
1918VMMDECL(bool) PGMGstIsPagePresent(PVMCPU pVCpu, RTGCPTR GCPtr)
1919{
1920 VMCPU_ASSERT_EMT(pVCpu);
1921 int rc = PGMGstGetPage(pVCpu, GCPtr, NULL, NULL);
1922 return RT_SUCCESS(rc);
1923}
1924
1925
1926/**
1927 * Sets (replaces) the page flags for a range of pages in the guest's tables.
1928 *
1929 * @returns VBox status code.
1930 * @param pVCpu The cross context virtual CPU structure.
1931 * @param GCPtr The address of the first page.
1932 * @param cb The size of the range in bytes.
1933 * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
1934 */
1935VMMDECL(int) PGMGstSetPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags)
1936{
1937 VMCPU_ASSERT_EMT(pVCpu);
1938 return PGMGstModifyPage(pVCpu, GCPtr, cb, fFlags, 0);
1939}
1940
1941
1942/**
1943 * Modify page flags for a range of pages in the guest's tables
1944 *
1945 * The existing flags are ANDed with the fMask and ORed with the fFlags.
1946 *
1947 * @returns VBox status code.
1948 * @param pVCpu The cross context virtual CPU structure.
1949 * @param GCPtr Virtual address of the first page in the range.
1950 * @param cb Size (in bytes) of the range to apply the modification to.
1951 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
1952 * @param fMask The AND mask - page flags X86_PTE_*, excluding the page mask of course.
1953 * Be very CAREFUL when ~'ing constants which could be 32-bit!
1954 */
1955VMMDECL(int) PGMGstModifyPage(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
1956{
1957 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,GstModifyPage), a);
1958 VMCPU_ASSERT_EMT(pVCpu);
1959
1960 /*
1961 * Validate input.
1962 */
1963 AssertMsg(!(fFlags & X86_PTE_PAE_PG_MASK), ("fFlags=%#llx\n", fFlags));
1964 Assert(cb);
1965
1966 LogFlow(("PGMGstModifyPage %RGv %d bytes fFlags=%08llx fMask=%08llx\n", GCPtr, cb, fFlags, fMask));
1967
1968 /*
1969 * Adjust input.
1970 */
1971 cb += GCPtr & PAGE_OFFSET_MASK;
1972 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
1973 GCPtr = (GCPtr & PAGE_BASE_GC_MASK);
1974
1975 /*
1976 * Call worker.
1977 */
1978 uintptr_t idx = pVCpu->pgm.s.idxGuestModeData;
1979 AssertReturn(idx < RT_ELEMENTS(g_aPgmGuestModeData), VERR_PGM_MODE_IPE);
1980 AssertReturn(g_aPgmGuestModeData[idx].pfnModifyPage, VERR_PGM_MODE_IPE);
1981 int rc = g_aPgmGuestModeData[idx].pfnModifyPage(pVCpu, GCPtr, cb, fFlags, fMask);
1982
1983 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,GstModifyPage), a);
1984 return rc;
1985}
1986
1987
1988#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
1989
1990/**
1991 * Performs the lazy mapping of the 32-bit guest PD.
1992 *
1993 * @returns VBox status code.
1994 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1995 * @param ppPd Where to return the pointer to the mapping. This is
1996 * always set.
1997 */
1998int pgmGstLazyMap32BitPD(PVMCPU pVCpu, PX86PD *ppPd)
1999{
2000 PVM pVM = pVCpu->CTX_SUFF(pVM);
2001 pgmLock(pVM);
2002
2003 Assert(!pVCpu->pgm.s.CTX_SUFF(pGst32BitPd));
2004
2005 RTGCPHYS GCPhysCR3 = pVCpu->pgm.s.GCPhysCR3 & X86_CR3_PAGE_MASK;
2006 PPGMPAGE pPage;
2007 int rc = pgmPhysGetPageEx(pVM, GCPhysCR3, &pPage);
2008 if (RT_SUCCESS(rc))
2009 {
2010 RTHCPTR HCPtrGuestCR3;
2011 rc = pgmPhysGCPhys2CCPtrInternalDepr(pVM, pPage, GCPhysCR3, (void **)&HCPtrGuestCR3);
2012 if (RT_SUCCESS(rc))
2013 {
2014 pVCpu->pgm.s.pGst32BitPdR3 = (R3PTRTYPE(PX86PD))HCPtrGuestCR3;
2015# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2016 pVCpu->pgm.s.pGst32BitPdR0 = (R0PTRTYPE(PX86PD))HCPtrGuestCR3;
2017# endif
2018 *ppPd = (PX86PD)HCPtrGuestCR3;
2019
2020 pgmUnlock(pVM);
2021 return VINF_SUCCESS;
2022 }
2023
2024 AssertRC(rc);
2025 }
2026 pgmUnlock(pVM);
2027
2028 *ppPd = NULL;
2029 return rc;
2030}
2031
2032
2033/**
2034 * Performs the lazy mapping of the PAE guest PDPT.
2035 *
2036 * @returns VBox status code.
2037 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2038 * @param ppPdpt Where to return the pointer to the mapping. This is
2039 * always set.
2040 */
2041int pgmGstLazyMapPaePDPT(PVMCPU pVCpu, PX86PDPT *ppPdpt)
2042{
2043 Assert(!pVCpu->pgm.s.CTX_SUFF(pGstPaePdpt));
2044 PVM pVM = pVCpu->CTX_SUFF(pVM);
2045 pgmLock(pVM);
2046
2047 RTGCPHYS GCPhysCR3 = pVCpu->pgm.s.GCPhysCR3 & X86_CR3_PAE_PAGE_MASK;
2048 PPGMPAGE pPage;
2049 int rc = pgmPhysGetPageEx(pVM, GCPhysCR3, &pPage);
2050 if (RT_SUCCESS(rc))
2051 {
2052 RTHCPTR HCPtrGuestCR3;
2053 rc = pgmPhysGCPhys2CCPtrInternalDepr(pVM, pPage, GCPhysCR3, (void **)&HCPtrGuestCR3);
2054 if (RT_SUCCESS(rc))
2055 {
2056 pVCpu->pgm.s.pGstPaePdptR3 = (R3PTRTYPE(PX86PDPT))HCPtrGuestCR3;
2057# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2058 pVCpu->pgm.s.pGstPaePdptR0 = (R0PTRTYPE(PX86PDPT))HCPtrGuestCR3;
2059# endif
2060 *ppPdpt = (PX86PDPT)HCPtrGuestCR3;
2061
2062 pgmUnlock(pVM);
2063 return VINF_SUCCESS;
2064 }
2065
2066 AssertRC(rc);
2067 }
2068
2069 pgmUnlock(pVM);
2070 *ppPdpt = NULL;
2071 return rc;
2072}
2073
2074
2075/**
2076 * Performs the lazy mapping / updating of a PAE guest PD.
2077 *
2078 * @returns Pointer to the mapping.
2079 * @returns VBox status code.
2080 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2081 * @param iPdpt Which PD entry to map (0..3).
2082 * @param ppPd Where to return the pointer to the mapping. This is
2083 * always set.
2084 */
2085int pgmGstLazyMapPaePD(PVMCPU pVCpu, uint32_t iPdpt, PX86PDPAE *ppPd)
2086{
2087 PVM pVM = pVCpu->CTX_SUFF(pVM);
2088 pgmLock(pVM);
2089
2090 PX86PDPT pGuestPDPT = pVCpu->pgm.s.CTX_SUFF(pGstPaePdpt);
2091 Assert(pGuestPDPT);
2092 Assert(pGuestPDPT->a[iPdpt].n.u1Present);
2093 RTGCPHYS GCPhys = pGuestPDPT->a[iPdpt].u & X86_PDPE_PG_MASK;
2094 bool const fChanged = pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt] != GCPhys;
2095
2096 PPGMPAGE pPage;
2097 int rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage);
2098 if (RT_SUCCESS(rc))
2099 {
2100 RTRCPTR RCPtr = NIL_RTRCPTR;
2101 RTHCPTR HCPtr = NIL_RTHCPTR;
2102#if !defined(IN_RC) && !defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
2103 rc = pgmPhysGCPhys2CCPtrInternalDepr(pVM, pPage, GCPhys, &HCPtr);
2104 AssertRC(rc);
2105#endif
2106 if (RT_SUCCESS(rc) && fChanged)
2107 {
2108 RCPtr = (RTRCPTR)(RTRCUINTPTR)(pVM->pgm.s.GCPtrCR3Mapping + (1 + iPdpt) * PAGE_SIZE);
2109 rc = PGMMap(pVM, (RTRCUINTPTR)RCPtr, PGM_PAGE_GET_HCPHYS(pPage), PAGE_SIZE, 0);
2110 }
2111 if (RT_SUCCESS(rc))
2112 {
2113 pVCpu->pgm.s.apGstPaePDsR3[iPdpt] = (R3PTRTYPE(PX86PDPAE))HCPtr;
2114# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2115 pVCpu->pgm.s.apGstPaePDsR0[iPdpt] = (R0PTRTYPE(PX86PDPAE))HCPtr;
2116# endif
2117 if (fChanged)
2118 {
2119 pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt] = GCPhys;
2120 pVCpu->pgm.s.apGstPaePDsRC[iPdpt] = (RCPTRTYPE(PX86PDPAE))RCPtr;
2121 }
2122
2123 *ppPd = pVCpu->pgm.s.CTX_SUFF(apGstPaePDs)[iPdpt];
2124 pgmUnlock(pVM);
2125 return VINF_SUCCESS;
2126 }
2127 }
2128
2129 /* Invalid page or some failure, invalidate the entry. */
2130 pVCpu->pgm.s.aGCPhysGstPaePDs[iPdpt] = NIL_RTGCPHYS;
2131 pVCpu->pgm.s.apGstPaePDsR3[iPdpt] = 0;
2132# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2133 pVCpu->pgm.s.apGstPaePDsR0[iPdpt] = 0;
2134# endif
2135 pVCpu->pgm.s.apGstPaePDsRC[iPdpt] = 0;
2136
2137 pgmUnlock(pVM);
2138 return rc;
2139}
2140
2141#endif /* !VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
2142#if !defined(IN_RC) && !defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
2143/**
2144 * Performs the lazy mapping of the 32-bit guest PD.
2145 *
2146 * @returns VBox status code.
2147 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2148 * @param ppPml4 Where to return the pointer to the mapping. This will
2149 * always be set.
2150 */
2151int pgmGstLazyMapPml4(PVMCPU pVCpu, PX86PML4 *ppPml4)
2152{
2153 Assert(!pVCpu->pgm.s.CTX_SUFF(pGstAmd64Pml4));
2154 PVM pVM = pVCpu->CTX_SUFF(pVM);
2155 pgmLock(pVM);
2156
2157 RTGCPHYS GCPhysCR3 = pVCpu->pgm.s.GCPhysCR3 & X86_CR3_AMD64_PAGE_MASK;
2158 PPGMPAGE pPage;
2159 int rc = pgmPhysGetPageEx(pVM, GCPhysCR3, &pPage);
2160 if (RT_SUCCESS(rc))
2161 {
2162 RTHCPTR HCPtrGuestCR3;
2163 rc = pgmPhysGCPhys2CCPtrInternalDepr(pVM, pPage, GCPhysCR3, (void **)&HCPtrGuestCR3);
2164 if (RT_SUCCESS(rc))
2165 {
2166 pVCpu->pgm.s.pGstAmd64Pml4R3 = (R3PTRTYPE(PX86PML4))HCPtrGuestCR3;
2167# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2168 pVCpu->pgm.s.pGstAmd64Pml4R0 = (R0PTRTYPE(PX86PML4))HCPtrGuestCR3;
2169# endif
2170 *ppPml4 = (PX86PML4)HCPtrGuestCR3;
2171
2172 pgmUnlock(pVM);
2173 return VINF_SUCCESS;
2174 }
2175 }
2176
2177 pgmUnlock(pVM);
2178 *ppPml4 = NULL;
2179 return rc;
2180}
2181#endif
2182
2183
2184/**
2185 * Gets the PAE PDPEs values cached by the CPU.
2186 *
2187 * @returns VBox status code.
2188 * @param pVCpu The cross context virtual CPU structure.
2189 * @param paPdpes Where to return the four PDPEs. The array
2190 * pointed to must have 4 entries.
2191 */
2192VMM_INT_DECL(int) PGMGstGetPaePdpes(PVMCPU pVCpu, PX86PDPE paPdpes)
2193{
2194 Assert(pVCpu->pgm.s.enmShadowMode == PGMMODE_EPT);
2195
2196 paPdpes[0] = pVCpu->pgm.s.aGstPaePdpeRegs[0];
2197 paPdpes[1] = pVCpu->pgm.s.aGstPaePdpeRegs[1];
2198 paPdpes[2] = pVCpu->pgm.s.aGstPaePdpeRegs[2];
2199 paPdpes[3] = pVCpu->pgm.s.aGstPaePdpeRegs[3];
2200 return VINF_SUCCESS;
2201}
2202
2203
2204/**
2205 * Sets the PAE PDPEs values cached by the CPU.
2206 *
2207 * @remarks This must be called *AFTER* PGMUpdateCR3.
2208 *
2209 * @param pVCpu The cross context virtual CPU structure.
2210 * @param paPdpes The four PDPE values. The array pointed to must
2211 * have exactly 4 entries.
2212 *
2213 * @remarks No-long-jump zone!!!
2214 */
2215VMM_INT_DECL(void) PGMGstUpdatePaePdpes(PVMCPU pVCpu, PCX86PDPE paPdpes)
2216{
2217 Assert(pVCpu->pgm.s.enmShadowMode == PGMMODE_EPT);
2218
2219 for (unsigned i = 0; i < RT_ELEMENTS(pVCpu->pgm.s.aGstPaePdpeRegs); i++)
2220 {
2221 if (pVCpu->pgm.s.aGstPaePdpeRegs[i].u != paPdpes[i].u)
2222 {
2223 pVCpu->pgm.s.aGstPaePdpeRegs[i] = paPdpes[i];
2224
2225 /* Force lazy remapping if it changed in any way. */
2226 pVCpu->pgm.s.apGstPaePDsR3[i] = 0;
2227# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2228 pVCpu->pgm.s.apGstPaePDsR0[i] = 0;
2229# endif
2230 pVCpu->pgm.s.apGstPaePDsRC[i] = 0;
2231 pVCpu->pgm.s.aGCPhysGstPaePDs[i] = NIL_RTGCPHYS;
2232 }
2233 }
2234
2235 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES);
2236}
2237
2238
2239/**
2240 * Gets the current CR3 register value for the shadow memory context.
2241 * @returns CR3 value.
2242 * @param pVCpu The cross context virtual CPU structure.
2243 */
2244VMMDECL(RTHCPHYS) PGMGetHyperCR3(PVMCPU pVCpu)
2245{
2246 PPGMPOOLPAGE pPoolPage = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
2247 AssertPtrReturn(pPoolPage, 0);
2248 return pPoolPage->Core.Key;
2249}
2250
2251
2252/**
2253 * Gets the current CR3 register value for the nested memory context.
2254 * @returns CR3 value.
2255 * @param pVCpu The cross context virtual CPU structure.
2256 * @param enmShadowMode The shadow paging mode.
2257 */
2258VMMDECL(RTHCPHYS) PGMGetNestedCR3(PVMCPU pVCpu, PGMMODE enmShadowMode)
2259{
2260 NOREF(enmShadowMode);
2261 Assert(pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
2262 return pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->Core.Key;
2263}
2264
2265
2266/**
2267 * Gets the current CR3 register value for the HC intermediate memory context.
2268 * @returns CR3 value.
2269 * @param pVM The cross context VM structure.
2270 */
2271VMMDECL(RTHCPHYS) PGMGetInterHCCR3(PVM pVM)
2272{
2273 switch (pVM->pgm.s.enmHostMode)
2274 {
2275 case SUPPAGINGMODE_32_BIT:
2276 case SUPPAGINGMODE_32_BIT_GLOBAL:
2277 return pVM->pgm.s.HCPhysInterPD;
2278
2279 case SUPPAGINGMODE_PAE:
2280 case SUPPAGINGMODE_PAE_GLOBAL:
2281 case SUPPAGINGMODE_PAE_NX:
2282 case SUPPAGINGMODE_PAE_GLOBAL_NX:
2283 return pVM->pgm.s.HCPhysInterPaePDPT;
2284
2285 case SUPPAGINGMODE_AMD64:
2286 case SUPPAGINGMODE_AMD64_GLOBAL:
2287 case SUPPAGINGMODE_AMD64_NX:
2288 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
2289 return pVM->pgm.s.HCPhysInterPaePDPT;
2290
2291 default:
2292 AssertMsgFailed(("enmHostMode=%d\n", pVM->pgm.s.enmHostMode));
2293 return NIL_RTHCPHYS;
2294 }
2295}
2296
2297
2298/**
2299 * Gets the current CR3 register value for the RC intermediate memory context.
2300 * @returns CR3 value.
2301 * @param pVM The cross context VM structure.
2302 * @param pVCpu The cross context virtual CPU structure.
2303 */
2304VMMDECL(RTHCPHYS) PGMGetInterRCCR3(PVM pVM, PVMCPU pVCpu)
2305{
2306 switch (pVCpu->pgm.s.enmShadowMode)
2307 {
2308 case PGMMODE_32_BIT:
2309 return pVM->pgm.s.HCPhysInterPD;
2310
2311 case PGMMODE_PAE:
2312 case PGMMODE_PAE_NX:
2313 return pVM->pgm.s.HCPhysInterPaePDPT;
2314
2315 case PGMMODE_AMD64:
2316 case PGMMODE_AMD64_NX:
2317 return pVM->pgm.s.HCPhysInterPaePML4;
2318
2319 case PGMMODE_NESTED_32BIT:
2320 case PGMMODE_NESTED_PAE:
2321 case PGMMODE_NESTED_AMD64:
2322 case PGMMODE_EPT:
2323 return 0; /* not relevant */
2324
2325 default:
2326 AssertMsgFailed(("enmShadowMode=%d\n", pVCpu->pgm.s.enmShadowMode));
2327 return NIL_RTHCPHYS;
2328 }
2329}
2330
2331
2332/**
2333 * Gets the CR3 register value for the 32-Bit intermediate memory context.
2334 * @returns CR3 value.
2335 * @param pVM The cross context VM structure.
2336 */
2337VMMDECL(RTHCPHYS) PGMGetInter32BitCR3(PVM pVM)
2338{
2339 return pVM->pgm.s.HCPhysInterPD;
2340}
2341
2342
2343/**
2344 * Gets the CR3 register value for the PAE intermediate memory context.
2345 * @returns CR3 value.
2346 * @param pVM The cross context VM structure.
2347 */
2348VMMDECL(RTHCPHYS) PGMGetInterPaeCR3(PVM pVM)
2349{
2350 return pVM->pgm.s.HCPhysInterPaePDPT;
2351}
2352
2353
2354/**
2355 * Gets the CR3 register value for the AMD64 intermediate memory context.
2356 * @returns CR3 value.
2357 * @param pVM The cross context VM structure.
2358 */
2359VMMDECL(RTHCPHYS) PGMGetInterAmd64CR3(PVM pVM)
2360{
2361 return pVM->pgm.s.HCPhysInterPaePML4;
2362}
2363
2364
2365/**
2366 * Performs and schedules necessary updates following a CR3 load or reload.
2367 *
2368 * This will normally involve mapping the guest PD or nPDPT
2369 *
2370 * @returns VBox status code.
2371 * @retval VINF_PGM_SYNC_CR3 if monitoring requires a CR3 sync. This can
2372 * safely be ignored and overridden since the FF will be set too then.
2373 * @param pVCpu The cross context virtual CPU structure.
2374 * @param cr3 The new cr3.
2375 * @param fGlobal Indicates whether this is a global flush or not.
2376 */
2377VMMDECL(int) PGMFlushTLB(PVMCPU pVCpu, uint64_t cr3, bool fGlobal)
2378{
2379 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FlushTLB), a);
2380 PVM pVM = pVCpu->CTX_SUFF(pVM);
2381
2382 VMCPU_ASSERT_EMT(pVCpu);
2383
2384 /*
2385 * Always flag the necessary updates; necessary for hardware acceleration
2386 */
2387 /** @todo optimize this, it shouldn't always be necessary. */
2388 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
2389 if (fGlobal)
2390 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2391 LogFlow(("PGMFlushTLB: cr3=%RX64 OldCr3=%RX64 fGlobal=%d\n", cr3, pVCpu->pgm.s.GCPhysCR3, fGlobal));
2392
2393 /*
2394 * Remap the CR3 content and adjust the monitoring if CR3 was actually changed.
2395 */
2396 int rc = VINF_SUCCESS;
2397 RTGCPHYS GCPhysCR3;
2398 switch (pVCpu->pgm.s.enmGuestMode)
2399 {
2400 case PGMMODE_PAE:
2401 case PGMMODE_PAE_NX:
2402 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
2403 break;
2404 case PGMMODE_AMD64:
2405 case PGMMODE_AMD64_NX:
2406 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
2407 break;
2408 default:
2409 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
2410 break;
2411 }
2412 PGM_A20_APPLY_TO_VAR(pVCpu, GCPhysCR3);
2413
2414 if (pVCpu->pgm.s.GCPhysCR3 != GCPhysCR3)
2415 {
2416 RTGCPHYS GCPhysOldCR3 = pVCpu->pgm.s.GCPhysCR3;
2417 pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3;
2418 rc = PGM_BTH_PFN(MapCR3, pVCpu)(pVCpu, GCPhysCR3);
2419 if (RT_LIKELY(rc == VINF_SUCCESS))
2420 {
2421 if (pgmMapAreMappingsFloating(pVM))
2422 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
2423 }
2424 else
2425 {
2426 AssertMsg(rc == VINF_PGM_SYNC_CR3, ("%Rrc\n", rc));
2427 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_PGM_SYNC_CR3));
2428 pVCpu->pgm.s.GCPhysCR3 = GCPhysOldCR3;
2429 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_MAP_CR3;
2430 if (pgmMapAreMappingsFloating(pVM))
2431 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_MONITOR_CR3;
2432 }
2433
2434 if (fGlobal)
2435 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FlushTLBNewCR3Global));
2436 else
2437 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FlushTLBNewCR3));
2438 }
2439 else
2440 {
2441# ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
2442 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
2443 if (pPool->cDirtyPages)
2444 {
2445 pgmLock(pVM);
2446 pgmPoolResetDirtyPages(pVM);
2447 pgmUnlock(pVM);
2448 }
2449# endif
2450 /*
2451 * Check if we have a pending update of the CR3 monitoring.
2452 */
2453 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
2454 {
2455 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
2456 Assert(!pVM->pgm.s.fMappingsFixed); Assert(pgmMapAreMappingsEnabled(pVM));
2457 }
2458 if (fGlobal)
2459 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FlushTLBSameCR3Global));
2460 else
2461 STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FlushTLBSameCR3));
2462 }
2463
2464 IEMTlbInvalidateAll(pVCpu, false /*fVmm*/);
2465 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,FlushTLB), a);
2466 return rc;
2467}
2468
2469
2470/**
2471 * Performs and schedules necessary updates following a CR3 load or reload when
2472 * using nested or extended paging.
2473 *
2474 * This API is an alternative to PGMFlushTLB that avoids actually flushing the
2475 * TLB and triggering a SyncCR3.
2476 *
2477 * This will normally involve mapping the guest PD or nPDPT
2478 *
2479 * @returns VBox status code.
2480 * @retval VINF_SUCCESS.
2481 * @retval VINF_PGM_SYNC_CR3 if monitoring requires a CR3 sync (not for nested
2482 * paging modes). This can safely be ignored and overridden since the
2483 * FF will be set too then.
2484 * @param pVCpu The cross context virtual CPU structure.
2485 * @param cr3 The new cr3.
2486 */
2487VMMDECL(int) PGMUpdateCR3(PVMCPU pVCpu, uint64_t cr3)
2488{
2489 VMCPU_ASSERT_EMT(pVCpu);
2490 LogFlow(("PGMUpdateCR3: cr3=%RX64 OldCr3=%RX64\n", cr3, pVCpu->pgm.s.GCPhysCR3));
2491
2492 /* We assume we're only called in nested paging mode. */
2493 Assert(pVCpu->CTX_SUFF(pVM)->pgm.s.fNestedPaging || pVCpu->pgm.s.enmShadowMode == PGMMODE_EPT);
2494 Assert(!pgmMapAreMappingsEnabled(pVCpu->CTX_SUFF(pVM)));
2495 Assert(!(pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3));
2496
2497 /*
2498 * Remap the CR3 content and adjust the monitoring if CR3 was actually changed.
2499 */
2500 int rc = VINF_SUCCESS;
2501 RTGCPHYS GCPhysCR3;
2502 switch (pVCpu->pgm.s.enmGuestMode)
2503 {
2504 case PGMMODE_PAE:
2505 case PGMMODE_PAE_NX:
2506 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
2507 break;
2508 case PGMMODE_AMD64:
2509 case PGMMODE_AMD64_NX:
2510 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
2511 break;
2512 default:
2513 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
2514 break;
2515 }
2516 PGM_A20_APPLY_TO_VAR(pVCpu, GCPhysCR3);
2517
2518 if (pVCpu->pgm.s.GCPhysCR3 != GCPhysCR3)
2519 {
2520 pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3;
2521 rc = PGM_BTH_PFN(MapCR3, pVCpu)(pVCpu, GCPhysCR3);
2522 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. */
2523 }
2524
2525 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
2526 return rc;
2527}
2528
2529
2530/**
2531 * Synchronize the paging structures.
2532 *
2533 * This function is called in response to the VM_FF_PGM_SYNC_CR3 and
2534 * VM_FF_PGM_SYNC_CR3_NONGLOBAL. Those two force action flags are set
2535 * in several places, most importantly whenever the CR3 is loaded.
2536 *
2537 * @returns VBox status code. May return VINF_PGM_SYNC_CR3 in RC/R0.
2538 * @retval VERR_PGM_NO_HYPERVISOR_ADDRESS in raw-mode when we're unable to map
2539 * the VMM into guest context.
2540 * @param pVCpu The cross context virtual CPU structure.
2541 * @param cr0 Guest context CR0 register
2542 * @param cr3 Guest context CR3 register
2543 * @param cr4 Guest context CR4 register
2544 * @param fGlobal Including global page directories or not
2545 */
2546VMMDECL(int) PGMSyncCR3(PVMCPU pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal)
2547{
2548 int rc;
2549
2550 VMCPU_ASSERT_EMT(pVCpu);
2551
2552 /*
2553 * The pool may have pending stuff and even require a return to ring-3 to
2554 * clear the whole thing.
2555 */
2556 rc = pgmPoolSyncCR3(pVCpu);
2557 if (rc != VINF_SUCCESS)
2558 return rc;
2559
2560 /*
2561 * We might be called when we shouldn't.
2562 *
2563 * The mode switching will ensure that the PD is resynced after every mode
2564 * switch. So, if we find ourselves here when in protected or real mode
2565 * we can safely clear the FF and return immediately.
2566 */
2567 if (pVCpu->pgm.s.enmGuestMode <= PGMMODE_PROTECTED)
2568 {
2569 Assert((cr0 & (X86_CR0_PG | X86_CR0_PE)) != (X86_CR0_PG | X86_CR0_PE));
2570 Assert(!(pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL));
2571 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2572 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
2573 return VINF_SUCCESS;
2574 }
2575
2576 /* If global pages are not supported, then all flushes are global. */
2577 if (!(cr4 & X86_CR4_PGE))
2578 fGlobal = true;
2579 LogFlow(("PGMSyncCR3: cr0=%RX64 cr3=%RX64 cr4=%RX64 fGlobal=%d[%d,%d]\n", cr0, cr3, cr4, fGlobal,
2580 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3), VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL)));
2581
2582 /*
2583 * Check if we need to finish an aborted MapCR3 call (see PGMFlushTLB).
2584 * This should be done before SyncCR3.
2585 */
2586 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MAP_CR3)
2587 {
2588 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MAP_CR3;
2589
2590 RTGCPHYS GCPhysCR3Old = pVCpu->pgm.s.GCPhysCR3; NOREF(GCPhysCR3Old);
2591 RTGCPHYS GCPhysCR3;
2592 switch (pVCpu->pgm.s.enmGuestMode)
2593 {
2594 case PGMMODE_PAE:
2595 case PGMMODE_PAE_NX:
2596 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
2597 break;
2598 case PGMMODE_AMD64:
2599 case PGMMODE_AMD64_NX:
2600 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_AMD64_PAGE_MASK);
2601 break;
2602 default:
2603 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
2604 break;
2605 }
2606 PGM_A20_APPLY_TO_VAR(pVCpu, GCPhysCR3);
2607
2608 if (pVCpu->pgm.s.GCPhysCR3 != GCPhysCR3)
2609 {
2610 pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3;
2611 rc = PGM_BTH_PFN(MapCR3, pVCpu)(pVCpu, GCPhysCR3);
2612 }
2613
2614 /* Make sure we check for pending pgm pool syncs as we clear VMCPU_FF_PGM_SYNC_CR3 later on! */
2615 if ( rc == VINF_PGM_SYNC_CR3
2616 || (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL))
2617 {
2618 Log(("PGMSyncCR3: pending pgm pool sync after MapCR3!\n"));
2619#ifdef IN_RING3
2620 rc = pgmPoolSyncCR3(pVCpu);
2621#else
2622 if (rc == VINF_PGM_SYNC_CR3)
2623 pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3Old;
2624 return VINF_PGM_SYNC_CR3;
2625#endif
2626 }
2627 AssertRCReturn(rc, rc);
2628 AssertRCSuccessReturn(rc, VERR_IPE_UNEXPECTED_INFO_STATUS);
2629 }
2630
2631 /*
2632 * Let the 'Bth' function do the work and we'll just keep track of the flags.
2633 */
2634 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,SyncCR3), a);
2635 rc = PGM_BTH_PFN(SyncCR3, pVCpu)(pVCpu, cr0, cr3, cr4, fGlobal);
2636 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,SyncCR3), a);
2637 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 || RT_FAILURE(rc), ("rc=%Rrc\n", rc));
2638 if (rc == VINF_SUCCESS)
2639 {
2640 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)
2641 {
2642 /* Go back to ring 3 if a pgm pool sync is again pending. */
2643 return VINF_PGM_SYNC_CR3;
2644 }
2645
2646 if (!(pVCpu->pgm.s.fSyncFlags & PGM_SYNC_ALWAYS))
2647 {
2648 Assert(!(pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL));
2649 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2650 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
2651 }
2652
2653 /*
2654 * Check if we have a pending update of the CR3 monitoring.
2655 */
2656 if (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
2657 {
2658 pVCpu->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
2659 Assert(!pVCpu->CTX_SUFF(pVM)->pgm.s.fMappingsFixed);
2660 Assert(pgmMapAreMappingsEnabled(pVCpu->CTX_SUFF(pVM)));
2661 }
2662 }
2663
2664 /*
2665 * Now flush the CR3 (guest context).
2666 */
2667 if (rc == VINF_SUCCESS)
2668 PGM_INVL_VCPU_TLBS(pVCpu);
2669 return rc;
2670}
2671
2672
2673/**
2674 * Called whenever CR0 or CR4 in a way which may affect the paging mode.
2675 *
2676 * @returns VBox status code, with the following informational code for
2677 * VM scheduling.
2678 * @retval VINF_SUCCESS if the was no change, or it was successfully dealt with.
2679 * @retval VINF_PGM_CHANGE_MODE if we're in RC or R0 and the mode changes.
2680 * (I.e. not in R3.)
2681 * @retval VINF_EM_SUSPEND or VINF_EM_OFF on a fatal runtime error. (R3 only)
2682 *
2683 * @param pVCpu The cross context virtual CPU structure.
2684 * @param cr0 The new cr0.
2685 * @param cr4 The new cr4.
2686 * @param efer The new extended feature enable register.
2687 */
2688VMMDECL(int) PGMChangeMode(PVMCPU pVCpu, uint64_t cr0, uint64_t cr4, uint64_t efer)
2689{
2690 VMCPU_ASSERT_EMT(pVCpu);
2691
2692 /*
2693 * Calc the new guest mode.
2694 *
2695 * Note! We check PG before PE and without requiring PE because of the
2696 * special AMD-V paged real mode (APM vol 2, rev 3.28, 15.9).
2697 */
2698 PGMMODE enmGuestMode;
2699 if (cr0 & X86_CR0_PG)
2700 {
2701 if (!(cr4 & X86_CR4_PAE))
2702 {
2703 bool const fPse = !!(cr4 & X86_CR4_PSE);
2704 if (pVCpu->pgm.s.fGst32BitPageSizeExtension != fPse)
2705 Log(("PGMChangeMode: CR4.PSE %d -> %d\n", pVCpu->pgm.s.fGst32BitPageSizeExtension, fPse));
2706 pVCpu->pgm.s.fGst32BitPageSizeExtension = fPse;
2707 enmGuestMode = PGMMODE_32_BIT;
2708 }
2709 else if (!(efer & MSR_K6_EFER_LME))
2710 {
2711 if (!(efer & MSR_K6_EFER_NXE))
2712 enmGuestMode = PGMMODE_PAE;
2713 else
2714 enmGuestMode = PGMMODE_PAE_NX;
2715 }
2716 else
2717 {
2718 if (!(efer & MSR_K6_EFER_NXE))
2719 enmGuestMode = PGMMODE_AMD64;
2720 else
2721 enmGuestMode = PGMMODE_AMD64_NX;
2722 }
2723 }
2724 else if (!(cr0 & X86_CR0_PE))
2725 enmGuestMode = PGMMODE_REAL;
2726 else
2727 enmGuestMode = PGMMODE_PROTECTED;
2728
2729 /*
2730 * Did it change?
2731 */
2732 if (pVCpu->pgm.s.enmGuestMode == enmGuestMode)
2733 return VINF_SUCCESS;
2734
2735 /* Flush the TLB */
2736 PGM_INVL_VCPU_TLBS(pVCpu);
2737
2738#ifdef IN_RING3
2739 return PGMR3ChangeMode(pVCpu->CTX_SUFF(pVM), pVCpu, enmGuestMode);
2740#else
2741 LogFlow(("PGMChangeMode: returns VINF_PGM_CHANGE_MODE.\n"));
2742 return VINF_PGM_CHANGE_MODE;
2743#endif
2744}
2745
2746
2747/**
2748 * Called by CPUM or REM when CR0.WP changes to 1.
2749 *
2750 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2751 * @thread EMT
2752 */
2753VMMDECL(void) PGMCr0WpEnabled(PVMCPU pVCpu)
2754{
2755 /*
2756 * Netware WP0+RO+US hack cleanup when WP0 -> WP1.
2757 *
2758 * Use the counter to judge whether there might be pool pages with active
2759 * hacks in them. If there are, we will be running the risk of messing up
2760 * the guest by allowing it to write to read-only pages. Thus, we have to
2761 * clear the page pool ASAP if there is the slightest chance.
2762 */
2763 if (pVCpu->pgm.s.cNetwareWp0Hacks > 0)
2764 {
2765 Assert(pVCpu->CTX_SUFF(pVM)->cCpus == 1);
2766
2767 Log(("PGMCr0WpEnabled: %llu WP0 hacks active - clearing page pool\n", pVCpu->pgm.s.cNetwareWp0Hacks));
2768 pVCpu->pgm.s.cNetwareWp0Hacks = 0;
2769 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2770 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2771 }
2772}
2773
2774
2775/**
2776 * Gets the current guest paging mode.
2777 *
2778 * If you just need the CPU mode (real/protected/long), use CPUMGetGuestMode().
2779 *
2780 * @returns The current paging mode.
2781 * @param pVCpu The cross context virtual CPU structure.
2782 */
2783VMMDECL(PGMMODE) PGMGetGuestMode(PVMCPU pVCpu)
2784{
2785 return pVCpu->pgm.s.enmGuestMode;
2786}
2787
2788
2789/**
2790 * Gets the current shadow paging mode.
2791 *
2792 * @returns The current paging mode.
2793 * @param pVCpu The cross context virtual CPU structure.
2794 */
2795VMMDECL(PGMMODE) PGMGetShadowMode(PVMCPU pVCpu)
2796{
2797 return pVCpu->pgm.s.enmShadowMode;
2798}
2799
2800
2801/**
2802 * Gets the current host paging mode.
2803 *
2804 * @returns The current paging mode.
2805 * @param pVM The cross context VM structure.
2806 */
2807VMMDECL(PGMMODE) PGMGetHostMode(PVM pVM)
2808{
2809 switch (pVM->pgm.s.enmHostMode)
2810 {
2811 case SUPPAGINGMODE_32_BIT:
2812 case SUPPAGINGMODE_32_BIT_GLOBAL:
2813 return PGMMODE_32_BIT;
2814
2815 case SUPPAGINGMODE_PAE:
2816 case SUPPAGINGMODE_PAE_GLOBAL:
2817 return PGMMODE_PAE;
2818
2819 case SUPPAGINGMODE_PAE_NX:
2820 case SUPPAGINGMODE_PAE_GLOBAL_NX:
2821 return PGMMODE_PAE_NX;
2822
2823 case SUPPAGINGMODE_AMD64:
2824 case SUPPAGINGMODE_AMD64_GLOBAL:
2825 return PGMMODE_AMD64;
2826
2827 case SUPPAGINGMODE_AMD64_NX:
2828 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
2829 return PGMMODE_AMD64_NX;
2830
2831 default: AssertMsgFailed(("enmHostMode=%d\n", pVM->pgm.s.enmHostMode)); break;
2832 }
2833
2834 return PGMMODE_INVALID;
2835}
2836
2837
2838/**
2839 * Get mode name.
2840 *
2841 * @returns read-only name string.
2842 * @param enmMode The mode which name is desired.
2843 */
2844VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode)
2845{
2846 switch (enmMode)
2847 {
2848 case PGMMODE_REAL: return "Real";
2849 case PGMMODE_PROTECTED: return "Protected";
2850 case PGMMODE_32_BIT: return "32-bit";
2851 case PGMMODE_PAE: return "PAE";
2852 case PGMMODE_PAE_NX: return "PAE+NX";
2853 case PGMMODE_AMD64: return "AMD64";
2854 case PGMMODE_AMD64_NX: return "AMD64+NX";
2855 case PGMMODE_NESTED_32BIT: return "Nested-32";
2856 case PGMMODE_NESTED_PAE: return "Nested-PAE";
2857 case PGMMODE_NESTED_AMD64: return "Nested-AMD64";
2858 case PGMMODE_EPT: return "EPT";
2859 default: return "unknown mode value";
2860 }
2861}
2862
2863
2864/**
2865 * Gets the physical address represented in the guest CR3 as PGM sees it.
2866 *
2867 * This is mainly for logging and debugging.
2868 *
2869 * @returns PGM's guest CR3 value.
2870 * @param pVCpu The cross context virtual CPU structure.
2871 */
2872VMM_INT_DECL(RTGCPHYS) PGMGetGuestCR3Phys(PVMCPU pVCpu)
2873{
2874 return pVCpu->pgm.s.GCPhysCR3;
2875}
2876
2877
2878
2879/**
2880 * Notification from CPUM that the EFER.NXE bit has changed.
2881 *
2882 * @param pVCpu The cross context virtual CPU structure of the CPU for
2883 * which EFER changed.
2884 * @param fNxe The new NXE state.
2885 */
2886VMM_INT_DECL(void) PGMNotifyNxeChanged(PVMCPU pVCpu, bool fNxe)
2887{
2888/** @todo VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu); */
2889 Log(("PGMNotifyNxeChanged: fNxe=%RTbool\n", fNxe));
2890
2891 pVCpu->pgm.s.fNoExecuteEnabled = fNxe;
2892 if (fNxe)
2893 {
2894 /*pVCpu->pgm.s.fGst32BitMbzBigPdeMask - N/A */
2895 pVCpu->pgm.s.fGstPaeMbzPteMask &= ~X86_PTE_PAE_NX;
2896 pVCpu->pgm.s.fGstPaeMbzPdeMask &= ~X86_PDE_PAE_NX;
2897 pVCpu->pgm.s.fGstPaeMbzBigPdeMask &= ~X86_PDE2M_PAE_NX;
2898 /*pVCpu->pgm.s.fGstPaeMbzPdpeMask - N/A */
2899 pVCpu->pgm.s.fGstAmd64MbzPteMask &= ~X86_PTE_PAE_NX;
2900 pVCpu->pgm.s.fGstAmd64MbzPdeMask &= ~X86_PDE_PAE_NX;
2901 pVCpu->pgm.s.fGstAmd64MbzBigPdeMask &= ~X86_PDE2M_PAE_NX;
2902 pVCpu->pgm.s.fGstAmd64MbzPdpeMask &= ~X86_PDPE_LM_NX;
2903 pVCpu->pgm.s.fGstAmd64MbzBigPdpeMask &= ~X86_PDPE_LM_NX;
2904 pVCpu->pgm.s.fGstAmd64MbzPml4eMask &= ~X86_PML4E_NX;
2905
2906 pVCpu->pgm.s.fGst64ShadowedPteMask |= X86_PTE_PAE_NX;
2907 pVCpu->pgm.s.fGst64ShadowedPdeMask |= X86_PDE_PAE_NX;
2908 pVCpu->pgm.s.fGst64ShadowedBigPdeMask |= X86_PDE2M_PAE_NX;
2909 pVCpu->pgm.s.fGst64ShadowedBigPde4PteMask |= X86_PDE2M_PAE_NX;
2910 pVCpu->pgm.s.fGstAmd64ShadowedPdpeMask |= X86_PDPE_LM_NX;
2911 pVCpu->pgm.s.fGstAmd64ShadowedPml4eMask |= X86_PML4E_NX;
2912 }
2913 else
2914 {
2915 /*pVCpu->pgm.s.fGst32BitMbzBigPdeMask - N/A */
2916 pVCpu->pgm.s.fGstPaeMbzPteMask |= X86_PTE_PAE_NX;
2917 pVCpu->pgm.s.fGstPaeMbzPdeMask |= X86_PDE_PAE_NX;
2918 pVCpu->pgm.s.fGstPaeMbzBigPdeMask |= X86_PDE2M_PAE_NX;
2919 /*pVCpu->pgm.s.fGstPaeMbzPdpeMask -N/A */
2920 pVCpu->pgm.s.fGstAmd64MbzPteMask |= X86_PTE_PAE_NX;
2921 pVCpu->pgm.s.fGstAmd64MbzPdeMask |= X86_PDE_PAE_NX;
2922 pVCpu->pgm.s.fGstAmd64MbzBigPdeMask |= X86_PDE2M_PAE_NX;
2923 pVCpu->pgm.s.fGstAmd64MbzPdpeMask |= X86_PDPE_LM_NX;
2924 pVCpu->pgm.s.fGstAmd64MbzBigPdpeMask |= X86_PDPE_LM_NX;
2925 pVCpu->pgm.s.fGstAmd64MbzPml4eMask |= X86_PML4E_NX;
2926
2927 pVCpu->pgm.s.fGst64ShadowedPteMask &= ~X86_PTE_PAE_NX;
2928 pVCpu->pgm.s.fGst64ShadowedPdeMask &= ~X86_PDE_PAE_NX;
2929 pVCpu->pgm.s.fGst64ShadowedBigPdeMask &= ~X86_PDE2M_PAE_NX;
2930 pVCpu->pgm.s.fGst64ShadowedBigPde4PteMask &= ~X86_PDE2M_PAE_NX;
2931 pVCpu->pgm.s.fGstAmd64ShadowedPdpeMask &= ~X86_PDPE_LM_NX;
2932 pVCpu->pgm.s.fGstAmd64ShadowedPml4eMask &= ~X86_PML4E_NX;
2933 }
2934}
2935
2936
2937/**
2938 * Check if any pgm pool pages are marked dirty (not monitored)
2939 *
2940 * @returns bool locked/not locked
2941 * @param pVM The cross context VM structure.
2942 */
2943VMMDECL(bool) PGMHasDirtyPages(PVM pVM)
2944{
2945 return pVM->pgm.s.CTX_SUFF(pPool)->cDirtyPages != 0;
2946}
2947
2948
2949/**
2950 * Check if this VCPU currently owns the PGM lock.
2951 *
2952 * @returns bool owner/not owner
2953 * @param pVM The cross context VM structure.
2954 */
2955VMMDECL(bool) PGMIsLockOwner(PVM pVM)
2956{
2957 return PDMCritSectIsOwner(&pVM->pgm.s.CritSectX);
2958}
2959
2960
2961/**
2962 * Enable or disable large page usage
2963 *
2964 * @returns VBox status code.
2965 * @param pVM The cross context VM structure.
2966 * @param fUseLargePages Use/not use large pages
2967 */
2968VMMDECL(int) PGMSetLargePageUsage(PVM pVM, bool fUseLargePages)
2969{
2970 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2971
2972 pVM->fUseLargePages = fUseLargePages;
2973 return VINF_SUCCESS;
2974}
2975
2976
2977/**
2978 * Acquire the PGM lock.
2979 *
2980 * @returns VBox status code
2981 * @param pVM The cross context VM structure.
2982 * @param SRC_POS The source position of the caller (RT_SRC_POS).
2983 */
2984#if (defined(VBOX_STRICT) && defined(IN_RING3)) || defined(DOXYGEN_RUNNING)
2985int pgmLockDebug(PVM pVM, RT_SRC_POS_DECL)
2986#else
2987int pgmLock(PVM pVM)
2988#endif
2989{
2990#if defined(VBOX_STRICT) && defined(IN_RING3)
2991 int rc = PDMCritSectEnterDebug(&pVM->pgm.s.CritSectX, VERR_SEM_BUSY, (uintptr_t)ASMReturnAddress(), RT_SRC_POS_ARGS);
2992#else
2993 int rc = PDMCritSectEnter(&pVM->pgm.s.CritSectX, VERR_SEM_BUSY);
2994#endif
2995#if defined(IN_RC) || defined(IN_RING0)
2996 if (rc == VERR_SEM_BUSY)
2997 rc = VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_PGM_LOCK, 0);
2998#endif
2999 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
3000 return rc;
3001}
3002
3003
3004/**
3005 * Release the PGM lock.
3006 *
3007 * @returns VBox status code
3008 * @param pVM The cross context VM structure.
3009 */
3010void pgmUnlock(PVM pVM)
3011{
3012 uint32_t cDeprecatedPageLocks = pVM->pgm.s.cDeprecatedPageLocks;
3013 pVM->pgm.s.cDeprecatedPageLocks = 0;
3014 int rc = PDMCritSectLeave(&pVM->pgm.s.CritSectX);
3015 if (rc == VINF_SEM_NESTED)
3016 pVM->pgm.s.cDeprecatedPageLocks = cDeprecatedPageLocks;
3017}
3018
3019#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
3020
3021/**
3022 * Common worker for pgmRZDynMapGCPageOffInlined and pgmRZDynMapGCPageV2Inlined.
3023 *
3024 * @returns VBox status code.
3025 * @param pVM The cross context VM structure.
3026 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3027 * @param GCPhys The guest physical address of the page to map. The
3028 * offset bits are not ignored.
3029 * @param ppv Where to return the address corresponding to @a GCPhys.
3030 * @param SRC_POS The source position of the caller (RT_SRC_POS).
3031 */
3032int pgmRZDynMapGCPageCommon(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, void **ppv RTLOG_COMMA_SRC_POS_DECL)
3033{
3034 pgmLock(pVM);
3035
3036 /*
3037 * Convert it to a writable page and it on to the dynamic mapper.
3038 */
3039 int rc;
3040 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
3041 if (RT_LIKELY(pPage))
3042 {
3043 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
3044 if (RT_SUCCESS(rc))
3045 {
3046 void *pv;
3047 rc = pgmRZDynMapHCPageInlined(pVCpu, PGM_PAGE_GET_HCPHYS(pPage), &pv RTLOG_COMMA_SRC_POS_ARGS);
3048 if (RT_SUCCESS(rc))
3049 *ppv = (void *)((uintptr_t)pv | ((uintptr_t)GCPhys & PAGE_OFFSET_MASK));
3050 }
3051 else
3052 AssertRC(rc);
3053 }
3054 else
3055 {
3056 AssertMsgFailed(("Invalid physical address %RGp!\n", GCPhys));
3057 rc = VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
3058 }
3059
3060 pgmUnlock(pVM);
3061 return rc;
3062}
3063
3064#endif /* IN_RC || VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
3065#if !defined(IN_R0) || defined(LOG_ENABLED)
3066
3067/** Format handler for PGMPAGE.
3068 * @copydoc FNRTSTRFORMATTYPE */
3069static DECLCALLBACK(size_t) pgmFormatTypeHandlerPage(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
3070 const char *pszType, void const *pvValue,
3071 int cchWidth, int cchPrecision, unsigned fFlags,
3072 void *pvUser)
3073{
3074 size_t cch;
3075 PCPGMPAGE pPage = (PCPGMPAGE)pvValue;
3076 if (RT_VALID_PTR(pPage))
3077 {
3078 char szTmp[64+80];
3079
3080 cch = 0;
3081
3082 /* The single char state stuff. */
3083 static const char s_achPageStates[4] = { 'Z', 'A', 'W', 'S' };
3084 szTmp[cch++] = s_achPageStates[PGM_PAGE_GET_STATE_NA(pPage)];
3085
3086#define IS_PART_INCLUDED(lvl) ( !(fFlags & RTSTR_F_PRECISION) || cchPrecision == (lvl) || cchPrecision >= (lvl)+10 )
3087 if (IS_PART_INCLUDED(5))
3088 {
3089 static const char s_achHandlerStates[4] = { '-', 't', 'w', 'a' };
3090 szTmp[cch++] = s_achHandlerStates[PGM_PAGE_GET_HNDL_PHYS_STATE(pPage)];
3091 szTmp[cch++] = s_achHandlerStates[PGM_PAGE_GET_HNDL_VIRT_STATE(pPage)];
3092 }
3093
3094 /* The type. */
3095 if (IS_PART_INCLUDED(4))
3096 {
3097 szTmp[cch++] = ':';
3098 static const char s_achPageTypes[8][4] = { "INV", "RAM", "MI2", "M2A", "SHA", "ROM", "MIO", "BAD" };
3099 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE_NA(pPage)][0];
3100 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE_NA(pPage)][1];
3101 szTmp[cch++] = s_achPageTypes[PGM_PAGE_GET_TYPE_NA(pPage)][2];
3102 }
3103
3104 /* The numbers. */
3105 if (IS_PART_INCLUDED(3))
3106 {
3107 szTmp[cch++] = ':';
3108 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_HCPHYS_NA(pPage), 16, 12, 0, RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
3109 }
3110
3111 if (IS_PART_INCLUDED(2))
3112 {
3113 szTmp[cch++] = ':';
3114 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_PAGEID(pPage), 16, 7, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
3115 }
3116
3117 if (IS_PART_INCLUDED(6))
3118 {
3119 szTmp[cch++] = ':';
3120 static const char s_achRefs[4] = { '-', 'U', '!', 'L' };
3121 szTmp[cch++] = s_achRefs[PGM_PAGE_GET_TD_CREFS_NA(pPage)];
3122 cch += RTStrFormatNumber(&szTmp[cch], PGM_PAGE_GET_TD_IDX_NA(pPage), 16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_16BIT);
3123 }
3124#undef IS_PART_INCLUDED
3125
3126 cch = pfnOutput(pvArgOutput, szTmp, cch);
3127 }
3128 else
3129 cch = pfnOutput(pvArgOutput, RT_STR_TUPLE("<bad-pgmpage-ptr>"));
3130 NOREF(pszType); NOREF(cchWidth); NOREF(pvUser);
3131 return cch;
3132}
3133
3134
3135/** Format handler for PGMRAMRANGE.
3136 * @copydoc FNRTSTRFORMATTYPE */
3137static DECLCALLBACK(size_t) pgmFormatTypeHandlerRamRange(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
3138 const char *pszType, void const *pvValue,
3139 int cchWidth, int cchPrecision, unsigned fFlags,
3140 void *pvUser)
3141{
3142 size_t cch;
3143 PGMRAMRANGE const *pRam = (PGMRAMRANGE const *)pvValue;
3144 if (VALID_PTR(pRam))
3145 {
3146 char szTmp[80];
3147 cch = RTStrPrintf(szTmp, sizeof(szTmp), "%RGp-%RGp", pRam->GCPhys, pRam->GCPhysLast);
3148 cch = pfnOutput(pvArgOutput, szTmp, cch);
3149 }
3150 else
3151 cch = pfnOutput(pvArgOutput, RT_STR_TUPLE("<bad-pgmramrange-ptr>"));
3152 NOREF(pszType); NOREF(cchWidth); NOREF(cchPrecision); NOREF(pvUser); NOREF(fFlags);
3153 return cch;
3154}
3155
3156/** Format type andlers to be registered/deregistered. */
3157static const struct
3158{
3159 char szType[24];
3160 PFNRTSTRFORMATTYPE pfnHandler;
3161} g_aPgmFormatTypes[] =
3162{
3163 { "pgmpage", pgmFormatTypeHandlerPage },
3164 { "pgmramrange", pgmFormatTypeHandlerRamRange }
3165};
3166
3167#endif /* !IN_R0 || LOG_ENABLED */
3168
3169/**
3170 * Registers the global string format types.
3171 *
3172 * This should be called at module load time or in some other manner that ensure
3173 * that it's called exactly one time.
3174 *
3175 * @returns IPRT status code on RTStrFormatTypeRegister failure.
3176 */
3177VMMDECL(int) PGMRegisterStringFormatTypes(void)
3178{
3179#if !defined(IN_R0) || defined(LOG_ENABLED)
3180 int rc = VINF_SUCCESS;
3181 unsigned i;
3182 for (i = 0; RT_SUCCESS(rc) && i < RT_ELEMENTS(g_aPgmFormatTypes); i++)
3183 {
3184 rc = RTStrFormatTypeRegister(g_aPgmFormatTypes[i].szType, g_aPgmFormatTypes[i].pfnHandler, NULL);
3185# ifdef IN_RING0
3186 if (rc == VERR_ALREADY_EXISTS)
3187 {
3188 /* in case of cleanup failure in ring-0 */
3189 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
3190 rc = RTStrFormatTypeRegister(g_aPgmFormatTypes[i].szType, g_aPgmFormatTypes[i].pfnHandler, NULL);
3191 }
3192# endif
3193 }
3194 if (RT_FAILURE(rc))
3195 while (i-- > 0)
3196 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
3197
3198 return rc;
3199#else
3200 return VINF_SUCCESS;
3201#endif
3202}
3203
3204
3205/**
3206 * Deregisters the global string format types.
3207 *
3208 * This should be called at module unload time or in some other manner that
3209 * ensure that it's called exactly one time.
3210 */
3211VMMDECL(void) PGMDeregisterStringFormatTypes(void)
3212{
3213#if !defined(IN_R0) || defined(LOG_ENABLED)
3214 for (unsigned i = 0; i < RT_ELEMENTS(g_aPgmFormatTypes); i++)
3215 RTStrFormatTypeDeregister(g_aPgmFormatTypes[i].szType);
3216#endif
3217}
3218
3219#ifdef VBOX_STRICT
3220
3221/**
3222 * Asserts that there are no mapping conflicts.
3223 *
3224 * @returns Number of conflicts.
3225 * @param pVM The cross context VM structure.
3226 */
3227VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM)
3228{
3229 unsigned cErrors = 0;
3230
3231 /* Only applies to raw mode -> 1 VPCU */
3232 Assert(pVM->cCpus == 1);
3233 PVMCPU pVCpu = &pVM->aCpus[0];
3234
3235 /*
3236 * Check for mapping conflicts.
3237 */
3238 for (PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
3239 pMapping;
3240 pMapping = pMapping->CTX_SUFF(pNext))
3241 {
3242 /** @todo This is slow and should be optimized, but since it's just assertions I don't care now. */
3243 for (RTGCPTR GCPtr = pMapping->GCPtr;
3244 GCPtr <= pMapping->GCPtrLast;
3245 GCPtr += PAGE_SIZE)
3246 {
3247 int rc = PGMGstGetPage(pVCpu, (RTGCPTR)GCPtr, NULL, NULL);
3248 if (rc != VERR_PAGE_TABLE_NOT_PRESENT)
3249 {
3250 AssertMsgFailed(("Conflict at %RGv with %s\n", GCPtr, R3STRING(pMapping->pszDesc)));
3251 cErrors++;
3252 break;
3253 }
3254 }
3255 }
3256
3257 return cErrors;
3258}
3259
3260
3261/**
3262 * Asserts that everything related to the guest CR3 is correctly shadowed.
3263 *
3264 * This will call PGMAssertNoMappingConflicts() and PGMAssertHandlerAndFlagsInSync(),
3265 * and assert the correctness of the guest CR3 mapping before asserting that the
3266 * shadow page tables is in sync with the guest page tables.
3267 *
3268 * @returns Number of conflicts.
3269 * @param pVM The cross context VM structure.
3270 * @param pVCpu The cross context virtual CPU structure.
3271 * @param cr3 The current guest CR3 register value.
3272 * @param cr4 The current guest CR4 register value.
3273 */
3274VMMDECL(unsigned) PGMAssertCR3(PVM pVM, PVMCPU pVCpu, uint64_t cr3, uint64_t cr4)
3275{
3276 STAM_PROFILE_START(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,SyncCR3), a);
3277 pgmLock(pVM);
3278 unsigned cErrors = PGM_BTH_PFN(AssertCR3, pVCpu)(pVCpu, cr3, cr4, 0, ~(RTGCPTR)0);
3279 pgmUnlock(pVM);
3280 STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,SyncCR3), a);
3281 return cErrors;
3282}
3283
3284#endif /* VBOX_STRICT */
3285
Note: See TracBrowser for help on using the repository browser.

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