VirtualBox

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

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

PGM: Split out the inlined code from PGMInternal.h and into PGMInline.h so we can drop all the &pVM->pgm.s and &pVCpu->pgm.s stuff.

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