VirtualBox

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

Last change on this file since 70898 was 69111, checked in by vboxsync, 7 years ago

(C) year

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