VirtualBox

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

Last change on this file since 62478 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 75.8 KB
Line 
1/* $Id: PGMAllHandler.cpp 62478 2016-07-22 18:29:06Z vboxsync $ */
2/** @file
3 * PGM - Page Manager / Monitor, Access Handlers.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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#ifdef VBOX_WITH_REM
410 /*
411 * Tell REM.
412 */
413 const bool fRestoreAsRAM = pCurType->pfnHandlerR3
414 && pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO; /** @todo this isn't entirely correct. */
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#ifdef VBOX_WITH_REM
629 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
630 const bool fRestoreAsRAM = pCurType->pfnHandlerR3
631 && pCurType->enmKind != PGMPHYSHANDLERKIND_MMIO; /** @todo this isn't entirely correct. */
632#endif
633
634 /*
635 * Validate the new range, modify and reinsert.
636 */
637 if (GCPhysLast >= GCPhys)
638 {
639 /*
640 * We require the range to be within registered ram.
641 * There is no apparent need to support ranges which cover more than one ram range.
642 */
643 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
644 if ( pRam
645 && GCPhys <= pRam->GCPhysLast
646 && GCPhysLast >= pRam->GCPhys)
647 {
648 pCur->Core.Key = GCPhys;
649 pCur->Core.KeyLast = GCPhysLast;
650 pCur->cPages = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + 1) >> PAGE_SHIFT;
651
652 if (RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pCur->Core))
653 {
654#ifdef VBOX_WITH_REM
655 RTGCPHYS cb = GCPhysLast - GCPhys + 1;
656 PGMPHYSHANDLERKIND enmKind = pCurType->enmKind;
657 bool fHasHCHandler = !!pCurType->pfnHandlerR3;
658#endif
659
660 /*
661 * Set ram flags, flush shadow PT entries and finally tell REM about this.
662 */
663 rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pCur, pRam);
664 pgmUnlock(pVM);
665
666#ifdef VBOX_WITH_REM
667# ifndef IN_RING3
668 REMNotifyHandlerPhysicalModify(pVM, enmKind, GCPhysCurrent, GCPhys, cb,
669 fHasHCHandler, fRestoreAsRAM);
670# else
671 REMR3NotifyHandlerPhysicalModify(pVM, enmKind, GCPhysCurrent, GCPhys, cb,
672 fHasHCHandler, fRestoreAsRAM);
673# endif
674#endif
675 PGM_INVL_ALL_VCPU_TLBS(pVM);
676 Log(("PGMHandlerPhysicalModify: GCPhysCurrent=%RGp -> GCPhys=%RGp GCPhysLast=%RGp\n",
677 GCPhysCurrent, GCPhys, GCPhysLast));
678 return VINF_SUCCESS;
679 }
680
681 AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp\n", GCPhys, GCPhysLast));
682 rc = VERR_PGM_HANDLER_PHYSICAL_CONFLICT;
683 }
684 else
685 {
686 AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
687 rc = VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE;
688 }
689 }
690 else
691 {
692 AssertMsgFailed(("Invalid range %RGp-%RGp\n", GCPhys, GCPhysLast));
693 rc = VERR_INVALID_PARAMETER;
694 }
695
696 /*
697 * Invalid new location, flush the cache and free it.
698 * We've only gotta notify REM and free the memory.
699 */
700 pgmHandlerPhysicalDeregisterNotifyREM(pVM, pCur);
701 pVM->pgm.s.pLastPhysHandlerR0 = 0;
702 pVM->pgm.s.pLastPhysHandlerR3 = 0;
703 pVM->pgm.s.pLastPhysHandlerRC = 0;
704 PGMHandlerPhysicalTypeRelease(pVM, pCur->hType);
705 MMHyperFree(pVM, pCur);
706 }
707 else
708 {
709 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhysCurrent));
710 rc = VERR_PGM_HANDLER_NOT_FOUND;
711 }
712
713 pgmUnlock(pVM);
714 return rc;
715}
716
717
718/**
719 * Changes the user callback arguments associated with a physical access
720 * handler.
721 *
722 * @returns VBox status code.
723 * @param pVM The cross context VM structure.
724 * @param GCPhys Start physical address of the handler.
725 * @param pvUserR3 User argument to the R3 handler.
726 * @param pvUserR0 User argument to the R0 handler.
727 * @param pvUserRC User argument to the RC handler. Values larger or
728 * equal to 0x10000 will be relocated automatically.
729 */
730VMMDECL(int) PGMHandlerPhysicalChangeUserArgs(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvUserR3, RTR0PTR pvUserR0, RTRCPTR pvUserRC)
731{
732 /*
733 * Find the handler.
734 */
735 int rc = VINF_SUCCESS;
736 pgmLock(pVM);
737 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
738 if (pCur)
739 {
740 /*
741 * Change arguments.
742 */
743 pCur->pvUserR3 = pvUserR3;
744 pCur->pvUserR0 = pvUserR0;
745 pCur->pvUserRC = pvUserRC;
746 }
747 else
748 {
749 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
750 rc = VERR_PGM_HANDLER_NOT_FOUND;
751 }
752
753 pgmUnlock(pVM);
754 return rc;
755}
756
757
758/**
759 * Splits a physical access handler in two.
760 *
761 * @returns VBox status code.
762 * @param pVM The cross context VM structure.
763 * @param GCPhys Start physical address of the handler.
764 * @param GCPhysSplit The split address.
765 */
766VMMDECL(int) PGMHandlerPhysicalSplit(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysSplit)
767{
768 AssertReturn(GCPhys < GCPhysSplit, VERR_INVALID_PARAMETER);
769
770 /*
771 * Do the allocation without owning the lock.
772 */
773 PPGMPHYSHANDLER pNew;
774 int rc = MMHyperAlloc(pVM, sizeof(*pNew), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew);
775 if (RT_FAILURE(rc))
776 return rc;
777
778 /*
779 * Get the handler.
780 */
781 pgmLock(pVM);
782 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
783 if (RT_LIKELY(pCur))
784 {
785 if (RT_LIKELY(GCPhysSplit <= pCur->Core.KeyLast))
786 {
787 /*
788 * Create new handler node for the 2nd half.
789 */
790 *pNew = *pCur;
791 pNew->Core.Key = GCPhysSplit;
792 pNew->cPages = (pNew->Core.KeyLast - (pNew->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
793
794 pCur->Core.KeyLast = GCPhysSplit - 1;
795 pCur->cPages = (pCur->Core.KeyLast - (pCur->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
796
797 if (RT_LIKELY(RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pNew->Core)))
798 {
799 LogFlow(("PGMHandlerPhysicalSplit: %RGp-%RGp and %RGp-%RGp\n",
800 pCur->Core.Key, pCur->Core.KeyLast, pNew->Core.Key, pNew->Core.KeyLast));
801 pgmUnlock(pVM);
802 return VINF_SUCCESS;
803 }
804 AssertMsgFailed(("whu?\n"));
805 rc = VERR_PGM_PHYS_HANDLER_IPE;
806 }
807 else
808 {
809 AssertMsgFailed(("outside range: %RGp-%RGp split %RGp\n", pCur->Core.Key, pCur->Core.KeyLast, GCPhysSplit));
810 rc = VERR_INVALID_PARAMETER;
811 }
812 }
813 else
814 {
815 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
816 rc = VERR_PGM_HANDLER_NOT_FOUND;
817 }
818 pgmUnlock(pVM);
819 MMHyperFree(pVM, pNew);
820 return rc;
821}
822
823
824/**
825 * Joins up two adjacent physical access handlers which has the same callbacks.
826 *
827 * @returns VBox status code.
828 * @param pVM The cross context VM structure.
829 * @param GCPhys1 Start physical address of the first handler.
830 * @param GCPhys2 Start physical address of the second handler.
831 */
832VMMDECL(int) PGMHandlerPhysicalJoin(PVM pVM, RTGCPHYS GCPhys1, RTGCPHYS GCPhys2)
833{
834 /*
835 * Get the handlers.
836 */
837 int rc;
838 pgmLock(pVM);
839 PPGMPHYSHANDLER pCur1 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys1);
840 if (RT_LIKELY(pCur1))
841 {
842 PPGMPHYSHANDLER pCur2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys2);
843 if (RT_LIKELY(pCur2))
844 {
845 /*
846 * Make sure that they are adjacent, and that they've got the same callbacks.
847 */
848 if (RT_LIKELY(pCur1->Core.KeyLast + 1 == pCur2->Core.Key))
849 {
850 if (RT_LIKELY(pCur1->hType == pCur2->hType))
851 {
852 PPGMPHYSHANDLER pCur3 = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys2);
853 if (RT_LIKELY(pCur3 == pCur2))
854 {
855 pCur1->Core.KeyLast = pCur2->Core.KeyLast;
856 pCur1->cPages = (pCur1->Core.KeyLast - (pCur1->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
857 LogFlow(("PGMHandlerPhysicalJoin: %RGp-%RGp %RGp-%RGp\n",
858 pCur1->Core.Key, pCur1->Core.KeyLast, pCur2->Core.Key, pCur2->Core.KeyLast));
859 pVM->pgm.s.pLastPhysHandlerR0 = 0;
860 pVM->pgm.s.pLastPhysHandlerR3 = 0;
861 pVM->pgm.s.pLastPhysHandlerRC = 0;
862 PGMHandlerPhysicalTypeRelease(pVM, pCur2->hType);
863 MMHyperFree(pVM, pCur2);
864 pgmUnlock(pVM);
865 return VINF_SUCCESS;
866 }
867
868 Assert(pCur3 == pCur2);
869 rc = VERR_PGM_PHYS_HANDLER_IPE;
870 }
871 else
872 {
873 AssertMsgFailed(("mismatching handlers\n"));
874 rc = VERR_ACCESS_DENIED;
875 }
876 }
877 else
878 {
879 AssertMsgFailed(("not adjacent: %RGp-%RGp %RGp-%RGp\n",
880 pCur1->Core.Key, pCur1->Core.KeyLast, pCur2->Core.Key, pCur2->Core.KeyLast));
881 rc = VERR_INVALID_PARAMETER;
882 }
883 }
884 else
885 {
886 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys2));
887 rc = VERR_PGM_HANDLER_NOT_FOUND;
888 }
889 }
890 else
891 {
892 AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys1));
893 rc = VERR_PGM_HANDLER_NOT_FOUND;
894 }
895 pgmUnlock(pVM);
896 return rc;
897
898}
899
900
901/**
902 * Resets any modifications to individual pages in a physical page access
903 * handler region.
904 *
905 * This is used in pair with PGMHandlerPhysicalPageTempOff(),
906 * PGMHandlerPhysicalPageAlias() or PGMHandlerPhysicalPageAliasHC().
907 *
908 * @returns VBox status code.
909 * @param pVM The cross context VM structure.
910 * @param GCPhys The start address of the handler regions, i.e. what you
911 * passed to PGMR3HandlerPhysicalRegister(),
912 * PGMHandlerPhysicalRegisterEx() or
913 * PGMHandlerPhysicalModify().
914 */
915VMMDECL(int) PGMHandlerPhysicalReset(PVM pVM, RTGCPHYS GCPhys)
916{
917 LogFlow(("PGMHandlerPhysicalReset GCPhys=%RGp\n", GCPhys));
918 pgmLock(pVM);
919
920 /*
921 * Find the handler.
922 */
923 int rc;
924 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
925 if (RT_LIKELY(pCur))
926 {
927 /*
928 * Validate kind.
929 */
930 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
931 switch (pCurType->enmKind)
932 {
933 case PGMPHYSHANDLERKIND_WRITE:
934 case PGMPHYSHANDLERKIND_ALL:
935 case PGMPHYSHANDLERKIND_MMIO: /* NOTE: Only use when clearing MMIO ranges with aliased MMIO2 pages! */
936 {
937 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PhysHandlerReset)); /** @todo move out of switch */
938 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
939 Assert(pRam);
940 Assert(pRam->GCPhys <= pCur->Core.Key);
941 Assert(pRam->GCPhysLast >= pCur->Core.KeyLast);
942
943 if (pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO)
944 {
945 /*
946 * Reset all the PGMPAGETYPE_MMIO2_ALIAS_MMIO pages first and that's it.
947 * This could probably be optimized a bit wrt to flushing, but I'm too lazy
948 * to do that now...
949 */
950 if (pCur->cAliasedPages)
951 {
952 PPGMPAGE pPage = &pRam->aPages[(pCur->Core.Key - pRam->GCPhys) >> PAGE_SHIFT];
953 uint32_t cLeft = pCur->cPages;
954 while (cLeft-- > 0)
955 {
956 if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
957 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO)
958 {
959 Assert(pCur->cAliasedPages > 0);
960 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)cLeft << PAGE_SHIFT),
961 false /*fDoAccounting*/);
962 --pCur->cAliasedPages;
963#ifndef VBOX_STRICT
964 if (pCur->cAliasedPages == 0)
965 break;
966#endif
967 }
968 Assert(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO);
969 pPage++;
970 }
971 Assert(pCur->cAliasedPages == 0);
972 }
973 }
974 else if (pCur->cTmpOffPages > 0)
975 {
976 /*
977 * Set the flags and flush shadow PT entries.
978 */
979 rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pCur, pRam);
980 }
981
982 pCur->cAliasedPages = 0;
983 pCur->cTmpOffPages = 0;
984
985 rc = VINF_SUCCESS;
986 break;
987 }
988
989 /*
990 * Invalid.
991 */
992 default:
993 AssertMsgFailed(("Invalid type %d! Corruption!\n", pCurType->enmKind));
994 rc = VERR_PGM_PHYS_HANDLER_IPE;
995 break;
996 }
997 }
998 else
999 {
1000 AssertMsgFailed(("Didn't find MMIO Range starting at %#x\n", GCPhys));
1001 rc = VERR_PGM_HANDLER_NOT_FOUND;
1002 }
1003
1004 pgmUnlock(pVM);
1005 return rc;
1006}
1007
1008
1009/**
1010 * Temporarily turns off the access monitoring of a page within a monitored
1011 * physical write/all page access handler region.
1012 *
1013 * Use this when no further \#PFs are required for that page. Be aware that
1014 * a page directory sync might reset the flags, and turn on access monitoring
1015 * for the page.
1016 *
1017 * The caller must do required page table modifications.
1018 *
1019 * @returns VBox status code.
1020 * @param pVM The cross context VM structure.
1021 * @param GCPhys The start address of the access handler. This
1022 * must be a fully page aligned range or we risk
1023 * messing up other handlers installed for the
1024 * start and end pages.
1025 * @param GCPhysPage The physical address of the page to turn off
1026 * access monitoring for.
1027 */
1028VMMDECL(int) PGMHandlerPhysicalPageTempOff(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)
1029{
1030 LogFlow(("PGMHandlerPhysicalPageTempOff GCPhysPage=%RGp\n", GCPhysPage));
1031
1032 pgmLock(pVM);
1033 /*
1034 * Validate the range.
1035 */
1036 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
1037 if (RT_LIKELY(pCur))
1038 {
1039 if (RT_LIKELY( GCPhysPage >= pCur->Core.Key
1040 && GCPhysPage <= pCur->Core.KeyLast))
1041 {
1042 Assert(!(pCur->Core.Key & PAGE_OFFSET_MASK));
1043 Assert((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
1044
1045 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
1046 AssertReturnStmt( pCurType->enmKind == PGMPHYSHANDLERKIND_WRITE
1047 || pCurType->enmKind == PGMPHYSHANDLERKIND_ALL,
1048 pgmUnlock(pVM), VERR_ACCESS_DENIED);
1049
1050 /*
1051 * Change the page status.
1052 */
1053 PPGMPAGE pPage;
1054 int rc = pgmPhysGetPageEx(pVM, GCPhysPage, &pPage);
1055 AssertReturnStmt(RT_SUCCESS_NP(rc), pgmUnlock(pVM), rc);
1056 if (PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
1057 {
1058 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
1059 pCur->cTmpOffPages++;
1060 }
1061 pgmUnlock(pVM);
1062 return VINF_SUCCESS;
1063 }
1064 pgmUnlock(pVM);
1065 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n",
1066 GCPhysPage, pCur->Core.Key, pCur->Core.KeyLast));
1067 return VERR_INVALID_PARAMETER;
1068 }
1069 pgmUnlock(pVM);
1070 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys));
1071 return VERR_PGM_HANDLER_NOT_FOUND;
1072}
1073
1074#ifndef IEM_VERIFICATION_MODE_FULL
1075
1076/**
1077 * Replaces an MMIO page with an MMIO2 page.
1078 *
1079 * This is a worker for IOMMMIOMapMMIO2Page that works in a similar way to
1080 * PGMHandlerPhysicalPageTempOff but for an MMIO page. Since an MMIO page has no
1081 * backing, the caller must provide a replacement page. For various reasons the
1082 * replacement page must be an MMIO2 page.
1083 *
1084 * The caller must do required page table modifications. You can get away
1085 * without making any modifications since it's an MMIO page, the cost is an extra
1086 * \#PF which will the resync the page.
1087 *
1088 * Call PGMHandlerPhysicalReset() to restore the MMIO page.
1089 *
1090 * The caller may still get handler callback even after this call and must be
1091 * able to deal correctly with such calls. The reason for these callbacks are
1092 * either that we're executing in the recompiler (which doesn't know about this
1093 * arrangement) or that we've been restored from saved state (where we won't
1094 * save the change).
1095 *
1096 * @returns VBox status code.
1097 * @param pVM The cross context VM structure.
1098 * @param GCPhys The start address of the access handler. This
1099 * must be a fully page aligned range or we risk
1100 * messing up other handlers installed for the
1101 * start and end pages.
1102 * @param GCPhysPage The physical address of the page to turn off
1103 * access monitoring for.
1104 * @param GCPhysPageRemap The physical address of the MMIO2 page that
1105 * serves as backing memory.
1106 *
1107 * @remark May cause a page pool flush if used on a page that is already
1108 * aliased.
1109 *
1110 * @note This trick does only work reliably if the two pages are never ever
1111 * mapped in the same page table. If they are the page pool code will
1112 * be confused should either of them be flushed. See the special case
1113 * of zero page aliasing mentioned in #3170.
1114 *
1115 */
1116VMMDECL(int) PGMHandlerPhysicalPageAlias(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTGCPHYS GCPhysPageRemap)
1117{
1118/// Assert(!IOMIsLockOwner(pVM)); /* We mustn't own any other locks when calling this */
1119 pgmLock(pVM);
1120
1121 /*
1122 * Lookup and validate the range.
1123 */
1124 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
1125 if (RT_LIKELY(pCur))
1126 {
1127 if (RT_LIKELY( GCPhysPage >= pCur->Core.Key
1128 && GCPhysPage <= pCur->Core.KeyLast))
1129 {
1130 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
1131 AssertReturnStmt(pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO, pgmUnlock(pVM), VERR_ACCESS_DENIED);
1132 AssertReturnStmt(!(pCur->Core.Key & PAGE_OFFSET_MASK), pgmUnlock(pVM), VERR_INVALID_PARAMETER);
1133 AssertReturnStmt((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK, pgmUnlock(pVM), VERR_INVALID_PARAMETER);
1134
1135 /*
1136 * Get and validate the two pages.
1137 */
1138 PPGMPAGE pPageRemap;
1139 int rc = pgmPhysGetPageEx(pVM, GCPhysPageRemap, &pPageRemap);
1140 AssertReturnStmt(RT_SUCCESS_NP(rc), pgmUnlock(pVM), rc);
1141 AssertMsgReturnStmt(PGM_PAGE_GET_TYPE(pPageRemap) == PGMPAGETYPE_MMIO2,
1142 ("GCPhysPageRemap=%RGp %R[pgmpage]\n", GCPhysPageRemap, pPageRemap),
1143 pgmUnlock(pVM), VERR_PGM_PHYS_NOT_MMIO2);
1144
1145 PPGMPAGE pPage;
1146 rc = pgmPhysGetPageEx(pVM, GCPhysPage, &pPage);
1147 AssertReturnStmt(RT_SUCCESS_NP(rc), pgmUnlock(pVM), rc);
1148 if (PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO)
1149 {
1150 AssertMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO,
1151 ("GCPhysPage=%RGp %R[pgmpage]\n", GCPhysPage, pPage),
1152 VERR_PGM_PHYS_NOT_MMIO2);
1153 if (PGM_PAGE_GET_HCPHYS(pPage) == PGM_PAGE_GET_HCPHYS(pPageRemap))
1154 {
1155 pgmUnlock(pVM);
1156 return VINF_PGM_HANDLER_ALREADY_ALIASED;
1157 }
1158
1159 /*
1160 * The page is already mapped as some other page, reset it
1161 * to an MMIO/ZERO page before doing the new mapping.
1162 */
1163 Log(("PGMHandlerPhysicalPageAlias: GCPhysPage=%RGp (%R[pgmpage]; %RHp -> %RHp\n",
1164 GCPhysPage, pPage, PGM_PAGE_GET_HCPHYS(pPage), PGM_PAGE_GET_HCPHYS(pPageRemap)));
1165 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, GCPhysPage, false /*fDoAccounting*/);
1166 pCur->cAliasedPages--;
1167 }
1168 Assert(PGM_PAGE_IS_ZERO(pPage));
1169
1170 /*
1171 * Do the actual remapping here.
1172 * This page now serves as an alias for the backing memory specified.
1173 */
1174 LogFlow(("PGMHandlerPhysicalPageAlias: %RGp (%R[pgmpage]) alias for %RGp (%R[pgmpage])\n",
1175 GCPhysPage, pPage, GCPhysPageRemap, pPageRemap ));
1176 PGM_PAGE_SET_HCPHYS(pVM, pPage, PGM_PAGE_GET_HCPHYS(pPageRemap));
1177 PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_MMIO2_ALIAS_MMIO);
1178 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ALLOCATED);
1179 PGM_PAGE_SET_PAGEID(pVM, pPage, PGM_PAGE_GET_PAGEID(pPageRemap));
1180 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
1181 pCur->cAliasedPages++;
1182 Assert(pCur->cAliasedPages <= pCur->cPages);
1183
1184 /* Flush its TLB entry. */
1185 pgmPhysInvalidatePageMapTLBEntry(pVM, GCPhysPage);
1186
1187 LogFlow(("PGMHandlerPhysicalPageAlias: => %R[pgmpage]\n", pPage));
1188 pgmUnlock(pVM);
1189 return VINF_SUCCESS;
1190 }
1191
1192 pgmUnlock(pVM);
1193 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n",
1194 GCPhysPage, pCur->Core.Key, pCur->Core.KeyLast));
1195 return VERR_INVALID_PARAMETER;
1196 }
1197
1198 pgmUnlock(pVM);
1199 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys));
1200 return VERR_PGM_HANDLER_NOT_FOUND;
1201}
1202
1203
1204/**
1205 * Replaces an MMIO page with an arbitrary HC page in the shadow page tables.
1206 *
1207 * This differs from PGMHandlerPhysicalPageAlias in that the page doesn't need
1208 * to be a known MMIO2 page and that only shadow paging may access the page.
1209 * The latter distinction is important because the only use for this feature is
1210 * for mapping the special APIC access page that VT-x uses to detect APIC MMIO
1211 * operations, the page is shared between all guest CPUs and actually not
1212 * written to. At least at the moment.
1213 *
1214 * The caller must do required page table modifications. You can get away
1215 * without making any modifications since it's an MMIO page, the cost is an extra
1216 * \#PF which will the resync the page.
1217 *
1218 * Call PGMHandlerPhysicalReset() to restore the MMIO page.
1219 *
1220 *
1221 * @returns VBox status code.
1222 * @param pVM The cross context VM structure.
1223 * @param GCPhys The start address of the access handler. This
1224 * must be a fully page aligned range or we risk
1225 * messing up other handlers installed for the
1226 * start and end pages.
1227 * @param GCPhysPage The physical address of the page to turn off
1228 * access monitoring for.
1229 * @param HCPhysPageRemap The physical address of the HC page that
1230 * serves as backing memory.
1231 *
1232 * @remark May cause a page pool flush if used on a page that is already
1233 * aliased.
1234 */
1235VMMDECL(int) PGMHandlerPhysicalPageAliasHC(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTHCPHYS HCPhysPageRemap)
1236{
1237/// Assert(!IOMIsLockOwner(pVM)); /* We mustn't own any other locks when calling this */
1238 pgmLock(pVM);
1239
1240 /*
1241 * Lookup and validate the range.
1242 */
1243 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
1244 if (RT_LIKELY(pCur))
1245 {
1246 if (RT_LIKELY( GCPhysPage >= pCur->Core.Key
1247 && GCPhysPage <= pCur->Core.KeyLast))
1248 {
1249 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
1250 AssertReturnStmt(pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO, pgmUnlock(pVM), VERR_ACCESS_DENIED);
1251 AssertReturnStmt(!(pCur->Core.Key & PAGE_OFFSET_MASK), pgmUnlock(pVM), VERR_INVALID_PARAMETER);
1252 AssertReturnStmt((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK, pgmUnlock(pVM), VERR_INVALID_PARAMETER);
1253
1254 /*
1255 * Get and validate the pages.
1256 */
1257 PPGMPAGE pPage;
1258 int rc = pgmPhysGetPageEx(pVM, GCPhysPage, &pPage);
1259 AssertReturnStmt(RT_SUCCESS_NP(rc), pgmUnlock(pVM), rc);
1260 if (PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO)
1261 {
1262 pgmUnlock(pVM);
1263 AssertMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO,
1264 ("GCPhysPage=%RGp %R[pgmpage]\n", GCPhysPage, pPage),
1265 VERR_PGM_PHYS_NOT_MMIO2);
1266 return VINF_PGM_HANDLER_ALREADY_ALIASED;
1267 }
1268 Assert(PGM_PAGE_IS_ZERO(pPage));
1269
1270 /*
1271 * Do the actual remapping here.
1272 * This page now serves as an alias for the backing memory
1273 * specified as far as shadow paging is concerned.
1274 */
1275 LogFlow(("PGMHandlerPhysicalPageAlias: %RGp (%R[pgmpage]) alias for %RHp\n",
1276 GCPhysPage, pPage, HCPhysPageRemap));
1277 PGM_PAGE_SET_HCPHYS(pVM, pPage, HCPhysPageRemap);
1278 PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_SPECIAL_ALIAS_MMIO);
1279 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ALLOCATED);
1280 PGM_PAGE_SET_PAGEID(pVM, pPage, NIL_GMM_PAGEID);
1281 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
1282 pCur->cAliasedPages++;
1283 Assert(pCur->cAliasedPages <= pCur->cPages);
1284
1285 /* Flush its TLB entry. */
1286 pgmPhysInvalidatePageMapTLBEntry(pVM, GCPhysPage);
1287
1288 LogFlow(("PGMHandlerPhysicalPageAliasHC: => %R[pgmpage]\n", pPage));
1289 pgmUnlock(pVM);
1290 return VINF_SUCCESS;
1291 }
1292 pgmUnlock(pVM);
1293 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n",
1294 GCPhysPage, pCur->Core.Key, pCur->Core.KeyLast));
1295 return VERR_INVALID_PARAMETER;
1296 }
1297 pgmUnlock(pVM);
1298
1299 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys));
1300 return VERR_PGM_HANDLER_NOT_FOUND;
1301}
1302
1303#endif /* !IEM_VERIFICATION_MODE_FULL */
1304
1305/**
1306 * Checks if a physical range is handled
1307 *
1308 * @returns boolean
1309 * @param pVM The cross context VM structure.
1310 * @param GCPhys Start physical address earlier passed to PGMR3HandlerPhysicalRegister().
1311 * @remarks Caller must take the PGM lock...
1312 * @thread EMT.
1313 */
1314VMMDECL(bool) PGMHandlerPhysicalIsRegistered(PVM pVM, RTGCPHYS GCPhys)
1315{
1316 /*
1317 * Find the handler.
1318 */
1319 pgmLock(pVM);
1320 PPGMPHYSHANDLER pCur = pgmHandlerPhysicalLookup(pVM, GCPhys);
1321 if (pCur)
1322 {
1323#ifdef VBOX_STRICT
1324 Assert(GCPhys >= pCur->Core.Key && GCPhys <= pCur->Core.KeyLast);
1325 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
1326 Assert( pCurType->enmKind == PGMPHYSHANDLERKIND_WRITE
1327 || pCurType->enmKind == PGMPHYSHANDLERKIND_ALL
1328 || pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO);
1329#endif
1330 pgmUnlock(pVM);
1331 return true;
1332 }
1333 pgmUnlock(pVM);
1334 return false;
1335}
1336
1337
1338/**
1339 * Checks if it's an disabled all access handler or write access handler at the
1340 * given address.
1341 *
1342 * @returns true if it's an all access handler, false if it's a write access
1343 * handler.
1344 * @param pVM The cross context VM structure.
1345 * @param GCPhys The address of the page with a disabled handler.
1346 *
1347 * @remarks The caller, PGMR3PhysTlbGCPhys2Ptr, must hold the PGM lock.
1348 */
1349bool pgmHandlerPhysicalIsAll(PVM pVM, RTGCPHYS GCPhys)
1350{
1351 pgmLock(pVM);
1352 PPGMPHYSHANDLER pCur = pgmHandlerPhysicalLookup(pVM, GCPhys);
1353 if (!pCur)
1354 {
1355 pgmUnlock(pVM);
1356 AssertFailed();
1357 return true;
1358 }
1359 PPGMPHYSHANDLERTYPEINT pCurType = PGMPHYSHANDLER_GET_TYPE(pVM, pCur);
1360 Assert( pCurType->enmKind == PGMPHYSHANDLERKIND_WRITE
1361 || pCurType->enmKind == PGMPHYSHANDLERKIND_ALL
1362 || pCurType->enmKind == PGMPHYSHANDLERKIND_MMIO); /* sanity */
1363 /* Only whole pages can be disabled. */
1364 Assert( pCur->Core.Key <= (GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK)
1365 && pCur->Core.KeyLast >= (GCPhys | PAGE_OFFSET_MASK));
1366
1367 bool bRet = pCurType->enmKind != PGMPHYSHANDLERKIND_WRITE;
1368 pgmUnlock(pVM);
1369 return bRet;
1370}
1371
1372
1373#ifdef VBOX_WITH_RAW_MODE
1374
1375/**
1376 * Internal worker for releasing a virtual handler type registration reference.
1377 *
1378 * @returns New reference count. UINT32_MAX if invalid input (asserted).
1379 * @param pVM The cross context VM structure.
1380 * @param pType Pointer to the type registration.
1381 */
1382DECLINLINE(uint32_t) pgmHandlerVirtualTypeRelease(PVM pVM, PPGMVIRTHANDLERTYPEINT pType)
1383{
1384 AssertMsgReturn(pType->u32Magic == PGMVIRTHANDLERTYPEINT_MAGIC, ("%#x\n", pType->u32Magic), UINT32_MAX);
1385 uint32_t cRefs = ASMAtomicDecU32(&pType->cRefs);
1386 if (cRefs == 0)
1387 {
1388 pgmLock(pVM);
1389 pType->u32Magic = PGMVIRTHANDLERTYPEINT_MAGIC_DEAD;
1390 RTListOff32NodeRemove(&pType->ListNode);
1391 pgmUnlock(pVM);
1392 MMHyperFree(pVM, pType);
1393 }
1394 return cRefs;
1395}
1396
1397
1398/**
1399 * Internal worker for retaining a virtual handler type registration reference.
1400 *
1401 * @returns New reference count. UINT32_MAX if invalid input (asserted).
1402 * @param pVM The cross context VM structure.
1403 * @param pType Pointer to the type registration.
1404 */
1405DECLINLINE(uint32_t) pgmHandlerVirtualTypeRetain(PVM pVM, PPGMVIRTHANDLERTYPEINT pType)
1406{
1407 NOREF(pVM);
1408 AssertMsgReturn(pType->u32Magic == PGMVIRTHANDLERTYPEINT_MAGIC, ("%#x\n", pType->u32Magic), UINT32_MAX);
1409 uint32_t cRefs = ASMAtomicIncU32(&pType->cRefs);
1410 Assert(cRefs < _1M && cRefs > 0);
1411 return cRefs;
1412}
1413
1414
1415/**
1416 * Releases a reference to a virtual handler type registration.
1417 *
1418 * @returns New reference count. UINT32_MAX if invalid input (asserted).
1419 * @param pVM The cross context VM structure.
1420 * @param hType The type regiration handle.
1421 */
1422VMM_INT_DECL(uint32_t) PGMHandlerVirtualTypeRelease(PVM pVM, PGMVIRTHANDLERTYPE hType)
1423{
1424 if (hType != NIL_PGMVIRTHANDLERTYPE)
1425 return pgmHandlerVirtualTypeRelease(pVM, PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hType));
1426 return 0;
1427}
1428
1429
1430/**
1431 * Retains a reference to a virtual handler type registration.
1432 *
1433 * @returns New reference count. UINT32_MAX if invalid input (asserted).
1434 * @param pVM The cross context VM structure.
1435 * @param hType The type regiration handle.
1436 */
1437VMM_INT_DECL(uint32_t) PGMHandlerVirtualTypeRetain(PVM pVM, PGMVIRTHANDLERTYPE hType)
1438{
1439 return pgmHandlerVirtualTypeRetain(pVM, PGMVIRTHANDLERTYPEINT_FROM_HANDLE(pVM, hType));
1440}
1441
1442
1443/**
1444 * Check if particular guest's VA is being monitored.
1445 *
1446 * @returns true or false
1447 * @param pVM The cross context VM structure.
1448 * @param GCPtr Virtual address.
1449 * @remarks Will acquire the PGM lock.
1450 * @thread Any.
1451 */
1452VMM_INT_DECL(bool) PGMHandlerVirtualIsRegistered(PVM pVM, RTGCPTR GCPtr)
1453{
1454 pgmLock(pVM);
1455 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtr);
1456 pgmUnlock(pVM);
1457
1458 return pCur != NULL;
1459}
1460
1461
1462/**
1463 * Search for virtual handler with matching physical address
1464 *
1465 * @returns Pointer to the virtual handler structure if found, otherwise NULL.
1466 * @param pVM The cross context VM structure.
1467 * @param GCPhys GC physical address to search for.
1468 * @param piPage Where to store the pointer to the index of the cached physical page.
1469 */
1470PPGMVIRTHANDLER pgmHandlerVirtualFindByPhysAddr(PVM pVM, RTGCPHYS GCPhys, unsigned *piPage)
1471{
1472 STAM_PROFILE_START(&pVM->pgm.s.CTX_MID_Z(Stat,VirtHandlerSearchByPhys), a);
1473
1474 pgmLock(pVM);
1475 PPGMPHYS2VIRTHANDLER pCur;
1476 pCur = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, GCPhys);
1477 if (pCur)
1478 {
1479 /* found a match! */
1480 PPGMVIRTHANDLER pVirt = (PPGMVIRTHANDLER)((uintptr_t)pCur + pCur->offVirtHandler);
1481 *piPage = pCur - &pVirt->aPhysToVirt[0];
1482 pgmUnlock(pVM);
1483
1484#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1485 AssertRelease(pCur->offNextAlias & PGMPHYS2VIRTHANDLER_IS_HEAD);
1486#endif
1487 LogFlow(("PHYS2VIRT: found match for %RGp -> %RGv *piPage=%#x\n", GCPhys, pVirt->Core.Key, *piPage));
1488 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,VirtHandlerSearchByPhys), a);
1489 return pVirt;
1490 }
1491
1492 pgmUnlock(pVM);
1493 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,VirtHandlerSearchByPhys), a);
1494 return NULL;
1495}
1496
1497
1498/**
1499 * Deal with aliases in phys2virt.
1500 *
1501 * As pointed out by the various todos, this currently only deals with
1502 * aliases where the two ranges match 100%.
1503 *
1504 * @param pVM The cross context VM structure.
1505 * @param pPhys2Virt The node we failed insert.
1506 */
1507static void pgmHandlerVirtualInsertAliased(PVM pVM, PPGMPHYS2VIRTHANDLER pPhys2Virt)
1508{
1509 /*
1510 * First find the node which is conflicting with us.
1511 */
1512 /** @todo Deal with partial overlapping. (Unlikely situation, so I'm too lazy to do anything about it now.) */
1513 /** @todo check if the current head node covers the ground we do. This is highly unlikely
1514 * and I'm too lazy to implement this now as it will require sorting the list and stuff like that. */
1515 PPGMPHYS2VIRTHANDLER pHead = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key);
1516#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1517 AssertReleaseMsg(pHead != pPhys2Virt, ("%RGp-%RGp offVirtHandler=%#RX32\n",
1518 pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offVirtHandler));
1519#endif
1520 if (RT_UNLIKELY(!pHead || pHead->Core.KeyLast != pPhys2Virt->Core.KeyLast))
1521 {
1522 /** @todo do something clever here... */
1523 LogRel(("pgmHandlerVirtualInsertAliased: %RGp-%RGp\n", pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast));
1524 pPhys2Virt->offNextAlias = 0;
1525 return;
1526 }
1527
1528 /*
1529 * Insert ourselves as the next node.
1530 */
1531 if (!(pHead->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK))
1532 pPhys2Virt->offNextAlias = PGMPHYS2VIRTHANDLER_IN_TREE;
1533 else
1534 {
1535 PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pHead + (pHead->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
1536 pPhys2Virt->offNextAlias = ((intptr_t)pNext - (intptr_t)pPhys2Virt)
1537 | PGMPHYS2VIRTHANDLER_IN_TREE;
1538 }
1539 pHead->offNextAlias = ((intptr_t)pPhys2Virt - (intptr_t)pHead)
1540 | (pHead->offNextAlias & ~PGMPHYS2VIRTHANDLER_OFF_MASK);
1541 Log(("pgmHandlerVirtualInsertAliased: %RGp-%RGp offNextAlias=%#RX32\n", pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias));
1542}
1543
1544
1545/**
1546 * Resets one virtual handler range.
1547 *
1548 * This is called by HandlerVirtualUpdate when it has detected some kind of
1549 * problem and have started clearing the virtual handler page states (or
1550 * when there have been registration/deregistrations). For this reason this
1551 * function will only update the page status if it's lower than desired.
1552 *
1553 * @returns 0
1554 * @param pNode Pointer to a PGMVIRTHANDLER.
1555 * @param pvUser Pointer to the VM.
1556 */
1557DECLCALLBACK(int) pgmHandlerVirtualResetOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
1558{
1559 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
1560 PVM pVM = (PVM)pvUser;
1561
1562 PGM_LOCK_ASSERT_OWNER(pVM);
1563
1564 /*
1565 * Iterate the pages and apply the new state.
1566 */
1567 uint32_t uState = PGMVIRTANDLER_GET_TYPE(pVM, pCur)->uState;
1568 PPGMRAMRANGE pRamHint = NULL;
1569 RTGCUINTPTR offPage = ((RTGCUINTPTR)pCur->Core.Key & PAGE_OFFSET_MASK);
1570 RTGCUINTPTR cbLeft = pCur->cb;
1571 for (unsigned iPage = 0; iPage < pCur->cPages; iPage++)
1572 {
1573 PPGMPHYS2VIRTHANDLER pPhys2Virt = &pCur->aPhysToVirt[iPage];
1574 if (pPhys2Virt->Core.Key != NIL_RTGCPHYS)
1575 {
1576 /*
1577 * Update the page state wrt virtual handlers.
1578 */
1579 PPGMPAGE pPage;
1580 int rc = pgmPhysGetPageWithHintEx(pVM, pPhys2Virt->Core.Key, &pPage, &pRamHint);
1581 if ( RT_SUCCESS(rc)
1582 && PGM_PAGE_GET_HNDL_VIRT_STATE(pPage) < uState)
1583 PGM_PAGE_SET_HNDL_VIRT_STATE(pPage, uState);
1584 else
1585 AssertRC(rc);
1586
1587 /*
1588 * Need to insert the page in the Phys2Virt lookup tree?
1589 */
1590 if (pPhys2Virt->Core.KeyLast == NIL_RTGCPHYS)
1591 {
1592#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1593 AssertRelease(!pPhys2Virt->offNextAlias);
1594#endif
1595 unsigned cbPhys = cbLeft;
1596 if (cbPhys > PAGE_SIZE - offPage)
1597 cbPhys = PAGE_SIZE - offPage;
1598 else
1599 Assert(iPage == pCur->cPages - 1);
1600 pPhys2Virt->Core.KeyLast = pPhys2Virt->Core.Key + cbPhys - 1; /* inclusive */
1601 pPhys2Virt->offNextAlias = PGMPHYS2VIRTHANDLER_IS_HEAD | PGMPHYS2VIRTHANDLER_IN_TREE;
1602 if (!RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, &pPhys2Virt->Core))
1603 pgmHandlerVirtualInsertAliased(pVM, pPhys2Virt);
1604#ifdef VBOX_STRICT_PGM_HANDLER_VIRTUAL
1605 else
1606 AssertReleaseMsg(RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key) == &pPhys2Virt->Core,
1607 ("%RGp-%RGp offNextAlias=%#RX32\n",
1608 pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias));
1609#endif
1610 Log2(("PHYS2VIRT: Insert physical range %RGp-%RGp offNextAlias=%#RX32 %s\n",
1611 pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias, R3STRING(pCur->pszDesc)));
1612 }
1613 }
1614 cbLeft -= PAGE_SIZE - offPage;
1615 offPage = 0;
1616 }
1617
1618 return 0;
1619}
1620
1621# if defined(VBOX_STRICT) || defined(LOG_ENABLED)
1622
1623/**
1624 * Worker for pgmHandlerVirtualDumpPhysPages.
1625 *
1626 * @returns 0 (continue enumeration).
1627 * @param pNode The virtual handler node.
1628 * @param pvUser User argument, unused.
1629 */
1630static DECLCALLBACK(int) pgmHandlerVirtualDumpPhysPagesCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser)
1631{
1632 PPGMPHYS2VIRTHANDLER pCur = (PPGMPHYS2VIRTHANDLER)pNode;
1633 PPGMVIRTHANDLER pVirt = (PPGMVIRTHANDLER)((uintptr_t)pCur + pCur->offVirtHandler);
1634 NOREF(pvUser); NOREF(pVirt);
1635
1636 Log(("PHYS2VIRT: Range %RGp-%RGp for virtual handler: %s\n", pCur->Core.Key, pCur->Core.KeyLast, pVirt->pszDesc));
1637 return 0;
1638}
1639
1640
1641/**
1642 * Assertion / logging helper for dumping all the
1643 * virtual handlers to the log.
1644 *
1645 * @param pVM The cross context VM structure.
1646 */
1647void pgmHandlerVirtualDumpPhysPages(PVM pVM)
1648{
1649 RTAvlroGCPhysDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, true /* from left */,
1650 pgmHandlerVirtualDumpPhysPagesCallback, 0);
1651}
1652
1653# endif /* VBOX_STRICT || LOG_ENABLED */
1654#endif /* VBOX_WITH_RAW_MODE */
1655#ifdef VBOX_STRICT
1656
1657/**
1658 * State structure used by the PGMAssertHandlerAndFlagsInSync() function
1659 * and its AVL enumerators.
1660 */
1661typedef struct PGMAHAFIS
1662{
1663 /** The current physical address. */
1664 RTGCPHYS GCPhys;
1665 /** The state we've calculated. */
1666 unsigned uVirtStateFound;
1667 /** The state we're matching up to. */
1668 unsigned uVirtState;
1669 /** Number of errors. */
1670 unsigned cErrors;
1671 /** Pointer to the VM. */
1672 PVM pVM;
1673} PGMAHAFIS, *PPGMAHAFIS;
1674
1675# ifdef VBOX_WITH_RAW_MODE
1676
1677# if 0 /* unused */
1678/**
1679 * Verify virtual handler by matching physical address.
1680 *
1681 * @returns 0
1682 * @param pNode Pointer to a PGMVIRTHANDLER.
1683 * @param pvUser Pointer to user parameter.
1684 */
1685static DECLCALLBACK(int) pgmHandlerVirtualVerifyOneByPhysAddr(PAVLROGCPTRNODECORE pNode, void *pvUser)
1686{
1687 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;
1688 PPGMAHAFIS pState = (PPGMAHAFIS)pvUser;
1689
1690 for (unsigned iPage = 0; iPage < pCur->cPages; iPage++)
1691 {
1692 if ((pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) == pState->GCPhys)
1693 {
1694 unsigned uState = pgmHandlerVirtualCalcState(pCur);
1695 if (pState->uVirtState < uState)
1696 {
1697 error
1698 }
1699
1700 if (pState->uVirtState == uState)
1701 break; //??
1702 }
1703 }
1704 return 0;
1705}
1706# endif /* unused */
1707
1708
1709/**
1710 * Verify a virtual handler (enumeration callback).
1711 *
1712 * Called by PGMAssertHandlerAndFlagsInSync to check the sanity of all
1713 * the virtual handlers, esp. that the physical addresses matches up.
1714 *
1715 * @returns 0
1716 * @param pNode Pointer to a PGMVIRTHANDLER.
1717 * @param pvUser Pointer to a PPGMAHAFIS structure.
1718 */
1719static DECLCALLBACK(int) pgmHandlerVirtualVerifyOne(PAVLROGCPTRNODECORE pNode, void *pvUser)
1720{
1721 PPGMAHAFIS pState = (PPGMAHAFIS)pvUser;
1722 PVM pVM = pState->pVM;
1723 PPGMVIRTHANDLER pVirt = (PPGMVIRTHANDLER)pNode;
1724 PPGMVIRTHANDLERTYPEINT pType = PGMVIRTANDLER_GET_TYPE(pVM, pVirt);
1725
1726 /*
1727 * Validate the type and calc state.
1728 */
1729 switch (pType->enmKind)
1730 {
1731 case PGMVIRTHANDLERKIND_WRITE:
1732 case PGMVIRTHANDLERKIND_ALL:
1733 break;
1734 default:
1735 AssertMsgFailed(("unknown/wrong enmKind=%d\n", pType->enmKind));
1736 pState->cErrors++;
1737 return 0;
1738 }
1739 const uint32_t uState = pType->uState;
1740
1741 /*
1742 * Check key alignment.
1743 */
1744 if ( (pVirt->aPhysToVirt[0].Core.Key & PAGE_OFFSET_MASK) != ((RTGCUINTPTR)pVirt->Core.Key & PAGE_OFFSET_MASK)
1745 && pVirt->aPhysToVirt[0].Core.Key != NIL_RTGCPHYS)
1746 {
1747 AssertMsgFailed(("virt handler phys has incorrect key! %RGp %RGv %s\n",
1748 pVirt->aPhysToVirt[0].Core.Key, pVirt->Core.Key, R3STRING(pVirt->pszDesc)));
1749 pState->cErrors++;
1750 }
1751
1752 if ( (pVirt->aPhysToVirt[pVirt->cPages - 1].Core.KeyLast & PAGE_OFFSET_MASK) != ((RTGCUINTPTR)pVirt->Core.KeyLast & PAGE_OFFSET_MASK)
1753 && pVirt->aPhysToVirt[pVirt->cPages - 1].Core.Key != NIL_RTGCPHYS)
1754 {
1755 AssertMsgFailed(("virt handler phys has incorrect key! %RGp %RGv %s\n",
1756 pVirt->aPhysToVirt[pVirt->cPages - 1].Core.KeyLast, pVirt->Core.KeyLast, R3STRING(pVirt->pszDesc)));
1757 pState->cErrors++;
1758 }
1759
1760 /*
1761 * Check pages for sanity and state.
1762 */
1763 RTGCUINTPTR GCPtr = (RTGCUINTPTR)pVirt->Core.Key;
1764 for (unsigned iPage = 0; iPage < pVirt->cPages; iPage++, GCPtr += PAGE_SIZE)
1765 {
1766 for (VMCPUID i = 0; i < pVM->cCpus; i++)
1767 {
1768 PVMCPU pVCpu = &pVM->aCpus[i];
1769
1770 RTGCPHYS GCPhysGst;
1771 uint64_t fGst;
1772 int rc = PGMGstGetPage(pVCpu, (RTGCPTR)GCPtr, &fGst, &GCPhysGst);
1773 if ( rc == VERR_PAGE_NOT_PRESENT
1774 || rc == VERR_PAGE_TABLE_NOT_PRESENT)
1775 {
1776 if (pVirt->aPhysToVirt[iPage].Core.Key != NIL_RTGCPHYS)
1777 {
1778 AssertMsgFailed(("virt handler phys out of sync. %RGp GCPhysNew=~0 iPage=%#x %RGv %s\n",
1779 pVirt->aPhysToVirt[iPage].Core.Key, iPage, GCPtr, R3STRING(pVirt->pszDesc)));
1780 pState->cErrors++;
1781 }
1782 continue;
1783 }
1784
1785 AssertRCReturn(rc, 0);
1786 if ((pVirt->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) != GCPhysGst)
1787 {
1788 AssertMsgFailed(("virt handler phys out of sync. %RGp GCPhysGst=%RGp iPage=%#x %RGv %s\n",
1789 pVirt->aPhysToVirt[iPage].Core.Key, GCPhysGst, iPage, GCPtr, R3STRING(pVirt->pszDesc)));
1790 pState->cErrors++;
1791 continue;
1792 }
1793
1794 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhysGst);
1795 if (!pPage)
1796 {
1797 AssertMsgFailed(("virt handler getting ram flags. GCPhysGst=%RGp iPage=%#x %RGv %s\n",
1798 GCPhysGst, iPage, GCPtr, R3STRING(pVirt->pszDesc)));
1799 pState->cErrors++;
1800 continue;
1801 }
1802
1803 if (PGM_PAGE_GET_HNDL_VIRT_STATE(pPage) < uState)
1804 {
1805 AssertMsgFailed(("virt handler state mismatch. pPage=%R[pgmpage] GCPhysGst=%RGp iPage=%#x %RGv state=%d expected>=%d %s\n",
1806 pPage, GCPhysGst, iPage, GCPtr, PGM_PAGE_GET_HNDL_VIRT_STATE(pPage), uState, R3STRING(pVirt->pszDesc)));
1807 pState->cErrors++;
1808 continue;
1809 }
1810 } /* for each VCPU */
1811 } /* for pages in virtual mapping. */
1812
1813 return 0;
1814}
1815
1816# endif /* VBOX_WITH_RAW_MODE */
1817
1818/**
1819 * Asserts that the handlers+guest-page-tables == ramrange-flags and
1820 * that the physical addresses associated with virtual handlers are correct.
1821 *
1822 * @returns Number of mismatches.
1823 * @param pVM The cross context VM structure.
1824 */
1825VMMDECL(unsigned) PGMAssertHandlerAndFlagsInSync(PVM pVM)
1826{
1827 PPGM pPGM = &pVM->pgm.s;
1828 PGMAHAFIS State;
1829 State.GCPhys = 0;
1830 State.uVirtState = 0;
1831 State.uVirtStateFound = 0;
1832 State.cErrors = 0;
1833 State.pVM = pVM;
1834
1835 PGM_LOCK_ASSERT_OWNER(pVM);
1836
1837 /*
1838 * Check the RAM flags against the handlers.
1839 */
1840 for (PPGMRAMRANGE pRam = pPGM->CTX_SUFF(pRamRangesX); pRam; pRam = pRam->CTX_SUFF(pNext))
1841 {
1842 const uint32_t cPages = pRam->cb >> PAGE_SHIFT;
1843 for (uint32_t iPage = 0; iPage < cPages; iPage++)
1844 {
1845 PGMPAGE const *pPage = &pRam->aPages[iPage];
1846 if (PGM_PAGE_HAS_ANY_HANDLERS(pPage))
1847 {
1848 State.GCPhys = pRam->GCPhys + (iPage << PAGE_SHIFT);
1849
1850 /*
1851 * Physical first - calculate the state based on the handlers
1852 * active on the page, then compare.
1853 */
1854 if (PGM_PAGE_HAS_ANY_PHYSICAL_HANDLERS(pPage))
1855 {
1856 /* the first */
1857 PPGMPHYSHANDLER pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pPGM->CTX_SUFF(pTrees)->PhysHandlers, State.GCPhys);
1858 if (!pPhys)
1859 {
1860 pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTX_SUFF(pTrees)->PhysHandlers, State.GCPhys, true);
1861 if ( pPhys
1862 && pPhys->Core.Key > (State.GCPhys + PAGE_SIZE - 1))
1863 pPhys = NULL;
1864 Assert(!pPhys || pPhys->Core.Key >= State.GCPhys);
1865 }
1866 if (pPhys)
1867 {
1868 PPGMPHYSHANDLERTYPEINT pPhysType = (PPGMPHYSHANDLERTYPEINT)MMHyperHeapOffsetToPtr(pVM, pPhys->hType);
1869 unsigned uState = pPhysType->uState;
1870
1871 /* more? */
1872 while (pPhys->Core.KeyLast < (State.GCPhys | PAGE_OFFSET_MASK))
1873 {
1874 PPGMPHYSHANDLER pPhys2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTX_SUFF(pTrees)->PhysHandlers,
1875 pPhys->Core.KeyLast + 1, true);
1876 if ( !pPhys2
1877 || pPhys2->Core.Key > (State.GCPhys | PAGE_OFFSET_MASK))
1878 break;
1879 PPGMPHYSHANDLERTYPEINT pPhysType2 = (PPGMPHYSHANDLERTYPEINT)MMHyperHeapOffsetToPtr(pVM, pPhys2->hType);
1880 uState = RT_MAX(uState, pPhysType2->uState);
1881 pPhys = pPhys2;
1882 }
1883
1884 /* compare.*/
1885 if ( PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != uState
1886 && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
1887 {
1888 AssertMsgFailed(("ram range vs phys handler flags mismatch. GCPhys=%RGp state=%d expected=%d %s\n",
1889 State.GCPhys, PGM_PAGE_GET_HNDL_PHYS_STATE(pPage), uState, pPhysType->pszDesc));
1890 State.cErrors++;
1891 }
1892
1893# ifdef VBOX_WITH_REM
1894# ifdef IN_RING3
1895 /* validate that REM is handling it. */
1896 if ( !REMR3IsPageAccessHandled(pVM, State.GCPhys)
1897 /* ignore shadowed ROM for the time being. */
1898 && PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_ROM_SHADOW)
1899 {
1900 AssertMsgFailed(("ram range vs phys handler REM mismatch. GCPhys=%RGp state=%d %s\n",
1901 State.GCPhys, PGM_PAGE_GET_HNDL_PHYS_STATE(pPage), pPhysType->pszDesc));
1902 State.cErrors++;
1903 }
1904# endif
1905# endif
1906 }
1907 else
1908 {
1909 AssertMsgFailed(("ram range vs phys handler mismatch. no handler for GCPhys=%RGp\n", State.GCPhys));
1910 State.cErrors++;
1911 }
1912 }
1913
1914 /*
1915 * Virtual handlers.
1916 */
1917 if (PGM_PAGE_HAS_ACTIVE_VIRTUAL_HANDLERS(pPage))
1918 {
1919 State.uVirtState = PGM_PAGE_GET_HNDL_VIRT_STATE(pPage);
1920
1921 /* locate all the matching physical ranges. */
1922 State.uVirtStateFound = PGM_PAGE_HNDL_VIRT_STATE_NONE;
1923# ifdef VBOX_WITH_RAW_MODE
1924 RTGCPHYS GCPhysKey = State.GCPhys;
1925 for (;;)
1926 {
1927 PPGMPHYS2VIRTHANDLER pPhys2Virt = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGetBestFit(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers,
1928 GCPhysKey, true /* above-or-equal */);
1929 if ( !pPhys2Virt
1930 || (pPhys2Virt->Core.Key & X86_PTE_PAE_PG_MASK) != State.GCPhys)
1931 break;
1932
1933 /* the head */
1934 GCPhysKey = pPhys2Virt->Core.KeyLast;
1935 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)((uintptr_t)pPhys2Virt + pPhys2Virt->offVirtHandler);
1936 unsigned uState = PGMVIRTANDLER_GET_TYPE(pVM, pCur)->uState;
1937 State.uVirtStateFound = RT_MAX(State.uVirtStateFound, uState);
1938
1939 /* any aliases */
1940 while (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK)
1941 {
1942 pPhys2Virt = (PPGMPHYS2VIRTHANDLER)((uintptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
1943 pCur = (PPGMVIRTHANDLER)((uintptr_t)pPhys2Virt + pPhys2Virt->offVirtHandler);
1944 uState = PGMVIRTANDLER_GET_TYPE(pVM, pCur)->uState;
1945 State.uVirtStateFound = RT_MAX(State.uVirtStateFound, uState);
1946 }
1947
1948 /* done? */
1949 if ((GCPhysKey & X86_PTE_PAE_PG_MASK) != State.GCPhys)
1950 break;
1951 }
1952# endif /* VBOX_WITH_RAW_MODE */
1953 if (State.uVirtState != State.uVirtStateFound)
1954 {
1955 AssertMsgFailed(("ram range vs virt handler flags mismatch. GCPhys=%RGp uVirtState=%#x uVirtStateFound=%#x\n",
1956 State.GCPhys, State.uVirtState, State.uVirtStateFound));
1957 State.cErrors++;
1958 }
1959 }
1960 }
1961 } /* foreach page in ram range. */
1962 } /* foreach ram range. */
1963
1964# ifdef VBOX_WITH_RAW_MODE
1965 /*
1966 * Check that the physical addresses of the virtual handlers matches up
1967 * and that they are otherwise sane.
1968 */
1969 RTAvlroGCPtrDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, true, pgmHandlerVirtualVerifyOne, &State);
1970# endif
1971
1972 /*
1973 * Do the reverse check for physical handlers.
1974 */
1975 /** @todo */
1976
1977 return State.cErrors;
1978}
1979
1980#endif /* VBOX_STRICT */
1981
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