VirtualBox

source: vbox/trunk/src/VBox/VMM/PGMMap.cpp@ 14981

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

Switcher fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 46.7 KB
Line 
1/* $Id: PGMMap.cpp 14979 2008-12-04 13:14:29Z vboxsync $ */
2/** @file
3 * PGM - Page Manager, Guest Context Mappings.
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/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_PGM
27#include <VBox/dbgf.h>
28#include <VBox/pgm.h>
29#include "PGMInternal.h"
30#include <VBox/vm.h>
31
32#include <VBox/log.h>
33#include <VBox/err.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/string.h>
37
38
39/*******************************************************************************
40* Internal Functions *
41*******************************************************************************/
42static void pgmR3MapClearPDEs(PPGM pPGM, PPGMMAPPING pMap, unsigned iOldPDE);
43static void pgmR3MapSetPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iNewPDE);
44static int pgmR3MapIntermediateCheckOne(PVM pVM, uintptr_t uAddress, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault);
45static void pgmR3MapIntermediateDoOne(PVM pVM, uintptr_t uAddress, RTHCPHYS HCPhys, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault);
46
47
48
49/**
50 * Creates a page table based mapping in GC.
51 *
52 * @returns VBox status code.
53 * @param pVM VM Handle.
54 * @param GCPtr Virtual Address. (Page table aligned!)
55 * @param cb Size of the range. Must be a 4MB aligned!
56 * @param pfnRelocate Relocation callback function.
57 * @param pvUser User argument to the callback.
58 * @param pszDesc Pointer to description string. This must not be freed.
59 */
60VMMR3DECL(int) PGMR3MapPT(PVM pVM, RTGCPTR GCPtr, uint32_t cb, PFNPGMRELOCATE pfnRelocate, void *pvUser, const char *pszDesc)
61{
62 LogFlow(("PGMR3MapPT: GCPtr=%#x cb=%d pfnRelocate=%p pvUser=%p pszDesc=%s\n", GCPtr, cb, pfnRelocate, pvUser, pszDesc));
63 AssertMsg(pVM->pgm.s.pInterPD && pVM->pgm.s.pShw32BitPdR3, ("Paging isn't initialized, init order problems!\n"));
64
65 /*
66 * Validate input.
67 */
68 if (cb < _2M || cb > 64 * _1M)
69 {
70 AssertMsgFailed(("Serious? cb=%d\n", cb));
71 return VERR_INVALID_PARAMETER;
72 }
73 cb = RT_ALIGN_32(cb, _4M);
74 RTGCPTR GCPtrLast = GCPtr + cb - 1;
75 if (GCPtrLast < GCPtr)
76 {
77 AssertMsgFailed(("Range wraps! GCPtr=%x GCPtrLast=%x\n", GCPtr, GCPtrLast));
78 return VERR_INVALID_PARAMETER;
79 }
80 if (pVM->pgm.s.fMappingsFixed)
81 {
82 AssertMsgFailed(("Mappings are fixed! It's not possible to add new mappings at this time!\n"));
83 return VERR_PGM_MAPPINGS_FIXED;
84 }
85 if (!pfnRelocate)
86 {
87 AssertMsgFailed(("Callback is required\n"));
88 return VERR_INVALID_PARAMETER;
89 }
90
91 /*
92 * Find list location.
93 */
94 PPGMMAPPING pPrev = NULL;
95 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
96 while (pCur)
97 {
98 if (pCur->GCPtrLast >= GCPtr && pCur->GCPtr <= GCPtrLast)
99 {
100 AssertMsgFailed(("Address is already in use by %s. req %#x-%#x take %#x-%#x\n",
101 pCur->pszDesc, GCPtr, GCPtrLast, pCur->GCPtr, pCur->GCPtrLast));
102 LogRel(("VERR_PGM_MAPPING_CONFLICT: Address is already in use by %s. req %#x-%#x take %#x-%#x\n",
103 pCur->pszDesc, GCPtr, GCPtrLast, pCur->GCPtr, pCur->GCPtrLast));
104 return VERR_PGM_MAPPING_CONFLICT;
105 }
106 if (pCur->GCPtr > GCPtr)
107 break;
108 pPrev = pCur;
109 pCur = pCur->pNextR3;
110 }
111
112 /*
113 * Check for conflicts with intermediate mappings.
114 */
115 const unsigned iPageDir = GCPtr >> X86_PD_SHIFT;
116 const unsigned cPTs = cb >> X86_PD_SHIFT;
117 unsigned i;
118 for (i = 0; i < cPTs; i++)
119 {
120 if (pVM->pgm.s.pInterPD->a[iPageDir + i].n.u1Present)
121 {
122 AssertMsgFailed(("Address %#x is already in use by an intermediate mapping.\n", GCPtr + (i << PAGE_SHIFT)));
123 LogRel(("VERR_PGM_MAPPING_CONFLICT: Address %#x is already in use by an intermediate mapping.\n", GCPtr + (i << PAGE_SHIFT)));
124 return VERR_PGM_MAPPING_CONFLICT;
125 }
126 }
127 /** @todo AMD64: add check in PAE structures too, so we can remove all the 32-Bit paging stuff there. */
128
129 /*
130 * Allocate and initialize the new list node.
131 */
132 PPGMMAPPING pNew;
133 int rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMMAPPING, aPTs[cPTs]), 0, MM_TAG_PGM, (void **)&pNew);
134 if (RT_FAILURE(rc))
135 return rc;
136 pNew->GCPtr = GCPtr;
137 pNew->GCPtrLast = GCPtrLast;
138 pNew->cb = cb;
139 pNew->pszDesc = pszDesc;
140 pNew->pfnRelocate = pfnRelocate;
141 pNew->pvUser = pvUser;
142 pNew->cPTs = cPTs;
143
144 /*
145 * Allocate page tables and insert them into the page directories.
146 * (One 32-bit PT and two PAE PTs.)
147 */
148 uint8_t *pbPTs;
149 rc = MMHyperAlloc(pVM, PAGE_SIZE * 3 * cPTs, PAGE_SIZE, MM_TAG_PGM, (void **)&pbPTs);
150 if (RT_FAILURE(rc))
151 {
152 MMHyperFree(pVM, pNew);
153 return VERR_NO_MEMORY;
154 }
155
156 /*
157 * Init the page tables and insert them into the page directories.
158 */
159 Log4(("PGMR3MapPT: GCPtr=%RGv cPTs=%u pbPTs=%p\n", GCPtr, cPTs, pbPTs));
160 for (i = 0; i < cPTs; i++)
161 {
162 /*
163 * 32-bit.
164 */
165 pNew->aPTs[i].pPTR3 = (PX86PT)pbPTs;
166 pNew->aPTs[i].pPTRC = MMHyperR3ToRC(pVM, pNew->aPTs[i].pPTR3);
167 pNew->aPTs[i].pPTR0 = MMHyperR3ToR0(pVM, pNew->aPTs[i].pPTR3);
168 pNew->aPTs[i].HCPhysPT = MMR3HyperHCVirt2HCPhys(pVM, pNew->aPTs[i].pPTR3);
169 pbPTs += PAGE_SIZE;
170 Log4(("PGMR3MapPT: i=%d: pPTR3=%RHv pPTRC=%RRv pPRTR0=%RHv HCPhysPT=%RHp\n",
171 i, pNew->aPTs[i].pPTR3, pNew->aPTs[i].pPTRC, pNew->aPTs[i].pPTR0, pNew->aPTs[i].HCPhysPT));
172
173 /*
174 * PAE.
175 */
176 pNew->aPTs[i].HCPhysPaePT0 = MMR3HyperHCVirt2HCPhys(pVM, pbPTs);
177 pNew->aPTs[i].HCPhysPaePT1 = MMR3HyperHCVirt2HCPhys(pVM, pbPTs + PAGE_SIZE);
178 pNew->aPTs[i].paPaePTsR3 = (PX86PTPAE)pbPTs;
179 pNew->aPTs[i].paPaePTsRC = MMHyperR3ToRC(pVM, pbPTs);
180 pNew->aPTs[i].paPaePTsR0 = MMHyperR3ToR0(pVM, pbPTs);
181 pbPTs += PAGE_SIZE * 2;
182 Log4(("PGMR3MapPT: i=%d: paPaePTsR#=%RHv paPaePTsRC=%RRv paPaePTsR#=%RHv HCPhysPaePT0=%RHp HCPhysPaePT1=%RHp\n",
183 i, pNew->aPTs[i].paPaePTsR3, pNew->aPTs[i].paPaePTsRC, pNew->aPTs[i].paPaePTsR0, pNew->aPTs[i].HCPhysPaePT0, pNew->aPTs[i].HCPhysPaePT1));
184 }
185 pgmR3MapSetPDEs(pVM, pNew, iPageDir);
186
187 /*
188 * Insert the new mapping.
189 */
190 pNew->pNextR3 = pCur;
191 pNew->pNextRC = pCur ? MMHyperR3ToRC(pVM, pCur) : NIL_RTRCPTR;
192 pNew->pNextR0 = pCur ? MMHyperR3ToR0(pVM, pCur) : NIL_RTR0PTR;
193 if (pPrev)
194 {
195 pPrev->pNextR3 = pNew;
196 pPrev->pNextRC = MMHyperR3ToRC(pVM, pNew);
197 pPrev->pNextR0 = MMHyperR3ToR0(pVM, pNew);
198 }
199 else
200 {
201 pVM->pgm.s.pMappingsR3 = pNew;
202 pVM->pgm.s.pMappingsRC = MMHyperR3ToRC(pVM, pNew);
203 pVM->pgm.s.pMappingsR0 = MMHyperR3ToR0(pVM, pNew);
204 }
205
206 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
207 return VINF_SUCCESS;
208}
209
210
211/**
212 * Removes a page table based mapping.
213 *
214 * @returns VBox status code.
215 * @param pVM VM Handle.
216 * @param GCPtr Virtual Address. (Page table aligned!)
217 */
218VMMR3DECL(int) PGMR3UnmapPT(PVM pVM, RTGCPTR GCPtr)
219{
220 LogFlow(("PGMR3UnmapPT: GCPtr=%#x\n", GCPtr));
221
222 /*
223 * Find it.
224 */
225 PPGMMAPPING pPrev = NULL;
226 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
227 while (pCur)
228 {
229 if (pCur->GCPtr == GCPtr)
230 {
231 /*
232 * Unlink it.
233 */
234 if (pPrev)
235 {
236 pPrev->pNextR3 = pCur->pNextR3;
237 pPrev->pNextRC = pCur->pNextRC;
238 pPrev->pNextR0 = pCur->pNextR0;
239 }
240 else
241 {
242 pVM->pgm.s.pMappingsR3 = pCur->pNextR3;
243 pVM->pgm.s.pMappingsRC = pCur->pNextRC;
244 pVM->pgm.s.pMappingsR0 = pCur->pNextR0;
245 }
246
247 /*
248 * Free the page table memory, clear page directory entries
249 * and free the page tables and node memory.
250 */
251 MMHyperFree(pVM, pCur->aPTs[0].pPTR3);
252 pgmR3MapClearPDEs(&pVM->pgm.s, pCur, pCur->GCPtr >> X86_PD_SHIFT);
253 MMHyperFree(pVM, pCur);
254
255 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
256 return VINF_SUCCESS;
257 }
258
259 /* done? */
260 if (pCur->GCPtr > GCPtr)
261 break;
262
263 /* next */
264 pPrev = pCur;
265 pCur = pCur->pNextR3;
266 }
267
268 AssertMsgFailed(("No mapping for %#x found!\n", GCPtr));
269 return VERR_INVALID_PARAMETER;
270}
271
272
273/**
274 * Gets the size of the current guest mappings if they were to be
275 * put next to oneanother.
276 *
277 * @returns VBox status code.
278 * @param pVM The VM.
279 * @param pcb Where to store the size.
280 */
281VMMR3DECL(int) PGMR3MappingsSize(PVM pVM, uint32_t *pcb)
282{
283 RTGCPTR cb = 0;
284 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
285 cb += pCur->cb;
286
287 *pcb = cb;
288 AssertReturn(*pcb == cb, VERR_NUMBER_TOO_BIG);
289 Log(("PGMR3MappingsSize: return %d (%#x) bytes\n", cb, cb));
290 return VINF_SUCCESS;
291}
292
293
294/**
295 * Fixes the guest context mappings in a range reserved from the Guest OS.
296 *
297 * @returns VBox status code.
298 * @param pVM The VM.
299 * @param GCPtrBase The address of the reserved range of guest memory.
300 * @param cb The size of the range starting at GCPtrBase.
301 */
302VMMR3DECL(int) PGMR3MappingsFix(PVM pVM, RTGCPTR GCPtrBase, uint32_t cb)
303{
304 Log(("PGMR3MappingsFix: GCPtrBase=%#x cb=%#x\n", GCPtrBase, cb));
305
306 /* Ignore the additions mapping fix call in VT-x/AMD-V. */
307 if ( pVM->pgm.s.fMappingsFixed
308 && HWACCMR3IsActive(pVM))
309 return VINF_SUCCESS;
310
311 /*
312 * This is all or nothing at all. So, a tiny bit of paranoia first.
313 */
314 if (GCPtrBase & X86_PAGE_4M_OFFSET_MASK)
315 {
316 AssertMsgFailed(("GCPtrBase (%#x) has to be aligned on a 4MB address!\n", GCPtrBase));
317 return VERR_INVALID_PARAMETER;
318 }
319 if (!cb || (cb & X86_PAGE_4M_OFFSET_MASK))
320 {
321 AssertMsgFailed(("cb (%#x) is 0 or not aligned on a 4MB address!\n", cb));
322 return VERR_INVALID_PARAMETER;
323 }
324
325 /*
326 * Before we do anything we'll do a forced PD sync to try make sure any
327 * pending relocations because of these mappings have been resolved.
328 */
329 PGMSyncCR3(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR3(pVM), CPUMGetGuestCR4(pVM), true);
330
331 /*
332 * Check that it's not conflicting with a core code mapping in the intermediate page table.
333 */
334 unsigned iPDNew = GCPtrBase >> X86_PD_SHIFT;
335 unsigned i = cb >> X86_PD_SHIFT;
336 while (i-- > 0)
337 {
338 if (pVM->pgm.s.pInterPD->a[iPDNew + i].n.u1Present)
339 {
340 /* Check that it's not one or our mappings. */
341 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
342 while (pCur)
343 {
344 if (iPDNew + i - (pCur->GCPtr >> X86_PD_SHIFT) < (pCur->cb >> X86_PD_SHIFT))
345 break;
346 pCur = pCur->pNextR3;
347 }
348 if (!pCur)
349 {
350 LogRel(("PGMR3MappingsFix: Conflicts with intermediate PDE %#x (GCPtrBase=%RGv cb=%#zx). The guest should retry.\n",
351 iPDNew + i, GCPtrBase, cb));
352 return VERR_PGM_MAPPINGS_FIX_CONFLICT;
353 }
354 }
355 }
356
357 /*
358 * In PAE / PAE mode, make sure we don't cross page directories.
359 */
360 if ( ( pVM->pgm.s.enmGuestMode == PGMMODE_PAE
361 || pVM->pgm.s.enmGuestMode == PGMMODE_PAE_NX)
362 && ( pVM->pgm.s.enmShadowMode == PGMMODE_PAE
363 || pVM->pgm.s.enmShadowMode == PGMMODE_PAE_NX))
364 {
365 unsigned iPdptBase = GCPtrBase >> X86_PDPT_SHIFT;
366 unsigned iPdptLast = (GCPtrBase + cb - 1) >> X86_PDPT_SHIFT;
367 if (iPdptBase != iPdptLast)
368 {
369 LogRel(("PGMR3MappingsFix: Crosses PD boundrary; iPdptBase=%#x iPdptLast=%#x (GCPtrBase=%RGv cb=%#zx). The guest should retry.\n",
370 iPdptBase, iPdptLast, GCPtrBase, cb));
371 return VERR_PGM_MAPPINGS_FIX_CONFLICT;
372 }
373 }
374
375 /*
376 * Loop the mappings and check that they all agree on their new locations.
377 */
378 RTGCPTR GCPtrCur = GCPtrBase;
379 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
380 while (pCur)
381 {
382 if (!pCur->pfnRelocate(pVM, pCur->GCPtr, GCPtrCur, PGMRELOCATECALL_SUGGEST, pCur->pvUser))
383 {
384 AssertMsgFailed(("The suggested fixed address %#x was rejected by '%s'!\n", GCPtrCur, pCur->pszDesc));
385 return VERR_PGM_MAPPINGS_FIX_REJECTED;
386 }
387 /* next */
388 GCPtrCur += pCur->cb;
389 pCur = pCur->pNextR3;
390 }
391 if (GCPtrCur > GCPtrBase + cb)
392 {
393 AssertMsgFailed(("cb (%#x) is less than the required range %#x!\n", cb, GCPtrCur - GCPtrBase));
394 return VERR_PGM_MAPPINGS_FIX_TOO_SMALL;
395 }
396
397 /*
398 * Loop the table assigning the mappings to the passed in memory
399 * and call their relocator callback.
400 */
401 GCPtrCur = GCPtrBase;
402 pCur = pVM->pgm.s.pMappingsR3;
403 while (pCur)
404 {
405 unsigned iPDOld = pCur->GCPtr >> X86_PD_SHIFT;
406 iPDNew = GCPtrCur >> X86_PD_SHIFT;
407
408 /*
409 * Relocate the page table(s).
410 */
411 pgmR3MapClearPDEs(&pVM->pgm.s, pCur, iPDOld);
412 pgmR3MapSetPDEs(pVM, pCur, iPDNew);
413
414 /*
415 * Update the entry.
416 */
417 pCur->GCPtr = GCPtrCur;
418 pCur->GCPtrLast = GCPtrCur + pCur->cb - 1;
419
420 /*
421 * Callback to execute the relocation.
422 */
423 pCur->pfnRelocate(pVM, iPDOld << X86_PD_SHIFT, iPDNew << X86_PD_SHIFT, PGMRELOCATECALL_RELOCATE, pCur->pvUser);
424
425 /*
426 * Advance.
427 */
428 GCPtrCur += pCur->cb;
429 pCur = pCur->pNextR3;
430 }
431
432#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
433 /*
434 * Turn off CR3 updating monitoring.
435 */
436 int rc2 = PGM_GST_PFN(UnmonitorCR3, pVM)(pVM);
437 AssertRC(rc2);
438#endif
439
440 /*
441 * Mark the mappings as fixed and return.
442 */
443 pVM->pgm.s.fMappingsFixed = true;
444 pVM->pgm.s.GCPtrMappingFixed = GCPtrBase;
445 pVM->pgm.s.cbMappingFixed = cb;
446 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
447 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
448 return VINF_SUCCESS;
449}
450
451
452/**
453 * Unfixes the mappings.
454 * After calling this function mapping conflict detection will be enabled.
455 *
456 * @returns VBox status code.
457 * @param pVM The VM.
458 */
459VMMR3DECL(int) PGMR3MappingsUnfix(PVM pVM)
460{
461 Log(("PGMR3MappingsUnfix: fMappingsFixed=%d\n", pVM->pgm.s.fMappingsFixed));
462
463 /* Refuse in VT-x/AMD-V mode. */
464 if (HWACCMR3IsActive(pVM))
465 return VINF_SUCCESS;
466
467 pVM->pgm.s.fMappingsFixed = false;
468 pVM->pgm.s.GCPtrMappingFixed = 0;
469 pVM->pgm.s.cbMappingFixed = 0;
470 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
471
472 /*
473 * Re-enable the CR3 monitoring.
474 *
475 * Paranoia: We flush the page pool before doing that because Windows
476 * is using the CR3 page both as a PD and a PT, e.g. the pool may
477 * be monitoring it.
478 */
479#ifdef PGMPOOL_WITH_MONITORING
480 pgmPoolFlushAll(pVM);
481#endif
482 /* Remap CR3 as we have just flushed the CR3 shadow PML4 in case we're in long mode. */
483 int rc = PGM_GST_PFN(MapCR3, pVM)(pVM, pVM->pgm.s.GCPhysCR3);
484 AssertRC(rc);
485
486#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
487 rc = PGM_GST_PFN(MonitorCR3, pVM)(pVM, pVM->pgm.s.GCPhysCR3);
488 AssertRC(rc);
489#endif
490 return VINF_SUCCESS;
491}
492
493
494/**
495 * Map pages into the intermediate context (switcher code).
496 * These pages are mapped at both the give virtual address and at
497 * the physical address (for identity mapping).
498 *
499 * @returns VBox status code.
500 * @param pVM The virtual machine.
501 * @param Addr Intermediate context address of the mapping.
502 * @param HCPhys Start of the range of physical pages. This must be entriely below 4GB!
503 * @param cbPages Number of bytes to map.
504 *
505 * @remark This API shall not be used to anything but mapping the switcher code.
506 */
507VMMR3DECL(int) PGMR3MapIntermediate(PVM pVM, RTUINTPTR Addr, RTHCPHYS HCPhys, unsigned cbPages)
508{
509 LogFlow(("PGMR3MapIntermediate: Addr=%RTptr HCPhys=%RHp cbPages=%#x\n", Addr, HCPhys, cbPages));
510
511 /*
512 * Adjust input.
513 */
514 cbPages += (uint32_t)HCPhys & PAGE_OFFSET_MASK;
515 cbPages = RT_ALIGN(cbPages, PAGE_SIZE);
516 HCPhys &= X86_PTE_PAE_PG_MASK;
517 Addr &= PAGE_BASE_MASK;
518 /* We only care about the first 4GB, because on AMD64 we'll be repeating them all over the address space. */
519 uint32_t uAddress = (uint32_t)Addr;
520
521 /*
522 * Assert input and state.
523 */
524 AssertMsg(pVM->pgm.s.offVM, ("Bad init order\n"));
525 AssertMsg(pVM->pgm.s.pInterPD, ("Bad init order, paging.\n"));
526 AssertMsg(cbPages <= (512 << PAGE_SHIFT), ("The mapping is too big %d bytes\n", cbPages));
527 AssertMsg(HCPhys < _4G && HCPhys + cbPages < _4G, ("Addr=%RTptr HCPhys=%RHp cbPages=%d\n", Addr, HCPhys, cbPages));
528
529 /*
530 * Check for internal conflicts between the virtual address and the physical address.
531 */
532 if ( uAddress != HCPhys
533 && ( uAddress < HCPhys
534 ? HCPhys - uAddress < cbPages
535 : uAddress - HCPhys < cbPages
536 )
537 )
538 AssertLogRelMsgFailedReturn(("Addr=%RTptr HCPhys=%RHp cbPages=%d\n", Addr, HCPhys, cbPages),
539 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
540
541 /* The intermediate mapping must not conflict with our default hypervisor address. */
542 size_t cbHyper;
543 RTGCPTR pvHyperGC = MMHyperGetArea(pVM, &cbHyper);
544 if (uAddress < pvHyperGC
545 ? uAddress + cbPages > pvHyperGC
546 : pvHyperGC + cbHyper > uAddress
547 )
548 AssertLogRelMsgFailedReturn(("Addr=%RTptr HyperGC=%RGv cbPages=%zu\n", Addr, pvHyperGC, cbPages),
549 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
550
551 const unsigned cPages = cbPages >> PAGE_SHIFT;
552 int rc = pgmR3MapIntermediateCheckOne(pVM, uAddress, cPages, pVM->pgm.s.apInterPTs[0], pVM->pgm.s.apInterPaePTs[0]);
553 if (RT_FAILURE(rc))
554 return rc;
555 rc = pgmR3MapIntermediateCheckOne(pVM, (uintptr_t)HCPhys, cPages, pVM->pgm.s.apInterPTs[1], pVM->pgm.s.apInterPaePTs[1]);
556 if (RT_FAILURE(rc))
557 return rc;
558
559 /*
560 * Everythings fine, do the mapping.
561 */
562 pgmR3MapIntermediateDoOne(pVM, uAddress, HCPhys, cPages, pVM->pgm.s.apInterPTs[0], pVM->pgm.s.apInterPaePTs[0]);
563 pgmR3MapIntermediateDoOne(pVM, (uintptr_t)HCPhys, HCPhys, cPages, pVM->pgm.s.apInterPTs[1], pVM->pgm.s.apInterPaePTs[1]);
564
565 return VINF_SUCCESS;
566}
567
568
569/**
570 * Validates that there are no conflicts for this mapping into the intermediate context.
571 *
572 * @returns VBox status code.
573 * @param pVM VM handle.
574 * @param uAddress Address of the mapping.
575 * @param cPages Number of pages.
576 * @param pPTDefault Pointer to the default page table for this mapping.
577 * @param pPTPaeDefault Pointer to the default page table for this mapping.
578 */
579static int pgmR3MapIntermediateCheckOne(PVM pVM, uintptr_t uAddress, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault)
580{
581 AssertMsg((uAddress >> X86_PD_SHIFT) + cPages <= 1024, ("64-bit fixme\n"));
582
583 /*
584 * Check that the ranges are available.
585 * (This code doesn't have to be fast.)
586 */
587 while (cPages > 0)
588 {
589 /*
590 * 32-Bit.
591 */
592 unsigned iPDE = (uAddress >> X86_PD_SHIFT) & X86_PD_MASK;
593 unsigned iPTE = (uAddress >> X86_PT_SHIFT) & X86_PT_MASK;
594 PX86PT pPT = pPTDefault;
595 if (pVM->pgm.s.pInterPD->a[iPDE].u)
596 {
597 RTHCPHYS HCPhysPT = pVM->pgm.s.pInterPD->a[iPDE].u & X86_PDE_PG_MASK;
598 if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPTs[0]))
599 pPT = pVM->pgm.s.apInterPTs[0];
600 else if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPTs[1]))
601 pPT = pVM->pgm.s.apInterPTs[1];
602 else
603 {
604 /** @todo this must be handled with a relocation of the conflicting mapping!
605 * Which of course cannot be done because we're in the middle of the initialization. bad design! */
606 AssertLogRelMsgFailedReturn(("Conflict between core code and PGMR3Mapping(). uAddress=%RHv\n", uAddress),
607 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
608 }
609 }
610 if (pPT->a[iPTE].u)
611 AssertLogRelMsgFailedReturn(("Conflict iPTE=%#x iPDE=%#x uAddress=%RHv pPT->a[iPTE].u=%RX32\n", iPTE, iPDE, uAddress, pPT->a[iPTE].u),
612 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
613
614 /*
615 * PAE.
616 */
617 const unsigned iPDPE= (uAddress >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
618 iPDE = (uAddress >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
619 iPTE = (uAddress >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
620 Assert(iPDPE < 4);
621 Assert(pVM->pgm.s.apInterPaePDs[iPDPE]);
622 PX86PTPAE pPTPae = pPTPaeDefault;
623 if (pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u)
624 {
625 RTHCPHYS HCPhysPT = pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u & X86_PDE_PAE_PG_MASK;
626 if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPaePTs[0]))
627 pPTPae = pVM->pgm.s.apInterPaePTs[0];
628 else if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPaePTs[0]))
629 pPTPae = pVM->pgm.s.apInterPaePTs[1];
630 else
631 {
632 /** @todo this must be handled with a relocation of the conflicting mapping!
633 * Which of course cannot be done because we're in the middle of the initialization. bad design! */
634 AssertLogRelMsgFailedReturn(("Conflict between core code and PGMR3Mapping(). uAddress=%RHv\n", uAddress),
635 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
636 }
637 }
638 if (pPTPae->a[iPTE].u)
639 AssertLogRelMsgFailedReturn(("Conflict iPTE=%#x iPDE=%#x uAddress=%RHv pPTPae->a[iPTE].u=%#RX64\n", iPTE, iPDE, uAddress, pPTPae->a[iPTE].u),
640 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
641
642 /* next */
643 uAddress += PAGE_SIZE;
644 cPages--;
645 }
646
647 return VINF_SUCCESS;
648}
649
650
651
652/**
653 * Sets up the intermediate page tables for a verified mapping.
654 *
655 * @param pVM VM handle.
656 * @param uAddress Address of the mapping.
657 * @param HCPhys The physical address of the page range.
658 * @param cPages Number of pages.
659 * @param pPTDefault Pointer to the default page table for this mapping.
660 * @param pPTPaeDefault Pointer to the default page table for this mapping.
661 */
662static void pgmR3MapIntermediateDoOne(PVM pVM, uintptr_t uAddress, RTHCPHYS HCPhys, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault)
663{
664 while (cPages > 0)
665 {
666 /*
667 * 32-Bit.
668 */
669 unsigned iPDE = (uAddress >> X86_PD_SHIFT) & X86_PD_MASK;
670 unsigned iPTE = (uAddress >> X86_PT_SHIFT) & X86_PT_MASK;
671 PX86PT pPT;
672 if (pVM->pgm.s.pInterPD->a[iPDE].u)
673 pPT = (PX86PT)MMPagePhys2Page(pVM, pVM->pgm.s.pInterPD->a[iPDE].u & X86_PDE_PG_MASK);
674 else
675 {
676 pVM->pgm.s.pInterPD->a[iPDE].u = X86_PDE_P | X86_PDE_A | X86_PDE_RW
677 | (uint32_t)MMPage2Phys(pVM, pPTDefault);
678 pPT = pPTDefault;
679 }
680 pPT->a[iPTE].u = X86_PTE_P | X86_PTE_RW | X86_PTE_A | X86_PTE_D | (uint32_t)HCPhys;
681
682 /*
683 * PAE
684 */
685 const unsigned iPDPE= (uAddress >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
686 iPDE = (uAddress >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
687 iPTE = (uAddress >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
688 Assert(iPDPE < 4);
689 Assert(pVM->pgm.s.apInterPaePDs[iPDPE]);
690 PX86PTPAE pPTPae;
691 if (pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u)
692 pPTPae = (PX86PTPAE)MMPagePhys2Page(pVM, pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u & X86_PDE_PAE_PG_MASK);
693 else
694 {
695 pPTPae = pPTPaeDefault;
696 pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u = X86_PDE_P | X86_PDE_A | X86_PDE_RW
697 | MMPage2Phys(pVM, pPTPaeDefault);
698 }
699 pPTPae->a[iPTE].u = X86_PTE_P | X86_PTE_RW | X86_PTE_A | X86_PTE_D | HCPhys;
700
701 /* next */
702 cPages--;
703 HCPhys += PAGE_SIZE;
704 uAddress += PAGE_SIZE;
705 }
706}
707
708
709/**
710 * Clears all PDEs involved with the mapping.
711 *
712 * @param pPGM Pointer to the PGM instance data.
713 * @param pMap Pointer to the mapping in question.
714 * @param iOldPDE The index of the 32-bit PDE corresponding to the base of the mapping.
715 */
716static void pgmR3MapClearPDEs(PPGM pPGM, PPGMMAPPING pMap, unsigned iOldPDE)
717{
718 unsigned i = pMap->cPTs;
719 iOldPDE += i;
720 while (i-- > 0)
721 {
722 iOldPDE--;
723
724 /*
725 * 32-bit.
726 */
727 pPGM->pInterPD->a[iOldPDE].u = 0;
728#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
729 pPGM->pShw32BitPdR3->a[iOldPDE].u = 0;
730#endif
731 /*
732 * PAE.
733 */
734 const unsigned iPD = iOldPDE / 256;
735 unsigned iPDE = iOldPDE * 2 % 512;
736 pPGM->apInterPaePDs[iPD]->a[iPDE].u = 0;
737#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
738 pPGM->apShwPaePDsR3[iPD]->a[iPDE].u = 0;
739#endif
740 iPDE++;
741 pPGM->apInterPaePDs[iPD]->a[iPDE].u = 0;
742#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
743 pPGM->apShwPaePDsR3[iPD]->a[iPDE].u = 0;
744
745 /* Clear the PGM_PDFLAGS_MAPPING flag for the page directory pointer entry. (legacy PAE guest mode) */
746 pPGM->pShwPaePdptR3->a[iPD].u &= ~PGM_PLXFLAGS_MAPPING;
747#endif
748 }
749}
750
751
752/**
753 * Sets all PDEs involved with the mapping.
754 *
755 * @param pVM The VM handle.
756 * @param pMap Pointer to the mapping in question.
757 * @param iNewPDE The index of the 32-bit PDE corresponding to the base of the mapping.
758 */
759static void pgmR3MapSetPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iNewPDE)
760{
761 PPGM pPGM = &pVM->pgm.s;
762
763 Assert(!pgmMapAreMappingsEnabled(&pVM->pgm.s) || PGMGetGuestMode(pVM) <= PGMMODE_PAE_NX);
764
765 /*
766 * Init the page tables and insert them into the page directories.
767 */
768 unsigned i = pMap->cPTs;
769 iNewPDE += i;
770 while (i-- > 0)
771 {
772 iNewPDE--;
773
774 /*
775 * 32-bit.
776 */
777#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
778 if ( pgmMapAreMappingsEnabled(&pVM->pgm.s)
779 && pPGM->pShw32BitPdR3->a[iNewPDE].n.u1Present)
780 pgmPoolFree(pVM, pPGM->pShw32BitPdR3->a[iNewPDE].u & X86_PDE_PG_MASK, PGMPOOL_IDX_PD, iNewPDE);
781#endif
782 X86PDE Pde;
783 /* Default mapping page directory flags are read/write and supervisor; individual page attributes determine the final flags */
784 Pde.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT;
785 pPGM->pInterPD->a[iNewPDE] = Pde;
786#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
787 if (pgmMapAreMappingsEnabled(&pVM->pgm.s))
788 pPGM->pShw32BitPdR3->a[iNewPDE] = Pde;
789#endif
790 /*
791 * PAE.
792 */
793 const unsigned iPD = iNewPDE / 256;
794 unsigned iPDE = iNewPDE * 2 % 512;
795#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
796 if ( pgmMapAreMappingsEnabled(&pVM->pgm.s)
797 && pPGM->apShwPaePDsR3[iPD]->a[iPDE].n.u1Present)
798 pgmPoolFree(pVM, pPGM->apShwPaePDsR3[iPD]->a[iPDE].u & X86_PDE_PAE_PG_MASK, PGMPOOL_IDX_PAE_PD, iNewPDE * 2);
799#endif
800 X86PDEPAE PdePae0;
801 PdePae0.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0;
802 pPGM->apInterPaePDs[iPD]->a[iPDE] = PdePae0;
803#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
804 if (pgmMapAreMappingsEnabled(&pVM->pgm.s))
805 pPGM->apShwPaePDsR3[iPD]->a[iPDE] = PdePae0;
806#endif
807 iPDE++;
808#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
809 if ( pgmMapAreMappingsEnabled(&pVM->pgm.s)
810 && pPGM->apShwPaePDsR3[iPD]->a[iPDE].n.u1Present)
811 pgmPoolFree(pVM, pPGM->apShwPaePDsR3[iPD]->a[iPDE].u & X86_PDE_PAE_PG_MASK, PGMPOOL_IDX_PAE_PD, iNewPDE * 2 + 1);
812#endif
813 X86PDEPAE PdePae1;
814 PdePae1.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1;
815 pPGM->apInterPaePDs[iPD]->a[iPDE] = PdePae1;
816#ifndef VBOX_WITH_PGMPOOL_PAGING_ONLY
817 if (pgmMapAreMappingsEnabled(&pVM->pgm.s))
818 {
819 pPGM->apShwPaePDsR3[iPD]->a[iPDE] = PdePae1;
820
821 /* Set the PGM_PDFLAGS_MAPPING flag in the page directory pointer entry. (legacy PAE guest mode) */
822 pPGM->pShwPaePdptR3->a[iPD].u |= PGM_PLXFLAGS_MAPPING;
823 }
824#endif
825 }
826}
827
828
829/**
830 * Relocates a mapping to a new address.
831 *
832 * @param pVM VM handle.
833 * @param pMapping The mapping to relocate.
834 * @param GCPtrOldMapping The address of the start of the old mapping.
835 * @param GCPtrNewMapping The address of the start of the new mapping.
836 */
837void pgmR3MapRelocate(PVM pVM, PPGMMAPPING pMapping, RTGCPTR GCPtrOldMapping, RTGCPTR GCPtrNewMapping)
838{
839 unsigned iPDOld = GCPtrOldMapping >> X86_PD_SHIFT;
840 unsigned iPDNew = GCPtrNewMapping >> X86_PD_SHIFT;
841
842 Log(("PGM: Relocating %s from %RGv to %RGv\n", pMapping->pszDesc, GCPtrOldMapping, GCPtrNewMapping));
843 Assert(((unsigned)iPDOld << X86_PD_SHIFT) == pMapping->GCPtr);
844
845 /*
846 * Relocate the page table(s).
847 */
848 pgmR3MapClearPDEs(&pVM->pgm.s, pMapping, iPDOld);
849 pgmR3MapSetPDEs(pVM, pMapping, iPDNew);
850
851 /*
852 * Update and resort the mapping list.
853 */
854
855 /* Find previous mapping for pMapping, put result into pPrevMap. */
856 PPGMMAPPING pPrevMap = NULL;
857 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
858 while (pCur && pCur != pMapping)
859 {
860 /* next */
861 pPrevMap = pCur;
862 pCur = pCur->pNextR3;
863 }
864 Assert(pCur);
865
866 /* Find mapping which >= than pMapping. */
867 RTGCPTR GCPtrNew = iPDNew << X86_PD_SHIFT;
868 PPGMMAPPING pPrev = NULL;
869 pCur = pVM->pgm.s.pMappingsR3;
870 while (pCur && pCur->GCPtr < GCPtrNew)
871 {
872 /* next */
873 pPrev = pCur;
874 pCur = pCur->pNextR3;
875 }
876
877 if (pCur != pMapping && pPrev != pMapping)
878 {
879 /*
880 * Unlink.
881 */
882 if (pPrevMap)
883 {
884 pPrevMap->pNextR3 = pMapping->pNextR3;
885 pPrevMap->pNextRC = pMapping->pNextRC;
886 pPrevMap->pNextR0 = pMapping->pNextR0;
887 }
888 else
889 {
890 pVM->pgm.s.pMappingsR3 = pMapping->pNextR3;
891 pVM->pgm.s.pMappingsRC = pMapping->pNextRC;
892 pVM->pgm.s.pMappingsR0 = pMapping->pNextR0;
893 }
894
895 /*
896 * Link
897 */
898 pMapping->pNextR3 = pCur;
899 if (pPrev)
900 {
901 pMapping->pNextRC = pPrev->pNextRC;
902 pMapping->pNextR0 = pPrev->pNextR0;
903 pPrev->pNextR3 = pMapping;
904 pPrev->pNextRC = MMHyperR3ToRC(pVM, pMapping);
905 pPrev->pNextR0 = MMHyperR3ToR0(pVM, pMapping);
906 }
907 else
908 {
909 pMapping->pNextRC = pVM->pgm.s.pMappingsRC;
910 pMapping->pNextR0 = pVM->pgm.s.pMappingsR0;
911 pVM->pgm.s.pMappingsR3 = pMapping;
912 pVM->pgm.s.pMappingsRC = MMHyperR3ToRC(pVM, pMapping);
913 pVM->pgm.s.pMappingsR0 = MMHyperR3ToR0(pVM, pMapping);
914 }
915 }
916
917 /*
918 * Update the entry.
919 */
920 pMapping->GCPtr = GCPtrNew;
921 pMapping->GCPtrLast = GCPtrNew + pMapping->cb - 1;
922
923 /*
924 * Callback to execute the relocation.
925 */
926 pMapping->pfnRelocate(pVM, iPDOld << X86_PD_SHIFT, iPDNew << X86_PD_SHIFT, PGMRELOCATECALL_RELOCATE, pMapping->pvUser);
927}
928
929
930/**
931 * Resolves a conflict between a page table based GC mapping and
932 * the Guest OS page tables. (32 bits version)
933 *
934 * @returns VBox status code.
935 * @param pVM VM Handle.
936 * @param pMapping The mapping which conflicts.
937 * @param pPDSrc The page directory of the guest OS.
938 * @param GCPtrOldMapping The address of the start of the current mapping.
939 */
940int pgmR3SyncPTResolveConflict(PVM pVM, PPGMMAPPING pMapping, PX86PD pPDSrc, RTGCPTR GCPtrOldMapping)
941{
942 STAM_PROFILE_START(&pVM->pgm.s.StatR3ResolveConflict, a);
943
944 /*
945 * Scan for free page directory entries.
946 *
947 * Note that we do not support mappings at the very end of the
948 * address space since that will break our GCPtrEnd assumptions.
949 */
950 const unsigned cPTs = pMapping->cPTs;
951 unsigned iPDNew = RT_ELEMENTS(pPDSrc->a) - cPTs; /* (+ 1 - 1) */
952 while (iPDNew-- > 0)
953 {
954 if (pPDSrc->a[iPDNew].n.u1Present)
955 continue;
956 if (cPTs > 1)
957 {
958 bool fOk = true;
959 for (unsigned i = 1; fOk && i < cPTs; i++)
960 if (pPDSrc->a[iPDNew + i].n.u1Present)
961 fOk = false;
962 if (!fOk)
963 continue;
964 }
965
966 /*
967 * Check that it's not conflicting with an intermediate page table mapping.
968 */
969 bool fOk = true;
970 unsigned i = cPTs;
971 while (fOk && i-- > 0)
972 fOk = !pVM->pgm.s.pInterPD->a[iPDNew + i].n.u1Present;
973 if (!fOk)
974 continue;
975 /** @todo AMD64 should check the PAE directories and skip the 32bit stuff. */
976
977 /*
978 * Ask for the mapping.
979 */
980 RTGCPTR GCPtrNewMapping = iPDNew << X86_PD_SHIFT;
981
982 if (pMapping->pfnRelocate(pVM, GCPtrOldMapping, GCPtrNewMapping, PGMRELOCATECALL_SUGGEST, pMapping->pvUser))
983 {
984 pgmR3MapRelocate(pVM, pMapping, GCPtrOldMapping, GCPtrNewMapping);
985 STAM_PROFILE_STOP(&pVM->pgm.s.StatR3ResolveConflict, a);
986 return VINF_SUCCESS;
987 }
988 }
989
990 STAM_PROFILE_STOP(&pVM->pgm.s.StatR3ResolveConflict, a);
991 AssertMsgFailed(("Failed to relocate page table mapping '%s' from %#x! (cPTs=%d)\n", pMapping->pszDesc, GCPtrOldMapping, cPTs));
992 return VERR_PGM_NO_HYPERVISOR_ADDRESS;
993}
994
995
996/**
997 * Resolves a conflict between a page table based GC mapping and
998 * the Guest OS page tables. (PAE bits version)
999 *
1000 * @returns VBox status code.
1001 * @param pVM VM Handle.
1002 * @param pMapping The mapping which conflicts.
1003 * @param GCPtrOldMapping The address of the start of the current mapping.
1004 */
1005int pgmR3SyncPTResolveConflictPAE(PVM pVM, PPGMMAPPING pMapping, RTGCPTR GCPtrOldMapping)
1006{
1007 STAM_PROFILE_START(&pVM->pgm.s.StatR3ResolveConflict, a);
1008
1009 for (int iPDPTE = X86_PG_PAE_PDPE_ENTRIES - 1; iPDPTE >= 0; iPDPTE--)
1010 {
1011 unsigned iPDSrc;
1012 PX86PDPAE pPDSrc = pgmGstGetPaePDPtr(&pVM->pgm.s, (RTGCPTR32)iPDPTE << X86_PDPT_SHIFT, &iPDSrc, NULL);
1013
1014 /*
1015 * Scan for free page directory entries.
1016 *
1017 * Note that we do not support mappings at the very end of the
1018 * address space since that will break our GCPtrEnd assumptions.
1019 * Nor do we support mappings crossing page directories.
1020 */
1021 const unsigned cPTs = pMapping->cb >> X86_PD_PAE_SHIFT;
1022 unsigned iPDNew = RT_ELEMENTS(pPDSrc->a) - cPTs; /* (+ 1 - 1) */
1023
1024 while (iPDNew-- > 0)
1025 {
1026 /* Ugly assumption that mappings start on a 4 MB boundary. */
1027 if (iPDNew & 1)
1028 continue;
1029
1030 if (pPDSrc)
1031 {
1032 if (pPDSrc->a[iPDNew].n.u1Present)
1033 continue;
1034 if (cPTs > 1)
1035 {
1036 bool fOk = true;
1037 for (unsigned i = 1; fOk && i < cPTs; i++)
1038 if (pPDSrc->a[iPDNew + i].n.u1Present)
1039 fOk = false;
1040 if (!fOk)
1041 continue;
1042 }
1043 }
1044 /*
1045 * Check that it's not conflicting with an intermediate page table mapping.
1046 */
1047 bool fOk = true;
1048 unsigned i = cPTs;
1049 while (fOk && i-- > 0)
1050 fOk = !pVM->pgm.s.apInterPaePDs[iPDPTE]->a[iPDNew + i].n.u1Present;
1051 if (!fOk)
1052 continue;
1053
1054 /*
1055 * Ask for the mapping.
1056 */
1057 RTGCPTR GCPtrNewMapping = ((RTGCPTR32)iPDPTE << X86_PDPT_SHIFT) + (iPDNew << X86_PD_PAE_SHIFT);
1058
1059 if (pMapping->pfnRelocate(pVM, GCPtrOldMapping, GCPtrNewMapping, PGMRELOCATECALL_SUGGEST, pMapping->pvUser))
1060 {
1061 pgmR3MapRelocate(pVM, pMapping, GCPtrOldMapping, GCPtrNewMapping);
1062 STAM_PROFILE_STOP(&pVM->pgm.s.StatR3ResolveConflict, a);
1063 return VINF_SUCCESS;
1064 }
1065 }
1066 }
1067 STAM_PROFILE_STOP(&pVM->pgm.s.StatR3ResolveConflict, a);
1068 AssertMsgFailed(("Failed to relocate page table mapping '%s' from %#x! (cPTs=%d)\n", pMapping->pszDesc, GCPtrOldMapping, pMapping->cb >> X86_PD_PAE_SHIFT));
1069 return VERR_PGM_NO_HYPERVISOR_ADDRESS;
1070}
1071
1072
1073/**
1074 * Checks guest PD for conflicts with VMM GC mappings.
1075 *
1076 * @returns true if conflict detected.
1077 * @returns false if not.
1078 * @param pVM The virtual machine.
1079 * @param cr3 Guest context CR3 register.
1080 * @param fRawR0 Whether RawR0 is enabled or not.
1081 */
1082VMMR3DECL(bool) PGMR3MapHasConflicts(PVM pVM, uint64_t cr3, bool fRawR0) /** @todo how many HasConflict constructs do we really need? */
1083{
1084 /*
1085 * Can skip this if mappings are safely fixed.
1086 */
1087 if (pVM->pgm.s.fMappingsFixed)
1088 return false;
1089
1090 PGMMODE const enmGuestMode = PGMGetGuestMode(pVM);
1091 Assert(enmGuestMode <= PGMMODE_PAE_NX);
1092
1093 /*
1094 * Iterate mappings.
1095 */
1096 if (enmGuestMode == PGMMODE_32_BIT)
1097 {
1098 /*
1099 * Resolve the page directory.
1100 */
1101 PX86PD pPD = pVM->pgm.s.pGst32BitPdR3;
1102 Assert(pPD);
1103 Assert(pPD == (PX86PD)PGMPhysGCPhys2R3PtrAssert(pVM, cr3 & X86_CR3_PAGE_MASK, sizeof(*pPD)));
1104
1105 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1106 {
1107 unsigned iPDE = pCur->GCPtr >> X86_PD_SHIFT;
1108 unsigned iPT = pCur->cPTs;
1109 while (iPT-- > 0)
1110 if ( pPD->a[iPDE + iPT].n.u1Present /** @todo PGMGstGetPDE. */
1111 && (fRawR0 || pPD->a[iPDE + iPT].n.u1User))
1112 {
1113 STAM_COUNTER_INC(&pVM->pgm.s.StatR3DetectedConflicts);
1114 Log(("PGMR3HasMappingConflicts: Conflict was detected at %08RX32 for mapping %s (32 bits)\n"
1115 " iPDE=%#x iPT=%#x PDE=%RGp.\n",
1116 (iPT + iPDE) << X86_PD_SHIFT, pCur->pszDesc,
1117 iPDE, iPT, pPD->a[iPDE + iPT].au32[0]));
1118 return true;
1119 }
1120 }
1121 }
1122 else if ( enmGuestMode == PGMMODE_PAE
1123 || enmGuestMode == PGMMODE_PAE_NX)
1124 {
1125 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1126 {
1127 RTGCPTR GCPtr = pCur->GCPtr;
1128
1129 unsigned iPT = pCur->cb >> X86_PD_PAE_SHIFT;
1130 while (iPT-- > 0)
1131 {
1132 X86PDEPAE Pde = pgmGstGetPaePDE(&pVM->pgm.s, GCPtr);
1133
1134 if ( Pde.n.u1Present
1135 && (fRawR0 || Pde.n.u1User))
1136 {
1137 STAM_COUNTER_INC(&pVM->pgm.s.StatR3DetectedConflicts);
1138 Log(("PGMR3HasMappingConflicts: Conflict was detected at %RGv for mapping %s (PAE)\n"
1139 " PDE=%016RX64.\n",
1140 GCPtr, pCur->pszDesc, Pde.u));
1141 return true;
1142 }
1143 GCPtr += (1 << X86_PD_PAE_SHIFT);
1144 }
1145 }
1146 }
1147 else
1148 AssertFailed();
1149
1150 return false;
1151}
1152
1153#ifdef VBOX_WITH_PGMPOOL_PAGING_ONLY
1154/**
1155 * Apply the hypervisor mappings to the active CR3.
1156 *
1157 * @returns VBox status.
1158 * @param pVM The virtual machine.
1159 */
1160VMMR3DECL(int) PGMR3MapActivate(PVM pVM)
1161{
1162 /*
1163 * Can skip this if mappings are safely fixed.
1164 */
1165 if (pVM->pgm.s.fMappingsFixed)
1166 return VINF_SUCCESS;
1167
1168 PGMMODE const enmGuestMode = PGMGetGuestMode(pVM);
1169 Assert(enmGuestMode <= PGMMODE_PAE_NX);
1170
1171 /*
1172 * Iterate mappings.
1173 */
1174 if (enmGuestMode == PGMMODE_32_BIT)
1175 {
1176 /*
1177 * Resolve the page directory.
1178 */
1179 PX86PD pPD = (PX86PD)pVM->pgm.s.pShwPageCR3R3;
1180 Assert(pPD);
1181
1182 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1183 {
1184 unsigned iPDE = pCur->GCPtr >> X86_PD_SHIFT;
1185 unsigned iPT = pCur->cPTs;
1186 while (iPT-- > 0)
1187 pPD->a[iPDE + iPT].u = 0;
1188 }
1189 }
1190 else if ( enmGuestMode == PGMMODE_PAE
1191 || enmGuestMode == PGMMODE_PAE_NX)
1192 {
1193 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1194 {
1195 RTGCPTR GCPtr = pCur->GCPtr;
1196 unsigned iPdpt = (GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
1197
1198 unsigned iPT = pCur->cb >> X86_PD_PAE_SHIFT;
1199 while (iPT-- > 0)
1200 {
1201 PX86PDEPAE pPDE = pgmShwGetPaePDEPtr(&pVM->pgm.s, GCPtr);
1202 pPDE->u = 0;
1203
1204 GCPtr += (1 << X86_PD_PAE_SHIFT);
1205 }
1206 }
1207 }
1208 else
1209 AssertFailed();
1210
1211 return VINF_SUCCESS;
1212}
1213
1214/**
1215 * Remove the hypervisor mappings from the active CR3
1216 *
1217 * @returns VBox status.
1218 * @param pVM The virtual machine.
1219 */
1220VMMR3DECL(int) PGMR3MapDeactivate(PVM pVM)
1221{
1222 /*
1223 * Can skip this if mappings are safely fixed.
1224 */
1225 if (pVM->pgm.s.fMappingsFixed)
1226 return VINF_SUCCESS;
1227
1228 PGMMODE const enmGuestMode = PGMGetGuestMode(pVM);
1229 Assert(enmGuestMode <= PGMMODE_PAE_NX);
1230
1231 /*
1232 * Iterate mappings.
1233 */
1234 if (enmGuestMode == PGMMODE_32_BIT)
1235 {
1236 /*
1237 * Resolve the page directory.
1238 */
1239 PX86PD pPD = (PX86PD)pVM->pgm.s.pShwPageCR3R3;
1240 Assert(pPD);
1241
1242 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1243 {
1244 unsigned iPDE = pCur->GCPtr >> X86_PD_SHIFT;
1245 unsigned iPT = pCur->cPTs;
1246 while (iPT-- > 0)
1247 pPD->a[iPDE + iPT].u = 0;
1248 }
1249 }
1250 else if ( enmGuestMode == PGMMODE_PAE
1251 || enmGuestMode == PGMMODE_PAE_NX)
1252 {
1253 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1254 {
1255 RTGCPTR GCPtr = pCur->GCPtr;
1256
1257 unsigned iPT = pCur->cb >> X86_PD_PAE_SHIFT;
1258 while (iPT-- > 0)
1259 {
1260 PX86PDEPAE pPDE = pgmShwGetPaePDEPtr(&pVM->pgm.s, GCPtr);
1261 pPDE->u = 0;
1262
1263 GCPtr += (1 << X86_PD_PAE_SHIFT);
1264 }
1265 }
1266
1267 /* Clear the PGM_PDFLAGS_MAPPING flag for the page directory pointer entries. (legacy PAE guest mode) */
1268 PX86PDPT pPdpt = (PX86PDPT)pVM->pgm.s.pShwPageCR3R3;
1269 for (unsigned i=0;i<X86_PG_PAE_PDPE_ENTRIES;i++)
1270 pPdpt->a[i].u &= ~PGM_PLXFLAGS_MAPPING;
1271 }
1272 else
1273 AssertFailed();
1274
1275 return VINF_SUCCESS;
1276}
1277#endif /* VBOX_WITH_PGMPOOL_PAGING_ONLY */
1278
1279/**
1280 * Read memory from the guest mappings.
1281 *
1282 * This will use the page tables associated with the mappings to
1283 * read the memory. This means that not all kind of memory is readable
1284 * since we don't necessarily know how to convert that physical address
1285 * to a HC virtual one.
1286 *
1287 * @returns VBox status.
1288 * @param pVM VM handle.
1289 * @param pvDst The destination address (HC of course).
1290 * @param GCPtrSrc The source address (GC virtual address).
1291 * @param cb Number of bytes to read.
1292 *
1293 * @remarks The is indirectly for DBGF only.
1294 * @todo Consider renaming it to indicate it's special usage, or just
1295 * reimplement it in MMR3HyperReadGCVirt.
1296 */
1297VMMR3DECL(int) PGMR3MapRead(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb)
1298{
1299 /*
1300 * Simplicity over speed... Chop the request up into chunks
1301 * which don't cross pages.
1302 */
1303 if (cb + (GCPtrSrc & PAGE_OFFSET_MASK) > PAGE_SIZE)
1304 {
1305 for (;;)
1306 {
1307 size_t cbRead = RT_MIN(cb, PAGE_SIZE - (GCPtrSrc & PAGE_OFFSET_MASK));
1308 int rc = PGMR3MapRead(pVM, pvDst, GCPtrSrc, cbRead);
1309 if (RT_FAILURE(rc))
1310 return rc;
1311 cb -= cbRead;
1312 if (!cb)
1313 break;
1314 pvDst = (char *)pvDst + cbRead;
1315 GCPtrSrc += cbRead;
1316 }
1317 return VINF_SUCCESS;
1318 }
1319
1320 /*
1321 * Find the mapping.
1322 */
1323 PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings);
1324 while (pCur)
1325 {
1326 RTGCPTR off = GCPtrSrc - pCur->GCPtr;
1327 if (off < pCur->cb)
1328 {
1329 if (off + cb > pCur->cb)
1330 {
1331 AssertMsgFailed(("Invalid page range %RGv LB%#x. mapping '%s' %RGv to %RGv\n",
1332 GCPtrSrc, cb, pCur->pszDesc, pCur->GCPtr, pCur->GCPtrLast));
1333 return VERR_INVALID_PARAMETER;
1334 }
1335
1336 unsigned iPT = off >> X86_PD_SHIFT;
1337 unsigned iPTE = (off >> PAGE_SHIFT) & X86_PT_MASK;
1338 while (cb > 0 && iPTE < RT_ELEMENTS(CTXALLSUFF(pCur->aPTs[iPT].pPT)->a))
1339 {
1340 if (!CTXALLSUFF(pCur->aPTs[iPT].paPaePTs)[iPTE / 512].a[iPTE % 512].n.u1Present)
1341 return VERR_PAGE_NOT_PRESENT;
1342 RTHCPHYS HCPhys = CTXALLSUFF(pCur->aPTs[iPT].paPaePTs)[iPTE / 512].a[iPTE % 512].u & X86_PTE_PAE_PG_MASK;
1343
1344 /*
1345 * Get the virtual page from the physical one.
1346 */
1347 void *pvPage;
1348 int rc = MMR3HCPhys2HCVirt(pVM, HCPhys, &pvPage);
1349 if (RT_FAILURE(rc))
1350 return rc;
1351
1352 memcpy(pvDst, (char *)pvPage + (GCPtrSrc & PAGE_OFFSET_MASK), cb);
1353 return VINF_SUCCESS;
1354 }
1355 }
1356
1357 /* next */
1358 pCur = CTXALLSUFF(pCur->pNext);
1359 }
1360
1361 return VERR_INVALID_POINTER;
1362}
1363
1364
1365/**
1366 * Info callback for 'pgmhandlers'.
1367 *
1368 * @param pHlp The output helpers.
1369 * @param pszArgs The arguments. phys or virt.
1370 */
1371DECLCALLBACK(void) pgmR3MapInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1372{
1373 pHlp->pfnPrintf(pHlp, pVM->pgm.s.fMappingsFixed
1374 ? "\nThe mappings are FIXED.\n"
1375 : "\nThe mappings are FLOATING.\n");
1376 PPGMMAPPING pCur;
1377 for (pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1378 pHlp->pfnPrintf(pHlp, "%RGv - %RGv %s\n", pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc);
1379}
1380
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