VirtualBox

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

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

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

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