VirtualBox

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

Last change on this file since 95259 was 93716, checked in by vboxsync, 3 years ago

VMM/PGM: Moved the physical handler allocation off the hyper heap and into its own slab, changing the it to the 'hardened' avl tree code. bugref:10093

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.0 KB
Line 
1/* $Id: PGMHandler.cpp 93716 2022-02-14 10:36:21Z 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/vmcc.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(PPGMPHYSHANDLER pHandler, void *pvUser);
55static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PPGMPHYSHANDLER pHandler, void *pvUser);
56static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PPGMPHYSHANDLER pHandler, 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 uint32_t const idxType = pVM->pgm.s.cPhysHandlerTypes;
110 AssertLogRelReturn(idxType < RT_ELEMENTS(pVM->pgm.s.aPhysHandlerTypes), VERR_OUT_OF_RESOURCES);
111 PPGMPHYSHANDLERTYPEINTR3 const pType = &pVM->pgm.s.aPhysHandlerTypes[idxType];
112 AssertReturn(pType->enmKind == PGMPHYSHANDLERKIND_INVALID, VERR_PGM_HANDLER_IPE_1);
113 pVM->pgm.s.cPhysHandlerTypes = idxType + 1;
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=%#RX64/%#x: enmKind=%d fFlags=%#x pfnHandler=%p pszDesc=%s\n",
125 pType->hType, idxType, 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
146 int rc = pVM->pgm.s.pPhysHandlerTree->doWithAllFromLeft(&pVM->pgm.s.PhysHandlerAllocator, pgmR3HandlerPhysicalOneClear, pVM);
147 AssertRC(rc);
148 rc = pVM->pgm.s.pPhysHandlerTree->doWithAllFromRight(&pVM->pgm.s.PhysHandlerAllocator, pgmR3HandlerPhysicalOneSet, pVM);
149 AssertRC(rc);
150
151 PGM_UNLOCK(pVM);
152}
153
154
155/**
156 * Clears all the page level flags for one physical handler range.
157 *
158 * @returns 0
159 * @param pHandler The physical access handler entry.
160 * @param pvUser Pointer to the VM.
161 */
162static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PPGMPHYSHANDLER pHandler, void *pvUser)
163{
164 PPGMRAMRANGE pRamHint = NULL;
165 RTGCPHYS GCPhys = pHandler->Key;
166 RTUINT cPages = pHandler->cPages;
167 PVM pVM = (PVM)pvUser;
168 for (;;)
169 {
170 PPGMPAGE pPage;
171 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
172 if (RT_SUCCESS(rc))
173 {
174 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE);
175
176#ifdef VBOX_WITH_NATIVE_NEM
177 /* Tell NEM about the protection change. */
178 if (VM_IS_NEM_ENABLED(pVM))
179 {
180 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
181 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
182 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
183 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRamHint, GCPhys),
184 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
185 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
186 }
187#endif
188 }
189 else
190 AssertRC(rc);
191
192 if (--cPages == 0)
193 return 0;
194 GCPhys += GUEST_PAGE_SIZE;
195 }
196}
197
198
199/**
200 * Sets all the page level flags for one physical handler range.
201 *
202 * @returns 0
203 * @param pHandler The physical access handler entry.
204 * @param pvUser Pointer to the VM.
205 */
206static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PPGMPHYSHANDLER pHandler, void *pvUser)
207{
208 PVM pVM = (PVM)pvUser;
209 PCPGMPHYSHANDLERTYPEINT pType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pHandler);
210 unsigned uState = pType->uState;
211 PPGMRAMRANGE pRamHint = NULL;
212 RTGCPHYS GCPhys = pHandler->Key;
213 RTUINT cPages = pHandler->cPages;
214 for (;;)
215 {
216 PPGMPAGE pPage;
217 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
218 if (RT_SUCCESS(rc))
219 {
220 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, uState);
221
222#ifdef VBOX_WITH_NATIVE_NEM
223 /* Tell NEM about the protection change. */
224 if (VM_IS_NEM_ENABLED(pVM))
225 {
226 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
227 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
228 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
229 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRamHint, GCPhys),
230 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
231 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
232 }
233#endif
234 }
235 else
236 AssertRC(rc);
237
238 if (--cPages == 0)
239 return 0;
240 GCPhys += GUEST_PAGE_SIZE;
241 }
242}
243
244
245/**
246 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
247 */
248typedef struct PGMHANDLERINFOARG
249{
250 /** The output helpers.*/
251 PCDBGFINFOHLP pHlp;
252 /** Pointer to the cross context VM handle. */
253 PVM pVM;
254 /** Set if statistics should be dumped. */
255 bool fStats;
256} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
257
258
259/**
260 * Info callback for 'pgmhandlers'.
261 *
262 * @param pVM The cross context VM structure.
263 * @param pHlp The output helpers.
264 * @param pszArgs The arguments. phys or virt.
265 */
266DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
267{
268 /*
269 * Parse options.
270 */
271 PGMHANDLERINFOARG Args = { pHlp, pVM, /* .fStats = */ true };
272 if (pszArgs)
273 Args.fStats = strstr(pszArgs, "nost") == NULL;
274
275 /*
276 * Dump the handlers.
277 */
278 pHlp->pfnPrintf(pHlp,
279 "Physical handlers: max %#x, %u allocator error%s, %u tree error%s\n"
280 "%*s %*s %*s uUser Type Description\n",
281 pVM->pgm.s.PhysHandlerAllocator.m_cNodes,
282 pVM->pgm.s.PhysHandlerAllocator.m_cErrors, pVM->pgm.s.PhysHandlerAllocator.m_cErrors != 0 ? "s" : "",
283 pVM->pgm.s.pPhysHandlerTree->m_cErrors, pVM->pgm.s.pPhysHandlerTree->m_cErrors != 0 ? "s" : "",
284 - (int)sizeof(RTGCPHYS) * 2, "From",
285 - (int)sizeof(RTGCPHYS) * 2 - 3, "- To (incl)",
286 - (int)sizeof(RTHCPTR) * 2 - 1, "Handler (R3)");
287 pVM->pgm.s.pPhysHandlerTree->doWithAllFromLeft(&pVM->pgm.s.PhysHandlerAllocator, pgmR3InfoHandlersPhysicalOne, &Args);
288}
289
290
291/**
292 * Displays one physical handler range.
293 *
294 * @returns 0
295 * @param pHandler The physical access handler entry.
296 * @param pvUser Pointer to command helper functions.
297 */
298static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PPGMPHYSHANDLER pHandler, void *pvUser)
299{
300 PPGMHANDLERINFOARG pArgs = (PPGMHANDLERINFOARG)pvUser;
301 PCDBGFINFOHLP pHlp = pArgs->pHlp;
302 PCPGMPHYSHANDLERTYPEINT pType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pArgs->pVM, pHandler);
303 const char *pszType;
304 switch (pType->enmKind)
305 {
306 case PGMPHYSHANDLERKIND_MMIO: pszType = "MMIO "; break;
307 case PGMPHYSHANDLERKIND_WRITE: pszType = "Write "; break;
308 case PGMPHYSHANDLERKIND_ALL: pszType = "All "; break;
309 default: pszType = "???????"; break;
310 }
311
312 char szFlags[80];
313 size_t cchFlags = 0;
314 if (pType->fKeepPgmLock)
315 cchFlags = RTStrPrintf(szFlags, sizeof(szFlags), "(keep-pgm-lock");
316 if (pType->fRing0DevInsIdx)
317 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", keep-pgm-lock" : "(keep-pgm-lock");
318 if (pType->fRing0Enabled)
319 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", r0-enabled)" : "(r0-enabled)");
320 else
321 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", r3-only)" : "(r3-only)");
322
323 pHlp->pfnPrintf(pHlp,
324 "%RGp - %RGp %p %016RX64 %s %s %s\n",
325 pHandler->Key, pHandler->KeyLast, pType->pfnHandler, pHandler->uUser, pszType, pHandler->pszDesc, szFlags);
326#ifdef VBOX_WITH_STATISTICS
327 if (pArgs->fStats)
328 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
329 pHandler->Stat.cPeriods, pHandler->Stat.cTicks, pHandler->Stat.cTicksMin,
330 pHandler->Stat.cPeriods ? pHandler->Stat.cTicks / pHandler->Stat.cPeriods : 0, pHandler->Stat.cTicksMax);
331#endif
332 return 0;
333}
334
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