VirtualBox

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

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

PGM: Made the virtual handler callbacks return VBOXSTRICTRC and prepared for RC execution.

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