VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp@ 97694

Last change on this file since 97694 was 97198, checked in by vboxsync, 2 years ago

VMM/PGM,IEM,EM: Changed FNPGMRZPHYSPFHANDLER, PGMTrap0eHandler and PGMR0Trap0eHandlerNPMisconfig to take PCPUMCTX instead of PCPUMCTXCORE parameters; dropped PCPUMCTXCORE parameters from IEMExecOneBypassEx, PGMInterpretInstruction and EMInterpretInstruction together with some associated cleanups. [fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 75.9 KB
Line 
1/* $Id: PGMAllHandler.cpp 97198 2022-10-18 11:31:32Z 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/iom.h>
37#include <VBox/vmm/mm.h>
38#include <VBox/vmm/em.h>
39#include <VBox/vmm/nem.h>
40#include <VBox/vmm/stam.h>
41#include <VBox/vmm/dbgf.h>
42#ifdef IN_RING0
43# include <VBox/vmm/pdmdev.h>
44#endif
45#include "PGMInternal.h"
46#include <VBox/vmm/vmcc.h>
47#include "PGMInline.h"
48
49#include <VBox/log.h>
50#include <iprt/assert.h>
51#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
52# include <iprt/asm-amd64-x86.h>
53#endif
54#include <iprt/string.h>
55#include <VBox/param.h>
56#include <VBox/err.h>
57#include <VBox/vmm/selm.h>
58
59
60/*********************************************************************************************************************************
61* Global Variables *
62*********************************************************************************************************************************/
63/** Dummy physical access handler type record. */
64CTX_SUFF(PGMPHYSHANDLERTYPEINT) const g_pgmHandlerPhysicalDummyType =
65{
66 /* .hType = */ UINT64_C(0x93b7557e1937aaff),
67 /* .enmKind = */ PGMPHYSHANDLERKIND_INVALID,
68 /* .uState = */ PGM_PAGE_HNDL_PHYS_STATE_ALL,
69 /* .fKeepPgmLock = */ true,
70 /* .fRing0DevInsIdx = */ false,
71#ifdef IN_RING0
72 /* .fNotInHm = */ false,
73 /* .pfnHandler = */ pgmR0HandlerPhysicalHandlerToRing3,
74 /* .pfnPfHandler = */ pgmR0HandlerPhysicalPfHandlerToRing3,
75#elif defined(IN_RING3)
76 /* .fRing0Enabled = */ false,
77 /* .fNotInHm = */ false,
78 /* .pfnHandler = */ pgmR3HandlerPhysicalHandlerInvalid,
79#else
80# error "unsupported context"
81#endif
82 /* .pszDesc = */ "dummy"
83};
84
85
86/*********************************************************************************************************************************
87* Internal Functions *
88*********************************************************************************************************************************/
89static int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVMCC pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam,
90 void *pvBitmap, uint32_t offBitmap);
91static void pgmHandlerPhysicalDeregisterNotifyNEM(PVMCC pVM, PPGMPHYSHANDLER pCur);
92static void pgmHandlerPhysicalResetRamFlags(PVMCC pVM, PPGMPHYSHANDLER pCur);
93
94
95#ifndef IN_RING3
96
97/**
98 * @callback_method_impl{FNPGMPHYSHANDLER,
99 * Dummy for forcing ring-3 handling of the access.}
100 */
101DECLCALLBACK(VBOXSTRICTRC)
102pgmR0HandlerPhysicalHandlerToRing3(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
103 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, uint64_t uUser)
104{
105 RT_NOREF(pVM, pVCpu, GCPhys, pvPhys, pvBuf, cbBuf, enmAccessType, enmOrigin, uUser);
106 return VINF_EM_RAW_EMULATE_INSTR;
107}
108
109
110/**
111 * @callback_method_impl{FNPGMRZPHYSPFHANDLER,
112 * Dummy for forcing ring-3 handling of the access.}
113 */
114DECLCALLBACK(VBOXSTRICTRC)
115pgmR0HandlerPhysicalPfHandlerToRing3(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTX pCtx,
116 RTGCPTR pvFault, RTGCPHYS GCPhysFault, uint64_t uUser)
117{
118 RT_NOREF(pVM, pVCpu, uErrorCode, pCtx, pvFault, GCPhysFault, uUser);
119 return VINF_EM_RAW_EMULATE_INSTR;
120}
121
122#endif /* !IN_RING3 */
123
124
125/**
126 * Creates a physical access handler, allocation part.
127 *
128 * @returns VBox status code.
129 * @retval VERR_OUT_OF_RESOURCES if no more handlers available.
130 *
131 * @param pVM The cross context VM structure.
132 * @param hType The handler type registration handle.
133 * @param uUser User argument to the handlers (not pointer).
134 * @param pszDesc Description of this handler. If NULL, the type
135 * description will be used instead.
136 * @param ppPhysHandler Where to return the access handler structure on
137 * success.
138 */
139int pgmHandlerPhysicalExCreate(PVMCC pVM, PGMPHYSHANDLERTYPE hType, uint64_t uUser,
140 R3PTRTYPE(const char *) pszDesc, PPGMPHYSHANDLER *ppPhysHandler)
141{
142 /*
143 * Validate input.
144 */
145 PCPGMPHYSHANDLERTYPEINT const pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
146 AssertReturn(pType, VERR_INVALID_HANDLE);
147 AssertReturn(pType->enmKind > PGMPHYSHANDLERKIND_INVALID && pType->enmKind < PGMPHYSHANDLERKIND_END, VERR_INVALID_HANDLE);
148 AssertPtr(ppPhysHandler);
149
150 Log(("pgmHandlerPhysicalExCreate: uUser=%#RX64 hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
151 uUser, hType, pType->enmKind, pType->pszDesc, pszDesc, R3STRING(pszDesc)));
152
153 /*
154 * Allocate and initialize the new entry.
155 */
156 int rc = PGM_LOCK(pVM);
157 AssertRCReturn(rc, rc);
158
159 PPGMPHYSHANDLER pNew = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.allocateNode();
160 if (pNew)
161 {
162 pNew->Key = NIL_RTGCPHYS;
163 pNew->KeyLast = NIL_RTGCPHYS;
164 pNew->cPages = 0;
165 pNew->cAliasedPages = 0;
166 pNew->cTmpOffPages = 0;
167 pNew->uUser = uUser;
168 pNew->hType = hType;
169 pNew->pszDesc = pszDesc != NIL_RTR3PTR ? pszDesc
170#ifdef IN_RING3
171 : pType->pszDesc;
172#else
173 : pVM->pgm.s.aPhysHandlerTypes[hType & PGMPHYSHANDLERTYPE_IDX_MASK].pszDesc;
174#endif
175
176 PGM_UNLOCK(pVM);
177 *ppPhysHandler = pNew;
178 return VINF_SUCCESS;
179 }
180
181 PGM_UNLOCK(pVM);
182 return VERR_OUT_OF_RESOURCES;
183}
184
185
186/**
187 * Duplicates a physical access handler.
188 *
189 * @returns VBox status code.
190 * @retval VINF_SUCCESS when successfully installed.
191 *
192 * @param pVM The cross context VM structure.
193 * @param pPhysHandlerSrc The source handler to duplicate
194 * @param ppPhysHandler Where to return the access handler structure on
195 * success.
196 */
197int pgmHandlerPhysicalExDup(PVMCC pVM, PPGMPHYSHANDLER pPhysHandlerSrc, PPGMPHYSHANDLER *ppPhysHandler)
198{
199 return pgmHandlerPhysicalExCreate(pVM, pPhysHandlerSrc->hType, pPhysHandlerSrc->uUser,
200 pPhysHandlerSrc->pszDesc, ppPhysHandler);
201}
202
203
204/**
205 * Register a access handler for a physical range.
206 *
207 * @returns VBox status code.
208 * @retval VINF_SUCCESS when successfully installed.
209 * @retval VINF_PGM_GCPHYS_ALIASED could be returned.
210 *
211 * @param pVM The cross context VM structure.
212 * @param pPhysHandler The physical handler.
213 * @param GCPhys Start physical address.
214 * @param GCPhysLast Last physical address. (inclusive)
215 */
216int pgmHandlerPhysicalExRegister(PVMCC pVM, PPGMPHYSHANDLER pPhysHandler, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast)
217{
218 /*
219 * Validate input.
220 */
221 AssertReturn(pPhysHandler, VERR_INVALID_POINTER);
222 PGMPHYSHANDLERTYPE const hType = pPhysHandler->hType;
223 PCPGMPHYSHANDLERTYPEINT const pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
224 AssertReturn(pType, VERR_INVALID_HANDLE);
225 AssertReturn(pType->enmKind > PGMPHYSHANDLERKIND_INVALID && pType->enmKind < PGMPHYSHANDLERKIND_END, VERR_INVALID_HANDLE);
226
227 AssertPtr(pPhysHandler);
228
229 Log(("pgmHandlerPhysicalExRegister: GCPhys=%RGp GCPhysLast=%RGp hType=%#x (%d, %s) pszDesc=%RHv:%s\n", GCPhys, GCPhysLast,
230 hType, pType->enmKind, pType->pszDesc, pPhysHandler->pszDesc, R3STRING(pPhysHandler->pszDesc)));
231 AssertReturn(pPhysHandler->Key == NIL_RTGCPHYS, VERR_WRONG_ORDER);
232
233 AssertMsgReturn(GCPhys < GCPhysLast, ("GCPhys >= GCPhysLast (%#x >= %#x)\n", GCPhys, GCPhysLast), VERR_INVALID_PARAMETER);
234 Assert(GCPhysLast - GCPhys < _4G); /* ASSUMPTION in PGMAllPhys.cpp */
235
236 switch (pType->enmKind)
237 {
238 case PGMPHYSHANDLERKIND_WRITE:
239 if (!pType->fNotInHm)
240 break;
241 RT_FALL_THRU(); /* Simplification: fNotInHm can only be used with full pages */
242 case PGMPHYSHANDLERKIND_MMIO:
243 case PGMPHYSHANDLERKIND_ALL:
244 /* Simplification for PGMPhysRead, PGMR0Trap0eHandlerNPMisconfig and others: Full pages. */
245 AssertMsgReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), ("%RGp\n", GCPhys), VERR_INVALID_PARAMETER);
246 AssertMsgReturn((GCPhysLast & GUEST_PAGE_OFFSET_MASK) == GUEST_PAGE_OFFSET_MASK, ("%RGp\n", GCPhysLast), VERR_INVALID_PARAMETER);
247 break;
248 default:
249 AssertMsgFailed(("Invalid input enmKind=%d!\n", pType->enmKind));
250 return VERR_INVALID_PARAMETER;
251 }
252
253 /*
254 * We require the range to be within registered ram.
255 * There is no apparent need to support ranges which cover more than one ram range.
256 */
257 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
258 if ( !pRam
259 || GCPhysLast > pRam->GCPhysLast)
260 {
261#ifdef IN_RING3
262 DBGFR3Info(pVM->pUVM, "phys", NULL, NULL);
263#endif
264 AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
265 return VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE;
266 }
267 Assert(GCPhys >= pRam->GCPhys && GCPhys < pRam->GCPhysLast);
268 Assert(GCPhysLast <= pRam->GCPhysLast && GCPhysLast >= pRam->GCPhys);
269
270 /*
271 * Try insert into list.
272 */
273 pPhysHandler->Key = GCPhys;
274 pPhysHandler->KeyLast = GCPhysLast;
275 pPhysHandler->cPages = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + GUEST_PAGE_SIZE) >> GUEST_PAGE_SHIFT;
276
277 int rc = PGM_LOCK(pVM);
278 if (RT_SUCCESS(rc))
279 {
280 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->insert(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, pPhysHandler);
281 if (RT_SUCCESS(rc))
282 {
283 rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pPhysHandler, pRam, NULL /*pvBitmap*/, 0 /*offBitmap*/);
284 if (rc == VINF_PGM_SYNC_CR3)
285 rc = VINF_PGM_GCPHYS_ALIASED;
286
287#if defined(IN_RING3) || defined(IN_RING0)
288 NEMHCNotifyHandlerPhysicalRegister(pVM, pType->enmKind, GCPhys, GCPhysLast - GCPhys + 1);
289#endif
290 PGM_UNLOCK(pVM);
291
292 if (rc != VINF_SUCCESS)
293 Log(("PGMHandlerPhysicalRegisterEx: returns %Rrc (%RGp-%RGp)\n", rc, GCPhys, GCPhysLast));
294 return rc;
295 }
296 PGM_UNLOCK(pVM);
297 }
298
299 pPhysHandler->Key = NIL_RTGCPHYS;
300 pPhysHandler->KeyLast = NIL_RTGCPHYS;
301
302 AssertMsgReturn(rc == VERR_ALREADY_EXISTS, ("%Rrc GCPhys=%RGp GCPhysLast=%RGp\n", rc, GCPhys, GCPhysLast), rc);
303
304#if defined(IN_RING3) && defined(VBOX_STRICT)
305 DBGFR3Info(pVM->pUVM, "handlers", "phys nostats", NULL);
306#endif
307 AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp pszDesc=%s/%s\n",
308 GCPhys, GCPhysLast, R3STRING(pPhysHandler->pszDesc), R3STRING(pType->pszDesc)));
309 return VERR_PGM_HANDLER_PHYSICAL_CONFLICT;
310}
311
312
313/**
314 * Register a access handler for a physical range.
315 *
316 * @returns VBox status code.
317 * @retval VINF_SUCCESS when successfully installed.
318 * @retval VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because
319 * the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been
320 * flagged together with a pool clearing.
321 * @retval VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing
322 * one. A debug assertion is raised.
323 *
324 * @param pVM The cross context VM structure.
325 * @param GCPhys Start physical address.
326 * @param GCPhysLast Last physical address. (inclusive)
327 * @param hType The handler type registration handle.
328 * @param uUser User argument to the handler.
329 * @param pszDesc Description of this handler. If NULL, the type
330 * description will be used instead.
331 */
332VMMDECL(int) PGMHandlerPhysicalRegister(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, PGMPHYSHANDLERTYPE hType,
333 uint64_t uUser, R3PTRTYPE(const char *) pszDesc)
334{
335#ifdef LOG_ENABLED
336 PCPGMPHYSHANDLERTYPEINT pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
337 Log(("PGMHandlerPhysicalRegister: GCPhys=%RGp GCPhysLast=%RGp uUser=%#RX64 hType=%#x (%d, %s) pszDesc=%RHv:%s\n",
338 GCPhys, GCPhysLast, uUser, hType, pType->enmKind, R3STRING(pType->pszDesc), pszDesc, R3STRING(pszDesc)));
339#endif
340
341 PPGMPHYSHANDLER pNew;
342 int rc = pgmHandlerPhysicalExCreate(pVM, hType, uUser, pszDesc, &pNew);
343 if (RT_SUCCESS(rc))
344 {
345 rc = pgmHandlerPhysicalExRegister(pVM, pNew, GCPhys, GCPhysLast);
346 if (RT_SUCCESS(rc))
347 return rc;
348 pgmHandlerPhysicalExDestroy(pVM, pNew);
349 }
350 return rc;
351}
352
353
354/**
355 * Sets ram range flags and attempts updating shadow PTs.
356 *
357 * @returns VBox status code.
358 * @retval VINF_SUCCESS when shadow PTs was successfully updated.
359 * @retval VINF_PGM_SYNC_CR3 when the shadow PTs could be updated because
360 * the guest page aliased or/and mapped by multiple PTs. FFs set.
361 * @param pVM The cross context VM structure.
362 * @param pCur The physical handler.
363 * @param pRam The RAM range.
364 * @param pvBitmap Dirty bitmap. Optional.
365 * @param offBitmap Dirty bitmap offset.
366 */
367static int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVMCC pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam,
368 void *pvBitmap, uint32_t offBitmap)
369{
370 /*
371 * Iterate the guest ram pages updating the flags and flushing PT entries
372 * mapping the page.
373 */
374 bool fFlushTLBs = false;
375 int rc = VINF_SUCCESS;
376 PCPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
377 const unsigned uState = pCurType->uState;
378 uint32_t cPages = pCur->cPages;
379 uint32_t i = (pCur->Key - pRam->GCPhys) >> GUEST_PAGE_SHIFT;
380 for (;;)
381 {
382 PPGMPAGE pPage = &pRam->aPages[i];
383 AssertMsg(pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO || PGM_PAGE_IS_MMIO(pPage),
384 ("%RGp %R[pgmpage]\n", pRam->GCPhys + (i << GUEST_PAGE_SHIFT), pPage));
385
386 /* Only do upgrades. */
387 if (PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) < uState)
388 {
389 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, uState, pCurType->fNotInHm);
390
391 const RTGCPHYS GCPhysPage = pRam->GCPhys + (i << GUEST_PAGE_SHIFT);
392 int rc2 = pgmPoolTrackUpdateGCPhys(pVM, GCPhysPage, pPage,
393 false /* allow updates of PTEs (instead of flushing) */, &fFlushTLBs);
394 if (rc2 != VINF_SUCCESS && rc == VINF_SUCCESS)
395 rc = rc2;
396
397#ifdef VBOX_WITH_NATIVE_NEM
398 /* Tell NEM about the protection update. */
399 if (VM_IS_NEM_ENABLED(pVM))
400 {
401 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
402 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
403 NEMHCNotifyPhysPageProtChanged(pVM, GCPhysPage, PGM_PAGE_GET_HCPHYS(pPage),
404 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysPage),
405 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
406 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
407 }
408#endif
409 if (pvBitmap)
410 ASMBitSet(pvBitmap, offBitmap);
411 }
412
413 /* next */
414 if (--cPages == 0)
415 break;
416 i++;
417 offBitmap++;
418 }
419
420 if (fFlushTLBs)
421 {
422 PGM_INVL_ALL_VCPU_TLBS(pVM);
423 Log(("pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs: flushing guest TLBs; rc=%d\n", rc));
424 }
425 else
426 Log(("pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs: doesn't flush guest TLBs. rc=%Rrc; sync flags=%x VMCPU_FF_PGM_SYNC_CR3=%d\n", rc, VMMGetCpu(pVM)->pgm.s.fSyncFlags, VMCPU_FF_IS_SET(VMMGetCpu(pVM), VMCPU_FF_PGM_SYNC_CR3)));
427
428 return rc;
429}
430
431
432/**
433 * Deregister a physical page access handler.
434 *
435 * @returns VBox status code.
436 * @param pVM The cross context VM structure.
437 * @param pPhysHandler The handler to deregister (but not free).
438 */
439int pgmHandlerPhysicalExDeregister(PVMCC pVM, PPGMPHYSHANDLER pPhysHandler)
440{
441 LogFlow(("pgmHandlerPhysicalExDeregister: Removing Range %RGp-%RGp %s\n",
442 pPhysHandler->Key, pPhysHandler->KeyLast, R3STRING(pPhysHandler->pszDesc)));
443
444 int rc = PGM_LOCK(pVM);
445 AssertRCReturn(rc, rc);
446
447 RTGCPHYS const GCPhys = pPhysHandler->Key;
448 AssertReturnStmt(GCPhys != NIL_RTGCPHYS, PGM_UNLOCK(pVM), VERR_PGM_HANDLER_NOT_FOUND);
449
450 /*
451 * Remove the handler from the tree.
452 */
453
454 PPGMPHYSHANDLER pRemoved;
455 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->remove(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pRemoved);
456 if (RT_SUCCESS(rc))
457 {
458 if (pRemoved == pPhysHandler)
459 {
460 /*
461 * Clear the page bits, notify the REM about this change and clear
462 * the cache.
463 */
464 pgmHandlerPhysicalResetRamFlags(pVM, pPhysHandler);
465 if (VM_IS_NEM_ENABLED(pVM))
466 pgmHandlerPhysicalDeregisterNotifyNEM(pVM, pPhysHandler);
467 pVM->pgm.s.idxLastPhysHandler = 0;
468
469 pPhysHandler->Key = NIL_RTGCPHYS;
470 pPhysHandler->KeyLast = NIL_RTGCPHYS;
471
472 PGM_UNLOCK(pVM);
473
474 return VINF_SUCCESS;
475 }
476
477 /*
478 * Both of the failure conditions here are considered internal processing
479 * errors because they can only be caused by race conditions or corruption.
480 * If we ever need to handle concurrent deregistration, we have to move
481 * the NIL_RTGCPHYS check inside the PGM lock.
482 */
483 pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->insert(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, pRemoved);
484 }
485
486 PGM_UNLOCK(pVM);
487
488 if (RT_FAILURE(rc))
489 AssertMsgFailed(("Didn't find range starting at %RGp in the tree! %Rrc=rc\n", GCPhys, rc));
490 else
491 AssertMsgFailed(("Found different handle at %RGp in the tree: got %p insteaded of %p\n",
492 GCPhys, pRemoved, pPhysHandler));
493 return VERR_PGM_HANDLER_IPE_1;
494}
495
496
497/**
498 * Destroys (frees) a physical handler.
499 *
500 * The caller must deregister it before destroying it!
501 *
502 * @returns VBox status code.
503 * @param pVM The cross context VM structure.
504 * @param pHandler The handler to free. NULL if ignored.
505 */
506int pgmHandlerPhysicalExDestroy(PVMCC pVM, PPGMPHYSHANDLER pHandler)
507{
508 if (pHandler)
509 {
510 AssertPtr(pHandler);
511 AssertReturn(pHandler->Key == NIL_RTGCPHYS, VERR_WRONG_ORDER);
512
513 int rc = PGM_LOCK(pVM);
514 if (RT_SUCCESS(rc))
515 {
516 rc = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.freeNode(pHandler);
517 PGM_UNLOCK(pVM);
518 }
519 return rc;
520 }
521 return VINF_SUCCESS;
522}
523
524
525/**
526 * Deregister a physical page access handler.
527 *
528 * @returns VBox status code.
529 * @param pVM The cross context VM structure.
530 * @param GCPhys Start physical address.
531 */
532VMMDECL(int) PGMHandlerPhysicalDeregister(PVMCC pVM, RTGCPHYS GCPhys)
533{
534 AssertReturn(pVM->VMCC_CTX(pgm).s.pPhysHandlerTree, VERR_PGM_HANDLER_IPE_1);
535
536 /*
537 * Find the handler.
538 */
539 int rc = PGM_LOCK(pVM);
540 AssertRCReturn(rc, rc);
541
542 PPGMPHYSHANDLER pRemoved;
543 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->remove(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pRemoved);
544 if (RT_SUCCESS(rc))
545 {
546 Assert(pRemoved->Key == GCPhys);
547 LogFlow(("PGMHandlerPhysicalDeregister: Removing Range %RGp-%RGp %s\n",
548 pRemoved->Key, pRemoved->KeyLast, R3STRING(pRemoved->pszDesc)));
549
550 /*
551 * Clear the page bits, notify the REM about this change and clear
552 * the cache.
553 */
554 pgmHandlerPhysicalResetRamFlags(pVM, pRemoved);
555 if (VM_IS_NEM_ENABLED(pVM))
556 pgmHandlerPhysicalDeregisterNotifyNEM(pVM, pRemoved);
557 pVM->pgm.s.idxLastPhysHandler = 0;
558
559 pRemoved->Key = NIL_RTGCPHYS;
560 rc = pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator.freeNode(pRemoved);
561
562 PGM_UNLOCK(pVM);
563 return rc;
564 }
565
566 PGM_UNLOCK(pVM);
567
568 if (rc == VERR_NOT_FOUND)
569 {
570 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
571 rc = VERR_PGM_HANDLER_NOT_FOUND;
572 }
573 return rc;
574}
575
576
577/**
578 * Shared code with modify.
579 */
580static void pgmHandlerPhysicalDeregisterNotifyNEM(PVMCC pVM, PPGMPHYSHANDLER pCur)
581{
582#ifdef VBOX_WITH_NATIVE_NEM
583 PCPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
584 RTGCPHYS GCPhysStart = pCur->Key;
585 RTGCPHYS GCPhysLast = pCur->KeyLast;
586
587 /*
588 * Page align the range.
589 *
590 * Since we've reset (recalculated) the physical handler state of all pages
591 * we can make use of the page states to figure out whether a page should be
592 * included in the REM notification or not.
593 */
594 if ( (pCur->Key & GUEST_PAGE_OFFSET_MASK)
595 || ((pCur->KeyLast + 1) & GUEST_PAGE_OFFSET_MASK))
596 {
597 Assert(pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO);
598
599 if (GCPhysStart & GUEST_PAGE_OFFSET_MASK)
600 {
601 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhysStart);
602 if ( pPage
603 && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_NONE)
604 {
605 RTGCPHYS GCPhys = (GCPhysStart + (GUEST_PAGE_SIZE - 1)) & X86_PTE_PAE_PG_MASK;
606 if ( GCPhys > GCPhysLast
607 || GCPhys < GCPhysStart)
608 return;
609 GCPhysStart = GCPhys;
610 }
611 else
612 GCPhysStart &= X86_PTE_PAE_PG_MASK;
613 Assert(!pPage || PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO); /* these are page aligned atm! */
614 }
615
616 if (GCPhysLast & GUEST_PAGE_OFFSET_MASK)
617 {
618 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhysLast);
619 if ( pPage
620 && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_NONE)
621 {
622 RTGCPHYS GCPhys = (GCPhysLast & X86_PTE_PAE_PG_MASK) - 1;
623 if ( GCPhys < GCPhysStart
624 || GCPhys > GCPhysLast)
625 return;
626 GCPhysLast = GCPhys;
627 }
628 else
629 GCPhysLast |= GUEST_PAGE_OFFSET_MASK;
630 Assert(!pPage || PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO); /* these are page aligned atm! */
631 }
632 }
633
634 /*
635 * Tell NEM.
636 */
637 PPGMRAMRANGE const pRam = pgmPhysGetRange(pVM, GCPhysStart);
638 RTGCPHYS const cb = GCPhysLast - GCPhysStart + 1;
639 uint8_t u2State = UINT8_MAX;
640 NEMHCNotifyHandlerPhysicalDeregister(pVM, pCurType->enmKind, GCPhysStart, cb,
641 pRam ? PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysStart) : NULL, &u2State);
642 if (u2State != UINT8_MAX && pRam)
643 pgmPhysSetNemStateForPages(&pRam->aPages[(GCPhysStart - pRam->GCPhys) >> GUEST_PAGE_SHIFT],
644 cb >> GUEST_PAGE_SHIFT, u2State);
645#else
646 RT_NOREF(pVM, pCur);
647#endif
648}
649
650
651/**
652 * pgmHandlerPhysicalResetRamFlags helper that checks for other handlers on
653 * edge pages.
654 */
655DECLINLINE(void) pgmHandlerPhysicalRecalcPageState(PVMCC pVM, RTGCPHYS GCPhys, bool fAbove, PPGMRAMRANGE *ppRamHint)
656{
657 /*
658 * Look for other handlers.
659 */
660 unsigned uState = PGM_PAGE_HNDL_PHYS_STATE_NONE;
661 for (;;)
662 {
663 PPGMPHYSHANDLER pCur;
664 int rc;
665 if (fAbove)
666 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookupMatchingOrAbove(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator,
667 GCPhys, &pCur);
668 else
669 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookupMatchingOrBelow(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator,
670 GCPhys, &pCur);
671 if (rc == VERR_NOT_FOUND)
672 break;
673 AssertRCBreak(rc);
674 if (((fAbove ? pCur->Key : pCur->KeyLast) >> GUEST_PAGE_SHIFT) != (GCPhys >> GUEST_PAGE_SHIFT))
675 break;
676 PCPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
677 uState = RT_MAX(uState, pCurType->uState);
678
679 /* next? */
680 RTGCPHYS GCPhysNext = fAbove
681 ? pCur->KeyLast + 1
682 : pCur->Key - 1;
683 if ((GCPhysNext >> GUEST_PAGE_SHIFT) != (GCPhys >> GUEST_PAGE_SHIFT))
684 break;
685 GCPhys = GCPhysNext;
686 }
687
688 /*
689 * Update if we found something that is a higher priority state than the current.
690 * Note! The PGMPHYSHANDLER_F_NOT_IN_HM can be ignored here as it requires whole pages.
691 */
692 if (uState != PGM_PAGE_HNDL_PHYS_STATE_NONE)
693 {
694 PPGMPAGE pPage;
695 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, ppRamHint);
696 if ( RT_SUCCESS(rc)
697 && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) < uState)
698 {
699 /* This should normally not be necessary. */
700 PGM_PAGE_SET_HNDL_PHYS_STATE_ONLY(pPage, uState);
701 bool fFlushTLBs;
702 rc = pgmPoolTrackUpdateGCPhys(pVM, GCPhys, pPage, false /*fFlushPTEs*/, &fFlushTLBs);
703 if (RT_SUCCESS(rc) && fFlushTLBs)
704 PGM_INVL_ALL_VCPU_TLBS(pVM);
705 else
706 AssertRC(rc);
707
708#ifdef VBOX_WITH_NATIVE_NEM
709 /* Tell NEM about the protection update. */
710 if (VM_IS_NEM_ENABLED(pVM))
711 {
712 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
713 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
714 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
715 PGM_RAMRANGE_CALC_PAGE_R3PTR(*ppRamHint, GCPhys),
716 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
717 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
718 }
719#endif
720 }
721 else
722 AssertRC(rc);
723 }
724}
725
726
727/**
728 * Resets an aliased page.
729 *
730 * @param pVM The cross context VM structure.
731 * @param pPage The page.
732 * @param GCPhysPage The page address in case it comes in handy.
733 * @param pRam The RAM range the page is associated with (for NEM
734 * notifications).
735 * @param fDoAccounting Whether to perform accounting. (Only set during
736 * reset where pgmR3PhysRamReset doesn't have the
737 * handler structure handy.)
738 */
739void pgmHandlerPhysicalResetAliasedPage(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhysPage, PPGMRAMRANGE pRam, bool fDoAccounting)
740{
741 Assert( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
742 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO);
743 Assert(PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
744#ifdef VBOX_WITH_NATIVE_NEM
745 RTHCPHYS const HCPhysPrev = PGM_PAGE_GET_HCPHYS(pPage);
746#endif
747
748 /*
749 * Flush any shadow page table references *first*.
750 */
751 bool fFlushTLBs = false;
752 int rc = pgmPoolTrackUpdateGCPhys(pVM, GCPhysPage, pPage, true /*fFlushPTEs*/, &fFlushTLBs);
753 AssertLogRelRCReturnVoid(rc);
754 HMFlushTlbOnAllVCpus(pVM);
755
756 /*
757 * Make it an MMIO/Zero page.
758 */
759 PGM_PAGE_SET_HCPHYS(pVM, pPage, pVM->pgm.s.HCPhysZeroPg);
760 PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_MMIO);
761 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ZERO);
762 PGM_PAGE_SET_PAGEID(pVM, pPage, NIL_GMM_PAGEID);
763 PGM_PAGE_SET_HNDL_PHYS_STATE_ONLY(pPage, PGM_PAGE_HNDL_PHYS_STATE_ALL);
764
765 /* Flush its TLB entry. */
766 pgmPhysInvalidatePageMapTLBEntry(pVM, GCPhysPage);
767 /* Not calling IEMTlbInvalidateAllPhysicalAllCpus here as aliased pages are handled like MMIO by the IEM TLB. */
768
769 /*
770 * Do accounting for pgmR3PhysRamReset.
771 */
772 if (fDoAccounting)
773 {
774 PPGMPHYSHANDLER pHandler;
775 rc = pgmHandlerPhysicalLookup(pVM, GCPhysPage, &pHandler);
776 if (RT_SUCCESS(rc))
777 {
778 Assert(pHandler->cAliasedPages > 0);
779 pHandler->cAliasedPages--;
780 }
781 else
782 AssertMsgFailed(("rc=%Rrc GCPhysPage=%RGp\n", rc, GCPhysPage));
783 }
784
785#ifdef VBOX_WITH_NATIVE_NEM
786 /*
787 * Tell NEM about the protection change.
788 */
789 if (VM_IS_NEM_ENABLED(pVM))
790 {
791 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
792 NEMHCNotifyPhysPageChanged(pVM, GCPhysPage, HCPhysPrev, pVM->pgm.s.HCPhysZeroPg,
793 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysPage),
794 NEM_PAGE_PROT_NONE, PGMPAGETYPE_MMIO, &u2State);
795 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
796 }
797#else
798 RT_NOREF(pRam);
799#endif
800}
801
802
803/**
804 * Resets ram range flags.
805 *
806 * @returns VBox status code.
807 * @retval VINF_SUCCESS when shadow PTs was successfully updated.
808 * @param pVM The cross context VM structure.
809 * @param pCur The physical handler.
810 *
811 * @remark We don't start messing with the shadow page tables, as we've
812 * already got code in Trap0e which deals with out of sync handler
813 * flags (originally conceived for global pages).
814 */
815static void pgmHandlerPhysicalResetRamFlags(PVMCC pVM, PPGMPHYSHANDLER pCur)
816{
817 /*
818 * Iterate the guest ram pages updating the state.
819 */
820 RTUINT cPages = pCur->cPages;
821 RTGCPHYS GCPhys = pCur->Key;
822 PPGMRAMRANGE pRamHint = NULL;
823 for (;;)
824 {
825 PPGMPAGE pPage;
826 int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
827 if (RT_SUCCESS(rc))
828 {
829 /* Reset aliased MMIO pages to MMIO, since this aliasing is our business.
830 (We don't flip MMIO to RAM though, that's PGMPhys.cpp's job.) */
831 bool fNemNotifiedAlready = false;
832 if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
833 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO)
834 {
835 Assert(pCur->cAliasedPages > 0);
836 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, GCPhys, pRamHint, false /*fDoAccounting*/);
837 pCur->cAliasedPages--;
838 fNemNotifiedAlready = true;
839 }
840#ifdef VBOX_STRICT
841 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
842 AssertMsg(pCurType && (pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO || PGM_PAGE_IS_MMIO(pPage)),
843 ("%RGp %R[pgmpage]\n", GCPhys, pPage));
844#endif
845 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE, false);
846
847#ifdef VBOX_WITH_NATIVE_NEM
848 /* Tell NEM about the protection change. */
849 if (VM_IS_NEM_ENABLED(pVM) && !fNemNotifiedAlready)
850 {
851 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
852 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
853 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
854 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRamHint, GCPhys),
855 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
856 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
857 }
858#endif
859 RT_NOREF(fNemNotifiedAlready);
860 }
861 else
862 AssertRC(rc);
863
864 /* next */
865 if (--cPages == 0)
866 break;
867 GCPhys += GUEST_PAGE_SIZE;
868 }
869
870 pCur->cAliasedPages = 0;
871 pCur->cTmpOffPages = 0;
872
873 /*
874 * Check for partial start and end pages.
875 */
876 if (pCur->Key & GUEST_PAGE_OFFSET_MASK)
877 pgmHandlerPhysicalRecalcPageState(pVM, pCur->Key - 1, false /* fAbove */, &pRamHint);
878 if ((pCur->KeyLast & GUEST_PAGE_OFFSET_MASK) != GUEST_PAGE_OFFSET_MASK)
879 pgmHandlerPhysicalRecalcPageState(pVM, pCur->KeyLast + 1, true /* fAbove */, &pRamHint);
880}
881
882
883#if 0 /* unused */
884/**
885 * Modify a physical page access handler.
886 *
887 * Modification can only be done to the range it self, not the type or anything else.
888 *
889 * @returns VBox status code.
890 * For all return codes other than VERR_PGM_HANDLER_NOT_FOUND and VINF_SUCCESS the range is deregistered
891 * and a new registration must be performed!
892 * @param pVM The cross context VM structure.
893 * @param GCPhysCurrent Current location.
894 * @param GCPhys New location.
895 * @param GCPhysLast New last location.
896 */
897VMMDECL(int) PGMHandlerPhysicalModify(PVMCC pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast)
898{
899 /*
900 * Remove it.
901 */
902 int rc;
903 PGM_LOCK_VOID(pVM);
904 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhysCurrent);
905 if (pCur)
906 {
907 /*
908 * Clear the ram flags. (We're gonna move or free it!)
909 */
910 pgmHandlerPhysicalResetRamFlags(pVM, pCur);
911 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
912 @todo pCurType validation
913 bool const fRestoreAsRAM = pCurType->pfnHandlerR3 /** @todo this isn't entirely correct. */
914 && pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO;
915
916 /*
917 * Validate the new range, modify and reinsert.
918 */
919 if (GCPhysLast >= GCPhys)
920 {
921 /*
922 * We require the range to be within registered ram.
923 * There is no apparent need to support ranges which cover more than one ram range.
924 */
925 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
926 if ( pRam
927 && GCPhys <= pRam->GCPhysLast
928 && GCPhysLast >= pRam->GCPhys)
929 {
930 pCur->Core.Key = GCPhys;
931 pCur->Core.KeyLast = GCPhysLast;
932 pCur->cPages = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + 1) >> GUEST_PAGE_SHIFT;
933
934 if (RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pCur->Core))
935 {
936 RTGCPHYS const cb = GCPhysLast - GCPhys + 1;
937 PGMPHYSHANDLERKIND const enmKind = pCurType->enmKind;
938
939 /*
940 * Set ram flags, flush shadow PT entries and finally tell REM about this.
941 */
942 rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pCur, pRam, NULL, 0);
943
944 /** @todo NEM: not sure we need this notification... */
945 NEMHCNotifyHandlerPhysicalModify(pVM, enmKind, GCPhysCurrent, GCPhys, cb, fRestoreAsRAM);
946
947 PGM_UNLOCK(pVM);
948
949 PGM_INVL_ALL_VCPU_TLBS(pVM);
950 Log(("PGMHandlerPhysicalModify: GCPhysCurrent=%RGp -> GCPhys=%RGp GCPhysLast=%RGp\n",
951 GCPhysCurrent, GCPhys, GCPhysLast));
952 return VINF_SUCCESS;
953 }
954
955 AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp\n", GCPhys, GCPhysLast));
956 rc = VERR_PGM_HANDLER_PHYSICAL_CONFLICT;
957 }
958 else
959 {
960 AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
961 rc = VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE;
962 }
963 }
964 else
965 {
966 AssertMsgFailed(("Invalid range %RGp-%RGp\n", GCPhys, GCPhysLast));
967 rc = VERR_INVALID_PARAMETER;
968 }
969
970 /*
971 * Invalid new location, flush the cache and free it.
972 * We've only gotta notify REM and free the memory.
973 */
974 if (VM_IS_NEM_ENABLED(pVM))
975 pgmHandlerPhysicalDeregisterNotifyNEM(pVM, pCur);
976 pVM->pgm.s.pLastPhysHandlerR0 = 0;
977 pVM->pgm.s.pLastPhysHandlerR3 = 0;
978 PGMHandlerPhysicalTypeRelease(pVM, pCur->hType);
979 MMHyperFree(pVM, pCur);
980 }
981 else
982 {
983 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhysCurrent));
984 rc = VERR_PGM_HANDLER_NOT_FOUND;
985 }
986
987 PGM_UNLOCK(pVM);
988 return rc;
989}
990#endif /* unused */
991
992
993/**
994 * Changes the user callback arguments associated with a physical access handler.
995 *
996 * @returns VBox status code.
997 * @param pVM The cross context VM structure.
998 * @param GCPhys Start physical address of the handler.
999 * @param uUser User argument to the handlers.
1000 */
1001VMMDECL(int) PGMHandlerPhysicalChangeUserArg(PVMCC pVM, RTGCPHYS GCPhys, uint64_t uUser)
1002{
1003 /*
1004 * Find the handler and make the change.
1005 */
1006 int rc = PGM_LOCK(pVM);
1007 AssertRCReturn(rc, rc);
1008
1009 PPGMPHYSHANDLER pCur;
1010 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pCur);
1011 if (RT_SUCCESS(rc))
1012 {
1013 Assert(pCur->Key == GCPhys);
1014 pCur->uUser = uUser;
1015 }
1016 else if (rc == VERR_NOT_FOUND)
1017 {
1018 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
1019 rc = VERR_PGM_HANDLER_NOT_FOUND;
1020 }
1021
1022 PGM_UNLOCK(pVM);
1023 return rc;
1024}
1025
1026#if 0 /* unused */
1027
1028/**
1029 * Splits a physical access handler in two.
1030 *
1031 * @returns VBox status code.
1032 * @param pVM The cross context VM structure.
1033 * @param GCPhys Start physical address of the handler.
1034 * @param GCPhysSplit The split address.
1035 */
1036VMMDECL(int) PGMHandlerPhysicalSplit(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysSplit)
1037{
1038 AssertReturn(GCPhys < GCPhysSplit, VERR_INVALID_PARAMETER);
1039
1040 /*
1041 * Do the allocation without owning the lock.
1042 */
1043 PPGMPHYSHANDLER pNew;
1044 int rc = MMHyperAlloc(pVM, sizeof(*pNew), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew);
1045 if (RT_FAILURE(rc))
1046 return rc;
1047
1048 /*
1049 * Get the handler.
1050 */
1051 PGM_LOCK_VOID(pVM);
1052 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
1053 if (RT_LIKELY(pCur))
1054 {
1055 if (RT_LIKELY(GCPhysSplit <= pCur->Core.KeyLast))
1056 {
1057 /*
1058 * Create new handler node for the 2nd half.
1059 */
1060 *pNew = *pCur;
1061 pNew->Core.Key = GCPhysSplit;
1062 pNew->cPages = (pNew->Core.KeyLast - (pNew->Core.Key & X86_PTE_PAE_PG_MASK) + GUEST_PAGE_SIZE) >> GUEST_PAGE_SHIFT;
1063
1064 pCur->Core.KeyLast = GCPhysSplit - 1;
1065 pCur->cPages = (pCur->Core.KeyLast - (pCur->Core.Key & X86_PTE_PAE_PG_MASK) + GUEST_PAGE_SIZE) >> GUEST_PAGE_SHIFT;
1066
1067 if (RT_LIKELY(RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pNew->Core)))
1068 {
1069 LogFlow(("PGMHandlerPhysicalSplit: %RGp-%RGp and %RGp-%RGp\n",
1070 pCur->Core.Key, pCur->Core.KeyLast, pNew->Core.Key, pNew->Core.KeyLast));
1071 PGM_UNLOCK(pVM);
1072 return VINF_SUCCESS;
1073 }
1074 AssertMsgFailed(("whu?\n"));
1075 rc = VERR_PGM_PHYS_HANDLER_IPE;
1076 }
1077 else
1078 {
1079 AssertMsgFailed(("outside range: %RGp-%RGp split %RGp\n", pCur->Core.Key, pCur->Core.KeyLast, GCPhysSplit));
1080 rc = VERR_INVALID_PARAMETER;
1081 }
1082 }
1083 else
1084 {
1085 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
1086 rc = VERR_PGM_HANDLER_NOT_FOUND;
1087 }
1088 PGM_UNLOCK(pVM);
1089 MMHyperFree(pVM, pNew);
1090 return rc;
1091}
1092
1093
1094/**
1095 * Joins up two adjacent physical access handlers which has the same callbacks.
1096 *
1097 * @returns VBox status code.
1098 * @param pVM The cross context VM structure.
1099 * @param GCPhys1 Start physical address of the first handler.
1100 * @param GCPhys2 Start physical address of the second handler.
1101 */
1102VMMDECL(int) PGMHandlerPhysicalJoin(PVMCC pVM, RTGCPHYS GCPhys1, RTGCPHYS GCPhys2)
1103{
1104 /*
1105 * Get the handlers.
1106 */
1107 int rc;
1108 PGM_LOCK_VOID(pVM);
1109 PPGMPHYSHANDLER pCur1 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys1);
1110 if (RT_LIKELY(pCur1))
1111 {
1112 PPGMPHYSHANDLER pCur2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys2);
1113 if (RT_LIKELY(pCur2))
1114 {
1115 /*
1116 * Make sure that they are adjacent, and that they've got the same callbacks.
1117 */
1118 if (RT_LIKELY(pCur1->Core.KeyLast + 1 == pCur2->Core.Key))
1119 {
1120 if (RT_LIKELY(pCur1->hType == pCur2->hType))
1121 {
1122 PPGMPHYSHANDLER pCur3 = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys2);
1123 if (RT_LIKELY(pCur3 == pCur2))
1124 {
1125 pCur1->Core.KeyLast = pCur2->Core.KeyLast;
1126 pCur1->cPages = (pCur1->Core.KeyLast - (pCur1->Core.Key & X86_PTE_PAE_PG_MASK) + GUEST_PAGE_SIZE) >> GUEST_PAGE_SHIFT;
1127 LogFlow(("PGMHandlerPhysicalJoin: %RGp-%RGp %RGp-%RGp\n",
1128 pCur1->Core.Key, pCur1->Core.KeyLast, pCur2->Core.Key, pCur2->Core.KeyLast));
1129 pVM->pgm.s.pLastPhysHandlerR0 = 0;
1130 pVM->pgm.s.pLastPhysHandlerR3 = 0;
1131 PGMHandlerPhysicalTypeRelease(pVM, pCur2->hType);
1132 MMHyperFree(pVM, pCur2);
1133 PGM_UNLOCK(pVM);
1134 return VINF_SUCCESS;
1135 }
1136
1137 Assert(pCur3 == pCur2);
1138 rc = VERR_PGM_PHYS_HANDLER_IPE;
1139 }
1140 else
1141 {
1142 AssertMsgFailed(("mismatching handlers\n"));
1143 rc = VERR_ACCESS_DENIED;
1144 }
1145 }
1146 else
1147 {
1148 AssertMsgFailed(("not adjacent: %RGp-%RGp %RGp-%RGp\n",
1149 pCur1->Core.Key, pCur1->Core.KeyLast, pCur2->Core.Key, pCur2->Core.KeyLast));
1150 rc = VERR_INVALID_PARAMETER;
1151 }
1152 }
1153 else
1154 {
1155 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys2));
1156 rc = VERR_PGM_HANDLER_NOT_FOUND;
1157 }
1158 }
1159 else
1160 {
1161 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys1));
1162 rc = VERR_PGM_HANDLER_NOT_FOUND;
1163 }
1164 PGM_UNLOCK(pVM);
1165 return rc;
1166
1167}
1168
1169#endif /* unused */
1170
1171/**
1172 * Resets any modifications to individual pages in a physical page access
1173 * handler region.
1174 *
1175 * This is used in pair with PGMHandlerPhysicalPageTempOff(),
1176 * PGMHandlerPhysicalPageAliasMmio2() or PGMHandlerPhysicalPageAliasHC().
1177 *
1178 * @returns VBox status code.
1179 * @param pVM The cross context VM structure.
1180 * @param GCPhys The start address of the handler regions, i.e. what you
1181 * passed to PGMR3HandlerPhysicalRegister(),
1182 * PGMHandlerPhysicalRegisterEx() or
1183 * PGMHandlerPhysicalModify().
1184 */
1185VMMDECL(int) PGMHandlerPhysicalReset(PVMCC pVM, RTGCPHYS GCPhys)
1186{
1187 LogFlow(("PGMHandlerPhysicalReset GCPhys=%RGp\n", GCPhys));
1188 int rc = PGM_LOCK(pVM);
1189 AssertRCReturn(rc, rc);
1190
1191 /*
1192 * Find the handler.
1193 */
1194 PPGMPHYSHANDLER pCur;
1195 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pCur);
1196 if (RT_SUCCESS(rc))
1197 {
1198 Assert(pCur->Key == GCPhys);
1199
1200 /*
1201 * Validate kind.
1202 */
1203 PCPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
1204 switch (pCurType->enmKind)
1205 {
1206 case PGMPHYSHANDLERKIND_WRITE:
1207 case PGMPHYSHANDLERKIND_ALL:
1208 case PGMPHYSHANDLERKIND_MMIO: /* NOTE: Only use when clearing MMIO ranges with aliased MMIO2 pages! */
1209 {
1210 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysHandlerReset)); /** @todo move out of switch */
1211 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
1212 Assert(pRam);
1213 Assert(pRam->GCPhys <= pCur->Key);
1214 Assert(pRam->GCPhysLast >= pCur->KeyLast);
1215
1216 if (pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO)
1217 {
1218 /*
1219 * Reset all the PGMPAGETYPE_MMIO2_ALIAS_MMIO pages first and that's it.
1220 * This could probably be optimized a bit wrt to flushing, but I'm too lazy
1221 * to do that now...
1222 */
1223 if (pCur->cAliasedPages)
1224 {
1225 PPGMPAGE pPage = &pRam->aPages[(pCur->Key - pRam->GCPhys) >> GUEST_PAGE_SHIFT];
1226 RTGCPHYS GCPhysPage = pCur->Key;
1227 uint32_t cLeft = pCur->cPages;
1228 while (cLeft-- > 0)
1229 {
1230 if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
1231 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO)
1232 {
1233 Assert(pCur->cAliasedPages > 0);
1234 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, GCPhysPage, pRam, false /*fDoAccounting*/);
1235 --pCur->cAliasedPages;
1236#ifndef VBOX_STRICT
1237 if (pCur->cAliasedPages == 0)
1238 break;
1239#endif
1240 }
1241 Assert(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO);
1242 GCPhysPage += GUEST_PAGE_SIZE;
1243 pPage++;
1244 }
1245 Assert(pCur->cAliasedPages == 0);
1246 }
1247 }
1248 else if (pCur->cTmpOffPages > 0)
1249 {
1250 /*
1251 * Set the flags and flush shadow PT entries.
1252 */
1253 rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pCur, pRam, NULL /*pvBitmap*/, 0 /*offBitmap*/);
1254 }
1255
1256 pCur->cAliasedPages = 0;
1257 pCur->cTmpOffPages = 0;
1258
1259 rc = VINF_SUCCESS;
1260 break;
1261 }
1262
1263 /*
1264 * Invalid.
1265 */
1266 default:
1267 AssertMsgFailed(("Invalid type %d/%#x! Corruption!\n", pCurType->enmKind, pCur->hType));
1268 rc = VERR_PGM_PHYS_HANDLER_IPE;
1269 break;
1270 }
1271 }
1272 else if (rc == VERR_NOT_FOUND)
1273 {
1274 AssertMsgFailed(("Didn't find MMIO Range starting at %#x\n", GCPhys));
1275 rc = VERR_PGM_HANDLER_NOT_FOUND;
1276 }
1277
1278 PGM_UNLOCK(pVM);
1279 return rc;
1280}
1281
1282
1283/**
1284 * Special version of PGMHandlerPhysicalReset used by MMIO2 w/ dirty page
1285 * tracking.
1286 *
1287 * @returns VBox status code.
1288 * @param pVM The cross context VM structure.
1289 * @param GCPhys The start address of the handler region.
1290 * @param pvBitmap Dirty bitmap. Caller has cleared this already, only
1291 * dirty bits will be set. Caller also made sure it's big
1292 * enough.
1293 * @param offBitmap Dirty bitmap offset.
1294 * @remarks Caller must own the PGM critical section.
1295 */
1296DECLHIDDEN(int) pgmHandlerPhysicalResetMmio2WithBitmap(PVMCC pVM, RTGCPHYS GCPhys, void *pvBitmap, uint32_t offBitmap)
1297{
1298 LogFlow(("pgmHandlerPhysicalResetMmio2WithBitmap GCPhys=%RGp\n", GCPhys));
1299 PGM_LOCK_ASSERT_OWNER(pVM);
1300
1301 /*
1302 * Find the handler.
1303 */
1304 PPGMPHYSHANDLER pCur;
1305 int rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pCur);
1306 if (RT_SUCCESS(rc))
1307 {
1308 Assert(pCur->Key == GCPhys);
1309
1310 /*
1311 * Validate kind.
1312 */
1313 PCPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
1314 if ( pCurType
1315 && pCurType->enmKind == PGMPHYSHANDLERKIND_WRITE)
1316 {
1317 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysHandlerReset));
1318
1319 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
1320 Assert(pRam);
1321 Assert(pRam->GCPhys <= pCur->Key);
1322 Assert(pRam->GCPhysLast >= pCur->KeyLast);
1323
1324 /*
1325 * Set the flags and flush shadow PT entries.
1326 */
1327 if (pCur->cTmpOffPages > 0)
1328 {
1329 rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pCur, pRam, pvBitmap, offBitmap);
1330 pCur->cTmpOffPages = 0;
1331 }
1332 else
1333 rc = VINF_SUCCESS;
1334 }
1335 else
1336 {
1337 AssertFailed();
1338 rc = VERR_WRONG_TYPE;
1339 }
1340 }
1341 else if (rc == VERR_NOT_FOUND)
1342 {
1343 AssertMsgFailed(("Didn't find MMIO Range starting at %#x\n", GCPhys));
1344 rc = VERR_PGM_HANDLER_NOT_FOUND;
1345 }
1346
1347 return rc;
1348}
1349
1350
1351/**
1352 * Temporarily turns off the access monitoring of a page within a monitored
1353 * physical write/all page access handler region.
1354 *
1355 * Use this when no further \#PFs are required for that page. Be aware that
1356 * a page directory sync might reset the flags, and turn on access monitoring
1357 * for the page.
1358 *
1359 * The caller must do required page table modifications.
1360 *
1361 * @returns VBox status code.
1362 * @param pVM The cross context VM structure.
1363 * @param GCPhys The start address of the access handler. This
1364 * must be a fully page aligned range or we risk
1365 * messing up other handlers installed for the
1366 * start and end pages.
1367 * @param GCPhysPage The physical address of the page to turn off
1368 * access monitoring for.
1369 */
1370VMMDECL(int) PGMHandlerPhysicalPageTempOff(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)
1371{
1372 LogFlow(("PGMHandlerPhysicalPageTempOff GCPhysPage=%RGp\n", GCPhysPage));
1373 int rc = PGM_LOCK(pVM);
1374 AssertRCReturn(rc, rc);
1375
1376 /*
1377 * Validate the range.
1378 */
1379 PPGMPHYSHANDLER pCur;
1380 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pCur);
1381 if (RT_SUCCESS(rc))
1382 {
1383 Assert(pCur->Key == GCPhys);
1384 if (RT_LIKELY( GCPhysPage >= pCur->Key
1385 && GCPhysPage <= pCur->KeyLast))
1386 {
1387 Assert(!(pCur->Key & GUEST_PAGE_OFFSET_MASK));
1388 Assert((pCur->KeyLast & GUEST_PAGE_OFFSET_MASK) == GUEST_PAGE_OFFSET_MASK);
1389
1390 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
1391 AssertReturnStmt( pCurType
1392 && ( pCurType->enmKind == PGMPHYSHANDLERKIND_WRITE
1393 || pCurType->enmKind == PGMPHYSHANDLERKIND_ALL),
1394 PGM_UNLOCK(pVM), VERR_ACCESS_DENIED);
1395
1396 /*
1397 * Change the page status.
1398 */
1399 PPGMPAGE pPage;
1400 PPGMRAMRANGE pRam;
1401 rc = pgmPhysGetPageAndRangeEx(pVM, GCPhysPage, &pPage, &pRam);
1402 AssertReturnStmt(RT_SUCCESS_NP(rc), PGM_UNLOCK(pVM), rc);
1403 if (PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
1404 {
1405 PGM_PAGE_SET_HNDL_PHYS_STATE_ONLY(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
1406 pCur->cTmpOffPages++;
1407
1408#ifdef VBOX_WITH_NATIVE_NEM
1409 /* Tell NEM about the protection change (VGA is using this to track dirty pages). */
1410 if (VM_IS_NEM_ENABLED(pVM))
1411 {
1412 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
1413 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
1414 NEMHCNotifyPhysPageProtChanged(pVM, GCPhysPage, PGM_PAGE_GET_HCPHYS(pPage),
1415 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysPage),
1416 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
1417 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
1418 }
1419#endif
1420 }
1421 PGM_UNLOCK(pVM);
1422 return VINF_SUCCESS;
1423 }
1424 PGM_UNLOCK(pVM);
1425 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n", GCPhysPage, pCur->Key, pCur->KeyLast));
1426 return VERR_INVALID_PARAMETER;
1427 }
1428 PGM_UNLOCK(pVM);
1429
1430 if (rc == VERR_NOT_FOUND)
1431 {
1432 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys));
1433 return VERR_PGM_HANDLER_NOT_FOUND;
1434 }
1435 return rc;
1436}
1437
1438
1439/**
1440 * Resolves an MMIO2 page.
1441 *
1442 * Caller as taken the PGM lock.
1443 *
1444 * @returns Pointer to the page if valid, NULL otherwise
1445 * @param pVM The cross context VM structure.
1446 * @param pDevIns The device owning it.
1447 * @param hMmio2 The MMIO2 region.
1448 * @param offMmio2Page The offset into the region.
1449 */
1450static PPGMPAGE pgmPhysResolveMmio2PageLocked(PVMCC pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS offMmio2Page)
1451{
1452 /* Only works if the handle is in the handle table! */
1453 AssertReturn(hMmio2 != 0, NULL);
1454 hMmio2--;
1455
1456 /* Must check the first one for PGMREGMMIO2RANGE_F_FIRST_CHUNK. */
1457 AssertReturn(hMmio2 < RT_ELEMENTS(pVM->pgm.s.apMmio2RangesR3), NULL);
1458 PPGMREGMMIO2RANGE pCur = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[hMmio2];
1459 AssertReturn(pCur, NULL);
1460 AssertReturn(pCur->fFlags & PGMREGMMIO2RANGE_F_FIRST_CHUNK, NULL);
1461
1462 /* Loop thru the sub-ranges till we find the one covering offMmio2. */
1463 for (;;)
1464 {
1465#ifdef IN_RING3
1466 AssertReturn(pCur->pDevInsR3 == pDevIns, NULL);
1467#else
1468 AssertReturn(pCur->pDevInsR3 == pDevIns->pDevInsForR3, NULL);
1469#endif
1470
1471 /* Does it match the offset? */
1472 if (offMmio2Page < pCur->cbReal)
1473 return &pCur->RamRange.aPages[offMmio2Page >> GUEST_PAGE_SHIFT];
1474
1475 /* Advance if we can. */
1476 AssertReturn(!(pCur->fFlags & PGMREGMMIO2RANGE_F_LAST_CHUNK), NULL);
1477 offMmio2Page -= pCur->cbReal;
1478 hMmio2++;
1479 AssertReturn(hMmio2 < RT_ELEMENTS(pVM->pgm.s.apMmio2RangesR3), NULL);
1480 pCur = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[hMmio2];
1481 AssertReturn(pCur, NULL);
1482 }
1483}
1484
1485
1486/**
1487 * Replaces an MMIO page with an MMIO2 page.
1488 *
1489 * This is a worker for IOMMMIOMapMMIO2Page that works in a similar way to
1490 * PGMHandlerPhysicalPageTempOff but for an MMIO page. Since an MMIO page has no
1491 * backing, the caller must provide a replacement page. For various reasons the
1492 * replacement page must be an MMIO2 page.
1493 *
1494 * The caller must do required page table modifications. You can get away
1495 * without making any modifications since it's an MMIO page, the cost is an extra
1496 * \#PF which will the resync the page.
1497 *
1498 * Call PGMHandlerPhysicalReset() to restore the MMIO page.
1499 *
1500 * The caller may still get handler callback even after this call and must be
1501 * able to deal correctly with such calls. The reason for these callbacks are
1502 * either that we're executing in the recompiler (which doesn't know about this
1503 * arrangement) or that we've been restored from saved state (where we won't
1504 * save the change).
1505 *
1506 * @returns VBox status code.
1507 * @param pVM The cross context VM structure.
1508 * @param GCPhys The start address of the access handler. This
1509 * must be a fully page aligned range or we risk
1510 * messing up other handlers installed for the
1511 * start and end pages.
1512 * @param GCPhysPage The physical address of the page to turn off
1513 * access monitoring for and replace with the MMIO2
1514 * page.
1515 * @param pDevIns The device instance owning @a hMmio2.
1516 * @param hMmio2 Handle to the MMIO2 region containing the page
1517 * to remap in the the MMIO page at @a GCPhys.
1518 * @param offMmio2PageRemap The offset into @a hMmio2 of the MMIO2 page that
1519 * should serve as backing memory.
1520 *
1521 * @remark May cause a page pool flush if used on a page that is already
1522 * aliased.
1523 *
1524 * @note This trick does only work reliably if the two pages are never ever
1525 * mapped in the same page table. If they are the page pool code will
1526 * be confused should either of them be flushed. See the special case
1527 * of zero page aliasing mentioned in #3170.
1528 *
1529 */
1530VMMDECL(int) PGMHandlerPhysicalPageAliasMmio2(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage,
1531 PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS offMmio2PageRemap)
1532{
1533#ifdef VBOX_WITH_PGM_NEM_MODE
1534 AssertReturn(!VM_IS_NEM_ENABLED(pVM) || !pVM->pgm.s.fNemMode, VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE);
1535#endif
1536 int rc = PGM_LOCK(pVM);
1537 AssertRCReturn(rc, rc);
1538
1539 /*
1540 * Resolve the MMIO2 reference.
1541 */
1542 PPGMPAGE pPageRemap = pgmPhysResolveMmio2PageLocked(pVM, pDevIns, hMmio2, offMmio2PageRemap);
1543 if (RT_LIKELY(pPageRemap))
1544 AssertMsgReturnStmt(PGM_PAGE_GET_TYPE(pPageRemap) == PGMPAGETYPE_MMIO2,
1545 ("hMmio2=%RU64 offMmio2PageRemap=%RGp %R[pgmpage]\n", hMmio2, offMmio2PageRemap, pPageRemap),
1546 PGM_UNLOCK(pVM), VERR_PGM_PHYS_NOT_MMIO2);
1547 else
1548 {
1549 PGM_UNLOCK(pVM);
1550 return VERR_OUT_OF_RANGE;
1551 }
1552
1553 /*
1554 * Lookup and validate the range.
1555 */
1556 PPGMPHYSHANDLER pCur;
1557 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pCur);
1558 if (RT_SUCCESS(rc))
1559 {
1560 Assert(pCur->Key == GCPhys);
1561 if (RT_LIKELY( GCPhysPage >= pCur->Key
1562 && GCPhysPage <= pCur->KeyLast))
1563 {
1564 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
1565 AssertReturnStmt(pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO, PGM_UNLOCK(pVM), VERR_ACCESS_DENIED);
1566 AssertReturnStmt(!(pCur->Key & GUEST_PAGE_OFFSET_MASK), PGM_UNLOCK(pVM), VERR_INVALID_PARAMETER);
1567 AssertReturnStmt((pCur->KeyLast & GUEST_PAGE_OFFSET_MASK) == GUEST_PAGE_OFFSET_MASK,
1568 PGM_UNLOCK(pVM), VERR_INVALID_PARAMETER);
1569
1570 /*
1571 * Validate the page.
1572 */
1573 PPGMPAGE pPage;
1574 PPGMRAMRANGE pRam;
1575 rc = pgmPhysGetPageAndRangeEx(pVM, GCPhysPage, &pPage, &pRam);
1576 AssertReturnStmt(RT_SUCCESS_NP(rc), PGM_UNLOCK(pVM), rc);
1577 if (PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO)
1578 {
1579 AssertMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO,
1580 ("GCPhysPage=%RGp %R[pgmpage]\n", GCPhysPage, pPage),
1581 VERR_PGM_PHYS_NOT_MMIO2);
1582 if (PGM_PAGE_GET_HCPHYS(pPage) == PGM_PAGE_GET_HCPHYS(pPageRemap))
1583 {
1584 PGM_UNLOCK(pVM);
1585 return VINF_PGM_HANDLER_ALREADY_ALIASED;
1586 }
1587
1588 /*
1589 * The page is already mapped as some other page, reset it
1590 * to an MMIO/ZERO page before doing the new mapping.
1591 */
1592 Log(("PGMHandlerPhysicalPageAliasMmio2: GCPhysPage=%RGp (%R[pgmpage]; %RHp -> %RHp\n",
1593 GCPhysPage, pPage, PGM_PAGE_GET_HCPHYS(pPage), PGM_PAGE_GET_HCPHYS(pPageRemap)));
1594 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, GCPhysPage, pRam, false /*fDoAccounting*/);
1595 pCur->cAliasedPages--;
1596 }
1597 Assert(PGM_PAGE_IS_ZERO(pPage));
1598
1599 /*
1600 * Do the actual remapping here.
1601 * This page now serves as an alias for the backing memory specified.
1602 */
1603 LogFlow(("PGMHandlerPhysicalPageAliasMmio2: %RGp (%R[pgmpage]) alias for %RU64/%RGp (%R[pgmpage])\n",
1604 GCPhysPage, pPage, hMmio2, offMmio2PageRemap, pPageRemap ));
1605 PGM_PAGE_SET_HCPHYS(pVM, pPage, PGM_PAGE_GET_HCPHYS(pPageRemap));
1606 PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_MMIO2_ALIAS_MMIO);
1607 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ALLOCATED);
1608 PGM_PAGE_SET_PAGEID(pVM, pPage, PGM_PAGE_GET_PAGEID(pPageRemap));
1609 PGM_PAGE_SET_HNDL_PHYS_STATE_ONLY(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
1610 pCur->cAliasedPages++;
1611 Assert(pCur->cAliasedPages <= pCur->cPages);
1612
1613 /* Flush its TLB entry. */
1614 pgmPhysInvalidatePageMapTLBEntry(pVM, GCPhysPage);
1615 /* Not calling IEMTlbInvalidateAllPhysicalAllCpus here as aliased pages are handled like MMIO by the IEM TLB. */
1616
1617#ifdef VBOX_WITH_NATIVE_NEM
1618 /* Tell NEM about the backing and protection change. */
1619 if (VM_IS_NEM_ENABLED(pVM))
1620 {
1621 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
1622 NEMHCNotifyPhysPageChanged(pVM, GCPhysPage, pVM->pgm.s.HCPhysZeroPg, PGM_PAGE_GET_HCPHYS(pPage),
1623 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysPage),
1624 pgmPhysPageCalcNemProtection(pPage, PGMPAGETYPE_MMIO2_ALIAS_MMIO),
1625 PGMPAGETYPE_MMIO2_ALIAS_MMIO, &u2State);
1626 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
1627 }
1628#endif
1629 LogFlow(("PGMHandlerPhysicalPageAliasMmio2: => %R[pgmpage]\n", pPage));
1630 PGM_UNLOCK(pVM);
1631 return VINF_SUCCESS;
1632 }
1633
1634 PGM_UNLOCK(pVM);
1635 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n", GCPhysPage, pCur->Key, pCur->KeyLast));
1636 return VERR_INVALID_PARAMETER;
1637 }
1638
1639 PGM_UNLOCK(pVM);
1640 if (rc == VERR_NOT_FOUND)
1641 {
1642 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys));
1643 return VERR_PGM_HANDLER_NOT_FOUND;
1644 }
1645 return rc;
1646}
1647
1648
1649/**
1650 * Replaces an MMIO page with an arbitrary HC page in the shadow page tables.
1651 *
1652 * This differs from PGMHandlerPhysicalPageAliasMmio2 in that the page doesn't
1653 * need to be a known MMIO2 page and that only shadow paging may access the
1654 * page. The latter distinction is important because the only use for this
1655 * feature is for mapping the special APIC access page that VT-x uses to detect
1656 * APIC MMIO operations, the page is shared between all guest CPUs and actually
1657 * not written to. At least at the moment.
1658 *
1659 * The caller must do required page table modifications. You can get away
1660 * without making any modifications since it's an MMIO page, the cost is an extra
1661 * \#PF which will the resync the page.
1662 *
1663 * Call PGMHandlerPhysicalReset() to restore the MMIO page.
1664 *
1665 *
1666 * @returns VBox status code.
1667 * @param pVM The cross context VM structure.
1668 * @param GCPhys The start address of the access handler. This
1669 * must be a fully page aligned range or we risk
1670 * messing up other handlers installed for the
1671 * start and end pages.
1672 * @param GCPhysPage The physical address of the page to turn off
1673 * access monitoring for.
1674 * @param HCPhysPageRemap The physical address of the HC page that
1675 * serves as backing memory.
1676 *
1677 * @remark May cause a page pool flush if used on a page that is already
1678 * aliased.
1679 */
1680VMMDECL(int) PGMHandlerPhysicalPageAliasHC(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTHCPHYS HCPhysPageRemap)
1681{
1682/// Assert(!IOMIsLockOwner(pVM)); /* We mustn't own any other locks when calling this */
1683#ifdef VBOX_WITH_PGM_NEM_MODE
1684 AssertReturn(!VM_IS_NEM_ENABLED(pVM) || !pVM->pgm.s.fNemMode, VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE);
1685#endif
1686 int rc = PGM_LOCK(pVM);
1687 AssertRCReturn(rc, rc);
1688
1689 /*
1690 * Lookup and validate the range.
1691 */
1692 PPGMPHYSHANDLER pCur;
1693 rc = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, GCPhys, &pCur);
1694 if (RT_SUCCESS(rc))
1695 {
1696 Assert(pCur->Key == GCPhys);
1697 if (RT_LIKELY( GCPhysPage >= pCur->Key
1698 && GCPhysPage <= pCur->KeyLast))
1699 {
1700 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
1701 AssertReturnStmt(pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO, PGM_UNLOCK(pVM), VERR_ACCESS_DENIED);
1702 AssertReturnStmt(!(pCur->Key & GUEST_PAGE_OFFSET_MASK), PGM_UNLOCK(pVM), VERR_INVALID_PARAMETER);
1703 AssertReturnStmt((pCur->KeyLast & GUEST_PAGE_OFFSET_MASK) == GUEST_PAGE_OFFSET_MASK,
1704 PGM_UNLOCK(pVM), VERR_INVALID_PARAMETER);
1705
1706 /*
1707 * Get and validate the pages.
1708 */
1709 PPGMPAGE pPage;
1710 rc = pgmPhysGetPageEx(pVM, GCPhysPage, &pPage);
1711 AssertReturnStmt(RT_SUCCESS_NP(rc), PGM_UNLOCK(pVM), rc);
1712 if (PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO)
1713 {
1714 PGM_UNLOCK(pVM);
1715 AssertMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO,
1716 ("GCPhysPage=%RGp %R[pgmpage]\n", GCPhysPage, pPage),
1717 VERR_PGM_PHYS_NOT_MMIO2);
1718 return VINF_PGM_HANDLER_ALREADY_ALIASED;
1719 }
1720 Assert(PGM_PAGE_IS_ZERO(pPage));
1721
1722 /*
1723 * Do the actual remapping here.
1724 * This page now serves as an alias for the backing memory
1725 * specified as far as shadow paging is concerned.
1726 */
1727 LogFlow(("PGMHandlerPhysicalPageAliasHC: %RGp (%R[pgmpage]) alias for %RHp\n",
1728 GCPhysPage, pPage, HCPhysPageRemap));
1729 PGM_PAGE_SET_HCPHYS(pVM, pPage, HCPhysPageRemap);
1730 PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_SPECIAL_ALIAS_MMIO);
1731 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ALLOCATED);
1732 PGM_PAGE_SET_PAGEID(pVM, pPage, NIL_GMM_PAGEID);
1733 PGM_PAGE_SET_HNDL_PHYS_STATE_ONLY(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
1734 pCur->cAliasedPages++;
1735 Assert(pCur->cAliasedPages <= pCur->cPages);
1736
1737 /* Flush its TLB entry. */
1738 pgmPhysInvalidatePageMapTLBEntry(pVM, GCPhysPage);
1739 /* Not calling IEMTlbInvalidateAllPhysicalAllCpus here as aliased pages are handled like MMIO by the IEM TLB. */
1740
1741#ifdef VBOX_WITH_NATIVE_NEM
1742 /* Tell NEM about the backing and protection change. */
1743 if (VM_IS_NEM_ENABLED(pVM))
1744 {
1745 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhysPage);
1746 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
1747 NEMHCNotifyPhysPageChanged(pVM, GCPhysPage, pVM->pgm.s.HCPhysZeroPg, PGM_PAGE_GET_HCPHYS(pPage),
1748 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysPage),
1749 pgmPhysPageCalcNemProtection(pPage, PGMPAGETYPE_SPECIAL_ALIAS_MMIO),
1750 PGMPAGETYPE_SPECIAL_ALIAS_MMIO, &u2State);
1751 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
1752 }
1753#endif
1754 LogFlow(("PGMHandlerPhysicalPageAliasHC: => %R[pgmpage]\n", pPage));
1755 PGM_UNLOCK(pVM);
1756 return VINF_SUCCESS;
1757 }
1758 PGM_UNLOCK(pVM);
1759 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n", GCPhysPage, pCur->Key, pCur->KeyLast));
1760 return VERR_INVALID_PARAMETER;
1761 }
1762 PGM_UNLOCK(pVM);
1763
1764 if (rc == VERR_NOT_FOUND)
1765 {
1766 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys));
1767 return VERR_PGM_HANDLER_NOT_FOUND;
1768 }
1769 return rc;
1770}
1771
1772
1773/**
1774 * Checks if a physical range is handled
1775 *
1776 * @returns boolean
1777 * @param pVM The cross context VM structure.
1778 * @param GCPhys Start physical address earlier passed to PGMR3HandlerPhysicalRegister().
1779 * @remarks Caller must take the PGM lock...
1780 * @thread EMT.
1781 */
1782VMMDECL(bool) PGMHandlerPhysicalIsRegistered(PVMCC pVM, RTGCPHYS GCPhys)
1783{
1784 /*
1785 * Find the handler.
1786 */
1787 PGM_LOCK_VOID(pVM);
1788 PPGMPHYSHANDLER pCur;
1789 int rc = pgmHandlerPhysicalLookup(pVM, GCPhys, &pCur);
1790 if (RT_SUCCESS(rc))
1791 {
1792#ifdef VBOX_STRICT
1793 Assert(GCPhys >= pCur->Key && GCPhys <= pCur->KeyLast);
1794 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
1795 Assert( pCurType->enmKind == PGMPHYSHANDLERKIND_WRITE
1796 || pCurType->enmKind == PGMPHYSHANDLERKIND_ALL
1797 || pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO);
1798#endif
1799 PGM_UNLOCK(pVM);
1800 return true;
1801 }
1802 PGM_UNLOCK(pVM);
1803 return false;
1804}
1805
1806
1807/**
1808 * Checks if it's an disabled all access handler or write access handler at the
1809 * given address.
1810 *
1811 * @returns true if it's an all access handler, false if it's a write access
1812 * handler.
1813 * @param pVM The cross context VM structure.
1814 * @param GCPhys The address of the page with a disabled handler.
1815 *
1816 * @remarks The caller, PGMR3PhysTlbGCPhys2Ptr, must hold the PGM lock.
1817 */
1818bool pgmHandlerPhysicalIsAll(PVMCC pVM, RTGCPHYS GCPhys)
1819{
1820 PGM_LOCK_VOID(pVM);
1821 PPGMPHYSHANDLER pCur;
1822 int rc = pgmHandlerPhysicalLookup(pVM, GCPhys, &pCur);
1823 AssertRCReturnStmt(rc, PGM_UNLOCK(pVM), true);
1824
1825 /* Only whole pages can be disabled. */
1826 Assert( pCur->Key <= (GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK)
1827 && pCur->KeyLast >= (GCPhys | GUEST_PAGE_OFFSET_MASK));
1828
1829 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
1830 Assert( pCurType->enmKind == PGMPHYSHANDLERKIND_WRITE
1831 || pCurType->enmKind == PGMPHYSHANDLERKIND_ALL
1832 || pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO); /* sanity */
1833 bool const fRet = pCurType->enmKind != PGMPHYSHANDLERKIND_WRITE;
1834 PGM_UNLOCK(pVM);
1835 return fRet;
1836}
1837
1838#ifdef VBOX_STRICT
1839
1840/**
1841 * State structure used by the PGMAssertHandlerAndFlagsInSync() function
1842 * and its AVL enumerators.
1843 */
1844typedef struct PGMAHAFIS
1845{
1846 /** The current physical address. */
1847 RTGCPHYS GCPhys;
1848 /** Number of errors. */
1849 unsigned cErrors;
1850 /** Pointer to the VM. */
1851 PVM pVM;
1852} PGMAHAFIS, *PPGMAHAFIS;
1853
1854
1855/**
1856 * Asserts that the handlers+guest-page-tables == ramrange-flags and
1857 * that the physical addresses associated with virtual handlers are correct.
1858 *
1859 * @returns Number of mismatches.
1860 * @param pVM The cross context VM structure.
1861 */
1862VMMDECL(unsigned) PGMAssertHandlerAndFlagsInSync(PVMCC pVM)
1863{
1864 PPGM pPGM = &pVM->pgm.s;
1865 PGMAHAFIS State;
1866 State.GCPhys = 0;
1867 State.cErrors = 0;
1868 State.pVM = pVM;
1869
1870 PGM_LOCK_ASSERT_OWNER(pVM);
1871
1872 /*
1873 * Check the RAM flags against the handlers.
1874 */
1875 PPGMPHYSHANDLERTREE const pPhysHandlerTree = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree;
1876 for (PPGMRAMRANGE pRam = pPGM->CTX_SUFF(pRamRangesX); pRam; pRam = pRam->CTX_SUFF(pNext))
1877 {
1878 const uint32_t cPages = pRam->cb >> GUEST_PAGE_SHIFT;
1879 for (uint32_t iPage = 0; iPage < cPages; iPage++)
1880 {
1881 PGMPAGE const *pPage = &pRam->aPages[iPage];
1882 if (PGM_PAGE_HAS_ANY_HANDLERS(pPage))
1883 {
1884 State.GCPhys = pRam->GCPhys + (iPage << GUEST_PAGE_SHIFT);
1885
1886 /*
1887 * Physical first - calculate the state based on the handlers
1888 * active on the page, then compare.
1889 */
1890 if (PGM_PAGE_HAS_ANY_PHYSICAL_HANDLERS(pPage))
1891 {
1892 /* the first */
1893 PPGMPHYSHANDLER pPhys;
1894 int rc = pPhysHandlerTree->lookup(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator, State.GCPhys, &pPhys);
1895 if (rc == VERR_NOT_FOUND)
1896 {
1897 rc = pPhysHandlerTree->lookupMatchingOrAbove(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator,
1898 State.GCPhys, &pPhys);
1899 if (RT_SUCCESS(rc))
1900 {
1901 Assert(pPhys->Key >= State.GCPhys);
1902 if (pPhys->Key > (State.GCPhys + GUEST_PAGE_SIZE - 1))
1903 pPhys = NULL;
1904 }
1905 else
1906 AssertLogRelMsgReturn(rc == VERR_NOT_FOUND, ("rc=%Rrc GCPhys=%RGp\n", rc, State.GCPhys), 999);
1907 }
1908 else
1909 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc GCPhys=%RGp\n", rc, State.GCPhys), 999);
1910
1911 if (pPhys)
1912 {
1913 PCPGMPHYSHANDLERTYPEINT pPhysType = pgmHandlerPhysicalTypeHandleToPtr(pVM, pPhys->hType);
1914 unsigned uState = pPhysType->uState;
1915 bool const fNotInHm = pPhysType->fNotInHm; /* whole pages, so no need to accumulate sub-page configs. */
1916
1917 /* more? */
1918 while (pPhys->KeyLast < (State.GCPhys | GUEST_PAGE_OFFSET_MASK))
1919 {
1920 PPGMPHYSHANDLER pPhys2;
1921 rc = pPhysHandlerTree->lookupMatchingOrAbove(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator,
1922 pPhys->KeyLast + 1, &pPhys2);
1923 if (rc == VERR_NOT_FOUND)
1924 break;
1925 AssertLogRelMsgReturn(RT_SUCCESS(rc), ("rc=%Rrc KeyLast+1=%RGp\n", rc, pPhys->KeyLast + 1), 999);
1926 if (pPhys2->Key > (State.GCPhys | GUEST_PAGE_OFFSET_MASK))
1927 break;
1928 PCPGMPHYSHANDLERTYPEINT pPhysType2 = pgmHandlerPhysicalTypeHandleToPtr(pVM, pPhys2->hType);
1929 uState = RT_MAX(uState, pPhysType2->uState);
1930 pPhys = pPhys2;
1931 }
1932
1933 /* compare.*/
1934 if ( PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != uState
1935 && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
1936 {
1937 AssertMsgFailed(("ram range vs phys handler flags mismatch. GCPhys=%RGp state=%d expected=%d %s\n",
1938 State.GCPhys, PGM_PAGE_GET_HNDL_PHYS_STATE(pPage), uState, pPhysType->pszDesc));
1939 State.cErrors++;
1940 }
1941 AssertMsgStmt(PGM_PAGE_IS_HNDL_PHYS_NOT_IN_HM(pPage) == fNotInHm,
1942 ("ram range vs phys handler flags mismatch. GCPhys=%RGp fNotInHm=%d, %d %s\n",
1943 State.GCPhys, PGM_PAGE_IS_HNDL_PHYS_NOT_IN_HM(pPage), fNotInHm, pPhysType->pszDesc),
1944 State.cErrors++);
1945 }
1946 else
1947 {
1948 AssertMsgFailed(("ram range vs phys handler mismatch. no handler for GCPhys=%RGp\n", State.GCPhys));
1949 State.cErrors++;
1950 }
1951 }
1952 }
1953 } /* foreach page in ram range. */
1954 } /* foreach ram range. */
1955
1956 /*
1957 * Do the reverse check for physical handlers.
1958 */
1959 /** @todo */
1960
1961 return State.cErrors;
1962}
1963
1964#endif /* VBOX_STRICT */
1965
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