VirtualBox

source: vbox/trunk/src/VBox/VMM/PGMHandler.cpp@ 2981

Last change on this file since 2981 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: 21.3 KB
Line 
1/* $Id: PGMHandler.cpp 2981 2007-06-01 16:01:28Z vboxsync $ */
2/** @file
3 * PGM - Page Manager / Monitor, Access Handlers.
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 <VBox/cpum.h>
30#include <VBox/iom.h>
31#include <VBox/sup.h>
32#include <VBox/mm.h>
33#include <VBox/pdm.h>
34#include <VBox/em.h>
35#include <VBox/stam.h>
36#include <VBox/csam.h>
37#include <VBox/rem.h>
38#include <VBox/dbgf.h>
39#include <VBox/rem.h>
40#include <VBox/selm.h>
41#include <VBox/ssm.h>
42#include "PGMInternal.h"
43#include <VBox/vm.h>
44#include <VBox/dbg.h>
45
46#include <VBox/log.h>
47#include <iprt/assert.h>
48#include <iprt/alloc.h>
49#include <iprt/asm.h>
50#include <iprt/thread.h>
51#include <iprt/string.h>
52#include <VBox/param.h>
53#include <VBox/err.h>
54#include <VBox/hwaccm.h>
55
56
57/*******************************************************************************
58* Internal Functions *
59*******************************************************************************/
60static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PAVLROGCPHYSNODECORE pNode, void *pvUser);
61static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser);
62static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser);
63static DECLCALLBACK(int) pgmR3InfoHandlersVirtualOne(PAVLROGCPTRNODECORE pNode, void *pvUser);
64
65
66
67/**
68 * Register a access handler for a physical range.
69 *
70 * @returns VBox status code.
71 * @param pVM VM handle.
72 * @param enmType Handler type. Any of the PGMPHYSHANDLERTYPE_PHYSICAL* enums.
73 * @param GCPhys Start physical address.
74 * @param GCPhysLast Last physical address. (inclusive)
75 * @param pfnHandlerR3 The R3 handler.
76 * @param pvUserR3 User argument to the R3 handler.
77 * @param pszModR0 The R0 handler module. NULL means default R0 module.
78 * @param pszHandlerR0 The R0 handler symbol name.
79 * @param pvUserR0 User argument to the R0 handler.
80 * @param pszModGC The GC handler module. NULL means default GC module.
81 * @param pszHandlerGC The GC handler symbol name.
82 * @param pvUserGC User argument to the GC handler.
83 * This must be a GC pointer because it will be relocated!
84 * @param pszDesc Pointer to description string. This must not be freed.
85 */
86PGMR3DECL(int) PGMR3HandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
87 PFNPGMR3PHYSHANDLER pfnHandlerR3, void *pvUserR3,
88 const char *pszModR0, const char *pszHandlerR0, RTR0PTR pvUserR0,
89 const char *pszModGC, const char *pszHandlerGC, RTGCPTR pvUserGC, const char *pszDesc)
90{
91 LogFlow(("PGMR3HandlerPhysicalRegister: enmType=%d GCPhys=%VGv GCPhysLast=%VGv pfnHandlerR3=%VHv pvUserHC=%VHv pszModGC=%p:{%s} pszHandlerGC=%p:{%s} pvUser=%VGv pszDesc=%s\n",
92 enmType, GCPhys, GCPhysLast, pfnHandlerR3, pvUserR3, pszModGC, pszModGC, pszHandlerGC, pszHandlerGC, pvUserGC, pszDesc));
93
94 /*
95 * Validate input.
96 */
97 if (!pszModGC)
98 pszModGC = VMMGC_MAIN_MODULE_NAME;
99
100 if (!pszModR0)
101 pszModR0 = VMMR0_MAIN_MODULE_NAME;
102
103 /*
104 * Resolve the R0 handler.
105 */
106 R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0 = NIL_RTR0PTR;
107 int rc = VINF_SUCCESS;
108 if (pszHandlerR0 && HWACCMR3IsAllowed(pVM))
109 rc = PDMR3GetSymbolR0Lazy(pVM, pszModR0, pszHandlerR0, &pfnHandlerR0);
110 if (VBOX_SUCCESS(rc))
111 {
112 /*
113 * Resolve the GC handler.
114 */
115 RTGCPTR pfnHandlerGC = NIL_RTGCPTR;
116 if (pszHandlerGC)
117 rc = PDMR3GetSymbolGCLazy(pVM, pszModGC, pszHandlerGC, &pfnHandlerGC);
118
119 if (VBOX_SUCCESS(rc))
120 return PGMHandlerPhysicalRegisterEx(pVM, enmType, GCPhys, GCPhysLast, pfnHandlerR3, pvUserR3,
121 pfnHandlerR0, pvUserR0, pfnHandlerGC, pvUserGC, pszDesc);
122
123 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Vrc.\n", pszModGC, pszHandlerGC, rc));
124 }
125 else
126 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Vrc.\n", pszModR0, pszHandlerR0, rc));
127
128 return rc;
129}
130
131
132/**
133 * Updates the physical page access handlers.
134 *
135 * @param pVM VM handle.
136 * @remark Only used when restoring a saved state.
137 */
138void pgmR3HandlerPhysicalUpdateAll(PVM pVM)
139{
140 LogFlow(("pgmHandlerPhysicalUpdateAll:\n"));
141
142 /*
143 * Clear and set.
144 * (the right -> left on the setting pass is just bird speculating on cache hits)
145 */
146 pgmLock(pVM);
147 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, true, pgmR3HandlerPhysicalOneClear, pVM);
148 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, false, pgmR3HandlerPhysicalOneSet, pVM);
149 pgmUnlock(pVM);
150}
151
152
153/**
154 * Clears all the page level flags for one physical handler range.
155 *
156 * @returns 0
157 * @param pNode Pointer to a PGMPHYSHANDLER.
158 * @param pvUser VM handle.
159 */
160static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PAVLROGCPHYSNODECORE pNode, void *pvUser)
161{
162 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
163 PPGMRAMRANGE pRamHint = NULL;
164 RTGCPHYS GCPhys = pCur->Core.Key;
165 RTUINT cPages = pCur->cPages;
166 PPGM pPGM = &((PVM)pvUser)->pgm.s;
167 for (;;)
168 {
169 PGMRamFlagsClearByGCPhysWithHint(pPGM, GCPhys, MM_RAM_FLAGS_PHYSICAL_HANDLER | MM_RAM_FLAGS_PHYSICAL_WRITE | MM_RAM_FLAGS_PHYSICAL_ALL, &pRamHint);
170 if (--cPages == 0)
171 return 0;
172 GCPhys += PAGE_SIZE;
173 }
174}
175
176
177/**
178 * Sets all the page level flags for one physical handler range.
179 *
180 * @returns 0
181 * @param pNode Pointer to a PGMPHYSHANDLER.
182 * @param pvUser VM handle.
183 */
184static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser)
185{
186 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
187 unsigned fFlags = pgmHandlerPhysicalCalcFlags(pCur);
188 PPGMRAMRANGE pRamHint = NULL;
189 RTGCPHYS GCPhys = pCur->Core.Key;
190 RTUINT cPages = pCur->cPages;
191 PPGM pPGM = &((PVM)pvUser)->pgm.s;
192 for (;;)
193 {
194 PGMRamFlagsSetByGCPhysWithHint(pPGM, GCPhys, fFlags, &pRamHint);
195 if (--cPages == 0)
196 return 0;
197 GCPhys += PAGE_SIZE;
198 }
199}
200
201
202
203/**
204 * Register a access handler for a virtual range.
205 *
206 * @returns VBox status code.
207 * @param pVM VM handle.
208 * @param enmType Handler type. Any of the PGMVIRTHANDLERTYPE_* enums.
209 * @param GCPtr Start address.
210 * @param GCPtrLast Last address (inclusive).
211 * @param pfnInvalidateHC The HC invalidate callback (can be 0)
212 * @param pfnHandlerHC The HC handler.
213 * @param pszHandlerGC The GC handler symbol name.
214 * @param pszModGC The GC handler module.
215 * @param pszDesc Pointer to description string. This must not be freed.
216 */
217/** @todo rename this function to PGMR3HandlerVirtualRegister */
218PGMR3DECL(int) PGMR3HandlerVirtualRegister(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
219 PFNPGMHCVIRTINVALIDATE pfnInvalidateHC,
220 PFNPGMHCVIRTHANDLER pfnHandlerHC,
221 const char *pszHandlerGC, const char *pszModGC,
222 const char *pszDesc)
223{
224 LogFlow(("PGMR3HandlerVirtualRegisterEx: enmType=%d GCPtr=%VGv GCPtrLast=%VGv pszHandlerGC=%p:{%s} pszModGC=%p:{%s} pszDesc=%s\n",
225 enmType, GCPtr, GCPtrLast, pszHandlerGC, pszHandlerGC, pszModGC, pszModGC, pszDesc));
226
227 /*
228 * Validate input.
229 */
230 if (!pszModGC)
231 pszModGC = VMMGC_MAIN_MODULE_NAME;
232 if (!pszModGC || !*pszModGC || !pszHandlerGC || !*pszHandlerGC)
233 {
234 AssertMsgFailed(("pfnHandlerGC or/and pszModGC is missing\n"));
235 return VERR_INVALID_PARAMETER;
236 }
237
238 /*
239 * Resolve the GC handler.
240 */
241 RTGCPTR pfnHandlerGC;
242 int rc = PDMR3GetSymbolGCLazy(pVM, pszModGC, pszHandlerGC, &pfnHandlerGC);
243 if (VBOX_SUCCESS(rc))
244 return PGMHandlerVirtualRegisterEx(pVM, enmType, GCPtr, GCPtrLast, pfnInvalidateHC, pfnHandlerHC, pfnHandlerGC, pszDesc);
245
246 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Vrc.\n", pszModGC, pszHandlerGC, rc));
247 return rc;
248}
249
250
251/**
252 * Register an access handler for a virtual range.
253 *
254 * @returns VBox status code.
255 * @param pVM VM handle.
256 * @param enmType Handler type. Any of the PGMVIRTHANDLERTYPE_* enums.
257 * @param GCPtr Start address.
258 * @param GCPtrLast Last address (inclusive).
259 * @param pfnInvalidateHC The HC invalidate callback (can be 0)
260 * @param pfnHandlerHC The HC handler.
261 * @param pfnHandlerGC The GC handler.
262 * @param pszDesc Pointer to description string. This must not be freed.
263 */
264/** @todo rename this to PGMR3HandlerVirtualRegisterEx. */
265PGMDECL(int) PGMHandlerVirtualRegisterEx(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
266 PFNPGMHCVIRTINVALIDATE pfnInvalidateHC,
267 PFNPGMHCVIRTHANDLER pfnHandlerHC, RTGCPTR pfnHandlerGC,
268 HCPTRTYPE(const char *) pszDesc)
269{
270 Log(("PGMR3HandlerVirtualRegister: enmType=%d GCPtr=%RGv GCPtrLast=%RGv pfnHandlerGC=%RGv pszDesc=%s\n", enmType, GCPtr, GCPtrLast, pfnHandlerGC, pszDesc));
271
272 /*
273 * Validate input.
274 */
275 switch (enmType)
276 {
277 case PGMVIRTHANDLERTYPE_NORMAL:
278 case PGMVIRTHANDLERTYPE_ALL:
279 case PGMVIRTHANDLERTYPE_WRITE:
280 case PGMVIRTHANDLERTYPE_EIP:
281 if (!pfnHandlerHC)
282 {
283 AssertMsgFailed(("No HC handler specified!!\n"));
284 return VERR_INVALID_PARAMETER;
285 }
286 break;
287
288 case PGMVIRTHANDLERTYPE_HYPERVISOR:
289 if (pfnHandlerHC)
290 {
291 AssertMsgFailed(("HC handler specified for hypervisor range!?!\n"));
292 return VERR_INVALID_PARAMETER;
293 }
294 break;
295 default:
296 AssertMsgFailed(("Invalid enmType! enmType=%d\n", enmType));
297 return VERR_INVALID_PARAMETER;
298 }
299 if (GCPtrLast < GCPtr)
300 {
301 AssertMsgFailed(("GCPtrLast < GCPtr (%#x < %#x)\n", GCPtrLast, GCPtr));
302 return VERR_INVALID_PARAMETER;
303 }
304 if (!pfnHandlerGC)
305 {
306 AssertMsgFailed(("pfnHandlerGC is missing\n"));
307 return VERR_INVALID_PARAMETER;
308 }
309
310 /*
311 * Allocate and initialize a new entry.
312 */
313 unsigned cPages = (RT_ALIGN((RTGCUINTPTR)GCPtrLast + 1, PAGE_SIZE) - ((RTGCUINTPTR)GCPtr & PAGE_BASE_GC_MASK)) >> PAGE_SHIFT;
314 PPGMVIRTHANDLER pNew;
315 int rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew); /** @todo r=bird: incorrect member name PhysToVirt? */
316 if (VBOX_FAILURE(rc))
317 return rc;
318
319 pNew->Core.Key = GCPtr;
320 pNew->Core.KeyLast = GCPtrLast;
321
322 pNew->enmType = enmType;
323 pNew->pfnInvalidateHC = pfnInvalidateHC;
324 pNew->pfnHandlerGC = pfnHandlerGC;
325 pNew->pfnHandlerHC = pfnHandlerHC;
326 pNew->pszDesc = pszDesc;
327 pNew->GCPtr = GCPtr;
328 pNew->GCPtrLast = GCPtrLast;
329 pNew->cb = GCPtrLast - GCPtr + 1;
330 pNew->cPages = cPages;
331 /* Will be synced at next guest execution attempt. */
332 while (cPages-- > 0)
333 {
334 pNew->aPhysToVirt[cPages].Core.Key = NIL_RTGCPHYS;
335 pNew->aPhysToVirt[cPages].Core.KeyLast = NIL_RTGCPHYS;
336 pNew->aPhysToVirt[cPages].offVirtHandler = -RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]);
337 pNew->aPhysToVirt[cPages].offNextAlias = 0;
338 }
339
340 /*
341 * Try to insert it into the tree.
342 *
343 * The current implementation doesn't allow multiple handlers for
344 * the same range this makes everything much simpler and faster.
345 */
346 pgmLock(pVM);
347 if (pVM->pgm.s.pTreesHC->VirtHandlers != 0)
348 {
349 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(&pVM->pgm.s.CTXSUFF(pTrees)->VirtHandlers, pNew->Core.Key, true);
350 if (!pCur || GCPtr > pCur->GCPtrLast || GCPtrLast < pCur->GCPtr)
351 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(&pVM->pgm.s.CTXSUFF(pTrees)->VirtHandlers, pNew->Core.Key, false);
352 if (pCur && GCPtr <= pCur->GCPtrLast && GCPtrLast >= pCur->GCPtr)
353 {
354 /*
355 * The LDT sometimes conflicts with the IDT and LDT ranges while being
356 * updated on linux. So, we don't assert simply log it.
357 */
358 Log(("PGMR3HandlerVirtualRegister: Conflict with existing range %RGv-%RGv (%s), req. %RGv-%RGv (%s)\n",
359 pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc, GCPtr, GCPtrLast, pszDesc));
360 MMHyperFree(pVM, pNew);
361 pgmUnlock(pVM);
362 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
363 }
364 }
365 if (RTAvlroGCPtrInsert(&pVM->pgm.s.CTXSUFF(pTrees)->VirtHandlers, &pNew->Core))
366 {
367 if (enmType != PGMVIRTHANDLERTYPE_HYPERVISOR)
368 {
369 pVM->pgm.s.fPhysCacheFlushPending = true;
370 pVM->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
371 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
372 }
373 pgmUnlock(pVM);
374
375#ifdef VBOX_WITH_STATISTICS
376 char szPath[256];
377 RTStrPrintf(szPath, sizeof(szPath), "/PGM/VirtHandler/Calls/%VGv-%VGv", pNew->GCPtr, pNew->GCPtrLast);
378 rc = STAMR3Register(pVM, &pNew->Stat, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szPath, STAMUNIT_TICKS_PER_CALL, pszDesc);
379 AssertRC(rc);
380#endif
381 return VINF_SUCCESS;
382 }
383 pgmUnlock(pVM);
384 AssertFailed();
385 MMHyperFree(pVM, pNew);
386 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
387}
388
389
390/**
391 * Modify the page invalidation callback handler for a registered virtual range
392 * (add more when needed)
393 *
394 * @returns VBox status code.
395 * @param pVM VM handle.
396 * @param GCPtr Start address.
397 * @param pfnInvalidateHC The HC invalidate callback (can be 0)
398 */
399PGMDECL(int) PGMHandlerVirtualChangeInvalidateCallback(PVM pVM, RTGCPTR GCPtr, PFNPGMHCVIRTINVALIDATE pfnInvalidateHC)
400{
401 pgmLock(pVM);
402 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGet(&pVM->pgm.s.pTreesHC->VirtHandlers, GCPtr);
403 if (pCur)
404 {
405 pCur->pfnInvalidateHC = pfnInvalidateHC;
406 pgmUnlock(pVM);
407 return VINF_SUCCESS;
408 }
409 pgmUnlock(pVM);
410 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
411 return VERR_INVALID_PARAMETER;
412}
413
414
415/**
416 * Deregister an access handler for a virtual range.
417 *
418 * @returns VBox status code.
419 * @param pVM VM handle.
420 * @param GCPtr Start address.
421 */
422PGMDECL(int) PGMHandlerVirtualDeregister(PVM pVM, RTGCPTR GCPtr)
423{
424 /*
425 * Find the handler.
426 * We naturally assume GCPtr is a unique specification.
427 */
428 pgmLock(pVM);
429 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTXSUFF(pTrees)->VirtHandlers, GCPtr);
430 if (pCur)
431 {
432 Log(("PGMR3HandlerVirtualDeregister: Removing Virtual (%d) Range %#x-%#x %s\n", pCur->enmType,
433 pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc));
434
435 /*
436 * Reset the flags and remove phys2virt nodes.
437 */
438 PPGM pPGM = &pVM->pgm.s;
439 for (unsigned iPage = 0; iPage < pCur->cPages; iPage++)
440 if (pCur->aPhysToVirt[iPage].offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE)
441 pgmHandlerVirtualClearPage(pPGM, pCur, iPage);
442
443 /*
444 * Schedule CR3 sync (if required) and the memory.
445 */
446 STAM_DEREG(pVM, &pCur->Stat);
447 if (pCur->enmType != PGMVIRTHANDLERTYPE_HYPERVISOR)
448 {
449 pVM->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
450 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
451 }
452 MMHyperFree(pVM, pCur);
453 pgmUnlock(pVM);
454 return VINF_SUCCESS;
455 }
456 pgmUnlock(pVM);
457 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
458 return VERR_INVALID_PARAMETER;
459}
460
461
462/**
463 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
464 */
465typedef struct PGMHANDLERINFOARG
466{
467 /** The output helpers.*/
468 PCDBGFINFOHLP pHlp;
469 /** Set if statistics should be dumped. */
470 bool fStats;
471} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
472
473
474/**
475 * Info callback for 'pgmhandlers'.
476 *
477 * @param pHlp The output helpers.
478 * @param pszArgs The arguments. phys or virt.
479 */
480DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
481{
482 /*
483 * Test input.
484 */
485 PGMHANDLERINFOARG Args = { pHlp, true };
486 bool fPhysical = !pszArgs || !*pszArgs;
487 bool fVirtual = fPhysical;
488 if (!fPhysical)
489 {
490 fPhysical = strstr(pszArgs, "phys") != NULL;
491 fVirtual = strstr(pszArgs, "virt") != NULL;
492 Args.fStats = strstr(pszArgs, "nost") == NULL;
493 }
494
495 /*
496 * Dump the handlers.
497 */
498 if (fPhysical)
499 {
500 pHlp->pfnPrintf(pHlp,
501 "Physical handlers: (PhysHandlers=%d (%#x))\n"
502 "From - To (incl) HandlerHC UserHC HandlerGC UserGC Type Description\n",
503 pVM->pgm.s.pTreesHC->PhysHandlers, pVM->pgm.s.pTreesHC->PhysHandlers);
504 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, true, pgmR3InfoHandlersPhysicalOne, &Args);
505 }
506
507 if (fVirtual)
508 {
509 pHlp->pfnPrintf(pHlp,
510 "Virtual handlers:\n"
511 "From - To (excl) HandlerHC HandlerGC Type Description\n");
512 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesHC->VirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
513 }
514}
515
516
517/**
518 * Displays one physical handler range.
519 *
520 * @returns 0
521 * @param pNode Pointer to a PGMPHYSHANDLER.
522 * @param pvUser Pointer to command helper functions.
523 */
524static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
525{
526 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
527 PPGMHANDLERINFOARG pArgs= (PPGMHANDLERINFOARG)pvUser;
528 PCDBGFINFOHLP pHlp = pArgs->pHlp;
529 const char *pszType;
530 switch (pCur->enmType)
531 {
532 case PGMPHYSHANDLERTYPE_MMIO: pszType = "MMIO "; break;
533 case PGMPHYSHANDLERTYPE_PHYSICAL: pszType = "Natural"; break;
534 case PGMPHYSHANDLERTYPE_PHYSICAL_WRITE: pszType = "Write "; break;
535 case PGMPHYSHANDLERTYPE_PHYSICAL_ALL: pszType = "All "; break;
536 default: pszType = "????"; break;
537 }
538 pHlp->pfnPrintf(pHlp,
539 "%VGp - %VGp %VHv %VHv %VGv %VGv %s %s\n",
540 pCur->Core.Key, pCur->Core.KeyLast, pCur->pfnHandlerR3, pCur->pvUserR3, pCur->pfnHandlerGC, pCur->pvUserGC, pszType, pCur->pszDesc);
541#ifdef VBOX_WITH_STATISTICS
542 if (pArgs->fStats)
543 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
544 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
545 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
546#endif
547 return 0;
548}
549
550
551/**
552 * Displays one virtual handler range.
553 *
554 * @returns 0
555 * @param pNode Pointer to a PGMVIRTHANDLER.
556 * @param pvUser Pointer to command helper functions.
557 */
558static DECLCALLBACK(int) pgmR3InfoHandlersVirtualOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
559{
560 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
561 PPGMHANDLERINFOARG pArgs= (PPGMHANDLERINFOARG)pvUser;
562 PCDBGFINFOHLP pHlp = pArgs->pHlp;
563 const char *pszType;
564 switch (pCur->enmType)
565 {
566 case PGMVIRTHANDLERTYPE_NORMAL: pszType = "Natural"; break;
567 case PGMVIRTHANDLERTYPE_WRITE: pszType = "Write "; break;
568 case PGMVIRTHANDLERTYPE_ALL: pszType = "All "; break;
569 case PGMVIRTHANDLERTYPE_EIP: pszType = "EIP "; break;
570 case PGMVIRTHANDLERTYPE_HYPERVISOR: pszType = "WriteHyp "; break;
571 default: pszType = "????"; break;
572 }
573 pHlp->pfnPrintf(pHlp, "%08x - %08x %08x %08x %s %s\n",
574 pCur->GCPtr, pCur->GCPtrLast, pCur->pfnHandlerHC, pCur->pfnHandlerGC, pszType, pCur->pszDesc);
575#ifdef VBOX_WITH_STATISTICS
576 if (pArgs->fStats)
577 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
578 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
579 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
580#endif
581 return 0;
582}
583
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