VirtualBox

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

Last change on this file since 86087 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 16.5 KB
Line 
1/* $Id: PGMHandler.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * PGM - Page Manager / Monitor, Access Handlers.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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/dbgf.h>
32#include <VBox/vmm/selm.h>
33#include <VBox/vmm/ssm.h>
34#include "PGMInternal.h"
35#include <VBox/vmm/vm.h>
36#include "PGMInline.h"
37#include <VBox/dbg.h>
38
39#include <VBox/log.h>
40#include <iprt/assert.h>
41#include <iprt/alloc.h>
42#include <iprt/asm.h>
43#include <iprt/errcore.h>
44#include <iprt/thread.h>
45#include <iprt/string.h>
46#include <VBox/param.h>
47#include <VBox/vmm/hm.h>
48
49
50/*********************************************************************************************************************************
51* Internal Functions *
52*********************************************************************************************************************************/
53static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PAVLROGCPHYSNODECORE pNode, void *pvUser);
54static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser);
55static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser);
56
57
58
59
60/**
61 * Register a physical page access handler type, extended version.
62 *
63 * @returns VBox status code.
64 * @param pVM The cross context VM structure.
65 * @param enmKind The kind of access handler.
66 * @param pfnHandlerR3 Pointer to the ring-3 handler callback.
67 * @param pfnHandlerR0 Pointer to the ring-0 handler callback.
68 * @param pfnPfHandlerR0 Pointer to the ring-0 \#PF handler callback.
69 * callback.
70 * @param pszDesc The type description.
71 * @param phType Where to return the type handle (cross context
72 * safe).
73 */
74VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegisterEx(PVM pVM, PGMPHYSHANDLERKIND enmKind,
75 PFNPGMPHYSHANDLER pfnHandlerR3,
76 R0PTRTYPE(PFNPGMPHYSHANDLER) pfnHandlerR0,
77 R0PTRTYPE(PFNPGMRZPHYSPFHANDLER) pfnPfHandlerR0,
78 const char *pszDesc, PPGMPHYSHANDLERTYPE phType)
79{
80 AssertPtrReturn(pfnHandlerR3, VERR_INVALID_POINTER);
81 AssertReturn(pfnHandlerR0 != NIL_RTR0PTR, VERR_INVALID_POINTER);
82 AssertReturn(pfnPfHandlerR0 != NIL_RTR0PTR, VERR_INVALID_POINTER);
83 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
84 AssertReturn( enmKind == PGMPHYSHANDLERKIND_WRITE
85 || enmKind == PGMPHYSHANDLERKIND_ALL
86 || enmKind == PGMPHYSHANDLERKIND_MMIO,
87 VERR_INVALID_PARAMETER);
88
89 PPGMPHYSHANDLERTYPEINT pType;
90 int rc = MMHyperAlloc(pVM, sizeof(*pType), 0, MM_TAG_PGM_HANDLER_TYPES, (void **)&pType);
91 if (RT_SUCCESS(rc))
92 {
93 pType->u32Magic = PGMPHYSHANDLERTYPEINT_MAGIC;
94 pType->cRefs = 1;
95 pType->enmKind = enmKind;
96 pType->uState = enmKind == PGMPHYSHANDLERKIND_WRITE
97 ? PGM_PAGE_HNDL_PHYS_STATE_WRITE : PGM_PAGE_HNDL_PHYS_STATE_ALL;
98 pType->pfnHandlerR3 = pfnHandlerR3;
99 pType->pfnHandlerR0 = pfnHandlerR0;
100 pType->pfnPfHandlerR0 = pfnPfHandlerR0;
101 pType->pszDesc = pszDesc;
102
103 pgmLock(pVM);
104 RTListOff32Append(&pVM->pgm.s.CTX_SUFF(pTrees)->HeadPhysHandlerTypes, &pType->ListNode);
105 pgmUnlock(pVM);
106
107 *phType = MMHyperHeapPtrToOffset(pVM, pType);
108 LogFlow(("PGMR3HandlerPhysicalTypeRegisterEx: %p/%#x: enmKind=%d pfnHandlerR3=%RHv pfnHandlerR0=%RHv pszDesc=%s\n",
109 pType, *phType, enmKind, pfnHandlerR3, pfnPfHandlerR0, pszDesc));
110 return VINF_SUCCESS;
111 }
112 *phType = NIL_PGMPHYSHANDLERTYPE;
113 return rc;
114}
115
116
117/**
118 * Register a physical page access handler type.
119 *
120 * @returns VBox status code.
121 * @param pVM The cross context VM structure.
122 * @param enmKind The kind of access handler.
123 * @param pfnHandlerR3 Pointer to the ring-3 handler callback.
124 * @param pszModR0 The name of the ring-0 module, NULL is an alias for
125 * the main ring-0 module.
126 * @param pszHandlerR0 The name of the ring-0 handler, NULL if the ring-3
127 * handler should be called.
128 * @param pszPfHandlerR0 The name of the ring-0 \#PF handler, NULL if the
129 * ring-3 handler should be called.
130 * @param pszModRC The name of the raw-mode context module, NULL is an
131 * alias for the main RC module.
132 * @param pszHandlerRC The name of the raw-mode context handler, NULL if
133 * the ring-3 handler should be called.
134 * @param pszPfHandlerRC The name of the raw-mode context \#PF handler, NULL
135 * if the ring-3 handler should be called.
136 * @param pszDesc The type description.
137 * @param phType Where to return the type handle (cross context
138 * safe).
139 */
140VMMR3DECL(int) PGMR3HandlerPhysicalTypeRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind,
141 R3PTRTYPE(PFNPGMPHYSHANDLER) pfnHandlerR3,
142 const char *pszModR0, const char *pszHandlerR0, const char *pszPfHandlerR0,
143 const char *pszModRC, const char *pszHandlerRC, const char *pszPfHandlerRC,
144 const char *pszDesc, PPGMPHYSHANDLERTYPE phType)
145{
146 LogFlow(("PGMR3HandlerPhysicalTypeRegister: enmKind=%d pfnHandlerR3=%RHv pszModR0=%s pszHandlerR0=%s pszPfHandlerR0=%s pszModRC=%s pszHandlerRC=%s pszPfHandlerRC=%s pszDesc=%s\n",
147 enmKind, pfnHandlerR3, pszModR0, pszHandlerR0, pszPfHandlerR0, pszModRC, pszHandlerRC, pszPfHandlerRC, pszDesc));
148
149 /*
150 * Validate input.
151 */
152 AssertPtrReturn(pfnHandlerR3, VERR_INVALID_POINTER);
153 AssertPtrNullReturn(pszModR0, VERR_INVALID_POINTER);
154 AssertPtrNullReturn(pszHandlerR0, VERR_INVALID_POINTER);
155 AssertPtrNullReturn(pszPfHandlerR0, VERR_INVALID_POINTER);
156 AssertPtrNullReturn(pszModRC, VERR_INVALID_POINTER);
157 AssertPtrNullReturn(pszHandlerRC, VERR_INVALID_POINTER);
158 AssertPtrNullReturn(pszPfHandlerRC, VERR_INVALID_POINTER);
159
160 /*
161 * Resolve the R0 handlers.
162 */
163 R0PTRTYPE(PFNPGMPHYSHANDLER) pfnHandlerR0 = NIL_RTR0PTR;
164 int rc = PDMR3LdrGetSymbolR0Lazy(pVM, pszHandlerR0 ? pszModR0 : NULL, NULL /*pszSearchPath*/,
165 pszHandlerR0 ? pszHandlerR0 : "pgmPhysHandlerRedirectToHC", &pfnHandlerR0);
166 if (RT_SUCCESS(rc))
167 {
168 R0PTRTYPE(PFNPGMR0PHYSPFHANDLER) pfnPfHandlerR0 = NIL_RTR0PTR;
169 rc = PDMR3LdrGetSymbolR0Lazy(pVM, pszPfHandlerR0 ? pszModR0 : NULL, NULL /*pszSearchPath*/,
170 pszPfHandlerR0 ? pszPfHandlerR0 : "pgmPhysPfHandlerRedirectToHC", &pfnPfHandlerR0);
171 if (RT_SUCCESS(rc))
172 {
173 /*
174 * Resolve the GC handler.
175 */
176 RTRCPTR pfnHandlerRC = NIL_RTRCPTR;
177 RTRCPTR pfnPfHandlerRC = NIL_RTRCPTR;
178 if (VM_IS_RAW_MODE_ENABLED(pVM))
179 {
180 rc = PDMR3LdrGetSymbolRCLazy(pVM, pszHandlerRC ? pszModRC : NULL, NULL /*pszSearchPath*/,
181 pszHandlerRC ? pszHandlerRC : "pgmPhysHandlerRedirectToHC", &pfnHandlerRC);
182 if (RT_SUCCESS(rc))
183 {
184 rc = PDMR3LdrGetSymbolRCLazy(pVM, pszPfHandlerRC ? pszModRC : NULL, NULL /*pszSearchPath*/,
185 pszPfHandlerRC ? pszPfHandlerRC : "pgmPhysPfHandlerRedirectToHC", &pfnPfHandlerRC);
186 AssertMsgRC(rc, ("Failed to resolve %s.%s, rc=%Rrc.\n", pszPfHandlerRC ? pszModRC : VMMRC_MAIN_MODULE_NAME,
187 pszPfHandlerRC ? pszPfHandlerRC : "pgmPhysPfHandlerRedirectToHC", rc));
188 }
189 else
190 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszHandlerRC ? pszModRC : VMMRC_MAIN_MODULE_NAME,
191 pszHandlerRC ? pszHandlerRC : "pgmPhysHandlerRedirectToHC", rc));
192
193 }
194 if (RT_SUCCESS(rc))
195 return PGMR3HandlerPhysicalTypeRegisterEx(pVM, enmKind, pfnHandlerR3,
196 pfnHandlerR0, pfnPfHandlerR0, pszDesc, phType);
197 }
198 else
199 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszPfHandlerR0 ? pszModR0 : VMMR0_MAIN_MODULE_NAME,
200 pszPfHandlerR0 ? pszPfHandlerR0 : "pgmPhysHandlerRedirectToHC", rc));
201 }
202 else
203 AssertMsgFailed(("Failed to resolve %s.%s, rc=%Rrc.\n", pszHandlerR0 ? pszModR0 : VMMR0_MAIN_MODULE_NAME,
204 pszHandlerR0 ? pszHandlerR0 : "pgmPhysHandlerRedirectToHC", rc));
205
206 return rc;
207}
208
209
210/**
211 * Updates the physical page access handlers.
212 *
213 * @param pVM The cross context VM structure.
214 * @remark Only used when restoring a saved state.
215 */
216void pgmR3HandlerPhysicalUpdateAll(PVM pVM)
217{
218 LogFlow(("pgmHandlerPhysicalUpdateAll:\n"));
219
220 /*
221 * Clear and set.
222 * (the right -> left on the setting pass is just bird speculating on cache hits)
223 */
224 pgmLock(pVM);
225 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, true, pgmR3HandlerPhysicalOneClear, pVM);
226 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, false, pgmR3HandlerPhysicalOneSet, pVM);
227 pgmUnlock(pVM);
228}
229
230
231/**
232 * Clears all the page level flags for one physical handler range.
233 *
234 * @returns 0
235 * @param pNode Pointer to a PGMPHYSHANDLER.
236 * @param pvUser Pointer to the VM.
237 */
238static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PAVLROGCPHYSNODECORE pNode, void *pvUser)
239{
240 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
241 PPGMRAMRANGE pRamHint = NULL;
242 RTGCPHYS GCPhys = pCur->Core.Key;
243 RTUINT cPages = pCur->cPages;
244 PVM pVM = (PVM)pvUser;
245 for (;;)
246 {
247 PPGMPAGE pPage;
248 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
249 if (RT_SUCCESS(rc))
250 {
251 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE);
252
253 /* Tell NEM about the protection change. */
254 if (VM_IS_NEM_ENABLED(pVM))
255 {
256 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
257 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
258 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
259 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
260 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
261 }
262 }
263 else
264 AssertRC(rc);
265
266 if (--cPages == 0)
267 return 0;
268 GCPhys += PAGE_SIZE;
269 }
270}
271
272
273/**
274 * Sets all the page level flags for one physical handler range.
275 *
276 * @returns 0
277 * @param pNode Pointer to a PGMPHYSHANDLER.
278 * @param pvUser Pointer to the VM.
279 */
280static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser)
281{
282 PVM pVM = (PVM)pvUser;
283 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
284 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
285 unsigned uState = pCurType->uState;
286 PPGMRAMRANGE pRamHint = NULL;
287 RTGCPHYS GCPhys = pCur->Core.Key;
288 RTUINT cPages = pCur->cPages;
289 for (;;)
290 {
291 PPGMPAGE pPage;
292 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
293 if (RT_SUCCESS(rc))
294 {
295 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, uState);
296
297 /* Tell NEM about the protection change. */
298 if (VM_IS_NEM_ENABLED(pVM))
299 {
300 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
301 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
302 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
303 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
304 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
305 }
306 }
307 else
308 AssertRC(rc);
309
310 if (--cPages == 0)
311 return 0;
312 GCPhys += PAGE_SIZE;
313 }
314}
315
316
317/**
318 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
319 */
320typedef struct PGMHANDLERINFOARG
321{
322 /** The output helpers.*/
323 PCDBGFINFOHLP pHlp;
324 /** Pointer to the cross context VM handle. */
325 PVM pVM;
326 /** Set if statistics should be dumped. */
327 bool fStats;
328} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
329
330
331/**
332 * Info callback for 'pgmhandlers'.
333 *
334 * @param pVM The cross context VM structure.
335 * @param pHlp The output helpers.
336 * @param pszArgs The arguments. phys or virt.
337 */
338DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
339{
340 /*
341 * Parse options.
342 */
343 PGMHANDLERINFOARG Args = { pHlp, pVM, /* .fStats = */ true };
344 if (pszArgs)
345 Args.fStats = strstr(pszArgs, "nost") == NULL;
346
347 /*
348 * Dump the handlers.
349 */
350 pHlp->pfnPrintf(pHlp,
351 "Physical handlers: (PhysHandlers=%d (%#x))\n"
352 "%*s %*s %*s %*s HandlerGC UserGC Type Description\n",
353 pVM->pgm.s.pTreesR3->PhysHandlers, pVM->pgm.s.pTreesR3->PhysHandlers,
354 - (int)sizeof(RTGCPHYS) * 2, "From",
355 - (int)sizeof(RTGCPHYS) * 2 - 3, "- To (incl)",
356 - (int)sizeof(RTHCPTR) * 2 - 1, "HandlerHC",
357 - (int)sizeof(RTHCPTR) * 2 - 1, "UserHC");
358 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesR3->PhysHandlers, true, pgmR3InfoHandlersPhysicalOne, &Args);
359}
360
361
362/**
363 * Displays one physical handler range.
364 *
365 * @returns 0
366 * @param pNode Pointer to a PGMPHYSHANDLER.
367 * @param pvUser Pointer to command helper functions.
368 */
369static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
370{
371 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
372 PPGMHANDLERINFOARG pArgs = (PPGMHANDLERINFOARG)pvUser;
373 PCDBGFINFOHLP pHlp = pArgs->pHlp;
374 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pArgs->pVM, pCur);
375 const char *pszType;
376 switch (pCurType->enmKind)
377 {
378 case PGMPHYSHANDLERKIND_MMIO: pszType = "MMIO "; break;
379 case PGMPHYSHANDLERKIND_WRITE: pszType = "Write "; break;
380 case PGMPHYSHANDLERKIND_ALL: pszType = "All "; break;
381 default: pszType = "????"; break;
382 }
383 pHlp->pfnPrintf(pHlp,
384 "%RGp - %RGp %RHv %RHv %RHv %RHv %s %s\n",
385 pCur->Core.Key, pCur->Core.KeyLast, pCurType->pfnHandlerR3, pCur->pvUserR3,
386 pCurType->pfnPfHandlerR0, pCur->pvUserR0, pszType, pCur->pszDesc);
387#ifdef VBOX_WITH_STATISTICS
388 if (pArgs->fStats)
389 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
390 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
391 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
392#endif
393 return 0;
394}
395
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