VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllMap.cpp@ 25935

Last change on this file since 25935 was 25935, checked in by vboxsync, 15 years ago

PGM,CPUM: Be more careful and flexible with guest mappings on restore. (#4362)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 33.9 KB
Line 
1/* $Id: PGMAllMap.cpp 25935 2010-01-20 14:43:56Z 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 "PGMInternal.h"
28#include <VBox/vm.h>
29#include <iprt/assert.h>
30#include <iprt/asm.h>
31#include <VBox/err.h>
32
33
34/**
35 * Maps a range of physical pages at a given virtual address
36 * in the guest context.
37 *
38 * The GC virtual address range must be within an existing mapping.
39 *
40 * @returns VBox status code.
41 * @param pVM The virtual machine.
42 * @param GCPtr Where to map the page(s). Must be page aligned.
43 * @param HCPhys Start of the range of physical pages. Must be page aligned.
44 * @param cbPages Number of bytes to map. Must be page aligned.
45 * @param fFlags Page flags (X86_PTE_*).
46 */
47VMMDECL(int) PGMMap(PVM pVM, RTGCUINTPTR GCPtr, RTHCPHYS HCPhys, uint32_t cbPages, unsigned fFlags)
48{
49 AssertMsg(pVM->pgm.s.offVM, ("Bad init order\n"));
50
51 /*
52 * Validate input.
53 */
54 AssertMsg(RT_ALIGN_T(GCPtr, PAGE_SIZE, RTGCUINTPTR) == GCPtr, ("Invalid alignment GCPtr=%#x\n", GCPtr));
55 AssertMsg(cbPages > 0 && RT_ALIGN_32(cbPages, PAGE_SIZE) == cbPages, ("Invalid cbPages=%#x\n", cbPages));
56 AssertMsg(!(fFlags & X86_PDE_PG_MASK), ("Invalid flags %#x\n", fFlags));
57
58 /* hypervisor defaults */
59 if (!fFlags)
60 fFlags = X86_PTE_P | X86_PTE_A | X86_PTE_D;
61
62 /*
63 * Find the mapping.
64 */
65 PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings);
66 while (pCur)
67 {
68 if (GCPtr - pCur->GCPtr < pCur->cb)
69 {
70 if (GCPtr + cbPages - 1 > pCur->GCPtrLast)
71 {
72 AssertMsgFailed(("Invalid range!!\n"));
73 return VERR_INVALID_PARAMETER;
74 }
75
76 /*
77 * Setup PTE.
78 */
79 X86PTEPAE Pte;
80 Pte.u = fFlags | (HCPhys & X86_PTE_PAE_PG_MASK);
81
82 /*
83 * Update the page tables.
84 */
85 for (;;)
86 {
87 RTGCUINTPTR off = GCPtr - pCur->GCPtr;
88 const unsigned iPT = off >> X86_PD_SHIFT;
89 const unsigned iPageNo = (off >> PAGE_SHIFT) & X86_PT_MASK;
90
91 /* 32-bit */
92 pCur->aPTs[iPT].CTX_SUFF(pPT)->a[iPageNo].u = (uint32_t)Pte.u; /* ASSUMES HCPhys < 4GB and/or that we're never gonna do 32-bit on a PAE host! */
93
94 /* pae */
95 pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPageNo / 512].a[iPageNo % 512].u = Pte.u;
96
97 /* next */
98 cbPages -= PAGE_SIZE;
99 if (!cbPages)
100 break;
101 GCPtr += PAGE_SIZE;
102 Pte.u += PAGE_SIZE;
103 }
104
105 return VINF_SUCCESS;
106 }
107
108 /* next */
109 pCur = pCur->CTX_SUFF(pNext);
110 }
111
112 AssertMsgFailed(("GCPtr=%#x was not found in any mapping ranges!\n", GCPtr));
113 return VERR_INVALID_PARAMETER;
114}
115
116
117/**
118 * Sets (replaces) the page flags for a range of pages in a mapping.
119 *
120 * @returns VBox status.
121 * @param pVM VM handle.
122 * @param GCPtr Virtual address of the first page in the range.
123 * @param cb Size (in bytes) of the range to apply the modification to.
124 * @param fFlags Page flags X86_PTE_*, excluding the page mask of course.
125 */
126VMMDECL(int) PGMMapSetPage(PVM pVM, RTGCPTR GCPtr, uint64_t cb, uint64_t fFlags)
127{
128 return PGMMapModifyPage(pVM, GCPtr, cb, fFlags, 0);
129}
130
131
132/**
133 * Modify page flags for a range of pages in a mapping.
134 *
135 * The existing flags are ANDed with the fMask and ORed with the fFlags.
136 *
137 * @returns VBox status code.
138 * @param pVM VM handle.
139 * @param GCPtr Virtual address of the first page in the range.
140 * @param cb Size (in bytes) of the range to apply the modification to.
141 * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
142 * @param fMask The AND mask - page flags X86_PTE_*, excluding the page mask of course.
143 */
144VMMDECL(int) PGMMapModifyPage(PVM pVM, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
145{
146 /*
147 * Validate input.
148 */
149 AssertMsg(!(fFlags & X86_PTE_PAE_PG_MASK), ("fFlags=%#x\n", fFlags));
150 Assert(cb);
151
152 /*
153 * Align the input.
154 */
155 cb += (RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK;
156 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
157 GCPtr = (RTGCPTR)((RTGCUINTPTR)GCPtr & PAGE_BASE_GC_MASK);
158
159 /*
160 * Find the mapping.
161 */
162 PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings);
163 while (pCur)
164 {
165 RTGCUINTPTR off = (RTGCUINTPTR)GCPtr - (RTGCUINTPTR)pCur->GCPtr;
166 if (off < pCur->cb)
167 {
168 AssertMsgReturn(off + cb <= pCur->cb,
169 ("Invalid page range %#x LB%#x. mapping '%s' %#x to %#x\n",
170 GCPtr, cb, pCur->pszDesc, pCur->GCPtr, pCur->GCPtrLast),
171 VERR_INVALID_PARAMETER);
172
173 /*
174 * Perform the requested operation.
175 */
176 while (cb > 0)
177 {
178 unsigned iPT = off >> X86_PD_SHIFT;
179 unsigned iPTE = (off >> PAGE_SHIFT) & X86_PT_MASK;
180 while (cb > 0 && iPTE < RT_ELEMENTS(pCur->aPTs[iPT].CTX_SUFF(pPT)->a))
181 {
182 /* 32-Bit */
183 pCur->aPTs[iPT].CTX_SUFF(pPT)->a[iPTE].u &= fMask | X86_PTE_PG_MASK;
184 pCur->aPTs[iPT].CTX_SUFF(pPT)->a[iPTE].u |= fFlags & ~X86_PTE_PG_MASK;
185
186 /* PAE */
187 pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPTE / 512].a[iPTE % 512].u &= fMask | X86_PTE_PAE_PG_MASK;
188 pCur->aPTs[iPT].CTX_SUFF(paPaePTs)[iPTE / 512].a[iPTE % 512].u |= fFlags & ~X86_PTE_PAE_PG_MASK;
189
190 /* invalidate tls */
191 PGM_INVL_PG(VMMGetCpu(pVM), (RTGCUINTPTR)pCur->GCPtr + off);
192
193 /* next */
194 iPTE++;
195 cb -= PAGE_SIZE;
196 off += PAGE_SIZE;
197 }
198 }
199
200 return VINF_SUCCESS;
201 }
202 /* next */
203 pCur = pCur->CTX_SUFF(pNext);
204 }
205
206 AssertMsgFailed(("Page range %#x LB%#x not found\n", GCPtr, cb));
207 return VERR_INVALID_PARAMETER;
208}
209
210
211#ifndef IN_RING0
212/**
213 * Sets all PDEs involved with the mapping in the shadow page table.
214 *
215 * @param pVM The VM handle.
216 * @param pMap Pointer to the mapping in question.
217 * @param iNewPDE The index of the 32-bit PDE corresponding to the base of the mapping.
218 */
219void pgmMapSetShadowPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iNewPDE)
220{
221 Log4(("pgmMapSetShadowPDEs new pde %x (mappings enabled %d)\n", iNewPDE, pgmMapAreMappingsEnabled(&pVM->pgm.s)));
222
223 if ( !pgmMapAreMappingsEnabled(&pVM->pgm.s)
224 || pVM->cCpus > 1)
225 return;
226
227 /* This only applies to raw mode where we only support 1 VCPU. */
228 PVMCPU pVCpu = VMMGetCpu0(pVM);
229 if (!pVCpu->pgm.s.CTX_SUFF(pShwPageCR3))
230 return; /* too early */
231
232 PGMMODE enmShadowMode = PGMGetShadowMode(pVCpu);
233 Assert(enmShadowMode <= PGMMODE_PAE_NX);
234
235 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
236
237 /*
238 * Insert the page tables into the shadow page directories.
239 */
240 unsigned i = pMap->cPTs;
241 iNewPDE += i;
242 while (i-- > 0)
243 {
244 iNewPDE--;
245
246 switch (enmShadowMode)
247 {
248 case PGMMODE_32_BIT:
249 {
250 PX86PD pShw32BitPd = pgmShwGet32BitPDPtr(&pVCpu->pgm.s);
251 AssertFatal(pShw32BitPd);
252#ifdef IN_RC /* Lock mapping to prevent it from being reused during pgmPoolFree. */
253 PGMDynLockHCPage(pVM, (uint8_t *)pShw32BitPd);
254#endif
255 /* Free any previous user, unless it's us. */
256 Assert( (pShw32BitPd->a[iNewPDE].u & (X86_PDE_P | PGM_PDFLAGS_MAPPING)) != (X86_PDE_P | PGM_PDFLAGS_MAPPING)
257 || (pShw32BitPd->a[iNewPDE].u & X86_PDE_PG_MASK) == pMap->aPTs[i].HCPhysPT);
258 if ( pShw32BitPd->a[iNewPDE].n.u1Present
259 && !(pShw32BitPd->a[iNewPDE].u & PGM_PDFLAGS_MAPPING))
260 pgmPoolFree(pVM, pShw32BitPd->a[iNewPDE].u & X86_PDE_PG_MASK, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3)->idx, iNewPDE);
261
262 /* Default mapping page directory flags are read/write and supervisor; individual page attributes determine the final flags. */
263 pShw32BitPd->a[iNewPDE].u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US
264 | (uint32_t)pMap->aPTs[i].HCPhysPT;
265#ifdef IN_RC
266 /* Unlock dynamic mappings again. */
267 PGMDynUnlockHCPage(pVM, (uint8_t *)pShw32BitPd);
268#endif
269 break;
270 }
271
272 case PGMMODE_PAE:
273 case PGMMODE_PAE_NX:
274 {
275 const uint32_t iPdPt = iNewPDE / 256;
276 unsigned iPaePde = iNewPDE * 2 % 512;
277 PX86PDPT pShwPdpt = pgmShwGetPaePDPTPtr(&pVCpu->pgm.s);
278 Assert(pShwPdpt);
279#ifdef IN_RC /* Lock mapping to prevent it from being reused during pgmShwSyncPaePDPtr. */
280 PGMDynLockHCPage(pVM, (uint8_t *)pShwPdpt);
281#endif
282
283 /*
284 * Get the shadow PD.
285 * If no PD, sync it (PAE guest) or fake (not present or 32-bit guest).
286 * Note! The RW, US and A bits are reserved for PAE PDPTEs. Setting the
287 * accessed bit causes invalid VT-x guest state errors.
288 */
289 PX86PDPAE pShwPaePd = pgmShwGetPaePDPtr(&pVCpu->pgm.s, iPdPt << X86_PDPT_SHIFT);
290 if (!pShwPaePd)
291 {
292 X86PDPE GstPdpe;
293 if (PGMGetGuestMode(pVCpu) < PGMMODE_PAE)
294 GstPdpe.u = X86_PDPE_P;
295 else
296 {
297 PX86PDPE pGstPdpe = pgmGstGetPaePDPEPtr(&pVCpu->pgm.s, iPdPt << X86_PDPT_SHIFT);
298 if (pGstPdpe)
299 GstPdpe = *pGstPdpe;
300 else
301 GstPdpe.u = X86_PDPE_P;
302 }
303 int rc = pgmShwSyncPaePDPtr(pVCpu, iPdPt << X86_PDPT_SHIFT, &GstPdpe, &pShwPaePd);
304 AssertFatalRC(rc);
305 }
306 Assert(pShwPaePd);
307#ifdef IN_RC /* Lock mapping to prevent it from being reused during pgmPoolFree. */
308 PGMDynLockHCPage(pVM, (uint8_t *)pShwPaePd);
309#endif
310
311 /*
312 * Mark the page as locked; disallow flushing.
313 */
314 PPGMPOOLPAGE pPoolPagePd = pgmPoolGetPage(pPool, pShwPdpt->a[iPdPt].u & X86_PDPE_PG_MASK);
315 AssertFatal(pPoolPagePd);
316 if (!pgmPoolIsPageLocked(&pVM->pgm.s, pPoolPagePd))
317 pgmPoolLockPage(pPool, pPoolPagePd);
318#ifdef VBOX_STRICT
319 else if (pShwPaePd->a[iPaePde].u & PGM_PDFLAGS_MAPPING)
320 {
321 Assert(PGMGetGuestMode(pVCpu) >= PGMMODE_PAE); /** @todo We may hit this during reset, will fix later. */
322 AssertFatalMsg( (pShwPaePd->a[iPaePde].u & X86_PDE_PAE_PG_MASK) == pMap->aPTs[i].HCPhysPaePT0
323 || !PGMMODE_WITH_PAGING(PGMGetGuestMode(pVCpu)),
324 ("%RX64 vs %RX64\n", pShwPaePd->a[iPaePde+1].u & X86_PDE_PAE_PG_MASK, pMap->aPTs[i].HCPhysPaePT0));
325 Assert(pShwPaePd->a[iPaePde+1].u & PGM_PDFLAGS_MAPPING);
326 AssertFatalMsg( (pShwPaePd->a[iPaePde+1].u & X86_PDE_PAE_PG_MASK) == pMap->aPTs[i].HCPhysPaePT1
327 || !PGMMODE_WITH_PAGING(PGMGetGuestMode(pVCpu)),
328 ("%RX64 vs %RX64\n", pShwPaePd->a[iPaePde+1].u & X86_PDE_PAE_PG_MASK, pMap->aPTs[i].HCPhysPaePT1));
329 }
330#endif
331
332 /*
333 * Insert our first PT, freeing anything we might be replacing unless it's a mapping (i.e. us).
334 */
335 Assert( (pShwPaePd->a[iPaePde].u & (X86_PDE_P | PGM_PDFLAGS_MAPPING)) != (X86_PDE_P | PGM_PDFLAGS_MAPPING)
336 || (pShwPaePd->a[iPaePde].u & X86_PDE_PAE_PG_MASK) == pMap->aPTs[i].HCPhysPaePT0);
337 if ( pShwPaePd->a[iPaePde].n.u1Present
338 && !(pShwPaePd->a[iPaePde].u & PGM_PDFLAGS_MAPPING))
339 {
340 Assert(!(pShwPaePd->a[iPaePde].u & PGM_PDFLAGS_MAPPING));
341 pgmPoolFree(pVM, pShwPaePd->a[iPaePde].u & X86_PDE_PAE_PG_MASK, pPoolPagePd->idx, iPaePde);
342 }
343 pShwPaePd->a[iPaePde].u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US
344 | pMap->aPTs[i].HCPhysPaePT0;
345
346 /* 2nd 2 MB PDE of the 4 MB region, same as above. */
347 iPaePde++;
348 AssertFatal(iPaePde < 512);
349 Assert( (pShwPaePd->a[iPaePde].u & (X86_PDE_P | PGM_PDFLAGS_MAPPING)) != (X86_PDE_P | PGM_PDFLAGS_MAPPING)
350 || (pShwPaePd->a[iPaePde].u & X86_PDE_PAE_PG_MASK) == pMap->aPTs[i].HCPhysPaePT1);
351 if ( pShwPaePd->a[iPaePde].n.u1Present
352 && !(pShwPaePd->a[iPaePde].u & PGM_PDFLAGS_MAPPING))
353 pgmPoolFree(pVM, pShwPaePd->a[iPaePde].u & X86_PDE_PG_MASK, pPoolPagePd->idx, iPaePde);
354 pShwPaePd->a[iPaePde].u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US
355 | pMap->aPTs[i].HCPhysPaePT1;
356
357 /*
358 * Set the PGM_PDFLAGS_MAPPING flag in the page directory pointer entry. (legacy PAE guest mode)
359 */
360 pShwPdpt->a[iPdPt].u |= PGM_PLXFLAGS_MAPPING;
361
362#ifdef IN_RC
363 /* Unlock dynamic mappings again. */
364 PGMDynUnlockHCPage(pVM, (uint8_t *)pShwPaePd);
365 PGMDynUnlockHCPage(pVM, (uint8_t *)pShwPdpt);
366#endif
367 break;
368 }
369
370 default:
371 AssertFailed();
372 break;
373 }
374 }
375}
376
377
378/**
379 * Clears all PDEs involved with the mapping in the shadow page table.
380 *
381 * @param pVM The VM handle.
382 * @param pShwPageCR3 CR3 root page
383 * @param pMap Pointer to the mapping in question.
384 * @param iOldPDE The index of the 32-bit PDE corresponding to the base of the mapping.
385 * @param fDeactivateCR3 Set if it's pgmMapDeactivateCR3 calling.
386 */
387void pgmMapClearShadowPDEs(PVM pVM, PPGMPOOLPAGE pShwPageCR3, PPGMMAPPING pMap, unsigned iOldPDE, bool fDeactivateCR3)
388{
389 Log(("pgmMapClearShadowPDEs: old pde %x (cPTs=%x) (mappings enabled %d) fDeactivateCR3=%RTbool\n", iOldPDE, pMap->cPTs, pgmMapAreMappingsEnabled(&pVM->pgm.s), fDeactivateCR3));
390
391 /*
392 * Skip this if disabled or if it doesn't apply.
393 */
394 if ( !pgmMapAreMappingsEnabled(&pVM->pgm.s)
395 || pVM->cCpus > 1)
396 return;
397
398 Assert(pShwPageCR3);
399
400 /* This only applies to raw mode where we only support 1 VCPU. */
401 PVMCPU pVCpu = VMMGetCpu0(pVM);
402# ifdef IN_RC
403 Assert(pShwPageCR3 != pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
404# endif
405
406 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
407
408 PX86PDPT pCurrentShwPdpt = NULL;
409 if ( PGMGetGuestMode(pVCpu) >= PGMMODE_PAE
410 && pShwPageCR3 != pVCpu->pgm.s.CTX_SUFF(pShwPageCR3))
411 {
412 pCurrentShwPdpt = pgmShwGetPaePDPTPtr(&pVCpu->pgm.s);
413#ifdef IN_RC /* Lock mapping to prevent it from being reused (currently not possible). */
414 if (pCurrentShwPdpt)
415 PGMDynLockHCPage(pVM, (uint8_t *)pCurrentShwPdpt);
416#endif
417 }
418
419 unsigned i = pMap->cPTs;
420 PGMMODE enmShadowMode = PGMGetShadowMode(pVCpu);
421
422 iOldPDE += i;
423 while (i-- > 0)
424 {
425 iOldPDE--;
426
427 switch(enmShadowMode)
428 {
429 case PGMMODE_32_BIT:
430 {
431 PX86PD pShw32BitPd = (PX86PD)PGMPOOL_PAGE_2_PTR_BY_PGM(&pVM->pgm.s, pShwPageCR3);
432 AssertFatal(pShw32BitPd);
433
434 Assert(!pShw32BitPd->a[iOldPDE].n.u1Present || (pShw32BitPd->a[iOldPDE].u & PGM_PDFLAGS_MAPPING));
435 pShw32BitPd->a[iOldPDE].u = 0;
436 break;
437 }
438
439 case PGMMODE_PAE:
440 case PGMMODE_PAE_NX:
441 {
442 const unsigned iPdpt = iOldPDE / 256; /* iOldPDE * 2 / 512; iOldPDE is in 4 MB pages */
443 unsigned iPaePde = iOldPDE * 2 % 512;
444 PX86PDPT pShwPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR_BY_PGM(&pVM->pgm.s, pShwPageCR3);
445 PX86PDPAE pShwPaePd = pgmShwGetPaePDPtr(&pVCpu->pgm.s, pShwPdpt, (iPdpt << X86_PDPT_SHIFT));
446
447 /*
448 * Clear the PGM_PDFLAGS_MAPPING flag for the page directory pointer entry. (legacy PAE guest mode)
449 */
450 if (fDeactivateCR3)
451 pShwPdpt->a[iPdpt].u &= ~PGM_PLXFLAGS_MAPPING;
452 else if (pShwPdpt->a[iPdpt].u & PGM_PLXFLAGS_MAPPING)
453 {
454 /* See if there are any other mappings here. This is suboptimal code. */
455 pShwPdpt->a[iPdpt].u &= ~PGM_PLXFLAGS_MAPPING;
456 for (PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings); pCur; pCur = pCur->CTX_SUFF(pNext))
457 if ( pCur != pMap
458 && ( (pCur->GCPtr >> X86_PDPT_SHIFT) == iPdpt
459 || (pCur->GCPtrLast >> X86_PDPT_SHIFT) == iPdpt))
460 {
461 pShwPdpt->a[iPdpt].u |= PGM_PLXFLAGS_MAPPING;
462 break;
463 }
464 }
465
466 /*
467 * If the page directory of the old CR3 is reused in the new one, then don't
468 * clear the hypervisor mappings.
469 */
470 if ( pCurrentShwPdpt
471 && (pCurrentShwPdpt->a[iPdpt].u & X86_PDPE_PG_MASK) == (pShwPdpt->a[iPdpt].u & X86_PDPE_PG_MASK) )
472 {
473 LogFlow(("pgmMapClearShadowPDEs: Pdpe %d reused -> don't clear hypervisor mappings!\n", iPdpt));
474 break;
475 }
476
477 /*
478 * Clear the mappings in the PD.
479 */
480 AssertFatal(pShwPaePd);
481 Assert(!pShwPaePd->a[iPaePde].n.u1Present || (pShwPaePd->a[iPaePde].u & PGM_PDFLAGS_MAPPING));
482 pShwPaePd->a[iPaePde].u = 0;
483
484 iPaePde++;
485 AssertFatal(iPaePde < 512);
486 Assert(!pShwPaePd->a[iPaePde].n.u1Present || (pShwPaePd->a[iPaePde].u & PGM_PDFLAGS_MAPPING));
487 pShwPaePd->a[iPaePde].u = 0;
488
489 /*
490 * Unlock the shadow pool PD page if the PDPTE no longer holds any mappings.
491 */
492 if ( fDeactivateCR3
493 || !(pShwPdpt->a[iPdpt].u & PGM_PLXFLAGS_MAPPING))
494 {
495 PPGMPOOLPAGE pPoolPagePd = pgmPoolGetPage(pPool, pShwPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
496 AssertFatal(pPoolPagePd);
497 if (pgmPoolIsPageLocked(&pVM->pgm.s, pPoolPagePd))
498 pgmPoolUnlockPage(pPool, pPoolPagePd);
499 }
500 break;
501 }
502
503 default:
504 AssertFailed();
505 break;
506 }
507 }
508#ifdef IN_RC
509 /* Unlock dynamic mappings again. */
510 if (pCurrentShwPdpt)
511 PGMDynUnlockHCPage(pVM, (uint8_t *)pCurrentShwPdpt);
512#endif
513}
514#endif /* !IN_RING0 */
515
516#if defined(VBOX_STRICT) && !defined(IN_RING0)
517/**
518 * Clears all PDEs involved with the mapping in the shadow page table.
519 *
520 * @param pVM The VM handle.
521 * @param pVCpu The VMCPU handle.
522 * @param pShwPageCR3 CR3 root page
523 * @param pMap Pointer to the mapping in question.
524 * @param iPDE The index of the 32-bit PDE corresponding to the base of the mapping.
525 */
526static void pgmMapCheckShadowPDEs(PVM pVM, PVMCPU pVCpu, PPGMPOOLPAGE pShwPageCR3, PPGMMAPPING pMap, unsigned iPDE)
527{
528 Assert(pShwPageCR3);
529
530 uint32_t i = pMap->cPTs;
531 PGMMODE enmShadowMode = PGMGetShadowMode(pVCpu);
532 PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool);
533
534 iPDE += i;
535 while (i-- > 0)
536 {
537 iPDE--;
538
539 switch (enmShadowMode)
540 {
541 case PGMMODE_32_BIT:
542 {
543 PCX86PD pShw32BitPd = (PCX86PD)PGMPOOL_PAGE_2_PTR_BY_PGM(&pVM->pgm.s, pShwPageCR3);
544 AssertFatal(pShw32BitPd);
545
546 AssertMsg(pShw32BitPd->a[iPDE].u == (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT),
547 ("Expected %x vs %x; iPDE=%#x %RGv %s\n",
548 pShw32BitPd->a[iPDE].u, (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT),
549 iPDE, pMap->GCPtr, R3STRING(pMap->pszDesc) ));
550 break;
551 }
552
553 case PGMMODE_PAE:
554 case PGMMODE_PAE_NX:
555 {
556 const unsigned iPdpt = iPDE / 256; /* iPDE * 2 / 512; iPDE is in 4 MB pages */
557 unsigned iPaePDE = iPDE * 2 % 512;
558 PX86PDPT pShwPdpt = (PX86PDPT)PGMPOOL_PAGE_2_PTR_BY_PGM(&pVM->pgm.s, pShwPageCR3);
559 PCX86PDPAE pShwPaePd = pgmShwGetPaePDPtr(&pVCpu->pgm.s, pShwPdpt, iPdpt << X86_PDPT_SHIFT);
560 AssertFatal(pShwPaePd);
561
562 AssertMsg(pShwPaePd->a[iPaePDE].u == (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0),
563 ("Expected %RX64 vs %RX64; iPDE=%#x iPdpt=%#x iPaePDE=%#x %RGv %s\n",
564 pShwPaePd->a[iPaePDE].u, (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0),
565 iPDE, iPdpt, iPaePDE, pMap->GCPtr, R3STRING(pMap->pszDesc) ));
566
567 iPaePDE++;
568 AssertFatal(iPaePDE < 512);
569
570 AssertMsg(pShwPaePd->a[iPaePDE].u == (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1),
571 ("Expected %RX64 vs %RX64; iPDE=%#x iPdpt=%#x iPaePDE=%#x %RGv %s\n",
572 pShwPaePd->a[iPaePDE].u, (PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1),
573 iPDE, iPdpt, iPaePDE, pMap->GCPtr, R3STRING(pMap->pszDesc) ));
574
575 AssertMsg(pShwPdpt->a[iPdpt].u & PGM_PLXFLAGS_MAPPING,
576 ("%RX64; iPdpt=%#x iPDE=%#x iPaePDE=%#x %RGv %s\n",
577 pShwPdpt->a[iPdpt].u,
578 iPDE, iPdpt, iPaePDE, pMap->GCPtr, R3STRING(pMap->pszDesc) ));
579
580 PCPGMPOOLPAGE pPoolPagePd = pgmPoolGetPage(pPool, pShwPdpt->a[iPdpt].u & X86_PDPE_PG_MASK);
581 AssertFatal(pPoolPagePd);
582 AssertMsg(pPoolPagePd->cLocked, (".idx=%d .type=%d\n", pPoolPagePd->idx, pPoolPagePd->enmKind));
583 break;
584 }
585
586 default:
587 AssertFailed();
588 break;
589 }
590 }
591}
592
593
594/**
595 * Check the hypervisor mappings in the active CR3.
596 *
597 * @param pVM The virtual machine.
598 */
599VMMDECL(void) PGMMapCheck(PVM pVM)
600{
601 /*
602 * Can skip this if mappings are disabled.
603 */
604 if (!pgmMapAreMappingsEnabled(&pVM->pgm.s))
605 return;
606
607 /* This only applies to raw mode where we only support 1 VCPU. */
608 Assert(pVM->cCpus == 1);
609 PVMCPU pVCpu = VMMGetCpu0(pVM);
610 Assert(pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
611
612 /*
613 * Iterate mappings.
614 */
615 pgmLock(pVM); /* to avoid assertions */
616 for (PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings); pCur; pCur = pCur->CTX_SUFF(pNext))
617 {
618 unsigned iPDE = pCur->GCPtr >> X86_PD_SHIFT;
619 pgmMapCheckShadowPDEs(pVM, pVCpu, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3), pCur, iPDE);
620 }
621 pgmUnlock(pVM);
622}
623#endif /* defined(VBOX_STRICT) && !defined(IN_RING0) */
624
625#ifndef IN_RING0
626
627/**
628 * Apply the hypervisor mappings to the active CR3.
629 *
630 * @returns VBox status.
631 * @param pVM The virtual machine.
632 * @param pShwPageCR3 CR3 root page
633 */
634int pgmMapActivateCR3(PVM pVM, PPGMPOOLPAGE pShwPageCR3)
635{
636 /*
637 * Skip this if disabled or if it doesn't apply.
638 */
639 if ( !pgmMapAreMappingsEnabled(&pVM->pgm.s)
640 || pVM->cCpus > 1)
641 return VINF_SUCCESS;
642
643 /* Note! This might not be logged successfully in RC because we usually
644 cannot flush the log at this point. */
645 Log4(("pgmMapActivateCR3: fixed mappings=%RTbool idxShwPageCR3=%#x\n", pVM->pgm.s.fMappingsFixed, pShwPageCR3 ? pShwPageCR3->idx : NIL_PGMPOOL_IDX));
646
647#ifdef VBOX_STRICT
648 PVMCPU pVCpu = VMMGetCpu0(pVM);
649 Assert(pShwPageCR3 && pShwPageCR3 == pVCpu->pgm.s.CTX_SUFF(pShwPageCR3));
650#endif
651
652 /*
653 * Iterate mappings.
654 */
655 for (PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings); pCur; pCur = pCur->CTX_SUFF(pNext))
656 {
657 unsigned iPDE = pCur->GCPtr >> X86_PD_SHIFT;
658 pgmMapSetShadowPDEs(pVM, pCur, iPDE);
659 }
660 return VINF_SUCCESS;
661}
662
663
664/**
665 * Remove the hypervisor mappings from the specified CR3
666 *
667 * @returns VBox status.
668 * @param pVM The virtual machine.
669 * @param pShwPageCR3 CR3 root page
670 */
671int pgmMapDeactivateCR3(PVM pVM, PPGMPOOLPAGE pShwPageCR3)
672{
673 /*
674 * Skip this if disabled or if it doesn't apply.
675 */
676 if ( !pgmMapAreMappingsEnabled(&pVM->pgm.s)
677 || pVM->cCpus > 1)
678 return VINF_SUCCESS;
679
680 Assert(pShwPageCR3);
681 Log4(("pgmMapDeactivateCR3: fixed mappings=%d idxShwPageCR3=%#x\n", pVM->pgm.s.fMappingsFixed, pShwPageCR3 ? pShwPageCR3->idx : NIL_PGMPOOL_IDX));
682
683 /*
684 * Iterate mappings.
685 */
686 for (PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings); pCur; pCur = pCur->CTX_SUFF(pNext))
687 {
688 unsigned iPDE = pCur->GCPtr >> X86_PD_SHIFT;
689 pgmMapClearShadowPDEs(pVM, pShwPageCR3, pCur, iPDE, true /*fDeactivateCR3*/);
690 }
691 return VINF_SUCCESS;
692}
693
694
695/**
696 * Checks guest PD for conflicts with VMM GC mappings.
697 *
698 * @returns true if conflict detected.
699 * @returns false if not.
700 * @param pVM The virtual machine.
701 */
702VMMDECL(bool) PGMMapHasConflicts(PVM pVM)
703{
704 /*
705 * Can skip this if mappings are safely fixed.
706 */
707 if (!pgmMapAreMappingsFloating(&pVM->pgm.s))
708 return false;
709
710 Assert(pVM->cCpus == 1);
711
712 /* This only applies to raw mode where we only support 1 VCPU. */
713 PVMCPU pVCpu = &pVM->aCpus[0];
714
715 PGMMODE const enmGuestMode = PGMGetGuestMode(pVCpu);
716 Assert(enmGuestMode <= PGMMODE_PAE_NX);
717
718 /*
719 * Iterate mappings.
720 */
721 if (enmGuestMode == PGMMODE_32_BIT)
722 {
723 /*
724 * Resolve the page directory.
725 */
726 PX86PD pPD = pgmGstGet32bitPDPtr(&pVCpu->pgm.s);
727 Assert(pPD);
728
729 for (PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings); pCur; pCur = pCur->CTX_SUFF(pNext))
730 {
731 unsigned iPDE = pCur->GCPtr >> X86_PD_SHIFT;
732 unsigned iPT = pCur->cPTs;
733 while (iPT-- > 0)
734 if ( pPD->a[iPDE + iPT].n.u1Present /** @todo PGMGstGetPDE. */
735 && (pVM->fRawR0Enabled || pPD->a[iPDE + iPT].n.u1User))
736 {
737 STAM_COUNTER_INC(&pVM->pgm.s.StatR3DetectedConflicts);
738
739#ifdef IN_RING3
740 Log(("PGMHasMappingConflicts: Conflict was detected at %08RX32 for mapping %s (32 bits)\n"
741 " iPDE=%#x iPT=%#x PDE=%RGp.\n",
742 (iPT + iPDE) << X86_PD_SHIFT, pCur->pszDesc,
743 iPDE, iPT, pPD->a[iPDE + iPT].au32[0]));
744#else
745 Log(("PGMHasMappingConflicts: Conflict was detected at %08RX32 for mapping (32 bits)\n"
746 " iPDE=%#x iPT=%#x PDE=%RGp.\n",
747 (iPT + iPDE) << X86_PD_SHIFT,
748 iPDE, iPT, pPD->a[iPDE + iPT].au32[0]));
749#endif
750 return true;
751 }
752 }
753 }
754 else if ( enmGuestMode == PGMMODE_PAE
755 || enmGuestMode == PGMMODE_PAE_NX)
756 {
757 for (PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings); pCur; pCur = pCur->CTX_SUFF(pNext))
758 {
759 RTGCPTR GCPtr = pCur->GCPtr;
760
761 unsigned iPT = pCur->cb >> X86_PD_PAE_SHIFT;
762 while (iPT-- > 0)
763 {
764 X86PDEPAE Pde = pgmGstGetPaePDE(&pVCpu->pgm.s, GCPtr);
765
766 if ( Pde.n.u1Present
767 && (pVM->fRawR0Enabled || Pde.n.u1User))
768 {
769 STAM_COUNTER_INC(&pVM->pgm.s.StatR3DetectedConflicts);
770#ifdef IN_RING3
771 Log(("PGMHasMappingConflicts: Conflict was detected at %RGv for mapping %s (PAE)\n"
772 " PDE=%016RX64.\n",
773 GCPtr, pCur->pszDesc, Pde.u));
774#else
775 Log(("PGMHasMappingConflicts: Conflict was detected at %RGv for mapping (PAE)\n"
776 " PDE=%016RX64.\n",
777 GCPtr, Pde.u));
778#endif
779 return true;
780 }
781 GCPtr += (1 << X86_PD_PAE_SHIFT);
782 }
783 }
784 }
785 else
786 AssertFailed();
787
788 return false;
789}
790
791
792/**
793 * Checks and resolves (ring 3 only) guest conflicts with the guest mappings.
794 *
795 * @returns VBox status.
796 * @param pVM The virtual machine.
797 */
798int pgmMapResolveConflicts(PVM pVM)
799{
800 /* The caller is expected to check these two conditions. */
801 Assert(!pVM->pgm.s.fMappingsFixed);
802 Assert(!pVM->pgm.s.fMappingsDisabled);
803
804 /* This only applies to raw mode where we only support 1 VCPU. */
805 Assert(pVM->cCpus == 1);
806 PVMCPU pVCpu = &pVM->aCpus[0];
807 PGMMODE const enmGuestMode = PGMGetGuestMode(pVCpu);
808 Assert(enmGuestMode <= PGMMODE_PAE_NX);
809
810 if (enmGuestMode == PGMMODE_32_BIT)
811 {
812 /*
813 * Resolve the page directory.
814 */
815 PX86PD pPD = pgmGstGet32bitPDPtr(&pVCpu->pgm.s);
816 Assert(pPD);
817
818 /*
819 * Iterate mappings.
820 */
821 for (PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings); pCur; )
822 {
823 PPGMMAPPING pNext = pCur->CTX_SUFF(pNext);
824 unsigned iPDE = pCur->GCPtr >> X86_PD_SHIFT;
825 unsigned iPT = pCur->cPTs;
826 while (iPT-- > 0)
827 {
828 if ( pPD->a[iPDE + iPT].n.u1Present /** @todo PGMGstGetPDE. */
829 && ( pVM->fRawR0Enabled
830 || pPD->a[iPDE + iPT].n.u1User))
831 {
832 STAM_COUNTER_INC(&pVM->pgm.s.StatR3DetectedConflicts);
833
834#ifdef IN_RING3
835 Log(("PGMHasMappingConflicts: Conflict was detected at %08RX32 for mapping %s (32 bits)\n"
836 " iPDE=%#x iPT=%#x PDE=%RGp.\n",
837 (iPT + iPDE) << X86_PD_SHIFT, pCur->pszDesc,
838 iPDE, iPT, pPD->a[iPDE + iPT].au32[0]));
839 int rc = pgmR3SyncPTResolveConflict(pVM, pCur, pPD, iPDE << X86_PD_SHIFT);
840 AssertRCReturn(rc, rc);
841 break;
842#else
843 Log(("PGMHasMappingConflicts: Conflict was detected at %08RX32 for mapping (32 bits)\n"
844 " iPDE=%#x iPT=%#x PDE=%RGp.\n",
845 (iPT + iPDE) << X86_PD_SHIFT,
846 iPDE, iPT, pPD->a[iPDE + iPT].au32[0]));
847 return VINF_PGM_SYNC_CR3;
848#endif
849 }
850 }
851 pCur = pNext;
852 }
853 }
854 else if ( enmGuestMode == PGMMODE_PAE
855 || enmGuestMode == PGMMODE_PAE_NX)
856 {
857 /*
858 * Iterate mappings.
859 */
860 for (PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings); pCur;)
861 {
862 PPGMMAPPING pNext = pCur->CTX_SUFF(pNext);
863 RTGCPTR GCPtr = pCur->GCPtr;
864 unsigned iPT = pCur->cb >> X86_PD_PAE_SHIFT;
865 while (iPT-- > 0)
866 {
867 X86PDEPAE Pde = pgmGstGetPaePDE(&pVCpu->pgm.s, GCPtr);
868
869 if ( Pde.n.u1Present
870 && (pVM->fRawR0Enabled || Pde.n.u1User))
871 {
872 STAM_COUNTER_INC(&pVM->pgm.s.StatR3DetectedConflicts);
873#ifdef IN_RING3
874 Log(("PGMHasMappingConflicts: Conflict was detected at %RGv for mapping %s (PAE)\n"
875 " PDE=%016RX64.\n",
876 GCPtr, pCur->pszDesc, Pde.u));
877 int rc = pgmR3SyncPTResolveConflictPAE(pVM, pCur, pCur->GCPtr);
878 AssertRCReturn(rc, rc);
879 break;
880#else
881 Log(("PGMHasMappingConflicts: Conflict was detected at %RGv for mapping (PAE)\n"
882 " PDE=%016RX64.\n",
883 GCPtr, Pde.u));
884 return VINF_PGM_SYNC_CR3;
885#endif
886 }
887 GCPtr += (1 << X86_PD_PAE_SHIFT);
888 }
889 pCur = pNext;
890 }
891 }
892 else
893 AssertFailed();
894
895 Assert(!PGMMapHasConflicts(pVM));
896 return VINF_SUCCESS;
897}
898
899#endif /* IN_RING0 */
900
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