VirtualBox

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

Last change on this file since 55895 was 55895, checked in by vboxsync, 10 years ago

Added pvUser to the raw-mode context virtual handler callbacks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 30.8 KB
Line 
1/* $Id: PGMHandler.cpp 55895 2015-05-17 19:42:38Z vboxsync $ */
2/** @file
3 * PGM - Page Manager / Monitor, Access Handlers.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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/**
69 * Register a physical page access handler type, extended version.
70 *
71 * @returns VBox status code.
72 * @param pVM Pointer to the cross context VM structure.
73 * @param enmKind The kind of access handler.
74 * @param pfnHandlerR3 Pointer to the ring-3 handler callback.
75 * @param pfnHandlerR0 Pointer to the ring-0 handler callback.
76 * @param pfnHandlerRC Pointer to the raw-mode context handler callback.
77 * @param pszDesc The type description.
78 * @param phType Where to return the type handle (cross context
79 * safe).
80 */
81VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegisterEx(PVM pVM, PGMPHYSHANDLERKIND enmKind,
82 PFNPGMR3PHYSHANDLER pfnHandlerR3,
83 R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0,
84 RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC,
85 const char *pszDesc, PPGMPHYSHANDLERTYPE phType)
86{
87 AssertPtrReturn(pfnHandlerR3, VERR_INVALID_POINTER);
88 AssertReturn(pfnHandlerR0 != NIL_RTR0PTR, VERR_INVALID_POINTER);
89 AssertReturn(pfnHandlerRC != NIL_RTRCPTR || HMIsEnabled(pVM), VERR_INVALID_POINTER);
90 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
91 AssertReturn( enmKind == PGMPHYSHANDLERKIND_WRITE
92 || enmKind == PGMPHYSHANDLERKIND_ALL
93 || enmKind == PGMPHYSHANDLERKIND_MMIO,
94 VERR_INVALID_PARAMETER);
95
96 PPGMPHYSHANDLERTYPEINT pType;
97 int rc = MMHyperAlloc(pVM, sizeof(*pType), 0, MM_TAG_PGM_HANDLER_TYPES, (void **)&pType);
98 if (RT_SUCCESS(rc))
99 {
100 pType->u32Magic = PGMPHYSHANDLERTYPEINT_MAGIC;
101 pType->cRefs = 1;
102 pType->enmKind = enmKind;
103 pType->uState = enmKind == PGMPHYSHANDLERKIND_WRITE ? PGM_PAGE_HNDL_PHYS_STATE_WRITE : PGM_PAGE_HNDL_PHYS_STATE_ALL;
104 pType->pfnHandlerR3 = pfnHandlerR3;
105 pType->pfnHandlerR0 = pfnHandlerR0;
106 pType->pfnHandlerRC = pfnHandlerRC;
107 pType->pszDesc = pszDesc;
108
109 pgmLock(pVM);
110 RTListOff32Append(&pVM->pgm.s.CTX_SUFF(pTrees)->HeadPhysHandlerTypes, &pType->ListNode);
111 pgmUnlock(pVM);
112
113 *phType = MMHyperHeapPtrToOffset(pVM, pType);
114 LogFlow(("PGMR3HandlerPhysicalTypeRegisterEx: %p/%#x: enmKind=%d pfnHandlerR3=%RHv pfnHandlerR0=%RHv pfnHandlerRC=%RRv pszDesc=%s\n",
115 pType, *phType, enmKind, pfnHandlerR3, pfnHandlerR0, pfnHandlerRC, pszDesc));
116 return VINF_SUCCESS;
117 }
118 *phType = NIL_PGMPHYSHANDLERTYPE;
119 return rc;
120}
121
122
123/**
124 * Register a physical page access handler type.
125 *
126 * @returns VBox status code.
127 * @param pVM Pointer to the cross context VM structure.
128 * @param enmKind The kind of access handler.
129 * @param pfnHandlerR3 Pointer to the ring-3 handler callback.
130 * @param pszModR0 The name of the ring-0 module, NULL is an alias for
131 * the main ring-0 module.
132 * @param pszHandlerR0 The name of the ring-0 handler, NULL if the ring-3
133 * handler should be called.
134 * @param pszModRC The name of the raw-mode context module, NULL is an
135 * alias for the main RC module.
136 * @param pszHandlerRC The name of the raw-mode context handler, NULL if
137 * the ring-3 handler should be called.
138 * @param pszDesc The type description.
139 * @param phType Where to return the type handle (cross context
140 * safe).
141 */
142VMMR3DECL(int) PGMR3HandlerPhysicalTypeRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind,
143 R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3,
144 const char *pszModR0, const char *pszHandlerR0,
145 const char *pszModRC, const char *pszHandlerRC, const char *pszDesc,
146 PPGMPHYSHANDLERTYPE phType)
147{
148 LogFlow(("PGMR3HandlerPhysicalTypeRegister: enmKind=%d pfnHandlerR3=%RHv pszModR0=%s pszHandlerR0=%s pszModRC=%s pszHandlerRC=%s pszDesc=%s\n",
149 enmKind, pfnHandlerR3, pszModR0, pszHandlerR0, pszHandlerRC, pszModRC, pszDesc));
150
151 /*
152 * Validate input.
153 */
154 if (!pszModRC)
155 pszModRC = VMMGC_MAIN_MODULE_NAME;
156 if (!pszModR0)
157 pszModR0 = VMMR0_MAIN_MODULE_NAME;
158 if (!pszHandlerR0)
159 pszHandlerR0 = "pgmPhysHandlerRedirectToHC";
160 if (!pszHandlerRC)
161 pszHandlerRC = "pgmPhysHandlerRedirectToHC";
162 AssertPtrReturn(pfnHandlerR3, VERR_INVALID_POINTER);
163 AssertPtrReturn(pszHandlerR0, VERR_INVALID_POINTER);
164 AssertPtrReturn(pszHandlerRC, VERR_INVALID_POINTER);
165
166 /*
167 * Resolve the R0 handler.
168 */
169 R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0 = NIL_RTR0PTR;
170 int rc = PDMR3LdrGetSymbolR0Lazy(pVM, pszModR0, NULL /*pszSearchPath*/, pszHandlerR0, &pfnHandlerR0);
171 if (RT_SUCCESS(rc))
172 {
173 /*
174 * Resolve the GC handler.
175 */
176 RTRCPTR pfnHandlerRC = NIL_RTRCPTR;
177 if (!HMIsEnabled(pVM))
178 rc = PDMR3LdrGetSymbolRCLazy(pVM, pszModRC, NULL /*pszSearchPath*/, pszHandlerRC, &pfnHandlerRC);
179 if (RT_SUCCESS(rc))
180 return PGMR3HandlerPhysicalTypeRegisterEx(pVM, enmKind, pfnHandlerR3, pfnHandlerR0, pfnHandlerRC, pszDesc, phType);
181
182 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszModRC, pszHandlerRC, rc));
183 }
184 else
185 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszModR0, pszHandlerR0, rc));
186
187 return rc;
188}
189
190
191/**
192 * Updates the physical page access handlers.
193 *
194 * @param pVM Pointer to the VM.
195 * @remark Only used when restoring a saved state.
196 */
197void pgmR3HandlerPhysicalUpdateAll(PVM pVM)
198{
199 LogFlow(("pgmHandlerPhysicalUpdateAll:\n"));
200
201 /*
202 * Clear and set.
203 * (the right -> left on the setting pass is just bird speculating on cache hits)
204 */
205 pgmLock(pVM);
206 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, true, pgmR3HandlerPhysicalOneClear, pVM);
207 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, false, pgmR3HandlerPhysicalOneSet, pVM);
208 pgmUnlock(pVM);
209}
210
211
212/**
213 * Clears all the page level flags for one physical handler range.
214 *
215 * @returns 0
216 * @param pNode Pointer to a PGMPHYSHANDLER.
217 * @param pvUser Pointer to the VM.
218 */
219static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PAVLROGCPHYSNODECORE pNode, void *pvUser)
220{
221 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
222 PPGMRAMRANGE pRamHint = NULL;
223 RTGCPHYS GCPhys = pCur->Core.Key;
224 RTUINT cPages = pCur->cPages;
225 PVM pVM = (PVM)pvUser;
226 for (;;)
227 {
228 PPGMPAGE pPage;
229 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
230 if (RT_SUCCESS(rc))
231 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE);
232 else
233 AssertRC(rc);
234
235 if (--cPages == 0)
236 return 0;
237 GCPhys += PAGE_SIZE;
238 }
239}
240
241
242/**
243 * Sets all the page level flags for one physical handler range.
244 *
245 * @returns 0
246 * @param pNode Pointer to a PGMPHYSHANDLER.
247 * @param pvUser Pointer to the VM.
248 */
249static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser)
250{
251 PVM pVM = (PVM)pvUser;
252 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
253 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
254 unsigned uState = pCurType->uState;
255 PPGMRAMRANGE pRamHint = NULL;
256 RTGCPHYS GCPhys = pCur->Core.Key;
257 RTUINT cPages = pCur->cPages;
258 for (;;)
259 {
260 PPGMPAGE pPage;
261 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
262 if (RT_SUCCESS(rc))
263 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, uState);
264 else
265 AssertRC(rc);
266
267 if (--cPages == 0)
268 return 0;
269 GCPhys += PAGE_SIZE;
270 }
271}
272
273
274/**
275 * Register a virtual page access handler type, extended version.
276 *
277 * @returns VBox status code.
278 * @param pVM Pointer to the cross context VM structure.
279 * @param enmKind The kind of access handler.
280 * @param fRelocUserRC Whether the pvUserRC argument should be
281 * automatically relocated or not.
282 * @param pfnInvalidateR3 Pointer to the ring-3 invalidation handler callback.
283 * @param pfnHandlerR3 Pointer to the ring-3 handler callback.
284 * @param pfnHandlerRC Pointer to the raw-mode context handler callback.
285 * @param pszDesc The type description.
286 * @param phType Where to return the type handle (cross context
287 * safe).
288 * @remarks No virtual handlers when executing using HM (i.e. ring-0).
289 */
290VMMR3_INT_DECL(int) PGMR3HandlerVirtualTypeRegisterEx(PVM pVM, PGMVIRTHANDLERKIND enmKind, bool fRelocUserRC,
291 PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
292 PFNPGMR3VIRTHANDLER pfnHandlerR3,
293 RCPTRTYPE(FNPGMRCVIRTPFHANDLER) pfnPfHandlerRC,
294 const char *pszDesc, PPGMVIRTHANDLERTYPE phType)
295{
296 AssertReturn(!HMIsEnabled(pVM), VERR_NOT_AVAILABLE); /* Not supported/relevant for VT-x and AMD-V. */
297 AssertReturn(RT_VALID_PTR(pfnHandlerR3) || enmKind == PGMVIRTHANDLERKIND_HYPERVISOR, VERR_INVALID_POINTER);
298 AssertPtrNullReturn(pfnInvalidateR3, VERR_INVALID_POINTER);
299 AssertReturn(pfnPfHandlerRC != NIL_RTRCPTR, VERR_INVALID_POINTER);
300 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
301 AssertReturn( enmKind == PGMVIRTHANDLERKIND_WRITE
302 || enmKind == PGMVIRTHANDLERKIND_ALL
303 || enmKind == PGMVIRTHANDLERKIND_HYPERVISOR,
304 VERR_INVALID_PARAMETER);
305
306 PPGMVIRTHANDLERTYPEINT pType;
307 int rc = MMHyperAlloc(pVM, sizeof(*pType), 0, MM_TAG_PGM_HANDLER_TYPES, (void **)&pType);
308 if (RT_SUCCESS(rc))
309 {
310 pType->u32Magic = PGMVIRTHANDLERTYPEINT_MAGIC;
311 pType->cRefs = 1;
312 pType->enmKind = enmKind;
313 pType->fRelocUserRC = fRelocUserRC;
314 pType->uState = enmKind == PGMVIRTHANDLERKIND_ALL
315 ? PGM_PAGE_HNDL_VIRT_STATE_ALL : PGM_PAGE_HNDL_VIRT_STATE_WRITE;
316 pType->pfnInvalidateR3 = pfnInvalidateR3;
317 pType->pfnHandlerR3 = pfnHandlerR3;
318 pType->pfnPfHandlerRC = pfnPfHandlerRC;
319 pType->pszDesc = pszDesc;
320
321 pgmLock(pVM);
322 RTListOff32Append(&pVM->pgm.s.CTX_SUFF(pTrees)->HeadVirtHandlerTypes, &pType->ListNode);
323 pgmUnlock(pVM);
324
325 *phType = MMHyperHeapPtrToOffset(pVM, pType);
326 LogFlow(("PGMR3HandlerVirtualTypeRegisterEx: %p/%#x: enmKind=%d pfnInvalidateR3=%RHv pfnHandlerR3=%RHv pfnPfHandlerRC=%RRv pszDesc=%s\n",
327 pType, *phType, enmKind, pfnInvalidateR3, pfnHandlerR3, pfnPfHandlerRC, pszDesc));
328 return VINF_SUCCESS;
329 }
330 *phType = NIL_PGMVIRTHANDLERTYPE;
331 return rc;
332}
333
334
335/**
336 * Register a physical page access handler type.
337 *
338 * @returns VBox status code.
339 * @param pVM Pointer to the cross context VM structure.
340 * @param enmKind The kind of access handler.
341 * @param fRelocUserRC Whether the pvUserRC argument should be
342 * automatically relocated or not.
343 * @param pfnInvalidateR3 Pointer to the ring-3 invalidateion callback
344 * (optional, can be NULL).
345 * @param pfnHandlerR3 Pointer to the ring-3 handler callback.
346 * @param pszModRC The name of the raw-mode context module, NULL is an
347 * alias for the main RC module.
348 * @param pszPfHandlerRC The name of the raw-mode context handler, NULL if
349 * the ring-3 handler should be called.
350 * @param pszDesc The type description.
351 * @param phType Where to return the type handle (cross context
352 * safe).
353 * @remarks No virtual handlers when executing using HM (i.e. ring-0).
354 */
355VMMR3_INT_DECL(int) PGMR3HandlerVirtualTypeRegister(PVM pVM, PGMVIRTHANDLERKIND enmKind, bool fRelocUserRC,
356 PFNPGMR3VIRTINVALIDATE pfnInvalidateR3,
357 PFNPGMR3VIRTHANDLER pfnHandlerR3,
358 const char *pszPfHandlerRC, const char *pszModRC, const char *pszDesc,
359 PPGMVIRTHANDLERTYPE phType)
360{
361 LogFlow(("PGMR3HandlerVirtualTypeRegister: enmKind=%d pfnInvalidateR3=%RHv pfnHandlerR3=%RHv pszModRC=%s pszPfHandlerRC=%s pszDesc=%s\n",
362 enmKind, pfnInvalidateR3, pfnHandlerR3, pszPfHandlerRC, pszModRC, pszDesc));
363
364 /*
365 * Validate input.
366 */
367 if (!pszModRC)
368 pszModRC = VMMGC_MAIN_MODULE_NAME;
369 AssertPtrReturn(pszPfHandlerRC, VERR_INVALID_POINTER);
370
371 /*
372 * Resolve the GC handler.
373 */
374 RTRCPTR pfnPfHandlerRC = NIL_RTRCPTR;
375 int rc = PDMR3LdrGetSymbolRCLazy(pVM, pszModRC, NULL /*pszSearchPath*/, pszPfHandlerRC, &pfnPfHandlerRC);
376 if (RT_SUCCESS(rc))
377 return PGMR3HandlerVirtualTypeRegisterEx(pVM, enmKind, fRelocUserRC,
378 pfnInvalidateR3, pfnHandlerR3,
379 pfnPfHandlerRC,
380 pszDesc, phType);
381
382 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszModRC, pszPfHandlerRC, rc));
383 return rc;
384}
385
386
387/**
388 * Register a access handler for a virtual range.
389 *
390 * @returns VBox status code.
391 * @param pVM Pointer to the VM.
392 * @param hType The handler type.
393 * @param GCPtr Start address.
394 * @param GCPtrLast Last address (inclusive).
395 * @param pvUserR3 The ring-3 context user argument.
396 * @param pvUserRC The raw-mode context user argument. Whether this is
397 * automatically relocated or not depends on the type.
398 * @param pszDesc Pointer to description string. This must not be freed.
399 */
400VMMR3_INT_DECL(int) PGMR3HandlerVirtualRegister(PVM pVM, PVMCPU pVCpu, PGMVIRTHANDLERTYPE hType, RTGCPTR GCPtr, RTGCPTR GCPtrLast,
401 void *pvUserR3, RTRCPTR pvUserRC, const char *pszDesc)
402{
403 AssertReturn(!HMIsEnabled(pVM), VERR_NOT_AVAILABLE); /* Not supported/relevant for VT-x and AMD-V. */
404 PPGMVIRTHANDLERTYPEINT pType = PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hType);
405 Log(("PGMR3HandlerVirtualRegister: GCPhys=%RGp GCPhysLast=%RGp pvUserR3=%RHv pvUserGC=%RRv hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
406 GCPtr, GCPtrLast, pvUserR3, pvUserRC, hType, pType->enmKind, R3STRING(pType->pszDesc), pszDesc, R3STRING(pszDesc)));
407
408 /*
409 * Validate input.
410 */
411 AssertReturn(pType->u32Magic == PGMVIRTHANDLERTYPEINT_MAGIC, VERR_INVALID_HANDLE);
412 AssertMsgReturn(GCPtr < GCPtrLast, ("GCPtr >= GCPtrLast (%RGp >= %RGp)\n", GCPtr, GCPtrLast), VERR_INVALID_PARAMETER);
413 switch (pType->enmKind)
414 {
415 case PGMVIRTHANDLERKIND_ALL:
416 AssertReleaseMsgReturn( (GCPtr & PAGE_OFFSET_MASK) == 0
417 && (GCPtrLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK,
418 ("PGMVIRTHANDLERKIND_ALL: GCPtr=%RGv GCPtrLast=%RGv\n", GCPtr, GCPtrLast),
419 VERR_NOT_IMPLEMENTED);
420 break;
421 case PGMVIRTHANDLERKIND_WRITE:
422 case PGMVIRTHANDLERKIND_HYPERVISOR:
423 break;
424 default:
425 AssertMsgFailedReturn(("Invalid enmKind=%d!\n", pType->enmKind), VERR_INVALID_PARAMETER);
426 }
427 AssertMsgReturn( (RTRCUINTPTR)pvUserRC < 0x10000
428 || MMHyperR3ToRC(pVM, MMHyperRCToR3(pVM, pvUserRC)) == pvUserRC,
429 ("Not RC pointer! pvUserRC=%RRv\n", pvUserRC),
430 VERR_INVALID_PARAMETER);
431
432 /*
433 * Allocate and initialize a new entry.
434 */
435 unsigned cPages = (RT_ALIGN(GCPtrLast + 1, PAGE_SIZE) - (GCPtr & PAGE_BASE_GC_MASK)) >> PAGE_SHIFT;
436 PPGMVIRTHANDLER pNew;
437 int rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew); /** @todo r=bird: incorrect member name PhysToVirt? */
438 if (RT_FAILURE(rc))
439 return rc;
440
441 pNew->Core.Key = GCPtr;
442 pNew->Core.KeyLast = GCPtrLast;
443
444 pNew->hType = hType;
445 pNew->pvUserRC = pvUserRC;
446 pNew->pvUserR3 = pvUserR3;
447 pNew->pszDesc = pszDesc ? pszDesc : pType->pszDesc;
448 pNew->cb = GCPtrLast - GCPtr + 1;
449 pNew->cPages = cPages;
450 /* Will be synced at next guest execution attempt. */
451 while (cPages-- > 0)
452 {
453 pNew->aPhysToVirt[cPages].Core.Key = NIL_RTGCPHYS;
454 pNew->aPhysToVirt[cPages].Core.KeyLast = NIL_RTGCPHYS;
455 pNew->aPhysToVirt[cPages].offVirtHandler = -RT_OFFSETOF(PGMVIRTHANDLER, aPhysToVirt[cPages]);
456 pNew->aPhysToVirt[cPages].offNextAlias = 0;
457 }
458
459 /*
460 * Try to insert it into the tree.
461 *
462 * The current implementation doesn't allow multiple handlers for
463 * the same range this makes everything much simpler and faster.
464 */
465 AVLROGCPTRTREE *pRoot = pType->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR
466 ? &pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers
467 : &pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers;
468 pgmLock(pVM);
469 if (*pRoot != 0)
470 {
471 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(pRoot, pNew->Core.Key, true);
472 if ( !pCur
473 || GCPtr > pCur->Core.KeyLast
474 || GCPtrLast < pCur->Core.Key)
475 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGetBestFit(pRoot, pNew->Core.Key, false);
476 if ( pCur
477 && GCPtr <= pCur->Core.KeyLast
478 && GCPtrLast >= pCur->Core.Key)
479 {
480 /*
481 * The LDT sometimes conflicts with the IDT and LDT ranges while being
482 * updated on linux. So, we don't assert simply log it.
483 */
484 Log(("PGMR3HandlerVirtualRegister: Conflict with existing range %RGv-%RGv (%s), req. %RGv-%RGv (%s)\n",
485 pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc, GCPtr, GCPtrLast, pszDesc));
486 MMHyperFree(pVM, pNew);
487 pgmUnlock(pVM);
488 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
489 }
490 }
491 if (RTAvlroGCPtrInsert(pRoot, &pNew->Core))
492 {
493 if (pType->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR)
494 {
495 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
496 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
497 }
498 PGMHandlerVirtualTypeRetain(pVM, hType);
499 pgmUnlock(pVM);
500
501#ifdef VBOX_WITH_STATISTICS
502 rc = STAMR3RegisterF(pVM, &pNew->Stat, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, pNew->pszDesc,
503 "/PGM/VirtHandler/Calls/%RGv-%RGv", pNew->Core.Key, pNew->Core.KeyLast);
504 AssertRC(rc);
505#endif
506 return VINF_SUCCESS;
507 }
508
509 pgmUnlock(pVM);
510 AssertFailed();
511 MMHyperFree(pVM, pNew);
512 return VERR_PGM_HANDLER_VIRTUAL_CONFLICT;
513
514}
515
516
517/**
518 * Changes the type of a virtual handler.
519 *
520 * The new and old type must have the same access kind.
521 *
522 * @returns VBox status code.
523 * @param pVM Pointer to the VM.
524 * @param GCPtr Start address of the virtual handler.
525 * @param hNewType The new handler type.
526 */
527VMMR3_INT_DECL(int) PGMHandlerVirtualChangeType(PVM pVM, RTGCPTR GCPtr, PGMVIRTHANDLERTYPE hNewType)
528{
529 PPGMVIRTHANDLERTYPEINT pNewType = PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hNewType);
530 AssertReturn(pNewType->u32Magic == PGMVIRTHANDLERTYPEINT_MAGIC, VERR_INVALID_HANDLE);
531
532 pgmLock(pVM);
533 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGet(&pVM->pgm.s.pTreesR3->VirtHandlers, GCPtr);
534 if (pCur)
535 {
536 PGMVIRTHANDLERTYPE hOldType = pCur->hType;
537 PPGMVIRTHANDLERTYPEINT pOldType = PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hOldType);
538 if (pOldType != pNewType)
539 {
540 AssertReturnStmt(pNewType->enmKind == pOldType->enmKind, pgmUnlock(pVM), VERR_ACCESS_DENIED);
541 PGMHandlerVirtualTypeRetain(pVM, hNewType);
542 pCur->hType = hNewType;
543 PGMHandlerVirtualTypeRelease(pVM, hOldType);
544 }
545 pgmUnlock(pVM);
546 return VINF_SUCCESS;
547 }
548 pgmUnlock(pVM);
549 AssertMsgFailed(("Range %#x not found!\n", GCPtr));
550 return VERR_INVALID_PARAMETER;
551}
552
553
554/**
555 * Deregister an access handler for a virtual range.
556 *
557 * @returns VBox status code.
558 * @param pVM Pointer to the VM.
559 * @param pVCpu Pointer to the cross context CPU structure for the
560 * calling EMT.
561 * @param GCPtr Start address.
562 * @param fHypervisor Set if PGMVIRTHANDLERKIND_HYPERVISOR, false if not.
563 * @thread EMT(pVCpu)
564 */
565VMMR3_INT_DECL(int) PGMHandlerVirtualDeregister(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, bool fHypervisor)
566{
567 pgmLock(pVM);
568
569 PPGMVIRTHANDLER pCur;
570 if (!fHypervisor)
571 {
572 /*
573 * Normal guest handler.
574 */
575 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtr);
576 AssertMsgReturnStmt(pCur, ("GCPtr=%RGv\n", GCPtr), pgmUnlock(pVM), VERR_INVALID_PARAMETER);
577 Assert(PGMVIRTANDLER_GET_TYPE(pVM, pCur)->enmKind != PGMVIRTHANDLERKIND_HYPERVISOR);
578
579 Log(("PGMHandlerVirtualDeregister: Removing Virtual (%d) Range %RGv-%RGv %s\n",
580 PGMVIRTANDLER_GET_TYPE(pVM, pCur)->enmKind, pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
581
582 /* Reset the flags and remove phys2virt nodes. */
583 for (uint32_t iPage = 0; iPage < pCur->cPages; iPage++)
584 if (pCur->aPhysToVirt[iPage].offNextAlias & PGMPHYS2VIRTHANDLER_IN_TREE)
585 pgmHandlerVirtualClearPage(pVM, pCur, iPage);
586
587 /* Schedule CR3 sync. */
588 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL | PGM_SYNC_CLEAR_PGM_POOL;
589 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
590 }
591 else
592 {
593 /*
594 * Hypervisor one (hypervisor relocation or termination only).
595 */
596 pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->HyperVirtHandlers, GCPtr);
597 AssertMsgReturnStmt(pCur, ("GCPtr=%RGv\n", GCPtr), pgmUnlock(pVM), VERR_INVALID_PARAMETER);
598 Assert(PGMVIRTANDLER_GET_TYPE(pVM, pCur)->enmKind == PGMVIRTHANDLERKIND_HYPERVISOR);
599
600 Log(("PGMHandlerVirtualDeregister: Removing Hyper Virtual Range %RGv-%RGv %s\n",
601 pCur->Core.Key, pCur->Core.KeyLast, pCur->pszDesc));
602 }
603
604 pgmUnlock(pVM);
605
606 /*
607 * Free it.
608 */
609#ifdef VBOX_WITH_STATISTICS
610 STAMR3DeregisterF(pVM->pUVM, "/PGM/VirtHandler/Calls/%RGv-%RGv", pCur->Core.Key, pCur->Core.KeyLast);
611#endif
612 PGMHandlerVirtualTypeRelease(pVM, pCur->hType);
613 MMHyperFree(pVM, pCur);
614
615 return VINF_SUCCESS;
616}
617
618
619/**
620 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
621 */
622typedef struct PGMHANDLERINFOARG
623{
624 /** The output helpers.*/
625 PCDBGFINFOHLP pHlp;
626 /** Pointer to the cross context VM handle. */
627 PVM pVM;
628 /** Set if statistics should be dumped. */
629 bool fStats;
630} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
631
632
633/**
634 * Info callback for 'pgmhandlers'.
635 *
636 * @param pHlp The output helpers.
637 * @param pszArgs The arguments. phys or virt.
638 */
639DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
640{
641 /*
642 * Test input.
643 */
644 PGMHANDLERINFOARG Args = { pHlp, pVM, /* .fStats = */ true };
645 bool fPhysical = !pszArgs || !*pszArgs;
646 bool fVirtual = fPhysical;
647 bool fHyper = fPhysical;
648 if (!fPhysical)
649 {
650 bool fAll = strstr(pszArgs, "all") != NULL;
651 fPhysical = fAll || strstr(pszArgs, "phys") != NULL;
652 fVirtual = fAll || strstr(pszArgs, "virt") != NULL;
653 fHyper = fAll || strstr(pszArgs, "hyper")!= NULL;
654 Args.fStats = strstr(pszArgs, "nost") == NULL;
655 }
656
657 /*
658 * Dump the handlers.
659 */
660 if (fPhysical)
661 {
662 pHlp->pfnPrintf(pHlp,
663 "Physical handlers: (PhysHandlers=%d (%#x))\n"
664 "%*s %*s %*s %*s HandlerGC UserGC Type Description\n",
665 pVM->pgm.s.pTreesR3->PhysHandlers, pVM->pgm.s.pTreesR3->PhysHandlers,
666 - (int)sizeof(RTGCPHYS) * 2, "From",
667 - (int)sizeof(RTGCPHYS) * 2 - 3, "- To (incl)",
668 - (int)sizeof(RTHCPTR) * 2 - 1, "HandlerHC",
669 - (int)sizeof(RTHCPTR) * 2 - 1, "UserHC");
670 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesR3->PhysHandlers, true, pgmR3InfoHandlersPhysicalOne, &Args);
671 }
672
673 if (fVirtual)
674 {
675 pHlp->pfnPrintf(pHlp,
676 "Virtual handlers:\n"
677 "%*s %*s %*s %*s Type Description\n",
678 - (int)sizeof(RTGCPTR) * 2, "From",
679 - (int)sizeof(RTGCPTR) * 2 - 3, "- To (excl)",
680 - (int)sizeof(RTHCPTR) * 2 - 1, "HandlerHC",
681 - (int)sizeof(RTRCPTR) * 2 - 1, "HandlerGC");
682 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->VirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
683 }
684
685 if (fHyper)
686 {
687 pHlp->pfnPrintf(pHlp,
688 "Hypervisor Virtual handlers:\n"
689 "%*s %*s %*s %*s Type Description\n",
690 - (int)sizeof(RTGCPTR) * 2, "From",
691 - (int)sizeof(RTGCPTR) * 2 - 3, "- To (excl)",
692 - (int)sizeof(RTHCPTR) * 2 - 1, "HandlerHC",
693 - (int)sizeof(RTRCPTR) * 2 - 1, "HandlerGC");
694 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.pTreesR3->HyperVirtHandlers, true, pgmR3InfoHandlersVirtualOne, &Args);
695 }
696}
697
698
699/**
700 * Displays one physical handler range.
701 *
702 * @returns 0
703 * @param pNode Pointer to a PGMPHYSHANDLER.
704 * @param pvUser Pointer to command helper functions.
705 */
706static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
707{
708 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
709 PPGMHANDLERINFOARG pArgs = (PPGMHANDLERINFOARG)pvUser;
710 PCDBGFINFOHLP pHlp = pArgs->pHlp;
711 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pArgs->pVM, pCur);
712 const char *pszType;
713 switch (pCurType->enmKind)
714 {
715 case PGMPHYSHANDLERKIND_MMIO: pszType = "MMIO "; break;
716 case PGMPHYSHANDLERKIND_WRITE: pszType = "Write "; break;
717 case PGMPHYSHANDLERKIND_ALL: pszType = "All "; break;
718 default: pszType = "????"; break;
719 }
720 pHlp->pfnPrintf(pHlp,
721 "%RGp - %RGp %RHv %RHv %RRv %RRv %s %s\n",
722 pCur->Core.Key, pCur->Core.KeyLast, pCurType->pfnHandlerR3, pCur->pvUserR3, pCurType->pfnHandlerRC, pCur->pvUserRC,
723 pszType, pCur->pszDesc);
724#ifdef VBOX_WITH_STATISTICS
725 if (pArgs->fStats)
726 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
727 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
728 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
729#endif
730 return 0;
731}
732
733
734/**
735 * Displays one virtual handler range.
736 *
737 * @returns 0
738 * @param pNode Pointer to a PGMVIRTHANDLER.
739 * @param pvUser Pointer to command helper functions.
740 */
741static DECLCALLBACK(int) pgmR3InfoHandlersVirtualOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
742{
743 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
744 PPGMHANDLERINFOARG pArgs = (PPGMHANDLERINFOARG)pvUser;
745 PCDBGFINFOHLP pHlp = pArgs->pHlp;
746 PPGMVIRTHANDLERTYPEINT pCurType = PGMVIRTANDLER_GET_TYPE(pArgs->pVM, pCur);
747 const char *pszType;
748 switch (pCurType->enmKind)
749 {
750 case PGMVIRTHANDLERKIND_WRITE: pszType = "Write "; break;
751 case PGMVIRTHANDLERKIND_ALL: pszType = "All "; break;
752 case PGMVIRTHANDLERKIND_HYPERVISOR: pszType = "WriteHyp "; break;
753 default: pszType = "????"; break;
754 }
755 pHlp->pfnPrintf(pHlp, "%RGv - %RGv %RHv %RRv %s %s\n",
756 pCur->Core.Key, pCur->Core.KeyLast, pCurType->pfnHandlerR3, pCurType->pfnPfHandlerRC, pszType, pCur->pszDesc);
757#ifdef VBOX_WITH_STATISTICS
758 if (pArgs->fStats)
759 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
760 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
761 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
762#endif
763 return 0;
764}
765
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette