VirtualBox

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

Last change on this file since 80161 was 80007, checked in by vboxsync, 5 years ago

VMM: Kicking out raw-mode (work in progress). bugref:9517

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