VirtualBox

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

Last change on this file since 72358 was 70977, checked in by vboxsync, 7 years ago

NEM: Working on PGM notifications. bugref:9044

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