VirtualBox

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

Last change on this file since 4050 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 40.5 KB
Line 
1/* $Id: PGMMap.cpp 2981 2007-06-01 16:01:28Z vboxsync $ */
2/** @file
3 * PGM - Page Manager, Guest Context Mappings.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_PGM
27#include <VBox/dbgf.h>
28#include <VBox/pgm.h>
29#include "PGMInternal.h"
30#include <VBox/vm.h>
31
32#include <VBox/log.h>
33#include <VBox/err.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/string.h>
37
38
39/*******************************************************************************
40* Internal Functions *
41*******************************************************************************/
42static void pgmR3MapClearPDEs(PPGM pPGM, PPGMMAPPING pMap, int iOldPDE);
43static void pgmR3MapSetPDEs(PVM pVM, PPGMMAPPING pMap, int iNewPDE);
44static DECLCALLBACK(int) pgmR3DumpMappingsPhysicalCB(PAVLROGCPHYSNODECORE pNode, void *pvUser);
45static int pgmR3MapIntermediateCheckOne(PVM pVM, uintptr_t uAddress, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault);
46static void pgmR3MapIntermediateDoOne(PVM pVM, uintptr_t uAddress, RTHCPHYS HCPhys, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault);
47
48
49
50/**
51 * Creates a page table based mapping in GC.
52 *
53 * @returns VBox status code.
54 * @param pVM VM Handle.
55 * @param GCPtr Virtual Address. (Page table aligned!)
56 * @param cb Size of the range. Must be a 4MB aligned!
57 * @param pfnRelocate Relocation callback function.
58 * @param pvUser User argument to the callback.
59 * @param pszDesc Pointer to description string. This must not be freed.
60 */
61PGMR3DECL(int) PGMR3MapPT(PVM pVM, RTGCPTR GCPtr, size_t cb, PFNPGMRELOCATE pfnRelocate, void *pvUser, const char *pszDesc)
62{
63 LogFlow(("PGMR3MapPT: GCPtr=%#x cb=%d pfnRelocate=%p pvUser=%p pszDesc=%s\n", GCPtr, cb, pfnRelocate, pvUser, pszDesc));
64 AssertMsg(pVM->pgm.s.pInterPD && pVM->pgm.s.pHC32BitPD, ("Paging isn't initialized, init order problems!\n"));
65
66 /*
67 * Validate input.
68 */
69 if (cb < _2M || cb > 64 * _1M)
70 {
71 AssertMsgFailed(("Serious? cb=%d\n", cb));
72 return VERR_INVALID_PARAMETER;
73 }
74 cb = RT_ALIGN_Z(cb, _4M);
75 RTGCPTR GCPtrLast = GCPtr + cb - 1;
76 if (GCPtrLast < GCPtr)
77 {
78 AssertMsgFailed(("Range wraps! GCPtr=%x GCPtrLast=%x\n", GCPtr, GCPtrLast));
79 return VERR_INVALID_PARAMETER;
80 }
81 if (pVM->pgm.s.fMappingsFixed)
82 {
83 AssertMsgFailed(("Mappings are fixed! It's not possible to add new mappings at this time!\n"));
84 return VERR_PGM_MAPPINGS_FIXED;
85 }
86 if (!pfnRelocate)
87 {
88 AssertMsgFailed(("Callback is required\n"));
89 return VERR_INVALID_PARAMETER;
90 }
91
92 /*
93 * Find list location.
94 */
95 PPGMMAPPING pPrev = NULL;
96 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
97 while (pCur)
98 {
99 if (pCur->GCPtrLast >= GCPtr && pCur->GCPtr <= GCPtrLast)
100 {
101 AssertMsgFailed(("Address is already in use by %s. req %#x-%#x take %#x-%#x\n",
102 pCur->pszDesc, GCPtr, GCPtrLast, pCur->GCPtr, pCur->GCPtrLast));
103 LogRel(("VERR_PGM_MAPPING_CONFLICT: Address is already in use by %s. req %#x-%#x take %#x-%#x\n",
104 pCur->pszDesc, GCPtr, GCPtrLast, pCur->GCPtr, pCur->GCPtrLast));
105 return VERR_PGM_MAPPING_CONFLICT;
106 }
107 if (pCur->GCPtr > GCPtr)
108 break;
109 pPrev = pCur;
110 pCur = pCur->pNextR3;
111 }
112
113 /*
114 * Check for conflicts with intermediate mappings.
115 */
116 const unsigned iPageDir = GCPtr >> PGDIR_SHIFT;
117 const unsigned cPTs = cb >> PGDIR_SHIFT;
118 unsigned i;
119 for (i = 0; i < cPTs; i++)
120 {
121 if (pVM->pgm.s.pInterPD->a[iPageDir + i].n.u1Present)
122 {
123 AssertMsgFailed(("Address %#x is already in use by an intermediate mapping.\n", GCPtr + (i << PAGE_SHIFT)));
124 LogRel(("VERR_PGM_MAPPING_CONFLICT: Address %#x is already in use by an intermediate mapping.\n", GCPtr + (i << PAGE_SHIFT)));
125 return VERR_PGM_MAPPING_CONFLICT;
126 }
127 }
128 /** @todo AMD64: add check in PAE structures too, so we can remove all the 32-Bit paging stuff there. */
129
130 /*
131 * Allocate and initialize the new list node.
132 */
133 PPGMMAPPING pNew;
134 int rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMMAPPING, aPTs[cPTs]), 0, MM_TAG_PGM, (void **)&pNew);
135 if (VBOX_FAILURE(rc))
136 return rc;
137 pNew->GCPtr = GCPtr;
138 pNew->GCPtrLast = GCPtrLast;
139 pNew->cb = cb;
140 pNew->pszDesc = pszDesc;
141 pNew->pfnRelocate = pfnRelocate;
142 pNew->pvUser = pvUser;
143 pNew->cPTs = cPTs;
144
145 /*
146 * Allocate page tables and insert them into the page directories.
147 * (One 32-bit PT and two PAE PTs.)
148 */
149 uint8_t *pbPTs;
150 rc = MMHyperAlloc(pVM, PAGE_SIZE * 3 * cPTs, PAGE_SIZE, MM_TAG_PGM, (void **)&pbPTs);
151 if (VBOX_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=%VGv cPTs=%u pbPTs=%p\n", GCPtr, cPTs, pbPTs));
161 for (i = 0; i < cPTs; i++)
162 {
163 /*
164 * 32-bit.
165 */
166 pNew->aPTs[i].pPTR3 = (PVBOXPT)pbPTs;
167 pNew->aPTs[i].pPTGC = MMHyperR3ToGC(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: pPTHC=%p pPTGC=%p HCPhysPT=%RHp\n",
172 i, pNew->aPTs[i].pPTR3, pNew->aPTs[i].pPTGC, 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 = (PX86PTPAE)pbPTs;
180 pNew->aPTs[i].paPaePTsGC = MMHyperR3ToGC(pVM, pbPTs);
181 pNew->aPTs[i].paPaePTsR0 = MMHyperR3ToR0(pVM, pbPTs);
182 pbPTs += PAGE_SIZE * 2;
183 Log4(("PGMR3MapPT: i=%d: paPaePTsHC=%p paPaePTsGC=%p HCPhysPaePT0=%RHp HCPhysPaePT1=%RHp\n",
184 i, pNew->aPTs[i].paPaePTsR3, pNew->aPTs[i].paPaePTsGC, pNew->aPTs[i].HCPhysPaePT0, pNew->aPTs[i].HCPhysPaePT1));
185 }
186 pgmR3MapSetPDEs(pVM, pNew, iPageDir);
187
188 /*
189 * Insert the new mapping.
190 */
191 pNew->pNextR3 = pCur;
192 pNew->pNextGC = pCur ? MMHyperR3ToGC(pVM, pCur) : 0;
193 pNew->pNextR0 = pCur ? MMHyperR3ToR0(pVM, pCur) : 0;
194 if (pPrev)
195 {
196 pPrev->pNextR3 = pNew;
197 pPrev->pNextGC = MMHyperR3ToGC(pVM, pNew);
198 pPrev->pNextR0 = MMHyperR3ToR0(pVM, pNew);
199 }
200 else
201 {
202 pVM->pgm.s.pMappingsR3 = pNew;
203 pVM->pgm.s.pMappingsGC = MMHyperR3ToGC(pVM, pNew);
204 pVM->pgm.s.pMappingsR0 = MMHyperR3ToR0(pVM, pNew);
205 }
206
207 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
208 return VINF_SUCCESS;
209}
210
211
212/**
213 * Removes a page table based mapping.
214 *
215 * @returns VBox status code.
216 * @param pVM VM Handle.
217 * @param GCPtr Virtual Address. (Page table aligned!)
218 */
219PGMR3DECL(int) PGMR3UnmapPT(PVM pVM, RTGCPTR GCPtr)
220{
221 LogFlow(("PGMR3UnmapPT: GCPtr=%#x\n", GCPtr));
222
223 /*
224 * Find it.
225 */
226 PPGMMAPPING pPrev = NULL;
227 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
228 while (pCur)
229 {
230 if (pCur->GCPtr == GCPtr)
231 {
232 /*
233 * Unlink it.
234 */
235 if (pPrev)
236 {
237 pPrev->pNextR3 = pCur->pNextR3;
238 pPrev->pNextGC = pCur->pNextGC;
239 pPrev->pNextR0 = pCur->pNextR0;
240 }
241 else
242 {
243 pVM->pgm.s.pMappingsR3 = pCur->pNextR3;
244 pVM->pgm.s.pMappingsGC = pCur->pNextGC;
245 pVM->pgm.s.pMappingsR0 = pCur->pNextR0;
246 }
247
248 /*
249 * Free the page table memory, clear page directory entries
250 * and free the page tables and node memory.
251 */
252 MMHyperFree(pVM, pCur->aPTs[0].pPTR3);
253 pgmR3MapClearPDEs(&pVM->pgm.s, pCur, pCur->GCPtr >> PGDIR_SHIFT);
254 MMHyperFree(pVM, pCur);
255
256 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
257 return VINF_SUCCESS;
258 }
259
260 /* done? */
261 if (pCur->GCPtr > GCPtr)
262 break;
263
264 /* next */
265 pPrev = pCur;
266 pCur = pCur->pNextR3;
267 }
268
269 AssertMsgFailed(("No mapping for %#x found!\n", GCPtr));
270 return VERR_INVALID_PARAMETER;
271}
272
273
274/**
275 * Gets the size of the current guest mappings if they were to be
276 * put next to oneanother.
277 *
278 * @returns VBox status code.
279 * @param pVM The VM.
280 * @param pcb Where to store the size.
281 */
282PGMR3DECL(int) PGMR3MappingsSize(PVM pVM, size_t *pcb)
283{
284 size_t cb = 0;
285 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
286 cb += pCur->cb;
287
288 *pcb = cb;
289 Log(("PGMR3MappingsSize: return %d (%#x) bytes\n", cb, cb));
290 return VINF_SUCCESS;
291}
292
293
294/**
295 * Fixes the guest context mappings in a range reserved from the Guest OS.
296 *
297 * @returns VBox status code.
298 * @param pVM The VM.
299 * @param GCPtrBase The address of the reserved range of guest memory.
300 * @param cb The size of the range starting at GCPtrBase.
301 */
302PGMR3DECL(int) PGMR3MappingsFix(PVM pVM, RTGCPTR GCPtrBase, size_t cb)
303{
304 Log(("PGMR3MappingsFix: GCPtrBase=%#x cb=%#x\n", GCPtrBase, cb));
305
306 /*
307 * This is all or nothing at all. So, a tiny bit of paranoia first.
308 */
309 if (GCPtrBase & PAGE_OFFSET_MASK_BIG)
310 {
311 AssertMsgFailed(("GCPtrBase (%#x) has to be aligned on a 4MB address!\n", GCPtrBase));
312 return VERR_INVALID_PARAMETER;
313 }
314 if (!cb || (cb & PAGE_OFFSET_MASK_BIG))
315 {
316 AssertMsgFailed(("cb (%#x) is 0 or not aligned on a 4MB address!\n", cb));
317 return VERR_INVALID_PARAMETER;
318 }
319
320 /*
321 * Before we do anything we'll do a forced PD sync to try make sure any
322 * pending relocations because of these mappings have been resolved.
323 */
324 PGMSyncCR3(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR3(pVM), CPUMGetGuestCR4(pVM), true);
325
326 /*
327 * Check that it's not conflicting with a core code mapping in the intermediate page table.
328 */
329 unsigned iPDNew = GCPtrBase >> PGDIR_SHIFT;
330 unsigned i = cb >> PGDIR_SHIFT;
331 while (i-- > 0)
332 {
333 if (pVM->pgm.s.pInterPD->a[iPDNew + i].n.u1Present)
334 {
335 /* Check that it's not one or our mappings. */
336 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
337 while (pCur)
338 {
339 if (iPDNew + i - (pCur->GCPtr >> PGDIR_SHIFT) < (pCur->cb >> PGDIR_SHIFT))
340 break;
341 pCur = pCur->pNextR3;
342 }
343 if (!pCur)
344 {
345 LogRel(("PGMR3MappingsFix: Conflicts with intermediate PDE %#x (GCPtrBase=%VGv cb=%#zx). The guest should retry.\n",
346 iPDNew + i, GCPtrBase, cb));
347 return VERR_PGM_MAPPINGS_FIX_CONFLICT;
348 }
349 }
350 }
351
352 /*
353 * Loop the mappings and check that they all agree on their new locations.
354 */
355 RTGCPTR GCPtrCur = GCPtrBase;
356 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
357 while (pCur)
358 {
359 if (!pCur->pfnRelocate(pVM, pCur->GCPtr, GCPtrCur, PGMRELOCATECALL_SUGGEST, pCur->pvUser))
360 {
361 AssertMsgFailed(("The suggested fixed address %#x was rejected by '%s'!\n", GCPtrCur, pCur->pszDesc));
362 return VERR_PGM_MAPPINGS_FIX_REJECTED;
363 }
364 /* next */
365 GCPtrCur += pCur->cb;
366 pCur = pCur->pNextR3;
367 }
368 if (GCPtrCur > GCPtrBase + cb)
369 {
370 AssertMsgFailed(("cb (%#x) is less than the required range %#x!\n", cb, GCPtrCur - GCPtrBase));
371 return VERR_PGM_MAPPINGS_FIX_TOO_SMALL;
372 }
373
374 /*
375 * Loop the table assigning the mappings to the passed in memory
376 * and call their relocator callback.
377 */
378 GCPtrCur = GCPtrBase;
379 pCur = pVM->pgm.s.pMappingsR3;
380 while (pCur)
381 {
382 unsigned iPDOld = pCur->GCPtr >> PGDIR_SHIFT;
383 iPDNew = GCPtrCur >> PGDIR_SHIFT;
384
385 /*
386 * Relocate the page table(s).
387 */
388 pgmR3MapClearPDEs(&pVM->pgm.s, pCur, iPDOld);
389 pgmR3MapSetPDEs(pVM, pCur, iPDNew);
390
391 /*
392 * Update the entry.
393 */
394 pCur->GCPtr = GCPtrCur;
395 pCur->GCPtrLast = GCPtrCur + pCur->cb - 1;
396
397 /*
398 * Callback to execute the relocation.
399 */
400 pCur->pfnRelocate(pVM, iPDOld << PGDIR_SHIFT, iPDNew << PGDIR_SHIFT, PGMRELOCATECALL_RELOCATE, pCur->pvUser);
401
402 /*
403 * Advance.
404 */
405 GCPtrCur += pCur->cb;
406 pCur = pCur->pNextR3;
407 }
408
409 /*
410 * Turn off CR3 updating monitoring.
411 */
412 int rc2 = PGM_GST_PFN(UnmonitorCR3, pVM)(pVM);
413 AssertRC(rc2);
414
415 /*
416 * Mark the mappings as fixed and return.
417 */
418 pVM->pgm.s.fMappingsFixed = true;
419 pVM->pgm.s.GCPtrMappingFixed = GCPtrBase;
420 pVM->pgm.s.cbMappingFixed = cb;
421 pVM->pgm.s.fSyncFlags &= ~PGM_SYNC_MONITOR_CR3;
422 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
423 return VINF_SUCCESS;
424}
425
426
427/**
428 * Unfixes the mappings.
429 * After calling this function mapping conflict detection will be enabled.
430 *
431 * @returns VBox status code.
432 * @param pVM The VM.
433 */
434PGMR3DECL(int) PGMR3MappingsUnfix(PVM pVM)
435{
436 Log(("PGMR3MappingsUnfix: fMappingsFixed=%d\n", pVM->pgm.s.fMappingsFixed));
437 pVM->pgm.s.fMappingsFixed = false;
438 pVM->pgm.s.GCPtrMappingFixed = 0;
439 pVM->pgm.s.cbMappingFixed = 0;
440 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
441
442 /*
443 * Re-enable the CR3 monitoring.
444 *
445 * Paranoia: We flush the page pool before doing that because Windows
446 * is using the CR3 page both as a PD and a PT, e.g. the pool may
447 * be monitoring it.
448 */
449#ifdef PGMPOOL_WITH_MONITORING
450 pgmPoolFlushAll(pVM);
451#endif
452 int rc = PGM_GST_PFN(MonitorCR3, pVM)(pVM, pVM->pgm.s.GCPhysCR3);
453 AssertRC(rc);
454
455 return VINF_SUCCESS;
456}
457
458
459/**
460 * Map pages into the intermediate context (switcher code).
461 * These pages are mapped at both the give virtual address and at
462 * the physical address (for identity mapping).
463 *
464 * @returns VBox status code.
465 * @param pVM The virtual machine.
466 * @param Addr Intermediate context address of the mapping.
467 * @param HCPhys Start of the range of physical pages. This must be entriely below 4GB!
468 * @param cbPages Number of bytes to map.
469 *
470 * @remark This API shall not be used to anything but mapping the switcher code.
471 */
472PGMR3DECL(int) PGMR3MapIntermediate(PVM pVM, RTUINTPTR Addr, RTHCPHYS HCPhys, unsigned cbPages)
473{
474 LogFlow(("PGMR3MapIntermediate: Addr=%RTptr HCPhys=%VHp cbPages=%#x\n", Addr, HCPhys, cbPages));
475
476 /*
477 * Adjust input.
478 */
479 cbPages += (uint32_t)HCPhys & PAGE_OFFSET_MASK;
480 cbPages = RT_ALIGN(cbPages, PAGE_SIZE);
481 HCPhys &= X86_PTE_PAE_PG_MASK;
482 Addr &= PAGE_BASE_MASK;
483 /* We only care about the first 4GB, because on AMD64 we'll be repeating them all over the address space. */
484 uint32_t uAddress = (uint32_t)Addr;
485
486 /*
487 * Assert input and state.
488 */
489 AssertMsg(pVM->pgm.s.offVM, ("Bad init order\n"));
490 AssertMsg(pVM->pgm.s.pInterPD, ("Bad init order, paging.\n"));
491 AssertMsg(cbPages <= (512 << PAGE_SHIFT), ("The mapping is too big %d bytes\n", cbPages));
492 AssertMsg(HCPhys < _4G && HCPhys + cbPages < _4G, ("Addr=%RTptr HCPhys=%VHp cbPages=%d\n", Addr, HCPhys, cbPages));
493
494 /*
495 * Check for internal conflicts between the virtual address and the physical address.
496 */
497 if ( uAddress != HCPhys
498 && ( uAddress < HCPhys
499 ? HCPhys - uAddress < cbPages
500 : uAddress - HCPhys < cbPages
501 )
502 )
503 {
504 AssertMsgFailed(("Addr=%RTptr HCPhys=%VHp cbPages=%d\n", Addr, HCPhys, cbPages));
505 LogRel(("Addr=%RTptr HCPhys=%VHp cbPages=%d\n", Addr, HCPhys, cbPages));
506 return VERR_PGM_MAPPINGS_FIX_CONFLICT; /** @todo new error code */
507 }
508
509 /* The intermediate mapping must not conflict with our default hypervisor address. */
510 size_t cbHyper;
511 RTGCPTR pvHyperGC = MMHyperGetArea(pVM, &cbHyper);
512 if (uAddress < pvHyperGC
513 ? uAddress + cbPages > pvHyperGC
514 : pvHyperGC + cbHyper > uAddress
515 )
516 {
517 AssertMsgFailed(("Addr=%RTptr HyperGC=%VGv cbPages=%zu\n", Addr, pvHyperGC, cbPages));
518 LogRel(("Addr=%RTptr HyperGC=%VGv cbPages=%zu\n", Addr, pvHyperGC, cbPages));
519 return VERR_PGM_MAPPINGS_FIX_CONFLICT; /** @todo new error code */
520 }
521
522 const unsigned cPages = cbPages >> PAGE_SHIFT;
523 int rc = pgmR3MapIntermediateCheckOne(pVM, uAddress, cPages, pVM->pgm.s.apInterPTs[0], pVM->pgm.s.apInterPaePTs[0]);
524 if (VBOX_FAILURE(rc))
525 return rc;
526 rc = pgmR3MapIntermediateCheckOne(pVM, (uintptr_t)HCPhys, cPages, pVM->pgm.s.apInterPTs[1], pVM->pgm.s.apInterPaePTs[1]);
527 if (VBOX_FAILURE(rc))
528 return rc;
529
530 /*
531 * Everythings fine, do the mapping.
532 */
533 pgmR3MapIntermediateDoOne(pVM, uAddress, HCPhys, cPages, pVM->pgm.s.apInterPTs[0], pVM->pgm.s.apInterPaePTs[0]);
534 pgmR3MapIntermediateDoOne(pVM, (uintptr_t)HCPhys, HCPhys, cPages, pVM->pgm.s.apInterPTs[1], pVM->pgm.s.apInterPaePTs[1]);
535
536 return VINF_SUCCESS;
537}
538
539
540/**
541 * Validates that there are no conflicts for this mapping into the intermediate context.
542 *
543 * @returns VBox status code.
544 * @param pVM VM handle.
545 * @param uAddress Address of the mapping.
546 * @param cPages Number of pages.
547 * @param pPTDefault Pointer to the default page table for this mapping.
548 * @param pPTPaeDefault Pointer to the default page table for this mapping.
549 */
550static int pgmR3MapIntermediateCheckOne(PVM pVM, uintptr_t uAddress, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault)
551{
552 AssertMsg((uAddress >> X86_PD_SHIFT) + cPages <= 1024, ("64-bit fixme\n"));
553
554 /*
555 * Check that the ranges are available.
556 * (This codes doesn't have to be fast.)
557 */
558 while (cPages > 0)
559 {
560 /*
561 * 32-Bit.
562 */
563 unsigned iPDE = (uAddress >> X86_PD_SHIFT) & X86_PD_MASK;
564 unsigned iPTE = (uAddress >> X86_PT_SHIFT) & X86_PT_MASK;
565 PX86PT pPT = pPTDefault;
566 if (pVM->pgm.s.pInterPD->a[iPDE].u)
567 {
568 RTHCPHYS HCPhysPT = pVM->pgm.s.pInterPD->a[iPDE].u & X86_PDE_PG_MASK;
569 if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPTs[0]))
570 pPT = pVM->pgm.s.apInterPTs[0];
571 else if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPTs[1]))
572 pPT = pVM->pgm.s.apInterPTs[1];
573 else
574 {
575 /** @todo this must be handled with a relocation of the conflicting mapping!
576 * Which of course cannot be done because we're in the middle of the initialization. bad design! */
577 AssertMsgFailed(("Conflict between core code and PGMR3Mapping(). uAddress=%VHv\n", uAddress));
578 LogRel(("Conflict between core code and PGMR3Mapping(). uAddress=%VHv\n", uAddress));
579 return VERR_PGM_MAPPINGS_FIX_CONFLICT; /** @todo error codes! */
580 }
581 }
582 if (pPT->a[iPTE].u)
583 {
584 AssertMsgFailed(("Conflict iPTE=%#x iPDE=%#x uAddress=%VHv pPT->a[iPTE].u=%RX32\n", iPTE, iPDE, uAddress, pPT->a[iPTE].u));
585 LogRel(("Conflict iPTE=%#x iPDE=%#x uAddress=%VHv pPT->a[iPTE].u=%RX32\n",
586 iPTE, iPDE, uAddress, pPT->a[iPTE].u));
587 return VERR_PGM_MAPPINGS_FIX_CONFLICT; /** @todo error codes! */
588 }
589
590 /*
591 * PAE.
592 */
593 const unsigned iPDPE= (uAddress >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK;
594 iPDE = (uAddress >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
595 iPTE = (uAddress >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
596 Assert(iPDPE < 4);
597 Assert(pVM->pgm.s.apInterPaePDs[iPDPE]);
598 PX86PTPAE pPTPae = pPTPaeDefault;
599 if (pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u)
600 {
601 RTHCPHYS HCPhysPT = pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u & X86_PDE_PAE_PG_MASK;
602 if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPaePTs[0]))
603 pPTPae = pVM->pgm.s.apInterPaePTs[0];
604 else if (HCPhysPT == MMPage2Phys(pVM, pVM->pgm.s.apInterPaePTs[0]))
605 pPTPae = pVM->pgm.s.apInterPaePTs[1];
606 else
607 {
608 /** @todo this must be handled with a relocation of the conflicting mapping!
609 * Which of course cannot be done because we're in the middle of the initialization. bad design! */
610 AssertMsgFailed(("Conflict between core code and PGMR3Mapping(). uAddress=%VHv\n", uAddress));
611 LogRel(("Conflict between core code and PGMR3Mapping(). uAddress=%VHv\n", uAddress));
612 return VERR_PGM_MAPPINGS_FIX_CONFLICT; /** @todo error codes! */
613 }
614 }
615 if (pPTPae->a[iPTE].u)
616 {
617 AssertMsgFailed(("Conflict iPTE=%#x iPDE=%#x uAddress=%VHv pPTPae->a[iPTE].u=%#RX64\n", iPTE, iPDE, uAddress, pPTPae->a[iPTE].u));
618 LogRel(("Conflict iPTE=%#x iPDE=%#x uAddress=%VHv pPTPae->a[iPTE].u=%#RX64\n",
619 iPTE, iPDE, uAddress, pPTPae->a[iPTE].u));
620 return VERR_PGM_MAPPINGS_FIX_CONFLICT; /** @todo error codes! */
621 }
622
623 /* next */
624 uAddress += PAGE_SIZE;
625 cPages--;
626 }
627
628 return VINF_SUCCESS;
629}
630
631
632
633/**
634 * Sets up the intermediate page tables for a verified mapping.
635 *
636 * @param pVM VM handle.
637 * @param uAddress Address of the mapping.
638 * @param HCPhys The physical address of the page range.
639 * @param cPages Number of pages.
640 * @param pPTDefault Pointer to the default page table for this mapping.
641 * @param pPTPaeDefault Pointer to the default page table for this mapping.
642 */
643static void pgmR3MapIntermediateDoOne(PVM pVM, uintptr_t uAddress, RTHCPHYS HCPhys, unsigned cPages, PX86PT pPTDefault, PX86PTPAE pPTPaeDefault)
644{
645 while (cPages > 0)
646 {
647 /*
648 * 32-Bit.
649 */
650 unsigned iPDE = (uAddress >> X86_PD_SHIFT) & X86_PD_MASK;
651 unsigned iPTE = (uAddress >> X86_PT_SHIFT) & X86_PT_MASK;
652 PX86PT pPT;
653 if (pVM->pgm.s.pInterPD->a[iPDE].u)
654 pPT = (PX86PT)MMPagePhys2Page(pVM, pVM->pgm.s.pInterPD->a[iPDE].u & X86_PDE_PG_MASK);
655 else
656 {
657 pVM->pgm.s.pInterPD->a[iPDE].u = X86_PDE_P | X86_PDE_A | X86_PDE_RW
658 | (uint32_t)MMPage2Phys(pVM, pPTDefault);
659 pPT = pPTDefault;
660 }
661 pPT->a[iPTE].u = X86_PTE_P | X86_PTE_RW | X86_PTE_A | X86_PTE_D | (uint32_t)HCPhys;
662
663 /*
664 * PAE
665 */
666 const unsigned iPDPE= (uAddress >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK;
667 iPDE = (uAddress >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
668 iPTE = (uAddress >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
669 Assert(iPDPE < 4);
670 Assert(pVM->pgm.s.apInterPaePDs[iPDPE]);
671 PX86PTPAE pPTPae;
672 if (pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u)
673 pPTPae = (PX86PTPAE)MMPagePhys2Page(pVM, pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u & X86_PDE_PAE_PG_MASK);
674 else
675 {
676 pPTPae = pPTPaeDefault;
677 pVM->pgm.s.apInterPaePDs[iPDPE]->a[iPDE].u = X86_PDE_P | X86_PDE_A | X86_PDE_RW
678 | MMPage2Phys(pVM, pPTPaeDefault);
679 }
680 pPTPae->a[iPTE].u = X86_PTE_P | X86_PTE_RW | X86_PTE_A | X86_PTE_D | HCPhys;
681
682 /* next */
683 cPages--;
684 HCPhys += PAGE_SIZE;
685 uAddress += PAGE_SIZE;
686 }
687}
688
689
690/**
691 * Clears all PDEs involved with the mapping.
692 *
693 * @param pPGM Pointer to the PGM instance data.
694 * @param pMap Pointer to the mapping in question.
695 * @param iOldPDE The index of the 32-bit PDE corresponding to the base of the mapping.
696 */
697static void pgmR3MapClearPDEs(PPGM pPGM, PPGMMAPPING pMap, int iOldPDE)
698{
699 unsigned i = pMap->cPTs;
700 iOldPDE += i;
701 while (i-- > 0)
702 {
703 iOldPDE--;
704
705 /*
706 * 32-bit.
707 */
708 pPGM->pInterPD->a[iOldPDE].u = 0;
709 pPGM->pHC32BitPD->a[iOldPDE].u = 0;
710
711 /*
712 * PAE.
713 */
714 const int iPD = iOldPDE / 256;
715 int iPDE = iOldPDE * 2 % 512;
716 pPGM->apInterPaePDs[iPD]->a[iPDE].u = 0;
717 pPGM->apHCPaePDs[iPD]->a[iPDE].u = 0;
718 iPDE++;
719 pPGM->apInterPaePDs[iPD]->a[iPDE].u = 0;
720 pPGM->apHCPaePDs[iPD]->a[iPDE].u = 0;
721 }
722}
723
724
725/**
726 * Sets all PDEs involved with the mapping.
727 *
728 * @param pVM The VM handle.
729 * @param pMap Pointer to the mapping in question.
730 * @param iNewPDE The index of the 32-bit PDE corresponding to the base of the mapping.
731 */
732static void pgmR3MapSetPDEs(PVM pVM, PPGMMAPPING pMap, int iNewPDE)
733{
734 PPGM pPGM = &pVM->pgm.s;
735
736 /* If mappings are not supposed to be put in the shadow page table, then this function is a nop. */
737 if (!pgmMapAreMappingsEnabled(&pVM->pgm.s))
738 return;
739
740 /*
741 * Init the page tables and insert them into the page directories.
742 */
743 unsigned i = pMap->cPTs;
744 iNewPDE += i;
745 while (i-- > 0)
746 {
747 iNewPDE--;
748
749 /*
750 * 32-bit.
751 */
752 if (pPGM->pHC32BitPD->a[iNewPDE].n.u1Present)
753 pgmPoolFree(pVM, pPGM->pHC32BitPD->a[iNewPDE].n.u1Present & X86_PDE_PG_MASK, PGMPOOL_IDX_PD, iNewPDE);
754 X86PDE Pde;
755 /* Default mapping page directory flags are read/write and supervisor; individual page attributes determine the final flags */
756 Pde.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | (uint32_t)pMap->aPTs[i].HCPhysPT;
757 pPGM->pInterPD->a[iNewPDE] = Pde;
758 pPGM->pHC32BitPD->a[iNewPDE] = Pde;
759
760 /*
761 * PAE.
762 */
763 const int iPD = iNewPDE / 256;
764 int iPDE = iNewPDE * 2 % 512;
765 if (pPGM->apHCPaePDs[iPD]->a[iPDE].n.u1Present)
766 pgmPoolFree(pVM, pPGM->apHCPaePDs[iPD]->a[iPDE].n.u1Present & X86_PDE_PAE_PG_MASK, PGMPOOL_IDX_PAE_PD, iNewPDE * 2);
767 X86PDEPAE PdePae0;
768 PdePae0.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT0;
769 pPGM->apInterPaePDs[iPD]->a[iPDE] = PdePae0;
770 pPGM->apHCPaePDs[iPD]->a[iPDE] = PdePae0;
771
772 iPDE++;
773 if (pPGM->apHCPaePDs[iPD]->a[iPDE].n.u1Present)
774 pgmPoolFree(pVM, pPGM->apHCPaePDs[iPD]->a[iPDE].n.u1Present & X86_PDE_PAE_PG_MASK, PGMPOOL_IDX_PAE_PD, iNewPDE * 2 + 1);
775 X86PDEPAE PdePae1;
776 PdePae1.u = PGM_PDFLAGS_MAPPING | X86_PDE_P | X86_PDE_A | X86_PDE_RW | X86_PDE_US | pMap->aPTs[i].HCPhysPaePT1;
777 pPGM->apInterPaePDs[iPD]->a[iPDE] = PdePae1;
778 pPGM->apHCPaePDs[iPD]->a[iPDE] = PdePae1;
779 }
780}
781
782/**
783 * Relocates a mapping to a new address.
784 *
785 * @param pVM VM handle.
786 * @param pMapping The mapping to relocate.
787 * @param iPDOld Old page directory index.
788 * @param iPDNew New page directory index.
789 */
790void pgmR3MapRelocate(PVM pVM, PPGMMAPPING pMapping, int iPDOld, int iPDNew)
791{
792 Log(("PGM: Relocating %s from %#x to %#x\n", pMapping->pszDesc, iPDOld << PGDIR_SHIFT, iPDNew << PGDIR_SHIFT));
793 Assert(((unsigned)iPDOld << PGDIR_SHIFT) == pMapping->GCPtr);
794
795 /*
796 * Relocate the page table(s).
797 */
798 pgmR3MapClearPDEs(&pVM->pgm.s, pMapping, iPDOld);
799 pgmR3MapSetPDEs(pVM, pMapping, iPDNew);
800
801 /*
802 * Update and resort the mapping list.
803 */
804
805 /* Find previous mapping for pMapping, put result into pPrevMap. */
806 PPGMMAPPING pPrevMap = NULL;
807 PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3;
808 while (pCur && pCur != pMapping)
809 {
810 /* next */
811 pPrevMap = pCur;
812 pCur = pCur->pNextR3;
813 }
814 Assert(pCur);
815
816 /* Find mapping which >= than pMapping. */
817 RTGCPTR GCPtrNew = iPDNew << PGDIR_SHIFT;
818 PPGMMAPPING pPrev = NULL;
819 pCur = pVM->pgm.s.pMappingsR3;
820 while (pCur && pCur->GCPtr < GCPtrNew)
821 {
822 /* next */
823 pPrev = pCur;
824 pCur = pCur->pNextR3;
825 }
826
827 if (pCur != pMapping && pPrev != pMapping)
828 {
829 /*
830 * Unlink.
831 */
832 if (pPrevMap)
833 {
834 pPrevMap->pNextR3 = pMapping->pNextR3;
835 pPrevMap->pNextGC = pMapping->pNextGC;
836 pPrevMap->pNextR0 = pMapping->pNextR0;
837 }
838 else
839 {
840 pVM->pgm.s.pMappingsR3 = pMapping->pNextR3;
841 pVM->pgm.s.pMappingsGC = pMapping->pNextGC;
842 pVM->pgm.s.pMappingsR0 = pMapping->pNextR0;
843 }
844
845 /*
846 * Link
847 */
848 pMapping->pNextR3 = pCur;
849 if (pPrev)
850 {
851 pMapping->pNextGC = pPrev->pNextGC;
852 pMapping->pNextR0 = pPrev->pNextR0;
853 pPrev->pNextR3 = pMapping;
854 pPrev->pNextGC = MMHyperR3ToGC(pVM, pMapping);
855 pPrev->pNextR0 = MMHyperR3ToR0(pVM, pMapping);
856 }
857 else
858 {
859 pMapping->pNextGC = pVM->pgm.s.pMappingsGC;
860 pMapping->pNextR0 = pVM->pgm.s.pMappingsR0;
861 pVM->pgm.s.pMappingsR3 = pMapping;
862 pVM->pgm.s.pMappingsGC = MMHyperR3ToGC(pVM, pMapping);
863 pVM->pgm.s.pMappingsR0 = MMHyperR3ToR0(pVM, pMapping);
864 }
865 }
866
867 /*
868 * Update the entry.
869 */
870 pMapping->GCPtr = GCPtrNew;
871 pMapping->GCPtrLast = GCPtrNew + pMapping->cb - 1;
872
873 /*
874 * Callback to execute the relocation.
875 */
876 pMapping->pfnRelocate(pVM, iPDOld << PGDIR_SHIFT, iPDNew << PGDIR_SHIFT, PGMRELOCATECALL_RELOCATE, pMapping->pvUser);
877}
878
879
880/**
881 * Resolves a conflict between a page table based GC mapping and
882 * the Guest OS page tables.
883 *
884 * @returns VBox status code.
885 * @param pVM VM Handle.
886 * @param pMapping The mapping which conflicts.
887 * @param pPDSrc The page directory of the guest OS.
888 * @param iPDOld The index to the start of the current mapping.
889 */
890int pgmR3SyncPTResolveConflict(PVM pVM, PPGMMAPPING pMapping, PVBOXPD pPDSrc, int iPDOld)
891{
892 STAM_PROFILE_START(&pVM->pgm.s.StatHCResolveConflict, a);
893
894 /*
895 * Scan for free page directory entries.
896 *
897 * Note that we do not support mappings at the very end of the
898 * address space since that will break our GCPtrEnd assumptions.
899 */
900 const unsigned cPTs = pMapping->cPTs;
901 unsigned iPDNew = ELEMENTS(pPDSrc->a) - cPTs; /* (+ 1 - 1) */
902 while (iPDNew-- > 0)
903 {
904 if (pPDSrc->a[iPDNew].n.u1Present)
905 continue;
906 if (cPTs > 1)
907 {
908 bool fOk = true;
909 for (unsigned i = 1; fOk && i < cPTs; i++)
910 if (pPDSrc->a[iPDNew + i].n.u1Present)
911 fOk = false;
912 if (!fOk)
913 continue;
914 }
915
916 /*
917 * Check that it's not conflicting with an intermediate page table mapping.
918 */
919 bool fOk = true;
920 unsigned i = cPTs;
921 while (fOk && i-- > 0)
922 fOk = !pVM->pgm.s.pInterPD->a[iPDNew + i].n.u1Present;
923 if (!fOk)
924 continue;
925 /** @todo AMD64 should check the PAE directories and skip the 32bit stuff. */
926
927 /*
928 * Ask the mapping.
929 */
930 if (pMapping->pfnRelocate(pVM, iPDOld << PGDIR_SHIFT, iPDNew << PGDIR_SHIFT, PGMRELOCATECALL_SUGGEST, pMapping->pvUser))
931 {
932 pgmR3MapRelocate(pVM, pMapping, iPDOld, iPDNew);
933 STAM_PROFILE_STOP(&pVM->pgm.s.StatHCResolveConflict, a);
934 return VINF_SUCCESS;
935 }
936 }
937
938 STAM_PROFILE_STOP(&pVM->pgm.s.StatHCResolveConflict, a);
939 AssertMsgFailed(("Failed to relocate page table mapping '%s' from %#x! (cPTs=%d)\n", pMapping->pszDesc, iPDOld << PGDIR_SHIFT, cPTs));
940 return VERR_PGM_NO_HYPERVISOR_ADDRESS;
941}
942
943
944
945/**
946 * Checks guest PD for conflicts with VMM GC mappings.
947 *
948 * @returns true if conflict detected.
949 * @returns false if not.
950 * @param pVM The virtual machine.
951 * @param cr3 Guest context CR3 register.
952 * @param fRawR0 Whether RawR0 is enabled or not.
953 */
954PGMR3DECL(bool) PGMR3MapHasConflicts(PVM pVM, uint32_t cr3, bool fRawR0) /** @todo how many HasConflict constructs do we really need? */
955{
956 /*
957 * Can skip this if mappings are safely fixed.
958 */
959 if (pVM->pgm.s.fMappingsFixed)
960 return false;
961
962 /*
963 * Resolve the page directory.
964 */
965 PVBOXPD pPD = pVM->pgm.s.pGuestPDHC; /** @todo Fix PAE! */
966 Assert(pPD);
967 Assert(pPD == (PVBOXPD)MMPhysGCPhys2HCVirt(pVM, cr3 & X86_CR3_PAGE_MASK, sizeof(*pPD)));
968
969 /*
970 * Iterate mappings.
971 */
972 for (PPGMMAPPING pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
973 {
974 unsigned iPDE = pCur->GCPtr >> PGDIR_SHIFT;
975 unsigned iPT = pCur->cPTs;
976 while (iPT-- > 0)
977 if ( pPD->a[iPDE + iPT].n.u1Present /** @todo PGMGstGetPDE. */
978 && (fRawR0 || pPD->a[iPDE + iPT].n.u1User))
979 {
980 STAM_COUNTER_INC(&pVM->pgm.s.StatHCDetectedConflicts);
981 #if 1
982 Log(("PGMR3HasMappingConflicts: Conflict was detected at %VGv for mapping %s\n"
983 " iPDE=%#x iPT=%#x PDE=%VGp.\n",
984 (iPT + iPDE) << PGDIR_SHIFT, pCur->pszDesc,
985 iPDE, iPT, pPD->a[iPDE + iPT].au32[0]));
986 #else
987 AssertMsgFailed(("PGMR3HasMappingConflicts: Conflict was detected at %VGv for mapping %s\n"
988 " iPDE=%#x iPT=%#x PDE=%VGp.\n",
989 (iPT + iPDE) << PGDIR_SHIFT, pCur->pszDesc,
990 iPDE, iPT, pPD->a[iPDE + iPT].au32[0]));
991 #endif
992 return true;
993 }
994 }
995
996 return false;
997}
998
999
1000/**
1001 * Read memory from the guest mappings.
1002 *
1003 * This will use the page tables associated with the mappings to
1004 * read the memory. This means that not all kind of memory is readable
1005 * since we don't necessarily know how to convert that physical address
1006 * to a HC virtual one.
1007 *
1008 * @returns VBox status.
1009 * @param pVM VM handle.
1010 * @param pvDst The destination address (HC of course).
1011 * @param GCPtrSrc The source address (GC virtual address).
1012 * @param cb Number of bytes to read.
1013 */
1014PGMR3DECL(int) PGMR3MapRead(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb)
1015{
1016/** @todo remove this simplicity hack */
1017 /*
1018 * Simplicity over speed... Chop the request up into chunks
1019 * which don't cross pages.
1020 */
1021 if (cb + (GCPtrSrc & PAGE_OFFSET_MASK) > PAGE_SIZE)
1022 {
1023 for (;;)
1024 {
1025 unsigned cbRead = RT_MIN(cb, PAGE_SIZE - (GCPtrSrc & PAGE_OFFSET_MASK));
1026 int rc = PGMR3MapRead(pVM, pvDst, GCPtrSrc, cbRead);
1027 if (VBOX_FAILURE(rc))
1028 return rc;
1029 cb -= cbRead;
1030 if (!cb)
1031 break;
1032 pvDst = (char *)pvDst + cbRead;
1033 GCPtrSrc += cbRead;
1034 }
1035 return VINF_SUCCESS;
1036 }
1037
1038 /*
1039 * Find the mapping.
1040 */
1041 PPGMMAPPING pCur = CTXALLSUFF(pVM->pgm.s.pMappings);
1042 while (pCur)
1043 {
1044 RTGCUINTPTR off = (RTGCUINTPTR)GCPtrSrc - (RTGCUINTPTR)pCur->GCPtr;
1045 if (off < pCur->cb)
1046 {
1047 if (off + cb > pCur->cb)
1048 {
1049 AssertMsgFailed(("Invalid page range %VGv LB%#x. mapping '%s' %VGv to %VGv\n",
1050 GCPtrSrc, cb, pCur->pszDesc, pCur->GCPtr, pCur->GCPtrLast));
1051 return VERR_INVALID_PARAMETER;
1052 }
1053
1054 unsigned iPT = off >> PGDIR_SHIFT;
1055 unsigned iPTE = (off >> PAGE_SHIFT) & PTE_MASK;
1056 while (cb > 0 && iPTE < ELEMENTS(CTXALLSUFF(pCur->aPTs[iPT].pPT)->a))
1057 {
1058 if (!CTXALLSUFF(pCur->aPTs[iPT].paPaePTs)[iPTE / 512].a[iPTE % 512].n.u1Present)
1059 return VERR_PAGE_NOT_PRESENT;
1060 RTHCPHYS HCPhys = CTXALLSUFF(pCur->aPTs[iPT].paPaePTs)[iPTE / 512].a[iPTE % 512].u & X86_PTE_PAE_PG_MASK;
1061
1062 /*
1063 * Get the virtual page from the physical one.
1064 */
1065 void *pvPage;
1066 int rc = MMR3HCPhys2HCVirt(pVM, HCPhys, &pvPage);
1067 if (VBOX_FAILURE(rc))
1068 return rc;
1069
1070 memcpy(pvDst, (char *)pvPage + (GCPtrSrc & PAGE_OFFSET_MASK), cb);
1071 return VINF_SUCCESS;
1072 }
1073 }
1074
1075 /* next */
1076 pCur = CTXALLSUFF(pCur->pNext);
1077 }
1078
1079 return VERR_INVALID_POINTER;
1080}
1081
1082
1083/**
1084 * Dumps one virtual handler range.
1085 *
1086 * @returns 0
1087 * @param pNode Pointer to a PGMVIRTHANDLER.
1088 * @param pvUser Pointer to command helper functions.
1089 */
1090static DECLCALLBACK(int) pgmVirtHandlerDump(PAVLROGCPTRNODECORE pNode, void *pvUser)
1091{
1092 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
1093
1094 switch (pCur->enmType)
1095 {
1096 case PGMVIRTHANDLERTYPE_EIP:
1097 RTLogPrintf("EIP %RGv-%RGv size %RGv %s\n", pCur->GCPtr, pCur->GCPtrLast, pCur->cb, pCur->pszDesc);
1098 break;
1099 case PGMVIRTHANDLERTYPE_NORMAL:
1100 RTLogPrintf("NORMAL %RGv-%RGv size %RGv %s\n", pCur->GCPtr, pCur->GCPtrLast, pCur->cb, pCur->pszDesc);
1101 break;
1102 case PGMVIRTHANDLERTYPE_WRITE:
1103 RTLogPrintf("WRITE %RGv-%RGv size %RGv %s\n", pCur->GCPtr, pCur->GCPtrLast, pCur->cb, pCur->pszDesc);
1104 break;
1105 case PGMVIRTHANDLERTYPE_HYPERVISOR:
1106 RTLogPrintf("WRITEHYP %RGv-%RGv size %RGv %s\n", pCur->GCPtr, pCur->GCPtrLast, pCur->cb, pCur->pszDesc);
1107 break;
1108 case PGMVIRTHANDLERTYPE_ALL:
1109 RTLogPrintf("ALL %RGv-%RGv size %RGv %s\n", pCur->GCPtr, pCur->GCPtrLast, pCur->cb, pCur->pszDesc);
1110 break;
1111 }
1112 if (pCur->enmType != PGMVIRTHANDLERTYPE_HYPERVISOR)
1113 for (unsigned i = 0; i < pCur->cPages; i++)
1114 RTLogPrintf("Physical page %#05d %VGp\n", i, pCur->aPhysToVirt[i].Core.Key);
1115 return 0;
1116}
1117
1118/**
1119 * Dumps the current mappings to the log
1120 *
1121 * @returns VBox status.
1122 * @param pVM Pointer to the current VM (if any).
1123 *
1124 */
1125PGMR3DECL(void) PGMR3DumpMappings(PVM pVM)
1126{
1127 /*
1128 * Print message about the fixedness of the mappings and dump them.
1129 */
1130 RTLogPrintf(pVM->pgm.s.fMappingsFixed ? "\nThe mappings are FIXED.\n" : "\nThe mappings are FLOATING.\n");
1131
1132 PPGMMAPPING pCur;
1133 for (pCur = pVM->pgm.s.pMappingsR3; pCur; pCur = pCur->pNextR3)
1134 RTLogPrintf("%VGv - %VGv %s\n", pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc);
1135
1136/** @todo The handler stuff is totally alien here. This should be converted into a 'info' function. */
1137 RTLogPrintf("\nVirtual handlers:\n");
1138 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesHC->VirtHandlers, true, pgmVirtHandlerDump, pVM);
1139
1140 RTLogPrintf("\n"
1141 "Physical handlers: (PhysHandlers=%d (%#x))\n"
1142 "From - To (incl) HandlerHC UserHC HandlerHC UserHC HandlerGC UserGC Type Description\n",
1143 pVM->pgm.s.pTreesHC->PhysHandlers, pVM->pgm.s.pTreesHC->PhysHandlers);
1144 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, true, pgmR3DumpMappingsPhysicalCB, NULL);
1145}
1146
1147
1148/**
1149 * Dumps one physical handler range.
1150 *
1151 * @returns 0
1152 * @param pNode Pointer to a PGMPHYSHANDLER.
1153 * @param pvUser Ignored.
1154 */
1155static DECLCALLBACK(int) pgmR3DumpMappingsPhysicalCB(PAVLROGCPHYSNODECORE pNode, void *pvUser)
1156{
1157 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode; NOREF(pvUser);
1158 const char *pszType;
1159 switch (pCur->enmType)
1160 {
1161 case PGMPHYSHANDLERTYPE_MMIO: pszType = "MMIO "; break;
1162 case PGMPHYSHANDLERTYPE_PHYSICAL: pszType = "Natural"; break;
1163 case PGMPHYSHANDLERTYPE_PHYSICAL_WRITE: pszType = "Write "; break;
1164 case PGMPHYSHANDLERTYPE_PHYSICAL_ALL: pszType = "All "; break;
1165 default: pszType = "????"; break;
1166 }
1167 RTLogPrintf("%VGp - %VGp %VHv %VHv %VHv %VHv %VGv %VGv %s %s\n",
1168 pCur->Core.Key, pCur->Core.KeyLast, pCur->pfnHandlerR3, pCur->pvUserR3, pCur->pfnHandlerR0, pCur->pvUserR0,
1169 pCur->pfnHandlerGC, pCur->pvUserGC, pszType, pCur->pszDesc);
1170 return 0;
1171}
1172
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette