VirtualBox

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

Last change on this file since 14492 was 14346, checked in by vboxsync, 16 years ago

Implemented check for monitored page accesses, fixing TSS out of sync problem with VA in TLB. Enabled VA in TLB by default in new REM>

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