VirtualBox

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

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

Replaced PGMR3DumpMappings by info handler.

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