VirtualBox

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

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

Recommitted 37737 & 37738 minus the dangerous changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 64.2 KB
Line 
1/* $Id: PGMAll.cpp 13198 2008-10-13 09:05:42Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - All context code.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_PGM
26#include <VBox/pgm.h>
27#include <VBox/cpum.h>
28#include <VBox/selm.h>
29#include <VBox/iom.h>
30#include <VBox/sup.h>
31#include <VBox/mm.h>
32#include <VBox/stam.h>
33#include <VBox/csam.h>
34#include <VBox/patm.h>
35#include <VBox/trpm.h>
36#include <VBox/rem.h>
37#include <VBox/em.h>
38#include <VBox/hwaccm.h>
39#include <VBox/hwacc_vmx.h>
40#include "PGMInternal.h"
41#include <VBox/vm.h>
42#include <iprt/assert.h>
43#include <iprt/asm.h>
44#include <iprt/string.h>
45#include <VBox/log.h>
46#include <VBox/param.h>
47#include <VBox/err.h>
48
49
50/*******************************************************************************
51* Structures and Typedefs *
52*******************************************************************************/
53/**
54 * Stated structure for PGM_GST_NAME(HandlerVirtualUpdate) that's
55 * passed to PGM_GST_NAME(VirtHandlerUpdateOne) during enumeration.
56 */
57typedef struct PGMHVUSTATE
58{
59 /** The VM handle. */
60 PVM pVM;
61 /** The todo flags. */
62 RTUINT fTodo;
63 /** The CR4 register value. */
64 uint32_t cr4;
65} PGMHVUSTATE, *PPGMHVUSTATE;
66
67
68/*******************************************************************************
69* Internal Functions *
70*******************************************************************************/
71
72/*
73 * Shadow - 32-bit mode
74 */
75#define PGM_SHW_TYPE PGM_TYPE_32BIT
76#define PGM_SHW_NAME(name) PGM_SHW_NAME_32BIT(name)
77#include "PGMAllShw.h"
78
79/* Guest - real mode */
80#define PGM_GST_TYPE PGM_TYPE_REAL
81#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
82#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_REAL(name)
83#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
84#include "PGMAllGst.h"
85#include "PGMAllBth.h"
86#undef BTH_PGMPOOLKIND_PT_FOR_PT
87#undef PGM_BTH_NAME
88#undef PGM_GST_TYPE
89#undef PGM_GST_NAME
90
91/* Guest - protected mode */
92#define PGM_GST_TYPE PGM_TYPE_PROT
93#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
94#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
95#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_PHYS
96#include "PGMAllGst.h"
97#include "PGMAllBth.h"
98#undef BTH_PGMPOOLKIND_PT_FOR_PT
99#undef PGM_BTH_NAME
100#undef PGM_GST_TYPE
101#undef PGM_GST_NAME
102
103/* Guest - 32-bit mode */
104#define PGM_GST_TYPE PGM_TYPE_32BIT
105#define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
106#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_32BIT(name)
107#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT
108#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB
109#include "PGMAllGst.h"
110#include "PGMAllBth.h"
111#undef BTH_PGMPOOLKIND_PT_FOR_BIG
112#undef BTH_PGMPOOLKIND_PT_FOR_PT
113#undef PGM_BTH_NAME
114#undef PGM_GST_TYPE
115#undef PGM_GST_NAME
116
117#undef PGM_SHW_TYPE
118#undef PGM_SHW_NAME
119
120
121/*
122 * Shadow - PAE mode
123 */
124#define PGM_SHW_TYPE PGM_TYPE_PAE
125#define PGM_SHW_NAME(name) PGM_SHW_NAME_PAE(name)
126#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
127#include "PGMAllShw.h"
128
129/* Guest - real mode */
130#define PGM_GST_TYPE PGM_TYPE_REAL
131#define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
132#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_REAL(name)
133#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
134#include "PGMAllBth.h"
135#undef BTH_PGMPOOLKIND_PT_FOR_PT
136#undef PGM_BTH_NAME
137#undef PGM_GST_TYPE
138#undef PGM_GST_NAME
139
140/* Guest - protected mode */
141#define PGM_GST_TYPE PGM_TYPE_PROT
142#define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
143#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
144#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
145#include "PGMAllBth.h"
146#undef BTH_PGMPOOLKIND_PT_FOR_PT
147#undef PGM_BTH_NAME
148#undef PGM_GST_TYPE
149#undef PGM_GST_NAME
150
151/* Guest - 32-bit mode */
152#define PGM_GST_TYPE PGM_TYPE_32BIT
153#define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
154#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_32BIT(name)
155#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_32BIT_PT
156#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_32BIT_4MB
157#include "PGMAllBth.h"
158#undef BTH_PGMPOOLKIND_PT_FOR_BIG
159#undef BTH_PGMPOOLKIND_PT_FOR_PT
160#undef PGM_BTH_NAME
161#undef PGM_GST_TYPE
162#undef PGM_GST_NAME
163
164
165/* Guest - PAE mode */
166#define PGM_GST_TYPE PGM_TYPE_PAE
167#define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
168#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PAE(name)
169#define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
170#define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
171#include "PGMAllGst.h"
172#include "PGMAllBth.h"
173#undef BTH_PGMPOOLKIND_PT_FOR_BIG
174#undef BTH_PGMPOOLKIND_PT_FOR_PT
175#undef PGM_BTH_NAME
176#undef PGM_GST_TYPE
177#undef PGM_GST_NAME
178
179#undef PGM_SHW_TYPE
180#undef PGM_SHW_NAME
181
182
183#ifndef IN_GC /* AMD64 implies VT-x/AMD-V */
184/*
185 * Shadow - AMD64 mode
186 */
187# define PGM_SHW_TYPE PGM_TYPE_AMD64
188# define PGM_SHW_NAME(name) PGM_SHW_NAME_AMD64(name)
189# include "PGMAllShw.h"
190
191/* Guest - protected mode */
192# define PGM_GST_TYPE PGM_TYPE_PROT
193# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
194# define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_PROT(name)
195# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PHYS
196# include "PGMAllBth.h"
197# undef BTH_PGMPOOLKIND_PT_FOR_PT
198# undef PGM_BTH_NAME
199# undef PGM_GST_TYPE
200# undef PGM_GST_NAME
201
202# ifdef VBOX_WITH_64_BITS_GUESTS
203/* Guest - AMD64 mode */
204# define PGM_GST_TYPE PGM_TYPE_AMD64
205# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
206# define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_AMD64(name)
207# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_PAE_PT_FOR_PAE_PT
208# define BTH_PGMPOOLKIND_PT_FOR_BIG PGMPOOLKIND_PAE_PT_FOR_PAE_2MB
209# include "PGMAllGst.h"
210# include "PGMAllBth.h"
211# undef BTH_PGMPOOLKIND_PT_FOR_BIG
212# undef BTH_PGMPOOLKIND_PT_FOR_PT
213# undef PGM_BTH_NAME
214# undef PGM_GST_TYPE
215# undef PGM_GST_NAME
216# endif /* VBOX_WITH_64_BITS_GUESTS */
217
218# undef PGM_SHW_TYPE
219# undef PGM_SHW_NAME
220
221
222/*
223 * Shadow - Nested paging mode
224 */
225# define PGM_SHW_TYPE PGM_TYPE_NESTED
226# define PGM_SHW_NAME(name) PGM_SHW_NAME_NESTED(name)
227# include "PGMAllShw.h"
228
229/* Guest - real mode */
230# define PGM_GST_TYPE PGM_TYPE_REAL
231# define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
232# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_REAL(name)
233# include "PGMAllBth.h"
234# undef PGM_BTH_NAME
235# undef PGM_GST_TYPE
236# undef PGM_GST_NAME
237
238/* Guest - protected mode */
239# define PGM_GST_TYPE PGM_TYPE_PROT
240# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
241# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PROT(name)
242# include "PGMAllBth.h"
243# undef PGM_BTH_NAME
244# undef PGM_GST_TYPE
245# undef PGM_GST_NAME
246
247/* Guest - 32-bit mode */
248# define PGM_GST_TYPE PGM_TYPE_32BIT
249# define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
250# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_32BIT(name)
251# include "PGMAllBth.h"
252# undef PGM_BTH_NAME
253# undef PGM_GST_TYPE
254# undef PGM_GST_NAME
255
256/* Guest - PAE mode */
257# define PGM_GST_TYPE PGM_TYPE_PAE
258# define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
259# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_PAE(name)
260# include "PGMAllBth.h"
261# undef PGM_BTH_NAME
262# undef PGM_GST_TYPE
263# undef PGM_GST_NAME
264
265# ifdef VBOX_WITH_64_BITS_GUESTS
266/* Guest - AMD64 mode */
267# define PGM_GST_TYPE PGM_TYPE_AMD64
268# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
269# define PGM_BTH_NAME(name) PGM_BTH_NAME_NESTED_AMD64(name)
270# include "PGMAllBth.h"
271# undef PGM_BTH_NAME
272# undef PGM_GST_TYPE
273# undef PGM_GST_NAME
274# endif /* VBOX_WITH_64_BITS_GUESTS */
275
276# undef PGM_SHW_TYPE
277# undef PGM_SHW_NAME
278
279
280/*
281 * Shadow - EPT
282 */
283# define PGM_SHW_TYPE PGM_TYPE_EPT
284# define PGM_SHW_NAME(name) PGM_SHW_NAME_EPT(name)
285# include "PGMAllShw.h"
286
287/* Guest - real mode */
288# define PGM_GST_TYPE PGM_TYPE_REAL
289# define PGM_GST_NAME(name) PGM_GST_NAME_REAL(name)
290# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_REAL(name)
291# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
292# include "PGMAllBth.h"
293# undef BTH_PGMPOOLKIND_PT_FOR_PT
294# undef PGM_BTH_NAME
295# undef PGM_GST_TYPE
296# undef PGM_GST_NAME
297
298/* Guest - protected mode */
299# define PGM_GST_TYPE PGM_TYPE_PROT
300# define PGM_GST_NAME(name) PGM_GST_NAME_PROT(name)
301# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PROT(name)
302# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
303# include "PGMAllBth.h"
304# undef BTH_PGMPOOLKIND_PT_FOR_PT
305# undef PGM_BTH_NAME
306# undef PGM_GST_TYPE
307# undef PGM_GST_NAME
308
309/* Guest - 32-bit mode */
310# define PGM_GST_TYPE PGM_TYPE_32BIT
311# define PGM_GST_NAME(name) PGM_GST_NAME_32BIT(name)
312# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_32BIT(name)
313# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
314# include "PGMAllBth.h"
315# undef BTH_PGMPOOLKIND_PT_FOR_PT
316# undef PGM_BTH_NAME
317# undef PGM_GST_TYPE
318# undef PGM_GST_NAME
319
320/* Guest - PAE mode */
321# define PGM_GST_TYPE PGM_TYPE_PAE
322# define PGM_GST_NAME(name) PGM_GST_NAME_PAE(name)
323# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PAE(name)
324# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
325# include "PGMAllBth.h"
326# undef BTH_PGMPOOLKIND_PT_FOR_PT
327# undef PGM_BTH_NAME
328# undef PGM_GST_TYPE
329# undef PGM_GST_NAME
330
331# ifdef VBOX_WITH_64_BITS_GUESTS
332/* Guest - AMD64 mode */
333# define PGM_GST_TYPE PGM_TYPE_AMD64
334# define PGM_GST_NAME(name) PGM_GST_NAME_AMD64(name)
335# define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_AMD64(name)
336# define BTH_PGMPOOLKIND_PT_FOR_PT PGMPOOLKIND_EPT_PT_FOR_PHYS
337# include "PGMAllBth.h"
338# undef BTH_PGMPOOLKIND_PT_FOR_PT
339# undef PGM_BTH_NAME
340# undef PGM_GST_TYPE
341# undef PGM_GST_NAME
342# endif /* VBOX_WITH_64_BITS_GUESTS */
343
344# undef PGM_SHW_TYPE
345# undef PGM_SHW_NAME
346
347#endif /* !IN_GC */
348
349
350#ifndef IN_RING3
351/**
352 * #PF Handler.
353 *
354 * @returns VBox status code (appropriate for trap handling and GC return).
355 * @param pVM VM Handle.
356 * @param uErr The trap error code.
357 * @param pRegFrame Trap register frame.
358 * @param pvFault The fault address.
359 */
360VMMDECL(int) PGMTrap0eHandler(PVM pVM, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
361{
362 LogFlow(("PGMTrap0eHandler: uErr=%RGu pvFault=%VGv eip=%VGv\n", uErr, pvFault, pRegFrame->rip));
363 STAM_PROFILE_START(&pVM->pgm.s.StatRZTrap0e, a);
364 STAM_STATS({ pVM->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = NULL; } );
365
366
367#ifdef VBOX_WITH_STATISTICS
368 /*
369 * Error code stats.
370 */
371 if (uErr & X86_TRAP_PF_US)
372 {
373 if (!(uErr & X86_TRAP_PF_P))
374 {
375 if (uErr & X86_TRAP_PF_RW)
376 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eUSNotPresentWrite);
377 else
378 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eUSNotPresentRead);
379 }
380 else if (uErr & X86_TRAP_PF_RW)
381 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eUSWrite);
382 else if (uErr & X86_TRAP_PF_RSVD)
383 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eUSReserved);
384 else if (uErr & X86_TRAP_PF_ID)
385 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eUSNXE);
386 else
387 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eUSRead);
388 }
389 else
390 { /* Supervisor */
391 if (!(uErr & X86_TRAP_PF_P))
392 {
393 if (uErr & X86_TRAP_PF_RW)
394 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eSVNotPresentWrite);
395 else
396 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eSVNotPresentRead);
397 }
398 else if (uErr & X86_TRAP_PF_RW)
399 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eSVWrite);
400 else if (uErr & X86_TRAP_PF_ID)
401 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eSNXE);
402 else if (uErr & X86_TRAP_PF_RSVD)
403 STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eSVReserved);
404 }
405#endif
406
407 /*
408 * Call the worker.
409 */
410 int rc = PGM_BTH_PFN(Trap0eHandler, pVM)(pVM, uErr, pRegFrame, pvFault);
411 if (rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE)
412 rc = VINF_SUCCESS;
413 STAM_STATS({ if (rc == VINF_EM_RAW_GUEST_TRAP) STAM_COUNTER_INC(&pVM->pgm.s.StatRZTrap0eGuestPF); });
414 STAM_STATS({ if (!pVM->pgm.s.CTX_SUFF(pStatTrap0eAttribution))
415 pVM->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVM->pgm.s.StatRZTrap0eTime2Misc; });
416 STAM_PROFILE_STOP_EX(&pVM->pgm.s.StatRZTrap0e, pVM->pgm.s.CTX_SUFF(pStatTrap0eAttribution), a);
417 return rc;
418}
419#endif /* !IN_RING3 */
420
421
422/**
423 * Prefetch a page
424 *
425 * Typically used to sync commonly used pages before entering raw mode
426 * after a CR3 reload.
427 *
428 * @returns VBox status code suitable for scheduling.
429 * @retval VINF_SUCCESS on success.
430 * @retval VINF_PGM_SYNC_CR3 if we're out of shadow pages or something like that.
431 * @param pVM VM handle.
432 * @param GCPtrPage Page to invalidate.
433 */
434VMMDECL(int) PGMPrefetchPage(PVM pVM, RTGCPTR GCPtrPage)
435{
436 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,Prefetch), a);
437 int rc = PGM_BTH_PFN(PrefetchPage, pVM)(pVM, (RTGCUINTPTR)GCPtrPage);
438 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,Prefetch), a);
439 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 || VBOX_FAILURE(rc), ("rc=%Vrc\n", rc));
440 return rc;
441}
442
443
444/**
445 * Gets the mapping corresponding to the specified address (if any).
446 *
447 * @returns Pointer to the mapping.
448 * @returns NULL if not
449 *
450 * @param pVM The virtual machine.
451 * @param GCPtr The guest context pointer.
452 */
453PPGMMAPPING pgmGetMapping(PVM pVM, RTGCPTR GCPtr)
454{
455 PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
456 while (pMapping)
457 {
458 if ((uintptr_t)GCPtr < (uintptr_t)pMapping->GCPtr)
459 break;
460 if ((uintptr_t)GCPtr - (uintptr_t)pMapping->GCPtr < pMapping->cb)
461 return pMapping;
462 pMapping = pMapping->CTX_SUFF(pNext);
463 }
464 return NULL;
465}
466
467
468/**
469 * Verifies a range of pages for read or write access
470 *
471 * Only checks the guest's page tables
472 *
473 * @returns VBox status code.
474 * @param pVM VM handle.
475 * @param Addr Guest virtual address to check
476 * @param cbSize Access size
477 * @param fAccess Access type (r/w, user/supervisor (X86_PTE_*))
478 */
479VMMDECL(int) PGMIsValidAccess(PVM pVM, RTGCUINTPTR Addr, uint32_t cbSize, uint32_t fAccess)
480{
481 /*
482 * Validate input.
483 */
484 if (fAccess & ~(X86_PTE_US | X86_PTE_RW))
485 {
486 AssertMsgFailed(("PGMIsValidAccess: invalid access type %08x\n", fAccess));
487 return VERR_INVALID_PARAMETER;
488 }
489
490 uint64_t fPage;
491 int rc = PGMGstGetPage(pVM, (RTGCPTR)Addr, &fPage, NULL);
492 if (VBOX_FAILURE(rc))
493 {
494 Log(("PGMIsValidAccess: access violation for %VGv rc=%d\n", Addr, rc));
495 return VINF_EM_RAW_GUEST_TRAP;
496 }
497
498 /*
499 * Check if the access would cause a page fault
500 *
501 * Note that hypervisor page directories are not present in the guest's tables, so this check
502 * is sufficient.
503 */
504 bool fWrite = !!(fAccess & X86_PTE_RW);
505 bool fUser = !!(fAccess & X86_PTE_US);
506 if ( !(fPage & X86_PTE_P)
507 || (fWrite && !(fPage & X86_PTE_RW))
508 || (fUser && !(fPage & X86_PTE_US)) )
509 {
510 Log(("PGMIsValidAccess: access violation for %VGv attr %#llx vs %d:%d\n", Addr, fPage, fWrite, fUser));
511 return VINF_EM_RAW_GUEST_TRAP;
512 }
513 if ( VBOX_SUCCESS(rc)
514 && PAGE_ADDRESS(Addr) != PAGE_ADDRESS(Addr + cbSize))
515 return PGMIsValidAccess(pVM, Addr + PAGE_SIZE, (cbSize > PAGE_SIZE) ? cbSize - PAGE_SIZE : 1, fAccess);
516 return rc;
517}
518
519
520/**
521 * Verifies a range of pages for read or write access
522 *
523 * Supports handling of pages marked for dirty bit tracking and CSAM
524 *
525 * @returns VBox status code.
526 * @param pVM VM handle.
527 * @param Addr Guest virtual address to check
528 * @param cbSize Access size
529 * @param fAccess Access type (r/w, user/supervisor (X86_PTE_*))
530 */
531VMMDECL(int) PGMVerifyAccess(PVM pVM, RTGCUINTPTR Addr, uint32_t cbSize, uint32_t fAccess)
532{
533 /*
534 * Validate input.
535 */
536 if (fAccess & ~(X86_PTE_US | X86_PTE_RW))
537 {
538 AssertMsgFailed(("PGMVerifyAccess: invalid access type %08x\n", fAccess));
539 return VERR_INVALID_PARAMETER;
540 }
541
542 uint64_t fPageGst;
543 int rc = PGMGstGetPage(pVM, (RTGCPTR)Addr, &fPageGst, NULL);
544 if (VBOX_FAILURE(rc))
545 {
546 Log(("PGMVerifyAccess: access violation for %VGv rc=%d\n", Addr, rc));
547 return VINF_EM_RAW_GUEST_TRAP;
548 }
549
550 /*
551 * Check if the access would cause a page fault
552 *
553 * Note that hypervisor page directories are not present in the guest's tables, so this check
554 * is sufficient.
555 */
556 const bool fWrite = !!(fAccess & X86_PTE_RW);
557 const bool fUser = !!(fAccess & X86_PTE_US);
558 if ( !(fPageGst & X86_PTE_P)
559 || (fWrite && !(fPageGst & X86_PTE_RW))
560 || (fUser && !(fPageGst & X86_PTE_US)) )
561 {
562 Log(("PGMVerifyAccess: access violation for %VGv attr %#llx vs %d:%d\n", Addr, fPageGst, fWrite, fUser));
563 return VINF_EM_RAW_GUEST_TRAP;
564 }
565
566 if (!HWACCMIsNestedPagingActive(pVM))
567 {
568 /*
569 * Next step is to verify if we protected this page for dirty bit tracking or for CSAM scanning
570 */
571 rc = PGMShwGetPage(pVM, (RTGCPTR)Addr, NULL, NULL);
572 if ( rc == VERR_PAGE_NOT_PRESENT
573 || rc == VERR_PAGE_TABLE_NOT_PRESENT)
574 {
575 /*
576 * Page is not present in our page tables.
577 * Try to sync it!
578 */
579 Assert(X86_TRAP_PF_RW == X86_PTE_RW && X86_TRAP_PF_US == X86_PTE_US);
580 uint32_t uErr = fAccess & (X86_TRAP_PF_RW | X86_TRAP_PF_US);
581 rc = PGM_BTH_PFN(VerifyAccessSyncPage, pVM)(pVM, Addr, fPageGst, uErr);
582 if (rc != VINF_SUCCESS)
583 return rc;
584 }
585 else
586 AssertMsg(rc == VINF_SUCCESS, ("PGMShwGetPage %VGv failed with %Vrc\n", Addr, rc));
587 }
588
589#if 0 /* def VBOX_STRICT; triggers too often now */
590 /*
591 * This check is a bit paranoid, but useful.
592 */
593 /** @note this will assert when writing to monitored pages (a bit annoying actually) */
594 uint64_t fPageShw;
595 rc = PGMShwGetPage(pVM, (RTGCPTR)Addr, &fPageShw, NULL);
596 if ( (rc == VERR_PAGE_NOT_PRESENT || VBOX_FAILURE(rc))
597 || (fWrite && !(fPageShw & X86_PTE_RW))
598 || (fUser && !(fPageShw & X86_PTE_US)) )
599 {
600 AssertMsgFailed(("Unexpected access violation for %VGv! rc=%Vrc write=%d user=%d\n",
601 Addr, rc, fWrite && !(fPageShw & X86_PTE_RW), fUser && !(fPageShw & X86_PTE_US)));
602 return VINF_EM_RAW_GUEST_TRAP;
603 }
604#endif
605
606 if ( VBOX_SUCCESS(rc)
607 && ( PAGE_ADDRESS(Addr) != PAGE_ADDRESS(Addr + cbSize - 1)
608 || Addr + cbSize < Addr))
609 {
610 /* Don't recursively call PGMVerifyAccess as we might run out of stack. */
611 for (;;)
612 {
613 Addr += PAGE_SIZE;
614 if (cbSize > PAGE_SIZE)
615 cbSize -= PAGE_SIZE;
616 else
617 cbSize = 1;
618 rc = PGMVerifyAccess(pVM, Addr, 1, fAccess);
619 if (rc != VINF_SUCCESS)
620 break;
621 if (PAGE_ADDRESS(Addr) == PAGE_ADDRESS(Addr + cbSize - 1))
622 break;
623 }
624 }
625 return rc;
626}
627
628
629#ifndef IN_GC
630/**
631 * Emulation of the invlpg instruction (HC only actually).
632 *
633 * @returns VBox status code.
634 * @param pVM VM handle.
635 * @param GCPtrPage Page to invalidate.
636 * @remark ASSUMES the page table entry or page directory is
637 * valid. Fairly safe, but there could be edge cases!
638 * @todo Flush page or page directory only if necessary!
639 */
640VMMDECL(int) PGMInvalidatePage(PVM pVM, RTGCPTR GCPtrPage)
641{
642 int rc;
643
644 Log3(("PGMInvalidatePage: GCPtrPage=%VGv\n", GCPtrPage));
645
646 /** @todo merge PGMGCInvalidatePage with this one */
647
648# ifndef IN_RING3
649 /*
650 * Notify the recompiler so it can record this instruction.
651 * Failure happens when it's out of space. We'll return to HC in that case.
652 */
653 rc = REMNotifyInvalidatePage(pVM, GCPtrPage);
654 if (VBOX_FAILURE(rc))
655 return rc;
656# endif
657
658 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,InvalidatePage), a);
659 rc = PGM_BTH_PFN(InvalidatePage, pVM)(pVM, GCPtrPage);
660 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,InvalidatePage), a);
661
662# ifndef IN_RING0
663 /*
664 * Check if we have a pending update of the CR3 monitoring.
665 */
666 if ( VBOX_SUCCESS(rc)
667 && (pVM->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3))
668 {
669 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
670 Assert(!pVM->pgm.s.fMappingsFixed);
671 Assert(pVM->pgm.s.GCPhysCR3 == pVM->pgm.s.GCPhysGstCR3Monitored);
672 rc = PGM_GST_PFN(MonitorCR3, pVM)(pVM, pVM->pgm.s.GCPhysCR3);
673 }
674# endif
675
676# ifdef IN_RING3
677 /*
678 * Inform CSAM about the flush
679 */
680 /** @note this is to check if monitored pages have been changed; when we implement callbacks for virtual handlers, this is no longer required. */
681 CSAMR3FlushPage(pVM, GCPtrPage);
682# endif
683 return rc;
684}
685#endif /* !IN_GC */
686
687
688/**
689 * Executes an instruction using the interpreter.
690 *
691 * @returns VBox status code (appropriate for trap handling and GC return).
692 * @param pVM VM handle.
693 * @param pRegFrame Register frame.
694 * @param pvFault Fault address.
695 */
696VMMDECL(int) PGMInterpretInstruction(PVM pVM, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault)
697{
698 uint32_t cb;
699 int rc = EMInterpretInstruction(pVM, pRegFrame, pvFault, &cb);
700 if (rc == VERR_EM_INTERPRETER)
701 rc = VINF_EM_RAW_EMULATE_INSTR;
702 if (rc != VINF_SUCCESS)
703 Log(("PGMInterpretInstruction: returns %Rrc (pvFault=%VGv)\n", rc, pvFault));
704 return rc;
705}
706
707
708/**
709 * Gets effective page information (from the VMM page directory).
710 *
711 * @returns VBox status.
712 * @param pVM VM Handle.
713 * @param GCPtr Guest Context virtual address of the page.
714 * @param pfFlags Where to store the flags. These are X86_PTE_*.
715 * @param pHCPhys Where to store the HC physical address of the page.
716 * This is page aligned.
717 * @remark You should use PGMMapGetPage() for pages in a mapping.
718 */
719VMMDECL(int) PGMShwGetPage(PVM pVM, RTGCPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys)
720{
721 return PGM_SHW_PFN(GetPage,pVM)(pVM, (RTGCUINTPTR)GCPtr, pfFlags, pHCPhys);
722}
723
724
725/**
726 * Sets (replaces) the page flags for a range of pages in the shadow context.
727 *
728 * @returns VBox status.
729 * @param pVM VM handle.
730 * @param GCPtr The address of the first page.
731 * @param cb The size of the range in bytes.
732 * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
733 * @remark You must use PGMMapSetPage() for pages in a mapping.
734 */
735VMMDECL(int) PGMShwSetPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags)
736{
737 return PGMShwModifyPage(pVM, GCPtr, cb, fFlags, 0);
738}
739
740
741/**
742 * Modify page flags for a range of pages in the shadow context.
743 *
744 * The existing flags are ANDed with the fMask and ORed with the fFlags.
745 *
746 * @returns VBox status code.
747 * @param pVM VM handle.
748 * @param GCPtr Virtual address of the first page in the range.
749 * @param cb Size (in bytes) of the range to apply the modification to.
750 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
751 * @param fMask The AND mask - page flags X86_PTE_*.
752 * Be very CAREFUL when ~'ing constants which could be 32-bit!
753 * @remark You must use PGMMapModifyPage() for pages in a mapping.
754 */
755VMMDECL(int) PGMShwModifyPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
756{
757 /*
758 * Validate input.
759 */
760 if (fFlags & X86_PTE_PAE_PG_MASK)
761 {
762 AssertMsgFailed(("fFlags=%#llx\n", fFlags));
763 return VERR_INVALID_PARAMETER;
764 }
765 if (!cb)
766 {
767 AssertFailed();
768 return VERR_INVALID_PARAMETER;
769 }
770
771 /*
772 * Align the input.
773 */
774 cb += (RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK;
775 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
776 GCPtr = (RTGCPTR)((RTGCUINTPTR)GCPtr & PAGE_BASE_GC_MASK); /** @todo this ain't necessary, right... */
777
778 /*
779 * Call worker.
780 */
781 return PGM_SHW_PFN(ModifyPage, pVM)(pVM, (RTGCUINTPTR)GCPtr, cb, fFlags, fMask);
782}
783
784
785/**
786 * Syncs the SHADOW page directory pointer for the specified address.
787 *
788 * Allocates backing pages in case the PDPT entry is missing.
789 *
790 * @returns VBox status.
791 * @param pVM VM handle.
792 * @param GCPtr The address.
793 * @param pGstPdpe Guest PDPT entry
794 * @param ppPD Receives address of page directory
795 */
796VMMDECL(int) PGMShwSyncPAEPDPtr(PVM pVM, RTGCUINTPTR GCPtr, PX86PDPE pGstPdpe, PX86PDPAE *ppPD)
797{
798 PPGM pPGM = &pVM->pgm.s;
799 PPGMPOOL pPool = pPGM->CTX_SUFF(pPool);
800 PPGMPOOLPAGE pShwPage;
801 int rc;
802
803 Assert(!HWACCMIsNestedPagingActive(pVM));
804
805 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
806 PX86PDPT pPdpt = pVM->pgm.s.CTXMID(p,PaePDPT);
807 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
808
809 /* Allocate page directory if not present. */
810 if ( !pPdpe->n.u1Present
811 && !(pPdpe->u & X86_PDPE_PG_MASK))
812 {
813 PX86PDPE pPdptGst = &CTXSUFF(pPGM->pGstPaePDPT)->a[iPdPt];
814
815 Assert(!(pPdpe->u & X86_PDPE_PG_MASK));
816 /* Create a reference back to the PDPT by using the index in its shadow page. */
817 rc = pgmPoolAlloc(pVM, pPdptGst->u & X86_PDPE_PG_MASK, PGMPOOLKIND_PAE_PD_FOR_PAE_PD, PGMPOOL_IDX_PDPT, iPdPt, &pShwPage);
818 if (rc == VERR_PGM_POOL_FLUSHED)
819 {
820 Assert(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL);
821 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
822 return VINF_PGM_SYNC_CR3;
823 }
824 AssertRCReturn(rc, rc);
825 }
826 else
827 {
828 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
829 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
830 }
831 /* The PD was cached or created; hook it up now. */
832 pPdpe->u |= pShwPage->Core.Key
833 | (pGstPdpe->u & ~(X86_PDPE_PG_MASK | X86_PDPE_AVL_MASK | X86_PDPE_PCD | X86_PDPE_PWT));
834
835 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
836 return VINF_SUCCESS;
837}
838
839
840/**
841 * Gets the SHADOW page directory pointer for the specified address.
842 *
843 * @returns VBox status.
844 * @param pVM VM handle.
845 * @param GCPtr The address.
846 * @param ppPdpt Receives address of pdpt
847 * @param ppPD Receives address of page directory
848 */
849VMMDECL(int) PGMShwGetPAEPDPtr(PVM pVM, RTGCUINTPTR GCPtr, PX86PDPT *ppPdpt, PX86PDPAE *ppPD)
850{
851 PPGM pPGM = &pVM->pgm.s;
852 PPGMPOOL pPool = pPGM->CTX_SUFF(pPool);
853 PPGMPOOLPAGE pShwPage;
854
855 Assert(!HWACCMIsNestedPagingActive(pVM));
856
857 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
858 PX86PDPT pPdpt = pVM->pgm.s.CTXMID(p,PaePDPT);
859 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
860
861 *ppPdpt = pPdpt;
862 if (!pPdpe->n.u1Present)
863 return VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT;
864
865 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
866 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
867
868 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
869 return VINF_SUCCESS;
870}
871
872
873#ifndef IN_GC
874/**
875 * Syncs the SHADOW page directory pointer for the specified address. Allocates
876 * backing pages in case the PDPT or PML4 entry is missing.
877 *
878 * @returns VBox status.
879 * @param pVM VM handle.
880 * @param GCPtr The address.
881 * @param pGstPml4e Guest PML4 entry
882 * @param pGstPdpe Guest PDPT entry
883 * @param ppPD Receives address of page directory
884 */
885VMMDECL(int) PGMShwSyncLongModePDPtr(PVM pVM, RTGCUINTPTR64 GCPtr, PX86PML4E pGstPml4e, PX86PDPE pGstPdpe, PX86PDPAE *ppPD)
886{
887 PPGM pPGM = &pVM->pgm.s;
888 const unsigned iPml4e = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
889 PPGMPOOL pPool = pPGM->CTX_SUFF(pPool);
890 PX86PML4E pPml4e;
891 PPGMPOOLPAGE pShwPage;
892 int rc;
893 bool fNestedPaging = HWACCMIsNestedPagingActive(pVM);
894
895 Assert(pVM->pgm.s.pHCPaePML4);
896
897 /* Allocate page directory pointer table if not present. */
898 pPml4e = &pPGM->pHCPaePML4->a[iPml4e];
899 if ( !pPml4e->n.u1Present
900 && !(pPml4e->u & X86_PML4E_PG_MASK))
901 {
902 Assert(!(pPml4e->u & X86_PML4E_PG_MASK));
903
904 if (!fNestedPaging)
905 {
906 Assert(pVM->pgm.s.pHCShwAmd64CR3);
907 Assert(pPGM->pGstPaePML4HC);
908
909 PX86PML4E pPml4eGst = &pPGM->pGstPaePML4HC->a[iPml4e];
910
911 rc = pgmPoolAlloc(pVM, pPml4eGst->u & X86_PML4E_PG_MASK, PGMPOOLKIND_64BIT_PDPT_FOR_64BIT_PDPT, pVM->pgm.s.pHCShwAmd64CR3->idx, iPml4e, &pShwPage);
912 }
913 else
914 rc = pgmPoolAlloc(pVM, GCPtr + RT_BIT_64(63) /* hack: make the address unique */, PGMPOOLKIND_64BIT_PDPT_FOR_PHYS, PGMPOOL_IDX_NESTED_ROOT, iPml4e, &pShwPage);
915
916 if (rc == VERR_PGM_POOL_FLUSHED)
917 {
918 Log(("PGMShwSyncLongModePDPtr: PGM pool flushed (1) -> signal sync cr3\n"));
919 Assert(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL);
920 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
921 return VINF_PGM_SYNC_CR3;
922 }
923 AssertRCReturn(rc, rc);
924 }
925 else
926 {
927 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & X86_PML4E_PG_MASK);
928 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
929 }
930 /* The PDPT was cached or created; hook it up now. */
931 pPml4e->u |= pShwPage->Core.Key
932 | (pGstPml4e->u & ~(X86_PML4E_PG_MASK | X86_PML4E_AVL_MASK | X86_PML4E_PCD | X86_PML4E_PWT));
933
934 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
935 PX86PDPT pPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
936 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
937
938 /* Allocate page directory if not present. */
939 if ( !pPdpe->n.u1Present
940 && !(pPdpe->u & X86_PDPE_PG_MASK))
941 {
942 if (!fNestedPaging)
943 {
944 Assert(pPGM->pGstPaePML4HC);
945
946 PX86PML4E pPml4eGst = &pPGM->pGstPaePML4HC->a[iPml4e];
947 PX86PDPT pPdptGst;
948 rc = PGM_GCPHYS_2_PTR(pVM, pPml4eGst->u & X86_PML4E_PG_MASK, &pPdptGst);
949 AssertRCReturn(rc, rc);
950
951 Assert(!(pPdpe->u & X86_PDPE_PG_MASK));
952 /* Create a reference back to the PDPT by using the index in its shadow page. */
953 rc = pgmPoolAlloc(pVM, pPdptGst->a[iPdPt].u & X86_PDPE_PG_MASK, PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD, pShwPage->idx, iPdPt, &pShwPage);
954 }
955 else
956 rc = pgmPoolAlloc(pVM, GCPtr + RT_BIT_64(62) /* hack: make the address unique */, PGMPOOLKIND_64BIT_PD_FOR_PHYS, pShwPage->idx, iPdPt, &pShwPage);
957
958 if (rc == VERR_PGM_POOL_FLUSHED)
959 {
960 Log(("PGMShwSyncLongModePDPtr: PGM pool flushed (2) -> signal sync cr3\n"));
961 Assert(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL);
962 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
963 return VINF_PGM_SYNC_CR3;
964 }
965 AssertRCReturn(rc, rc);
966 }
967 else
968 {
969 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
970 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
971 }
972 /* The PD was cached or created; hook it up now. */
973 pPdpe->u |= pShwPage->Core.Key
974 | (pGstPdpe->u & ~(X86_PDPE_PG_MASK | X86_PDPE_AVL_MASK | X86_PDPE_PCD | X86_PDPE_PWT));
975
976 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
977 return VINF_SUCCESS;
978}
979
980/**
981 * Gets the SHADOW page directory pointer for the specified address.
982 *
983 * @returns VBox status.
984 * @param pVM VM handle.
985 * @param GCPtr The address.
986 * @param ppPdpt Receives address of pdpt
987 * @param ppPD Receives address of page directory
988 */
989VMMDECL(int) PGMShwGetLongModePDPtr(PVM pVM, RTGCUINTPTR64 GCPtr, PX86PDPT *ppPdpt, PX86PDPAE *ppPD)
990{
991 PPGM pPGM = &pVM->pgm.s;
992 const unsigned iPml4e = (GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK;
993 PPGMPOOL pPool = pPGM->CTX_SUFF(pPool);
994 PX86PML4E pPml4e;
995 PPGMPOOLPAGE pShwPage;
996
997 AssertReturn(pVM->pgm.s.pHCPaePML4, VERR_INTERNAL_ERROR);
998
999 pPml4e = &pPGM->pHCPaePML4->a[iPml4e];
1000 if (!pPml4e->n.u1Present)
1001 return VERR_PAGE_MAP_LEVEL4_NOT_PRESENT;
1002
1003 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & X86_PML4E_PG_MASK);
1004 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1005
1006 const unsigned iPdPt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64;
1007 PX86PDPT pPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1008 PX86PDPE pPdpe = &pPdpt->a[iPdPt];
1009
1010 *ppPdpt = pPdpt;
1011 if (!pPdpe->n.u1Present)
1012 return VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT;
1013
1014 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & X86_PDPE_PG_MASK);
1015 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1016
1017 *ppPD = (PX86PDPAE)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1018 return VINF_SUCCESS;
1019}
1020
1021/**
1022 * Syncs the SHADOW EPT page directory pointer for the specified address. Allocates
1023 * backing pages in case the PDPT or PML4 entry is missing.
1024 *
1025 * @returns VBox status.
1026 * @param pVM VM handle.
1027 * @param GCPtr The address.
1028 * @param ppPdpt Receives address of pdpt
1029 * @param ppPD Receives address of page directory
1030 */
1031VMMDECL(int) PGMShwGetEPTPDPtr(PVM pVM, RTGCUINTPTR64 GCPtr, PEPTPDPT *ppPdpt, PEPTPD *ppPD)
1032{
1033 PPGM pPGM = &pVM->pgm.s;
1034 const unsigned iPml4e = (GCPtr >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
1035 PPGMPOOL pPool = pPGM->CTX_SUFF(pPool);
1036 PEPTPML4 pPml4 = (PEPTPML4)pPGM->pHCNestedRoot;
1037 PEPTPML4E pPml4e;
1038 PPGMPOOLPAGE pShwPage;
1039 int rc;
1040
1041 Assert(HWACCMIsNestedPagingActive(pVM));
1042 Assert(pPml4);
1043
1044 /* Allocate page directory pointer table if not present. */
1045 pPml4e = &pPml4->a[iPml4e];
1046 if ( !pPml4e->n.u1Present
1047 && !(pPml4e->u & EPT_PML4E_PG_MASK))
1048 {
1049 Assert(!(pPml4e->u & EPT_PML4E_PG_MASK));
1050
1051 rc = pgmPoolAlloc(pVM, (GCPtr & EPT_PML4E_PG_MASK) + RT_BIT_64(63) /* hack: make the address unique */, PGMPOOLKIND_EPT_PDPT_FOR_PHYS, PGMPOOL_IDX_NESTED_ROOT, iPml4e, &pShwPage);
1052 if (rc == VERR_PGM_POOL_FLUSHED)
1053 {
1054 Log(("PGMShwSyncEPTPDPtr: PGM pool flushed (1) -> signal sync cr3\n"));
1055 Assert(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL);
1056 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
1057 return VINF_PGM_SYNC_CR3;
1058 }
1059 AssertRCReturn(rc, rc);
1060 }
1061 else
1062 {
1063 pShwPage = pgmPoolGetPage(pPool, pPml4e->u & EPT_PML4E_PG_MASK);
1064 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1065 }
1066 /* The PDPT was cached or created; hook it up now and fill with the default value. */
1067 pPml4e->u = pShwPage->Core.Key;
1068 pPml4e->n.u1Present = 1;
1069 pPml4e->n.u1Write = 1;
1070 pPml4e->n.u1Execute = 1;
1071
1072 const unsigned iPdPt = (GCPtr >> EPT_PDPT_SHIFT) & EPT_PDPT_MASK;
1073 PEPTPDPT pPdpt = (PEPTPDPT)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1074 PEPTPDPTE pPdpe = &pPdpt->a[iPdPt];
1075
1076 if (ppPdpt)
1077 *ppPdpt = pPdpt;
1078
1079 /* Allocate page directory if not present. */
1080 if ( !pPdpe->n.u1Present
1081 && !(pPdpe->u & EPT_PDPTE_PG_MASK))
1082 {
1083 rc = pgmPoolAlloc(pVM, (GCPtr & EPT_PDPTE_PG_MASK) + RT_BIT_64(62) /* hack: make the address unique */, PGMPOOLKIND_64BIT_PD_FOR_PHYS, pShwPage->idx, iPdPt, &pShwPage);
1084 if (rc == VERR_PGM_POOL_FLUSHED)
1085 {
1086 Log(("PGMShwSyncEPTPDPtr: PGM pool flushed (2) -> signal sync cr3\n"));
1087 Assert(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL);
1088 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
1089 return VINF_PGM_SYNC_CR3;
1090 }
1091 AssertRCReturn(rc, rc);
1092 }
1093 else
1094 {
1095 pShwPage = pgmPoolGetPage(pPool, pPdpe->u & EPT_PDPTE_PG_MASK);
1096 AssertReturn(pShwPage, VERR_INTERNAL_ERROR);
1097 }
1098 /* The PD was cached or created; hook it up now and fill with the default value. */
1099 pPdpe->u = pShwPage->Core.Key;
1100 pPdpe->n.u1Present = 1;
1101 pPdpe->n.u1Write = 1;
1102 pPdpe->n.u1Execute = 1;
1103
1104 *ppPD = (PEPTPD)PGMPOOL_PAGE_2_PTR(pVM, pShwPage);
1105 return VINF_SUCCESS;
1106}
1107
1108#endif
1109
1110/**
1111 * Gets effective Guest OS page information.
1112 *
1113 * When GCPtr is in a big page, the function will return as if it was a normal
1114 * 4KB page. If the need for distinguishing between big and normal page becomes
1115 * necessary at a later point, a PGMGstGetPage() will be created for that
1116 * purpose.
1117 *
1118 * @returns VBox status.
1119 * @param pVM VM Handle.
1120 * @param GCPtr Guest Context virtual address of the page.
1121 * @param pfFlags Where to store the flags. These are X86_PTE_*, even for big pages.
1122 * @param pGCPhys Where to store the GC physical address of the page.
1123 * This is page aligned. The fact that the
1124 */
1125VMMDECL(int) PGMGstGetPage(PVM pVM, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys)
1126{
1127 return PGM_GST_PFN(GetPage,pVM)(pVM, (RTGCUINTPTR)GCPtr, pfFlags, pGCPhys);
1128}
1129
1130
1131/**
1132 * Checks if the page is present.
1133 *
1134 * @returns true if the page is present.
1135 * @returns false if the page is not present.
1136 * @param pVM The VM handle.
1137 * @param GCPtr Address within the page.
1138 */
1139VMMDECL(bool) PGMGstIsPagePresent(PVM pVM, RTGCPTR GCPtr)
1140{
1141 int rc = PGMGstGetPage(pVM, GCPtr, NULL, NULL);
1142 return VBOX_SUCCESS(rc);
1143}
1144
1145
1146/**
1147 * Sets (replaces) the page flags for a range of pages in the guest's tables.
1148 *
1149 * @returns VBox status.
1150 * @param pVM VM handle.
1151 * @param GCPtr The address of the first page.
1152 * @param cb The size of the range in bytes.
1153 * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
1154 */
1155VMMDECL(int) PGMGstSetPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags)
1156{
1157 return PGMGstModifyPage(pVM, GCPtr, cb, fFlags, 0);
1158}
1159
1160
1161/**
1162 * Modify page flags for a range of pages in the guest's tables
1163 *
1164 * The existing flags are ANDed with the fMask and ORed with the fFlags.
1165 *
1166 * @returns VBox status code.
1167 * @param pVM VM handle.
1168 * @param GCPtr Virtual address of the first page in the range.
1169 * @param cb Size (in bytes) of the range to apply the modification to.
1170 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
1171 * @param fMask The AND mask - page flags X86_PTE_*, excluding the page mask of course.
1172 * Be very CAREFUL when ~'ing constants which could be 32-bit!
1173 */
1174VMMDECL(int) PGMGstModifyPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
1175{
1176 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,GstModifyPage), a);
1177
1178 /*
1179 * Validate input.
1180 */
1181 if (fFlags & X86_PTE_PAE_PG_MASK)
1182 {
1183 AssertMsgFailed(("fFlags=%#llx\n", fFlags));
1184 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,GstModifyPage), a);
1185 return VERR_INVALID_PARAMETER;
1186 }
1187
1188 if (!cb)
1189 {
1190 AssertFailed();
1191 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,GstModifyPage), a);
1192 return VERR_INVALID_PARAMETER;
1193 }
1194
1195 LogFlow(("PGMGstModifyPage %VGv %d bytes fFlags=%08llx fMask=%08llx\n", GCPtr, cb, fFlags, fMask));
1196
1197 /*
1198 * Adjust input.
1199 */
1200 cb += (RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK;
1201 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
1202 GCPtr = (RTGCPTR)((RTGCUINTPTR)GCPtr & PAGE_BASE_GC_MASK);
1203
1204 /*
1205 * Call worker.
1206 */
1207 int rc = PGM_GST_PFN(ModifyPage, pVM)(pVM, (RTGCUINTPTR)GCPtr, cb, fFlags, fMask);
1208
1209 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,GstModifyPage), a);
1210 return rc;
1211}
1212
1213/**
1214 * Gets the specified page directory pointer table entry.
1215 *
1216 * @returns PDP entry
1217 * @param pPGM Pointer to the PGM instance data.
1218 * @param iPdpt PDPT index
1219 */
1220VMMDECL(X86PDPE) PGMGstGetPaePDPtr(PVM pVM, unsigned iPdpt)
1221{
1222 Assert(iPdpt <= 3);
1223 return pVM->pgm.s.CTXSUFF(pGstPaePDPT)->a[iPdpt & 3];
1224}
1225
1226
1227/**
1228 * Gets the current CR3 register value for the shadow memory context.
1229 * @returns CR3 value.
1230 * @param pVM The VM handle.
1231 */
1232VMMDECL(RTHCPHYS) PGMGetHyperCR3(PVM pVM)
1233{
1234 PGMMODE enmShadowMode = pVM->pgm.s.enmShadowMode;
1235 switch (enmShadowMode)
1236 {
1237 case PGMMODE_32_BIT:
1238 return pVM->pgm.s.HCPhys32BitPD;
1239
1240 case PGMMODE_PAE:
1241 case PGMMODE_PAE_NX:
1242 return pVM->pgm.s.HCPhysPaePDPT;
1243
1244 case PGMMODE_AMD64:
1245 case PGMMODE_AMD64_NX:
1246 return pVM->pgm.s.HCPhysPaePML4;
1247
1248 case PGMMODE_EPT:
1249 return pVM->pgm.s.HCPhysNestedRoot;
1250
1251 case PGMMODE_NESTED:
1252 return PGMGetNestedCR3(pVM, PGMGetHostMode(pVM));
1253
1254 default:
1255 AssertMsgFailed(("enmShadowMode=%d\n", enmShadowMode));
1256 return ~0;
1257 }
1258}
1259
1260/**
1261 * Gets the current CR3 register value for the nested memory context.
1262 * @returns CR3 value.
1263 * @param pVM The VM handle.
1264 */
1265VMMDECL(RTHCPHYS) PGMGetNestedCR3(PVM pVM, PGMMODE enmShadowMode)
1266{
1267 switch (enmShadowMode)
1268 {
1269 case PGMMODE_32_BIT:
1270 return pVM->pgm.s.HCPhys32BitPD;
1271
1272 case PGMMODE_PAE:
1273 case PGMMODE_PAE_NX:
1274 return pVM->pgm.s.HCPhysPaePDPT;
1275
1276 case PGMMODE_AMD64:
1277 case PGMMODE_AMD64_NX:
1278 return pVM->pgm.s.HCPhysPaePML4;
1279
1280 default:
1281 AssertMsgFailed(("enmShadowMode=%d\n", enmShadowMode));
1282 return ~0;
1283 }
1284}
1285
1286/**
1287 * Gets the current CR3 register value for the EPT paging memory context.
1288 * @returns CR3 value.
1289 * @param pVM The VM handle.
1290 */
1291VMMDECL(RTHCPHYS) PGMGetEPTCR3(PVM pVM)
1292{
1293 return pVM->pgm.s.HCPhysNestedRoot;
1294}
1295
1296/**
1297 * Gets the CR3 register value for the 32-Bit shadow memory context.
1298 * @returns CR3 value.
1299 * @param pVM The VM handle.
1300 */
1301VMMDECL(RTHCPHYS) PGMGetHyper32BitCR3(PVM pVM)
1302{
1303 return pVM->pgm.s.HCPhys32BitPD;
1304}
1305
1306
1307/**
1308 * Gets the CR3 register value for the PAE shadow memory context.
1309 * @returns CR3 value.
1310 * @param pVM The VM handle.
1311 */
1312VMMDECL(RTHCPHYS) PGMGetHyperPaeCR3(PVM pVM)
1313{
1314 return pVM->pgm.s.HCPhysPaePDPT;
1315}
1316
1317
1318/**
1319 * Gets the CR3 register value for the AMD64 shadow memory context.
1320 * @returns CR3 value.
1321 * @param pVM The VM handle.
1322 */
1323VMMDECL(RTHCPHYS) PGMGetHyperAmd64CR3(PVM pVM)
1324{
1325 return pVM->pgm.s.HCPhysPaePML4;
1326}
1327
1328
1329/**
1330 * Gets the current CR3 register value for the HC intermediate memory context.
1331 * @returns CR3 value.
1332 * @param pVM The VM handle.
1333 */
1334VMMDECL(RTHCPHYS) PGMGetInterHCCR3(PVM pVM)
1335{
1336 switch (pVM->pgm.s.enmHostMode)
1337 {
1338 case SUPPAGINGMODE_32_BIT:
1339 case SUPPAGINGMODE_32_BIT_GLOBAL:
1340 return pVM->pgm.s.HCPhysInterPD;
1341
1342 case SUPPAGINGMODE_PAE:
1343 case SUPPAGINGMODE_PAE_GLOBAL:
1344 case SUPPAGINGMODE_PAE_NX:
1345 case SUPPAGINGMODE_PAE_GLOBAL_NX:
1346 return pVM->pgm.s.HCPhysInterPaePDPT;
1347
1348 case SUPPAGINGMODE_AMD64:
1349 case SUPPAGINGMODE_AMD64_GLOBAL:
1350 case SUPPAGINGMODE_AMD64_NX:
1351 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
1352 return pVM->pgm.s.HCPhysInterPaePDPT;
1353
1354 default:
1355 AssertMsgFailed(("enmHostMode=%d\n", pVM->pgm.s.enmHostMode));
1356 return ~0;
1357 }
1358}
1359
1360
1361/**
1362 * Gets the current CR3 register value for the GC intermediate memory context.
1363 * @returns CR3 value.
1364 * @param pVM The VM handle.
1365 */
1366VMMDECL(RTHCPHYS) PGMGetInterGCCR3(PVM pVM)
1367{
1368 switch (pVM->pgm.s.enmShadowMode)
1369 {
1370 case PGMMODE_32_BIT:
1371 return pVM->pgm.s.HCPhysInterPD;
1372
1373 case PGMMODE_PAE:
1374 case PGMMODE_PAE_NX:
1375 return pVM->pgm.s.HCPhysInterPaePDPT;
1376
1377 case PGMMODE_AMD64:
1378 case PGMMODE_AMD64_NX:
1379 return pVM->pgm.s.HCPhysInterPaePML4;
1380
1381 case PGMMODE_EPT:
1382 case PGMMODE_NESTED:
1383 return 0; /* not relevant */
1384
1385 default:
1386 AssertMsgFailed(("enmShadowMode=%d\n", pVM->pgm.s.enmShadowMode));
1387 return ~0;
1388 }
1389}
1390
1391
1392/**
1393 * Gets the CR3 register value for the 32-Bit intermediate memory context.
1394 * @returns CR3 value.
1395 * @param pVM The VM handle.
1396 */
1397VMMDECL(RTHCPHYS) PGMGetInter32BitCR3(PVM pVM)
1398{
1399 return pVM->pgm.s.HCPhysInterPD;
1400}
1401
1402
1403/**
1404 * Gets the CR3 register value for the PAE intermediate memory context.
1405 * @returns CR3 value.
1406 * @param pVM The VM handle.
1407 */
1408VMMDECL(RTHCPHYS) PGMGetInterPaeCR3(PVM pVM)
1409{
1410 return pVM->pgm.s.HCPhysInterPaePDPT;
1411}
1412
1413
1414/**
1415 * Gets the CR3 register value for the AMD64 intermediate memory context.
1416 * @returns CR3 value.
1417 * @param pVM The VM handle.
1418 */
1419VMMDECL(RTHCPHYS) PGMGetInterAmd64CR3(PVM pVM)
1420{
1421 return pVM->pgm.s.HCPhysInterPaePML4;
1422}
1423
1424
1425/**
1426 * Performs and schedules necessary updates following a CR3 load or reload.
1427 *
1428 * This will normally involve mapping the guest PD or nPDPT
1429 *
1430 * @returns VBox status code.
1431 * @retval VINF_PGM_SYNC_CR3 if monitoring requires a CR3 sync. This can
1432 * safely be ignored and overridden since the FF will be set too then.
1433 * @param pVM VM handle.
1434 * @param cr3 The new cr3.
1435 * @param fGlobal Indicates whether this is a global flush or not.
1436 */
1437VMMDECL(int) PGMFlushTLB(PVM pVM, uint64_t cr3, bool fGlobal)
1438{
1439 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLB), a);
1440
1441 /*
1442 * Always flag the necessary updates; necessary for hardware acceleration
1443 */
1444 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL);
1445 if (fGlobal)
1446 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
1447 LogFlow(("PGMFlushTLB: cr3=%VX64 OldCr3=%VX64 fGlobal=%d\n", cr3, pVM->pgm.s.GCPhysCR3, fGlobal));
1448
1449 /*
1450 * Remap the CR3 content and adjust the monitoring if CR3 was actually changed.
1451 */
1452 int rc = VINF_SUCCESS;
1453 RTGCPHYS GCPhysCR3;
1454 if ( pVM->pgm.s.enmGuestMode == PGMMODE_PAE
1455 || pVM->pgm.s.enmGuestMode == PGMMODE_PAE_NX
1456 || pVM->pgm.s.enmGuestMode == PGMMODE_AMD64
1457 || pVM->pgm.s.enmGuestMode == PGMMODE_AMD64_NX)
1458 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
1459 else
1460 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
1461 if (pVM->pgm.s.GCPhysCR3 != GCPhysCR3)
1462 {
1463 pVM->pgm.s.GCPhysCR3 = GCPhysCR3;
1464 rc = PGM_GST_PFN(MapCR3, pVM)(pVM, GCPhysCR3);
1465 if (VBOX_SUCCESS(rc) && !pVM->pgm.s.fMappingsFixed)
1466 {
1467 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1468 rc = PGM_GST_PFN(MonitorCR3, pVM)(pVM, GCPhysCR3);
1469 }
1470 if (fGlobal)
1471 STAM_COUNTER_INC(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLBNewCR3Global));
1472 else
1473 STAM_COUNTER_INC(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLBNewCR3));
1474 }
1475 else
1476 {
1477 /*
1478 * Check if we have a pending update of the CR3 monitoring.
1479 */
1480 if (pVM->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
1481 {
1482 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1483 Assert(!pVM->pgm.s.fMappingsFixed);
1484 rc = PGM_GST_PFN(MonitorCR3, pVM)(pVM, GCPhysCR3);
1485 }
1486 if (fGlobal)
1487 STAM_COUNTER_INC(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLBSameCR3Global));
1488 else
1489 STAM_COUNTER_INC(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLBSameCR3));
1490 }
1491
1492 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,FlushTLB), a);
1493 return rc;
1494}
1495
1496/**
1497 * Performs and schedules necessary updates following a CR3 load or reload,
1498 * without actually flushing the TLB as with PGMFlushTLB.
1499 *
1500 * This will normally involve mapping the guest PD or nPDPT
1501 *
1502 * @returns VBox status code.
1503 * @retval VINF_PGM_SYNC_CR3 if monitoring requires a CR3 sync. This can
1504 * safely be ignored and overridden since the FF will be set too then.
1505 * @param pVM VM handle.
1506 * @param cr3 The new cr3.
1507 */
1508VMMDECL(int) PGMUpdateCR3(PVM pVM, uint64_t cr3)
1509{
1510 LogFlow(("PGMUpdateCR3: cr3=%VX64 OldCr3=%VX64\n", cr3, pVM->pgm.s.GCPhysCR3));
1511
1512 /* We assume we're only called in nested paging mode. */
1513 Assert(pVM->pgm.s.fMappingsFixed);
1514 Assert(!(pVM->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3));
1515 Assert(pVM->pgm.s.enmShadowMode == PGMMODE_NESTED || pVM->pgm.s.enmShadowMode == PGMMODE_EPT);
1516
1517 /*
1518 * Remap the CR3 content and adjust the monitoring if CR3 was actually changed.
1519 */
1520 int rc = VINF_SUCCESS;
1521 RTGCPHYS GCPhysCR3;
1522 if ( pVM->pgm.s.enmGuestMode == PGMMODE_PAE
1523 || pVM->pgm.s.enmGuestMode == PGMMODE_PAE_NX
1524 || pVM->pgm.s.enmGuestMode == PGMMODE_AMD64
1525 || pVM->pgm.s.enmGuestMode == PGMMODE_AMD64_NX)
1526 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAE_PAGE_MASK);
1527 else
1528 GCPhysCR3 = (RTGCPHYS)(cr3 & X86_CR3_PAGE_MASK);
1529 if (pVM->pgm.s.GCPhysCR3 != GCPhysCR3)
1530 {
1531 pVM->pgm.s.GCPhysCR3 = GCPhysCR3;
1532 rc = PGM_GST_PFN(MapCR3, pVM)(pVM, GCPhysCR3);
1533 }
1534 AssertRC(rc);
1535 return rc;
1536}
1537
1538/**
1539 * Synchronize the paging structures.
1540 *
1541 * This function is called in response to the VM_FF_PGM_SYNC_CR3 and
1542 * VM_FF_PGM_SYNC_CR3_NONGLOBAL. Those two force action flags are set
1543 * in several places, most importantly whenever the CR3 is loaded.
1544 *
1545 * @returns VBox status code.
1546 * @param pVM The virtual machine.
1547 * @param cr0 Guest context CR0 register
1548 * @param cr3 Guest context CR3 register
1549 * @param cr4 Guest context CR4 register
1550 * @param fGlobal Including global page directories or not
1551 */
1552VMMDECL(int) PGMSyncCR3(PVM pVM, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal)
1553{
1554 /*
1555 * We might be called when we shouldn't.
1556 *
1557 * The mode switching will ensure that the PD is resynced
1558 * after every mode switch. So, if we find ourselves here
1559 * when in protected or real mode we can safely disable the
1560 * FF and return immediately.
1561 */
1562 if (pVM->pgm.s.enmGuestMode <= PGMMODE_PROTECTED)
1563 {
1564 Assert((cr0 & (X86_CR0_PG | X86_CR0_PE)) != (X86_CR0_PG | X86_CR0_PE));
1565 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3);
1566 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL);
1567 return VINF_SUCCESS;
1568 }
1569
1570 /* If global pages are not supported, then all flushes are global */
1571 if (!(cr4 & X86_CR4_PGE))
1572 fGlobal = true;
1573 LogFlow(("PGMSyncCR3: cr0=%VX64 cr3=%VX64 cr4=%VX64 fGlobal=%d[%d,%d]\n", cr0, cr3, cr4, fGlobal,
1574 VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3), VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL)));
1575
1576 /*
1577 * Let the 'Bth' function do the work and we'll just keep track of the flags.
1578 */
1579 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
1580 int rc = PGM_BTH_PFN(SyncCR3, pVM)(pVM, cr0, cr3, cr4, fGlobal);
1581 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
1582 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 || VBOX_FAILURE(rc), ("rc=%VRc\n", rc));
1583 if (rc == VINF_SUCCESS)
1584 {
1585 if (!(pVM->pgm.s.fSyncFlags & PGM_SYNC_ALWAYS))
1586 {
1587 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3);
1588 VM_FF_CLEAR(pVM, VM_FF_PGM_SYNC_CR3_NON_GLOBAL);
1589 }
1590
1591 /*
1592 * Check if we have a pending update of the CR3 monitoring.
1593 */
1594 if (pVM->pgm.s.fSyncFlags & PGM_SYNC_MONITOR_CR3)
1595 {
1596 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
1597 Assert(!pVM->pgm.s.fMappingsFixed);
1598 Assert(pVM->pgm.s.GCPhysCR3 == pVM->pgm.s.GCPhysGstCR3Monitored);
1599 rc = PGM_GST_PFN(MonitorCR3, pVM)(pVM, pVM->pgm.s.GCPhysCR3);
1600 }
1601 }
1602
1603 /*
1604 * Now flush the CR3 (guest context).
1605 */
1606 if (rc == VINF_SUCCESS)
1607 PGM_INVL_GUEST_TLBS();
1608 return rc;
1609}
1610
1611
1612/**
1613 * Called whenever CR0 or CR4 in a way which may change
1614 * the paging mode.
1615 *
1616 * @returns VBox status code fit for scheduling in GC and R0.
1617 * @retval VINF_SUCCESS if the was no change, or it was successfully dealt with.
1618 * @retval VINF_PGM_CHANGE_MODE if we're in GC or R0 and the mode changes.
1619 * @param pVM VM handle.
1620 * @param cr0 The new cr0.
1621 * @param cr4 The new cr4.
1622 * @param efer The new extended feature enable register.
1623 */
1624VMMDECL(int) PGMChangeMode(PVM pVM, uint64_t cr0, uint64_t cr4, uint64_t efer)
1625{
1626 PGMMODE enmGuestMode;
1627
1628 /*
1629 * Calc the new guest mode.
1630 */
1631 if (!(cr0 & X86_CR0_PE))
1632 enmGuestMode = PGMMODE_REAL;
1633 else if (!(cr0 & X86_CR0_PG))
1634 enmGuestMode = PGMMODE_PROTECTED;
1635 else if (!(cr4 & X86_CR4_PAE))
1636 enmGuestMode = PGMMODE_32_BIT;
1637 else if (!(efer & MSR_K6_EFER_LME))
1638 {
1639 if (!(efer & MSR_K6_EFER_NXE))
1640 enmGuestMode = PGMMODE_PAE;
1641 else
1642 enmGuestMode = PGMMODE_PAE_NX;
1643 }
1644 else
1645 {
1646 if (!(efer & MSR_K6_EFER_NXE))
1647 enmGuestMode = PGMMODE_AMD64;
1648 else
1649 enmGuestMode = PGMMODE_AMD64_NX;
1650 }
1651
1652 /*
1653 * Did it change?
1654 */
1655 if (pVM->pgm.s.enmGuestMode == enmGuestMode)
1656 return VINF_SUCCESS;
1657
1658 /* Flush the TLB */
1659 PGM_INVL_GUEST_TLBS();
1660
1661#ifdef IN_RING3
1662 return PGMR3ChangeMode(pVM, enmGuestMode);
1663#else
1664 Log(("PGMChangeMode: returns VINF_PGM_CHANGE_MODE.\n"));
1665 return VINF_PGM_CHANGE_MODE;
1666#endif
1667}
1668
1669
1670/**
1671 * Gets the current guest paging mode.
1672 *
1673 * If you just need the CPU mode (real/protected/long), use CPUMGetGuestMode().
1674 *
1675 * @returns The current paging mode.
1676 * @param pVM The VM handle.
1677 */
1678VMMDECL(PGMMODE) PGMGetGuestMode(PVM pVM)
1679{
1680 return pVM->pgm.s.enmGuestMode;
1681}
1682
1683
1684/**
1685 * Gets the current shadow paging mode.
1686 *
1687 * @returns The current paging mode.
1688 * @param pVM The VM handle.
1689 */
1690VMMDECL(PGMMODE) PGMGetShadowMode(PVM pVM)
1691{
1692 return pVM->pgm.s.enmShadowMode;
1693}
1694
1695/**
1696 * Gets the current host paging mode.
1697 *
1698 * @returns The current paging mode.
1699 * @param pVM The VM handle.
1700 */
1701VMMDECL(PGMMODE) PGMGetHostMode(PVM pVM)
1702{
1703 switch (pVM->pgm.s.enmHostMode)
1704 {
1705 case SUPPAGINGMODE_32_BIT:
1706 case SUPPAGINGMODE_32_BIT_GLOBAL:
1707 return PGMMODE_32_BIT;
1708
1709 case SUPPAGINGMODE_PAE:
1710 case SUPPAGINGMODE_PAE_GLOBAL:
1711 return PGMMODE_PAE;
1712
1713 case SUPPAGINGMODE_PAE_NX:
1714 case SUPPAGINGMODE_PAE_GLOBAL_NX:
1715 return PGMMODE_PAE_NX;
1716
1717 case SUPPAGINGMODE_AMD64:
1718 case SUPPAGINGMODE_AMD64_GLOBAL:
1719 return PGMMODE_AMD64;
1720
1721 case SUPPAGINGMODE_AMD64_NX:
1722 case SUPPAGINGMODE_AMD64_GLOBAL_NX:
1723 return PGMMODE_AMD64_NX;
1724
1725 default: AssertMsgFailed(("enmHostMode=%d\n", pVM->pgm.s.enmHostMode)); break;
1726 }
1727
1728 return PGMMODE_INVALID;
1729}
1730
1731
1732/**
1733 * Get mode name.
1734 *
1735 * @returns read-only name string.
1736 * @param enmMode The mode which name is desired.
1737 */
1738VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode)
1739{
1740 switch (enmMode)
1741 {
1742 case PGMMODE_REAL: return "Real";
1743 case PGMMODE_PROTECTED: return "Protected";
1744 case PGMMODE_32_BIT: return "32-bit";
1745 case PGMMODE_PAE: return "PAE";
1746 case PGMMODE_PAE_NX: return "PAE+NX";
1747 case PGMMODE_AMD64: return "AMD64";
1748 case PGMMODE_AMD64_NX: return "AMD64+NX";
1749 case PGMMODE_NESTED: return "Nested";
1750 case PGMMODE_EPT: return "EPT";
1751 default: return "unknown mode value";
1752 }
1753}
1754
1755
1756/**
1757 * Acquire the PGM lock.
1758 *
1759 * @returns VBox status code
1760 * @param pVM The VM to operate on.
1761 */
1762int pgmLock(PVM pVM)
1763{
1764 int rc = PDMCritSectEnter(&pVM->pgm.s.CritSect, VERR_SEM_BUSY);
1765#ifdef IN_GC
1766 if (rc == VERR_SEM_BUSY)
1767 rc = VMMGCCallHost(pVM, VMMCALLHOST_PGM_LOCK, 0);
1768#elif defined(IN_RING0)
1769 if (rc == VERR_SEM_BUSY)
1770 rc = VMMR0CallHost(pVM, VMMCALLHOST_PGM_LOCK, 0);
1771#endif
1772 AssertRC(rc);
1773 return rc;
1774}
1775
1776
1777/**
1778 * Release the PGM lock.
1779 *
1780 * @returns VBox status code
1781 * @param pVM The VM to operate on.
1782 */
1783void pgmUnlock(PVM pVM)
1784{
1785 PDMCritSectLeave(&pVM->pgm.s.CritSect);
1786}
1787
1788#if defined(IN_GC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
1789
1790/**
1791 * Temporarily maps one guest page specified by GC physical address.
1792 * These pages must have a physical mapping in HC, i.e. they cannot be MMIO pages.
1793 *
1794 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
1795 * reused after 8 mappings (or perhaps a few more if you score with the cache).
1796 *
1797 * @returns VBox status.
1798 * @param pVM VM handle.
1799 * @param GCPhys GC Physical address of the page.
1800 * @param ppv Where to store the address of the mapping.
1801 */
1802VMMDECL(int) PGMDynMapGCPage(PVM pVM, RTGCPHYS GCPhys, void **ppv)
1803{
1804 AssertMsg(!(GCPhys & PAGE_OFFSET_MASK), ("GCPhys=%RGp\n", GCPhys));
1805
1806 /*
1807 * Get the ram range.
1808 */
1809 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
1810 while (pRam && GCPhys - pRam->GCPhys >= pRam->cb)
1811 pRam = pRam->CTX_SUFF(pNext);
1812 if (!pRam)
1813 {
1814 AssertMsgFailed(("Invalid physical address %RGp!\n", GCPhys));
1815 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
1816 }
1817
1818 /*
1819 * Pass it on to PGMDynMapHCPage.
1820 */
1821 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT]);
1822 //Log(("PGMDynMapGCPage: GCPhys=%VGp HCPhys=%VHp\n", GCPhys, HCPhys));
1823 return PGMDynMapHCPage(pVM, HCPhys, ppv);
1824}
1825
1826
1827/**
1828 * Temporarily maps one guest page specified by unaligned GC physical address.
1829 * These pages must have a physical mapping in HC, i.e. they cannot be MMIO pages.
1830 *
1831 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
1832 * reused after 8 mappings (or perhaps a few more if you score with the cache).
1833 *
1834 * The caller is aware that only the speicifed page is mapped and that really bad things
1835 * will happen if writing beyond the page!
1836 *
1837 * @returns VBox status.
1838 * @param pVM VM handle.
1839 * @param GCPhys GC Physical address within the page to be mapped.
1840 * @param ppv Where to store the address of the mapping address corresponding to GCPhys.
1841 */
1842VMMDECL(int) PGMDynMapGCPageOff(PVM pVM, RTGCPHYS GCPhys, void **ppv)
1843{
1844 /*
1845 * Get the ram range.
1846 */
1847 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
1848 while (pRam && GCPhys - pRam->GCPhys >= pRam->cb)
1849 pRam = pRam->CTX_SUFF(pNext);
1850 if (!pRam)
1851 {
1852 AssertMsgFailed(("Invalid physical address %VGp!\n", GCPhys));
1853 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
1854 }
1855
1856 /*
1857 * Pass it on to PGMDynMapHCPage.
1858 */
1859 RTHCPHYS HCPhys = PGM_PAGE_GET_HCPHYS(&pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT]);
1860 int rc = PGMDynMapHCPage(pVM, HCPhys, ppv);
1861 if (RT_SUCCESS(rc))
1862 *ppv = (void *)((uintptr_t)*ppv | (GCPhys & PAGE_OFFSET_MASK));
1863 return rc;
1864}
1865
1866
1867/**
1868 * Temporarily maps one host page specified by HC physical address.
1869 *
1870 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
1871 * reused after 8 mappings (or perhaps a few more if you score with the cache).
1872 *
1873 * @returns VBox status.
1874 * @param pVM VM handle.
1875 * @param HCPhys HC Physical address of the page.
1876 * @param ppv Where to store the address of the mapping. This is the
1877 * address of the PAGE not the exact address corresponding
1878 * to HCPhys. Use PGMDynMapHCPageOff if you care for the
1879 * page offset.
1880 */
1881VMMDECL(int) PGMDynMapHCPage(PVM pVM, RTHCPHYS HCPhys, void **ppv)
1882{
1883 AssertMsg(!(HCPhys & PAGE_OFFSET_MASK), ("HCPhys=%RHp\n", HCPhys));
1884# ifdef IN_GC
1885
1886 /*
1887 * Check the cache.
1888 */
1889 register unsigned iCache;
1890 if ( pVM->pgm.s.aHCPhysDynPageMapCache[iCache = 0] == HCPhys
1891 || pVM->pgm.s.aHCPhysDynPageMapCache[iCache = 1] == HCPhys
1892 || pVM->pgm.s.aHCPhysDynPageMapCache[iCache = 2] == HCPhys
1893 || pVM->pgm.s.aHCPhysDynPageMapCache[iCache = 3] == HCPhys)
1894 {
1895 static const uint8_t au8Trans[MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT][RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache)] =
1896 {
1897 { 0, 5, 6, 7 },
1898 { 0, 1, 6, 7 },
1899 { 0, 1, 2, 7 },
1900 { 0, 1, 2, 3 },
1901 { 4, 1, 2, 3 },
1902 { 4, 5, 2, 3 },
1903 { 4, 5, 6, 3 },
1904 { 4, 5, 6, 7 },
1905 };
1906 Assert(RT_ELEMENTS(au8Trans) == 8);
1907 Assert(RT_ELEMENTS(au8Trans[0]) == 4);
1908 int iPage = au8Trans[pVM->pgm.s.iDynPageMapLast][iCache];
1909 void *pv = pVM->pgm.s.pbDynPageMapBaseGC + (iPage << PAGE_SHIFT);
1910 *ppv = pv;
1911 STAM_COUNTER_INC(&pVM->pgm.s.StatRCDynMapCacheHits);
1912 //Log(("PGMGCDynMapHCPage: HCPhys=%VHp pv=%VGv iPage=%d iCache=%d\n", HCPhys, pv, iPage, iCache));
1913 return VINF_SUCCESS;
1914 }
1915 Assert(RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) == 4);
1916 STAM_COUNTER_INC(&pVM->pgm.s.StatRCDynMapCacheMisses);
1917
1918 /*
1919 * Update the page tables.
1920 */
1921 register unsigned iPage = pVM->pgm.s.iDynPageMapLast;
1922 pVM->pgm.s.iDynPageMapLast = iPage = (iPage + 1) & ((MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT) - 1);
1923 Assert((MM_HYPER_DYNAMIC_SIZE >> PAGE_SHIFT) == 8);
1924
1925 pVM->pgm.s.aHCPhysDynPageMapCache[iPage & (RT_ELEMENTS(pVM->pgm.s.aHCPhysDynPageMapCache) - 1)] = HCPhys;
1926 pVM->pgm.s.paDynPageMap32BitPTEsGC[iPage].u = (uint32_t)HCPhys | X86_PTE_P | X86_PTE_A | X86_PTE_D;
1927 pVM->pgm.s.paDynPageMapPaePTEsGC[iPage].u = HCPhys | X86_PTE_P | X86_PTE_A | X86_PTE_D;
1928
1929 void *pv = pVM->pgm.s.pbDynPageMapBaseGC + (iPage << PAGE_SHIFT);
1930 *ppv = pv;
1931 ASMInvalidatePage(pv);
1932 Log4(("PGMGCDynMapHCPage: HCPhys=%VHp pv=%VGv iPage=%d\n", HCPhys, pv, iPage));
1933 return VINF_SUCCESS;
1934
1935#else /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
1936 AssertFailed();
1937 return VERR_NOT_IMPLEMENTED;
1938#endif /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
1939}
1940
1941
1942/**
1943 * Temporarily maps one host page specified by HC physical address, returning
1944 * pointer within the page.
1945 *
1946 * Be WARNED that the dynamic page mapping area is small, 8 pages, thus the space is
1947 * reused after 8 mappings (or perhaps a few more if you score with the cache).
1948 *
1949 * @returns VBox status.
1950 * @param pVM VM handle.
1951 * @param HCPhys HC Physical address of the page.
1952 * @param ppv Where to store the address corresponding to HCPhys.
1953 */
1954VMMDECL(int) PGMDynMapHCPageOff(PVM pVM, RTHCPHYS HCPhys, void **ppv)
1955{
1956 int rc = PGMDynMapHCPage(pVM, HCPhys & ~(RTHCPHYS)PAGE_OFFSET_MASK, ppv);
1957 if (RT_SUCCESS(rc))
1958 *ppv = (void *)((uintptr_t)*ppv | (HCPhys & PAGE_OFFSET_MASK));
1959 return rc;
1960}
1961
1962#endif /* IN_GC || VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
1963
1964#ifdef VBOX_STRICT
1965
1966/**
1967 * Asserts that there are no mapping conflicts.
1968 *
1969 * @returns Number of conflicts.
1970 * @param pVM The VM Handle.
1971 */
1972VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM)
1973{
1974 unsigned cErrors = 0;
1975
1976 /*
1977 * Check for mapping conflicts.
1978 */
1979 for (PPGMMAPPING pMapping = pVM->pgm.s.CTX_SUFF(pMappings);
1980 pMapping;
1981 pMapping = pMapping->CTX_SUFF(pNext))
1982 {
1983 /** @todo This is slow and should be optimized, but since it's just assertions I don't care now. */
1984 for (RTGCUINTPTR GCPtr = (RTGCUINTPTR)pMapping->GCPtr;
1985 GCPtr <= (RTGCUINTPTR)pMapping->GCPtrLast;
1986 GCPtr += PAGE_SIZE)
1987 {
1988 int rc = PGMGstGetPage(pVM, (RTGCPTR)GCPtr, NULL, NULL);
1989 if (rc != VERR_PAGE_TABLE_NOT_PRESENT)
1990 {
1991 AssertMsgFailed(("Conflict at %VGv with %s\n", GCPtr, R3STRING(pMapping->pszDesc)));
1992 cErrors++;
1993 break;
1994 }
1995 }
1996 }
1997
1998 return cErrors;
1999}
2000
2001
2002/**
2003 * Asserts that everything related to the guest CR3 is correctly shadowed.
2004 *
2005 * This will call PGMAssertNoMappingConflicts() and PGMAssertHandlerAndFlagsInSync(),
2006 * and assert the correctness of the guest CR3 mapping before asserting that the
2007 * shadow page tables is in sync with the guest page tables.
2008 *
2009 * @returns Number of conflicts.
2010 * @param pVM The VM Handle.
2011 * @param cr3 The current guest CR3 register value.
2012 * @param cr4 The current guest CR4 register value.
2013 */
2014VMMDECL(unsigned) PGMAssertCR3(PVM pVM, uint64_t cr3, uint64_t cr4)
2015{
2016 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
2017 unsigned cErrors = PGM_BTH_PFN(AssertCR3, pVM)(pVM, cr3, cr4, 0, ~(RTGCUINTPTR)0);
2018 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_MID_Z(Stat,SyncCR3), a);
2019 return cErrors;
2020 return 0;
2021}
2022
2023#endif /* VBOX_STRICT */
Note: See TracBrowser for help on using the repository browser.

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