VirtualBox

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

Last change on this file since 50653 was 46493, checked in by vboxsync, 11 years ago

STAMR3Deregister* optimizations. Relevant for both startup and shutdown times.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use