VirtualBox

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

Last change on this file since 97178 was 96979, checked in by vboxsync, 2 years ago

VMM/PGM,IEM,HM: Added a PGMPHYSHANDLER_F_NOT_IN_HM flag to better deal with a nested APIC access page. bugref:10092

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.3 KB
Line 
1/* $Id: PGMHandler.cpp 96979 2022-10-04 12:46:05Z vboxsync $ */
2/** @file
3 * PGM - Page Manager / Monitor, Access Handlers.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_PGM
33#define VBOX_WITHOUT_PAGING_BIT_FIELDS /* 64-bit bitfields are just asking for trouble. See @bugref{9841} and others. */
34#include <VBox/vmm/dbgf.h>
35#include <VBox/vmm/pgm.h>
36#include <VBox/vmm/cpum.h>
37#include <VBox/vmm/iom.h>
38#include <VBox/sup.h>
39#include <VBox/vmm/mm.h>
40#include <VBox/vmm/em.h>
41#include <VBox/vmm/stam.h>
42#include <VBox/vmm/dbgf.h>
43#include <VBox/vmm/selm.h>
44#include <VBox/vmm/ssm.h>
45#include "PGMInternal.h"
46#include <VBox/vmm/vmcc.h>
47#include "PGMInline.h"
48#include <VBox/dbg.h>
49
50#include <VBox/log.h>
51#include <iprt/assert.h>
52#include <iprt/alloc.h>
53#include <iprt/asm.h>
54#include <iprt/errcore.h>
55#include <iprt/thread.h>
56#include <iprt/string.h>
57#include <VBox/param.h>
58#include <VBox/vmm/hm.h>
59
60
61/*********************************************************************************************************************************
62* Internal Functions *
63*********************************************************************************************************************************/
64static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PPGMPHYSHANDLER pHandler, void *pvUser);
65static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PPGMPHYSHANDLER pHandler, void *pvUser);
66static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PPGMPHYSHANDLER pHandler, void *pvUser);
67
68
69
70/**
71 * @callback_method_impl{FNPGMPHYSHANDLER,
72 * Invalid callback entry triggering guru mediation}
73 */
74DECLCALLBACK(VBOXSTRICTRC) pgmR3HandlerPhysicalHandlerInvalid(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, void *pvPhys,
75 void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType,
76 PGMACCESSORIGIN enmOrigin, uint64_t uUser)
77{
78 RT_NOREF(pVM, pVCpu, GCPhys, pvPhys, pvBuf, cbBuf, enmAccessType, enmOrigin, uUser);
79 LogRel(("GCPhys=%RGp cbBuf=%#zx enmAccessType=%d uUser=%#RX64\n", GCPhys, cbBuf, enmAccessType, uUser));
80 return VERR_PGM_HANDLER_IPE_1;
81}
82
83
84/**
85 * Register a physical page access handler type.
86 *
87 * @returns VBox status code.
88 * @param pVM The cross context VM structure.
89 * @param enmKind The kind of access handler.
90 * @param fFlags PGMPHYSHANDLER_F_XXX
91 * @param pfnHandler Pointer to the ring-3 handler callback.
92 * @param pszDesc The type description.
93 * @param phType Where to return the type handle (cross context safe).
94 */
95VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind, uint32_t fFlags,
96 PFNPGMPHYSHANDLER pfnHandler, const char *pszDesc,
97 PPGMPHYSHANDLERTYPE phType)
98{
99 /*
100 * Validate input.
101 */
102 AssertPtrReturn(phType, VERR_INVALID_POINTER);
103 *phType = NIL_PGMPHYSHANDLERTYPE;
104
105 AssertPtrReturn(pfnHandler, VERR_INVALID_POINTER);
106 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
107 AssertReturn( enmKind == PGMPHYSHANDLERKIND_WRITE
108 || enmKind == PGMPHYSHANDLERKIND_ALL
109 || enmKind == PGMPHYSHANDLERKIND_MMIO,
110 VERR_INVALID_PARAMETER);
111 AssertMsgReturn(!(fFlags & ~PGMPHYSHANDLER_F_VALID_MASK), ("%#x\n", fFlags), VERR_INVALID_FLAGS);
112
113 VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
114 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
115
116 /*
117 * Do the allocating.
118 */
119 uint32_t const idxType = pVM->pgm.s.cPhysHandlerTypes;
120 AssertLogRelReturn(idxType < RT_ELEMENTS(pVM->pgm.s.aPhysHandlerTypes), VERR_OUT_OF_RESOURCES);
121 PPGMPHYSHANDLERTYPEINTR3 const pType = &pVM->pgm.s.aPhysHandlerTypes[idxType];
122 AssertReturn(pType->enmKind == PGMPHYSHANDLERKIND_INVALID, VERR_PGM_HANDLER_IPE_1);
123 pVM->pgm.s.cPhysHandlerTypes = idxType + 1;
124
125 pType->enmKind = enmKind;
126 pType->uState = enmKind == PGMPHYSHANDLERKIND_WRITE
127 ? PGM_PAGE_HNDL_PHYS_STATE_WRITE : PGM_PAGE_HNDL_PHYS_STATE_ALL;
128 pType->fKeepPgmLock = RT_BOOL(fFlags & PGMPHYSHANDLER_F_KEEP_PGM_LOCK);
129 pType->fRing0DevInsIdx = RT_BOOL(fFlags & PGMPHYSHANDLER_F_R0_DEVINS_IDX);
130 pType->fNotInHm = RT_BOOL(fFlags & PGMPHYSHANDLER_F_NOT_IN_HM);
131 pType->pfnHandler = pfnHandler;
132 pType->pszDesc = pszDesc;
133
134 *phType = pType->hType;
135 LogFlow(("PGMR3HandlerPhysicalTypeRegisterEx: hType=%#RX64/%#x: enmKind=%d fFlags=%#x pfnHandler=%p pszDesc=%s\n",
136 pType->hType, idxType, enmKind, fFlags, pfnHandler, pszDesc));
137 return VINF_SUCCESS;
138}
139
140
141/**
142 * Updates the physical page access handlers.
143 *
144 * @param pVM The cross context VM structure.
145 * @remark Only used when restoring a saved state.
146 */
147void pgmR3HandlerPhysicalUpdateAll(PVM pVM)
148{
149 LogFlow(("pgmHandlerPhysicalUpdateAll:\n"));
150
151 /*
152 * Clear and set.
153 * (the right -> left on the setting pass is just bird speculating on cache hits)
154 */
155 PGM_LOCK_VOID(pVM);
156
157 int rc = pVM->pgm.s.pPhysHandlerTree->doWithAllFromLeft(&pVM->pgm.s.PhysHandlerAllocator, pgmR3HandlerPhysicalOneClear, pVM);
158 AssertRC(rc);
159 rc = pVM->pgm.s.pPhysHandlerTree->doWithAllFromRight(&pVM->pgm.s.PhysHandlerAllocator, pgmR3HandlerPhysicalOneSet, pVM);
160 AssertRC(rc);
161
162 PGM_UNLOCK(pVM);
163}
164
165
166/**
167 * Clears all the page level flags for one physical handler range.
168 *
169 * @returns 0
170 * @param pHandler The physical access handler entry.
171 * @param pvUser Pointer to the VM.
172 */
173static DECLCALLBACK(int) pgmR3HandlerPhysicalOneClear(PPGMPHYSHANDLER pHandler, void *pvUser)
174{
175 PPGMRAMRANGE pRamHint = NULL;
176 RTGCPHYS GCPhys = pHandler->Key;
177 RTUINT cPages = pHandler->cPages;
178 PVM pVM = (PVM)pvUser;
179 for (;;)
180 {
181 PPGMPAGE pPage;
182 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
183 if (RT_SUCCESS(rc))
184 {
185 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE, false);
186
187#ifdef VBOX_WITH_NATIVE_NEM
188 /* Tell NEM about the protection change. */
189 if (VM_IS_NEM_ENABLED(pVM))
190 {
191 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
192 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
193 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
194 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRamHint, GCPhys),
195 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
196 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
197 }
198#endif
199 }
200 else
201 AssertRC(rc);
202
203 if (--cPages == 0)
204 return 0;
205 GCPhys += GUEST_PAGE_SIZE;
206 }
207}
208
209
210/**
211 * Sets all the page level flags for one physical handler range.
212 *
213 * @returns 0
214 * @param pHandler The physical access handler entry.
215 * @param pvUser Pointer to the VM.
216 */
217static DECLCALLBACK(int) pgmR3HandlerPhysicalOneSet(PPGMPHYSHANDLER pHandler, void *pvUser)
218{
219 PVM pVM = (PVM)pvUser;
220 PCPGMPHYSHANDLERTYPEINT pType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pHandler);
221 unsigned uState = pType->uState;
222 PPGMRAMRANGE pRamHint = NULL;
223 RTGCPHYS GCPhys = pHandler->Key;
224 RTUINT cPages = pHandler->cPages;
225 for (;;)
226 {
227 PPGMPAGE pPage;
228 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
229 if (RT_SUCCESS(rc))
230 {
231 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, uState, pType->fNotInHm);
232
233#ifdef VBOX_WITH_NATIVE_NEM
234 /* Tell NEM about the protection change. */
235 if (VM_IS_NEM_ENABLED(pVM))
236 {
237 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
238 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
239 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
240 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRamHint, GCPhys),
241 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
242 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
243 }
244#endif
245 }
246 else
247 AssertRC(rc);
248
249 if (--cPages == 0)
250 return 0;
251 GCPhys += GUEST_PAGE_SIZE;
252 }
253}
254
255
256/**
257 * Arguments for pgmR3InfoHandlersPhysicalOne and pgmR3InfoHandlersVirtualOne.
258 */
259typedef struct PGMHANDLERINFOARG
260{
261 /** The output helpers.*/
262 PCDBGFINFOHLP pHlp;
263 /** Pointer to the cross context VM handle. */
264 PVM pVM;
265 /** Set if statistics should be dumped. */
266 bool fStats;
267} PGMHANDLERINFOARG, *PPGMHANDLERINFOARG;
268
269
270/**
271 * Info callback for 'pgmhandlers'.
272 *
273 * @param pVM The cross context VM structure.
274 * @param pHlp The output helpers.
275 * @param pszArgs The arguments. phys or virt.
276 */
277DECLCALLBACK(void) pgmR3InfoHandlers(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
278{
279 /*
280 * Parse options.
281 */
282 PGMHANDLERINFOARG Args = { pHlp, pVM, /* .fStats = */ true };
283 if (pszArgs)
284 Args.fStats = strstr(pszArgs, "nost") == NULL;
285
286 /*
287 * Dump the handlers.
288 */
289 pHlp->pfnPrintf(pHlp,
290 "Physical handlers: max %#x, %u allocator error%s, %u tree error%s\n"
291 "%*s %*s %*s uUser Type Description\n",
292 pVM->pgm.s.PhysHandlerAllocator.m_cNodes,
293 pVM->pgm.s.PhysHandlerAllocator.m_cErrors, pVM->pgm.s.PhysHandlerAllocator.m_cErrors != 0 ? "s" : "",
294 pVM->pgm.s.pPhysHandlerTree->m_cErrors, pVM->pgm.s.pPhysHandlerTree->m_cErrors != 0 ? "s" : "",
295 - (int)sizeof(RTGCPHYS) * 2, "From",
296 - (int)sizeof(RTGCPHYS) * 2 - 3, "- To (incl)",
297 - (int)sizeof(RTHCPTR) * 2 - 1, "Handler (R3)");
298 pVM->pgm.s.pPhysHandlerTree->doWithAllFromLeft(&pVM->pgm.s.PhysHandlerAllocator, pgmR3InfoHandlersPhysicalOne, &Args);
299}
300
301
302/**
303 * Displays one physical handler range.
304 *
305 * @returns 0
306 * @param pHandler The physical access handler entry.
307 * @param pvUser Pointer to command helper functions.
308 */
309static DECLCALLBACK(int) pgmR3InfoHandlersPhysicalOne(PPGMPHYSHANDLER pHandler, void *pvUser)
310{
311 PPGMHANDLERINFOARG pArgs = (PPGMHANDLERINFOARG)pvUser;
312 PCDBGFINFOHLP pHlp = pArgs->pHlp;
313 PCPGMPHYSHANDLERTYPEINT pType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pArgs->pVM, pHandler);
314 const char *pszType;
315 switch (pType->enmKind)
316 {
317 case PGMPHYSHANDLERKIND_MMIO: pszType = "MMIO "; break;
318 case PGMPHYSHANDLERKIND_WRITE: pszType = "Write "; break;
319 case PGMPHYSHANDLERKIND_ALL: pszType = "All "; break;
320 default: pszType = "???????"; break;
321 }
322
323 char szFlags[80];
324 size_t cchFlags = 0;
325 if (pType->fKeepPgmLock)
326 cchFlags = RTStrPrintf(szFlags, sizeof(szFlags), "(keep-pgm-lock");
327 if (pType->fRing0DevInsIdx)
328 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", keep-pgm-lock" : "(keep-pgm-lock");
329 if (pType->fRing0Enabled)
330 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", r0-enabled)" : "(r0-enabled)");
331 else
332 cchFlags += RTStrPrintf(&szFlags[cchFlags], sizeof(szFlags) - cchFlags, cchFlags ? ", r3-only)" : "(r3-only)");
333
334 pHlp->pfnPrintf(pHlp,
335 "%RGp - %RGp %p %016RX64 %s %s %s\n",
336 pHandler->Key, pHandler->KeyLast, pType->pfnHandler, pHandler->uUser, pszType, pHandler->pszDesc, szFlags);
337#ifdef VBOX_WITH_STATISTICS
338 if (pArgs->fStats)
339 pHlp->pfnPrintf(pHlp, " cPeriods: %9RU64 cTicks: %11RU64 Min: %11RU64 Avg: %11RU64 Max: %11RU64\n",
340 pHandler->Stat.cPeriods, pHandler->Stat.cTicks, pHandler->Stat.cTicksMin,
341 pHandler->Stat.cPeriods ? pHandler->Stat.cTicks / pHandler->Stat.cPeriods : 0, pHandler->Stat.cTicksMax);
342#endif
343 return 0;
344}
345
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