VirtualBox

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

Last change on this file since 16358 was 16321, checked in by vboxsync, 16 years ago

More paging updates

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

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