VirtualBox

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

Last change on this file since 18499 was 17517, checked in by vboxsync, 15 years ago

PGM: Fixed PGMVIRTHANDLERTYPE_ALL regression from the other day - it seems like there are a few users of this type after all. Implemented PGMPhysRead support for it. Enforce page-sized-ness of this type just a for PGMPHYSHANDLERTYPE_ALL/MMIO.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use