VirtualBox

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

Last change on this file since 44528 was 44528, checked in by vboxsync, 11 years ago

header (C) fixes

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

© 2023 Oracle
ContactPrivacy policyTerms of Use