VirtualBox

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

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

More string specifiers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.5 KB
Line 
1/* $Id: PGMHandler.cpp 9256 2008-05-30 14:20:11Z vboxsync $ */
2/** @file
3 * PGM - Page Manager / Monitor, Access Handlers.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
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 the 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 the 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)
108 rc = PDMR3GetSymbolR0Lazy(pVM, pszModR0, pszHandlerR0, &pfnHandlerR0);
109 if (VBOX_SUCCESS(rc))
110 {
111 /*
112 * Resolve the GC handler.
113 */
114 RTGCPTR32 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 PPGMPAGE pPage;
169 int rc = pgmPhysGetPageWithHintEx(pPGM, GCPhys, &pPage, &pRamHint);
170 if (RT_SUCCESS(rc))
171 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE);
172 else
173 AssertRC(rc);
174
175 if (--cPages == 0)
176 return 0;
177 GCPhys += PAGE_SIZE;
178 }
179}
180
181
182/**
183 * Sets all the page level flags for one physical handler range.
184 *
185 * @returns 0
186 * @param pNode Pointer to a PGMPHYSHANDLER.
187 * @param pvUser VM handle.
188 */
189static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser)
190{
191 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
192 unsigned uState = pgmHandlerPhysicalCalcState(pCur);
193 PPGMRAMRANGE pRamHint = NULL;
194 RTGCPHYS GCPhys = pCur->Core.Key;
195 RTUINT cPages = pCur->cPages;
196 PPGM pPGM = &((PVM)pvUser)->pgm.s;
197 for (;;)
198 {
199 PPGMPAGE pPage;
200 int rc = pgmPhysGetPageWithHintEx(pPGM, GCPhys, &pPage, &pRamHint);
201 if (RT_SUCCESS(rc))
202 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, uState);
203 else
204 AssertRC(rc);
205
206 if (--cPages == 0)
207 return 0;
208 GCPhys += PAGE_SIZE;
209 }
210}
211
212
213
214/**
215 * Register a access handler for a virtual range.
216 *
217 * @returns VBox status code.
218 * @param pVM VM handle.
219 * @param enmType Handler type. Any of the PGMVIRTHANDLERTYPE_* enums.
220 * @param GCPtr Start address.
221 * @param GCPtrLast Last address (inclusive).
222 * @param pfnInvalidateHC The HC invalidate callback (can be 0)
223 * @param pfnHandlerHC The HC handler.
224 * @param pszHandlerGC The GC handler symbol name.
225 * @param pszModGC The GC handler module.
226 * @param pszDesc Pointer to description string. This must not be freed.
227 */
228/** @todo rename this function to PGMR3HandlerVirtualRegister */
229PGMR3DECL(int) PGMR3HandlerVirtualRegister(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
230 PFNPGMHCVIRTINVALIDATE pfnInvalidateHC,
231 PFNPGMHCVIRTHANDLER pfnHandlerHC,
232 const char *pszHandlerGC, const char *pszModGC,
233 const char *pszDesc)
234{
235 LogFlow(("PGMR3HandlerVirtualRegisterEx: enmType=%d GCPtr=%VGv GCPtrLast=%VGv pszHandlerGC=%p:{%s} pszModGC=%p:{%s} pszDesc=%s\n",
236 enmType, GCPtr, GCPtrLast, pszHandlerGC, pszHandlerGC, pszModGC, pszModGC, pszDesc));
237
238 /*
239 * Validate input.
240 */
241 if (!pszModGC)
242 pszModGC = VMMGC_MAIN_MODULE_NAME;
243 if (!pszModGC || !*pszModGC || !pszHandlerGC || !*pszHandlerGC)
244 {
245 AssertMsgFailed(("pfnHandlerGC or/and pszModGC is missing\n"));
246 return VERR_INVALID_PARAMETER;
247 }
248
249 /*
250 * Resolve the GC handler.
251 */
252 RTGCPTR32 pfnHandlerGC;
253 int rc = PDMR3GetSymbolGCLazy(pVM, pszModGC, pszHandlerGC, &pfnHandlerGC);
254 if (VBOX_SUCCESS(rc))
255 return PGMHandlerVirtualRegisterEx(pVM, enmType, GCPtr, GCPtrLast, pfnInvalidateHC, pfnHandlerHC, pfnHandlerGC, pszDesc);
256
257 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Vrc.\n", pszModGC, pszHandlerGC, rc));
258 return rc;
259}
260
261
262/**
263 * Register an access handler for a virtual range.
264 *
265 * @returns VBox status code.
266 * @param pVM VM handle.
267 * @param enmType Handler type. Any of the PGMVIRTHANDLERTYPE_* enums.
268 * @param GCPtr Start address.
269 * @param GCPtrLast Last address (inclusive).
270 * @param pfnInvalidateHC The HC invalidate callback (can be 0)
271 * @param pfnHandlerHC The HC handler.
272 * @param pfnHandlerGC The GC handler.
273 * @param pszDesc Pointer to description string. This must not be freed.
274 * @thread EMT
275 */
276/** @todo rename this to PGMR3HandlerVirtualRegisterEx. */
277/** @todo create a template for virtual handlers (see async i/o), we're wasting space
278 * duplicating the function pointers now. (Or we will once we add the missing callbacks.) */
279PGMDECL(int) PGMHandlerVirtualRegisterEx(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
280 PFNPGMHCVIRTINVALIDATE pfnInvalidateHC,
281 PFNPGMHCVIRTHANDLER pfnHandlerHC, RTGCPTR pfnHandlerGC,
282 R3PTRTYPE(const char *) pszDesc)
283{
284 Log(("PGMR3HandlerVirtualRegister: enmType=%d GCPtr=%RGv GCPtrLast=%RGv pfnHandlerGC=%RGv pszDesc=%s\n", enmType, GCPtr, GCPtrLast, pfnHandlerGC, pszDesc));
285
286 /*
287 * Validate input.
288 */
289 switch (enmType)
290 {
291 case PGMVIRTHANDLERTYPE_ALL:
292 case PGMVIRTHANDLERTYPE_WRITE:
293 if (!pfnHandlerHC)
294 {
295 AssertMsgFailed(("No HC handler specified!!\n"));
296 return VERR_INVALID_PARAMETER;
297 }
298 break;
299
300 case PGMVIRTHANDLERTYPE_HYPERVISOR:
301 if (pfnHandlerHC)
302 {
303 AssertMsgFailed(("HC handler specified for hypervisor range!?!\n"));
304 return VERR_INVALID_PARAMETER;
305 }
306 break;
307 default:
308 AssertMsgFailed(("Invalid enmType! enmType=%d\n", enmType));
309 return VERR_INVALID_PARAMETER;
310 }
311 if (GCPtrLast < GCPtr)
312 {
313 AssertMsgFailed(("GCPtrLast < GCPtr (%#x < %#x)\n", GCPtrLast, GCPtr));
314 return VERR_INVALID_PARAMETER;
315 }
316 if (!pfnHandlerGC)
317 {
318 AssertMsgFailed(("pfnHandlerGC is missing\n"));
319 return VERR_INVALID_PARAMETER;
320 }
321
322 /*
323 * Allocate and initialize a new entry.
324 */
325 unsigned cPages = (RT_ALIGN((RTGCUINTPTR)GCPtrLast + 1, PAGE_SIZE) - ((RTGCUINTPTR)GCPtr & PAGE_BASE_GC_MASK)) >> PAGE_SHIFT;
326 PPGMVIRTHANDLER pNew;
327 int rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew); /** @todo r=bird: incorrect member name PhysToVirt? */
328 if (VBOX_FAILURE(rc))
329 return rc;
330
331 pNew->Core.Key = GCPtr;
332 pNew->Core.KeyLast = GCPtrLast;
333
334 pNew->enmType = enmType;
335 pNew->pfnInvalidateHC = pfnInvalidateHC;
336 pNew->pfnHandlerGC = pfnHandlerGC;
337 pNew->pfnHandlerHC = pfnHandlerHC;
338 pNew->pszDesc = pszDesc;
339 pNew->GCPtr = GCPtr;
340 pNew->GCPtrLast = GCPtrLast;
341 pNew->cb = GCPtrLast - GCPtr + 1;
342 pNew->cPages = cPages;
343 /* Will be synced at next guest execution attempt. */
344 while (cPages-- > 0)
345 {
346 pNew->aPhysToVirt[cPages].Core.Key = NIL_RTGCPHYS;
347 pNew->aPhysToVirt[cPages].Core.KeyLast = NIL_RTGCPHYS;
348 pNew->aPhysToVirt[cPages].offVirtHandler = -RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]);
349 pNew->aPhysToVirt[cPages].offNextAlias = 0;
350 }
351
352 /*
353 * Try to insert it into the tree.
354 *
355 * The current implementation doesn't allow multiple handlers for
356 * the same range this makes everything much simpler and faster.
357 */
358 AVLROGCPTRTREE *pRoot = enmType != PGMVIRTHANDLERTYPE_HYPERVISOR
359 ? &pVM->pgm.s.CTXSUFF(pTrees)->VirtHandlers
360 : &pVM->pgm.s.CTXSUFF(pTrees)->HyperVirtHandlers;
361 pgmLock(pVM);
362 if (*pRoot != 0)
363 {
364 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(pRoot, pNew->Core.Key, true);
365 if ( !pCur
366 || GCPtr > pCur->GCPtrLast
367 || GCPtrLast < pCur->GCPtr)
368 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(pRoot, pNew->Core.Key, false);
369 if ( pCur
370 && GCPtr <= pCur->GCPtrLast
371 && GCPtrLast >= pCur->GCPtr)
372 {
373 /*
374 * The LDT sometimes conflicts with the IDT and LDT ranges while being
375 * updated on linux. So, we don't assert simply log it.
376 */
377 Log(("PGMR3HandlerVirtualRegister: Conflict with existing range %RGv-%RGv (%s), req. %RGv-%RGv (%s)\n",
378 pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc, GCPtr, GCPtrLast, pszDesc));
379 MMHyperFree(pVM, pNew);
380 pgmUnlock(pVM);
381 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
382 }
383 }
384 if (RTAvlroGCPtrInsert(pRoot, &pNew->Core))
385 {
386 if (enmType != PGMVIRTHANDLERTYPE_HYPERVISOR)
387 {
388 pVM->pgm.s.fPhysCacheFlushPending = true;
389 pVM->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
390 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
391 }
392 pgmUnlock(pVM);
393
394#ifdef VBOX_WITH_STATISTICS
395 char szPath[256];
396 RTStrPrintf(szPath, sizeof(szPath), "/PGM/VirtHandler/Calls/%VGv-%VGv", pNew->GCPtr, pNew->GCPtrLast);
397 rc = STAMR3Register(pVM, &pNew->Stat, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szPath, STAMUNIT_TICKS_PER_CALL, pszDesc);
398 AssertRC(rc);
399#endif
400 return VINF_SUCCESS;
401 }
402
403 pgmUnlock(pVM);
404 AssertFailed();
405 MMHyperFree(pVM, pNew);
406 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
407}
408
409
410/**
411 * Modify the page invalidation callback handler for a registered virtual range.
412 * (add more when needed)
413 *
414 * @returns VBox status code.
415 * @param pVM VM handle.
416 * @param GCPtr Start address.
417 * @param pfnInvalidateHC The HC invalidate callback (can be 0)
418 * @remarks Doesn't work with the hypervisor access handler type.
419 */
420PGMDECL(int) PGMHandlerVirtualChangeInvalidateCallback(PVM pVM, RTGCPTR GCPtr, PFNPGMHCVIRTINVALIDATE pfnInvalidateHC)
421{
422 pgmLock(pVM);
423 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGet(&pVM->pgm.s.pTreesHC->VirtHandlers, GCPtr);
424 if (pCur)
425 {
426 pCur->pfnInvalidateHC = pfnInvalidateHC;
427 pgmUnlock(pVM);
428 return VINF_SUCCESS;
429 }
430 pgmUnlock(pVM);
431 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
432 return VERR_INVALID_PARAMETER;
433}
434
435
436/**
437 * Deregister an access handler for a virtual range.
438 *
439 * @returns VBox status code.
440 * @param pVM VM handle.
441 * @param GCPtr Start address.
442 * @thread EMT
443 */
444PGMDECL(int) PGMHandlerVirtualDeregister(PVM pVM, RTGCPTR GCPtr)
445{
446 pgmLock(pVM);
447
448 /*
449 * Find the handler.
450 * We naturally assume GCPtr is a unique specification.
451 */
452 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTXSUFF(pTrees)->VirtHandlers, GCPtr);
453 if (RT_LIKELY(pCur))
454 {
455 Log(("PGMHandlerVirtualDeregister: Removing Virtual (%d) Range %VGv-%VGv %s\n", pCur->enmType,
456 pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc));
457 Assert(pCur->enmType != PGMVIRTHANDLERTYPE_HYPERVISOR);
458
459 /*
460 * Reset the flags and remove phys2virt nodes.
461 */
462 PPGM pPGM = &pVM->pgm.s;
463 for (unsigned iPage = 0; iPage < pCur->cPages; iPage++)
464 if (pCur->aPhysToVirt[iPage].offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE)
465 pgmHandlerVirtualClearPage(pPGM, pCur, iPage);
466
467 /*
468 * Schedule CR3 sync.
469 */
470 pVM->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
471 VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3);
472 }
473 else
474 {
475 /* must be a hypervisor one then. */
476 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTXSUFF(pTrees)->HyperVirtHandlers, GCPtr);
477 if (RT_UNLIKELY(!pCur))
478 {
479 pgmUnlock(pVM);
480 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
481 return VERR_INVALID_PARAMETER;
482 }
483
484 Log(("PGMHandlerVirtualDeregister: Removing Hyper Virtual (%d) Range %VGv-%VGv %s\n", pCur->enmType,
485 pCur->GCPtr, pCur->GCPtrLast, pCur->pszDesc));
486 Assert(pCur->enmType == PGMVIRTHANDLERTYPE_HYPERVISOR);
487 }
488
489 pgmUnlock(pVM);
490
491 STAM_DEREG(pVM, &pCur->Stat);
492 MMHyperFree(pVM, pCur);
493
494 return VINF_SUCCESS;
495}
496
497
498/**
499 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
500 */
501typedef struct PGMHANDLERINFOARG
502{
503 /** The output helpers.*/
504 PCDBGFINFOHLP pHlp;
505 /** Set if statistics should be dumped. */
506 bool fStats;
507} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
508
509
510/**
511 * Info callback for 'pgmhandlers'.
512 *
513 * @param pHlp The output helpers.
514 * @param pszArgs The arguments. phys or virt.
515 */
516DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
517{
518 /*
519 * Test input.
520 */
521 PGMHANDLERINFOARG Args = { pHlp, /* .fStats = */ true };
522 bool fPhysical = !pszArgs || !*pszArgs;
523 bool fVirtual = fPhysical;
524 bool fHyper = fPhysical;
525 if (!fPhysical)
526 {
527 bool fAll = strstr(pszArgs, "all") != NULL;
528 fPhysical = fAll || strstr(pszArgs, "phys") != NULL;
529 fVirtual = fAll || strstr(pszArgs, "virt") != NULL;
530 fHyper = fAll || strstr(pszArgs, "hyper")!= NULL;
531 Args.fStats = strstr(pszArgs, "nost") == NULL;
532 }
533
534 /*
535 * Dump the handlers.
536 */
537 if (fPhysical)
538 {
539 pHlp->pfnPrintf(pHlp,
540 "Physical handlers: (PhysHandlers=%d (%#x))\n"
541 "From - To (incl) HandlerHC UserHC HandlerGC UserGC Type Description\n",
542 pVM->pgm.s.pTreesHC->PhysHandlers, pVM->pgm.s.pTreesHC->PhysHandlers);
543 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesHC->PhysHandlers, true, pgmR3InfoHandlersPhysicalOne, &Args);
544 }
545
546 if (fVirtual)
547 {
548 pHlp->pfnPrintf(pHlp,
549 "Virtual handlers:\n"
550 "From - To (excl) HandlerHC HandlerGC Type Description\n");
551 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesHC->VirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
552 }
553
554 if (fHyper)
555 {
556 pHlp->pfnPrintf(pHlp,
557 "Hypervisor Virtual handlers:\n"
558 "From - To (excl) HandlerHC HandlerGC Type Description\n");
559 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesHC->HyperVirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
560 }
561}
562
563
564/**
565 * Displays one physical handler range.
566 *
567 * @returns 0
568 * @param pNode Pointer to a PGMPHYSHANDLER.
569 * @param pvUser Pointer to command helper functions.
570 */
571static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
572{
573 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
574 PPGMHANDLERINFOARG pArgs= (PPGMHANDLERINFOARG)pvUser;
575 PCDBGFINFOHLP pHlp = pArgs->pHlp;
576 const char *pszType;
577 switch (pCur->enmType)
578 {
579 case PGMPHYSHANDLERTYPE_MMIO: pszType = "MMIO "; break;
580 case PGMPHYSHANDLERTYPE_PHYSICAL_WRITE: pszType = "Write "; break;
581 case PGMPHYSHANDLERTYPE_PHYSICAL_ALL: pszType = "All "; break;
582 default: pszType = "????"; break;
583 }
584 pHlp->pfnPrintf(pHlp,
585 "%VGp - %VGp %VHv %VHv %VRv %VRv %s %s\n",
586 pCur->Core.Key, pCur->Core.KeyLast, pCur->pfnHandlerR3, pCur->pvUserR3, pCur->pfnHandlerGC, pCur->pvUserGC, pszType, pCur->pszDesc);
587#ifdef VBOX_WITH_STATISTICS
588 if (pArgs->fStats)
589 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
590 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
591 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
592#endif
593 return 0;
594}
595
596
597/**
598 * Displays one virtual handler range.
599 *
600 * @returns 0
601 * @param pNode Pointer to a PGMVIRTHANDLER.
602 * @param pvUser Pointer to command helper functions.
603 */
604static DECLCALLBACK(int) pgmR3InfoHandlersVirtualOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
605{
606 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
607 PPGMHANDLERINFOARG pArgs= (PPGMHANDLERINFOARG)pvUser;
608 PCDBGFINFOHLP pHlp = pArgs->pHlp;
609 const char *pszType;
610 switch (pCur->enmType)
611 {
612 case PGMVIRTHANDLERTYPE_WRITE: pszType = "Write "; break;
613 case PGMVIRTHANDLERTYPE_ALL: pszType = "All "; break;
614 case PGMVIRTHANDLERTYPE_HYPERVISOR: pszType = "WriteHyp "; break;
615 default: pszType = "????"; break;
616 }
617 pHlp->pfnPrintf(pHlp, "%VGv - %VGv %VHv %VRv %s %s\n",
618 pCur->GCPtr, pCur->GCPtrLast, pCur->pfnHandlerHC, pCur->pfnHandlerGC, pszType, pCur->pszDesc);
619#ifdef VBOX_WITH_STATISTICS
620 if (pArgs->fStats)
621 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
622 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
623 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
624#endif
625 return 0;
626}
627
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