VirtualBox

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

Last change on this file since 63495 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

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