VirtualBox

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

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

VMM: Added non-PF raw-mode context virtual page access handler callback (not yet called).

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