VirtualBox

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

Last change on this file since 1995 was 1578, checked in by vboxsync, 18 years ago

style

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