VirtualBox

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

Last change on this file since 74795 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use