VirtualBox

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

Last change on this file since 28800 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.1 KB
Line 
1/* $Id: PGMHandler.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * PGM - Page Manager / Monitor, Access Handlers.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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 "PGMInline.h"
40#include <VBox/dbg.h>
41
42#include <VBox/log.h>
43#include <iprt/assert.h>
44#include <iprt/alloc.h>
45#include <iprt/asm.h>
46#include <iprt/thread.h>
47#include <iprt/string.h>
48#include <VBox/param.h>
49#include <VBox/err.h>
50#include <VBox/hwaccm.h>
51
52
53/*******************************************************************************
54* Internal Functions *
55*******************************************************************************/
56static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PAVLROGCPHYSNODECORE pNode, void *pvUser);
57static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser);
58static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser);
59static DECLCALLBACK(int) pgmR3InfoHandlersVirtualOne(PAVLROGCPTRNODECORE pNode, void *pvUser);
60
61
62
63/**
64 * Register a access handler for a physical range.
65 *
66 * @returns VBox status code.
67 * @param pVM VM handle.
68 * @param enmType Handler type. Any of the PGMPHYSHANDLERTYPE_PHYSICAL* enums.
69 * @param GCPhys Start physical address.
70 * @param GCPhysLast Last physical address. (inclusive)
71 * @param pfnHandlerR3 The R3 handler.
72 * @param pvUserR3 User argument to the R3 handler.
73 * @param pszModR0 The R0 handler module. NULL means the default R0 module.
74 * @param pszHandlerR0 The R0 handler symbol name.
75 * @param pvUserR0 User argument to the R0 handler.
76 * @param pszModRC The RC handler module. NULL means the default RC
77 * module.
78 * @param pszHandlerRC The RC handler symbol name.
79 * @param pvUserRC User argument to the RC handler. Values less than
80 * 0x10000 will not be relocated.
81 * @param pszDesc Pointer to description string. This must not be freed.
82 */
83VMMR3DECL(int) PGMR3HandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
84 PFNPGMR3PHYSHANDLER pfnHandlerR3, void *pvUserR3,
85 const char *pszModR0, const char *pszHandlerR0, RTR0PTR pvUserR0,
86 const char *pszModRC, const char *pszHandlerRC, RTRCPTR pvUserRC, const char *pszDesc)
87{
88 LogFlow(("PGMR3HandlerPhysicalRegister: enmType=%d GCPhys=%RGp GCPhysLast=%RGp pfnHandlerR3=%RHv pvUserHC=%RHv pszModR0=%s pszHandlerR0=%s pvUserR0=%RHv pszModRC=%s pszHandlerRC=%s pvUser=%RRv pszDesc=%s\n",
89 enmType, GCPhys, GCPhysLast, pfnHandlerR3, pvUserR3, pszModR0, pszHandlerR0, pvUserR0, pszHandlerRC, pszModRC, pvUserRC, pszDesc));
90
91 /*
92 * Validate input.
93 */
94 if (!pszModRC)
95 pszModRC = VMMGC_MAIN_MODULE_NAME;
96 if (!pszModR0)
97 pszModR0 = VMMR0_MAIN_MODULE_NAME;
98 if (!pszHandlerR0)
99 pszHandlerR0 = "pgmPhysHandlerRedirectToHC";
100 if (!pszHandlerRC)
101 pszHandlerRC = "pgmPhysHandlerRedirectToHC";
102 AssertPtrReturn(pfnHandlerR3, VERR_INVALID_POINTER);
103 AssertPtrReturn(pszHandlerR0, VERR_INVALID_POINTER);
104 AssertPtrReturn(pszHandlerRC, VERR_INVALID_POINTER);
105
106 /*
107 * Resolve the R0 handler.
108 */
109 R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0 = NIL_RTR0PTR;
110 int rc = VINF_SUCCESS;
111 rc = PDMR3LdrGetSymbolR0Lazy(pVM, pszModR0, pszHandlerR0, &pfnHandlerR0);
112 if (RT_SUCCESS(rc))
113 {
114 /*
115 * Resolve the GC handler.
116 */
117 RTRCPTR pfnHandlerRC = NIL_RTRCPTR;
118 rc = PDMR3LdrGetSymbolRCLazy(pVM, pszModRC, pszHandlerRC, &pfnHandlerRC);
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=%RRv 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 AssertReleaseMsgReturn( (GCPtr & PAGE_OFFSET_MASK) == 0
293 && (GCPtrLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK,
294 ("PGMVIRTHANDLERTYPE_ALL: GCPtr=%RGv GCPtrLast=%RGv\n", GCPtr, GCPtrLast),
295 VERR_NOT_IMPLEMENTED);
296 break;
297 case PGMVIRTHANDLERTYPE_WRITE:
298 if (!pfnHandlerR3)
299 {
300 AssertMsgFailed(("No HC handler specified!!\n"));
301 return VERR_INVALID_PARAMETER;
302 }
303 break;
304
305 case PGMVIRTHANDLERTYPE_HYPERVISOR:
306 if (pfnHandlerR3)
307 {
308 AssertMsgFailed(("R3 handler specified for hypervisor range!?!\n"));
309 return VERR_INVALID_PARAMETER;
310 }
311 break;
312 default:
313 AssertMsgFailed(("Invalid enmType! enmType=%d\n", enmType));
314 return VERR_INVALID_PARAMETER;
315 }
316 if (GCPtrLast < GCPtr)
317 {
318 AssertMsgFailed(("GCPtrLast < GCPtr (%#x < %#x)\n", GCPtrLast, GCPtr));
319 return VERR_INVALID_PARAMETER;
320 }
321 if (!pfnHandlerRC)
322 {
323 AssertMsgFailed(("pfnHandlerRC is missing\n"));
324 return VERR_INVALID_PARAMETER;
325 }
326
327 /*
328 * Allocate and initialize a new entry.
329 */
330 unsigned cPages = (RT_ALIGN(GCPtrLast + 1, PAGE_SIZE) - (GCPtr & PAGE_BASE_GC_MASK)) >> PAGE_SHIFT;
331 PPGMVIRTHANDLER pNew;
332 int rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew); /** @todo r=bird: incorrect member name PhysToVirt? */
333 if (RT_FAILURE(rc))
334 return rc;
335
336 pNew->Core.Key = GCPtr;
337 pNew->Core.KeyLast = GCPtrLast;
338
339 pNew->enmType = enmType;
340 pNew->pfnInvalidateR3 = pfnInvalidateR3;
341 pNew->pfnHandlerRC = pfnHandlerRC;
342 pNew->pfnHandlerR3 = pfnHandlerR3;
343 pNew->pszDesc = pszDesc;
344 pNew->cb = GCPtrLast - GCPtr + 1;
345 pNew->cPages = cPages;
346 /* Will be synced at next guest execution attempt. */
347 while (cPages-- > 0)
348 {
349 pNew->aPhysToVirt[cPages].Core.Key = NIL_RTGCPHYS;
350 pNew->aPhysToVirt[cPages].Core.KeyLast = NIL_RTGCPHYS;
351 pNew->aPhysToVirt[cPages].offVirtHandler = -RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]);
352 pNew->aPhysToVirt[cPages].offNextAlias = 0;
353 }
354
355 /*
356 * Try to insert it into the tree.
357 *
358 * The current implementation doesn't allow multiple handlers for
359 * the same range this makes everything much simpler and faster.
360 */
361 AVLROGCPTRTREE *pRoot = enmType != PGMVIRTHANDLERTYPE_HYPERVISOR
362 ? &pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers
363 : &pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers;
364 pgmLock(pVM);
365 if (*pRoot != 0)
366 {
367 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(pRoot, pNew->Core.Key, true);
368 if ( !pCur
369 || GCPtr > pCur->Core.KeyLast
370 || GCPtrLast < pCur->Core.Key)
371 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(pRoot, pNew->Core.Key, false);
372 if ( pCur
373 && GCPtr <= pCur->Core.KeyLast
374 && GCPtrLast >= pCur->Core.Key)
375 {
376 /*
377 * The LDT sometimes conflicts with the IDT and LDT ranges while being
378 * updated on linux. So, we don't assert simply log it.
379 */
380 Log(("PGMR3HandlerVirtualRegister: Conflict with existing range %RGv-%RGv (%s), req. %RGv-%RGv (%s)\n",
381 pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc, GCPtr, GCPtrLast, pszDesc));
382 MMHyperFree(pVM, pNew);
383 pgmUnlock(pVM);
384 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
385 }
386 }
387 if (RTAvlroGCPtrInsert(pRoot, &pNew->Core))
388 {
389 if (enmType != PGMVIRTHANDLERTYPE_HYPERVISOR)
390 {
391 PVMCPU pVCpu = VMMGetCpu(pVM);
392
393 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
394 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
395 }
396 pgmUnlock(pVM);
397
398#ifdef VBOX_WITH_STATISTICS
399 char szPath[256];
400 RTStrPrintf(szPath, sizeof(szPath), "/PGM/VirtHandler/Calls/%RGv-%RGv", pNew->Core.Key, pNew->Core.KeyLast);
401 rc = STAMR3Register(pVM, &pNew->Stat, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szPath, STAMUNIT_TICKS_PER_CALL, pszDesc);
402 AssertRC(rc);
403#endif
404 return VINF_SUCCESS;
405 }
406
407 pgmUnlock(pVM);
408 AssertFailed();
409 MMHyperFree(pVM, pNew);
410 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
411}
412
413
414/**
415 * Modify the page invalidation callback handler for a registered virtual range.
416 * (add more when needed)
417 *
418 * @returns VBox status code.
419 * @param pVM VM handle.
420 * @param GCPtr Start address.
421 * @param pfnInvalidateR3 The R3 invalidate callback (can be 0)
422 * @remarks Doesn't work with the hypervisor access handler type.
423 */
424VMMDECL(int) PGMHandlerVirtualChangeInvalidateCallback(PVM pVM, RTGCPTR GCPtr, PFNPGMR3VIRTINVALIDATE pfnInvalidateR3)
425{
426 pgmLock(pVM);
427 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGet(&pVM->pgm.s.pTreesR3->VirtHandlers, GCPtr);
428 if (pCur)
429 {
430 pCur->pfnInvalidateR3 = pfnInvalidateR3;
431 pgmUnlock(pVM);
432 return VINF_SUCCESS;
433 }
434 pgmUnlock(pVM);
435 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
436 return VERR_INVALID_PARAMETER;
437}
438
439/**
440 * Deregister an access handler for a virtual range.
441 *
442 * @returns VBox status code.
443 * @param pVM VM handle.
444 * @param GCPtr Start address.
445 * @thread EMT
446 */
447VMMDECL(int) PGMHandlerVirtualDeregister(PVM pVM, RTGCPTR GCPtr)
448{
449 pgmLock(pVM);
450
451 /*
452 * Find the handler.
453 * We naturally assume GCPtr is a unique specification.
454 */
455 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtr);
456 if (RT_LIKELY(pCur))
457 {
458 Log(("PGMHandlerVirtualDeregister: Removing Virtual (%d) Range %RGv-%RGv %s\n", pCur->enmType,
459 pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
460 Assert(pCur->enmType != PGMVIRTHANDLERTYPE_HYPERVISOR);
461
462 /*
463 * Reset the flags and remove phys2virt nodes.
464 */
465 PPGM pPGM = &pVM->pgm.s;
466 for (unsigned iPage = 0; iPage < pCur->cPages; iPage++)
467 if (pCur->aPhysToVirt[iPage].offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE)
468 pgmHandlerVirtualClearPage(pPGM, pCur, iPage);
469
470 /*
471 * Schedule CR3 sync.
472 */
473 PVMCPU pVCpu = VMMGetCpu(pVM);
474
475 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
476 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
477 }
478 else
479 {
480 /* must be a hypervisor one then. */
481 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers, GCPtr);
482 if (RT_UNLIKELY(!pCur))
483 {
484 pgmUnlock(pVM);
485 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
486 return VERR_INVALID_PARAMETER;
487 }
488
489 Log(("PGMHandlerVirtualDeregister: Removing Hyper Virtual (%d) Range %RGv-%RGv %s\n", pCur->enmType,
490 pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
491 Assert(pCur->enmType == PGMVIRTHANDLERTYPE_HYPERVISOR);
492 }
493
494 pgmUnlock(pVM);
495
496 STAM_DEREG(pVM, &pCur->Stat);
497 MMHyperFree(pVM, pCur);
498
499 return VINF_SUCCESS;
500}
501
502
503/**
504 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
505 */
506typedef struct PGMHANDLERINFOARG
507{
508 /** The output helpers.*/
509 PCDBGFINFOHLP pHlp;
510 /** Set if statistics should be dumped. */
511 bool fStats;
512} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
513
514
515/**
516 * Info callback for 'pgmhandlers'.
517 *
518 * @param pHlp The output helpers.
519 * @param pszArgs The arguments. phys or virt.
520 */
521DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
522{
523 /*
524 * Test input.
525 */
526 PGMHANDLERINFOARG Args = { pHlp, /* .fStats = */ true };
527 bool fPhysical = !pszArgs || !*pszArgs;
528 bool fVirtual = fPhysical;
529 bool fHyper = fPhysical;
530 if (!fPhysical)
531 {
532 bool fAll = strstr(pszArgs, "all") != NULL;
533 fPhysical = fAll || strstr(pszArgs, "phys") != NULL;
534 fVirtual = fAll || strstr(pszArgs, "virt") != NULL;
535 fHyper = fAll || strstr(pszArgs, "hyper")!= NULL;
536 Args.fStats = strstr(pszArgs, "nost") == NULL;
537 }
538
539 /*
540 * Dump the handlers.
541 */
542 if (fPhysical)
543 {
544 pHlp->pfnPrintf(pHlp,
545 "Physical handlers: (PhysHandlers=%d (%#x))\n"
546 "From - To (incl) HandlerHC UserHC HandlerGC UserGC Type Description\n",
547 pVM->pgm.s.pTreesR3->PhysHandlers, pVM->pgm.s.pTreesR3->PhysHandlers);
548 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesR3->PhysHandlers, true, pgmR3InfoHandlersPhysicalOne, &Args);
549 }
550
551 if (fVirtual)
552 {
553 pHlp->pfnPrintf(pHlp,
554 "Virtual handlers:\n"
555 "From - To (excl) HandlerHC HandlerGC Type Description\n");
556 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->VirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
557 }
558
559 if (fHyper)
560 {
561 pHlp->pfnPrintf(pHlp,
562 "Hypervisor Virtual handlers:\n"
563 "From - To (excl) HandlerHC HandlerGC Type Description\n");
564 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->HyperVirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
565 }
566}
567
568
569/**
570 * Displays one physical handler range.
571 *
572 * @returns 0
573 * @param pNode Pointer to a PGMPHYSHANDLER.
574 * @param pvUser Pointer to command helper functions.
575 */
576static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
577{
578 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
579 PPGMHANDLERINFOARG pArgs= (PPGMHANDLERINFOARG)pvUser;
580 PCDBGFINFOHLP pHlp = pArgs->pHlp;
581 const char *pszType;
582 switch (pCur->enmType)
583 {
584 case PGMPHYSHANDLERTYPE_MMIO: pszType = "MMIO "; break;
585 case PGMPHYSHANDLERTYPE_PHYSICAL_WRITE: pszType = "Write "; break;
586 case PGMPHYSHANDLERTYPE_PHYSICAL_ALL: pszType = "All "; break;
587 default: pszType = "????"; break;
588 }
589 pHlp->pfnPrintf(pHlp,
590 "%RGp - %RGp %RHv %RHv %RRv %RRv %s %s\n",
591 pCur->Core.Key, pCur->Core.KeyLast, pCur->pfnHandlerR3, pCur->pvUserR3, pCur->pfnHandlerRC, pCur->pvUserRC, pszType, pCur->pszDesc);
592#ifdef VBOX_WITH_STATISTICS
593 if (pArgs->fStats)
594 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
595 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
596 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
597#endif
598 return 0;
599}
600
601
602/**
603 * Displays one virtual handler range.
604 *
605 * @returns 0
606 * @param pNode Pointer to a PGMVIRTHANDLER.
607 * @param pvUser Pointer to command helper functions.
608 */
609static DECLCALLBACK(int) pgmR3InfoHandlersVirtualOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
610{
611 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
612 PPGMHANDLERINFOARG pArgs= (PPGMHANDLERINFOARG)pvUser;
613 PCDBGFINFOHLP pHlp = pArgs->pHlp;
614 const char *pszType;
615 switch (pCur->enmType)
616 {
617 case PGMVIRTHANDLERTYPE_WRITE: pszType = "Write "; break;
618 case PGMVIRTHANDLERTYPE_ALL: pszType = "All "; break;
619 case PGMVIRTHANDLERTYPE_HYPERVISOR: pszType = "WriteHyp "; break;
620 default: pszType = "????"; break;
621 }
622 pHlp->pfnPrintf(pHlp, "%RGv - %RGv %RHv %RRv %s %s\n",
623 pCur->Core.Key, pCur->Core.KeyLast, pCur->pfnHandlerR3, pCur->pfnHandlerRC, pszType, pCur->pszDesc);
624#ifdef VBOX_WITH_STATISTICS
625 if (pArgs->fStats)
626 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
627 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
628 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
629#endif
630 return 0;
631}
632
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use