VirtualBox

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

Last change on this file since 93666 was 93650, checked in by vboxsync, 3 years ago

VMM/PGM,*: Split the physical access handler type registration into separate ring-0 and ring-3 steps, expanding the type to 64-bit. bugref:10094

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.8 KB
Line 
1/* $Id: PGMHandler.cpp 93650 2022-02-08 10:43:53Z 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 * @callback_method_impl{FNPGMPHYSHANDLER,
62 * Invalid callback entry triggering guru mediation}
63 */
64DECLCALLBACK(VBOXSTRICTRC) pgmR3HandlerPhysicalHandlerInvalid(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, void *pvPhys,
65 void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType,
66 PGMACCESSORIGIN enmOrigin, uint64_t uUser)
67{
68 RT_NOREF(pVM, pVCpu, GCPhys, pvPhys, pvBuf, cbBuf, enmAccessType, enmOrigin, uUser);
69 LogRel(("GCPhys=%RGp cbBuf=%#zx enmAccessType=%d uUser=%#RX64\n", GCPhys, cbBuf, enmAccessType, uUser));
70 return VERR_PGM_HANDLER_IPE_1;
71}
72
73
74/**
75 * Register a physical page access handler type.
76 *
77 * @returns VBox status code.
78 * @param pVM The cross context VM structure.
79 * @param enmKind The kind of access handler.
80 * @param fFlags PGMPHYSHANDLER_F_XXX
81 * @param pfnHandler Pointer to the ring-3 handler callback.
82 * @param pszDesc The type description.
83 * @param phType Where to return the type handle (cross context safe).
84 */
85VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind, uint32_t fFlags,
86 PFNPGMPHYSHANDLER pfnHandler, const char *pszDesc,
87 PPGMPHYSHANDLERTYPE phType)
88{
89 /*
90 * Validate input.
91 */
92 AssertPtrReturn(phType, VERR_INVALID_POINTER);
93 *phType = NIL_PGMPHYSHANDLERTYPE;
94
95 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
96 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
97 AssertReturn( enmKind == PGMPHYSHANDLERKIND_WRITE
98 || enmKind == PGMPHYSHANDLERKIND_ALL
99 || enmKind == PGMPHYSHANDLERKIND_MMIO,
100 VERR_INVALID_PARAMETER);
101 AssertMsgReturn(!(fFlags & ~PGMPHYSHANDLER_F_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_FLAGS);
102
103 VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
104 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
105
106 /*
107 * Do the allocating.
108 */
109 PGMPHYSHANDLERTYPE hType = pVM->pgm.s.cPhysHandlerTypes;
110 AssertLogRelReturn(hType < RT_ELEMENTS(pVM->pgm.s.aPhysHandlerTypes), VERR_OUT_OF_RESOURCES);
111 PPGMPHYSHANDLERTYPEINTR3 const pType = &pVM->pgm.s.aPhysHandlerTypes[hType];
112 AssertReturn(pType->enmKind == PGMPHYSHANDLERKIND_INVALID, VERR_PGM_HANDLER_IPE_1);
113 pVM->pgm.s.cPhysHandlerTypes++;
114
115 pType->enmKind = enmKind;
116 pType->uState = enmKind == PGMPHYSHANDLERKIND_WRITE
117 ? PGM_PAGE_HNDL_PHYS_STATE_WRITE : PGM_PAGE_HNDL_PHYS_STATE_ALL;
118 pType->fKeepPgmLock = RT_BOOL(fFlags & PGMPHYSHANDLER_F_KEEP_PGM_LOCK);
119 pType->fRing0DevInsIdx = RT_BOOL(fFlags & PGMPHYSHANDLER_F_R0_DEVINS_IDX);
120 pType->pfnHandler = pfnHandler;
121 pType->pszDesc = pszDesc;
122
123 *phType = pType->hType;
124 LogFlow(("PGMR3HandlerPhysicalTypeRegisterEx: hType=%#x: enmKind=%d fFlags=%#x pfnHandler=%p pszDesc=%s\n",
125 hType, enmKind, fFlags, pfnHandler, pszDesc));
126 return VINF_SUCCESS;
127}
128
129
130/**
131 * Updates the physical page access handlers.
132 *
133 * @param pVM The cross context VM structure.
134 * @remark Only used when restoring a saved state.
135 */
136void pgmR3HandlerPhysicalUpdateAll(PVM pVM)
137{
138 LogFlow(("pgmHandlerPhysicalUpdateAll:\n"));
139
140 /*
141 * Clear and set.
142 * (the right -> left on the setting pass is just bird speculating on cache hits)
143 */
144 PGM_LOCK_VOID(pVM);
145 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, true, pgmR3HandlerPhysicalOneClear, pVM);
146 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, false, pgmR3HandlerPhysicalOneSet, pVM);
147 PGM_UNLOCK(pVM);
148}
149
150
151/**
152 * Clears all the page level flags for one physical handler range.
153 *
154 * @returns 0
155 * @param pNode Pointer to a PGMPHYSHANDLER.
156 * @param pvUser Pointer to the VM.
157 */
158static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PAVLROGCPHYSNODECORE pNode, void *pvUser)
159{
160 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
161 PPGMRAMRANGE pRamHint = NULL;
162 RTGCPHYS GCPhys = pCur->Core.Key;
163 RTUINT cPages = pCur->cPages;
164 PVM pVM = (PVM)pvUser;
165 for (;;)
166 {
167 PPGMPAGE pPage;
168 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
169 if (RT_SUCCESS(rc))
170 {
171 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE);
172
173#ifdef VBOX_WITH_NATIVE_NEM
174 /* Tell NEM about the protection change. */
175 if (VM_IS_NEM_ENABLED(pVM))
176 {
177 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
178 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
179 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
180 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRamHint, GCPhys),
181 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
182 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
183 }
184#endif
185 }
186 else
187 AssertRC(rc);
188
189 if (--cPages == 0)
190 return 0;
191 GCPhys += GUEST_PAGE_SIZE;
192 }
193}
194
195
196/**
197 * Sets all the page level flags for one physical handler range.
198 *
199 * @returns 0
200 * @param pNode Pointer to a PGMPHYSHANDLER.
201 * @param pvUser Pointer to the VM.
202 */
203static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PAVLROGCPHYSNODECORE pNode, void *pvUser)
204{
205 PVM pVM = (PVM)pvUser;
206 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
207 PCPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
208 unsigned uState = pCurType->uState;
209 PPGMRAMRANGE pRamHint = NULL;
210 RTGCPHYS GCPhys = pCur->Core.Key;
211 RTUINT cPages = pCur->cPages;
212 for (;;)
213 {
214 PPGMPAGE pPage;
215 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
216 if (RT_SUCCESS(rc))
217 {
218 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, uState);
219
220#ifdef VBOX_WITH_NATIVE_NEM
221 /* Tell NEM about the protection change. */
222 if (VM_IS_NEM_ENABLED(pVM))
223 {
224 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
225 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
226 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
227 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRamHint, GCPhys),
228 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
229 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
230 }
231#endif
232 }
233 else
234 AssertRC(rc);
235
236 if (--cPages == 0)
237 return 0;
238 GCPhys += GUEST_PAGE_SIZE;
239 }
240}
241
242
243/**
244 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
245 */
246typedef struct PGMHANDLERINFOARG
247{
248 /** The output helpers.*/
249 PCDBGFINFOHLP pHlp;
250 /** Pointer to the cross context VM handle. */
251 PVM pVM;
252 /** Set if statistics should be dumped. */
253 bool fStats;
254} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
255
256
257/**
258 * Info callback for 'pgmhandlers'.
259 *
260 * @param pVM The cross context VM structure.
261 * @param pHlp The output helpers.
262 * @param pszArgs The arguments. phys or virt.
263 */
264DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
265{
266 /*
267 * Parse options.
268 */
269 PGMHANDLERINFOARG Args = { pHlp, pVM, /* .fStats = */ true };
270 if (pszArgs)
271 Args.fStats = strstr(pszArgs, "nost") == NULL;
272
273 /*
274 * Dump the handlers.
275 */
276 pHlp->pfnPrintf(pHlp,
277 "Physical handlers: (PhysHandlers=%d (%#x))\n"
278 "%*s %*s %*s uUser Type Description\n",
279 pVM->pgm.s.pTreesR3->PhysHandlers, pVM->pgm.s.pTreesR3->PhysHandlers,
280 - (int)sizeof(RTGCPHYS) * 2, "From",
281 - (int)sizeof(RTGCPHYS) * 2 - 3, "- To (incl)",
282 - (int)sizeof(RTHCPTR) * 2 - 1, "Handler (R3)");
283 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.pTreesR3->PhysHandlers, true, pgmR3InfoHandlersPhysicalOne, &Args);
284}
285
286
287/**
288 * Displays one physical handler range.
289 *
290 * @returns 0
291 * @param pNode Pointer to a PGMPHYSHANDLER.
292 * @param pvUser Pointer to command helper functions.
293 */
294static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PAVLROGCPHYSNODECORE pNode, void *pvUser)
295{
296 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)pNode;
297 PPGMHANDLERINFOARG pArgs = (PPGMHANDLERINFOARG)pvUser;
298 PCDBGFINFOHLP pHlp = pArgs->pHlp;
299 PCPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pArgs->pVM, pCur);
300 const char *pszType;
301 switch (pCurType->enmKind)
302 {
303 case PGMPHYSHANDLERKIND_MMIO: pszType = "MMIO "; break;
304 case PGMPHYSHANDLERKIND_WRITE: pszType = "Write "; break;
305 case PGMPHYSHANDLERKIND_ALL: pszType = "All "; break;
306 default: pszType = "???????"; break;
307 }
308
309 char szFlags[80];
310 size_t cchFlags = 0;
311 if (pCurType->fKeepPgmLock)
312 cchFlags = RTStrPrintf(szFlags, sizeof(szFlags), "(keep-pgm-lock");
313 if (pCurType->fRing0DevInsIdx)
314 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", keep-pgm-lock" : "(keep-pgm-lock");
315 if (pCurType->fRing0Enabled)
316 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", r0-enabled)" : "(r0-enabled)");
317 else
318 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", r3-only)" : "(r3-only)");
319
320 pHlp->pfnPrintf(pHlp,
321 "%RGp - %RGp %p %016RX64 %s %s %s\n",
322 pCur->Core.Key, pCur->Core.KeyLast, pCurType->pfnHandler, pCur->uUser, pszType, pCur->pszDesc, szFlags);
323#ifdef VBOX_WITH_STATISTICS
324 if (pArgs->fStats)
325 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
326 pCur->Stat.cPeriods, pCur->Stat.cTicks, pCur->Stat.cTicksMin,
327 pCur->Stat.cPeriods ? pCur->Stat.cTicks / pCur->Stat.cPeriods : 0, pCur->Stat.cTicksMax);
328#endif
329 return 0;
330}
331
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette