VirtualBox

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

Last change on this file since 93444 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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