VirtualBox

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

Last change on this file since 57446 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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