VirtualBox

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

Last change on this file since 13100 was 13062, checked in by vboxsync, 16 years ago

#1865: More PGM changes.

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