VirtualBox

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

Last change on this file since 45276 was 45276, checked in by vboxsync, 12 years ago

Ring-1 compression patches, courtesy of trivirt AG:

  • main: diff to remove the hwvirt requirement for QNX
  • rem: diff for dealing with raw ring 0/1 selectors and general changes to allowed guest execution states
  • vmm: changes for using the guest's TSS selector index as our hypervisor TSS selector (makes str safe) (VBOX_WITH_SAFE_STR )
  • vmm: changes for dealing with guest ring 1 code (VBOX_WITH_RAW_RING1)
  • vmm: change to emulate smsw in RC/R0 (QNX uses this old style instruction a lot so going to qemu for emulation is very expensive)
  • vmm: change (hack) to kick out patm virtual handlers in case they conflict with guest GDT/TSS write monitors; we should allow multiple handlers per page, but that change would be rather invasive
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 24.1 KB
Line 
1/* $Id: PGMHandler.cpp 45276 2013-04-02 08:17:11Z 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 rc = PDMR3LdrGetSymbolRCLazy(pVM, pszModRC, NULL /*pszSearchPath*/, pszHandlerRC, &pfnHandlerRC);
123 if (RT_SUCCESS(rc))
124 return PGMHandlerPhysicalRegisterEx(pVM, enmType, GCPhys, GCPhysLast, pfnHandlerR3, pvUserR3,
125 pfnHandlerR0, pvUserR0, pfnHandlerRC, pvUserRC, pszDesc);
126
127 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszModRC, pszHandlerRC, rc));
128 }
129 else
130 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszModR0, pszHandlerR0, rc));
131
132 return rc;
133}
134
135
136/**
137 * Updates the physical page access handlers.
138 *
139 * @param pVM Pointer to the VM.
140 * @remark Only used when restoring a saved state.
141 */
142void pgmR3HandlerPhysicalUpdateAll(PVM pVM)
143{
144 LogFlow(("pgmHandlerPhysicalUpdateAll:\n"));
145
146 /*
147 * Clear and set.
148 * (the right -> left on the setting pass is just bird speculating on cache hits)
149 */
150 pgmLock(pVM);
151 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, true, pgmR3HandlerPhysicalOneClear, pVM);
152 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, false, pgmR3HandlerPhysicalOneSet, pVM);
153 pgmUnlock(pVM);
154}
155
156
157/**
158 * Clears all the page level flags for one physical handler range.
159 *
160 * @returns 0
161 * @param pNode Pointer to a PGMPHYSHANDLER.
162 * @param pvUser Pointer to the VM.
163 */
164static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PAVLROGCPHYSNODECORE pNode, void *pvUser)
165{
166 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
167 PPGMRAMRANGE pRamHint = NULL;
168 RTGCPHYS GCPhys = pCur->Core.Key;
169 RTUINT cPages = pCur->cPages;
170 PVM pVM = (PVM)pvUser;
171 for (;;)
172 {
173 PPGMPAGE pPage;
174 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
175 if (RT_SUCCESS(rc))
176 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE);
177 else
178 AssertRC(rc);
179
180 if (--cPages == 0)
181 return 0;
182 GCPhys += PAGE_SIZE;
183 }
184}
185
186
187/**
188 * Sets all the page level flags for one physical handler range.
189 *
190 * @returns 0
191 * @param pNode Pointer to a PGMPHYSHANDLER.
192 * @param pvUser Pointer to the VM.
193 */
194static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser)
195{
196 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
197 unsigned uState = pgmHandlerPhysicalCalcState(pCur);
198 PPGMRAMRANGE pRamHint = NULL;
199 RTGCPHYS GCPhys = pCur->Core.Key;
200 RTUINT cPages = pCur->cPages;
201 PVM pVM = (PVM)pvUser;
202 for (;;)
203 {
204 PPGMPAGE pPage;
205 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
206 if (RT_SUCCESS(rc))
207 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, uState);
208 else
209 AssertRC(rc);
210
211 if (--cPages == 0)
212 return 0;
213 GCPhys += PAGE_SIZE;
214 }
215}
216
217
218/**
219 * Register a access handler for a virtual range.
220 *
221 * @returns VBox status code.
222 * @param pVM Pointer to the VM.
223 * @param enmType Handler type. Any of the PGMVIRTHANDLERTYPE_* enums.
224 * @param GCPtr Start address.
225 * @param GCPtrLast Last address (inclusive).
226 * @param pfnInvalidateR3 The R3 invalidate callback (can be 0)
227 * @param pfnHandlerR3 The R3 handler.
228 * @param pszHandlerRC The RC handler symbol name.
229 * @param pszModRC The RC handler module.
230 * @param pszDesc Pointer to description string. This must not be freed.
231 */
232VMMR3DECL(int) PGMR3HandlerVirtualRegister(PVM pVM, PGMVIRTHANDLERTYPE enmType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
233 PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
234 PFNPGMR3VIRTHANDLER pfnHandlerR3,
235 const char *pszHandlerRC, const char *pszModRC,
236 const char *pszDesc)
237{
238 LogFlow(("PGMR3HandlerVirtualRegisterEx: enmType=%d GCPtr=%RGv GCPtrLast=%RGv pszHandlerRC=%p:{%s} pszModRC=%p:{%s} pszDesc=%s\n",
239 enmType, GCPtr, GCPtrLast, pszHandlerRC, pszHandlerRC, pszModRC, pszModRC, pszDesc));
240
241 /* Not supported/relevant for VT-x and AMD-V. */
242 if (HMIsEnabled(pVM))
243 return VERR_NOT_IMPLEMENTED;
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, NULL /*pszSearchPath*/, 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 Pointer to the VM.
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 /* Not supported/relevant for VT-x and AMD-V. */
295 if (HMIsEnabled(pVM))
296 return VERR_NOT_IMPLEMENTED;
297
298 /*
299 * Validate input.
300 */
301 switch (enmType)
302 {
303 case PGMVIRTHANDLERTYPE_ALL:
304 AssertReleaseMsgReturn( (GCPtr & PAGE_OFFSET_MASK) == 0
305 && (GCPtrLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK,
306 ("PGMVIRTHANDLERTYPE_ALL: GCPtr=%RGv GCPtrLast=%RGv\n", GCPtr, GCPtrLast),
307 VERR_NOT_IMPLEMENTED);
308 break;
309 case PGMVIRTHANDLERTYPE_WRITE:
310 if (!pfnHandlerR3)
311 {
312 AssertMsgFailed(("No HC handler specified!!\n"));
313 return VERR_INVALID_PARAMETER;
314 }
315 break;
316
317 case PGMVIRTHANDLERTYPE_HYPERVISOR:
318 if (pfnHandlerR3)
319 {
320 AssertMsgFailed(("R3 handler specified for hypervisor range!?!\n"));
321 return VERR_INVALID_PARAMETER;
322 }
323 break;
324 default:
325 AssertMsgFailed(("Invalid enmType! enmType=%d\n", enmType));
326 return VERR_INVALID_PARAMETER;
327 }
328 if (GCPtrLast < GCPtr)
329 {
330 AssertMsgFailed(("GCPtrLast < GCPtr (%#x < %#x)\n", GCPtrLast, GCPtr));
331 return VERR_INVALID_PARAMETER;
332 }
333 if (!pfnHandlerRC)
334 {
335 AssertMsgFailed(("pfnHandlerRC is missing\n"));
336 return VERR_INVALID_PARAMETER;
337 }
338
339 /*
340 * Allocate and initialize a new entry.
341 */
342 unsigned cPages = (RT_ALIGN(GCPtrLast + 1, PAGE_SIZE) - (GCPtr & PAGE_BASE_GC_MASK)) >> PAGE_SHIFT;
343 PPGMVIRTHANDLER pNew;
344 int rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew); /** @todo r=bird: incorrect member name PhysToVirt? */
345 if (RT_FAILURE(rc))
346 return rc;
347
348 pNew->Core.Key = GCPtr;
349 pNew->Core.KeyLast = GCPtrLast;
350
351 pNew->enmType = enmType;
352 pNew->pfnInvalidateR3 = pfnInvalidateR3;
353 pNew->pfnHandlerRC = pfnHandlerRC;
354 pNew->pfnHandlerR3 = pfnHandlerR3;
355 pNew->pszDesc = pszDesc;
356 pNew->cb = GCPtrLast - GCPtr + 1;
357 pNew->cPages = cPages;
358 /* Will be synced at next guest execution attempt. */
359 while (cPages-- > 0)
360 {
361 pNew->aPhysToVirt[cPages].Core.Key = NIL_RTGCPHYS;
362 pNew->aPhysToVirt[cPages].Core.KeyLast = NIL_RTGCPHYS;
363 pNew->aPhysToVirt[cPages].offVirtHandler = -RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]);
364 pNew->aPhysToVirt[cPages].offNextAlias = 0;
365 }
366
367 /*
368 * Try to insert it into the tree.
369 *
370 * The current implementation doesn't allow multiple handlers for
371 * the same range this makes everything much simpler and faster.
372 */
373 AVLROGCPTRTREE *pRoot = enmType != PGMVIRTHANDLERTYPE_HYPERVISOR
374 ? &pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers
375 : &pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers;
376 pgmLock(pVM);
377 if (*pRoot != 0)
378 {
379 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(pRoot, pNew->Core.Key, true);
380 if ( !pCur
381 || GCPtr > pCur->Core.KeyLast
382 || GCPtrLast < pCur->Core.Key)
383 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(pRoot, pNew->Core.Key, false);
384 if ( pCur
385 && GCPtr <= pCur->Core.KeyLast
386 && GCPtrLast >= pCur->Core.Key)
387 {
388 /*
389 * The LDT sometimes conflicts with the IDT and LDT ranges while being
390 * updated on linux. So, we don't assert simply log it.
391 */
392 Log(("PGMR3HandlerVirtualRegister: Conflict with existing range %RGv-%RGv (%s), req. %RGv-%RGv (%s)\n",
393 pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc, GCPtr, GCPtrLast, pszDesc));
394 MMHyperFree(pVM, pNew);
395 pgmUnlock(pVM);
396 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
397 }
398 }
399 if (RTAvlroGCPtrInsert(pRoot, &pNew->Core))
400 {
401 if (enmType != PGMVIRTHANDLERTYPE_HYPERVISOR)
402 {
403 PVMCPU pVCpu = VMMGetCpu(pVM);
404
405 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
406 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
407 }
408 pgmUnlock(pVM);
409
410#ifdef VBOX_WITH_STATISTICS
411 char szPath[256];
412 RTStrPrintf(szPath, sizeof(szPath), "/PGM/VirtHandler/Calls/%RGv-%RGv", pNew->Core.Key, pNew->Core.KeyLast);
413 rc = STAMR3Register(pVM, &pNew->Stat, STAMTYPE_PROFILE, STAMVISIBILITY_USED, szPath, STAMUNIT_TICKS_PER_CALL, pszDesc);
414 AssertRC(rc);
415#endif
416 return VINF_SUCCESS;
417 }
418
419 pgmUnlock(pVM);
420 AssertFailed();
421 MMHyperFree(pVM, pNew);
422 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
423}
424
425
426/**
427 * Modify the page invalidation callback handler for a registered virtual range.
428 * (add more when needed)
429 *
430 * @returns VBox status code.
431 * @param pVM Pointer to the VM.
432 * @param GCPtr Start address.
433 * @param pfnInvalidateR3 The R3 invalidate callback (can be 0)
434 * @remarks Doesn't work with the hypervisor access handler type.
435 */
436VMMDECL(int) PGMHandlerVirtualChangeInvalidateCallback(PVM pVM, RTGCPTR GCPtr, PFNPGMR3VIRTINVALIDATE pfnInvalidateR3)
437{
438 pgmLock(pVM);
439 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGet(&pVM->pgm.s.pTreesR3->VirtHandlers, GCPtr);
440 if (pCur)
441 {
442 pCur->pfnInvalidateR3 = pfnInvalidateR3;
443 pgmUnlock(pVM);
444 return VINF_SUCCESS;
445 }
446 pgmUnlock(pVM);
447 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
448 return VERR_INVALID_PARAMETER;
449}
450
451/**
452 * Deregister an access handler for a virtual range.
453 *
454 * @returns VBox status code.
455 * @param pVM Pointer to the VM.
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 for (uint32_t iPage = 0; iPage < pCur->cPages; iPage++)
478 if (pCur->aPhysToVirt[iPage].offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE)
479 pgmHandlerVirtualClearPage(pVM, pCur, iPage);
480
481 /*
482 * Schedule CR3 sync.
483 */
484 PVMCPU pVCpu = VMMGetCpu(pVM);
485
486 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
487 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
488 }
489 else
490 {
491 /* must be a hypervisor one then. */
492 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers, GCPtr);
493 if (RT_UNLIKELY(!pCur))
494 {
495 pgmUnlock(pVM);
496#ifndef DEBUG_sander
497 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
498#endif
499 return VERR_INVALID_PARAMETER;
500 }
501
502 Log(("PGMHandlerVirtualDeregister: Removing Hyper Virtual (%d) Range %RGv-%RGv %s\n", pCur->enmType,
503 pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
504 Assert(pCur->enmType == PGMVIRTHANDLERTYPE_HYPERVISOR);
505 }
506
507 pgmUnlock(pVM);
508
509 STAM_DEREG(pVM, &pCur->Stat);
510 MMHyperFree(pVM, pCur);
511
512 return VINF_SUCCESS;
513}
514
515
516/**
517 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
518 */
519typedef struct PGMHANDLERINFOARG
520{
521 /** The output helpers.*/
522 PCDBGFINFOHLP pHlp;
523 /** Set if statistics should be dumped. */
524 bool fStats;
525} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
526
527
528/**
529 * Info callback for 'pgmhandlers'.
530 *
531 * @param pHlp The output helpers.
532 * @param pszArgs The arguments. phys or virt.
533 */
534DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
535{
536 /*
537 * Test input.
538 */
539 PGMHANDLERINFOARG Args = { pHlp, /* .fStats = */ true };
540 bool fPhysical = !pszArgs || !*pszArgs;
541 bool fVirtual = fPhysical;
542 bool fHyper = fPhysical;
543 if (!fPhysical)
544 {
545 bool fAll = strstr(pszArgs, "all") != NULL;
546 fPhysical = fAll || strstr(pszArgs, "phys") != NULL;
547 fVirtual = fAll || strstr(pszArgs, "virt") != NULL;
548 fHyper = fAll || strstr(pszArgs, "hyper")!= NULL;
549 Args.fStats = strstr(pszArgs, "nost") == NULL;
550 }
551
552 /*
553 * Dump the handlers.
554 */
555 if (fPhysical)
556 {
557 pHlp->pfnPrintf(pHlp,
558 "Physical handlers: (PhysHandlers=%d (%#x))\n"
559 "%*s %*s %*s %*s HandlerGC UserGC Type Description\n",
560 pVM->pgm.s.pTreesR3->PhysHandlers, pVM->pgm.s.pTreesR3->PhysHandlers,
561 - (int)sizeof(RTGCPHYS) * 2, "From",
562 - (int)sizeof(RTGCPHYS) * 2 - 3, "- To (incl)",
563 - (int)sizeof(RTHCPTR) * 2 - 1, "HandlerHC",
564 - (int)sizeof(RTHCPTR) * 2 - 1, "UserHC");
565 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesR3->PhysHandlers, true, pgmR3InfoHandlersPhysicalOne, &Args);
566 }
567
568 if (fVirtual)
569 {
570 pHlp->pfnPrintf(pHlp,
571 "Virtual handlers:\n"
572 "%*s %*s %*s %*s Type Description\n",
573 - (int)sizeof(RTGCPTR) * 2, "From",
574 - (int)sizeof(RTGCPTR) * 2 - 3, "- To (excl)",
575 - (int)sizeof(RTHCPTR) * 2 - 1, "HandlerHC",
576 - (int)sizeof(RTRCPTR) * 2 - 1, "HandlerGC");
577 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->VirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
578 }
579
580 if (fHyper)
581 {
582 pHlp->pfnPrintf(pHlp,
583 "Hypervisor Virtual handlers:\n"
584 "%*s %*s %*s %*s Type Description\n",
585 - (int)sizeof(RTGCPTR) * 2, "From",
586 - (int)sizeof(RTGCPTR) * 2 - 3, "- To (excl)",
587 - (int)sizeof(RTHCPTR) * 2 - 1, "HandlerHC",
588 - (int)sizeof(RTRCPTR) * 2 - 1, "HandlerGC");
589 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->HyperVirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
590 }
591}
592
593
594/**
595 * Displays one physical handler range.
596 *
597 * @returns 0
598 * @param pNode Pointer to a PGMPHYSHANDLER.
599 * @param pvUser Pointer to command helper functions.
600 */
601static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
602{
603 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
604 PPGMHANDLERINFOARG pArgs= (PPGMHANDLERINFOARG)pvUser;
605 PCDBGFINFOHLP pHlp = pArgs->pHlp;
606 const char *pszType;
607 switch (pCur->enmType)
608 {
609 case PGMPHYSHANDLERTYPE_MMIO: pszType = "MMIO "; break;
610 case PGMPHYSHANDLERTYPE_PHYSICAL_WRITE: pszType = "Write "; break;
611 case PGMPHYSHANDLERTYPE_PHYSICAL_ALL: pszType = "All "; break;
612 default: pszType = "????"; break;
613 }
614 pHlp->pfnPrintf(pHlp,
615 "%RGp - %RGp %RHv %RHv %RRv %RRv %s %s\n",
616 pCur->Core.Key, pCur->Core.KeyLast, pCur->pfnHandlerR3, pCur->pvUserR3, pCur->pfnHandlerRC, pCur->pvUserRC, pszType, pCur->pszDesc);
617#ifdef VBOX_WITH_STATISTICS
618 if (pArgs->fStats)
619 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
620 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
621 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
622#endif
623 return 0;
624}
625
626
627/**
628 * Displays one virtual handler range.
629 *
630 * @returns 0
631 * @param pNode Pointer to a PGMVIRTHANDLER.
632 * @param pvUser Pointer to command helper functions.
633 */
634static DECLCALLBACK(int) pgmR3InfoHandlersVirtualOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
635{
636 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
637 PPGMHANDLERINFOARG pArgs= (PPGMHANDLERINFOARG)pvUser;
638 PCDBGFINFOHLP pHlp = pArgs->pHlp;
639 const char *pszType;
640 switch (pCur->enmType)
641 {
642 case PGMVIRTHANDLERTYPE_WRITE: pszType = "Write "; break;
643 case PGMVIRTHANDLERTYPE_ALL: pszType = "All "; break;
644 case PGMVIRTHANDLERTYPE_HYPERVISOR: pszType = "WriteHyp "; break;
645 default: pszType = "????"; break;
646 }
647 pHlp->pfnPrintf(pHlp, "%RGv - %RGv %RHv %RRv %s %s\n",
648 pCur->Core.Key, pCur->Core.KeyLast, pCur->pfnHandlerR3, pCur->pfnHandlerRC, pszType, pCur->pszDesc);
649#ifdef VBOX_WITH_STATISTICS
650 if (pArgs->fStats)
651 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
652 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
653 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
654#endif
655 return 0;
656}
657
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