VirtualBox

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

Last change on this file since 4014 was 4013, checked in by vboxsync, 17 years ago

pdm.h = include pdm*.h; pdmapi.h = only the 'core' pdm APIs.

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