VirtualBox

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

Last change on this file since 80239 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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