VirtualBox

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

Last change on this file since 58591 was 58126, checked in by vboxsync, 9 years ago

VMM: Fixed almost all the Doxygen warnings.

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