VirtualBox

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

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

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

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