VirtualBox

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

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

VMM: First part of HMIsEnabled() and PGMMap*.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 50.0 KB
Line 
1/* $Id: PGMMap.cpp 45739 2013-04-25 19:44:05Z 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 MappingEnabled=%RTbool)\n",
517 GCPtrBase, cb, pVM->pgm.s.fMappingsFixed, pgmMapAreMappingsEnabled(pVM)));
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 * Unfixes the mappings.
688 *
689 * Unless PGMR3MappingsDisable is in effect, mapping conflict detection will be
690 * enabled after this call. If the mappings are fixed, a full CR3 resync will
691 * take place afterwards.
692 *
693 * @returns VBox status code.
694 * @param pVM Pointer to the VM.
695 */
696VMMR3DECL(int) PGMR3MappingsUnfix(PVM pVM)
697{
698 Log(("PGMR3MappingsUnfix: fMappingsFixed=%RTbool MappingsEnabled=%RTbool\n", pVM->pgm.s.fMappingsFixed, pgmMapAreMappingsEnabled(pVM)));
699 if ( pgmMapAreMappingsEnabled(pVM)
700 && ( pVM->pgm.s.fMappingsFixed
701 || pVM->pgm.s.fMappingsFixedRestored)
702 )
703 {
704 bool const fResyncCR3 = pVM->pgm.s.fMappingsFixed;
705
706 pVM->pgm.s.fMappingsFixed = false;
707 pVM->pgm.s.fMappingsFixedRestored = false;
708 pVM->pgm.s.GCPtrMappingFixed = 0;
709 pVM->pgm.s.cbMappingFixed = 0;
710
711 if (fResyncCR3)
712 for (VMCPUID i = 0; i < pVM->cCpus; i++)
713 VMCPU_FF_SET(&pVM->aCpus[i], VMCPU_FF_PGM_SYNC_CR3);
714 }
715 return VINF_SUCCESS;
716}
717
718
719/**
720 * Checks if the mappings needs re-fixing after a restore.
721 *
722 * @returns true if they need, false if not.
723 * @param pVM Pointer to the VM.
724 */
725VMMR3DECL(bool) PGMR3MappingsNeedReFixing(PVM pVM)
726{
727 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
728 return pVM->pgm.s.fMappingsFixedRestored;
729}
730
731#ifndef PGM_WITHOUT_MAPPINGS
732
733/**
734 * Map pages into the intermediate context (switcher code).
735 *
736 * These pages are mapped at both the give virtual address and at the physical
737 * address (for identity mapping).
738 *
739 * @returns VBox status code.
740 * @param pVM Pointer to the VM.
741 * @param Addr Intermediate context address of the mapping.
742 * @param HCPhys Start of the range of physical pages. This must be entriely below 4GB!
743 * @param cbPages Number of bytes to map.
744 *
745 * @remark This API shall not be used to anything but mapping the switcher code.
746 */
747VMMR3DECL(int) PGMR3MapIntermediate(PVM pVM, RTUINTPTR Addr, RTHCPHYS HCPhys, unsigned cbPages)
748{
749 LogFlow(("PGMR3MapIntermediate: Addr=%RTptr HCPhys=%RHp cbPages=%#x\n", Addr, HCPhys, cbPages));
750
751 /*
752 * Adjust input.
753 */
754 cbPages += (uint32_t)HCPhys & PAGE_OFFSET_MASK;
755 cbPages = RT_ALIGN(cbPages, PAGE_SIZE);
756 HCPhys &= X86_PTE_PAE_PG_MASK;
757 Addr &= PAGE_BASE_MASK;
758 /* We only care about the first 4GB, because on AMD64 we'll be repeating them all over the address space. */
759 uint32_t uAddress = (uint32_t)Addr;
760
761 /*
762 * Assert input and state.
763 */
764 AssertMsg(pVM->pgm.s.offVM, ("Bad init order\n"));
765 AssertMsg(pVM->pgm.s.pInterPD, ("Bad init order, paging.\n"));
766 AssertMsg(cbPages <= (512 << PAGE_SHIFT), ("The mapping is too big %d bytes\n", cbPages));
767 AssertMsg(HCPhys < _4G && HCPhys + cbPages < _4G, ("Addr=%RTptr HCPhys=%RHp cbPages=%d\n", Addr, HCPhys, cbPages));
768 AssertReturn(!pVM->pgm.s.fFinalizedMappings, VERR_WRONG_ORDER);
769
770 /*
771 * Check for internal conflicts between the virtual address and the physical address.
772 * A 1:1 mapping is fine, but partial overlapping is a no-no.
773 */
774 if ( uAddress != HCPhys
775 && ( uAddress < HCPhys
776 ? HCPhys - uAddress < cbPages
777 : uAddress - HCPhys < cbPages
778 )
779 )
780 AssertLogRelMsgFailedReturn(("Addr=%RTptr HCPhys=%RHp cbPages=%d\n", Addr, HCPhys, cbPages),
781 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
782
783 const unsigned cPages = cbPages >> PAGE_SHIFT;
784 int rc = pgmR3MapIntermediateCheckOne(pVM, uAddress, cPages, pVM->pgm.s.apInterPTs[0], pVM->pgm.s.apInterPaePTs[0]);
785 if (RT_FAILURE(rc))
786 return rc;
787 rc = pgmR3MapIntermediateCheckOne(pVM, (uintptr_t)HCPhys, cPages, pVM->pgm.s.apInterPTs[1], pVM->pgm.s.apInterPaePTs[1]);
788 if (RT_FAILURE(rc))
789 return rc;
790
791 /*
792 * Everythings fine, do the mapping.
793 */
794 pgmR3MapIntermediateDoOne(pVM, uAddress, HCPhys, cPages, pVM->pgm.s.apInterPTs[0], pVM->pgm.s.apInterPaePTs[0]);
795 pgmR3MapIntermediateDoOne(pVM, (uintptr_t)HCPhys, HCPhys, cPages, pVM->pgm.s.apInterPTs[1], pVM->pgm.s.apInterPaePTs[1]);
796
797 return VINF_SUCCESS;
798}
799
800
801/**
802 * Validates that there are no conflicts for this mapping into the intermediate context.
803 *
804 * @returns VBox status code.
805 * @param pVM Pointer to the VM.
806 * @param uAddress Address of the mapping.
807 * @param cPages Number of pages.
808 * @param pPTDefault Pointer to the default page table for this mapping.
809 * @param pPTPaeDefault Pointer to the default page table for this mapping.
810 */
811static int pgmR3MapIntermediateCheckOne(PVM pVM, uintptr_t uAddress, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault)
812{
813 AssertMsg((uAddress >> X86_PD_SHIFT) + cPages <= 1024, ("64-bit fixme uAddress=%RGv cPages=%u\n", uAddress, cPages));
814
815 /*
816 * Check that the ranges are available.
817 * (This code doesn't have to be fast.)
818 */
819 while (cPages > 0)
820 {
821 /*
822 * 32-Bit.
823 */
824 unsigned iPDE = (uAddress >> X86_PD_SHIFT) & X86_PD_MASK;
825 unsigned iPTE = (uAddress >> X86_PT_SHIFT) & X86_PT_MASK;
826 PX86PT pPT = pPTDefault;
827 if (pVM->pgm.s.pInterPD->a[iPDE].u)
828 {
829 RTHCPHYS HCPhysPT = pVM->pgm.s.pInterPD->a[iPDE].u & X86_PDE_PG_MASK;
830 if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPTs[0]))
831 pPT = pVM->pgm.s.apInterPTs[0];
832 else if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPTs[1]))
833 pPT = pVM->pgm.s.apInterPTs[1];
834 else
835 {
836 /** @todo this must be handled with a relocation of the conflicting mapping!
837 * Which of course cannot be done because we're in the middle of the initialization. bad design! */
838 AssertLogRelMsgFailedReturn(("Conflict between core code and PGMR3Mapping(). uAddress=%RHv\n", uAddress),
839 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
840 }
841 }
842 if (pPT->a[iPTE].u)
843 AssertLogRelMsgFailedReturn(("Conflict iPTE=%#x iPDE=%#x uAddress=%RHv pPT->a[iPTE].u=%RX32\n", iPTE, iPDE, uAddress, pPT->a[iPTE].u),
844 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
845
846 /*
847 * PAE.
848 */
849 const unsigned iPDPE= (uAddress >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
850 iPDE = (uAddress >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
851 iPTE = (uAddress >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
852 Assert(iPDPE < 4);
853 Assert(pVM->pgm.s.apInterPaePDs[iPDPE]);
854 PX86PTPAE pPTPae = pPTPaeDefault;
855 if (pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u)
856 {
857 RTHCPHYS HCPhysPT = pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u & X86_PDE_PAE_PG_MASK;
858 if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPaePTs[0]))
859 pPTPae = pVM->pgm.s.apInterPaePTs[0];
860 else if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPaePTs[0]))
861 pPTPae = pVM->pgm.s.apInterPaePTs[1];
862 else
863 {
864 /** @todo this must be handled with a relocation of the conflicting mapping!
865 * Which of course cannot be done because we're in the middle of the initialization. bad design! */
866 AssertLogRelMsgFailedReturn(("Conflict between core code and PGMR3Mapping(). uAddress=%RHv\n", uAddress),
867 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
868 }
869 }
870 if (pPTPae->a[iPTE].u)
871 AssertLogRelMsgFailedReturn(("Conflict iPTE=%#x iPDE=%#x uAddress=%RHv pPTPae->a[iPTE].u=%#RX64\n", iPTE, iPDE, uAddress, pPTPae->a[iPTE].u),
872 VERR_PGM_INTERMEDIATE_PAGING_CONFLICT);
873
874 /* next */
875 uAddress += PAGE_SIZE;
876 cPages--;
877 }
878
879 return VINF_SUCCESS;
880}
881
882
883
884/**
885 * Sets up the intermediate page tables for a verified mapping.
886 *
887 * @param pVM Pointer to the VM.
888 * @param uAddress Address of the mapping.
889 * @param HCPhys The physical address of the page range.
890 * @param cPages Number of pages.
891 * @param pPTDefault Pointer to the default page table for this mapping.
892 * @param pPTPaeDefault Pointer to the default page table for this mapping.
893 */
894static void pgmR3MapIntermediateDoOne(PVM pVM, uintptr_t uAddress, RTHCPHYS HCPhys, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault)
895{
896 while (cPages > 0)
897 {
898 /*
899 * 32-Bit.
900 */
901 unsigned iPDE = (uAddress >> X86_PD_SHIFT) & X86_PD_MASK;
902 unsigned iPTE = (uAddress >> X86_PT_SHIFT) & X86_PT_MASK;
903 PX86PT pPT;
904 if (pVM->pgm.s.pInterPD->a[iPDE].u)
905 pPT = (PX86PT)MMPagePhys2Page(pVM, pVM->pgm.s.pInterPD->a[iPDE].u & X86_PDE_PG_MASK);
906 else
907 {
908 pVM->pgm.s.pInterPD->a[iPDE].u = X86_PDE_P | X86_PDE_A | X86_PDE_RW
909 | (uint32_t)MMPage2Phys(pVM, pPTDefault);
910 pPT = pPTDefault;
911 }
912 pPT->a[iPTE].u = X86_PTE_P | X86_PTE_RW | X86_PTE_A | X86_PTE_D | (uint32_t)HCPhys;
913
914 /*
915 * PAE
916 */
917 const unsigned iPDPE= (uAddress >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE;
918 iPDE = (uAddress >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
919 iPTE = (uAddress >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
920 Assert(iPDPE < 4);
921 Assert(pVM->pgm.s.apInterPaePDs[iPDPE]);
922 PX86PTPAE pPTPae;
923 if (pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u)
924 pPTPae = (PX86PTPAE)MMPagePhys2Page(pVM, pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u & X86_PDE_PAE_PG_MASK);
925 else
926 {
927 pPTPae = pPTPaeDefault;
928 pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u = X86_PDE_P | X86_PDE_A | X86_PDE_RW
929 | MMPage2Phys(pVM, pPTPaeDefault);
930 }
931 pPTPae->a[iPTE].u = X86_PTE_P | X86_PTE_RW | X86_PTE_A | X86_PTE_D | HCPhys;
932
933 /* next */
934 cPages--;
935 HCPhys += PAGE_SIZE;
936 uAddress += PAGE_SIZE;
937 }
938}
939
940
941/**
942 * Clears all PDEs involved with the mapping in the shadow and intermediate page tables.
943 *
944 * @param pVM Pointer to the VM.
945 * @param pMap Pointer to the mapping in question.
946 * @param iOldPDE The index of the 32-bit PDE corresponding to the base of the mapping.
947 */
948static void pgmR3MapClearPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iOldPDE)
949{
950 unsigned i = pMap->cPTs;
951 PVMCPU pVCpu = VMMGetCpu(pVM);
952 pgmLock(pVM); /* to avoid assertions */
953
954 pgmMapClearShadowPDEs(pVM, pVCpu->pgm.s.CTX_SUFF(pShwPageCR3), pMap, iOldPDE, false /*fDeactivateCR3*/);
955
956 iOldPDE += i;
957 while (i-- > 0)
958 {
959 iOldPDE--;
960
961 /*
962 * 32-bit.
963 */
964 pVM->pgm.s.pInterPD->a[iOldPDE].u = 0;
965
966 /*
967 * PAE.
968 */
969 const unsigned iPD = iOldPDE / 256; /* iOldPDE * 2 / 512; iOldPDE is in 4 MB pages */
970 unsigned iPDE = iOldPDE * 2 % 512;
971 pVM->pgm.s.apInterPaePDs[iPD]->a[iPDE].u = 0;
972 iPDE++;
973 AssertFatal(iPDE < 512);
974 pVM->pgm.s.apInterPaePDs[iPD]->a[iPDE].u = 0;
975 }
976
977 pgmUnlock(pVM);
978}
979
980
981/**
982 * Sets all PDEs involved with the mapping in the shadow and intermediate page tables.
983 *
984 * @param pVM Pointer to the VM.
985 * @param pMap Pointer to the mapping in question.
986 * @param iNewPDE The index of the 32-bit PDE corresponding to the base of the mapping.
987 */
988static void pgmR3MapSetPDEs(PVM pVM, PPGMMAPPING pMap, unsigned iNewPDE)
989{
990 PPGM pPGM = &pVM->pgm.s;
991#ifdef VBOX_STRICT
992 PVMCPU pVCpu = VMMGetCpu(pVM);
993#endif
994 pgmLock(pVM); /* to avoid assertions */
995
996 Assert(!pgmMapAreMappingsEnabled(pVM) || PGMGetGuestMode(pVCpu) <= PGMMODE_PAE_NX);
997
998 pgmMapSetShadowPDEs(pVM, pMap, iNewPDE);
999
1000 /*
1001 * Init the page tables and insert them into the page directories.
1002 */
1003 unsigned i = pMap->cPTs;
1004 iNewPDE += i;
1005 while (i-- > 0)
1006 {
1007 iNewPDE--;
1008
1009 /*
1010 * 32-bit.
1011 */
1012 X86PDE Pde;
1013 /* Default mapping page directory flags are read/write and supervisor; individual page attributes determine the final flags */
1014 Pde.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT;
1015 pPGM->pInterPD->a[iNewPDE] = Pde;
1016
1017 /*
1018 * PAE.
1019 */
1020 const unsigned iPD = iNewPDE / 256;
1021 unsigned iPDE = iNewPDE * 2 % 512;
1022 X86PDEPAE PdePae0;
1023 PdePae0.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0;
1024 pPGM->apInterPaePDs[iPD]->a[iPDE] = PdePae0;
1025 iPDE++;
1026 AssertFatal(iPDE < 512);
1027 X86PDEPAE PdePae1;
1028 PdePae1.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1;
1029 pPGM->apInterPaePDs[iPD]->a[iPDE] = PdePae1;
1030 }
1031
1032 pgmUnlock(pVM);
1033}
1034
1035
1036/**
1037 * Relocates a mapping to a new address.
1038 *
1039 * @param pVM Pointer to the VM.
1040 * @param pMapping The mapping to relocate.
1041 * @param GCPtrOldMapping The address of the start of the old mapping.
1042 * NIL_RTGCPTR if not currently mapped.
1043 * @param GCPtrNewMapping The address of the start of the new mapping.
1044 */
1045static void pgmR3MapRelocate(PVM pVM, PPGMMAPPING pMapping, RTGCPTR GCPtrOldMapping, RTGCPTR GCPtrNewMapping)
1046{
1047 Log(("PGM: Relocating %s from %RGv to %RGv\n", pMapping->pszDesc, GCPtrOldMapping, GCPtrNewMapping));
1048 AssertMsg(GCPtrOldMapping == pMapping->GCPtr, ("%RGv vs %RGv\n", GCPtrOldMapping, pMapping->GCPtr));
1049 AssertMsg((GCPtrOldMapping >> X86_PD_SHIFT) < X86_PG_ENTRIES, ("%RGv\n", GCPtrOldMapping));
1050 AssertMsg((GCPtrNewMapping >> X86_PD_SHIFT) < X86_PG_ENTRIES, ("%RGv\n", GCPtrOldMapping));
1051
1052 /*
1053 * Relocate the page table(s).
1054 */
1055 if (GCPtrOldMapping != NIL_RTGCPTR)
1056 pgmR3MapClearPDEs(pVM, pMapping, GCPtrOldMapping >> X86_PD_SHIFT);
1057 pgmR3MapSetPDEs(pVM, pMapping, GCPtrNewMapping >> X86_PD_SHIFT);
1058
1059 /*
1060 * Update and resort the mapping list.
1061 */
1062
1063 /* Find previous mapping for pMapping, put result into pPrevMap. */
1064 PPGMMAPPING pPrevMap = NULL;
1065 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
1066 while (pCur && pCur != pMapping)
1067 {
1068 /* next */
1069 pPrevMap = pCur;
1070 pCur = pCur->pNextR3;
1071 }
1072 Assert(pCur);
1073
1074 /* Find mapping which >= than pMapping. */
1075 RTGCPTR GCPtrNew = GCPtrNewMapping;
1076 PPGMMAPPING pPrev = NULL;
1077 pCur = pVM->pgm.s.pMappingsR3;
1078 while (pCur && pCur->GCPtr < GCPtrNew)
1079 {
1080 /* next */
1081 pPrev = pCur;
1082 pCur = pCur->pNextR3;
1083 }
1084
1085 if (pCur != pMapping && pPrev != pMapping)
1086 {
1087 /*
1088 * Unlink.
1089 */
1090 if (pPrevMap)
1091 {
1092 pPrevMap->pNextR3 = pMapping->pNextR3;
1093 pPrevMap->pNextRC = pMapping->pNextRC;
1094 pPrevMap->pNextR0 = pMapping->pNextR0;
1095 }
1096 else
1097 {
1098 pVM->pgm.s.pMappingsR3 = pMapping->pNextR3;
1099 pVM->pgm.s.pMappingsRC = pMapping->pNextRC;
1100 pVM->pgm.s.pMappingsR0 = pMapping->pNextR0;
1101 }
1102
1103 /*
1104 * Link
1105 */
1106 pMapping->pNextR3 = pCur;
1107 if (pPrev)
1108 {
1109 pMapping->pNextRC = pPrev->pNextRC;
1110 pMapping->pNextR0 = pPrev->pNextR0;
1111 pPrev->pNextR3 = pMapping;
1112 pPrev->pNextRC = MMHyperR3ToRC(pVM, pMapping);
1113 pPrev->pNextR0 = MMHyperR3ToR0(pVM, pMapping);
1114 }
1115 else
1116 {
1117 pMapping->pNextRC = pVM->pgm.s.pMappingsRC;
1118 pMapping->pNextR0 = pVM->pgm.s.pMappingsR0;
1119 pVM->pgm.s.pMappingsR3 = pMapping;
1120 pVM->pgm.s.pMappingsRC = MMHyperR3ToRC(pVM, pMapping);
1121 pVM->pgm.s.pMappingsR0 = MMHyperR3ToR0(pVM, pMapping);
1122 }
1123 }
1124
1125 /*
1126 * Update the entry.
1127 */
1128 pMapping->GCPtr = GCPtrNew;
1129 pMapping->GCPtrLast = GCPtrNew + pMapping->cb - 1;
1130
1131 /*
1132 * Callback to execute the relocation.
1133 */
1134 pMapping->pfnRelocate(pVM, GCPtrOldMapping, GCPtrNewMapping, PGMRELOCATECALL_RELOCATE, pMapping->pvUser);
1135}
1136
1137
1138/**
1139 * Checks if a new mapping address wasn't previously used and caused a clash with guest mappings.
1140 *
1141 * @returns VBox status code.
1142 * @param pMapping The mapping which conflicts.
1143 * @param GCPtr New mapping address to try
1144 */
1145bool pgmR3MapIsKnownConflictAddress(PPGMMAPPING pMapping, RTGCPTR GCPtr)
1146{
1147 for (unsigned i = 0; i < RT_ELEMENTS(pMapping->aGCPtrConflicts); i++)
1148 {
1149 if (GCPtr == pMapping->aGCPtrConflicts[i])
1150 return true;
1151 }
1152 return false;
1153}
1154
1155
1156/**
1157 * Resolves a conflict between a page table based GC mapping and
1158 * the Guest OS page tables. (32 bits version)
1159 *
1160 * @returns VBox status code.
1161 * @param pVM Pointer to the VM.
1162 * @param pMapping The mapping which conflicts.
1163 * @param pPDSrc The page directory of the guest OS.
1164 * @param GCPtrOldMapping The address of the start of the current mapping.
1165 */
1166int pgmR3SyncPTResolveConflict(PVM pVM, PPGMMAPPING pMapping, PX86PD pPDSrc, RTGCPTR GCPtrOldMapping)
1167{
1168 STAM_REL_COUNTER_INC(&pVM->pgm.s.cRelocations);
1169 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->StatR3ResolveConflict, a);
1170
1171 /* Raw mode only which implies one VCPU. */
1172 Assert(pVM->cCpus == 1);
1173
1174 pMapping->aGCPtrConflicts[pMapping->cConflicts & (PGMMAPPING_CONFLICT_MAX-1)] = GCPtrOldMapping;
1175 pMapping->cConflicts++;
1176
1177 /*
1178 * Scan for free page directory entries.
1179 *
1180 * Note that we do not support mappings at the very end of the
1181 * address space since that will break our GCPtrEnd assumptions.
1182 */
1183 const unsigned cPTs = pMapping->cPTs;
1184 unsigned iPDNew = RT_ELEMENTS(pPDSrc->a) - cPTs; /* (+ 1 - 1) */
1185 while (iPDNew-- > 0)
1186 {
1187 if (pPDSrc->a[iPDNew].n.u1Present)
1188 continue;
1189
1190 if (pgmR3MapIsKnownConflictAddress(pMapping, iPDNew << X86_PD_SHIFT))
1191 continue;
1192
1193 if (cPTs > 1)
1194 {
1195 bool fOk = true;
1196 for (unsigned i = 1; fOk && i < cPTs; i++)
1197 if (pPDSrc->a[iPDNew + i].n.u1Present)
1198 fOk = false;
1199 if (!fOk)
1200 continue;
1201 }
1202
1203 /*
1204 * Check that it's not conflicting with an intermediate page table mapping.
1205 */
1206 bool fOk = true;
1207 unsigned i = cPTs;
1208 while (fOk && i-- > 0)
1209 fOk = !pVM->pgm.s.pInterPD->a[iPDNew + i].n.u1Present;
1210 if (!fOk)
1211 continue;
1212 /** @todo AMD64 should check the PAE directories and skip the 32bit stuff. */
1213
1214 /*
1215 * Ask for the mapping.
1216 */
1217 RTGCPTR GCPtrNewMapping = (RTGCPTR32)iPDNew << X86_PD_SHIFT;
1218
1219 if (pMapping->pfnRelocate(pVM, GCPtrOldMapping, GCPtrNewMapping, PGMRELOCATECALL_SUGGEST, pMapping->pvUser))
1220 {
1221 pgmR3MapRelocate(pVM, pMapping, GCPtrOldMapping, GCPtrNewMapping);
1222 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatR3ResolveConflict, a);
1223 return VINF_SUCCESS;
1224 }
1225 }
1226
1227 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatR3ResolveConflict, a);
1228 AssertMsgFailed(("Failed to relocate page table mapping '%s' from %#x! (cPTs=%d)\n", pMapping->pszDesc, GCPtrOldMapping, cPTs));
1229 return VERR_PGM_NO_HYPERVISOR_ADDRESS;
1230}
1231
1232
1233/**
1234 * Resolves a conflict between a page table based GC mapping and
1235 * the Guest OS page tables. (PAE bits version)
1236 *
1237 * @returns VBox status code.
1238 * @param pVM Pointer to the VM.
1239 * @param pMapping The mapping which conflicts.
1240 * @param GCPtrOldMapping The address of the start of the current mapping.
1241 */
1242int pgmR3SyncPTResolveConflictPAE(PVM pVM, PPGMMAPPING pMapping, RTGCPTR GCPtrOldMapping)
1243{
1244 STAM_REL_COUNTER_INC(&pVM->pgm.s.cRelocations);
1245 STAM_PROFILE_START(&pVM->pgm.s.StatR3ResolveConflict, a);
1246
1247 /* Raw mode only which implies one VCPU. */
1248 Assert(pVM->cCpus == 1);
1249 PVMCPU pVCpu = VMMGetCpu(pVM);
1250
1251 pMapping->aGCPtrConflicts[pMapping->cConflicts & (PGMMAPPING_CONFLICT_MAX-1)] = GCPtrOldMapping;
1252 pMapping->cConflicts++;
1253
1254 for (int iPDPTE = X86_PG_PAE_PDPE_ENTRIES - 1; iPDPTE >= 0; iPDPTE--)
1255 {
1256 unsigned iPDSrc;
1257 PX86PDPAE pPDSrc = pgmGstGetPaePDPtr(pVCpu, (RTGCPTR32)iPDPTE << X86_PDPT_SHIFT, &iPDSrc, NULL);
1258
1259 /*
1260 * Scan for free page directory entries.
1261 *
1262 * Note that we do not support mappings at the very end of the
1263 * address space since that will break our GCPtrEnd assumptions.
1264 * Nor do we support mappings crossing page directories.
1265 */
1266 const unsigned cPTs = pMapping->cb >> X86_PD_PAE_SHIFT;
1267 unsigned iPDNew = RT_ELEMENTS(pPDSrc->a) - cPTs; /* (+ 1 - 1) */
1268
1269 while (iPDNew-- > 0)
1270 {
1271 /* Ugly assumption that mappings start on a 4 MB boundary. */
1272 if (iPDNew & 1)
1273 continue;
1274
1275 if (pgmR3MapIsKnownConflictAddress(pMapping, ((RTGCPTR32)iPDPTE << X86_PDPT_SHIFT) + (iPDNew << X86_PD_PAE_SHIFT)))
1276 continue;
1277
1278 if (pPDSrc)
1279 {
1280 if (pPDSrc->a[iPDNew].n.u1Present)
1281 continue;
1282 if (cPTs > 1)
1283 {
1284 bool fOk = true;
1285 for (unsigned i = 1; fOk && i < cPTs; i++)
1286 if (pPDSrc->a[iPDNew + i].n.u1Present)
1287 fOk = false;
1288 if (!fOk)
1289 continue;
1290 }
1291 }
1292 /*
1293 * Check that it's not conflicting with an intermediate page table mapping.
1294 */
1295 bool fOk = true;
1296 unsigned i = cPTs;
1297 while (fOk && i-- > 0)
1298 fOk = !pVM->pgm.s.apInterPaePDs[iPDPTE]->a[iPDNew + i].n.u1Present;
1299 if (!fOk)
1300 continue;
1301
1302 /*
1303 * Ask for the mapping.
1304 */
1305 RTGCPTR GCPtrNewMapping = ((RTGCPTR32)iPDPTE << X86_PDPT_SHIFT) + ((RTGCPTR32)iPDNew << X86_PD_PAE_SHIFT);
1306
1307 if (pMapping->pfnRelocate(pVM, GCPtrOldMapping, GCPtrNewMapping, PGMRELOCATECALL_SUGGEST, pMapping->pvUser))
1308 {
1309 pgmR3MapRelocate(pVM, pMapping, GCPtrOldMapping, GCPtrNewMapping);
1310 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatR3ResolveConflict, a);
1311 return VINF_SUCCESS;
1312 }
1313 }
1314 }
1315 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatR3ResolveConflict, a);
1316 AssertMsgFailed(("Failed to relocate page table mapping '%s' from %#x! (cPTs=%d)\n", pMapping->pszDesc, GCPtrOldMapping, pMapping->cb >> X86_PD_PAE_SHIFT));
1317 return VERR_PGM_NO_HYPERVISOR_ADDRESS;
1318}
1319
1320#endif /* !PGM_WITHOUT_MAPPINGS */
1321
1322/**
1323 * Read memory from the guest mappings.
1324 *
1325 * This will use the page tables associated with the mappings to
1326 * read the memory. This means that not all kind of memory is readable
1327 * since we don't necessarily know how to convert that physical address
1328 * to a HC virtual one.
1329 *
1330 * @returns VBox status.
1331 * @param pVM Pointer to the VM.
1332 * @param pvDst The destination address (HC of course).
1333 * @param GCPtrSrc The source address (GC virtual address).
1334 * @param cb Number of bytes to read.
1335 *
1336 * @remarks The is indirectly for DBGF only.
1337 * @todo Consider renaming it to indicate it's special usage, or just
1338 * reimplement it in MMR3HyperReadGCVirt.
1339 */
1340VMMR3DECL(int) PGMR3MapRead(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb)
1341{
1342 /*
1343 * Simplicity over speed... Chop the request up into chunks
1344 * which don't cross pages.
1345 */
1346 if (cb + (GCPtrSrc & PAGE_OFFSET_MASK) > PAGE_SIZE)
1347 {
1348 for (;;)
1349 {
1350 size_t cbRead = RT_MIN(cb, PAGE_SIZE - (GCPtrSrc & PAGE_OFFSET_MASK));
1351 int rc = PGMR3MapRead(pVM, pvDst, GCPtrSrc, cbRead);
1352 if (RT_FAILURE(rc))
1353 return rc;
1354 cb -= cbRead;
1355 if (!cb)
1356 break;
1357 pvDst = (char *)pvDst + cbRead;
1358 GCPtrSrc += cbRead;
1359 }
1360 return VINF_SUCCESS;
1361 }
1362
1363 /*
1364 * Find the mapping.
1365 */
1366 PPGMMAPPING pCur = pVM->pgm.s.CTX_SUFF(pMappings);
1367 while (pCur)
1368 {
1369 RTGCPTR off = GCPtrSrc - pCur->GCPtr;
1370 if (off < pCur->cb)
1371 {
1372 if (off + cb > pCur->cb)
1373 {
1374 AssertMsgFailed(("Invalid page range %RGv LB%#x. mapping '%s' %RGv to %RGv\n",
1375 GCPtrSrc, cb, pCur->pszDesc, pCur->GCPtr, pCur->GCPtrLast));
1376 return VERR_INVALID_PARAMETER;
1377 }
1378
1379 unsigned iPT = off >> X86_PD_SHIFT;
1380 unsigned iPTE = (off >> PAGE_SHIFT) & X86_PT_MASK;
1381 while (cb > 0 && iPTE < RT_ELEMENTS(CTXALLSUFF(pCur->aPTs[iPT].pPT)->a))
1382 {
1383 PCPGMSHWPTEPAE pPte = &pCur->aPTs[iPT].CTXALLSUFF(paPaePTs)[iPTE / 512].a[iPTE % 512];
1384 if (!PGMSHWPTEPAE_IS_P(*pPte))
1385 return VERR_PAGE_NOT_PRESENT;
1386 RTHCPHYS HCPhys = PGMSHWPTEPAE_GET_HCPHYS(*pPte);
1387
1388 /*
1389 * Get the virtual page from the physical one.
1390 */
1391 void *pvPage;
1392 int rc = MMR3HCPhys2HCVirt(pVM, HCPhys, &pvPage);
1393 if (RT_FAILURE(rc))
1394 return rc;
1395
1396 memcpy(pvDst, (char *)pvPage + (GCPtrSrc & PAGE_OFFSET_MASK), cb);
1397 return VINF_SUCCESS;
1398 }
1399 }
1400
1401 /* next */
1402 pCur = CTXALLSUFF(pCur->pNext);
1403 }
1404
1405 return VERR_INVALID_POINTER;
1406}
1407
1408
1409/**
1410 * Info callback for 'pgmhandlers'.
1411 *
1412 * @param pHlp The output helpers.
1413 * @param pszArgs The arguments. phys or virt.
1414 */
1415DECLCALLBACK(void) pgmR3MapInfo(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
1416{
1417 NOREF(pszArgs);
1418 if (!pgmMapAreMappingsEnabled(pVM))
1419 pHlp->pfnPrintf(pHlp, "\nThe mappings are DISABLED.\n");
1420 else if (pVM->pgm.s.fMappingsFixed)
1421 pHlp->pfnPrintf(pHlp, "\nThe mappings are FIXED: %RGv-%RGv\n",
1422 pVM->pgm.s.GCPtrMappingFixed, pVM->pgm.s.GCPtrMappingFixed + pVM->pgm.s.cbMappingFixed - 1);
1423 else if (pVM->pgm.s.fMappingsFixedRestored)
1424 pHlp->pfnPrintf(pHlp, "\nThe mappings are FLOATING-RESTORED-FIXED: %RGv-%RGv\n",
1425 pVM->pgm.s.GCPtrMappingFixed, pVM->pgm.s.GCPtrMappingFixed + pVM->pgm.s.cbMappingFixed - 1);
1426 else
1427 pHlp->pfnPrintf(pHlp, "\nThe mappings are FLOATING.\n");
1428
1429 PPGMMAPPING pCur;
1430 for (pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1431 {
1432 pHlp->pfnPrintf(pHlp, "%RGv - %RGv %s\n", pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc);
1433 if (pCur->cConflicts > 0)
1434 {
1435 pHlp->pfnPrintf(pHlp, " %u conflict%s: ", pCur->cConflicts, pCur->cConflicts == 1 ? "" : "s");
1436 uint32_t cLeft = RT_MIN(pCur->cConflicts, RT_ELEMENTS(pCur->aGCPtrConflicts));
1437 uint32_t i = pCur->cConflicts;
1438 while (cLeft-- > 0)
1439 {
1440 i = (i - 1) & (PGMMAPPING_CONFLICT_MAX - 1);
1441 pHlp->pfnPrintf(pHlp, cLeft ? "%RGv, " : "%RGv\n", pCur->aGCPtrConflicts[i]);
1442 }
1443 }
1444 }
1445}
1446
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use