VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PGMPhys.cpp@ 106590

Last change on this file since 106590 was 106590, checked in by vboxsync, 4 weeks ago

VMM/PGMPhys.cpp: Missing #ifdef VBOX_WITH_NATIVE_NEM around some NEM specific cleanup code that is unreachable if native NEM isn't enabled (VC 2022/arm complaint). jiraref:VBP-1171

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 248.8 KB
Line 
1/* $Id: PGMPhys.cpp 106590 2024-10-22 23:56:49Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor, Physical Memory Addressing.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_PGM_PHYS
33#define VBOX_WITHOUT_PAGING_BIT_FIELDS /* 64-bit bitfields are just asking for trouble. See @bugref{9841} and others. */
34#include <VBox/vmm/pgm.h>
35#include <VBox/vmm/iem.h>
36#include <VBox/vmm/iom.h>
37#include <VBox/vmm/mm.h>
38#include <VBox/vmm/nem.h>
39#include <VBox/vmm/stam.h>
40#include <VBox/vmm/pdmdev.h>
41#include "PGMInternal.h"
42#include <VBox/vmm/vmcc.h>
43
44#include "PGMInline.h"
45
46#include <VBox/sup.h>
47#include <VBox/param.h>
48#include <VBox/err.h>
49#include <VBox/log.h>
50#include <iprt/assert.h>
51#include <iprt/alloc.h>
52#include <iprt/asm.h>
53#ifdef VBOX_STRICT
54# include <iprt/crc.h>
55#endif
56#include <iprt/thread.h>
57#include <iprt/string.h>
58#include <iprt/system.h>
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64/** The number of pages to free in one batch. */
65#define PGMPHYS_FREE_PAGE_BATCH_SIZE 128
66
67
68
69/*********************************************************************************************************************************
70* Reading and Writing Guest Pysical Memory *
71*********************************************************************************************************************************/
72
73/*
74 * PGMR3PhysReadU8-64
75 * PGMR3PhysWriteU8-64
76 */
77#define PGMPHYSFN_READNAME PGMR3PhysReadU8
78#define PGMPHYSFN_WRITENAME PGMR3PhysWriteU8
79#define PGMPHYS_DATASIZE 1
80#define PGMPHYS_DATATYPE uint8_t
81#include "PGMPhysRWTmpl.h"
82
83#define PGMPHYSFN_READNAME PGMR3PhysReadU16
84#define PGMPHYSFN_WRITENAME PGMR3PhysWriteU16
85#define PGMPHYS_DATASIZE 2
86#define PGMPHYS_DATATYPE uint16_t
87#include "PGMPhysRWTmpl.h"
88
89#define PGMPHYSFN_READNAME PGMR3PhysReadU32
90#define PGMPHYSFN_WRITENAME PGMR3PhysWriteU32
91#define PGMPHYS_DATASIZE 4
92#define PGMPHYS_DATATYPE uint32_t
93#include "PGMPhysRWTmpl.h"
94
95#define PGMPHYSFN_READNAME PGMR3PhysReadU64
96#define PGMPHYSFN_WRITENAME PGMR3PhysWriteU64
97#define PGMPHYS_DATASIZE 8
98#define PGMPHYS_DATATYPE uint64_t
99#include "PGMPhysRWTmpl.h"
100
101
102/**
103 * EMT worker for PGMR3PhysReadExternal.
104 */
105static DECLCALLBACK(int) pgmR3PhysReadExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, void *pvBuf, size_t cbRead,
106 PGMACCESSORIGIN enmOrigin)
107{
108 VBOXSTRICTRC rcStrict = PGMPhysRead(pVM, *pGCPhys, pvBuf, cbRead, enmOrigin);
109 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); NOREF(rcStrict);
110 return VINF_SUCCESS;
111}
112
113
114/**
115 * Read from physical memory, external users.
116 *
117 * @returns VBox status code.
118 * @retval VINF_SUCCESS.
119 *
120 * @param pVM The cross context VM structure.
121 * @param GCPhys Physical address to read from.
122 * @param pvBuf Where to read into.
123 * @param cbRead How many bytes to read.
124 * @param enmOrigin Who is calling.
125 *
126 * @thread Any but EMTs.
127 */
128VMMR3DECL(int) PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin)
129{
130 VM_ASSERT_OTHER_THREAD(pVM);
131
132 AssertMsgReturn(cbRead > 0, ("don't even think about reading zero bytes!\n"), VINF_SUCCESS);
133 LogFlow(("PGMR3PhysReadExternal: %RGp %d\n", GCPhys, cbRead));
134
135 PGM_LOCK_VOID(pVM);
136
137 /*
138 * Copy loop on ram ranges.
139 */
140 for (;;)
141 {
142 PPGMRAMRANGE pRam = pgmPhysGetRangeAtOrAbove(pVM, GCPhys);
143
144 /* Inside range or not? */
145 if (pRam && GCPhys >= pRam->GCPhys)
146 {
147 /*
148 * Must work our way thru this page by page.
149 */
150 RTGCPHYS off = GCPhys - pRam->GCPhys;
151 while (off < pRam->cb)
152 {
153 unsigned iPage = off >> GUEST_PAGE_SHIFT;
154 PPGMPAGE pPage = &pRam->aPages[iPage];
155
156 /*
157 * If the page has an ALL access handler, we'll have to
158 * delegate the job to EMT.
159 */
160 if ( PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)
161 || PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
162 {
163 PGM_UNLOCK(pVM);
164
165 return VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysReadExternalEMT, 5,
166 pVM, &GCPhys, pvBuf, cbRead, enmOrigin);
167 }
168 Assert(!PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage));
169
170 /*
171 * Simple stuff, go ahead.
172 */
173 size_t cb = GUEST_PAGE_SIZE - (off & GUEST_PAGE_OFFSET_MASK);
174 if (cb > cbRead)
175 cb = cbRead;
176 PGMPAGEMAPLOCK PgMpLck;
177 const void *pvSrc;
178 int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, pRam->GCPhys + off, &pvSrc, &PgMpLck);
179 if (RT_SUCCESS(rc))
180 {
181 memcpy(pvBuf, pvSrc, cb);
182 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
183 }
184 else
185 {
186 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
187 pRam->GCPhys + off, pPage, rc));
188 memset(pvBuf, 0xff, cb);
189 }
190
191 /* next page */
192 if (cb >= cbRead)
193 {
194 PGM_UNLOCK(pVM);
195 return VINF_SUCCESS;
196 }
197 cbRead -= cb;
198 off += cb;
199 GCPhys += cb;
200 pvBuf = (char *)pvBuf + cb;
201 } /* walk pages in ram range. */
202 }
203 else
204 {
205 LogFlow(("PGMPhysRead: Unassigned %RGp size=%u\n", GCPhys, cbRead));
206
207 /*
208 * Unassigned address space.
209 */
210 size_t cb = pRam ? pRam->GCPhys - GCPhys : ~(size_t)0;
211 if (cb >= cbRead)
212 {
213 memset(pvBuf, 0xff, cbRead);
214 break;
215 }
216 memset(pvBuf, 0xff, cb);
217
218 cbRead -= cb;
219 pvBuf = (char *)pvBuf + cb;
220 GCPhys += cb;
221 }
222 } /* Ram range walk */
223
224 PGM_UNLOCK(pVM);
225
226 return VINF_SUCCESS;
227}
228
229
230/**
231 * EMT worker for PGMR3PhysWriteExternal.
232 */
233static DECLCALLBACK(int) pgmR3PhysWriteExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, const void *pvBuf, size_t cbWrite,
234 PGMACCESSORIGIN enmOrigin)
235{
236 /** @todo VERR_EM_NO_MEMORY */
237 VBOXSTRICTRC rcStrict = PGMPhysWrite(pVM, *pGCPhys, pvBuf, cbWrite, enmOrigin);
238 AssertMsg(rcStrict == VINF_SUCCESS, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict))); NOREF(rcStrict);
239 return VINF_SUCCESS;
240}
241
242
243/**
244 * Write to physical memory, external users.
245 *
246 * @returns VBox status code.
247 * @retval VINF_SUCCESS.
248 * @retval VERR_EM_NO_MEMORY.
249 *
250 * @param pVM The cross context VM structure.
251 * @param GCPhys Physical address to write to.
252 * @param pvBuf What to write.
253 * @param cbWrite How many bytes to write.
254 * @param enmOrigin Who is calling.
255 *
256 * @thread Any but EMTs.
257 */
258VMMDECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin)
259{
260 VM_ASSERT_OTHER_THREAD(pVM);
261
262 AssertMsg(!pVM->pgm.s.fNoMorePhysWrites,
263 ("Calling PGMR3PhysWriteExternal after pgmR3Save()! GCPhys=%RGp cbWrite=%#x enmOrigin=%d\n",
264 GCPhys, cbWrite, enmOrigin));
265 AssertMsgReturn(cbWrite > 0, ("don't even think about writing zero bytes!\n"), VINF_SUCCESS);
266 LogFlow(("PGMR3PhysWriteExternal: %RGp %d\n", GCPhys, cbWrite));
267
268 PGM_LOCK_VOID(pVM);
269
270 /*
271 * Copy loop on ram ranges, stop when we hit something difficult.
272 */
273 for (;;)
274 {
275 PPGMRAMRANGE const pRam = pgmPhysGetRangeAtOrAbove(pVM, GCPhys);
276
277 /* Inside range or not? */
278 if (pRam && GCPhys >= pRam->GCPhys)
279 {
280 /*
281 * Must work our way thru this page by page.
282 */
283 RTGCPTR off = GCPhys - pRam->GCPhys;
284 while (off < pRam->cb)
285 {
286 RTGCPTR iPage = off >> GUEST_PAGE_SHIFT;
287 PPGMPAGE pPage = &pRam->aPages[iPage];
288
289 /*
290 * Is the page problematic, we have to do the work on the EMT.
291 *
292 * Allocating writable pages and access handlers are
293 * problematic, write monitored pages are simple and can be
294 * dealt with here.
295 */
296 if ( PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
297 || PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
298 || PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
299 {
300 if ( PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
301 && !PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
302 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, GCPhys);
303 else
304 {
305 PGM_UNLOCK(pVM);
306
307 return VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysWriteExternalEMT, 5,
308 pVM, &GCPhys, pvBuf, cbWrite, enmOrigin);
309 }
310 }
311 Assert(!PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage));
312
313 /*
314 * Simple stuff, go ahead.
315 */
316 size_t cb = GUEST_PAGE_SIZE - (off & GUEST_PAGE_OFFSET_MASK);
317 if (cb > cbWrite)
318 cb = cbWrite;
319 PGMPAGEMAPLOCK PgMpLck;
320 void *pvDst;
321 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pRam->GCPhys + off, &pvDst, &PgMpLck);
322 if (RT_SUCCESS(rc))
323 {
324 memcpy(pvDst, pvBuf, cb);
325 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
326 }
327 else
328 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
329 pRam->GCPhys + off, pPage, rc));
330
331 /* next page */
332 if (cb >= cbWrite)
333 {
334 PGM_UNLOCK(pVM);
335 return VINF_SUCCESS;
336 }
337
338 cbWrite -= cb;
339 off += cb;
340 GCPhys += cb;
341 pvBuf = (const char *)pvBuf + cb;
342 } /* walk pages in ram range */
343 }
344 else
345 {
346 /*
347 * Unassigned address space, skip it.
348 */
349 if (!pRam)
350 break;
351 size_t cb = pRam->GCPhys - GCPhys;
352 if (cb >= cbWrite)
353 break;
354 cbWrite -= cb;
355 pvBuf = (const char *)pvBuf + cb;
356 GCPhys += cb;
357 }
358 } /* Ram range walk */
359
360 PGM_UNLOCK(pVM);
361 return VINF_SUCCESS;
362}
363
364
365/*********************************************************************************************************************************
366* Mapping Guest Physical Memory *
367*********************************************************************************************************************************/
368
369/**
370 * VMR3ReqCall worker for PGMR3PhysGCPhys2CCPtrExternal to make pages writable.
371 *
372 * @returns see PGMR3PhysGCPhys2CCPtrExternal
373 * @param pVM The cross context VM structure.
374 * @param pGCPhys Pointer to the guest physical address.
375 * @param ppv Where to store the mapping address.
376 * @param pLock Where to store the lock.
377 */
378static DECLCALLBACK(int) pgmR3PhysGCPhys2CCPtrDelegated(PVM pVM, PRTGCPHYS pGCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
379{
380 /*
381 * Just hand it to PGMPhysGCPhys2CCPtr and check that it's not a page with
382 * an access handler after it succeeds.
383 */
384 int rc = PGM_LOCK(pVM);
385 AssertRCReturn(rc, rc);
386
387 rc = PGMPhysGCPhys2CCPtr(pVM, *pGCPhys, ppv, pLock);
388 if (RT_SUCCESS(rc))
389 {
390 PPGMPAGEMAPTLBE pTlbe;
391 int rc2 = pgmPhysPageQueryTlbe(pVM, *pGCPhys, &pTlbe);
392 AssertFatalRC(rc2);
393 PPGMPAGE pPage = pTlbe->pPage;
394 if (PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
395 {
396 PGMPhysReleasePageMappingLock(pVM, pLock);
397 rc = VERR_PGM_PHYS_PAGE_RESERVED;
398 }
399 else if ( PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
400#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
401 || pgmPoolIsDirtyPage(pVM, *pGCPhys)
402#endif
403 )
404 {
405 /* We *must* flush any corresponding pgm pool page here, otherwise we'll
406 * not be informed about writes and keep bogus gst->shw mappings around.
407 */
408 pgmPoolFlushPageByGCPhys(pVM, *pGCPhys);
409 Assert(!PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage));
410 /** @todo r=bird: return VERR_PGM_PHYS_PAGE_RESERVED here if it still has
411 * active handlers, see the PGMR3PhysGCPhys2CCPtrExternal docs. */
412 }
413 }
414
415 PGM_UNLOCK(pVM);
416 return rc;
417}
418
419
420/**
421 * Requests the mapping of a guest page into ring-3, external threads.
422 *
423 * When you're done with the page, call PGMPhysReleasePageMappingLock() ASAP to
424 * release it.
425 *
426 * This API will assume your intention is to write to the page, and will
427 * therefore replace shared and zero pages. If you do not intend to modify the
428 * page, use the PGMR3PhysGCPhys2CCPtrReadOnlyExternal() API.
429 *
430 * @returns VBox status code.
431 * @retval VINF_SUCCESS on success.
432 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical
433 * backing or if the page has any active access handlers. The caller
434 * must fall back on using PGMR3PhysWriteExternal.
435 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
436 *
437 * @param pVM The cross context VM structure.
438 * @param GCPhys The guest physical address of the page that should be mapped.
439 * @param ppv Where to store the address corresponding to GCPhys.
440 * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
441 *
442 * @remark Avoid calling this API from within critical sections (other than the
443 * PGM one) because of the deadlock risk when we have to delegating the
444 * task to an EMT.
445 * @thread Any.
446 */
447VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrExternal(PVM pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
448{
449 AssertPtr(ppv);
450 AssertPtr(pLock);
451
452 Assert(VM_IS_EMT(pVM) || !PGMIsLockOwner(pVM));
453
454 int rc = PGM_LOCK(pVM);
455 AssertRCReturn(rc, rc);
456
457 /*
458 * Query the Physical TLB entry for the page (may fail).
459 */
460 PPGMPAGEMAPTLBE pTlbe;
461 rc = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
462 if (RT_SUCCESS(rc))
463 {
464 PPGMPAGE pPage = pTlbe->pPage;
465 if (PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
466 rc = VERR_PGM_PHYS_PAGE_RESERVED;
467 else
468 {
469 /*
470 * If the page is shared, the zero page, or being write monitored
471 * it must be converted to an page that's writable if possible.
472 * We can only deal with write monitored pages here, the rest have
473 * to be on an EMT.
474 */
475 if ( PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
476 || PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
477#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
478 || pgmPoolIsDirtyPage(pVM, GCPhys)
479#endif
480 )
481 {
482 if ( PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
483 && !PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
484#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
485 && !pgmPoolIsDirtyPage(pVM, GCPhys) /** @todo we're very likely doing this twice. */
486#endif
487 )
488 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, GCPhys);
489 else
490 {
491 PGM_UNLOCK(pVM);
492
493 return VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysGCPhys2CCPtrDelegated, 4,
494 pVM, &GCPhys, ppv, pLock);
495 }
496 }
497
498 /*
499 * Now, just perform the locking and calculate the return address.
500 */
501 PPGMPAGEMAP pMap = pTlbe->pMap;
502 if (pMap)
503 pMap->cRefs++;
504
505 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
506 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
507 {
508 if (cLocks == 0)
509 pVM->pgm.s.cWriteLockedPages++;
510 PGM_PAGE_INC_WRITE_LOCKS(pPage);
511 }
512 else if (cLocks != PGM_PAGE_GET_WRITE_LOCKS(pPage))
513 {
514 PGM_PAGE_INC_WRITE_LOCKS(pPage);
515 AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent write locked state!\n", GCPhys, pPage));
516 if (pMap)
517 pMap->cRefs++; /* Extra ref to prevent it from going away. */
518 }
519
520 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
521 pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_WRITE;
522 pLock->pvMap = pMap;
523 }
524 }
525
526 PGM_UNLOCK(pVM);
527 return rc;
528}
529
530
531/**
532 * Requests the mapping of a guest page into ring-3, external threads.
533 *
534 * When you're done with the page, call PGMPhysReleasePageMappingLock() ASAP to
535 * release it.
536 *
537 * @returns VBox status code.
538 * @retval VINF_SUCCESS on success.
539 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical
540 * backing or if the page as an active ALL access handler. The caller
541 * must fall back on using PGMPhysRead.
542 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
543 *
544 * @param pVM The cross context VM structure.
545 * @param GCPhys The guest physical address of the page that should be mapped.
546 * @param ppv Where to store the address corresponding to GCPhys.
547 * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
548 *
549 * @remark Avoid calling this API from within critical sections (other than
550 * the PGM one) because of the deadlock risk.
551 * @thread Any.
552 */
553VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrReadOnlyExternal(PVM pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock)
554{
555 int rc = PGM_LOCK(pVM);
556 AssertRCReturn(rc, rc);
557
558 /*
559 * Query the Physical TLB entry for the page (may fail).
560 */
561 PPGMPAGEMAPTLBE pTlbe;
562 rc = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
563 if (RT_SUCCESS(rc))
564 {
565 PPGMPAGE pPage = pTlbe->pPage;
566#if 1
567 /* MMIO pages doesn't have any readable backing. */
568 if (PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
569 rc = VERR_PGM_PHYS_PAGE_RESERVED;
570#else
571 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
572 rc = VERR_PGM_PHYS_PAGE_RESERVED;
573#endif
574 else
575 {
576 /*
577 * Now, just perform the locking and calculate the return address.
578 */
579 PPGMPAGEMAP pMap = pTlbe->pMap;
580 if (pMap)
581 pMap->cRefs++;
582
583 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
584 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
585 {
586 if (cLocks == 0)
587 pVM->pgm.s.cReadLockedPages++;
588 PGM_PAGE_INC_READ_LOCKS(pPage);
589 }
590 else if (cLocks != PGM_PAGE_GET_READ_LOCKS(pPage))
591 {
592 PGM_PAGE_INC_READ_LOCKS(pPage);
593 AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent readonly locked state!\n", GCPhys, pPage));
594 if (pMap)
595 pMap->cRefs++; /* Extra ref to prevent it from going away. */
596 }
597
598 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
599 pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_READ;
600 pLock->pvMap = pMap;
601 }
602 }
603
604 PGM_UNLOCK(pVM);
605 return rc;
606}
607
608
609/**
610 * Requests the mapping of multiple guest page into ring-3, external threads.
611 *
612 * When you're done with the pages, call PGMPhysBulkReleasePageMappingLock()
613 * ASAP to release them.
614 *
615 * This API will assume your intention is to write to the pages, and will
616 * therefore replace shared and zero pages. If you do not intend to modify the
617 * pages, use the PGMR3PhysBulkGCPhys2CCPtrReadOnlyExternal() API.
618 *
619 * @returns VBox status code.
620 * @retval VINF_SUCCESS on success.
621 * @retval VERR_PGM_PHYS_PAGE_RESERVED if any of the pages has no physical
622 * backing or if any of the pages the page has any active access
623 * handlers. The caller must fall back on using PGMR3PhysWriteExternal.
624 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if @a paGCPhysPages contains
625 * an invalid physical address.
626 *
627 * @param pVM The cross context VM structure.
628 * @param cPages Number of pages to lock.
629 * @param paGCPhysPages The guest physical address of the pages that
630 * should be mapped (@a cPages entries).
631 * @param papvPages Where to store the ring-3 mapping addresses
632 * corresponding to @a paGCPhysPages.
633 * @param paLocks Where to store the locking information that
634 * pfnPhysBulkReleasePageMappingLock needs (@a cPages
635 * in length).
636 *
637 * @remark Avoid calling this API from within critical sections (other than the
638 * PGM one) because of the deadlock risk when we have to delegating the
639 * task to an EMT.
640 * @thread Any.
641 */
642VMMR3DECL(int) PGMR3PhysBulkGCPhys2CCPtrExternal(PVM pVM, uint32_t cPages, PCRTGCPHYS paGCPhysPages,
643 void **papvPages, PPGMPAGEMAPLOCK paLocks)
644{
645 Assert(cPages > 0);
646 AssertPtr(papvPages);
647 AssertPtr(paLocks);
648
649 Assert(VM_IS_EMT(pVM) || !PGMIsLockOwner(pVM));
650
651 int rc = PGM_LOCK(pVM);
652 AssertRCReturn(rc, rc);
653
654 /*
655 * Lock the pages one by one.
656 * The loop body is similar to PGMR3PhysGCPhys2CCPtrExternal.
657 */
658 int32_t cNextYield = 128;
659 uint32_t iPage;
660 for (iPage = 0; iPage < cPages; iPage++)
661 {
662 if (--cNextYield > 0)
663 { /* likely */ }
664 else
665 {
666 PGM_UNLOCK(pVM);
667 ASMNopPause();
668 PGM_LOCK_VOID(pVM);
669 cNextYield = 128;
670 }
671
672 /*
673 * Query the Physical TLB entry for the page (may fail).
674 */
675 PPGMPAGEMAPTLBE pTlbe;
676 rc = pgmPhysPageQueryTlbe(pVM, paGCPhysPages[iPage], &pTlbe);
677 if (RT_SUCCESS(rc))
678 { }
679 else
680 break;
681 PPGMPAGE pPage = pTlbe->pPage;
682
683 /*
684 * No MMIO or active access handlers.
685 */
686 if ( !PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage)
687 && !PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
688 { }
689 else
690 {
691 rc = VERR_PGM_PHYS_PAGE_RESERVED;
692 break;
693 }
694
695 /*
696 * The page must be in the allocated state and not be a dirty pool page.
697 * We can handle converting a write monitored page to an allocated one, but
698 * anything more complicated must be delegated to an EMT.
699 */
700 bool fDelegateToEmt = false;
701 if (PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED)
702#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
703 fDelegateToEmt = pgmPoolIsDirtyPage(pVM, paGCPhysPages[iPage]);
704#else
705 fDelegateToEmt = false;
706#endif
707 else if (PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED)
708 {
709#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
710 if (!pgmPoolIsDirtyPage(pVM, paGCPhysPages[iPage]))
711 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, paGCPhysPages[iPage]);
712 else
713 fDelegateToEmt = true;
714#endif
715 }
716 else
717 fDelegateToEmt = true;
718 if (!fDelegateToEmt)
719 { }
720 else
721 {
722 /* We could do this delegation in bulk, but considered too much work vs gain. */
723 PGM_UNLOCK(pVM);
724 rc = VMR3ReqPriorityCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysGCPhys2CCPtrDelegated, 4,
725 pVM, &paGCPhysPages[iPage], &papvPages[iPage], &paLocks[iPage]);
726 PGM_LOCK_VOID(pVM);
727 if (RT_FAILURE(rc))
728 break;
729 cNextYield = 128;
730 }
731
732 /*
733 * Now, just perform the locking and address calculation.
734 */
735 PPGMPAGEMAP pMap = pTlbe->pMap;
736 if (pMap)
737 pMap->cRefs++;
738
739 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
740 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
741 {
742 if (cLocks == 0)
743 pVM->pgm.s.cWriteLockedPages++;
744 PGM_PAGE_INC_WRITE_LOCKS(pPage);
745 }
746 else if (cLocks != PGM_PAGE_GET_WRITE_LOCKS(pPage))
747 {
748 PGM_PAGE_INC_WRITE_LOCKS(pPage);
749 AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent write locked state!\n", paGCPhysPages[iPage], pPage));
750 if (pMap)
751 pMap->cRefs++; /* Extra ref to prevent it from going away. */
752 }
753
754 papvPages[iPage] = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(paGCPhysPages[iPage] & GUEST_PAGE_OFFSET_MASK));
755 paLocks[iPage].uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_WRITE;
756 paLocks[iPage].pvMap = pMap;
757 }
758
759 PGM_UNLOCK(pVM);
760
761 /*
762 * On failure we must unlock any pages we managed to get already.
763 */
764 if (RT_FAILURE(rc) && iPage > 0)
765 PGMPhysBulkReleasePageMappingLocks(pVM, iPage, paLocks);
766
767 return rc;
768}
769
770
771/**
772 * Requests the mapping of multiple guest page into ring-3, for reading only,
773 * external threads.
774 *
775 * When you're done with the pages, call PGMPhysReleasePageMappingLock() ASAP
776 * to release them.
777 *
778 * @returns VBox status code.
779 * @retval VINF_SUCCESS on success.
780 * @retval VERR_PGM_PHYS_PAGE_RESERVED if any of the pages has no physical
781 * backing or if any of the pages the page has an active ALL access
782 * handler. The caller must fall back on using PGMR3PhysWriteExternal.
783 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if @a paGCPhysPages contains
784 * an invalid physical address.
785 *
786 * @param pVM The cross context VM structure.
787 * @param cPages Number of pages to lock.
788 * @param paGCPhysPages The guest physical address of the pages that
789 * should be mapped (@a cPages entries).
790 * @param papvPages Where to store the ring-3 mapping addresses
791 * corresponding to @a paGCPhysPages.
792 * @param paLocks Where to store the lock information that
793 * pfnPhysReleasePageMappingLock needs (@a cPages
794 * in length).
795 *
796 * @remark Avoid calling this API from within critical sections (other than
797 * the PGM one) because of the deadlock risk.
798 * @thread Any.
799 */
800VMMR3DECL(int) PGMR3PhysBulkGCPhys2CCPtrReadOnlyExternal(PVM pVM, uint32_t cPages, PCRTGCPHYS paGCPhysPages,
801 void const **papvPages, PPGMPAGEMAPLOCK paLocks)
802{
803 Assert(cPages > 0);
804 AssertPtr(papvPages);
805 AssertPtr(paLocks);
806
807 Assert(VM_IS_EMT(pVM) || !PGMIsLockOwner(pVM));
808
809 int rc = PGM_LOCK(pVM);
810 AssertRCReturn(rc, rc);
811
812 /*
813 * Lock the pages one by one.
814 * The loop body is similar to PGMR3PhysGCPhys2CCPtrReadOnlyExternal.
815 */
816 int32_t cNextYield = 256;
817 uint32_t iPage;
818 for (iPage = 0; iPage < cPages; iPage++)
819 {
820 if (--cNextYield > 0)
821 { /* likely */ }
822 else
823 {
824 PGM_UNLOCK(pVM);
825 ASMNopPause();
826 PGM_LOCK_VOID(pVM);
827 cNextYield = 256;
828 }
829
830 /*
831 * Query the Physical TLB entry for the page (may fail).
832 */
833 PPGMPAGEMAPTLBE pTlbe;
834 rc = pgmPhysPageQueryTlbe(pVM, paGCPhysPages[iPage], &pTlbe);
835 if (RT_SUCCESS(rc))
836 { }
837 else
838 break;
839 PPGMPAGE pPage = pTlbe->pPage;
840
841 /*
842 * No MMIO or active all access handlers, everything else can be accessed.
843 */
844 if ( !PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage)
845 && !PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
846 { }
847 else
848 {
849 rc = VERR_PGM_PHYS_PAGE_RESERVED;
850 break;
851 }
852
853 /*
854 * Now, just perform the locking and address calculation.
855 */
856 PPGMPAGEMAP pMap = pTlbe->pMap;
857 if (pMap)
858 pMap->cRefs++;
859
860 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
861 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
862 {
863 if (cLocks == 0)
864 pVM->pgm.s.cReadLockedPages++;
865 PGM_PAGE_INC_READ_LOCKS(pPage);
866 }
867 else if (cLocks != PGM_PAGE_GET_READ_LOCKS(pPage))
868 {
869 PGM_PAGE_INC_READ_LOCKS(pPage);
870 AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent readonly locked state!\n", paGCPhysPages[iPage], pPage));
871 if (pMap)
872 pMap->cRefs++; /* Extra ref to prevent it from going away. */
873 }
874
875 papvPages[iPage] = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(paGCPhysPages[iPage] & GUEST_PAGE_OFFSET_MASK));
876 paLocks[iPage].uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_READ;
877 paLocks[iPage].pvMap = pMap;
878 }
879
880 PGM_UNLOCK(pVM);
881
882 /*
883 * On failure we must unlock any pages we managed to get already.
884 */
885 if (RT_FAILURE(rc) && iPage > 0)
886 PGMPhysBulkReleasePageMappingLocks(pVM, iPage, paLocks);
887
888 return rc;
889}
890
891
892/**
893 * Converts a GC physical address to a HC ring-3 pointer, with some
894 * additional checks.
895 *
896 * @returns VBox status code.
897 * @retval VINF_SUCCESS on success.
898 * @retval VINF_PGM_PHYS_TLB_CATCH_WRITE and *ppv set if the page has a write
899 * access handler of some kind.
900 * @retval VERR_PGM_PHYS_TLB_CATCH_ALL if the page has a handler catching all
901 * accesses or is odd in any way.
902 * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist.
903 *
904 * @param pVM The cross context VM structure.
905 * @param GCPhys The GC physical address to convert. Since this is only
906 * used for filling the REM TLB, the A20 mask must be
907 * applied before calling this API.
908 * @param fWritable Whether write access is required.
909 * @param ppv Where to store the pointer corresponding to GCPhys on
910 * success.
911 */
912VMMR3DECL(int) PGMR3PhysTlbGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, void **ppv)
913{
914 PGM_LOCK_VOID(pVM);
915 PGM_A20_ASSERT_MASKED(VMMGetCpu(pVM), GCPhys);
916
917 PPGMRAMRANGE pRam;
918 PPGMPAGE pPage;
919 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
920 if (RT_SUCCESS(rc))
921 {
922 if (PGM_PAGE_IS_BALLOONED(pPage))
923 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
924 else if (!PGM_PAGE_HAS_ANY_HANDLERS(pPage))
925 rc = VINF_SUCCESS;
926 else
927 {
928 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)) /* catches MMIO */
929 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
930 else if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
931 {
932 /** @todo Handle TLB loads of virtual handlers so ./test.sh can be made to work
933 * in -norawr0 mode. */
934 if (fWritable)
935 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
936 }
937 else
938 {
939 /* Temporarily disabled physical handler(s), since the recompiler
940 doesn't get notified when it's reset we'll have to pretend it's
941 operating normally. */
942 if (pgmHandlerPhysicalIsAll(pVM, GCPhys))
943 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
944 else
945 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
946 }
947 }
948 if (RT_SUCCESS(rc))
949 {
950 int rc2;
951
952 /* Make sure what we return is writable. */
953 if (fWritable)
954 switch (PGM_PAGE_GET_STATE(pPage))
955 {
956 case PGM_PAGE_STATE_ALLOCATED:
957 break;
958 case PGM_PAGE_STATE_BALLOONED:
959 AssertFailed();
960 break;
961 case PGM_PAGE_STATE_ZERO:
962 case PGM_PAGE_STATE_SHARED:
963 if (rc == VINF_PGM_PHYS_TLB_CATCH_WRITE)
964 break;
965 RT_FALL_THRU();
966 case PGM_PAGE_STATE_WRITE_MONITORED:
967 rc2 = pgmPhysPageMakeWritable(pVM, pPage, GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK);
968 AssertLogRelRCReturn(rc2, rc2);
969 break;
970 }
971
972 /* Get a ring-3 mapping of the address. */
973 PPGMPAGER3MAPTLBE pTlbe;
974 rc2 = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
975 AssertLogRelRCReturn(rc2, rc2);
976 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
977 /** @todo mapping/locking hell; this isn't horribly efficient since
978 * pgmPhysPageLoadIntoTlb will repeat the lookup we've done here. */
979
980 Log6(("PGMR3PhysTlbGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage] *ppv=%p\n", GCPhys, rc, pPage, *ppv));
981 }
982 else
983 Log6(("PGMR3PhysTlbGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage]\n", GCPhys, rc, pPage));
984
985 /* else: handler catching all access, no pointer returned. */
986 }
987 else
988 rc = VERR_PGM_PHYS_TLB_UNASSIGNED;
989
990 PGM_UNLOCK(pVM);
991 return rc;
992}
993
994
995
996/*********************************************************************************************************************************
997* RAM Range Management *
998*********************************************************************************************************************************/
999
1000/**
1001 * Given the range @a GCPhys thru @a GCPhysLast, find overlapping RAM range or
1002 * the correct insertion point.
1003 *
1004 * @returns Pointer to overlapping RAM range if found, NULL if not.
1005 * @param pVM The cross context VM structure.
1006 * @param GCPhys The address of the first byte in the range.
1007 * @param GCPhysLast The address of the last byte in the range.
1008 * @param pidxInsert Where to return the lookup table index to insert the
1009 * range at when returning NULL. Set to UINT32_MAX when
1010 * returning the pointer to an overlapping range.
1011 * @note Caller must own the PGM lock.
1012 */
1013static PPGMRAMRANGE pgmR3PhysRamRangeFindOverlapping(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, uint32_t *pidxInsert)
1014{
1015 PGM_LOCK_ASSERT_OWNER(pVM);
1016 uint32_t iStart = 0;
1017 uint32_t iEnd = pVM->pgm.s.RamRangeUnion.cLookupEntries;
1018 for (;;)
1019 {
1020 uint32_t idxLookup = iStart + (iEnd - iStart) / 2;
1021 RTGCPHYS const GCPhysEntryFirst = PGMRAMRANGELOOKUPENTRY_GET_FIRST(pVM->pgm.s.aRamRangeLookup[idxLookup]);
1022 if (GCPhysLast < GCPhysEntryFirst)
1023 {
1024 if (idxLookup > iStart)
1025 iEnd = idxLookup;
1026 else
1027 {
1028 *pidxInsert = idxLookup;
1029 return NULL;
1030 }
1031 }
1032 else
1033 {
1034 RTGCPHYS const GCPhysEntryLast = pVM->pgm.s.aRamRangeLookup[idxLookup].GCPhysLast;
1035 if (GCPhys > GCPhysEntryLast)
1036 {
1037 idxLookup += 1;
1038 if (idxLookup < iEnd)
1039 iStart = idxLookup;
1040 else
1041 {
1042 *pidxInsert = idxLookup;
1043 return NULL;
1044 }
1045 }
1046 else
1047 {
1048 /* overlap */
1049 Assert(GCPhysEntryLast > GCPhys && GCPhysEntryFirst < GCPhysLast);
1050 *pidxInsert = UINT32_MAX;
1051 return pVM->pgm.s.apRamRanges[PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup])];
1052 }
1053 }
1054 }
1055}
1056
1057
1058/**
1059 * Given the range @a GCPhys thru @a GCPhysLast, find the lookup table entry
1060 * that's overlapping it.
1061 *
1062 * @returns The lookup table index of the overlapping entry, UINT32_MAX if not
1063 * found.
1064 * @param pVM The cross context VM structure.
1065 * @param GCPhys The address of the first byte in the range.
1066 * @param GCPhysLast The address of the last byte in the range.
1067 * @note Caller must own the PGM lock.
1068 */
1069static uint32_t pgmR3PhysRamRangeFindOverlappingIndex(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast)
1070{
1071 PGM_LOCK_ASSERT_OWNER(pVM);
1072 uint32_t iStart = 0;
1073 uint32_t iEnd = pVM->pgm.s.RamRangeUnion.cLookupEntries;
1074 for (;;)
1075 {
1076 uint32_t idxLookup = iStart + (iEnd - iStart) / 2;
1077 RTGCPHYS const GCPhysEntryFirst = PGMRAMRANGELOOKUPENTRY_GET_FIRST(pVM->pgm.s.aRamRangeLookup[idxLookup]);
1078 if (GCPhysLast < GCPhysEntryFirst)
1079 {
1080 if (idxLookup > iStart)
1081 iEnd = idxLookup;
1082 else
1083 return UINT32_MAX;
1084 }
1085 else
1086 {
1087 RTGCPHYS const GCPhysEntryLast = pVM->pgm.s.aRamRangeLookup[idxLookup].GCPhysLast;
1088 if (GCPhys > GCPhysEntryLast)
1089 {
1090 idxLookup += 1;
1091 if (idxLookup < iEnd)
1092 iStart = idxLookup;
1093 else
1094 return UINT32_MAX;
1095 }
1096 else
1097 {
1098 /* overlap */
1099 Assert(GCPhysEntryLast > GCPhys && GCPhysEntryFirst < GCPhysLast);
1100 return idxLookup;
1101 }
1102 }
1103 }
1104}
1105
1106
1107/**
1108 * Insert @a pRam into the lookup table.
1109 *
1110 * @returns VBox status code.
1111 * @param pVM The cross context VM structure.
1112 * @param pRam The RAM range to insert into the lookup table.
1113 * @param GCPhys The new mapping address to assign @a pRam on insertion.
1114 * @param pidxLookup Optional lookup table hint. This is updated.
1115 * @note Caller must own PGM lock.
1116 */
1117static int pgmR3PhysRamRangeInsertLookup(PVM pVM, PPGMRAMRANGE pRam, RTGCPHYS GCPhys, uint32_t *pidxLookup)
1118{
1119 PGM_LOCK_ASSERT_OWNER(pVM);
1120#ifdef DEBUG_bird
1121 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, true /*fRamRelaxed*/);
1122#endif
1123 AssertMsg(pRam->pszDesc, ("%RGp-%RGp\n", pRam->GCPhys, pRam->GCPhysLast));
1124 AssertLogRelMsgReturn( pRam->GCPhys == NIL_RTGCPHYS
1125 && pRam->GCPhysLast == NIL_RTGCPHYS,
1126 ("GCPhys=%RGp; range: GCPhys=%RGp LB %RGp GCPhysLast=%RGp %s\n",
1127 GCPhys, pRam->GCPhys, pRam->cb, pRam->GCPhysLast, pRam->pszDesc),
1128 VERR_ALREADY_EXISTS);
1129 uint32_t const idRamRange = pRam->idRange;
1130 AssertReturn(pVM->pgm.s.apRamRanges[idRamRange] == pRam, VERR_INTERNAL_ERROR_2);
1131
1132 AssertReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
1133 RTGCPHYS const GCPhysLast = GCPhys + pRam->cb - 1U;
1134 AssertReturn(GCPhysLast > GCPhys, VERR_INTERNAL_ERROR_4);
1135 LogFlowFunc(("GCPhys=%RGp LB %RGp GCPhysLast=%RGp id=%#x %s\n", GCPhys, pRam->cb, GCPhysLast, idRamRange, pRam->pszDesc));
1136
1137 /*
1138 * Find the lookup table location if necessary.
1139 */
1140 uint32_t const cLookupEntries = pVM->pgm.s.RamRangeUnion.cLookupEntries;
1141 AssertLogRelMsgReturn(cLookupEntries + 1 < RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup), /* id=0 is unused, so < is correct. */
1142 ("%#x\n", cLookupEntries), VERR_INTERNAL_ERROR_3);
1143
1144 uint32_t idxLookup = pidxLookup ? *pidxLookup : UINT32_MAX;
1145 if (cLookupEntries == 0)
1146 idxLookup = 0; /* special case: empty table */
1147 else
1148 {
1149 if ( idxLookup > cLookupEntries
1150 || ( idxLookup != 0
1151 && pVM->pgm.s.aRamRangeLookup[idxLookup - 1].GCPhysLast >= GCPhys)
1152 || ( idxLookup < cLookupEntries
1153 && PGMRAMRANGELOOKUPENTRY_GET_FIRST(pVM->pgm.s.aRamRangeLookup[idxLookup]) < GCPhysLast))
1154 {
1155 PPGMRAMRANGE pOverlapping = pgmR3PhysRamRangeFindOverlapping(pVM, GCPhys, GCPhysLast, &idxLookup);
1156 AssertLogRelMsgReturn(!pOverlapping,
1157 ("GCPhys=%RGp; GCPhysLast=%RGp %s - overlaps %RGp...%RGp %s\n",
1158 GCPhys, GCPhysLast, pRam->pszDesc,
1159 pOverlapping->GCPhys, pOverlapping->GCPhysLast, pOverlapping->pszDesc),
1160 VERR_PGM_RAM_CONFLICT);
1161 AssertLogRelMsgReturn(idxLookup <= cLookupEntries, ("%#x vs %#x\n", idxLookup, cLookupEntries), VERR_INTERNAL_ERROR_5);
1162 }
1163 /* else we've got a good hint. */
1164 }
1165
1166 /*
1167 * Do the actual job.
1168 *
1169 * The moving of existing table entries is done in a way that allows other
1170 * EMTs to perform concurrent lookups with the updating.
1171 */
1172 bool const fUseAtomic = pVM->enmVMState != VMSTATE_CREATING
1173 && pVM->cCpus > 1
1174#ifdef RT_ARCH_AMD64
1175 && g_CpumHostFeatures.s.fCmpXchg16b
1176#endif
1177 ;
1178
1179 /* Signal that we're modifying the lookup table: */
1180 uint32_t const idGeneration = (pVM->pgm.s.RamRangeUnion.idGeneration + 1) | 1; /* paranoia^3 */
1181 ASMAtomicWriteU32(&pVM->pgm.s.RamRangeUnion.idGeneration, idGeneration);
1182
1183 /* Update the RAM range entry. */
1184 pRam->GCPhys = GCPhys;
1185 pRam->GCPhysLast = GCPhysLast;
1186
1187 /* Do we need to shift any lookup table entries? */
1188 if (idxLookup != cLookupEntries)
1189 {
1190 /* We do. Make a copy of the final entry first. */
1191 uint32_t cToMove = cLookupEntries - idxLookup;
1192 PGMRAMRANGELOOKUPENTRY *pCur = &pVM->pgm.s.aRamRangeLookup[cLookupEntries];
1193 pCur->GCPhysFirstAndId = pCur[-1].GCPhysFirstAndId;
1194 pCur->GCPhysLast = pCur[-1].GCPhysLast;
1195
1196 /* Then increase the table size. This will ensure that anyone starting
1197 a search from here on should have consistent data. */
1198 ASMAtomicWriteU32(&pVM->pgm.s.RamRangeUnion.cLookupEntries, cLookupEntries + 1);
1199
1200 /* Transfer the rest of the entries. */
1201 cToMove -= 1;
1202 if (cToMove > 0)
1203 {
1204 if (!fUseAtomic)
1205 do
1206 {
1207 pCur -= 1;
1208 pCur->GCPhysFirstAndId = pCur[-1].GCPhysFirstAndId;
1209 pCur->GCPhysLast = pCur[-1].GCPhysLast;
1210 cToMove -= 1;
1211 } while (cToMove > 0);
1212 else
1213 {
1214#if RTASM_HAVE_WRITE_U128 >= 2
1215 do
1216 {
1217 pCur -= 1;
1218 ASMAtomicWriteU128U(&pCur->u128Volatile, pCur[-1].u128Normal);
1219 cToMove -= 1;
1220 } while (cToMove > 0);
1221
1222#else
1223 uint64_t u64PrevLo = pCur[-1].u128Normal.s.Lo;
1224 uint64_t u64PrevHi = pCur[-1].u128Normal.s.Hi;
1225 do
1226 {
1227 pCur -= 1;
1228 uint64_t const u64CurLo = pCur[-1].u128Normal.s.Lo;
1229 uint64_t const u64CurHi = pCur[-1].u128Normal.s.Hi;
1230 uint128_t uOldIgn;
1231 AssertStmt(ASMAtomicCmpXchgU128v2(&pCur->u128Volatile.u, u64CurHi, u64CurLo, u64PrevHi, u64PrevLo, &uOldIgn),
1232 (pCur->u128Volatile.s.Lo = u64CurLo, pCur->u128Volatile.s.Hi = u64CurHi));
1233 u64PrevLo = u64CurLo;
1234 u64PrevHi = u64CurHi;
1235 cToMove -= 1;
1236 } while (cToMove > 0);
1237#endif
1238 }
1239 }
1240 }
1241
1242 /*
1243 * Write the new entry.
1244 */
1245 PGMRAMRANGELOOKUPENTRY *pInsert = &pVM->pgm.s.aRamRangeLookup[idxLookup];
1246 if (!fUseAtomic)
1247 {
1248 pInsert->GCPhysFirstAndId = idRamRange | GCPhys;
1249 pInsert->GCPhysLast = GCPhysLast;
1250 }
1251 else
1252 {
1253 PGMRAMRANGELOOKUPENTRY NewEntry;
1254 NewEntry.GCPhysFirstAndId = idRamRange | GCPhys;
1255 NewEntry.GCPhysLast = GCPhysLast;
1256 ASMAtomicWriteU128v2(&pInsert->u128Volatile.u, NewEntry.u128Normal.s.Hi, NewEntry.u128Normal.s.Lo);
1257 }
1258
1259 /*
1260 * Update the generation and count in one go, signaling the end of the updating.
1261 */
1262 PGM::PGMRAMRANGEGENANDLOOKUPCOUNT GenAndCount;
1263 GenAndCount.cLookupEntries = cLookupEntries + 1;
1264 GenAndCount.idGeneration = idGeneration + 1;
1265 ASMAtomicWriteU64(&pVM->pgm.s.RamRangeUnion.u64Combined, GenAndCount.u64Combined);
1266
1267 if (pidxLookup)
1268 *pidxLookup = idxLookup + 1;
1269
1270#ifdef DEBUG_bird
1271 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, false /*fRamRelaxed*/);
1272#endif
1273 return VINF_SUCCESS;
1274}
1275
1276
1277/**
1278 * Removes @a pRam from the lookup table.
1279 *
1280 * @returns VBox status code.
1281 * @param pVM The cross context VM structure.
1282 * @param pRam The RAM range to insert into the lookup table.
1283 * @param pidxLookup Optional lookup table hint. This is updated.
1284 * @note Caller must own PGM lock.
1285 */
1286static int pgmR3PhysRamRangeRemoveLookup(PVM pVM, PPGMRAMRANGE pRam, uint32_t *pidxLookup)
1287{
1288 PGM_LOCK_ASSERT_OWNER(pVM);
1289 AssertMsg(pRam->pszDesc, ("%RGp-%RGp\n", pRam->GCPhys, pRam->GCPhysLast));
1290
1291 RTGCPHYS const GCPhys = pRam->GCPhys;
1292 RTGCPHYS const GCPhysLast = pRam->GCPhysLast;
1293 AssertLogRelMsgReturn( GCPhys != NIL_RTGCPHYS
1294 || GCPhysLast != NIL_RTGCPHYS,
1295 ("range: GCPhys=%RGp LB %RGp GCPhysLast=%RGp %s\n", GCPhys, pRam->cb, GCPhysLast, pRam->pszDesc),
1296 VERR_NOT_FOUND);
1297 AssertLogRelMsgReturn( GCPhys != NIL_RTGCPHYS
1298 && GCPhysLast == GCPhys + pRam->cb - 1U
1299 && (GCPhys & GUEST_PAGE_OFFSET_MASK) == 0
1300 && (GCPhysLast & GUEST_PAGE_OFFSET_MASK) == GUEST_PAGE_OFFSET_MASK
1301 && GCPhysLast > GCPhys,
1302 ("range: GCPhys=%RGp LB %RGp GCPhysLast=%RGp %s\n", GCPhys, pRam->cb, GCPhysLast, pRam->pszDesc),
1303 VERR_INTERNAL_ERROR_5);
1304 uint32_t const idRamRange = pRam->idRange;
1305 AssertReturn(pVM->pgm.s.apRamRanges[idRamRange] == pRam, VERR_INTERNAL_ERROR_4);
1306 LogFlowFunc(("GCPhys=%RGp LB %RGp GCPhysLast=%RGp id=%#x %s\n", GCPhys, pRam->cb, GCPhysLast, idRamRange, pRam->pszDesc));
1307
1308 /*
1309 * Find the lookup table location.
1310 */
1311 uint32_t const cLookupEntries = pVM->pgm.s.RamRangeUnion.cLookupEntries;
1312 AssertLogRelMsgReturn( cLookupEntries > 0
1313 && cLookupEntries < RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup), /* id=0 is unused, so < is correct. */
1314 ("%#x\n", cLookupEntries), VERR_INTERNAL_ERROR_3);
1315
1316 uint32_t idxLookup = pidxLookup ? *pidxLookup : UINT32_MAX;
1317 if ( idxLookup >= cLookupEntries
1318 || pVM->pgm.s.aRamRangeLookup[idxLookup].GCPhysLast != GCPhysLast
1319 || pVM->pgm.s.aRamRangeLookup[idxLookup].GCPhysFirstAndId != (GCPhys | idRamRange))
1320 {
1321 uint32_t iStart = 0;
1322 uint32_t iEnd = cLookupEntries;
1323 for (;;)
1324 {
1325 idxLookup = iStart + (iEnd - iStart) / 2;
1326 RTGCPHYS const GCPhysEntryFirst = PGMRAMRANGELOOKUPENTRY_GET_FIRST(pVM->pgm.s.aRamRangeLookup[idxLookup]);
1327 if (GCPhysLast < GCPhysEntryFirst)
1328 {
1329 AssertLogRelMsgReturn(idxLookup > iStart,
1330 ("range: GCPhys=%RGp LB %RGp GCPhysLast=%RGp %s\n",
1331 GCPhys, pRam->cb, GCPhysLast, pRam->pszDesc),
1332 VERR_NOT_FOUND);
1333 iEnd = idxLookup;
1334 }
1335 else
1336 {
1337 RTGCPHYS const GCPhysEntryLast = pVM->pgm.s.aRamRangeLookup[idxLookup].GCPhysLast;
1338 if (GCPhys > GCPhysEntryLast)
1339 {
1340 idxLookup += 1;
1341 AssertLogRelMsgReturn(idxLookup < iEnd,
1342 ("range: GCPhys=%RGp LB %RGp GCPhysLast=%RGp %s\n",
1343 GCPhys, pRam->cb, GCPhysLast, pRam->pszDesc),
1344 VERR_NOT_FOUND);
1345 iStart = idxLookup;
1346 }
1347 else
1348 {
1349 uint32_t const idEntry = PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup]);
1350 AssertLogRelMsgReturn( GCPhysEntryFirst == GCPhys
1351 && GCPhysEntryLast == GCPhysLast
1352 && idEntry == idRamRange,
1353 ("Found: %RGp..%RGp id=%#x; Wanted: GCPhys=%RGp LB %RGp GCPhysLast=%RGp id=%#x %s\n",
1354 GCPhysEntryFirst, GCPhysEntryLast, idEntry,
1355 GCPhys, pRam->cb, GCPhysLast, pRam->idRange, pRam->pszDesc),
1356 VERR_NOT_FOUND);
1357 break;
1358 }
1359 }
1360 }
1361 }
1362 /* else we've got a good hint. */
1363
1364 /*
1365 * Do the actual job.
1366 *
1367 * The moving of existing table entries is done in a way that allows other
1368 * EMTs to perform concurrent lookups with the updating.
1369 */
1370 bool const fUseAtomic = pVM->enmVMState != VMSTATE_CREATING
1371 && pVM->cCpus > 1
1372#ifdef RT_ARCH_AMD64
1373 && g_CpumHostFeatures.s.fCmpXchg16b
1374#endif
1375 ;
1376
1377 /* Signal that we're modifying the lookup table: */
1378 uint32_t const idGeneration = (pVM->pgm.s.RamRangeUnion.idGeneration + 1) | 1; /* paranoia^3 */
1379 ASMAtomicWriteU32(&pVM->pgm.s.RamRangeUnion.idGeneration, idGeneration);
1380
1381 /* Do we need to shift any lookup table entries? (This is a lot simpler
1382 than insertion.) */
1383 if (idxLookup + 1U < cLookupEntries)
1384 {
1385 uint32_t cToMove = cLookupEntries - idxLookup - 1U;
1386 PGMRAMRANGELOOKUPENTRY *pCur = &pVM->pgm.s.aRamRangeLookup[idxLookup];
1387 if (!fUseAtomic)
1388 do
1389 {
1390 pCur->GCPhysFirstAndId = pCur[1].GCPhysFirstAndId;
1391 pCur->GCPhysLast = pCur[1].GCPhysLast;
1392 pCur += 1;
1393 cToMove -= 1;
1394 } while (cToMove > 0);
1395 else
1396 {
1397#if RTASM_HAVE_WRITE_U128 >= 2
1398 do
1399 {
1400 ASMAtomicWriteU128U(&pCur->u128Volatile, pCur[1].u128Normal);
1401 pCur += 1;
1402 cToMove -= 1;
1403 } while (cToMove > 0);
1404
1405#else
1406 uint64_t u64PrevLo = pCur->u128Normal.s.Lo;
1407 uint64_t u64PrevHi = pCur->u128Normal.s.Hi;
1408 do
1409 {
1410 uint64_t const u64CurLo = pCur[1].u128Normal.s.Lo;
1411 uint64_t const u64CurHi = pCur[1].u128Normal.s.Hi;
1412 uint128_t uOldIgn;
1413 AssertStmt(ASMAtomicCmpXchgU128v2(&pCur->u128Volatile.u, u64CurHi, u64CurLo, u64PrevHi, u64PrevLo, &uOldIgn),
1414 (pCur->u128Volatile.s.Lo = u64CurLo, pCur->u128Volatile.s.Hi = u64CurHi));
1415 u64PrevLo = u64CurLo;
1416 u64PrevHi = u64CurHi;
1417 pCur += 1;
1418 cToMove -= 1;
1419 } while (cToMove > 0);
1420#endif
1421 }
1422 }
1423
1424 /* Update the RAM range entry to indicate that it is no longer mapped.
1425 The GCPhys member is accessed by the lockless TLB lookup code, so update
1426 it last and atomically to be on the safe side. */
1427 pRam->GCPhysLast = NIL_RTGCPHYS;
1428 ASMAtomicWriteU64(&pRam->GCPhys, NIL_RTGCPHYS);
1429
1430 /*
1431 * Update the generation and count in one go, signaling the end of the updating.
1432 */
1433 PGM::PGMRAMRANGEGENANDLOOKUPCOUNT GenAndCount;
1434 GenAndCount.cLookupEntries = cLookupEntries - 1;
1435 GenAndCount.idGeneration = idGeneration + 1;
1436 ASMAtomicWriteU64(&pVM->pgm.s.RamRangeUnion.u64Combined, GenAndCount.u64Combined);
1437
1438 if (pidxLookup)
1439 *pidxLookup = idxLookup + 1;
1440
1441 return VINF_SUCCESS;
1442}
1443
1444
1445/**
1446 * Gets the number of ram ranges.
1447 *
1448 * @returns Number of ram ranges. Returns UINT32_MAX if @a pVM is invalid.
1449 * @param pVM The cross context VM structure.
1450 */
1451VMMR3DECL(uint32_t) PGMR3PhysGetRamRangeCount(PVM pVM)
1452{
1453 VM_ASSERT_VALID_EXT_RETURN(pVM, UINT32_MAX);
1454
1455 PGM_LOCK_VOID(pVM);
1456 uint32_t const cRamRanges = RT_MIN(pVM->pgm.s.RamRangeUnion.cLookupEntries, RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup));
1457 PGM_UNLOCK(pVM);
1458 return cRamRanges;
1459}
1460
1461
1462/**
1463 * Get information about a range.
1464 *
1465 * @returns VINF_SUCCESS or VERR_OUT_OF_RANGE.
1466 * @param pVM The cross context VM structure.
1467 * @param iRange The ordinal of the range.
1468 * @param pGCPhysStart Where to return the start of the range. Optional.
1469 * @param pGCPhysLast Where to return the address of the last byte in the
1470 * range. Optional.
1471 * @param ppszDesc Where to return the range description. Optional.
1472 * @param pfIsMmio Where to indicate that this is a pure MMIO range.
1473 * Optional.
1474 */
1475VMMR3DECL(int) PGMR3PhysGetRange(PVM pVM, uint32_t iRange, PRTGCPHYS pGCPhysStart, PRTGCPHYS pGCPhysLast,
1476 const char **ppszDesc, bool *pfIsMmio)
1477{
1478 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1479
1480 PGM_LOCK_VOID(pVM);
1481 uint32_t const cLookupEntries = RT_MIN(pVM->pgm.s.RamRangeUnion.cLookupEntries, RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup));
1482 if (iRange < cLookupEntries)
1483 {
1484 uint32_t const idRamRange = PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[iRange]);
1485 Assert(idRamRange && idRamRange <= pVM->pgm.s.idRamRangeMax);
1486 PGMRAMRANGE const * const pRamRange = pVM->pgm.s.apRamRanges[idRamRange];
1487 AssertPtr(pRamRange);
1488
1489 if (pGCPhysStart)
1490 *pGCPhysStart = pRamRange->GCPhys;
1491 if (pGCPhysLast)
1492 *pGCPhysLast = pRamRange->GCPhysLast;
1493 if (ppszDesc)
1494 *ppszDesc = pRamRange->pszDesc;
1495 if (pfIsMmio)
1496 *pfIsMmio = !!(pRamRange->fFlags & PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO);
1497
1498 PGM_UNLOCK(pVM);
1499 return VINF_SUCCESS;
1500 }
1501 PGM_UNLOCK(pVM);
1502 return VERR_OUT_OF_RANGE;
1503}
1504
1505
1506/**
1507 * Gets RAM ranges that are supposed to be zero'ed at boot.
1508 *
1509 * This function gets all RAM ranges that are not ad hoc (ROM, MMIO, MMIO2) memory.
1510 * The RAM hole (if any) is -NOT- included because we don't return 0s when it is
1511 * read anyway.
1512 *
1513 * @returns VBox status code.
1514 * @param pVM The cross context VM structure.
1515 * @param pRanges Where to store the physical RAM ranges.
1516 * @param cMaxRanges The maximum ranges that can be stored.
1517 */
1518VMMR3_INT_DECL(int) PGMR3PhysGetRamBootZeroedRanges(PVM pVM, PPGMPHYSRANGES pRanges, uint32_t cMaxRanges)
1519{
1520 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1521 AssertPtrReturn(pRanges, VERR_INVALID_PARAMETER);
1522 AssertReturn(cMaxRanges > 0, VERR_INVALID_PARAMETER);
1523
1524 int rc = VINF_SUCCESS;
1525 uint32_t idxRange = 0;
1526 PGM_LOCK_VOID(pVM);
1527
1528 /*
1529 * The primary purpose of this API is the GIM Hyper-V hypercall which recommends (not
1530 * requires) that the largest ranges are reported earlier. Therefore, here we iterate
1531 * the ranges in reverse because in PGM the largest range is generally at the end.
1532 */
1533 uint32_t const cLookupEntries = RT_MIN(pVM->pgm.s.RamRangeUnion.cLookupEntries, RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup));
1534 for (int32_t idxLookup = cLookupEntries - 1; idxLookup >= 0; idxLookup--)
1535 {
1536 uint32_t const idRamRange = PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup]);
1537 Assert(idRamRange < RT_ELEMENTS(pVM->pgm.s.apRamRanges));
1538 PPGMRAMRANGE const pCur = pVM->pgm.s.apRamRanges[idRamRange];
1539 AssertContinue(pCur);
1540
1541 if (!PGM_RAM_RANGE_IS_AD_HOC(pCur))
1542 {
1543 if (idxRange < cMaxRanges)
1544 {
1545 /* Combine with previous range if it is contiguous, otherwise add it as a new range. */
1546 if ( idxRange > 0
1547 && pRanges->aRanges[idxRange - 1].GCPhysStart == pCur->GCPhysLast + 1U)
1548 {
1549 pRanges->aRanges[idxRange - 1].GCPhysStart = pCur->GCPhys;
1550 pRanges->aRanges[idxRange - 1].cPages += (pCur->cb >> GUEST_PAGE_SHIFT);
1551 }
1552 else
1553 {
1554 pRanges->aRanges[idxRange].GCPhysStart = pCur->GCPhys;
1555 pRanges->aRanges[idxRange].cPages = pCur->cb >> GUEST_PAGE_SHIFT;
1556 ++idxRange;
1557 }
1558 }
1559 else
1560 {
1561 rc = VERR_BUFFER_OVERFLOW;
1562 break;
1563 }
1564 }
1565 }
1566 pRanges->cRanges = idxRange;
1567 PGM_UNLOCK(pVM);
1568 return rc;
1569}
1570
1571
1572/*********************************************************************************************************************************
1573* RAM *
1574*********************************************************************************************************************************/
1575
1576/**
1577 * Frees the specified RAM page and replaces it with the ZERO page.
1578 *
1579 * This is used by ballooning, remapping MMIO2, RAM reset and state loading.
1580 *
1581 * @param pVM The cross context VM structure.
1582 * @param pReq Pointer to the request. This is NULL when doing a
1583 * bulk free in NEM memory mode.
1584 * @param pcPendingPages Where the number of pages waiting to be freed are
1585 * kept. This will normally be incremented. This is
1586 * NULL when doing a bulk free in NEM memory mode.
1587 * @param pPage Pointer to the page structure.
1588 * @param GCPhys The guest physical address of the page, if applicable.
1589 * @param enmNewType New page type for NEM notification, since several
1590 * callers will change the type upon successful return.
1591 *
1592 * @remarks The caller must own the PGM lock.
1593 */
1594int pgmPhysFreePage(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t *pcPendingPages, PPGMPAGE pPage, RTGCPHYS GCPhys,
1595 PGMPAGETYPE enmNewType)
1596{
1597 /*
1598 * Assert sanity.
1599 */
1600 PGM_LOCK_ASSERT_OWNER(pVM);
1601 if (RT_UNLIKELY( PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_RAM
1602 && PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_ROM_SHADOW))
1603 {
1604 AssertMsgFailed(("GCPhys=%RGp pPage=%R[pgmpage]\n", GCPhys, pPage));
1605 return VMSetError(pVM, VERR_PGM_PHYS_NOT_RAM, RT_SRC_POS, "GCPhys=%RGp type=%d", GCPhys, PGM_PAGE_GET_TYPE(pPage));
1606 }
1607
1608 /** @todo What about ballooning of large pages??! */
1609 Assert( PGM_PAGE_GET_PDE_TYPE(pPage) != PGM_PAGE_PDE_TYPE_PDE
1610 && PGM_PAGE_GET_PDE_TYPE(pPage) != PGM_PAGE_PDE_TYPE_PDE_DISABLED);
1611
1612 if ( PGM_PAGE_IS_ZERO(pPage)
1613 || PGM_PAGE_IS_BALLOONED(pPage))
1614 return VINF_SUCCESS;
1615
1616 const uint32_t idPage = PGM_PAGE_GET_PAGEID(pPage);
1617 Log3(("pgmPhysFreePage: idPage=%#x GCPhys=%RGp pPage=%R[pgmpage]\n", idPage, GCPhys, pPage));
1618 if (RT_UNLIKELY(!PGM_IS_IN_NEM_MODE(pVM)
1619 ? idPage == NIL_GMM_PAGEID
1620 || idPage > GMM_PAGEID_LAST
1621 || PGM_PAGE_GET_CHUNKID(pPage) == NIL_GMM_CHUNKID
1622 : idPage != NIL_GMM_PAGEID))
1623 {
1624 AssertMsgFailed(("GCPhys=%RGp pPage=%R[pgmpage]\n", GCPhys, pPage));
1625 return VMSetError(pVM, VERR_PGM_PHYS_INVALID_PAGE_ID, RT_SRC_POS, "GCPhys=%RGp idPage=%#x", GCPhys, pPage);
1626 }
1627#ifdef VBOX_WITH_NATIVE_NEM
1628 const RTHCPHYS HCPhysPrev = PGM_PAGE_GET_HCPHYS(pPage);
1629#endif
1630
1631 /* update page count stats. */
1632 if (PGM_PAGE_IS_SHARED(pPage))
1633 pVM->pgm.s.cSharedPages--;
1634 else
1635 pVM->pgm.s.cPrivatePages--;
1636 pVM->pgm.s.cZeroPages++;
1637
1638 /* Deal with write monitored pages. */
1639 if (PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED)
1640 {
1641 PGM_PAGE_SET_WRITTEN_TO(pVM, pPage);
1642 pVM->pgm.s.cWrittenToPages++;
1643 }
1644 PGM_PAGE_CLEAR_CODE_PAGE(pVM, pPage); /* No callback needed, IEMTlbInvalidateAllPhysicalAllCpus is called below. */
1645
1646 /*
1647 * pPage = ZERO page.
1648 */
1649 PGM_PAGE_SET_HCPHYS(pVM, pPage, pVM->pgm.s.HCPhysZeroPg);
1650 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ZERO);
1651 PGM_PAGE_SET_PAGEID(pVM, pPage, NIL_GMM_PAGEID);
1652 PGM_PAGE_SET_PDE_TYPE(pVM, pPage, PGM_PAGE_PDE_TYPE_DONTCARE);
1653 PGM_PAGE_SET_PTE_INDEX(pVM, pPage, 0);
1654 PGM_PAGE_SET_TRACKING(pVM, pPage, 0);
1655
1656 /* Flush physical page map TLB entry. */
1657 pgmPhysInvalidatePageMapTLBEntry(pVM, GCPhys);
1658 IEMTlbInvalidateAllPhysicalAllCpus(pVM, NIL_VMCPUID, IEMTLBPHYSFLUSHREASON_FREED); /// @todo move to the perform step.
1659
1660#ifdef VBOX_WITH_PGM_NEM_MODE
1661 /*
1662 * Skip the rest if we're doing a bulk free in NEM memory mode.
1663 */
1664 if (!pReq)
1665 return VINF_SUCCESS;
1666 AssertLogRelReturn(!pVM->pgm.s.fNemMode, VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE);
1667#endif
1668
1669#ifdef VBOX_WITH_NATIVE_NEM
1670 /* Notify NEM. */
1671 /** @todo Remove this one? */
1672 if (VM_IS_NEM_ENABLED(pVM))
1673 {
1674 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
1675 NEMHCNotifyPhysPageChanged(pVM, GCPhys, HCPhysPrev, pVM->pgm.s.HCPhysZeroPg, pVM->pgm.s.abZeroPg,
1676 pgmPhysPageCalcNemProtection(pPage, enmNewType), enmNewType, &u2State);
1677 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
1678 }
1679#else
1680 RT_NOREF(enmNewType);
1681#endif
1682
1683 /*
1684 * Make sure it's not in the handy page array.
1685 */
1686 for (uint32_t i = pVM->pgm.s.cHandyPages; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
1687 {
1688 if (pVM->pgm.s.aHandyPages[i].idPage == idPage)
1689 {
1690 pVM->pgm.s.aHandyPages[i].HCPhysGCPhys = NIL_GMMPAGEDESC_PHYS;
1691 pVM->pgm.s.aHandyPages[i].fZeroed = false;
1692 pVM->pgm.s.aHandyPages[i].idPage = NIL_GMM_PAGEID;
1693 break;
1694 }
1695 if (pVM->pgm.s.aHandyPages[i].idSharedPage == idPage)
1696 {
1697 pVM->pgm.s.aHandyPages[i].idSharedPage = NIL_GMM_PAGEID;
1698 break;
1699 }
1700 }
1701
1702 /*
1703 * Push it onto the page array.
1704 */
1705 uint32_t iPage = *pcPendingPages;
1706 Assert(iPage < PGMPHYS_FREE_PAGE_BATCH_SIZE);
1707 *pcPendingPages += 1;
1708
1709 pReq->aPages[iPage].idPage = idPage;
1710
1711 if (iPage + 1 < PGMPHYS_FREE_PAGE_BATCH_SIZE)
1712 return VINF_SUCCESS;
1713
1714 /*
1715 * Flush the pages.
1716 */
1717 int rc = GMMR3FreePagesPerform(pVM, pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE);
1718 if (RT_SUCCESS(rc))
1719 {
1720 GMMR3FreePagesRePrep(pVM, pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
1721 *pcPendingPages = 0;
1722 }
1723 return rc;
1724}
1725
1726
1727/**
1728 * Frees a range of pages, replacing them with ZERO pages of the specified type.
1729 *
1730 * @returns VBox status code.
1731 * @param pVM The cross context VM structure.
1732 * @param pRam The RAM range in which the pages resides.
1733 * @param GCPhys The address of the first page.
1734 * @param GCPhysLast The address of the last page.
1735 * @param pvMmio2 Pointer to the ring-3 mapping of any MMIO2 memory that
1736 * will replace the pages we're freeing up.
1737 */
1738static int pgmR3PhysFreePageRange(PVM pVM, PPGMRAMRANGE pRam, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, void *pvMmio2)
1739{
1740 PGM_LOCK_ASSERT_OWNER(pVM);
1741
1742#ifdef VBOX_WITH_PGM_NEM_MODE
1743 /*
1744 * In simplified memory mode we don't actually free the memory,
1745 * we just unmap it and let NEM do any unlocking of it.
1746 */
1747 if (pVM->pgm.s.fNemMode)
1748 {
1749 Assert(VM_IS_NEM_ENABLED(pVM) || VM_IS_EXEC_ENGINE_IEM(pVM));
1750 uint8_t u2State = 0; /* (We don't support UINT8_MAX here.) */
1751 if (VM_IS_NEM_ENABLED(pVM))
1752 {
1753 uint32_t const fNemNotify = (pvMmio2 ? NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2 : 0) | NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE;
1754 int rc = NEMR3NotifyPhysMmioExMapEarly(pVM, GCPhys, GCPhysLast - GCPhys + 1, fNemNotify,
1755 pRam->pbR3 ? pRam->pbR3 + GCPhys - pRam->GCPhys : NULL,
1756 pvMmio2, &u2State, NULL /*puNemRange*/);
1757 AssertLogRelRCReturn(rc, rc);
1758 }
1759
1760 /* Iterate the pages. */
1761 PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> GUEST_PAGE_SHIFT];
1762 uint32_t cPagesLeft = ((GCPhysLast - GCPhys) >> GUEST_PAGE_SHIFT) + 1;
1763 while (cPagesLeft-- > 0)
1764 {
1765 int rc = pgmPhysFreePage(pVM, NULL, NULL, pPageDst, GCPhys, PGMPAGETYPE_MMIO);
1766 AssertLogRelRCReturn(rc, rc); /* We're done for if this goes wrong. */
1767
1768 PGM_PAGE_SET_TYPE(pVM, pPageDst, PGMPAGETYPE_MMIO);
1769 PGM_PAGE_SET_NEM_STATE(pPageDst, u2State);
1770
1771 GCPhys += GUEST_PAGE_SIZE;
1772 pPageDst++;
1773 }
1774 return VINF_SUCCESS;
1775 }
1776#else /* !VBOX_WITH_PGM_NEM_MODE */
1777 RT_NOREF(pvMmio2);
1778#endif /* !VBOX_WITH_PGM_NEM_MODE */
1779
1780 /*
1781 * Regular mode.
1782 */
1783 /* Prepare. */
1784 uint32_t cPendingPages = 0;
1785 PGMMFREEPAGESREQ pReq;
1786 int rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
1787 AssertLogRelRCReturn(rc, rc);
1788
1789#ifdef VBOX_WITH_NATIVE_NEM
1790 /* Tell NEM up-front. */
1791 uint8_t u2State = UINT8_MAX;
1792 if (VM_IS_NEM_ENABLED(pVM))
1793 {
1794 uint32_t const fNemNotify = (pvMmio2 ? NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2 : 0) | NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE;
1795 rc = NEMR3NotifyPhysMmioExMapEarly(pVM, GCPhys, GCPhysLast - GCPhys + 1, fNemNotify, NULL, pvMmio2,
1796 &u2State, NULL /*puNemRange*/);
1797 AssertLogRelRCReturnStmt(rc, GMMR3FreePagesCleanup(pReq), rc);
1798 }
1799#endif
1800
1801 /* Iterate the pages. */
1802 PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> GUEST_PAGE_SHIFT];
1803 uint32_t cPagesLeft = ((GCPhysLast - GCPhys) >> GUEST_PAGE_SHIFT) + 1;
1804 while (cPagesLeft-- > 0)
1805 {
1806 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPageDst, GCPhys, PGMPAGETYPE_MMIO);
1807 AssertLogRelRCReturn(rc, rc); /* We're done for if this goes wrong. */
1808
1809 PGM_PAGE_SET_TYPE(pVM, pPageDst, PGMPAGETYPE_MMIO);
1810#ifdef VBOX_WITH_NATIVE_NEM
1811 if (u2State != UINT8_MAX)
1812 PGM_PAGE_SET_NEM_STATE(pPageDst, u2State);
1813#endif
1814
1815 GCPhys += GUEST_PAGE_SIZE;
1816 pPageDst++;
1817 }
1818
1819 /* Finish pending and cleanup. */
1820 if (cPendingPages)
1821 {
1822 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
1823 AssertLogRelRCReturn(rc, rc);
1824 }
1825 GMMR3FreePagesCleanup(pReq);
1826
1827 return rc;
1828}
1829
1830
1831/**
1832 * Wrapper around VMMR0_DO_PGM_PHYS_ALLOCATE_RAM_RANGE.
1833 */
1834static int pgmR3PhysAllocateRamRange(PVM pVM, PVMCPU pVCpu, uint32_t cGuestPages, uint32_t fFlags, PPGMRAMRANGE *ppRamRange)
1835{
1836 int rc;
1837 PGMPHYSALLOCATERAMRANGEREQ AllocRangeReq;
1838 AllocRangeReq.idNewRange = UINT32_MAX / 4;
1839 if (SUPR3IsDriverless())
1840 rc = pgmPhysRamRangeAllocCommon(pVM, cGuestPages, fFlags, &AllocRangeReq.idNewRange);
1841 else
1842 {
1843 AllocRangeReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1844 AllocRangeReq.Hdr.cbReq = sizeof(AllocRangeReq);
1845 AllocRangeReq.cbGuestPage = GUEST_PAGE_SIZE;
1846 AllocRangeReq.cGuestPages = cGuestPages;
1847 AllocRangeReq.fFlags = fFlags;
1848 rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_PGM_PHYS_ALLOCATE_RAM_RANGE, 0 /*u64Arg*/, &AllocRangeReq.Hdr);
1849 }
1850 if (RT_SUCCESS(rc))
1851 {
1852 Assert(AllocRangeReq.idNewRange != 0);
1853 Assert(AllocRangeReq.idNewRange < RT_ELEMENTS(pVM->pgm.s.apRamRanges));
1854 AssertPtr(pVM->pgm.s.apRamRanges[AllocRangeReq.idNewRange]);
1855 *ppRamRange = pVM->pgm.s.apRamRanges[AllocRangeReq.idNewRange];
1856 return VINF_SUCCESS;
1857 }
1858
1859 *ppRamRange = NULL;
1860 return rc;
1861}
1862
1863
1864/**
1865 * PGMR3PhysRegisterRam worker that initializes and links a RAM range.
1866 *
1867 * In NEM mode, this will allocate the pages backing the RAM range and this may
1868 * fail. NEM registration may also fail. (In regular HM mode it won't fail.)
1869 *
1870 * @returns VBox status code.
1871 * @param pVM The cross context VM structure.
1872 * @param pNew The new RAM range.
1873 * @param GCPhys The address of the RAM range.
1874 * @param GCPhysLast The last address of the RAM range.
1875 * @param pszDesc The description.
1876 * @param pidxLookup The lookup table insertion point.
1877 */
1878static int pgmR3PhysInitAndLinkRamRange(PVM pVM, PPGMRAMRANGE pNew, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
1879 const char *pszDesc, uint32_t *pidxLookup)
1880{
1881 /*
1882 * Initialize the range.
1883 */
1884 Assert(pNew->cb == GCPhysLast - GCPhys + 1U); RT_NOREF(GCPhysLast);
1885 pNew->pszDesc = pszDesc;
1886 pNew->uNemRange = UINT32_MAX;
1887 pNew->pbR3 = NULL;
1888 pNew->paLSPages = NULL;
1889
1890 uint32_t const cPages = pNew->cb >> GUEST_PAGE_SHIFT;
1891#ifdef VBOX_WITH_PGM_NEM_MODE
1892 if (!pVM->pgm.s.fNemMode)
1893#endif
1894 {
1895 RTGCPHYS iPage = cPages;
1896 while (iPage-- > 0)
1897 PGM_PAGE_INIT_ZERO(&pNew->aPages[iPage], pVM, PGMPAGETYPE_RAM);
1898
1899 /* Update the page count stats. */
1900 pVM->pgm.s.cZeroPages += cPages;
1901 pVM->pgm.s.cAllPages += cPages;
1902 }
1903#ifdef VBOX_WITH_PGM_NEM_MODE
1904 else
1905 {
1906 int rc = SUPR3PageAlloc(RT_ALIGN_Z(pNew->cb, HOST_PAGE_SIZE) >> HOST_PAGE_SHIFT,
1907 pVM->pgm.s.fUseLargePages ? SUP_PAGE_ALLOC_F_LARGE_PAGES : 0, (void **)&pNew->pbR3);
1908 if (RT_FAILURE(rc))
1909 return rc;
1910
1911 RTGCPHYS iPage = cPages;
1912 while (iPage-- > 0)
1913 PGM_PAGE_INIT(&pNew->aPages[iPage], UINT64_C(0x0000fffffffff000), NIL_GMM_PAGEID,
1914 PGMPAGETYPE_RAM, PGM_PAGE_STATE_ALLOCATED);
1915
1916 /* Update the page count stats. */
1917 pVM->pgm.s.cPrivatePages += cPages;
1918 pVM->pgm.s.cAllPages += cPages;
1919 }
1920#endif
1921
1922 /*
1923 * Insert it into the lookup table.
1924 */
1925 int rc = pgmR3PhysRamRangeInsertLookup(pVM, pNew, GCPhys, pidxLookup);
1926 AssertRCReturn(rc, rc);
1927
1928#ifdef VBOX_WITH_NATIVE_NEM
1929 /*
1930 * Notify NEM now that it has been linked.
1931 *
1932 * As above, it is assumed that on failure the VM creation will fail, so
1933 * no extra cleanup is needed here.
1934 */
1935 if (VM_IS_NEM_ENABLED(pVM))
1936 {
1937 uint8_t u2State = UINT8_MAX;
1938 rc = NEMR3NotifyPhysRamRegister(pVM, GCPhys, pNew->cb, pNew->pbR3, &u2State, &pNew->uNemRange);
1939 if (RT_SUCCESS(rc) && u2State != UINT8_MAX)
1940 pgmPhysSetNemStateForPages(&pNew->aPages[0], cPages, u2State);
1941 return rc;
1942 }
1943#endif
1944 return VINF_SUCCESS;
1945}
1946
1947
1948/**
1949 * Worker for PGMR3PhysRegisterRam called with the PGM lock.
1950 *
1951 * The caller releases the lock.
1952 */
1953static int pgmR3PhysRegisterRamWorker(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, RTGCPHYS cb, const char *pszDesc,
1954 uint32_t const cRamRanges, RTGCPHYS const GCPhysLast)
1955{
1956#ifdef VBOX_STRICT
1957 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, false /*fRamRelaxed*/);
1958#endif
1959
1960 /*
1961 * Check that we've got enough free RAM ranges.
1962 */
1963 AssertLogRelMsgReturn((uint64_t)pVM->pgm.s.idRamRangeMax + cRamRanges + 1 <= RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup),
1964 ("idRamRangeMax=%#RX32 vs GCPhys=%RGp cb=%RGp / %#RX32 ranges (%s)\n",
1965 pVM->pgm.s.idRamRangeMax, GCPhys, cb, cRamRanges, pszDesc),
1966 VERR_PGM_TOO_MANY_RAM_RANGES);
1967
1968 /*
1969 * Check for conflicts via the lookup table. We search it backwards,
1970 * assuming that memory is added in ascending order by address.
1971 */
1972 uint32_t idxLookup = pVM->pgm.s.RamRangeUnion.cLookupEntries;
1973 while (idxLookup)
1974 {
1975 if (GCPhys > pVM->pgm.s.aRamRangeLookup[idxLookup - 1].GCPhysLast)
1976 break;
1977 idxLookup--;
1978 RTGCPHYS const GCPhysCur = PGMRAMRANGELOOKUPENTRY_GET_FIRST(pVM->pgm.s.aRamRangeLookup[idxLookup]);
1979 AssertLogRelMsgReturn( GCPhysLast < GCPhysCur
1980 || GCPhys > pVM->pgm.s.aRamRangeLookup[idxLookup].GCPhysLast,
1981 ("%RGp-%RGp (%s) conflicts with existing %RGp-%RGp (%s)\n",
1982 GCPhys, GCPhysLast, pszDesc, GCPhysCur, pVM->pgm.s.aRamRangeLookup[idxLookup].GCPhysLast,
1983 pVM->pgm.s.apRamRanges[PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup])]->pszDesc),
1984 VERR_PGM_RAM_CONFLICT);
1985 }
1986
1987 /*
1988 * Register it with GMM (the API bitches).
1989 */
1990 const RTGCPHYS cPages = cb >> GUEST_PAGE_SHIFT;
1991 int rc = MMR3IncreaseBaseReservation(pVM, cPages);
1992 if (RT_FAILURE(rc))
1993 return rc;
1994
1995 /*
1996 * Create the required chunks.
1997 */
1998 RTGCPHYS cPagesLeft = cPages;
1999 RTGCPHYS GCPhysChunk = GCPhys;
2000 uint32_t idxChunk = 0;
2001 while (cPagesLeft > 0)
2002 {
2003 uint32_t cPagesInChunk = cPagesLeft;
2004 if (cPagesInChunk > PGM_MAX_PAGES_PER_RAM_RANGE)
2005 cPagesInChunk = PGM_MAX_PAGES_PER_RAM_RANGE;
2006
2007 const char *pszDescChunk = idxChunk == 0
2008 ? pszDesc
2009 : MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS, "%s (#%u)", pszDesc, idxChunk + 1);
2010 AssertReturn(pszDescChunk, VERR_NO_MEMORY);
2011
2012 /*
2013 * Allocate a RAM range.
2014 */
2015 PPGMRAMRANGE pNew = NULL;
2016 rc = pgmR3PhysAllocateRamRange(pVM, pVCpu, cPagesInChunk, 0 /*fFlags*/, &pNew);
2017 AssertLogRelMsgReturn(RT_SUCCESS(rc),
2018 ("pgmR3PhysAllocateRamRange failed: GCPhysChunk=%RGp cPagesInChunk=%#RX32 (%s): %Rrc\n",
2019 GCPhysChunk, cPagesInChunk, pszDescChunk, rc),
2020 rc);
2021
2022 /*
2023 * Ok, init and link the range.
2024 */
2025 rc = pgmR3PhysInitAndLinkRamRange(pVM, pNew, GCPhysChunk,
2026 GCPhysChunk + ((RTGCPHYS)cPagesInChunk << GUEST_PAGE_SHIFT) - 1U,
2027 pszDescChunk, &idxLookup);
2028 AssertLogRelMsgReturn(RT_SUCCESS(rc),
2029 ("pgmR3PhysInitAndLinkRamRange failed: GCPhysChunk=%RGp cPagesInChunk=%#RX32 (%s): %Rrc\n",
2030 GCPhysChunk, cPagesInChunk, pszDescChunk, rc),
2031 rc);
2032
2033 /* advance */
2034 GCPhysChunk += (RTGCPHYS)cPagesInChunk << GUEST_PAGE_SHIFT;
2035 cPagesLeft -= cPagesInChunk;
2036 idxChunk++;
2037 }
2038
2039 return rc;
2040}
2041
2042
2043/**
2044 * Sets up a range RAM.
2045 *
2046 * This will check for conflicting registrations, make a resource reservation
2047 * for the memory (with GMM), and setup the per-page tracking structures
2048 * (PGMPAGE).
2049 *
2050 * @returns VBox status code.
2051 * @param pVM The cross context VM structure.
2052 * @param GCPhys The physical address of the RAM.
2053 * @param cb The size of the RAM.
2054 * @param pszDesc The description - not copied, so, don't free or change it.
2055 */
2056VMMR3DECL(int) PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, const char *pszDesc)
2057{
2058 /*
2059 * Validate input.
2060 */
2061 Log(("PGMR3PhysRegisterRam: GCPhys=%RGp cb=%RGp pszDesc=%s\n", GCPhys, cb, pszDesc));
2062 AssertReturn(RT_ALIGN_T(GCPhys, GUEST_PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
2063 AssertReturn(RT_ALIGN_T(cb, GUEST_PAGE_SIZE, RTGCPHYS) == cb, VERR_INVALID_PARAMETER);
2064 AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
2065 RTGCPHYS const GCPhysLast = GCPhys + (cb - 1);
2066 AssertMsgReturn(GCPhysLast > GCPhys, ("The range wraps! GCPhys=%RGp cb=%RGp\n", GCPhys, cb), VERR_INVALID_PARAMETER);
2067 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
2068 PVMCPU const pVCpu = VMMGetCpu(pVM);
2069 AssertReturn(pVCpu, VERR_VM_THREAD_NOT_EMT);
2070 AssertReturn(pVCpu->idCpu == 0, VERR_VM_THREAD_NOT_EMT);
2071
2072 /*
2073 * Calculate the number of RAM ranges required.
2074 * See also pgmPhysMmio2CalcChunkCount.
2075 */
2076 uint32_t const cPagesPerChunk = PGM_MAX_PAGES_PER_RAM_RANGE;
2077 uint32_t const cRamRanges = (uint32_t)(((cb >> GUEST_PAGE_SHIFT) + cPagesPerChunk - 1) / cPagesPerChunk);
2078 AssertLogRelMsgReturn(cRamRanges * (RTGCPHYS)cPagesPerChunk * GUEST_PAGE_SIZE >= cb,
2079 ("cb=%RGp cRamRanges=%#RX32 cPagesPerChunk=%#RX32\n", cb, cRamRanges, cPagesPerChunk),
2080 VERR_OUT_OF_RANGE);
2081
2082 PGM_LOCK_VOID(pVM);
2083
2084 int rc = pgmR3PhysRegisterRamWorker(pVM, pVCpu, GCPhys, cb, pszDesc, cRamRanges, GCPhysLast);
2085#ifdef VBOX_STRICT
2086 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, false /*fRamRelaxed*/);
2087#endif
2088
2089 PGM_UNLOCK(pVM);
2090 return rc;
2091}
2092
2093
2094/**
2095 * Worker called by PGMR3InitFinalize if we're configured to pre-allocate RAM.
2096 *
2097 * We do this late in the init process so that all the ROM and MMIO ranges have
2098 * been registered already and we don't go wasting memory on them.
2099 *
2100 * @returns VBox status code.
2101 *
2102 * @param pVM The cross context VM structure.
2103 */
2104int pgmR3PhysRamPreAllocate(PVM pVM)
2105{
2106 Assert(pVM->pgm.s.fRamPreAlloc);
2107 Log(("pgmR3PhysRamPreAllocate: enter\n"));
2108#ifdef VBOX_WITH_PGM_NEM_MODE
2109 AssertLogRelReturn(!pVM->pgm.s.fNemMode, VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE);
2110#endif
2111
2112 /*
2113 * Walk the RAM ranges and allocate all RAM pages, halt at
2114 * the first allocation error.
2115 */
2116 uint64_t cPages = 0;
2117 uint64_t NanoTS = RTTimeNanoTS();
2118 PGM_LOCK_VOID(pVM);
2119 uint32_t const cLookupEntries = RT_MIN(pVM->pgm.s.RamRangeUnion.cLookupEntries, RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup));
2120 for (uint32_t idxLookup = 0; idxLookup < cLookupEntries; idxLookup++)
2121 {
2122 uint32_t const idRamRange = PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup]);
2123 AssertContinue(idRamRange < RT_ELEMENTS(pVM->pgm.s.apRamRanges));
2124 PPGMRAMRANGE const pRam = pVM->pgm.s.apRamRanges[idRamRange];
2125 AssertContinue(pRam);
2126
2127 PPGMPAGE pPage = &pRam->aPages[0];
2128 RTGCPHYS GCPhys = pRam->GCPhys;
2129 uint32_t cLeft = pRam->cb >> GUEST_PAGE_SHIFT;
2130 while (cLeft-- > 0)
2131 {
2132 if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM)
2133 {
2134 switch (PGM_PAGE_GET_STATE(pPage))
2135 {
2136 case PGM_PAGE_STATE_ZERO:
2137 {
2138 int rc = pgmPhysAllocPage(pVM, pPage, GCPhys);
2139 if (RT_FAILURE(rc))
2140 {
2141 LogRel(("PGM: RAM Pre-allocation failed at %RGp (in %s) with rc=%Rrc\n", GCPhys, pRam->pszDesc, rc));
2142 PGM_UNLOCK(pVM);
2143 return rc;
2144 }
2145 cPages++;
2146 break;
2147 }
2148
2149 case PGM_PAGE_STATE_BALLOONED:
2150 case PGM_PAGE_STATE_ALLOCATED:
2151 case PGM_PAGE_STATE_WRITE_MONITORED:
2152 case PGM_PAGE_STATE_SHARED:
2153 /* nothing to do here. */
2154 break;
2155 }
2156 }
2157
2158 /* next */
2159 pPage++;
2160 GCPhys += GUEST_PAGE_SIZE;
2161 }
2162 }
2163 PGM_UNLOCK(pVM);
2164 NanoTS = RTTimeNanoTS() - NanoTS;
2165
2166 LogRel(("PGM: Pre-allocated %llu pages in %llu ms\n", cPages, NanoTS / 1000000));
2167 Log(("pgmR3PhysRamPreAllocate: returns VINF_SUCCESS\n"));
2168 return VINF_SUCCESS;
2169}
2170
2171
2172/**
2173 * Checks shared page checksums.
2174 *
2175 * @param pVM The cross context VM structure.
2176 */
2177void pgmR3PhysAssertSharedPageChecksums(PVM pVM)
2178{
2179#ifdef VBOX_STRICT
2180 PGM_LOCK_VOID(pVM);
2181
2182 if (pVM->pgm.s.cSharedPages > 0)
2183 {
2184 /*
2185 * Walk the ram ranges.
2186 */
2187 uint32_t const cLookupEntries = RT_MIN(pVM->pgm.s.RamRangeUnion.cLookupEntries, RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup));
2188 for (uint32_t idxLookup = 0; idxLookup < cLookupEntries; idxLookup++)
2189 {
2190 uint32_t const idRamRange = PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup]);
2191 AssertContinue(idRamRange < RT_ELEMENTS(pVM->pgm.s.apRamRanges));
2192 PPGMRAMRANGE const pRam = pVM->pgm.s.apRamRanges[idRamRange];
2193 AssertContinue(pRam);
2194
2195 uint32_t iPage = pRam->cb >> GUEST_PAGE_SHIFT;
2196 AssertMsg(((RTGCPHYS)iPage << GUEST_PAGE_SHIFT) == pRam->cb,
2197 ("%RGp %RGp\n", (RTGCPHYS)iPage << GUEST_PAGE_SHIFT, pRam->cb));
2198
2199 while (iPage-- > 0)
2200 {
2201 PPGMPAGE pPage = &pRam->aPages[iPage];
2202 if (PGM_PAGE_IS_SHARED(pPage))
2203 {
2204 uint32_t u32Checksum = pPage->s.u2Unused0/* | ((uint32_t)pPage->s.u2Unused1 << 8)*/;
2205 if (!u32Checksum)
2206 {
2207 RTGCPHYS GCPhysPage = pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT);
2208 void const *pvPage;
2209 int rc = pgmPhysPageMapReadOnly(pVM, pPage, GCPhysPage, &pvPage);
2210 if (RT_SUCCESS(rc))
2211 {
2212 uint32_t u32Checksum2 = RTCrc32(pvPage, GUEST_PAGE_SIZE);
2213# if 0
2214 AssertMsg((u32Checksum2 & /*UINT32_C(0x00000303)*/ 0x3) == u32Checksum, ("GCPhysPage=%RGp\n", GCPhysPage));
2215# else
2216 if ((u32Checksum2 & /*UINT32_C(0x00000303)*/ 0x3) == u32Checksum)
2217 LogFlow(("shpg %#x @ %RGp %#x [OK]\n", PGM_PAGE_GET_PAGEID(pPage), GCPhysPage, u32Checksum2));
2218 else
2219 AssertMsgFailed(("shpg %#x @ %RGp %#x\n", PGM_PAGE_GET_PAGEID(pPage), GCPhysPage, u32Checksum2));
2220# endif
2221 }
2222 else
2223 AssertRC(rc);
2224 }
2225 }
2226
2227 } /* for each page */
2228
2229 } /* for each ram range */
2230 }
2231
2232 PGM_UNLOCK(pVM);
2233#endif /* VBOX_STRICT */
2234 NOREF(pVM);
2235}
2236
2237
2238/**
2239 * Resets the physical memory state.
2240 *
2241 * ASSUMES that the caller owns the PGM lock.
2242 *
2243 * @returns VBox status code.
2244 * @param pVM The cross context VM structure.
2245 */
2246int pgmR3PhysRamReset(PVM pVM)
2247{
2248 PGM_LOCK_ASSERT_OWNER(pVM);
2249
2250 /* Reset the memory balloon. */
2251 int rc = GMMR3BalloonedPages(pVM, GMMBALLOONACTION_RESET, 0);
2252 AssertRC(rc);
2253
2254#ifdef VBOX_WITH_PAGE_SHARING
2255 /* Clear all registered shared modules. */
2256 pgmR3PhysAssertSharedPageChecksums(pVM);
2257 rc = GMMR3ResetSharedModules(pVM);
2258 AssertRC(rc);
2259#endif
2260 /* Reset counters. */
2261 pVM->pgm.s.cReusedSharedPages = 0;
2262 pVM->pgm.s.cBalloonedPages = 0;
2263
2264 return VINF_SUCCESS;
2265}
2266
2267
2268/**
2269 * Resets (zeros) the RAM after all devices and components have been reset.
2270 *
2271 * ASSUMES that the caller owns the PGM lock.
2272 *
2273 * @returns VBox status code.
2274 * @param pVM The cross context VM structure.
2275 */
2276int pgmR3PhysRamZeroAll(PVM pVM)
2277{
2278 PGM_LOCK_ASSERT_OWNER(pVM);
2279
2280 /*
2281 * We batch up pages that should be freed instead of calling GMM for
2282 * each and every one of them.
2283 */
2284 uint32_t cPendingPages = 0;
2285 PGMMFREEPAGESREQ pReq;
2286 int rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
2287 AssertLogRelRCReturn(rc, rc);
2288
2289 /*
2290 * Walk the ram ranges.
2291 */
2292 uint32_t const idRamRangeMax = RT_MIN(pVM->pgm.s.idRamRangeMax, RT_ELEMENTS(pVM->pgm.s.apRamRanges) - 1U);
2293 for (uint32_t idRamRange = 0; idRamRange <= idRamRangeMax; idRamRange++)
2294 {
2295 PPGMRAMRANGE const pRam = pVM->pgm.s.apRamRanges[idRamRange];
2296 Assert(pRam || idRamRange == 0);
2297 if (!pRam) continue;
2298 Assert(pRam->idRange == idRamRange);
2299
2300 uint32_t iPage = pRam->cb >> GUEST_PAGE_SHIFT;
2301 AssertMsg(((RTGCPHYS)iPage << GUEST_PAGE_SHIFT) == pRam->cb, ("%RGp %RGp\n", (RTGCPHYS)iPage << GUEST_PAGE_SHIFT, pRam->cb));
2302
2303 if ( !pVM->pgm.s.fRamPreAlloc
2304#ifdef VBOX_WITH_PGM_NEM_MODE
2305 && !pVM->pgm.s.fNemMode
2306#endif
2307 && pVM->pgm.s.fZeroRamPagesOnReset)
2308 {
2309 /* Replace all RAM pages by ZERO pages. */
2310 while (iPage-- > 0)
2311 {
2312 PPGMPAGE pPage = &pRam->aPages[iPage];
2313 switch (PGM_PAGE_GET_TYPE(pPage))
2314 {
2315 case PGMPAGETYPE_RAM:
2316 /* Do not replace pages part of a 2 MB continuous range
2317 with zero pages, but zero them instead. */
2318 if ( PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE
2319 || PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE_DISABLED)
2320 {
2321 void *pvPage;
2322 rc = pgmPhysPageMap(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT), &pvPage);
2323 AssertLogRelRCReturn(rc, rc);
2324 RT_BZERO(pvPage, GUEST_PAGE_SIZE);
2325 }
2326 else if (PGM_PAGE_IS_BALLOONED(pPage))
2327 {
2328 /* Turn into a zero page; the balloon status is lost when the VM reboots. */
2329 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ZERO);
2330 }
2331 else if (!PGM_PAGE_IS_ZERO(pPage))
2332 {
2333 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage,
2334 pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT), PGMPAGETYPE_RAM);
2335 AssertLogRelRCReturn(rc, rc);
2336 }
2337 break;
2338
2339 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
2340 case PGMPAGETYPE_SPECIAL_ALIAS_MMIO: /** @todo perhaps leave the special page alone? I don't think VT-x copes with this code. */
2341 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT),
2342 pRam, true /*fDoAccounting*/, false /*fFlushIemTlbs*/);
2343 break;
2344
2345 case PGMPAGETYPE_MMIO2:
2346 case PGMPAGETYPE_ROM_SHADOW: /* handled by pgmR3PhysRomReset. */
2347 case PGMPAGETYPE_ROM:
2348 case PGMPAGETYPE_MMIO:
2349 break;
2350 default:
2351 AssertFailed();
2352 }
2353 } /* for each page */
2354 }
2355 else
2356 {
2357 /* Zero the memory. */
2358 while (iPage-- > 0)
2359 {
2360 PPGMPAGE pPage = &pRam->aPages[iPage];
2361 switch (PGM_PAGE_GET_TYPE(pPage))
2362 {
2363 case PGMPAGETYPE_RAM:
2364 switch (PGM_PAGE_GET_STATE(pPage))
2365 {
2366 case PGM_PAGE_STATE_ZERO:
2367 break;
2368
2369 case PGM_PAGE_STATE_BALLOONED:
2370 /* Turn into a zero page; the balloon status is lost when the VM reboots. */
2371 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ZERO);
2372 break;
2373
2374 case PGM_PAGE_STATE_SHARED:
2375 case PGM_PAGE_STATE_WRITE_MONITORED:
2376 rc = pgmPhysPageMakeWritable(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT));
2377 AssertLogRelRCReturn(rc, rc);
2378 RT_FALL_THRU();
2379
2380 case PGM_PAGE_STATE_ALLOCATED:
2381 if (pVM->pgm.s.fZeroRamPagesOnReset)
2382 {
2383 void *pvPage;
2384 rc = pgmPhysPageMap(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT), &pvPage);
2385 AssertLogRelRCReturn(rc, rc);
2386 RT_BZERO(pvPage, GUEST_PAGE_SIZE);
2387 }
2388 break;
2389 }
2390 break;
2391
2392 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
2393 case PGMPAGETYPE_SPECIAL_ALIAS_MMIO: /** @todo perhaps leave the special page alone? I don't think VT-x copes with this code. */
2394 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT),
2395 pRam, true /*fDoAccounting*/, false /*fFlushIemTlbs*/);
2396 break;
2397
2398 case PGMPAGETYPE_MMIO2:
2399 case PGMPAGETYPE_ROM_SHADOW:
2400 case PGMPAGETYPE_ROM:
2401 case PGMPAGETYPE_MMIO:
2402 break;
2403 default:
2404 AssertFailed();
2405
2406 }
2407 } /* for each page */
2408 }
2409 }
2410
2411 /*
2412 * Finish off any pages pending freeing.
2413 */
2414 if (cPendingPages)
2415 {
2416 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
2417 AssertLogRelRCReturn(rc, rc);
2418 }
2419 GMMR3FreePagesCleanup(pReq);
2420
2421 /*
2422 * Flush the IEM TLB, just to be sure it really is done.
2423 */
2424 IEMTlbInvalidateAllPhysicalAllCpus(pVM, NIL_VMCPUID, IEMTLBPHYSFLUSHREASON_ZERO_ALL);
2425
2426 return VINF_SUCCESS;
2427}
2428
2429
2430/**
2431 * Frees all RAM during VM termination
2432 *
2433 * ASSUMES that the caller owns the PGM lock.
2434 *
2435 * @returns VBox status code.
2436 * @param pVM The cross context VM structure.
2437 */
2438int pgmR3PhysRamTerm(PVM pVM)
2439{
2440 PGM_LOCK_ASSERT_OWNER(pVM);
2441
2442 /* Reset the memory balloon. */
2443 int rc = GMMR3BalloonedPages(pVM, GMMBALLOONACTION_RESET, 0);
2444 AssertRC(rc);
2445
2446#ifdef VBOX_WITH_PAGE_SHARING
2447 /*
2448 * Clear all registered shared modules.
2449 */
2450 pgmR3PhysAssertSharedPageChecksums(pVM);
2451 rc = GMMR3ResetSharedModules(pVM);
2452 AssertRC(rc);
2453
2454 /*
2455 * Flush the handy pages updates to make sure no shared pages are hiding
2456 * in there. (Not unlikely if the VM shuts down, apparently.)
2457 */
2458# ifdef VBOX_WITH_PGM_NEM_MODE
2459 if (!pVM->pgm.s.fNemMode)
2460# endif
2461 rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_FLUSH_HANDY_PAGES, 0, NULL);
2462#endif
2463
2464 /*
2465 * We batch up pages that should be freed instead of calling GMM for
2466 * each and every one of them.
2467 */
2468 uint32_t cPendingPages = 0;
2469 PGMMFREEPAGESREQ pReq;
2470 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
2471 AssertLogRelRCReturn(rc, rc);
2472
2473 /*
2474 * Walk the ram ranges.
2475 */
2476 uint32_t const idRamRangeMax = RT_MIN(pVM->pgm.s.idRamRangeMax, RT_ELEMENTS(pVM->pgm.s.apRamRanges) - 1U);
2477 for (uint32_t idRamRange = 0; idRamRange <= idRamRangeMax; idRamRange++)
2478 {
2479 PPGMRAMRANGE const pRam = pVM->pgm.s.apRamRanges[idRamRange];
2480 Assert(pRam || idRamRange == 0);
2481 if (!pRam) continue;
2482 Assert(pRam->idRange == idRamRange);
2483
2484 uint32_t iPage = pRam->cb >> GUEST_PAGE_SHIFT;
2485 AssertMsg(((RTGCPHYS)iPage << GUEST_PAGE_SHIFT) == pRam->cb, ("%RGp %RGp\n", (RTGCPHYS)iPage << GUEST_PAGE_SHIFT, pRam->cb));
2486
2487 while (iPage-- > 0)
2488 {
2489 PPGMPAGE pPage = &pRam->aPages[iPage];
2490 switch (PGM_PAGE_GET_TYPE(pPage))
2491 {
2492 case PGMPAGETYPE_RAM:
2493 /* Free all shared pages. Private pages are automatically freed during GMM VM cleanup. */
2494 /** @todo change this to explicitly free private pages here. */
2495 if (PGM_PAGE_IS_SHARED(pPage))
2496 {
2497 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage,
2498 pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT), PGMPAGETYPE_RAM);
2499 AssertLogRelRCReturn(rc, rc);
2500 }
2501 break;
2502
2503 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
2504 case PGMPAGETYPE_SPECIAL_ALIAS_MMIO:
2505 case PGMPAGETYPE_MMIO2:
2506 case PGMPAGETYPE_ROM_SHADOW: /* handled by pgmR3PhysRomReset. */
2507 case PGMPAGETYPE_ROM:
2508 case PGMPAGETYPE_MMIO:
2509 break;
2510 default:
2511 AssertFailed();
2512 }
2513 } /* for each page */
2514 }
2515
2516 /*
2517 * Finish off any pages pending freeing.
2518 */
2519 if (cPendingPages)
2520 {
2521 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
2522 AssertLogRelRCReturn(rc, rc);
2523 }
2524 GMMR3FreePagesCleanup(pReq);
2525 return VINF_SUCCESS;
2526}
2527
2528
2529
2530/*********************************************************************************************************************************
2531* MMIO *
2532*********************************************************************************************************************************/
2533
2534/**
2535 * This is the interface IOM is using to register an MMIO region (unmapped).
2536 *
2537 *
2538 * @returns VBox status code.
2539 *
2540 * @param pVM The cross context VM structure.
2541 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2542 * @param cb The size of the MMIO region.
2543 * @param pszDesc The description of the MMIO region.
2544 * @param pidRamRange Where to return the RAM range ID for the MMIO region
2545 * on success.
2546 * @thread EMT(0)
2547 */
2548VMMR3_INT_DECL(int) PGMR3PhysMmioRegister(PVM pVM, PVMCPU pVCpu, RTGCPHYS cb, const char *pszDesc, uint16_t *pidRamRange)
2549{
2550 /*
2551 * Assert assumptions.
2552 */
2553 AssertPtrReturn(pidRamRange, VERR_INVALID_POINTER);
2554 *pidRamRange = UINT16_MAX;
2555 AssertReturn(pVCpu == VMMGetCpu(pVM) && pVCpu->idCpu == 0, VERR_VM_THREAD_NOT_EMT);
2556 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
2557 /// @todo AssertReturn(!pVM->pgm.s.fRamRangesFrozen, VERR_WRONG_ORDER);
2558 AssertReturn(cb <= ((RTGCPHYS)PGM_MAX_PAGES_PER_RAM_RANGE << GUEST_PAGE_SHIFT), VERR_OUT_OF_RANGE);
2559 AssertReturn(!(cb & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2560 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
2561 AssertReturn(*pszDesc != '\0', VERR_INVALID_POINTER);
2562
2563 /*
2564 * Take the PGM lock and allocate an ad-hoc MMIO RAM range.
2565 */
2566 int rc = PGM_LOCK(pVM);
2567 AssertRCReturn(rc, rc);
2568
2569 uint32_t const cPages = cb >> GUEST_PAGE_SHIFT;
2570 PPGMRAMRANGE pNew = NULL;
2571 rc = pgmR3PhysAllocateRamRange(pVM, pVCpu, cPages, PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO, &pNew);
2572 AssertLogRelMsg(RT_SUCCESS(rc), ("pgmR3PhysAllocateRamRange failed: cPages=%#RX32 (%s): %Rrc\n", cPages, pszDesc, rc));
2573 if (RT_SUCCESS(rc))
2574 {
2575 /* Initialize the range. */
2576 pNew->pszDesc = pszDesc;
2577 pNew->uNemRange = UINT32_MAX;
2578 pNew->pbR3 = NULL;
2579 pNew->paLSPages = NULL;
2580 Assert(pNew->fFlags == PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO && pNew->cb == cb);
2581
2582 uint32_t iPage = cPages;
2583 while (iPage-- > 0)
2584 PGM_PAGE_INIT_ZERO(&pNew->aPages[iPage], pVM, PGMPAGETYPE_MMIO);
2585 Assert(PGM_PAGE_GET_TYPE(&pNew->aPages[0]) == PGMPAGETYPE_MMIO);
2586
2587 /* update the page count stats. */
2588 pVM->pgm.s.cPureMmioPages += cPages;
2589 pVM->pgm.s.cAllPages += cPages;
2590
2591 /*
2592 * Set the return value, release lock and return to IOM.
2593 */
2594 *pidRamRange = pNew->idRange;
2595 }
2596
2597 PGM_UNLOCK(pVM);
2598 return rc;
2599}
2600
2601
2602/**
2603 * Worker for PGMR3PhysMmioMap that's called owning the lock.
2604 */
2605static int pgmR3PhysMmioMapLocked(PVM pVM, PVMCPU pVCpu, RTGCPHYS const GCPhys, RTGCPHYS const cb, RTGCPHYS const GCPhysLast,
2606 PPGMRAMRANGE const pMmioRamRange, PGMPHYSHANDLERTYPE const hType, uint64_t const uUser)
2607{
2608 /* Check that the range isn't mapped already. */
2609 AssertLogRelMsgReturn(pMmioRamRange->GCPhys == NIL_RTGCPHYS,
2610 ("desired %RGp mapping for '%s' - already mapped at %RGp!\n",
2611 GCPhys, pMmioRamRange->pszDesc, pMmioRamRange->GCPhys),
2612 VERR_ALREADY_EXISTS);
2613
2614 /*
2615 * Now, check if this falls into a regular RAM range or if we should use
2616 * the ad-hoc one (idRamRange).
2617 */
2618 int rc;
2619 uint32_t idxInsert = UINT32_MAX;
2620 PPGMRAMRANGE const pOverlappingRange = pgmR3PhysRamRangeFindOverlapping(pVM, GCPhys, GCPhysLast, &idxInsert);
2621 if (pOverlappingRange)
2622 {
2623 /* Simplification: all within the same range. */
2624 AssertLogRelMsgReturn( GCPhys >= pOverlappingRange->GCPhys
2625 && GCPhysLast <= pOverlappingRange->GCPhysLast,
2626 ("%RGp-%RGp (MMIO/%s) falls partly outside %RGp-%RGp (%s)\n",
2627 GCPhys, GCPhysLast, pMmioRamRange->pszDesc,
2628 pOverlappingRange->GCPhys, pOverlappingRange->GCPhysLast, pOverlappingRange->pszDesc),
2629 VERR_PGM_RAM_CONFLICT);
2630
2631 /* Check that is isn't an ad hoc range, but a real RAM range. */
2632 AssertLogRelMsgReturn(!PGM_RAM_RANGE_IS_AD_HOC(pOverlappingRange),
2633 ("%RGp-%RGp (MMIO/%s) mapping attempt in non-RAM range: %RGp-%RGp (%s)\n",
2634 GCPhys, GCPhysLast, pMmioRamRange->pszDesc,
2635 pOverlappingRange->GCPhys, pOverlappingRange->GCPhysLast, pOverlappingRange->pszDesc),
2636 VERR_PGM_RAM_CONFLICT);
2637
2638 /* Check that it's all RAM or MMIO pages. */
2639 PCPGMPAGE pPage = &pOverlappingRange->aPages[(GCPhys - pOverlappingRange->GCPhys) >> GUEST_PAGE_SHIFT];
2640 uint32_t cLeft = cb >> GUEST_PAGE_SHIFT;
2641 while (cLeft-- > 0)
2642 {
2643 AssertLogRelMsgReturn( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
2644 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO, /** @todo MMIO type isn't right */
2645 ("%RGp-%RGp (MMIO/%s): %RGp is not a RAM or MMIO page - type=%d desc=%s\n",
2646 GCPhys, GCPhysLast, pMmioRamRange->pszDesc, pOverlappingRange->GCPhys,
2647 PGM_PAGE_GET_TYPE(pPage), pOverlappingRange->pszDesc),
2648 VERR_PGM_RAM_CONFLICT);
2649 pPage++;
2650 }
2651
2652 /*
2653 * Make all the pages in the range MMIO/ZERO pages, freeing any
2654 * RAM pages currently mapped here. This might not be 100% correct
2655 * for PCI memory, but we're doing the same thing for MMIO2 pages.
2656 */
2657 rc = pgmR3PhysFreePageRange(pVM, pOverlappingRange, GCPhys, GCPhysLast, NULL);
2658 AssertRCReturn(rc, rc);
2659
2660 /* Force a PGM pool flush as guest ram references have been changed. */
2661 /** @todo not entirely SMP safe; assuming for now the guest takes
2662 * care of this internally (not touch mapped mmio while changing the
2663 * mapping). */
2664 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2665 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2666 }
2667 else
2668 {
2669 /*
2670 * No RAM range, use the ad hoc one (idRamRange).
2671 *
2672 * Note that we don't have to tell REM about this range because
2673 * PGMHandlerPhysicalRegisterEx will do that for us.
2674 */
2675 AssertLogRelReturn(idxInsert <= pVM->pgm.s.RamRangeUnion.cLookupEntries, VERR_INTERNAL_ERROR_4);
2676 Log(("PGMR3PhysMmioMap: Inserting ad hoc MMIO range #%x for %RGp-%RGp %s\n",
2677 pMmioRamRange->idRange, GCPhys, GCPhysLast, pMmioRamRange->pszDesc));
2678
2679 Assert(PGM_PAGE_GET_TYPE(&pMmioRamRange->aPages[0]) == PGMPAGETYPE_MMIO);
2680
2681 /* We ASSUME that all the pages in the ad-hoc range are in the proper
2682 state and all that and that we don't need to re-initialize them here. */
2683
2684#ifdef VBOX_WITH_NATIVE_NEM
2685 /* Notify NEM. */
2686 if (VM_IS_NEM_ENABLED(pVM))
2687 {
2688 uint8_t u2State = 0; /* (must have valid state as there can't be anything to preserve) */
2689 rc = NEMR3NotifyPhysMmioExMapEarly(pVM, GCPhys, cb, 0 /*fFlags*/, NULL, NULL, &u2State, &pMmioRamRange->uNemRange);
2690 AssertLogRelRCReturn(rc, rc);
2691
2692 uint32_t iPage = cb >> GUEST_PAGE_SHIFT;
2693 while (iPage-- > 0)
2694 PGM_PAGE_SET_NEM_STATE(&pMmioRamRange->aPages[iPage], u2State);
2695 }
2696#endif
2697 /* Insert it into the lookup table (may in theory fail). */
2698 rc = pgmR3PhysRamRangeInsertLookup(pVM, pMmioRamRange, GCPhys, &idxInsert);
2699 }
2700 if (RT_SUCCESS(rc))
2701 {
2702 /*
2703 * Register the access handler.
2704 */
2705 rc = PGMHandlerPhysicalRegister(pVM, GCPhys, GCPhysLast, hType, uUser, pMmioRamRange->pszDesc);
2706 if (RT_SUCCESS(rc))
2707 {
2708#ifdef VBOX_WITH_NATIVE_NEM
2709 /* Late NEM notification (currently not used by anyone). */
2710 if (VM_IS_NEM_ENABLED(pVM))
2711 {
2712 if (pOverlappingRange)
2713 rc = NEMR3NotifyPhysMmioExMapLate(pVM, GCPhys, cb, NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE,
2714 pOverlappingRange->pbR3 + (uintptr_t)(GCPhys - pOverlappingRange->GCPhys),
2715 NULL /*pvMmio2*/, NULL /*puNemRange*/);
2716 else
2717 rc = NEMR3NotifyPhysMmioExMapLate(pVM, GCPhys, cb, 0 /*fFlags*/, NULL /*pvRam*/, NULL /*pvMmio2*/,
2718 &pMmioRamRange->uNemRange);
2719 AssertLogRelRC(rc);
2720 }
2721 if (RT_SUCCESS(rc))
2722#endif
2723 {
2724 pgmPhysInvalidatePageMapTLB(pVM, false /*fInRendezvous*/);
2725 return VINF_SUCCESS;
2726 }
2727
2728#ifdef VBOX_WITH_NATIVE_NEM
2729 /*
2730 * Failed, so revert it all as best as we can (the memory content in
2731 * the overlapping case is gone).
2732 */
2733 PGMHandlerPhysicalDeregister(pVM, GCPhys);
2734#endif
2735 }
2736 }
2737
2738 if (!pOverlappingRange)
2739 {
2740#ifdef VBOX_WITH_NATIVE_NEM
2741 /* Notify NEM about the sudden removal of the RAM range we just told it about. */
2742 NEMR3NotifyPhysMmioExUnmap(pVM, GCPhys, cb, 0 /*fFlags*/, NULL /*pvRam*/, NULL /*pvMmio2*/,
2743 NULL /*pu2State*/, &pMmioRamRange->uNemRange);
2744#endif
2745
2746 /* Remove the ad hoc range from the lookup table. */
2747 idxInsert -= 1;
2748 pgmR3PhysRamRangeRemoveLookup(pVM, pMmioRamRange, &idxInsert);
2749 }
2750
2751 pgmPhysInvalidatePageMapTLB(pVM, false /*fInRendezvous*/);
2752 return rc;
2753}
2754
2755
2756/**
2757 * This is the interface IOM is using to map an MMIO region.
2758 *
2759 * It will check for conflicts and ensure that a RAM range structure
2760 * is present before calling the PGMR3HandlerPhysicalRegister API to
2761 * register the callbacks.
2762 *
2763 * @returns VBox status code.
2764 *
2765 * @param pVM The cross context VM structure.
2766 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2767 * @param GCPhys The start of the MMIO region.
2768 * @param cb The size of the MMIO region.
2769 * @param idRamRange The RAM range ID for the MMIO region as returned by
2770 * PGMR3PhysMmioRegister().
2771 * @param hType The physical access handler type registration.
2772 * @param uUser The user argument.
2773 * @thread EMT(pVCpu)
2774 */
2775VMMR3_INT_DECL(int) PGMR3PhysMmioMap(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, RTGCPHYS cb, uint16_t idRamRange,
2776 PGMPHYSHANDLERTYPE hType, uint64_t uUser)
2777{
2778 /*
2779 * Assert on some assumption.
2780 */
2781 VMCPU_ASSERT_EMT(pVCpu);
2782 AssertReturn(!(cb & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2783 AssertReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2784 RTGCPHYS const GCPhysLast = GCPhys + cb - 1U;
2785 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
2786#ifdef VBOX_STRICT
2787 PCPGMPHYSHANDLERTYPEINT pType = pgmHandlerPhysicalTypeHandleToPtr(pVM, hType);
2788 Assert(pType);
2789 Assert(pType->enmKind == PGMPHYSHANDLERKIND_MMIO);
2790#endif
2791 AssertReturn(idRamRange <= pVM->pgm.s.idRamRangeMax && idRamRange > 0, VERR_INVALID_HANDLE);
2792 PPGMRAMRANGE const pMmioRamRange = pVM->pgm.s.apRamRanges[idRamRange];
2793 AssertReturn(pMmioRamRange, VERR_INVALID_HANDLE);
2794 AssertReturn(pMmioRamRange->fFlags & PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO, VERR_INVALID_HANDLE);
2795 AssertReturn(pMmioRamRange->cb == cb, VERR_OUT_OF_RANGE);
2796
2797 /*
2798 * Take the PGM lock and do the work.
2799 */
2800 int rc = PGM_LOCK(pVM);
2801 AssertRCReturn(rc, rc);
2802
2803 rc = pgmR3PhysMmioMapLocked(pVM, pVCpu, GCPhys, cb, GCPhysLast, pMmioRamRange, hType, uUser);
2804#ifdef VBOX_STRICT
2805 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, false /*fRamRelaxed*/);
2806#endif
2807
2808 PGM_UNLOCK(pVM);
2809 return rc;
2810}
2811
2812
2813/**
2814 * Worker for PGMR3PhysMmioUnmap that's called with the PGM lock held.
2815 */
2816static int pgmR3PhysMmioUnmapLocked(PVM pVM, PVMCPU pVCpu, RTGCPHYS const GCPhys, RTGCPHYS const cb,
2817 RTGCPHYS const GCPhysLast, PPGMRAMRANGE const pMmioRamRange)
2818{
2819 /*
2820 * Lookup the RAM range containing the region to make sure it is actually mapped.
2821 */
2822 uint32_t idxLookup = pgmR3PhysRamRangeFindOverlappingIndex(pVM, GCPhys, GCPhysLast);
2823 AssertLogRelMsgReturn(idxLookup < pVM->pgm.s.RamRangeUnion.cLookupEntries,
2824 ("MMIO range not found at %RGp LB %RGp! (%s)\n", GCPhys, cb, pMmioRamRange->pszDesc),
2825 VERR_NOT_FOUND);
2826
2827 uint32_t const idLookupRange = PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup]);
2828 AssertLogRelReturn(idLookupRange != 0 && idLookupRange <= pVM->pgm.s.idRamRangeMax, VERR_INTERNAL_ERROR_5);
2829 PPGMRAMRANGE const pLookupRange = pVM->pgm.s.apRamRanges[idLookupRange];
2830 AssertLogRelReturn(pLookupRange, VERR_INTERNAL_ERROR_4);
2831
2832 AssertLogRelMsgReturn(pLookupRange == pMmioRamRange || !PGM_RAM_RANGE_IS_AD_HOC(pLookupRange),
2833 ("MMIO unmap mixup at %RGp LB %RGp (%s) vs %RGp LB %RGp (%s)\n",
2834 GCPhys, cb, pMmioRamRange->pszDesc, pLookupRange->GCPhys, pLookupRange->cb, pLookupRange->pszDesc),
2835 VERR_NOT_FOUND);
2836
2837 /*
2838 * Deregister the handler. This should reset any aliases, so an ad hoc
2839 * range will only contain MMIO type pages afterwards.
2840 */
2841 int rc = PGMHandlerPhysicalDeregister(pVM, GCPhys);
2842 if (RT_SUCCESS(rc))
2843 {
2844 if (pLookupRange != pMmioRamRange)
2845 {
2846 /*
2847 * Turn the pages back into RAM pages.
2848 */
2849 Log(("pgmR3PhysMmioUnmapLocked: Reverting MMIO range %RGp-%RGp (%s) in %RGp-%RGp (%s) to RAM.\n",
2850 GCPhys, GCPhysLast, pMmioRamRange->pszDesc,
2851 pLookupRange->GCPhys, pLookupRange->GCPhysLast, pLookupRange->pszDesc));
2852
2853 RTGCPHYS const offRange = GCPhys - pLookupRange->GCPhys;
2854 uint32_t iPage = offRange >> GUEST_PAGE_SHIFT;
2855 uint32_t cLeft = cb >> GUEST_PAGE_SHIFT;
2856 while (cLeft--)
2857 {
2858 PPGMPAGE pPage = &pLookupRange->aPages[iPage];
2859 AssertMsg( (PGM_PAGE_IS_MMIO(pPage) && PGM_PAGE_IS_ZERO(pPage))
2860 //|| PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO
2861 //|| PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_SPECIAL_ALIAS_MMIO
2862 , ("%RGp %R[pgmpage]\n", pLookupRange->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT), pPage));
2863/** @todo this isn't entirely correct, is it now... aliases must be converted
2864 * to zero pages as they won't be. however, shouldn't
2865 * PGMHandlerPhysicalDeregister deal with this already? */
2866 if (PGM_PAGE_IS_MMIO_OR_ALIAS(pPage))
2867 PGM_PAGE_SET_TYPE(pVM, pPage, PGMPAGETYPE_RAM);
2868 iPage++;
2869 }
2870
2871#ifdef VBOX_WITH_NATIVE_NEM
2872 /* Notify REM (failure will probably leave things in a non-working state). */
2873 if (VM_IS_NEM_ENABLED(pVM))
2874 {
2875 uint8_t u2State = UINT8_MAX;
2876 rc = NEMR3NotifyPhysMmioExUnmap(pVM, GCPhys, GCPhysLast - GCPhys + 1, NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE,
2877 pLookupRange->pbR3 ? pLookupRange->pbR3 + GCPhys - pLookupRange->GCPhys : NULL,
2878 NULL, &u2State, &pLookupRange->uNemRange);
2879 AssertLogRelRC(rc);
2880 /** @todo status code propagation here... This is likely fatal, right? */
2881 if (u2State != UINT8_MAX)
2882 pgmPhysSetNemStateForPages(&pLookupRange->aPages[(GCPhys - pLookupRange->GCPhys) >> GUEST_PAGE_SHIFT],
2883 cb >> GUEST_PAGE_SHIFT, u2State);
2884 }
2885#endif
2886 }
2887 else
2888 {
2889 /*
2890 * Unlink the ad hoc range.
2891 */
2892#ifdef VBOX_STRICT
2893 uint32_t iPage = cb >> GUEST_PAGE_SHIFT;
2894 while (iPage-- > 0)
2895 {
2896 PPGMPAGE const pPage = &pMmioRamRange->aPages[iPage];
2897 Assert(PGM_PAGE_IS_MMIO(pPage));
2898 }
2899#endif
2900
2901 Log(("pgmR3PhysMmioUnmapLocked: Unmapping ad hoc MMIO range for %RGp-%RGp %s\n",
2902 GCPhys, GCPhysLast, pMmioRamRange->pszDesc));
2903
2904#ifdef VBOX_WITH_NATIVE_NEM
2905 if (VM_IS_NEM_ENABLED(pVM)) /* Notify REM before we unlink the range. */
2906 {
2907 rc = NEMR3NotifyPhysMmioExUnmap(pVM, GCPhys, GCPhysLast - GCPhys + 1, 0 /*fFlags*/,
2908 NULL, NULL, NULL, &pMmioRamRange->uNemRange);
2909 AssertLogRelRCReturn(rc, rc); /* we're up the creek if this hits. */
2910 }
2911#endif
2912
2913 pgmR3PhysRamRangeRemoveLookup(pVM, pMmioRamRange, &idxLookup);
2914 }
2915 }
2916
2917 /* Force a PGM pool flush as guest ram references have been changed. */
2918 /** @todo Not entirely SMP safe; assuming for now the guest takes care of
2919 * this internally (not touch mapped mmio while changing the mapping). */
2920 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2921 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2922
2923 pgmPhysInvalidatePageMapTLB(pVM, false /*fInRendezvous*/);
2924 /*pgmPhysInvalidRamRangeTlbs(pVM); - not necessary */
2925
2926 return rc;
2927}
2928
2929
2930/**
2931 * This is the interface IOM is using to register an MMIO region.
2932 *
2933 * It will take care of calling PGMHandlerPhysicalDeregister and clean up
2934 * any ad hoc PGMRAMRANGE left behind.
2935 *
2936 * @returns VBox status code.
2937 * @param pVM The cross context VM structure.
2938 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
2939 * @param GCPhys The start of the MMIO region.
2940 * @param cb The size of the MMIO region.
2941 * @param idRamRange The RAM range ID for the MMIO region as returned by
2942 * PGMR3PhysMmioRegister().
2943 * @thread EMT(pVCpu)
2944 */
2945VMMR3_INT_DECL(int) PGMR3PhysMmioUnmap(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, RTGCPHYS cb, uint16_t idRamRange)
2946{
2947 /*
2948 * Input validation.
2949 */
2950 VMCPU_ASSERT_EMT(pVCpu);
2951 AssertReturn(!(cb & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2952 AssertReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2953 RTGCPHYS const GCPhysLast = GCPhys + cb - 1U;
2954 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
2955 AssertReturn(idRamRange <= pVM->pgm.s.idRamRangeMax && idRamRange > 0, VERR_INVALID_HANDLE);
2956 PPGMRAMRANGE const pMmioRamRange = pVM->pgm.s.apRamRanges[idRamRange];
2957 AssertReturn(pMmioRamRange, VERR_INVALID_HANDLE);
2958 AssertReturn(pMmioRamRange->fFlags & PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO, VERR_INVALID_HANDLE);
2959 AssertReturn(pMmioRamRange->cb == cb, VERR_OUT_OF_RANGE);
2960
2961 /*
2962 * Take the PGM lock and do what's asked.
2963 */
2964 int rc = PGM_LOCK(pVM);
2965 AssertRCReturn(rc, rc);
2966
2967 rc = pgmR3PhysMmioUnmapLocked(pVM, pVCpu, GCPhys, cb, GCPhysLast, pMmioRamRange);
2968#ifdef VBOX_STRICT
2969 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, false /*fRamRelaxed*/);
2970#endif
2971
2972 PGM_UNLOCK(pVM);
2973 return rc;
2974}
2975
2976
2977
2978/*********************************************************************************************************************************
2979* MMIO2 *
2980*********************************************************************************************************************************/
2981
2982/**
2983 * Validates the claim to an MMIO2 range and returns the pointer to it.
2984 *
2985 * @returns The MMIO2 entry index on success, negative error status on failure.
2986 * @param pVM The cross context VM structure.
2987 * @param pDevIns The device instance owning the region.
2988 * @param hMmio2 Handle to look up.
2989 * @param pcChunks Where to return the number of chunks associated with
2990 * this handle.
2991 */
2992static int32_t pgmR3PhysMmio2ResolveHandle(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, uint32_t *pcChunks)
2993{
2994 *pcChunks = 0;
2995 uint32_t const idxFirst = hMmio2 - 1U;
2996 uint32_t const cMmio2Ranges = RT_MIN(pVM->pgm.s.cMmio2Ranges, RT_ELEMENTS(pVM->pgm.s.aMmio2Ranges));
2997 AssertReturn(idxFirst < cMmio2Ranges, VERR_INVALID_HANDLE);
2998
2999 PPGMREGMMIO2RANGE const pFirst = &pVM->pgm.s.aMmio2Ranges[idxFirst];
3000 AssertReturn(pFirst->idMmio2 == hMmio2, VERR_INVALID_HANDLE);
3001 AssertReturn((pFirst->fFlags & PGMREGMMIO2RANGE_F_FIRST_CHUNK), VERR_INVALID_HANDLE);
3002 AssertReturn(pFirst->pDevInsR3 == pDevIns && RT_VALID_PTR(pDevIns), VERR_NOT_OWNER);
3003
3004 /* Figure out how many chunks this handle spans. */
3005 if (pFirst->fFlags & PGMREGMMIO2RANGE_F_LAST_CHUNK)
3006 *pcChunks = 1;
3007 else
3008 {
3009 uint32_t cChunks = 1;
3010 for (uint32_t idx = idxFirst + 1;; idx++)
3011 {
3012 cChunks++;
3013 AssertReturn(idx < cMmio2Ranges, VERR_INTERNAL_ERROR_2);
3014 PPGMREGMMIO2RANGE const pCur = &pVM->pgm.s.aMmio2Ranges[idx];
3015 AssertLogRelMsgReturn( pCur->pDevInsR3 == pDevIns
3016 && pCur->idMmio2 == idx + 1
3017 && pCur->iSubDev == pFirst->iSubDev
3018 && pCur->iRegion == pFirst->iRegion
3019 && !(pCur->fFlags & PGMREGMMIO2RANGE_F_FIRST_CHUNK),
3020 ("cur: %p/%#x/%#x/%#x/%#x/%s; first: %p/%#x/%#x/%#x/%#x/%s\n",
3021 pCur->pDevInsR3, pCur->idMmio2, pCur->iSubDev, pCur->iRegion, pCur->fFlags,
3022 pVM->pgm.s.apMmio2RamRanges[idx]->pszDesc,
3023 pDevIns, idx + 1, pFirst->iSubDev, pFirst->iRegion, pFirst->fFlags,
3024 pVM->pgm.s.apMmio2RamRanges[idxFirst]->pszDesc),
3025 VERR_INTERNAL_ERROR_3);
3026 if (pCur->fFlags & PGMREGMMIO2RANGE_F_LAST_CHUNK)
3027 break;
3028 }
3029 *pcChunks = cChunks;
3030 }
3031
3032 return (int32_t)idxFirst;
3033}
3034
3035
3036/**
3037 * Check if a device has already registered a MMIO2 region.
3038 *
3039 * @returns NULL if not registered, otherwise pointer to the MMIO2.
3040 * @param pVM The cross context VM structure.
3041 * @param pDevIns The device instance owning the region.
3042 * @param iSubDev The sub-device number.
3043 * @param iRegion The region.
3044 */
3045DECLINLINE(PPGMREGMMIO2RANGE) pgmR3PhysMmio2Find(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion)
3046{
3047 /*
3048 * Search the array. There shouldn't be many entries.
3049 */
3050 uint32_t idx = RT_MIN(pVM->pgm.s.cMmio2Ranges, RT_ELEMENTS(pVM->pgm.s.aMmio2Ranges));
3051 while (idx-- > 0)
3052 if (RT_LIKELY( pVM->pgm.s.aMmio2Ranges[idx].pDevInsR3 != pDevIns
3053 || pVM->pgm.s.aMmio2Ranges[idx].iRegion != iRegion
3054 || pVM->pgm.s.aMmio2Ranges[idx].iSubDev != iSubDev))
3055 { /* likely */ }
3056 else
3057 return &pVM->pgm.s.aMmio2Ranges[idx];
3058 return NULL;
3059}
3060
3061/**
3062 * Worker for PGMR3PhysMmio2ControlDirtyPageTracking and PGMR3PhysMmio2Map.
3063 */
3064static int pgmR3PhysMmio2EnableDirtyPageTracing(PVM pVM, uint32_t idx, uint32_t cChunks)
3065{
3066 int rc = VINF_SUCCESS;
3067 while (cChunks-- > 0)
3068 {
3069 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idx];
3070 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
3071
3072 Assert(!(pMmio2->fFlags & PGMREGMMIO2RANGE_F_IS_TRACKING));
3073 int rc2 = pgmHandlerPhysicalExRegister(pVM, pMmio2->pPhysHandlerR3, pRamRange->GCPhys, pRamRange->GCPhysLast);
3074 if (RT_SUCCESS(rc2))
3075 pMmio2->fFlags |= PGMREGMMIO2RANGE_F_IS_TRACKING;
3076 else
3077 AssertLogRelMsgFailedStmt(("%#RGp-%#RGp %s failed -> %Rrc\n",
3078 pRamRange->GCPhys, pRamRange->GCPhysLast, pRamRange->pszDesc, rc2),
3079 rc = RT_SUCCESS(rc) ? rc2 : rc);
3080
3081 idx++;
3082 }
3083 return rc;
3084}
3085
3086
3087/**
3088 * Worker for PGMR3PhysMmio2ControlDirtyPageTracking and PGMR3PhysMmio2Unmap.
3089 */
3090static int pgmR3PhysMmio2DisableDirtyPageTracing(PVM pVM, uint32_t idx, uint32_t cChunks)
3091{
3092 int rc = VINF_SUCCESS;
3093 while (cChunks-- > 0)
3094 {
3095 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idx];
3096 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
3097 if (pMmio2->fFlags & PGMREGMMIO2RANGE_F_IS_TRACKING)
3098 {
3099 int rc2 = pgmHandlerPhysicalExDeregister(pVM, pMmio2->pPhysHandlerR3);
3100 AssertLogRelMsgStmt(RT_SUCCESS(rc2),
3101 ("%#RGp-%#RGp %s failed -> %Rrc\n",
3102 pRamRange->GCPhys, pRamRange->GCPhysLast, pRamRange->pszDesc, rc2),
3103 rc = RT_SUCCESS(rc) ? rc2 : rc);
3104 pMmio2->fFlags &= ~PGMREGMMIO2RANGE_F_IS_TRACKING;
3105 }
3106 idx++;
3107 }
3108 return rc;
3109}
3110
3111#if 0 // temp
3112
3113/**
3114 * Common worker PGMR3PhysMmio2PreRegister & PGMR3PhysMMIO2Register that links a
3115 * complete registration entry into the lists and lookup tables.
3116 *
3117 * @param pVM The cross context VM structure.
3118 * @param pNew The new MMIO / MMIO2 registration to link.
3119 */
3120static void pgmR3PhysMmio2Link(PVM pVM, PPGMREGMMIO2RANGE pNew)
3121{
3122 Assert(pNew->idMmio2 != UINT8_MAX);
3123
3124 /*
3125 * Link it into the list (order doesn't matter, so insert it at the head).
3126 *
3127 * Note! The range we're linking may consist of multiple chunks, so we
3128 * have to find the last one.
3129 */
3130 PPGMREGMMIO2RANGE pLast = pNew;
3131 for (pLast = pNew; ; pLast = pLast->pNextR3)
3132 {
3133 if (pLast->fFlags & PGMREGMMIO2RANGE_F_LAST_CHUNK)
3134 break;
3135 Assert(pLast->pNextR3);
3136 Assert(pLast->pNextR3->pDevInsR3 == pNew->pDevInsR3);
3137 Assert(pLast->pNextR3->iSubDev == pNew->iSubDev);
3138 Assert(pLast->pNextR3->iRegion == pNew->iRegion);
3139 Assert(pLast->pNextR3->idMmio2 == pLast->idMmio2 + 1);
3140 }
3141
3142 PGM_LOCK_VOID(pVM);
3143
3144 /* Link in the chain of ranges at the head of the list. */
3145 pLast->pNextR3 = pVM->pgm.s.pRegMmioRangesR3;
3146 pVM->pgm.s.pRegMmioRangesR3 = pNew;
3147
3148 /* Insert the MMIO2 range/page IDs. */
3149 uint8_t idMmio2 = pNew->idMmio2;
3150 for (;;)
3151 {
3152 Assert(pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] == NULL);
3153 Assert(pVM->pgm.s.apMmio2RangesR0[idMmio2 - 1] == NIL_RTR0PTR);
3154 pVM->pgm.s.apMmio2RangesR3[idMmio2 - 1] = pNew;
3155 pVM->pgm.s.apMmio2RangesR0[idMmio2 - 1] = pNew->RamRange.pSelfR0 - RT_UOFFSETOF(PGMREGMMIO2RANGE, RamRange);
3156 if (pNew->fFlags & PGMREGMMIO2RANGE_F_LAST_CHUNK)
3157 break;
3158 pNew = pNew->pNextR3;
3159 idMmio2++;
3160 }
3161
3162 pgmPhysInvalidatePageMapTLB(pVM);
3163 PGM_UNLOCK(pVM);
3164}
3165#endif
3166
3167
3168/**
3169 * Allocate and register an MMIO2 region.
3170 *
3171 * As mentioned elsewhere, MMIO2 is just RAM spelled differently. It's RAM
3172 * associated with a device. It is also non-shared memory with a permanent
3173 * ring-3 mapping and page backing (presently).
3174 *
3175 * A MMIO2 range may overlap with base memory if a lot of RAM is configured for
3176 * the VM, in which case we'll drop the base memory pages. Presently we will
3177 * make no attempt to preserve anything that happens to be present in the base
3178 * memory that is replaced, this is of course incorrect but it's too much
3179 * effort.
3180 *
3181 * @returns VBox status code.
3182 * @retval VINF_SUCCESS on success, *ppv pointing to the R3 mapping of the
3183 * memory.
3184 * @retval VERR_ALREADY_EXISTS if the region already exists.
3185 *
3186 * @param pVM The cross context VM structure.
3187 * @param pDevIns The device instance owning the region.
3188 * @param iSubDev The sub-device number.
3189 * @param iRegion The region number. If the MMIO2 memory is a PCI
3190 * I/O region this number has to be the number of that
3191 * region. Otherwise it can be any number save
3192 * UINT8_MAX.
3193 * @param cb The size of the region. Must be page aligned.
3194 * @param fFlags Reserved for future use, must be zero.
3195 * @param pszDesc The description.
3196 * @param ppv Where to store the pointer to the ring-3 mapping of
3197 * the memory.
3198 * @param phRegion Where to return the MMIO2 region handle. Optional.
3199 * @thread EMT(0)
3200 *
3201 * @note Only callable at VM creation time and during VM state loading.
3202 * The latter is for PCNet saved state compatibility with pre 4.3.6
3203 * state.
3204 */
3205VMMR3_INT_DECL(int) PGMR3PhysMmio2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cb,
3206 uint32_t fFlags, const char *pszDesc, void **ppv, PGMMMIO2HANDLE *phRegion)
3207{
3208 /*
3209 * Validate input.
3210 */
3211 AssertPtrReturn(ppv, VERR_INVALID_POINTER);
3212 *ppv = NULL;
3213 if (phRegion)
3214 {
3215 AssertPtrReturn(phRegion, VERR_INVALID_POINTER);
3216 *phRegion = NIL_PGMMMIO2HANDLE;
3217 }
3218 PVMCPU const pVCpu = VMMGetCpu(pVM);
3219 AssertReturn(pVCpu && pVCpu->idCpu == 0, VERR_VM_THREAD_NOT_EMT);
3220 VMSTATE const enmVMState = VMR3GetState(pVM);
3221 AssertMsgReturn(enmVMState == VMSTATE_CREATING || enmVMState == VMSTATE_LOADING,
3222 ("state %s, expected CREATING or LOADING\n", VMGetStateName(enmVMState)),
3223 VERR_VM_INVALID_VM_STATE);
3224
3225 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
3226 AssertReturn(iSubDev <= UINT8_MAX, VERR_INVALID_PARAMETER);
3227 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
3228
3229 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
3230 AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
3231
3232 AssertReturn(!(cb & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
3233 AssertReturn(cb, VERR_INVALID_PARAMETER);
3234 AssertReturn(!(fFlags & ~PGMPHYS_MMIO2_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
3235
3236 const uint32_t cGuestPages = cb >> GUEST_PAGE_SHIFT;
3237 AssertLogRelReturn(((RTGCPHYS)cGuestPages << GUEST_PAGE_SHIFT) == cb, VERR_INVALID_PARAMETER);
3238 AssertLogRelReturn(cGuestPages <= PGM_MAX_PAGES_PER_MMIO2_REGION, VERR_OUT_OF_RANGE);
3239 AssertLogRelReturn(cGuestPages <= (MM_MMIO_64_MAX >> GUEST_PAGE_SHIFT), VERR_OUT_OF_RANGE);
3240
3241 AssertReturn(pgmR3PhysMmio2Find(pVM, pDevIns, iSubDev, iRegion) == NULL, VERR_ALREADY_EXISTS);
3242
3243 /*
3244 * For the 2nd+ instance, mangle the description string so it's unique.
3245 */
3246 if (pDevIns->iInstance > 0) /** @todo Move to PDMDevHlp.cpp and use a real string cache. */
3247 {
3248 pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS, "%s [%u]", pszDesc, pDevIns->iInstance);
3249 if (!pszDesc)
3250 return VERR_NO_MEMORY;
3251 }
3252
3253 /*
3254 * Check that we've got sufficient MMIO2 ID space for this request (the
3255 * allocation will be done later once we've got the backing memory secured,
3256 * but given the EMT0 restriction, that's not going to be a problem).
3257 *
3258 * The zero ID is not used as it could be confused with NIL_GMM_PAGEID, so
3259 * the IDs goes from 1 thru PGM_MAX_MMIO2_RANGES.
3260 */
3261 unsigned const cChunks = pgmPhysMmio2CalcChunkCount(cb, NULL);
3262
3263 int rc = PGM_LOCK(pVM);
3264 AssertRCReturn(rc, rc);
3265
3266 AssertCompile(PGM_MAX_MMIO2_RANGES < 255);
3267 uint8_t const idMmio2 = pVM->pgm.s.cMmio2Ranges + 1;
3268 AssertLogRelReturnStmt(idMmio2 + cChunks <= PGM_MAX_MMIO2_RANGES, PGM_UNLOCK(pVM), VERR_PGM_TOO_MANY_MMIO2_RANGES);
3269
3270 /*
3271 * Try reserve and allocate the backing memory first as this is what is
3272 * most likely to fail.
3273 */
3274 rc = MMR3AdjustFixedReservation(pVM, cGuestPages, pszDesc);
3275 if (RT_SUCCESS(rc))
3276 {
3277 /*
3278 * If we're in driverless we'll be doing the work here, otherwise we
3279 * must call ring-0 to do the job as we'll need physical addresses
3280 * and maybe a ring-0 mapping address for it all.
3281 */
3282 if (SUPR3IsDriverless())
3283 rc = pgmPhysMmio2RegisterWorker(pVM, cGuestPages, idMmio2, cChunks, pDevIns, iSubDev, iRegion, fFlags);
3284 else
3285 {
3286 PGMPHYSMMIO2REGISTERREQ Mmio2RegReq;
3287 Mmio2RegReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
3288 Mmio2RegReq.Hdr.cbReq = sizeof(Mmio2RegReq);
3289 Mmio2RegReq.cbGuestPage = GUEST_PAGE_SIZE;
3290 Mmio2RegReq.cGuestPages = cGuestPages;
3291 Mmio2RegReq.idMmio2 = idMmio2;
3292 Mmio2RegReq.cChunks = cChunks;
3293 Mmio2RegReq.iSubDev = (uint8_t)iSubDev;
3294 Mmio2RegReq.iRegion = (uint8_t)iRegion;
3295 Mmio2RegReq.fFlags = fFlags;
3296 Mmio2RegReq.pDevIns = pDevIns;
3297 rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_PGM_PHYS_MMIO2_REGISTER, 0 /*u64Arg*/, &Mmio2RegReq.Hdr);
3298 }
3299 if (RT_SUCCESS(rc))
3300 {
3301 Assert(idMmio2 + cChunks - 1 == pVM->pgm.s.cMmio2Ranges);
3302
3303 /*
3304 * There are two things left to do:
3305 * 1. Add the description to the associated RAM ranges.
3306 * 2. Pre-allocate access handlers for dirty bit tracking if necessary.
3307 */
3308 bool const fNeedHandler = (fFlags & PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES)
3309#ifdef VBOX_WITH_PGM_NEM_MODE
3310 && (!VM_IS_NEM_ENABLED(pVM) || !NEMR3IsMmio2DirtyPageTrackingSupported(pVM))
3311#endif
3312 ;
3313 for (uint32_t idxChunk = 0; idxChunk < cChunks; idxChunk++)
3314 {
3315 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idxChunk + idMmio2 - 1];
3316 Assert(pMmio2->idRamRange < RT_ELEMENTS(pVM->pgm.s.apRamRanges));
3317 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apRamRanges[pMmio2->idRamRange];
3318 Assert(pRamRange->pbR3 == pMmio2->pbR3);
3319 Assert(pRamRange->cb == pMmio2->cbReal);
3320
3321 pRamRange->pszDesc = pszDesc; /** @todo mangle this if we got more than one chunk */
3322 if (fNeedHandler)
3323 {
3324 rc = pgmHandlerPhysicalExCreate(pVM, pVM->pgm.s.hMmio2DirtyPhysHandlerType, pMmio2->idMmio2,
3325 pszDesc, &pMmio2->pPhysHandlerR3);
3326 AssertLogRelMsgReturnStmt(RT_SUCCESS(rc),
3327 ("idMmio2=%#x idxChunk=%#x rc=%Rc\n", idMmio2, idxChunk, rc),
3328 PGM_UNLOCK(pVM),
3329 rc); /* PGMR3Term will take care of it all. */
3330 }
3331 }
3332
3333 /*
3334 * Done!
3335 */
3336 if (phRegion)
3337 *phRegion = idMmio2;
3338 *ppv = pVM->pgm.s.aMmio2Ranges[idMmio2 - 1].pbR3;
3339
3340 PGM_UNLOCK(pVM);
3341 return VINF_SUCCESS;
3342 }
3343
3344 MMR3AdjustFixedReservation(pVM, -(int32_t)cGuestPages, pszDesc);
3345 }
3346 if (pDevIns->iInstance > 0)
3347 MMR3HeapFree((void *)pszDesc);
3348 return rc;
3349}
3350
3351/**
3352 * Deregisters and frees an MMIO2 region.
3353 *
3354 * Any physical access handlers registered for the region must be deregistered
3355 * before calling this function.
3356 *
3357 * @returns VBox status code.
3358 * @param pVM The cross context VM structure.
3359 * @param pDevIns The device instance owning the region.
3360 * @param hMmio2 The MMIO2 handle to deregister, or NIL if all
3361 * regions for the given device is to be deregistered.
3362 * @thread EMT(0)
3363 *
3364 * @note Only callable during VM state loading. This is to jettison an unused
3365 * MMIO2 section present in PCNet saved state prior to VBox v4.3.6.
3366 */
3367VMMR3_INT_DECL(int) PGMR3PhysMmio2Deregister(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2)
3368{
3369 /*
3370 * Validate input.
3371 */
3372 PVMCPU const pVCpu = VMMGetCpu(pVM);
3373 AssertReturn(pVCpu && pVCpu->idCpu == 0, VERR_VM_THREAD_NOT_EMT);
3374 VMSTATE const enmVMState = VMR3GetState(pVM);
3375 AssertMsgReturn(enmVMState == VMSTATE_LOADING,
3376 ("state %s, expected LOADING\n", VMGetStateName(enmVMState)),
3377 VERR_VM_INVALID_VM_STATE);
3378
3379 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
3380
3381 /*
3382 * Take the PGM lock and scan for registrations matching the requirements.
3383 * We do this backwards to more easily reduce the cMmio2Ranges count when
3384 * stuff is removed.
3385 */
3386 PGM_LOCK_VOID(pVM);
3387
3388 int rc = VINF_SUCCESS;
3389 unsigned cFound = 0;
3390 uint32_t const cMmio2Ranges = RT_MIN(pVM->pgm.s.cMmio2Ranges, RT_ELEMENTS(pVM->pgm.s.aMmio2Ranges));
3391 uint32_t idx = cMmio2Ranges;
3392 while (idx-- > 0)
3393 {
3394 PPGMREGMMIO2RANGE pCur = &pVM->pgm.s.aMmio2Ranges[idx];
3395 if ( pCur->pDevInsR3 == pDevIns
3396 && ( hMmio2 == NIL_PGMMMIO2HANDLE
3397 || pCur->idMmio2 == hMmio2))
3398 {
3399 cFound++;
3400
3401 /*
3402 * Wind back the first chunk for this registration.
3403 */
3404 AssertLogRelMsgReturnStmt(pCur->fFlags & PGMREGMMIO2RANGE_F_LAST_CHUNK, ("idx=%u fFlags=%#x\n", idx, pCur->fFlags),
3405 PGM_UNLOCK(pVM), VERR_INTERNAL_ERROR_3);
3406 uint32_t cGuestPages = pCur->cbReal >> GUEST_PAGE_SHIFT;
3407 uint32_t cChunks = 1;
3408 while ( idx > 0
3409 && !(pCur->fFlags & PGMREGMMIO2RANGE_F_FIRST_CHUNK))
3410 {
3411 AssertLogRelMsgReturnStmt( pCur[-1].pDevInsR3 == pDevIns
3412 && pCur[-1].iRegion == pCur->iRegion
3413 && pCur[-1].iSubDev == pCur->iSubDev,
3414 ("[%u]: %p/%#x/%#x/fl=%#x; [%u]: %p/%#x/%#x/fl=%#x; cChunks=%#x\n",
3415 idx - 1, pCur[-1].pDevInsR3, pCur[-1].iRegion, pCur[-1].iSubDev, pCur[-1].fFlags,
3416 idx, pCur->pDevInsR3, pCur->iRegion, pCur->iSubDev, pCur->fFlags, cChunks),
3417 PGM_UNLOCK(pVM), VERR_INTERNAL_ERROR_3);
3418 cChunks++;
3419 pCur--;
3420 idx--;
3421 cGuestPages += pCur->cbReal >> GUEST_PAGE_SHIFT;
3422 }
3423 AssertLogRelMsgReturnStmt(pCur->fFlags & PGMREGMMIO2RANGE_F_FIRST_CHUNK,
3424 ("idx=%u fFlags=%#x cChunks=%#x\n", idx, pCur->fFlags, cChunks),
3425 PGM_UNLOCK(pVM), VERR_INTERNAL_ERROR_3);
3426
3427 /*
3428 * Unmap it if it's mapped.
3429 */
3430 if (pCur->fFlags & PGMREGMMIO2RANGE_F_MAPPED)
3431 {
3432 int rc2 = PGMR3PhysMmio2Unmap(pVM, pCur->pDevInsR3, idx + 1, pCur->GCPhys);
3433 AssertRC(rc2);
3434 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
3435 rc = rc2;
3436 }
3437
3438 /*
3439 * Destroy access handlers.
3440 */
3441 for (uint32_t iChunk = 0; iChunk < cChunks; iChunk++)
3442 if (pCur[iChunk].pPhysHandlerR3)
3443 {
3444 pgmHandlerPhysicalExDestroy(pVM, pCur[iChunk].pPhysHandlerR3);
3445 pCur[iChunk].pPhysHandlerR3 = NULL;
3446 }
3447
3448 /*
3449 * Call kernel mode / worker to do the actual deregistration.
3450 */
3451 const char * const pszDesc = pVM->pgm.s.apMmio2RamRanges[idx] ? pVM->pgm.s.apMmio2RamRanges[idx]->pszDesc : NULL;
3452 int rc2;
3453 if (SUPR3IsDriverless())
3454 {
3455 Assert(PGM_IS_IN_NEM_MODE(pVM));
3456 rc2 = pgmPhysMmio2DeregisterWorker(pVM, idx, cChunks, pDevIns);
3457 AssertLogRelMsgStmt(RT_SUCCESS(rc2),
3458 ("pgmPhysMmio2DeregisterWorker: rc=%Rrc idx=%#x cChunks=%#x %s\n",
3459 rc2, idx, cChunks, pszDesc),
3460 rc = RT_SUCCESS(rc) ? rc2 : rc);
3461 }
3462 else
3463 {
3464 PGMPHYSMMIO2DEREGISTERREQ Mmio2DeregReq;
3465 Mmio2DeregReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
3466 Mmio2DeregReq.Hdr.cbReq = sizeof(Mmio2DeregReq);
3467 Mmio2DeregReq.idMmio2 = idx + 1;
3468 Mmio2DeregReq.cChunks = cChunks;
3469 Mmio2DeregReq.pDevIns = pDevIns;
3470 rc2 = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_PGM_PHYS_MMIO2_DEREGISTER, 0 /*u64Arg*/, &Mmio2DeregReq.Hdr);
3471 AssertLogRelMsgStmt(RT_SUCCESS(rc2),
3472 ("VMMR0_DO_PGM_PHYS_MMIO2_DEREGISTER: rc=%Rrc idx=%#x cChunks=%#x %s\n",
3473 rc2, idx, cChunks, pszDesc),
3474 rc = RT_SUCCESS(rc) ? rc2 : rc);
3475 pgmPhysInvalidRamRangeTlbs(pVM); /* Ensure no stale pointers in the ring-3 RAM range TLB. */
3476 }
3477 if (RT_FAILURE(rc2))
3478 {
3479 LogRel(("PGMR3PhysMmio2Deregister: Deregistration failed: %Rrc; cChunks=%u %s\n", rc, cChunks, pszDesc));
3480 if (RT_SUCCESS(rc))
3481 rc = rc2;
3482 }
3483
3484 /*
3485 * Adjust the memory reservation.
3486 */
3487 if (!PGM_IS_IN_NEM_MODE(pVM) && RT_SUCCESS(rc2))
3488 {
3489 rc2 = MMR3AdjustFixedReservation(pVM, -(int32_t)cGuestPages, pszDesc);
3490 AssertLogRelMsgStmt(RT_SUCCESS(rc2), ("rc=%Rrc cGuestPages=%#x\n", rc, cGuestPages),
3491 rc = RT_SUCCESS(rc) ? rc2 : rc);
3492 }
3493
3494 /* Are we done? */
3495 if (hMmio2 != NIL_PGMMMIO2HANDLE)
3496 break;
3497 }
3498 }
3499 pgmPhysInvalidatePageMapTLB(pVM, false /*fInRendezvous*/);
3500 PGM_UNLOCK(pVM);
3501 return !cFound && hMmio2 != NIL_PGMMMIO2HANDLE ? VERR_NOT_FOUND : rc;
3502}
3503
3504
3505/**
3506 * Worker form PGMR3PhysMmio2Map.
3507 */
3508static int pgmR3PhysMmio2MapLocked(PVM pVM, uint32_t const idxFirst, uint32_t const cChunks,
3509 RTGCPHYS const GCPhys, RTGCPHYS const GCPhysLast)
3510{
3511 /*
3512 * Validate the mapped status now that we've got the lock.
3513 */
3514 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
3515 {
3516 AssertReturn( pVM->pgm.s.aMmio2Ranges[idx].GCPhys == NIL_RTGCPHYS
3517 && !(pVM->pgm.s.aMmio2Ranges[idx].fFlags & PGMREGMMIO2RANGE_F_MAPPED),
3518 VERR_WRONG_ORDER);
3519 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
3520 AssertReturn(pRamRange->GCPhys == NIL_RTGCPHYS, VERR_INTERNAL_ERROR_3);
3521 AssertReturn(pRamRange->GCPhysLast == NIL_RTGCPHYS, VERR_INTERNAL_ERROR_3);
3522 Assert(pRamRange->pbR3 == pVM->pgm.s.aMmio2Ranges[idx].pbR3);
3523 Assert(pRamRange->idRange == pVM->pgm.s.aMmio2Ranges[idx].idRamRange);
3524 }
3525
3526 const char * const pszDesc = pVM->pgm.s.apMmio2RamRanges[idxFirst]->pszDesc;
3527#ifdef VBOX_WITH_NATIVE_NEM
3528 uint32_t const fNemFlags = NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2
3529 | (pVM->pgm.s.aMmio2Ranges[idxFirst].fFlags & PGMREGMMIO2RANGE_F_TRACK_DIRTY_PAGES
3530 ? NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES : 0);
3531#endif
3532
3533 /*
3534 * Now, check if this falls into a regular RAM range or if we should use
3535 * the ad-hoc one.
3536 *
3537 * Note! For reasons of simplictly, we're considering the whole MMIO2 area
3538 * here rather than individual chunks.
3539 */
3540 int rc = VINF_SUCCESS;
3541 uint32_t idxInsert = UINT32_MAX;
3542 PPGMRAMRANGE const pOverlappingRange = pgmR3PhysRamRangeFindOverlapping(pVM, GCPhys, GCPhysLast, &idxInsert);
3543 if (pOverlappingRange)
3544 {
3545 /* Simplification: all within the same range. */
3546 AssertLogRelMsgReturn( GCPhys >= pOverlappingRange->GCPhys
3547 && GCPhysLast <= pOverlappingRange->GCPhysLast,
3548 ("%RGp-%RGp (MMIO2/%s) falls partly outside %RGp-%RGp (%s)\n",
3549 GCPhys, GCPhysLast, pszDesc,
3550 pOverlappingRange->GCPhys, pOverlappingRange->GCPhysLast, pOverlappingRange->pszDesc),
3551 VERR_PGM_RAM_CONFLICT);
3552
3553 /* Check that is isn't an ad hoc range, but a real RAM range. */
3554 AssertLogRelMsgReturn(!PGM_RAM_RANGE_IS_AD_HOC(pOverlappingRange),
3555 ("%RGp-%RGp (MMIO2/%s) mapping attempt in non-RAM range: %RGp-%RGp (%s)\n",
3556 GCPhys, GCPhysLast, pszDesc,
3557 pOverlappingRange->GCPhys, pOverlappingRange->GCPhysLast, pOverlappingRange->pszDesc),
3558 VERR_PGM_RAM_CONFLICT);
3559
3560 /* There can only be one MMIO2 chunk matching here! */
3561 AssertLogRelMsgReturn(cChunks == 1,
3562 ("%RGp-%RGp (MMIO2/%s) consists of %u chunks whereas the RAM (%s) somehow doesn't!\n",
3563 GCPhys, GCPhysLast, pszDesc, cChunks, pOverlappingRange->pszDesc),
3564 VERR_PGM_PHYS_MMIO_EX_IPE);
3565
3566 /* Check that it's all RAM pages. */
3567 PCPGMPAGE pPage = &pOverlappingRange->aPages[(GCPhys - pOverlappingRange->GCPhys) >> GUEST_PAGE_SHIFT];
3568 uint32_t const cMmio2Pages = pVM->pgm.s.apMmio2RamRanges[idxFirst]->cb >> GUEST_PAGE_SHIFT;
3569 uint32_t cPagesLeft = cMmio2Pages;
3570 while (cPagesLeft-- > 0)
3571 {
3572 AssertLogRelMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
3573 ("%RGp-%RGp (MMIO2/%s): %RGp is not a RAM page - type=%d desc=%s\n", GCPhys, GCPhysLast,
3574 pszDesc, pOverlappingRange->GCPhys, PGM_PAGE_GET_TYPE(pPage), pOverlappingRange->pszDesc),
3575 VERR_PGM_RAM_CONFLICT);
3576 pPage++;
3577 }
3578
3579#ifdef VBOX_WITH_PGM_NEM_MODE
3580 /* We cannot mix MMIO2 into a RAM range in simplified memory mode because pOverlappingRange->pbR3 can't point
3581 both at the RAM and MMIO2, so we won't ever write & read from the actual MMIO2 memory if we try. */
3582 AssertLogRelMsgReturn(!VM_IS_NEM_ENABLED(pVM),
3583 ("Putting %s at %RGp-%RGp is not possible in NEM mode because existing %RGp-%RGp (%s) mapping\n",
3584 pszDesc, GCPhys, GCPhysLast,
3585 pOverlappingRange->GCPhys, pOverlappingRange->GCPhysLast, pOverlappingRange->pszDesc),
3586 VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE);
3587#endif
3588
3589 /*
3590 * Make all the pages in the range MMIO/ZERO pages, freeing any
3591 * RAM pages currently mapped here. This might not be 100% correct,
3592 * but so what, we do the same from MMIO...
3593 */
3594 rc = pgmR3PhysFreePageRange(pVM, pOverlappingRange, GCPhys, GCPhysLast, NULL);
3595 AssertRCReturn(rc, rc);
3596
3597 Log(("PGMR3PhysMmio2Map: %RGp-%RGp %s - inside %RGp-%RGp %s\n", GCPhys, GCPhysLast, pszDesc,
3598 pOverlappingRange->GCPhys, pOverlappingRange->GCPhysLast, pOverlappingRange->pszDesc));
3599
3600 /*
3601 * We're all in for mapping it now. Update the MMIO2 range to reflect it.
3602 */
3603 pVM->pgm.s.aMmio2Ranges[idxFirst].GCPhys = GCPhys;
3604 pVM->pgm.s.aMmio2Ranges[idxFirst].fFlags |= PGMREGMMIO2RANGE_F_OVERLAPPING | PGMREGMMIO2RANGE_F_MAPPED;
3605
3606 /*
3607 * Replace the pages in the range.
3608 */
3609 PPGMPAGE pPageSrc = &pVM->pgm.s.apMmio2RamRanges[idxFirst]->aPages[0];
3610 PPGMPAGE pPageDst = &pOverlappingRange->aPages[(GCPhys - pOverlappingRange->GCPhys) >> GUEST_PAGE_SHIFT];
3611 cPagesLeft = cMmio2Pages;
3612 while (cPagesLeft-- > 0)
3613 {
3614 Assert(PGM_PAGE_IS_MMIO(pPageDst));
3615
3616 RTHCPHYS const HCPhys = PGM_PAGE_GET_HCPHYS(pPageSrc);
3617 uint32_t const idPage = PGM_PAGE_GET_PAGEID(pPageSrc);
3618 PGM_PAGE_SET_PAGEID(pVM, pPageDst, idPage);
3619 PGM_PAGE_SET_HCPHYS(pVM, pPageDst, HCPhys);
3620 PGM_PAGE_SET_TYPE(pVM, pPageDst, PGMPAGETYPE_MMIO2);
3621 PGM_PAGE_SET_STATE(pVM, pPageDst, PGM_PAGE_STATE_ALLOCATED);
3622 PGM_PAGE_SET_PDE_TYPE(pVM, pPageDst, PGM_PAGE_PDE_TYPE_DONTCARE);
3623 PGM_PAGE_SET_PTE_INDEX(pVM, pPageDst, 0);
3624 PGM_PAGE_SET_TRACKING(pVM, pPageDst, 0);
3625 /* NEM state is not relevant, see VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE above. */
3626
3627 pVM->pgm.s.cZeroPages--;
3628 pPageSrc++;
3629 pPageDst++;
3630 }
3631
3632 /* Force a PGM pool flush as guest ram references have been changed. */
3633 /** @todo not entirely SMP safe; assuming for now the guest takes
3634 * care of this internally (not touch mapped mmio while changing the
3635 * mapping). */
3636 PVMCPU pVCpu = VMMGetCpu(pVM);
3637 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
3638 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
3639 }
3640 else
3641 {
3642 /*
3643 * No RAM range, insert the ones prepared during registration.
3644 */
3645 Log(("PGMR3PhysMmio2Map: %RGp-%RGp %s - no RAM overlap\n", GCPhys, GCPhysLast, pszDesc));
3646 RTGCPHYS GCPhysCur = GCPhys;
3647 uint32_t iChunk = 0;
3648 uint32_t idx = idxFirst;
3649 for (; iChunk < cChunks; iChunk++, idx++)
3650 {
3651 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idx];
3652 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
3653 Assert(pRamRange->idRange == pMmio2->idRamRange);
3654 Assert(pMmio2->GCPhys == NIL_RTGCPHYS);
3655
3656#ifdef VBOX_WITH_NATIVE_NEM
3657 /* Tell NEM and get the new NEM state for the pages. */
3658 uint8_t u2NemState = 0;
3659 if (VM_IS_NEM_ENABLED(pVM))
3660 {
3661 rc = NEMR3NotifyPhysMmioExMapEarly(pVM, GCPhysCur, pRamRange->cb, fNemFlags, NULL /*pvRam*/, pRamRange->pbR3,
3662 &u2NemState, &pRamRange->uNemRange);
3663 AssertLogRelMsgBreak(RT_SUCCESS(rc),
3664 ("%RGp LB %RGp fFlags=%#x (%s)\n",
3665 GCPhysCur, pRamRange->cb, pMmio2->fFlags, pRamRange->pszDesc));
3666 pMmio2->fFlags |= PGMREGMMIO2RANGE_F_MAPPED; /* Set this early to indicate that NEM has been notified. */
3667 }
3668#endif
3669
3670 /* Clear the tracking data of pages we're going to reactivate. */
3671 PPGMPAGE pPageSrc = &pRamRange->aPages[0];
3672 uint32_t cPagesLeft = pRamRange->cb >> GUEST_PAGE_SHIFT;
3673 while (cPagesLeft-- > 0)
3674 {
3675 PGM_PAGE_SET_TRACKING(pVM, pPageSrc, 0);
3676 PGM_PAGE_SET_PTE_INDEX(pVM, pPageSrc, 0);
3677#ifdef VBOX_WITH_NATIVE_NEM
3678 PGM_PAGE_SET_NEM_STATE(pPageSrc, u2NemState);
3679#endif
3680 pPageSrc++;
3681 }
3682
3683 /* Insert the RAM range into the lookup table. */
3684 rc = pgmR3PhysRamRangeInsertLookup(pVM, pRamRange, GCPhysCur, &idxInsert);
3685 AssertRCBreak(rc);
3686
3687 /* Mark the range as fully mapped. */
3688 pMmio2->fFlags &= ~PGMREGMMIO2RANGE_F_OVERLAPPING;
3689 pMmio2->fFlags |= PGMREGMMIO2RANGE_F_MAPPED;
3690 pMmio2->GCPhys = GCPhysCur;
3691
3692 /* Advance. */
3693 GCPhysCur += pRamRange->cb;
3694 }
3695 if (RT_FAILURE(rc))
3696 {
3697 /*
3698 * Bail out anything we've done so far.
3699 */
3700 idxInsert -= 1;
3701 do
3702 {
3703 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idx];
3704 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
3705
3706#ifdef VBOX_WITH_NATIVE_NEM
3707 if ( VM_IS_NEM_ENABLED(pVM)
3708 && (pVM->pgm.s.aMmio2Ranges[idx].fFlags & PGMREGMMIO2RANGE_F_MAPPED))
3709 {
3710 uint8_t u2NemState = UINT8_MAX;
3711 NEMR3NotifyPhysMmioExUnmap(pVM, GCPhysCur, pRamRange->cb, fNemFlags, NULL, pRamRange->pbR3,
3712 &u2NemState, &pRamRange->uNemRange);
3713 if (u2NemState != UINT8_MAX)
3714 pgmPhysSetNemStateForPages(pRamRange->aPages, pRamRange->cb >> GUEST_PAGE_SHIFT, u2NemState);
3715 }
3716#endif
3717 if (pMmio2->GCPhys != NIL_RTGCPHYS)
3718 pgmR3PhysRamRangeRemoveLookup(pVM, pRamRange, &idxInsert);
3719
3720 pMmio2->GCPhys = NIL_RTGCPHYS;
3721 pMmio2->fFlags &= ~PGMREGMMIO2RANGE_F_MAPPED;
3722
3723 idx--;
3724 } while (iChunk-- > 0);
3725 return rc;
3726 }
3727 }
3728
3729 /*
3730 * If the range have dirty page monitoring enabled, enable that.
3731 *
3732 * We ignore failures here for now because if we fail, the whole mapping
3733 * will have to be reversed and we'll end up with nothing at all on the
3734 * screen and a grumpy guest, whereas if we just go on, we'll only have
3735 * visual distortions to gripe about. There will be something in the
3736 * release log.
3737 */
3738 if ( pVM->pgm.s.aMmio2Ranges[idxFirst].pPhysHandlerR3
3739 && (pVM->pgm.s.aMmio2Ranges[idxFirst].fFlags & PGMREGMMIO2RANGE_F_TRACKING_ENABLED))
3740 pgmR3PhysMmio2EnableDirtyPageTracing(pVM, idxFirst, cChunks);
3741
3742 /* Flush physical page map TLB. */
3743 pgmPhysInvalidatePageMapTLB(pVM, false /*fInRendezvous*/);
3744
3745#ifdef VBOX_WITH_NATIVE_NEM
3746 /*
3747 * Late NEM notification (currently unused).
3748 */
3749 if (VM_IS_NEM_ENABLED(pVM))
3750 {
3751 if (pOverlappingRange)
3752 {
3753 uint8_t * const pbRam = pOverlappingRange->pbR3 ? &pOverlappingRange->pbR3[GCPhys - pOverlappingRange->GCPhys] : NULL;
3754 rc = NEMR3NotifyPhysMmioExMapLate(pVM, GCPhys, GCPhysLast - GCPhys + 1U,
3755 fNemFlags | NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE, pbRam,
3756 pVM->pgm.s.aMmio2Ranges[idxFirst].pbR3, NULL /*puNemRange*/);
3757 }
3758 else
3759 {
3760 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
3761 {
3762 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
3763 Assert(pVM->pgm.s.aMmio2Ranges[idx].GCPhys == pRamRange->GCPhys);
3764
3765 rc = NEMR3NotifyPhysMmioExMapLate(pVM, pRamRange->GCPhys, pRamRange->cb, fNemFlags, NULL /*pvRam*/,
3766 pRamRange->pbR3, &pRamRange->uNemRange);
3767 AssertRCBreak(rc);
3768 }
3769 }
3770 AssertLogRelRCReturnStmt(rc,
3771 PGMR3PhysMmio2Unmap(pVM, pVM->pgm.s.aMmio2Ranges[idxFirst].pDevInsR3, idxFirst + 1, GCPhys),
3772 rc);
3773 }
3774#endif
3775
3776 return VINF_SUCCESS;
3777}
3778
3779
3780/**
3781 * Maps a MMIO2 region.
3782 *
3783 * This is typically done when a guest / the bios / state loading changes the
3784 * PCI config. The replacing of base memory has the same restrictions as during
3785 * registration, of course.
3786 *
3787 * @returns VBox status code.
3788 *
3789 * @param pVM The cross context VM structure.
3790 * @param pDevIns The device instance owning the region.
3791 * @param hMmio2 The handle of the region to map.
3792 * @param GCPhys The guest-physical address to be remapped.
3793 */
3794VMMR3_INT_DECL(int) PGMR3PhysMmio2Map(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS GCPhys)
3795{
3796 /*
3797 * Validate input.
3798 */
3799 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
3800 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
3801 AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
3802 AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
3803 AssertReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
3804 AssertReturn(hMmio2 != NIL_PGMMMIO2HANDLE, VERR_INVALID_HANDLE);
3805
3806 uint32_t cChunks = 0;
3807 uint32_t const idxFirst = pgmR3PhysMmio2ResolveHandle(pVM, pDevIns, hMmio2, &cChunks);
3808 AssertReturn((int32_t)idxFirst >= 0, (int32_t)idxFirst);
3809
3810 /* Gather the full range size so we can validate the mapping address properly. */
3811 RTGCPHYS cbRange = 0;
3812 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
3813 cbRange += pVM->pgm.s.apMmio2RamRanges[idx]->cb;
3814
3815 RTGCPHYS const GCPhysLast = GCPhys + cbRange - 1;
3816 AssertLogRelReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
3817
3818 /*
3819 * Take the PGM lock and call worker.
3820 */
3821 int rc = PGM_LOCK(pVM);
3822 AssertRCReturn(rc, rc);
3823
3824 rc = pgmR3PhysMmio2MapLocked(pVM, idxFirst, cChunks, GCPhys, GCPhysLast);
3825#ifdef VBOX_STRICT
3826 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, false /*fRamRelaxed*/);
3827#endif
3828
3829 PGM_UNLOCK(pVM);
3830 return rc;
3831}
3832
3833
3834/**
3835 * Worker form PGMR3PhysMmio2Map.
3836 */
3837static int pgmR3PhysMmio2UnmapLocked(PVM pVM, uint32_t const idxFirst, uint32_t const cChunks, RTGCPHYS const GCPhysIn)
3838{
3839 /*
3840 * Validate input.
3841 */
3842 RTGCPHYS cbRange = 0;
3843 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
3844 {
3845 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idx];
3846 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
3847 AssertReturn(pMmio2->idRamRange == pRamRange->idRange, VERR_INTERNAL_ERROR_3);
3848 AssertReturn(pMmio2->fFlags & PGMREGMMIO2RANGE_F_MAPPED, VERR_WRONG_ORDER);
3849 AssertReturn(pMmio2->GCPhys != NIL_RTGCPHYS, VERR_WRONG_ORDER);
3850 cbRange += pRamRange->cb;
3851 }
3852
3853 PPGMREGMMIO2RANGE const pFirstMmio2 = &pVM->pgm.s.aMmio2Ranges[idxFirst];
3854 PPGMRAMRANGE const pFirstRamRange = pVM->pgm.s.apMmio2RamRanges[idxFirst];
3855 const char * const pszDesc = pFirstRamRange->pszDesc;
3856 AssertLogRelMsgReturn(GCPhysIn == pFirstMmio2->GCPhys || GCPhysIn == NIL_RTGCPHYS,
3857 ("GCPhys=%RGp, actual address is %RGp\n", GCPhysIn, pFirstMmio2->GCPhys),
3858 VERR_MISMATCH);
3859 RTGCPHYS const GCPhys = pFirstMmio2->GCPhys; /* (it's always NIL_RTGCPHYS) */
3860 Log(("PGMR3PhysMmio2Unmap: %RGp-%RGp %s\n", GCPhys, GCPhys + cbRange - 1U, pszDesc));
3861
3862 uint16_t const fOldFlags = pFirstMmio2->fFlags;
3863 Assert(fOldFlags & PGMREGMMIO2RANGE_F_MAPPED);
3864
3865 /* Find the first entry in the lookup table and verify the overlapping flag. */
3866 uint32_t idxLookup = pgmR3PhysRamRangeFindOverlappingIndex(pVM, GCPhys, GCPhys + pFirstRamRange->cb - 1U);
3867 AssertLogRelMsgReturn(idxLookup < pVM->pgm.s.RamRangeUnion.cLookupEntries,
3868 ("MMIO2 range not found at %RGp LB %RGp in the lookup table! (%s)\n",
3869 GCPhys, pFirstRamRange->cb, pszDesc),
3870 VERR_INTERNAL_ERROR_2);
3871
3872 uint32_t const idLookupRange = PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup]);
3873 AssertLogRelReturn(idLookupRange != 0 && idLookupRange <= pVM->pgm.s.idRamRangeMax, VERR_INTERNAL_ERROR_5);
3874 PPGMRAMRANGE const pLookupRange = pVM->pgm.s.apRamRanges[idLookupRange];
3875 AssertLogRelReturn(pLookupRange, VERR_INTERNAL_ERROR_3);
3876
3877 AssertLogRelMsgReturn(fOldFlags & PGMREGMMIO2RANGE_F_OVERLAPPING
3878 ? pLookupRange != pFirstRamRange : pLookupRange == pFirstRamRange,
3879 ("MMIO2 unmap mixup at %RGp LB %RGp fl=%#x (%s) vs %RGp LB %RGp (%s)\n",
3880 GCPhys, cbRange, fOldFlags, pszDesc, pLookupRange->GCPhys, pLookupRange->cb, pLookupRange->pszDesc),
3881 VERR_INTERNAL_ERROR_4);
3882
3883 /*
3884 * If monitoring dirty pages, we must deregister the handlers first.
3885 */
3886 if ( pFirstMmio2->pPhysHandlerR3
3887 && (fOldFlags & PGMREGMMIO2RANGE_F_TRACKING_ENABLED))
3888 pgmR3PhysMmio2DisableDirtyPageTracing(pVM, idxFirst, cChunks);
3889
3890 /*
3891 * Unmap it.
3892 */
3893 int rcRet = VINF_SUCCESS;
3894#ifdef VBOX_WITH_NATIVE_NEM
3895 uint32_t const fNemFlags = NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2
3896 | (fOldFlags & PGMREGMMIO2RANGE_F_TRACK_DIRTY_PAGES
3897 ? NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES : 0);
3898#endif
3899 if (fOldFlags & PGMREGMMIO2RANGE_F_OVERLAPPING)
3900 {
3901 /*
3902 * We've replaced RAM, replace with zero pages.
3903 *
3904 * Note! This is where we might differ a little from a real system, because
3905 * it's likely to just show the RAM pages as they were before the
3906 * MMIO2 region was mapped here.
3907 */
3908 /* Only one chunk allowed when overlapping! */
3909 Assert(cChunks == 1);
3910 /* No NEM stuff should ever get here, see assertion in the mapping function. */
3911 AssertReturn(!VM_IS_NEM_ENABLED(pVM), VERR_INTERNAL_ERROR_4);
3912
3913 /* Restore the RAM pages we've replaced. */
3914 PPGMPAGE pPageDst = &pLookupRange->aPages[(pFirstRamRange->GCPhys - pLookupRange->GCPhys) >> GUEST_PAGE_SHIFT];
3915 uint32_t cPagesLeft = pFirstRamRange->cb >> GUEST_PAGE_SHIFT;
3916 pVM->pgm.s.cZeroPages += cPagesLeft;
3917 while (cPagesLeft-- > 0)
3918 {
3919 PGM_PAGE_INIT_ZERO(pPageDst, pVM, PGMPAGETYPE_RAM);
3920 pPageDst++;
3921 }
3922
3923 /* Update range state. */
3924 pFirstMmio2->fFlags &= ~(PGMREGMMIO2RANGE_F_OVERLAPPING | PGMREGMMIO2RANGE_F_MAPPED);
3925 pFirstMmio2->GCPhys = NIL_RTGCPHYS;
3926 Assert(pFirstRamRange->GCPhys == NIL_RTGCPHYS);
3927 Assert(pFirstRamRange->GCPhysLast == NIL_RTGCPHYS);
3928 }
3929 else
3930 {
3931 /*
3932 * Unlink the chunks related to the MMIO/MMIO2 region.
3933 */
3934 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
3935 {
3936 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idx];
3937 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
3938 Assert(pMmio2->idRamRange == pRamRange->idRange);
3939 Assert(pMmio2->GCPhys == pRamRange->GCPhys);
3940
3941#ifdef VBOX_WITH_NATIVE_NEM
3942 if (VM_IS_NEM_ENABLED(pVM)) /* Notify NEM. */
3943 {
3944 uint8_t u2State = UINT8_MAX;
3945 int rc = NEMR3NotifyPhysMmioExUnmap(pVM, pRamRange->GCPhys, pRamRange->cb, fNemFlags,
3946 NULL, pMmio2->pbR3, &u2State, &pRamRange->uNemRange);
3947 AssertLogRelMsgStmt(RT_SUCCESS(rc),
3948 ("NEMR3NotifyPhysMmioExUnmap failed: %Rrc - GCPhys=RGp LB %RGp fNemFlags=%#x pbR3=%p %s\n",
3949 rc, pRamRange->GCPhys, pRamRange->cb, fNemFlags, pMmio2->pbR3, pRamRange->pszDesc),
3950 rcRet = rc);
3951 if (u2State != UINT8_MAX)
3952 pgmPhysSetNemStateForPages(pRamRange->aPages, pRamRange->cb >> GUEST_PAGE_SHIFT, u2State);
3953 }
3954#endif
3955
3956 int rc = pgmR3PhysRamRangeRemoveLookup(pVM, pRamRange, &idxLookup);
3957 AssertLogRelMsgStmt(RT_SUCCESS(rc),
3958 ("pgmR3PhysRamRangeRemoveLookup failed: %Rrc - GCPhys=%RGp LB %RGp %s\n",
3959 rc, pRamRange->GCPhys, pRamRange->cb, pRamRange->pszDesc),
3960 rcRet = rc);
3961
3962 pMmio2->GCPhys = NIL_RTGCPHYS;
3963 pMmio2->fFlags &= ~(PGMREGMMIO2RANGE_F_OVERLAPPING | PGMREGMMIO2RANGE_F_MAPPED);
3964 Assert(pRamRange->GCPhys == NIL_RTGCPHYS);
3965 Assert(pRamRange->GCPhysLast == NIL_RTGCPHYS);
3966 }
3967 }
3968
3969 /* Force a PGM pool flush as guest ram references have been changed. */
3970 /** @todo not entirely SMP safe; assuming for now the guest takes care
3971 * of this internally (not touch mapped mmio while changing the
3972 * mapping). */
3973 PVMCPU pVCpu = VMMGetCpu(pVM);
3974 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
3975 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
3976
3977 pgmPhysInvalidatePageMapTLB(pVM, false /*fInRendezvous*/);
3978 /* pgmPhysInvalidRamRangeTlbs(pVM); - not necessary */
3979
3980 return rcRet;
3981}
3982
3983
3984/**
3985 * Unmaps an MMIO2 region.
3986 *
3987 * This is typically done when a guest / the bios / state loading changes the
3988 * PCI config. The replacing of base memory has the same restrictions as during
3989 * registration, of course.
3990 */
3991VMMR3_INT_DECL(int) PGMR3PhysMmio2Unmap(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS GCPhys)
3992{
3993 /*
3994 * Validate input
3995 */
3996 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
3997 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
3998 AssertReturn(hMmio2 != NIL_PGMMMIO2HANDLE, VERR_INVALID_HANDLE);
3999 if (GCPhys != NIL_RTGCPHYS)
4000 {
4001 AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
4002 AssertReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
4003 }
4004
4005 uint32_t cChunks = 0;
4006 uint32_t const idxFirst = pgmR3PhysMmio2ResolveHandle(pVM, pDevIns, hMmio2, &cChunks);
4007 AssertReturn((int32_t)idxFirst >= 0, (int32_t)idxFirst);
4008
4009
4010 /*
4011 * Take the PGM lock and call worker.
4012 */
4013 int rc = PGM_LOCK(pVM);
4014 AssertRCReturn(rc, rc);
4015
4016 rc = pgmR3PhysMmio2UnmapLocked(pVM, idxFirst, cChunks, GCPhys);
4017#ifdef VBOX_STRICT
4018 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, false /*fRamRelaxed*/);
4019#endif
4020
4021 PGM_UNLOCK(pVM);
4022 return rc;
4023}
4024
4025
4026/**
4027 * Reduces the mapping size of a MMIO2 region.
4028 *
4029 * This is mainly for dealing with old saved states after changing the default
4030 * size of a mapping region. See PDMDevHlpMmio2Reduce and
4031 * PDMPCIDEV::pfnRegionLoadChangeHookR3.
4032 *
4033 * The region must not currently be mapped when making this call. The VM state
4034 * must be state restore or VM construction.
4035 *
4036 * @returns VBox status code.
4037 * @param pVM The cross context VM structure.
4038 * @param pDevIns The device instance owning the region.
4039 * @param hMmio2 The handle of the region to reduce.
4040 * @param cbRegion The new mapping size.
4041 */
4042VMMR3_INT_DECL(int) PGMR3PhysMmio2Reduce(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS cbRegion)
4043{
4044 /*
4045 * Validate input
4046 */
4047 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
4048 AssertReturn(hMmio2 != NIL_PGMMMIO2HANDLE && hMmio2 != 0 && hMmio2 <= RT_ELEMENTS(pVM->pgm.s.aMmio2Ranges),
4049 VERR_INVALID_HANDLE);
4050 AssertReturn(cbRegion >= GUEST_PAGE_SIZE, VERR_INVALID_PARAMETER);
4051 AssertReturn(!(cbRegion & GUEST_PAGE_OFFSET_MASK), VERR_UNSUPPORTED_ALIGNMENT);
4052
4053 PVMCPU const pVCpu = VMMGetCpu(pVM);
4054 AssertReturn(pVCpu && pVCpu->idCpu == 0, VERR_VM_THREAD_NOT_EMT);
4055
4056 VMSTATE const enmVmState = VMR3GetState(pVM);
4057 AssertLogRelMsgReturn( enmVmState == VMSTATE_CREATING
4058 || enmVmState == VMSTATE_LOADING,
4059 ("enmVmState=%d (%s)\n", enmVmState, VMR3GetStateName(enmVmState)),
4060 VERR_VM_INVALID_VM_STATE);
4061
4062 /*
4063 * Grab the PGM lock and validate the request properly.
4064 */
4065 int rc = PGM_LOCK(pVM);
4066 AssertRCReturn(rc, rc);
4067
4068 uint32_t cChunks = 0;
4069 uint32_t const idxFirst = pgmR3PhysMmio2ResolveHandle(pVM, pDevIns, hMmio2, &cChunks);
4070 if ((int32_t)idxFirst >= 0)
4071 {
4072 PPGMREGMMIO2RANGE const pFirstMmio2 = &pVM->pgm.s.aMmio2Ranges[idxFirst];
4073 PPGMRAMRANGE const pFirstRamRange = pVM->pgm.s.apMmio2RamRanges[idxFirst];
4074 if ( !(pFirstMmio2->fFlags & PGMREGMMIO2RANGE_F_MAPPED)
4075 && pFirstMmio2->GCPhys == NIL_RTGCPHYS)
4076 {
4077 /*
4078 * NOTE! Current implementation does not support multiple ranges.
4079 * Implement when there is a real world need and thus a testcase.
4080 */
4081 if (cChunks == 1)
4082 {
4083 /*
4084 * The request has to be within the initial size.
4085 */
4086 if (cbRegion <= pFirstMmio2->cbReal)
4087 {
4088 /*
4089 * All we have to do is modify the size stored in the RAM range,
4090 * as it is the one used when mapping it and such.
4091 * The two page counts stored in PGMR0PERVM remain unchanged.
4092 */
4093 Log(("PGMR3PhysMmio2Reduce: %s changes from %#RGp bytes (%#RGp) to %#RGp bytes.\n",
4094 pFirstRamRange->pszDesc, pFirstRamRange->cb, pFirstMmio2->cbReal, cbRegion));
4095 pFirstRamRange->cb = cbRegion;
4096 rc = VINF_SUCCESS;
4097 }
4098 else
4099 {
4100 AssertLogRelMsgFailed(("MMIO2/%s: cbRegion=%#RGp > cbReal=%#RGp\n",
4101 pFirstRamRange->pszDesc, cbRegion, pFirstMmio2->cbReal));
4102 rc = VERR_OUT_OF_RANGE;
4103 }
4104 }
4105 else
4106 {
4107 AssertLogRelMsgFailed(("MMIO2/%s: more than one chunk: %d (flags=%#x)\n",
4108 pFirstRamRange->pszDesc, cChunks, pFirstMmio2->fFlags));
4109 rc = VERR_NOT_SUPPORTED;
4110 }
4111 }
4112 else
4113 {
4114 AssertLogRelMsgFailed(("MMIO2/%s: cannot change size of mapped range: %RGp..%RGp\n", pFirstRamRange->pszDesc,
4115 pFirstMmio2->GCPhys, pFirstMmio2->GCPhys + pFirstRamRange->cb - 1U));
4116 rc = VERR_WRONG_ORDER;
4117 }
4118 }
4119 else
4120 rc = (int32_t)idxFirst;
4121
4122 PGM_UNLOCK(pVM);
4123 return rc;
4124}
4125
4126
4127/**
4128 * Validates @a hMmio2, making sure it belongs to @a pDevIns.
4129 *
4130 * @returns VBox status code.
4131 * @param pVM The cross context VM structure.
4132 * @param pDevIns The device which allegedly owns @a hMmio2.
4133 * @param hMmio2 The handle to validate.
4134 */
4135VMMR3_INT_DECL(int) PGMR3PhysMmio2ValidateHandle(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2)
4136{
4137 /*
4138 * Validate input
4139 */
4140 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
4141 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
4142
4143 /*
4144 * Just do this the simple way.
4145 */
4146 int rc = PGM_LOCK_VOID(pVM);
4147 AssertRCReturn(rc, rc);
4148 uint32_t cChunks;
4149 uint32_t const idxFirst = pgmR3PhysMmio2ResolveHandle(pVM, pDevIns, hMmio2, &cChunks);
4150 PGM_UNLOCK(pVM);
4151 AssertReturn((int32_t)idxFirst >= 0, (int32_t)idxFirst);
4152 return VINF_SUCCESS;
4153}
4154
4155
4156/**
4157 * Gets the mapping address of an MMIO2 region.
4158 *
4159 * @returns Mapping address, NIL_RTGCPHYS if not mapped or invalid handle.
4160 *
4161 * @param pVM The cross context VM structure.
4162 * @param pDevIns The device owning the MMIO2 handle.
4163 * @param hMmio2 The region handle.
4164 */
4165VMMR3_INT_DECL(RTGCPHYS) PGMR3PhysMmio2GetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2)
4166{
4167 RTGCPHYS GCPhysRet = NIL_RTGCPHYS;
4168
4169 int rc = PGM_LOCK_VOID(pVM);
4170 AssertRCReturn(rc, NIL_RTGCPHYS);
4171
4172 uint32_t cChunks;
4173 uint32_t const idxFirst = pgmR3PhysMmio2ResolveHandle(pVM, pDevIns, hMmio2, &cChunks);
4174 if ((int32_t)idxFirst >= 0)
4175 GCPhysRet = pVM->pgm.s.aMmio2Ranges[idxFirst].GCPhys;
4176
4177 PGM_UNLOCK(pVM);
4178 return NIL_RTGCPHYS;
4179}
4180
4181
4182/**
4183 * Worker for PGMR3PhysMmio2QueryAndResetDirtyBitmap.
4184 *
4185 * Called holding the PGM lock.
4186 */
4187static int pgmR3PhysMmio2QueryAndResetDirtyBitmapLocked(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2,
4188 void *pvBitmap, size_t cbBitmap)
4189{
4190 /*
4191 * Continue validation.
4192 */
4193 uint32_t cChunks;
4194 uint32_t const idxFirst = pgmR3PhysMmio2ResolveHandle(pVM, pDevIns, hMmio2, &cChunks);
4195 AssertReturn((int32_t)idxFirst >= 0, (int32_t)idxFirst);
4196 PPGMREGMMIO2RANGE const pFirstMmio2 = &pVM->pgm.s.aMmio2Ranges[idxFirst];
4197 AssertReturn(pFirstMmio2->fFlags & PGMREGMMIO2RANGE_F_TRACK_DIRTY_PAGES, VERR_INVALID_FUNCTION);
4198
4199 int rc = VINF_SUCCESS;
4200 if (cbBitmap || pvBitmap)
4201 {
4202 /*
4203 * Check the bitmap size and collect all the dirty flags.
4204 */
4205 RTGCPHYS cbTotal = 0;
4206 uint16_t fTotalDirty = 0;
4207 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
4208 {
4209 /* Not using cbReal here, because NEM is not in on the creating, only the mapping. */
4210 cbTotal += pVM->pgm.s.apMmio2RamRanges[idx]->cb;
4211 fTotalDirty |= pVM->pgm.s.aMmio2Ranges[idx].fFlags;
4212 }
4213 size_t const cbTotalBitmap = RT_ALIGN_T(cbTotal, GUEST_PAGE_SIZE * 64, RTGCPHYS) / GUEST_PAGE_SIZE / 8;
4214
4215 AssertPtrReturn(pvBitmap, VERR_INVALID_POINTER);
4216 AssertReturn(RT_ALIGN_P(pvBitmap, sizeof(uint64_t)) == pvBitmap, VERR_INVALID_POINTER);
4217 AssertReturn(cbBitmap == cbTotalBitmap, VERR_INVALID_PARAMETER);
4218
4219#ifdef VBOX_WITH_PGM_NEM_MODE
4220 /*
4221 * If there is no physical handler we must be in NEM mode and NEM
4222 * taking care of the dirty bit collecting.
4223 */
4224 if (pFirstMmio2->pPhysHandlerR3 == NULL)
4225 {
4226/** @todo This does not integrate at all with --execute-all-in-iem, leaving the
4227 * screen blank when using it together with --driverless. Fixing this won't be
4228 * entirely easy as we take the PGM_PAGE_HNDL_PHYS_STATE_DISABLED page status to
4229 * mean a dirty page. */
4230 AssertReturn(VM_IS_NEM_ENABLED(pVM), VERR_INTERNAL_ERROR_4);
4231 uint8_t *pbBitmap = (uint8_t *)pvBitmap;
4232 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
4233 {
4234 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
4235 size_t const cbBitmapChunk = (pRamRange->cb / GUEST_PAGE_SIZE + 7) / 8;
4236 Assert((RTGCPHYS)cbBitmapChunk * GUEST_PAGE_SIZE * 8 == pRamRange->cb);
4237 Assert(pRamRange->GCPhys == pVM->pgm.s.aMmio2Ranges[idx].GCPhys); /* (No MMIO2 inside RAM in NEM mode!)*/
4238 int rc2 = NEMR3PhysMmio2QueryAndResetDirtyBitmap(pVM, pRamRange->GCPhys, pRamRange->cb,
4239 pRamRange->uNemRange, pbBitmap, cbBitmapChunk);
4240 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
4241 rc = rc2;
4242 pbBitmap += pRamRange->cb / GUEST_PAGE_SIZE / 8;
4243 }
4244 }
4245 else
4246#endif
4247 if (fTotalDirty & PGMREGMMIO2RANGE_F_IS_DIRTY)
4248 {
4249 if ( (pFirstMmio2->fFlags & (PGMREGMMIO2RANGE_F_MAPPED | PGMREGMMIO2RANGE_F_TRACKING_ENABLED))
4250 == (PGMREGMMIO2RANGE_F_MAPPED | PGMREGMMIO2RANGE_F_TRACKING_ENABLED))
4251 {
4252 /*
4253 * Reset each chunk, gathering dirty bits.
4254 */
4255 RT_BZERO(pvBitmap, cbBitmap); /* simpler for now. */
4256 for (uint32_t iChunk = 0, idx = idxFirst, iPageNo = 0; iChunk < cChunks; iChunk++, idx++)
4257 {
4258 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idx];
4259 if (pMmio2->fFlags & PGMREGMMIO2RANGE_F_IS_DIRTY)
4260 {
4261 int rc2 = pgmHandlerPhysicalResetMmio2WithBitmap(pVM, pMmio2->GCPhys, pvBitmap, iPageNo);
4262 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
4263 rc = rc2;
4264 pMmio2->fFlags &= ~PGMREGMMIO2RANGE_F_IS_DIRTY;
4265 }
4266 iPageNo += pVM->pgm.s.apMmio2RamRanges[idx]->cb >> GUEST_PAGE_SHIFT;
4267 }
4268 }
4269 else
4270 {
4271 /*
4272 * If not mapped or tracking is disabled, we return the
4273 * PGMREGMMIO2RANGE_F_IS_DIRTY status for all pages. We cannot
4274 * get more accurate data than that after unmapping or disabling.
4275 */
4276 RT_BZERO(pvBitmap, cbBitmap);
4277 for (uint32_t iChunk = 0, idx = idxFirst, iPageNo = 0; iChunk < cChunks; iChunk++, idx++)
4278 {
4279 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
4280 PPGMREGMMIO2RANGE const pMmio2 = &pVM->pgm.s.aMmio2Ranges[idx];
4281 if (pMmio2->fFlags & PGMREGMMIO2RANGE_F_IS_DIRTY)
4282 {
4283 ASMBitSetRange(pvBitmap, iPageNo, iPageNo + (pRamRange->cb >> GUEST_PAGE_SHIFT));
4284 pMmio2->fFlags &= ~PGMREGMMIO2RANGE_F_IS_DIRTY;
4285 }
4286 iPageNo += pRamRange->cb >> GUEST_PAGE_SHIFT;
4287 }
4288 }
4289 }
4290 /*
4291 * No dirty chunks.
4292 */
4293 else
4294 RT_BZERO(pvBitmap, cbBitmap);
4295 }
4296 /*
4297 * No bitmap. Reset the region if tracking is currently enabled.
4298 */
4299 else if ( (pFirstMmio2->fFlags & (PGMREGMMIO2RANGE_F_MAPPED | PGMREGMMIO2RANGE_F_TRACKING_ENABLED))
4300 == (PGMREGMMIO2RANGE_F_MAPPED | PGMREGMMIO2RANGE_F_TRACKING_ENABLED))
4301 {
4302#ifdef VBOX_WITH_PGM_NEM_MODE
4303 if (pFirstMmio2->pPhysHandlerR3 == NULL)
4304 {
4305 AssertReturn(VM_IS_NEM_ENABLED(pVM), VERR_INTERNAL_ERROR_4);
4306 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
4307 {
4308 PPGMRAMRANGE const pRamRange = pVM->pgm.s.apMmio2RamRanges[idx];
4309 Assert(pRamRange->GCPhys == pVM->pgm.s.aMmio2Ranges[idx].GCPhys); /* (No MMIO2 inside RAM in NEM mode!)*/
4310 int rc2 = NEMR3PhysMmio2QueryAndResetDirtyBitmap(pVM, pRamRange->GCPhys, pRamRange->cb,
4311 pRamRange->uNemRange, NULL, 0);
4312 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
4313 rc = rc2;
4314 }
4315 }
4316 else
4317#endif
4318 {
4319 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
4320 {
4321 pVM->pgm.s.aMmio2Ranges[idx].fFlags &= ~PGMREGMMIO2RANGE_F_IS_DIRTY;
4322 int rc2 = PGMHandlerPhysicalReset(pVM, pVM->pgm.s.aMmio2Ranges[idx].GCPhys);
4323 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
4324 rc = rc2;
4325 }
4326 }
4327 }
4328
4329 return rc;
4330}
4331
4332
4333/**
4334 * Queries the dirty page bitmap and resets the monitoring.
4335 *
4336 * The PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag must be specified when
4337 * creating the range for this to work.
4338 *
4339 * @returns VBox status code.
4340 * @retval VERR_INVALID_FUNCTION if not created using
4341 * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES.
4342 * @param pVM The cross context VM structure.
4343 * @param pDevIns The device owning the MMIO2 handle.
4344 * @param hMmio2 The region handle.
4345 * @param pvBitmap The output bitmap. Must be 8-byte aligned. Ignored
4346 * when @a cbBitmap is zero.
4347 * @param cbBitmap The size of the bitmap. Must be the size of the whole
4348 * MMIO2 range, rounded up to the nearest 8 bytes.
4349 * When zero only a reset is done.
4350 */
4351VMMR3_INT_DECL(int) PGMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2,
4352 void *pvBitmap, size_t cbBitmap)
4353{
4354 /*
4355 * Do some basic validation before grapping the PGM lock and continuing.
4356 */
4357 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
4358 AssertReturn(RT_ALIGN_Z(cbBitmap, sizeof(uint64_t)) == cbBitmap, VERR_INVALID_PARAMETER);
4359 int rc = PGM_LOCK(pVM);
4360 if (RT_SUCCESS(rc))
4361 {
4362 STAM_PROFILE_START(&pVM->pgm.s.StatMmio2QueryAndResetDirtyBitmap, a);
4363 rc = pgmR3PhysMmio2QueryAndResetDirtyBitmapLocked(pVM, pDevIns, hMmio2, pvBitmap, cbBitmap);
4364 STAM_PROFILE_STOP(&pVM->pgm.s.StatMmio2QueryAndResetDirtyBitmap, a);
4365 PGM_UNLOCK(pVM);
4366 }
4367 return rc;
4368}
4369
4370
4371/**
4372 * Worker for PGMR3PhysMmio2ControlDirtyPageTracking
4373 *
4374 * Called owning the PGM lock.
4375 */
4376static int pgmR3PhysMmio2ControlDirtyPageTrackingLocked(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, bool fEnabled)
4377{
4378 /*
4379 * Continue validation.
4380 */
4381 uint32_t cChunks;
4382 uint32_t const idxFirst = pgmR3PhysMmio2ResolveHandle(pVM, pDevIns, hMmio2, &cChunks);
4383 AssertReturn((int32_t)idxFirst >= 0, (int32_t)idxFirst);
4384 PPGMREGMMIO2RANGE const pFirstMmio2 = &pVM->pgm.s.aMmio2Ranges[idxFirst];
4385 AssertReturn(pFirstMmio2->fFlags & PGMREGMMIO2RANGE_F_TRACK_DIRTY_PAGES, VERR_INVALID_FUNCTION);
4386
4387#ifdef VBOX_WITH_PGM_NEM_MODE
4388 /*
4389 * This is a nop if NEM is responsible for doing the tracking, we simply
4390 * leave the tracking on all the time there.
4391 */
4392 if (pFirstMmio2->pPhysHandlerR3 == NULL)
4393 {
4394 AssertReturn(VM_IS_NEM_ENABLED(pVM), VERR_INTERNAL_ERROR_4);
4395 return VINF_SUCCESS;
4396 }
4397#endif
4398
4399 /*
4400 * Anything needing doing?
4401 */
4402 if (fEnabled != RT_BOOL(pFirstMmio2->fFlags & PGMREGMMIO2RANGE_F_TRACKING_ENABLED))
4403 {
4404 LogFlowFunc(("fEnabled=%RTbool %s\n", fEnabled, pVM->pgm.s.apMmio2RamRanges[idxFirst]->pszDesc));
4405
4406 /*
4407 * Update the PGMREGMMIO2RANGE_F_TRACKING_ENABLED flag.
4408 */
4409 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
4410 if (fEnabled)
4411 pVM->pgm.s.aMmio2Ranges[idx].fFlags |= PGMREGMMIO2RANGE_F_TRACKING_ENABLED;
4412 else
4413 pVM->pgm.s.aMmio2Ranges[idx].fFlags &= ~PGMREGMMIO2RANGE_F_TRACKING_ENABLED;
4414
4415 /*
4416 * Enable/disable handlers if currently mapped.
4417 *
4418 * We ignore status codes here as we've already changed the flags and
4419 * returning a failure status now would be confusing. Besides, the two
4420 * functions will continue past failures. As argued in the mapping code,
4421 * it's in the release log.
4422 */
4423 if (pFirstMmio2->fFlags & PGMREGMMIO2RANGE_F_MAPPED)
4424 {
4425 if (fEnabled)
4426 pgmR3PhysMmio2EnableDirtyPageTracing(pVM, idxFirst, cChunks);
4427 else
4428 pgmR3PhysMmio2DisableDirtyPageTracing(pVM, idxFirst, cChunks);
4429 }
4430 }
4431 else
4432 LogFlowFunc(("fEnabled=%RTbool %s - no change\n", fEnabled, pVM->pgm.s.apMmio2RamRanges[idxFirst]->pszDesc));
4433
4434 return VINF_SUCCESS;
4435}
4436
4437
4438/**
4439 * Controls the dirty page tracking for an MMIO2 range.
4440 *
4441 * @returns VBox status code.
4442 * @param pVM The cross context VM structure.
4443 * @param pDevIns The device owning the MMIO2 memory.
4444 * @param hMmio2 The handle of the region.
4445 * @param fEnabled The new tracking state.
4446 */
4447VMMR3_INT_DECL(int) PGMR3PhysMmio2ControlDirtyPageTracking(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, bool fEnabled)
4448{
4449 /*
4450 * Do some basic validation before grapping the PGM lock and continuing.
4451 */
4452 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
4453 int rc = PGM_LOCK(pVM);
4454 if (RT_SUCCESS(rc))
4455 {
4456 rc = pgmR3PhysMmio2ControlDirtyPageTrackingLocked(pVM, pDevIns, hMmio2, fEnabled);
4457 PGM_UNLOCK(pVM);
4458 }
4459 return rc;
4460}
4461
4462
4463/**
4464 * Changes the region number of an MMIO2 region.
4465 *
4466 * This is only for dealing with save state issues, nothing else.
4467 *
4468 * @return VBox status code.
4469 *
4470 * @param pVM The cross context VM structure.
4471 * @param pDevIns The device owning the MMIO2 memory.
4472 * @param hMmio2 The handle of the region.
4473 * @param iNewRegion The new region index.
4474 *
4475 * @thread EMT(0)
4476 * @sa @bugref{9359}
4477 */
4478VMMR3_INT_DECL(int) PGMR3PhysMmio2ChangeRegionNo(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, uint32_t iNewRegion)
4479{
4480 /*
4481 * Validate input.
4482 */
4483 VM_ASSERT_EMT0_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
4484 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_LOADING, VERR_VM_INVALID_VM_STATE);
4485 AssertReturn(iNewRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
4486
4487 int rc = PGM_LOCK(pVM);
4488 AssertRCReturn(rc, rc);
4489
4490 /* Validate and resolve the handle. */
4491 uint32_t cChunks;
4492 uint32_t const idxFirst = pgmR3PhysMmio2ResolveHandle(pVM, pDevIns, hMmio2, &cChunks);
4493 if ((int32_t)idxFirst >= 0)
4494 {
4495 /* Check that the new range number is unused. */
4496 PPGMREGMMIO2RANGE const pConflict = pgmR3PhysMmio2Find(pVM, pDevIns, pVM->pgm.s.aMmio2Ranges[idxFirst].iSubDev,
4497 iNewRegion);
4498 if (!pConflict)
4499 {
4500 /*
4501 * Make the change.
4502 */
4503 for (uint32_t iChunk = 0, idx = idxFirst; iChunk < cChunks; iChunk++, idx++)
4504 pVM->pgm.s.aMmio2Ranges[idx].iRegion = (uint8_t)iNewRegion;
4505 rc = VINF_SUCCESS;
4506 }
4507 else
4508 {
4509 AssertLogRelMsgFailed(("MMIO2/%s: iNewRegion=%d conflicts with %s\n", pVM->pgm.s.apMmio2RamRanges[idxFirst]->pszDesc,
4510 iNewRegion, pVM->pgm.s.apMmio2RamRanges[pConflict->idRamRange]->pszDesc));
4511 rc = VERR_RESOURCE_IN_USE;
4512 }
4513 }
4514 else
4515 rc = (int32_t)idxFirst;
4516
4517 PGM_UNLOCK(pVM);
4518 return rc;
4519}
4520
4521
4522
4523/*********************************************************************************************************************************
4524* ROM *
4525*********************************************************************************************************************************/
4526
4527/**
4528 * Worker for PGMR3PhysRomRegister.
4529 *
4530 * This is here to simplify lock management, i.e. the caller does all the
4531 * locking and we can simply return without needing to remember to unlock
4532 * anything first.
4533 *
4534 * @returns VBox status code.
4535 * @param pVM The cross context VM structure.
4536 * @param pDevIns The device instance owning the ROM.
4537 * @param GCPhys First physical address in the range.
4538 * Must be page aligned!
4539 * @param cb The size of the range (in bytes).
4540 * Must be page aligned!
4541 * @param pvBinary Pointer to the binary data backing the ROM image.
4542 * @param cbBinary The size of the binary data pvBinary points to.
4543 * This must be less or equal to @a cb.
4544 * @param fFlags Mask of flags. PGMPHYS_ROM_FLAGS_SHADOWED
4545 * and/or PGMPHYS_ROM_FLAGS_PERMANENT_BINARY.
4546 * @param pszDesc Pointer to description string. This must not be freed.
4547 */
4548static int pgmR3PhysRomRegisterLocked(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb,
4549 const void *pvBinary, uint32_t cbBinary, uint8_t fFlags, const char *pszDesc)
4550{
4551 /*
4552 * Validate input.
4553 */
4554 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
4555 AssertReturn(RT_ALIGN_T(GCPhys, GUEST_PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
4556 AssertReturn(RT_ALIGN_T(cb, GUEST_PAGE_SIZE, RTGCPHYS) == cb, VERR_INVALID_PARAMETER);
4557 RTGCPHYS const GCPhysLast = GCPhys + (cb - 1);
4558 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
4559 AssertPtrReturn(pvBinary, VERR_INVALID_PARAMETER);
4560 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
4561 AssertReturn(!(fFlags & ~PGMPHYS_ROM_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
4562
4563 PVMCPU const pVCpu = VMMGetCpu(pVM);
4564 AssertReturn(pVCpu && pVCpu->idCpu == 0, VERR_VM_THREAD_NOT_EMT);
4565 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
4566
4567 const uint32_t cGuestPages = cb >> GUEST_PAGE_SHIFT;
4568 AssertReturn(cGuestPages <= PGM_MAX_PAGES_PER_ROM_RANGE, VERR_OUT_OF_RANGE);
4569
4570#ifdef VBOX_WITH_PGM_NEM_MODE
4571 const uint32_t cHostPages = RT_ALIGN_T(cb, HOST_PAGE_SIZE, RTGCPHYS) >> HOST_PAGE_SHIFT;
4572#endif
4573
4574 /*
4575 * Make sure we've got a free ROM range.
4576 */
4577 uint8_t const idRomRange = pVM->pgm.s.cRomRanges;
4578 AssertLogRelReturn(idRomRange < RT_ELEMENTS(pVM->pgm.s.apRomRanges), VERR_PGM_TOO_MANY_ROM_RANGES);
4579
4580 /*
4581 * Look thru the existing ROM range and make sure there aren't any
4582 * overlapping registration.
4583 */
4584 uint32_t const cRomRanges = RT_MIN(pVM->pgm.s.cRomRanges, RT_ELEMENTS(pVM->pgm.s.apRomRanges));
4585 for (uint32_t idx = 0; idx < cRomRanges; idx++)
4586 {
4587 PPGMROMRANGE const pRom = pVM->pgm.s.apRomRanges[idx];
4588 AssertLogRelMsgReturn( GCPhys > pRom->GCPhysLast
4589 || GCPhysLast < pRom->GCPhys,
4590 ("%RGp-%RGp (%s) conflicts with existing %RGp-%RGp (%s)\n",
4591 GCPhys, GCPhysLast, pszDesc,
4592 pRom->GCPhys, pRom->GCPhysLast, pRom->pszDesc),
4593 VERR_PGM_RAM_CONFLICT);
4594 }
4595
4596 /*
4597 * Find the RAM location and check for conflicts.
4598 *
4599 * Conflict detection is a bit different than for RAM registration since a
4600 * ROM can be located within a RAM range. So, what we have to check for is
4601 * other memory types (other than RAM that is) and that we don't span more
4602 * than one RAM range (lazy).
4603 */
4604 uint32_t idxInsert = UINT32_MAX;
4605 PPGMRAMRANGE const pOverlappingRange = pgmR3PhysRamRangeFindOverlapping(pVM, GCPhys, GCPhysLast, &idxInsert);
4606 if (pOverlappingRange)
4607 {
4608 /* completely within? */
4609 AssertLogRelMsgReturn( GCPhys >= pOverlappingRange->GCPhys
4610 && GCPhysLast <= pOverlappingRange->GCPhysLast,
4611 ("%RGp-%RGp (%s) falls partly outside %RGp-%RGp (%s)\n",
4612 GCPhys, GCPhysLast, pszDesc,
4613 pOverlappingRange->GCPhys, pOverlappingRange->GCPhysLast, pOverlappingRange->pszDesc),
4614 VERR_PGM_RAM_CONFLICT);
4615
4616 /* Check that is isn't an ad hoc range, but a real RAM range. */
4617 AssertLogRelMsgReturn(!PGM_RAM_RANGE_IS_AD_HOC(pOverlappingRange),
4618 ("%RGp-%RGp (ROM/%s) mapping attempt in non-RAM range: %RGp-%RGp (%s)\n",
4619 GCPhys, GCPhysLast, pszDesc,
4620 pOverlappingRange->GCPhys, pOverlappingRange->GCPhysLast, pOverlappingRange->pszDesc),
4621 VERR_PGM_RAM_CONFLICT);
4622
4623 /* All the pages must be RAM pages. */
4624 PPGMPAGE pPage = &pOverlappingRange->aPages[(GCPhys - pOverlappingRange->GCPhys) >> GUEST_PAGE_SHIFT];
4625 uint32_t cPagesLeft = cGuestPages;
4626 while (cPagesLeft-- > 0)
4627 {
4628 AssertLogRelMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
4629 ("%RGp (%R[pgmpage]) isn't a RAM page - registering %RGp-%RGp (%s).\n",
4630 GCPhys + ((RTGCPHYS)cPagesLeft << GUEST_PAGE_SHIFT), pPage, GCPhys, GCPhysLast, pszDesc),
4631 VERR_PGM_RAM_CONFLICT);
4632 AssertLogRelMsgReturn(PGM_PAGE_IS_ZERO(pPage) || PGM_IS_IN_NEM_MODE(pVM),
4633 ("%RGp (%R[pgmpage]) is not a ZERO page - registering %RGp-%RGp (%s).\n",
4634 GCPhys + ((RTGCPHYS)cPagesLeft << GUEST_PAGE_SHIFT), pPage, GCPhys, GCPhysLast, pszDesc),
4635 VERR_PGM_UNEXPECTED_PAGE_STATE);
4636 pPage++;
4637 }
4638 }
4639
4640 /*
4641 * Update the base memory reservation if necessary.
4642 */
4643 uint32_t const cExtraBaseCost = (pOverlappingRange ? 0 : cGuestPages)
4644 + (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED ? cGuestPages : 0);
4645 if (cExtraBaseCost)
4646 {
4647 int rc = MMR3IncreaseBaseReservation(pVM, cExtraBaseCost);
4648 AssertRCReturn(rc, rc);
4649 }
4650
4651#ifdef VBOX_WITH_NATIVE_NEM
4652 /*
4653 * Early NEM notification before we've made any changes or anything.
4654 */
4655 uint32_t const fNemNotify = (pOverlappingRange ? NEM_NOTIFY_PHYS_ROM_F_REPLACE : 0)
4656 | (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED ? NEM_NOTIFY_PHYS_ROM_F_SHADOW : 0);
4657 uint8_t u2NemState = UINT8_MAX;
4658 uint32_t uNemRange = 0;
4659 if (VM_IS_NEM_ENABLED(pVM))
4660 {
4661 int rc = NEMR3NotifyPhysRomRegisterEarly(pVM, GCPhys, cGuestPages << GUEST_PAGE_SHIFT,
4662 pOverlappingRange
4663 ? PGM_RAMRANGE_CALC_PAGE_R3PTR(pOverlappingRange, GCPhys) : NULL,
4664 fNemNotify, &u2NemState,
4665 pOverlappingRange ? &pOverlappingRange->uNemRange : &uNemRange);
4666 AssertLogRelRCReturn(rc, rc);
4667 }
4668#endif
4669
4670 /*
4671 * Allocate memory for the virgin copy of the RAM. In simplified memory
4672 * mode, we allocate memory for any ad-hoc RAM range and for shadow pages.
4673 */
4674 int rc;
4675 PGMMALLOCATEPAGESREQ pReq = NULL;
4676#ifdef VBOX_WITH_PGM_NEM_MODE
4677 void *pvRam = NULL;
4678 void *pvAlt = NULL;
4679 if (PGM_IS_IN_NEM_MODE(pVM))
4680 {
4681 if (!pOverlappingRange)
4682 {
4683 rc = SUPR3PageAlloc(cHostPages, 0, &pvRam);
4684 if (RT_FAILURE(rc))
4685 return rc;
4686 }
4687 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
4688 {
4689 rc = SUPR3PageAlloc(cHostPages, 0, &pvAlt);
4690 if (RT_FAILURE(rc))
4691 {
4692 if (pvRam)
4693 SUPR3PageFree(pvRam, cHostPages);
4694 return rc;
4695 }
4696 }
4697 }
4698 else
4699#endif
4700 {
4701 rc = GMMR3AllocatePagesPrepare(pVM, &pReq, cGuestPages, GMMACCOUNT_BASE);
4702 AssertRCReturn(rc, rc);
4703
4704 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++)
4705 {
4706 pReq->aPages[iPage].HCPhysGCPhys = GCPhys + (iPage << GUEST_PAGE_SHIFT);
4707 pReq->aPages[iPage].fZeroed = false;
4708 pReq->aPages[iPage].idPage = NIL_GMM_PAGEID;
4709 pReq->aPages[iPage].idSharedPage = NIL_GMM_PAGEID;
4710 }
4711
4712 rc = GMMR3AllocatePagesPerform(pVM, pReq);
4713 if (RT_FAILURE(rc))
4714 {
4715 GMMR3AllocatePagesCleanup(pReq);
4716 return rc;
4717 }
4718 }
4719
4720 /*
4721 * Allocate a RAM range if required.
4722 * Note! We don't clean up the RAM range here on failure, VM destruction does that.
4723 */
4724 rc = VINF_SUCCESS;
4725 PPGMRAMRANGE pRamRange = NULL;
4726 if (!pOverlappingRange)
4727 rc = pgmR3PhysAllocateRamRange(pVM, pVCpu, cGuestPages, PGM_RAM_RANGE_FLAGS_AD_HOC_ROM, &pRamRange);
4728 if (RT_SUCCESS(rc))
4729 {
4730 /*
4731 * Allocate a ROM range.
4732 * Note! We don't clean up the ROM range here on failure, VM destruction does that.
4733 */
4734 if (SUPR3IsDriverless())
4735 rc = pgmPhysRomRangeAllocCommon(pVM, cGuestPages, idRomRange, fFlags);
4736 else
4737 {
4738 PGMPHYSROMALLOCATERANGEREQ RomRangeReq;
4739 RomRangeReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
4740 RomRangeReq.Hdr.cbReq = sizeof(RomRangeReq);
4741 RomRangeReq.cbGuestPage = GUEST_PAGE_SIZE;
4742 RomRangeReq.cGuestPages = cGuestPages;
4743 RomRangeReq.idRomRange = idRomRange;
4744 RomRangeReq.fFlags = fFlags;
4745 rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_PGM_PHYS_ROM_ALLOCATE_RANGE, 0 /*u64Arg*/, &RomRangeReq.Hdr);
4746 }
4747 }
4748 if (RT_SUCCESS(rc))
4749 {
4750 /*
4751 * Initialize and map the RAM range (if required).
4752 */
4753 PPGMROMRANGE const pRomRange = pVM->pgm.s.apRomRanges[idRomRange];
4754 AssertPtr(pRomRange);
4755 uint32_t const idxFirstRamPage = pOverlappingRange ? (GCPhys - pOverlappingRange->GCPhys) >> GUEST_PAGE_SHIFT : 0;
4756 PPGMROMPAGE pRomPage = &pRomRange->aPages[0];
4757 if (!pOverlappingRange)
4758 {
4759 /* Initialize the new RAM range and insert it into the lookup table. */
4760 pRamRange->pszDesc = pszDesc;
4761#ifdef VBOX_WITH_NATIVE_NEM
4762 pRamRange->uNemRange = uNemRange;
4763#endif
4764
4765 PPGMPAGE pRamPage = &pRamRange->aPages[idxFirstRamPage];
4766#ifdef VBOX_WITH_PGM_NEM_MODE
4767 if (PGM_IS_IN_NEM_MODE(pVM))
4768 {
4769 AssertPtr(pvRam); Assert(pReq == NULL);
4770 pRamRange->pbR3 = (uint8_t *)pvRam;
4771 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++, pRamPage++, pRomPage++)
4772 {
4773 PGM_PAGE_INIT(pRamPage, UINT64_C(0x0000fffffffff000), NIL_GMM_PAGEID,
4774 PGMPAGETYPE_ROM, PGM_PAGE_STATE_ALLOCATED);
4775 pRomPage->Virgin = *pRamPage;
4776 }
4777 }
4778 else
4779#endif
4780 {
4781 Assert(!pRamRange->pbR3); Assert(!pvRam);
4782 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++, pRamPage++, pRomPage++)
4783 {
4784 PGM_PAGE_INIT(pRamPage,
4785 pReq->aPages[iPage].HCPhysGCPhys,
4786 pReq->aPages[iPage].idPage,
4787 PGMPAGETYPE_ROM,
4788 PGM_PAGE_STATE_ALLOCATED);
4789
4790 pRomPage->Virgin = *pRamPage;
4791 }
4792 }
4793
4794 pVM->pgm.s.cAllPages += cGuestPages;
4795 pVM->pgm.s.cPrivatePages += cGuestPages;
4796
4797 rc = pgmR3PhysRamRangeInsertLookup(pVM, pRamRange, GCPhys, &idxInsert);
4798 }
4799 else
4800 {
4801 /* Insert the ROM into an existing RAM range. */
4802 PPGMPAGE pRamPage = &pOverlappingRange->aPages[idxFirstRamPage];
4803#ifdef VBOX_WITH_PGM_NEM_MODE
4804 if (PGM_IS_IN_NEM_MODE(pVM))
4805 {
4806 Assert(pvRam == NULL); Assert(pReq == NULL);
4807 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++, pRamPage++, pRomPage++)
4808 {
4809 Assert(PGM_PAGE_GET_HCPHYS(pRamPage) == UINT64_C(0x0000fffffffff000));
4810 Assert(PGM_PAGE_GET_PAGEID(pRamPage) == NIL_GMM_PAGEID);
4811 Assert(PGM_PAGE_GET_STATE(pRamPage) == PGM_PAGE_STATE_ALLOCATED);
4812 PGM_PAGE_SET_TYPE(pVM, pRamPage, PGMPAGETYPE_ROM);
4813 PGM_PAGE_SET_STATE(pVM, pRamPage, PGM_PAGE_STATE_ALLOCATED);
4814 PGM_PAGE_SET_PDE_TYPE(pVM, pRamPage, PGM_PAGE_PDE_TYPE_DONTCARE);
4815 PGM_PAGE_SET_PTE_INDEX(pVM, pRamPage, 0);
4816 PGM_PAGE_SET_TRACKING(pVM, pRamPage, 0);
4817
4818 pRomPage->Virgin = *pRamPage;
4819 }
4820 }
4821 else
4822#endif
4823 {
4824 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++, pRamPage++, pRomPage++)
4825 {
4826 PGM_PAGE_SET_TYPE(pVM, pRamPage, PGMPAGETYPE_ROM);
4827 PGM_PAGE_SET_HCPHYS(pVM, pRamPage, pReq->aPages[iPage].HCPhysGCPhys);
4828 PGM_PAGE_SET_STATE(pVM, pRamPage, PGM_PAGE_STATE_ALLOCATED);
4829 PGM_PAGE_SET_PAGEID(pVM, pRamPage, pReq->aPages[iPage].idPage);
4830 PGM_PAGE_SET_PDE_TYPE(pVM, pRamPage, PGM_PAGE_PDE_TYPE_DONTCARE);
4831 PGM_PAGE_SET_PTE_INDEX(pVM, pRamPage, 0);
4832 PGM_PAGE_SET_TRACKING(pVM, pRamPage, 0);
4833
4834 pRomPage->Virgin = *pRamPage;
4835 }
4836 pVM->pgm.s.cZeroPages -= cGuestPages;
4837 pVM->pgm.s.cPrivatePages += cGuestPages;
4838 }
4839 pRamRange = pOverlappingRange;
4840 }
4841
4842 if (RT_SUCCESS(rc))
4843 {
4844#ifdef VBOX_WITH_NATIVE_NEM
4845 /* Set the NEM state of the pages if needed. */
4846 if (u2NemState != UINT8_MAX)
4847 pgmPhysSetNemStateForPages(&pRamRange->aPages[idxFirstRamPage], cGuestPages, u2NemState);
4848#endif
4849
4850 /* Flush physical page map TLB. */
4851 pgmPhysInvalidatePageMapTLB(pVM, false /*fInRendezvous*/);
4852
4853 /*
4854 * Register the ROM access handler.
4855 */
4856 rc = PGMHandlerPhysicalRegister(pVM, GCPhys, GCPhysLast, pVM->pgm.s.hRomPhysHandlerType, idRomRange, pszDesc);
4857 if (RT_SUCCESS(rc))
4858 {
4859 /*
4860 * Copy the image over to the virgin pages.
4861 * This must be done after linking in the RAM range.
4862 */
4863 size_t cbBinaryLeft = cbBinary;
4864 PPGMPAGE pRamPage = &pRamRange->aPages[idxFirstRamPage];
4865 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++, pRamPage++)
4866 {
4867 void *pvDstPage;
4868 rc = pgmPhysPageMap(pVM, pRamPage, GCPhys + (iPage << GUEST_PAGE_SHIFT), &pvDstPage);
4869 if (RT_FAILURE(rc))
4870 {
4871 VMSetError(pVM, rc, RT_SRC_POS, "Failed to map virgin ROM page at %RGp", GCPhys);
4872 break;
4873 }
4874 if (cbBinaryLeft >= GUEST_PAGE_SIZE)
4875 {
4876 memcpy(pvDstPage, (uint8_t const *)pvBinary + ((size_t)iPage << GUEST_PAGE_SHIFT), GUEST_PAGE_SIZE);
4877 cbBinaryLeft -= GUEST_PAGE_SIZE;
4878 }
4879 else
4880 {
4881 RT_BZERO(pvDstPage, GUEST_PAGE_SIZE); /* (shouldn't be necessary, but can't hurt either) */
4882 if (cbBinaryLeft > 0)
4883 {
4884 memcpy(pvDstPage, (uint8_t const *)pvBinary + ((size_t)iPage << GUEST_PAGE_SHIFT), cbBinaryLeft);
4885 cbBinaryLeft = 0;
4886 }
4887 }
4888 }
4889 if (RT_SUCCESS(rc))
4890 {
4891 /*
4892 * Initialize the ROM range.
4893 * Note that the Virgin member of the pages has already been initialized above.
4894 */
4895 Assert(pRomRange->cb == cb);
4896 Assert(pRomRange->fFlags == fFlags);
4897 Assert(pRomRange->idSavedState == UINT8_MAX);
4898 pRomRange->GCPhys = GCPhys;
4899 pRomRange->GCPhysLast = GCPhysLast;
4900 pRomRange->cbOriginal = cbBinary;
4901 pRomRange->pszDesc = pszDesc;
4902#ifdef VBOX_WITH_PGM_NEM_MODE
4903 pRomRange->pbR3Alternate = (uint8_t *)pvAlt;
4904#endif
4905 pRomRange->pvOriginal = fFlags & PGMPHYS_ROM_FLAGS_PERMANENT_BINARY
4906 ? pvBinary : RTMemDup(pvBinary, cbBinary);
4907 if (pRomRange->pvOriginal)
4908 {
4909 for (unsigned iPage = 0; iPage < cGuestPages; iPage++)
4910 {
4911 PPGMROMPAGE const pPage = &pRomRange->aPages[iPage];
4912 pPage->enmProt = PGMROMPROT_READ_ROM_WRITE_IGNORE;
4913#ifdef VBOX_WITH_PGM_NEM_MODE
4914 if (PGM_IS_IN_NEM_MODE(pVM))
4915 PGM_PAGE_INIT(&pPage->Shadow, UINT64_C(0x0000fffffffff000), NIL_GMM_PAGEID,
4916 PGMPAGETYPE_ROM_SHADOW, PGM_PAGE_STATE_ALLOCATED);
4917 else
4918#endif
4919 PGM_PAGE_INIT_ZERO(&pPage->Shadow, pVM, PGMPAGETYPE_ROM_SHADOW);
4920 }
4921
4922 /* update the page count stats for the shadow pages. */
4923 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
4924 {
4925 if (PGM_IS_IN_NEM_MODE(pVM))
4926 pVM->pgm.s.cPrivatePages += cGuestPages;
4927 else
4928 pVM->pgm.s.cZeroPages += cGuestPages;
4929 pVM->pgm.s.cAllPages += cGuestPages;
4930 }
4931
4932#ifdef VBOX_WITH_NATIVE_NEM
4933 /*
4934 * Notify NEM again.
4935 */
4936 if (VM_IS_NEM_ENABLED(pVM))
4937 {
4938 u2NemState = UINT8_MAX;
4939 rc = NEMR3NotifyPhysRomRegisterLate(pVM, GCPhys, cb, PGM_RAMRANGE_CALC_PAGE_R3PTR(pRamRange, GCPhys),
4940 fNemNotify, &u2NemState, &pRamRange->uNemRange);
4941 if (u2NemState != UINT8_MAX)
4942 pgmPhysSetNemStateForPages(&pRamRange->aPages[idxFirstRamPage], cGuestPages, u2NemState);
4943 }
4944 else
4945#endif
4946 GMMR3AllocatePagesCleanup(pReq);
4947 if (RT_SUCCESS(rc))
4948 {
4949 /*
4950 * Done!
4951 */
4952#ifdef VBOX_STRICT
4953 pgmPhysAssertRamRangesLocked(pVM, false /*fInUpdate*/, false /*fRamRelaxed*/);
4954#endif
4955 return rc;
4956 }
4957
4958 /*
4959 * bail out
4960 */
4961#ifdef VBOX_WITH_NATIVE_NEM
4962 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
4963 {
4964 Assert(VM_IS_NEM_ENABLED(pVM));
4965 pVM->pgm.s.cPrivatePages -= cGuestPages;
4966 pVM->pgm.s.cAllPages -= cGuestPages;
4967 }
4968#endif
4969 }
4970 else
4971 rc = VERR_NO_MEMORY;
4972 }
4973
4974 int rc2 = PGMHandlerPhysicalDeregister(pVM, GCPhys);
4975 AssertRC(rc2);
4976 }
4977
4978 idxInsert -= 1;
4979 if (!pOverlappingRange)
4980 pgmR3PhysRamRangeRemoveLookup(pVM, pRamRange, &idxInsert);
4981 }
4982 /* else: lookup insertion failed. */
4983
4984 if (pOverlappingRange)
4985 {
4986 PPGMPAGE pRamPage = &pOverlappingRange->aPages[idxFirstRamPage];
4987#ifdef VBOX_WITH_PGM_NEM_MODE
4988 if (PGM_IS_IN_NEM_MODE(pVM))
4989 {
4990 Assert(pvRam == NULL); Assert(pReq == NULL);
4991 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++, pRamPage++, pRomPage++)
4992 {
4993 Assert(PGM_PAGE_GET_HCPHYS(pRamPage) == UINT64_C(0x0000fffffffff000));
4994 Assert(PGM_PAGE_GET_PAGEID(pRamPage) == NIL_GMM_PAGEID);
4995 Assert(PGM_PAGE_GET_STATE(pRamPage) == PGM_PAGE_STATE_ALLOCATED);
4996 PGM_PAGE_SET_TYPE(pVM, pRamPage, PGMPAGETYPE_RAM);
4997 PGM_PAGE_SET_STATE(pVM, pRamPage, PGM_PAGE_STATE_ALLOCATED);
4998 }
4999 }
5000 else
5001#endif
5002 {
5003 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++, pRamPage++)
5004 PGM_PAGE_INIT_ZERO(pRamPage, pVM, PGMPAGETYPE_RAM);
5005 pVM->pgm.s.cZeroPages += cGuestPages;
5006 pVM->pgm.s.cPrivatePages -= cGuestPages;
5007 }
5008 }
5009 }
5010 pgmPhysInvalidatePageMapTLB(pVM, false /*fInRendezvous*/);
5011 pgmPhysInvalidRamRangeTlbs(pVM);
5012
5013#ifdef VBOX_WITH_PGM_NEM_MODE
5014 if (PGM_IS_IN_NEM_MODE(pVM))
5015 {
5016 Assert(!pReq);
5017 if (pvRam)
5018 SUPR3PageFree(pvRam, cHostPages);
5019 if (pvAlt)
5020 SUPR3PageFree(pvAlt, cHostPages);
5021 }
5022 else
5023#endif
5024 {
5025 GMMR3FreeAllocatedPages(pVM, pReq);
5026 GMMR3AllocatePagesCleanup(pReq);
5027 }
5028
5029 /* We don't bother to actually free either the ROM nor the RAM ranges
5030 themselves, as already mentioned above, we'll leave that to the VM
5031 termination cleanup code. */
5032 return rc;
5033}
5034
5035
5036/**
5037 * Registers a ROM image.
5038 *
5039 * Shadowed ROM images requires double the amount of backing memory, so,
5040 * don't use that unless you have to. Shadowing of ROM images is process
5041 * where we can select where the reads go and where the writes go. On real
5042 * hardware the chipset provides means to configure this. We provide
5043 * PGMR3PhysRomProtect() for this purpose.
5044 *
5045 * A read-only copy of the ROM image will always be kept around while we
5046 * will allocate RAM pages for the changes on demand (unless all memory
5047 * is configured to be preallocated).
5048 *
5049 * @returns VBox status code.
5050 * @param pVM The cross context VM structure.
5051 * @param pDevIns The device instance owning the ROM.
5052 * @param GCPhys First physical address in the range.
5053 * Must be page aligned!
5054 * @param cb The size of the range (in bytes).
5055 * Must be page aligned!
5056 * @param pvBinary Pointer to the binary data backing the ROM image.
5057 * @param cbBinary The size of the binary data pvBinary points to.
5058 * This must be less or equal to @a cb.
5059 * @param fFlags Mask of flags, PGMPHYS_ROM_FLAGS_XXX.
5060 * @param pszDesc Pointer to description string. This must not be freed.
5061 *
5062 * @remark There is no way to remove the rom, automatically on device cleanup or
5063 * manually from the device yet. This isn't difficult in any way, it's
5064 * just not something we expect to be necessary for a while.
5065 */
5066VMMR3DECL(int) PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb,
5067 const void *pvBinary, uint32_t cbBinary, uint8_t fFlags, const char *pszDesc)
5068{
5069 Log(("PGMR3PhysRomRegister: pDevIns=%p GCPhys=%RGp(-%RGp) cb=%RGp pvBinary=%p cbBinary=%#x fFlags=%#x pszDesc=%s\n",
5070 pDevIns, GCPhys, GCPhys + cb, cb, pvBinary, cbBinary, fFlags, pszDesc));
5071 PGM_LOCK_VOID(pVM);
5072
5073 int rc = pgmR3PhysRomRegisterLocked(pVM, pDevIns, GCPhys, cb, pvBinary, cbBinary, fFlags, pszDesc);
5074
5075 PGM_UNLOCK(pVM);
5076 return rc;
5077}
5078
5079
5080/**
5081 * Called by PGMR3MemSetup to reset the shadow, switch to the virgin, and verify
5082 * that the virgin part is untouched.
5083 *
5084 * This is done after the normal memory has been cleared.
5085 *
5086 * ASSUMES that the caller owns the PGM lock.
5087 *
5088 * @param pVM The cross context VM structure.
5089 */
5090int pgmR3PhysRomReset(PVM pVM)
5091{
5092 PGM_LOCK_ASSERT_OWNER(pVM);
5093 uint32_t const cRomRanges = RT_MIN(pVM->pgm.s.cRomRanges, RT_ELEMENTS(pVM->pgm.s.apRomRanges));
5094 for (uint32_t idx = 0; idx < cRomRanges; idx++)
5095 {
5096 PPGMROMRANGE const pRom = pVM->pgm.s.apRomRanges[idx];
5097 uint32_t const cGuestPages = pRom->cb >> GUEST_PAGE_SHIFT;
5098
5099 if (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
5100 {
5101 /*
5102 * Reset the physical handler.
5103 */
5104 int rc = PGMR3PhysRomProtect(pVM, pRom->GCPhys, pRom->cb, PGMROMPROT_READ_ROM_WRITE_IGNORE);
5105 AssertRCReturn(rc, rc);
5106
5107 /*
5108 * What we do with the shadow pages depends on the memory
5109 * preallocation option. If not enabled, we'll just throw
5110 * out all the dirty pages and replace them by the zero page.
5111 */
5112#ifdef VBOX_WITH_PGM_NEM_MODE
5113 if (PGM_IS_IN_NEM_MODE(pVM))
5114 {
5115 /* Clear all the shadow pages (currently using alternate backing). */
5116 RT_BZERO(pRom->pbR3Alternate, pRom->cb);
5117 }
5118 else
5119#endif
5120 if (!pVM->pgm.s.fRamPreAlloc)
5121 {
5122 /* Free the dirty pages. */
5123 uint32_t cPendingPages = 0;
5124 PGMMFREEPAGESREQ pReq;
5125 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
5126 AssertRCReturn(rc, rc);
5127
5128 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++)
5129 if ( !PGM_PAGE_IS_ZERO(&pRom->aPages[iPage].Shadow)
5130 && !PGM_PAGE_IS_BALLOONED(&pRom->aPages[iPage].Shadow))
5131 {
5132 Assert(PGM_PAGE_GET_STATE(&pRom->aPages[iPage].Shadow) == PGM_PAGE_STATE_ALLOCATED);
5133 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, &pRom->aPages[iPage].Shadow,
5134 pRom->GCPhys + (iPage << GUEST_PAGE_SHIFT),
5135 (PGMPAGETYPE)PGM_PAGE_GET_TYPE(&pRom->aPages[iPage].Shadow));
5136 AssertLogRelRCReturn(rc, rc);
5137 }
5138
5139 if (cPendingPages)
5140 {
5141 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
5142 AssertLogRelRCReturn(rc, rc);
5143 }
5144 GMMR3FreePagesCleanup(pReq);
5145 }
5146 else
5147 {
5148 /* clear all the shadow pages. */
5149 for (uint32_t iPage = 0; iPage < cGuestPages; iPage++)
5150 {
5151 if (PGM_PAGE_IS_ZERO(&pRom->aPages[iPage].Shadow))
5152 continue;
5153 Assert(!PGM_PAGE_IS_BALLOONED(&pRom->aPages[iPage].Shadow));
5154 void *pvDstPage;
5155 RTGCPHYS const GCPhys = pRom->GCPhys + (iPage << GUEST_PAGE_SHIFT);
5156 rc = pgmPhysPageMakeWritableAndMap(pVM, &pRom->aPages[iPage].Shadow, GCPhys, &pvDstPage);
5157 if (RT_FAILURE(rc))
5158 break;
5159 RT_BZERO(pvDstPage, GUEST_PAGE_SIZE);
5160 }
5161 AssertRCReturn(rc, rc);
5162 }
5163 }
5164
5165 /*
5166 * Restore the original ROM pages after a saved state load.
5167 * Also, in strict builds check that ROM pages remain unmodified.
5168 */
5169#ifndef VBOX_STRICT
5170 if (pVM->pgm.s.fRestoreRomPagesOnReset)
5171#endif
5172 {
5173 size_t cbSrcLeft = pRom->cbOriginal;
5174 uint8_t const *pbSrcPage = (uint8_t const *)pRom->pvOriginal;
5175 uint32_t cRestored = 0;
5176 for (uint32_t iPage = 0; iPage < cGuestPages && cbSrcLeft > 0; iPage++, pbSrcPage += GUEST_PAGE_SIZE)
5177 {
5178 RTGCPHYS const GCPhys = pRom->GCPhys + (iPage << GUEST_PAGE_SHIFT);
5179 PPGMPAGE const pPage = pgmPhysGetPage(pVM, GCPhys);
5180 void const *pvDstPage = NULL;
5181 int rc = pgmPhysPageMapReadOnly(pVM, pPage, GCPhys, &pvDstPage);
5182 if (RT_FAILURE(rc))
5183 break;
5184
5185 if (memcmp(pvDstPage, pbSrcPage, RT_MIN(cbSrcLeft, GUEST_PAGE_SIZE)))
5186 {
5187 if (pVM->pgm.s.fRestoreRomPagesOnReset)
5188 {
5189 void *pvDstPageW = NULL;
5190 rc = pgmPhysPageMap(pVM, pPage, GCPhys, &pvDstPageW);
5191 AssertLogRelRCReturn(rc, rc);
5192 memcpy(pvDstPageW, pbSrcPage, RT_MIN(cbSrcLeft, GUEST_PAGE_SIZE));
5193 cRestored++;
5194 }
5195 else
5196 LogRel(("pgmR3PhysRomReset: %RGp: ROM page changed (%s)\n", GCPhys, pRom->pszDesc));
5197 }
5198 cbSrcLeft -= RT_MIN(cbSrcLeft, GUEST_PAGE_SIZE);
5199 }
5200 if (cRestored > 0)
5201 LogRel(("PGM: ROM \"%s\": Reloaded %u of %u pages.\n", pRom->pszDesc, cRestored, cGuestPages));
5202 }
5203 }
5204
5205 /* Clear the ROM restore flag now as we only need to do this once after
5206 loading saved state. */
5207 pVM->pgm.s.fRestoreRomPagesOnReset = false;
5208
5209 return VINF_SUCCESS;
5210}
5211
5212
5213/**
5214 * Called by PGMR3Term to free resources.
5215 *
5216 * ASSUMES that the caller owns the PGM lock.
5217 *
5218 * @param pVM The cross context VM structure.
5219 */
5220void pgmR3PhysRomTerm(PVM pVM)
5221{
5222 /*
5223 * Free the heap copy of the original bits.
5224 */
5225 uint32_t const cRomRanges = RT_MIN(pVM->pgm.s.cRomRanges, RT_ELEMENTS(pVM->pgm.s.apRomRanges));
5226 for (uint32_t idx = 0; idx < cRomRanges; idx++)
5227 {
5228 PPGMROMRANGE const pRom = pVM->pgm.s.apRomRanges[idx];
5229 if ( pRom->pvOriginal
5230 && !(pRom->fFlags & PGMPHYS_ROM_FLAGS_PERMANENT_BINARY))
5231 {
5232 RTMemFree((void *)pRom->pvOriginal);
5233 pRom->pvOriginal = NULL;
5234 }
5235 }
5236}
5237
5238
5239/**
5240 * Change the shadowing of a range of ROM pages.
5241 *
5242 * This is intended for implementing chipset specific memory registers
5243 * and will not be very strict about the input. It will silently ignore
5244 * any pages that are not the part of a shadowed ROM.
5245 *
5246 * @returns VBox status code.
5247 * @retval VINF_PGM_SYNC_CR3
5248 *
5249 * @param pVM The cross context VM structure.
5250 * @param GCPhys Where to start. Page aligned.
5251 * @param cb How much to change. Page aligned.
5252 * @param enmProt The new ROM protection.
5253 */
5254VMMR3DECL(int) PGMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMROMPROT enmProt)
5255{
5256 LogFlow(("PGMR3PhysRomProtect: GCPhys=%RGp cb=%RGp enmProt=%d\n", GCPhys, cb, enmProt));
5257
5258 /*
5259 * Check input
5260 */
5261 if (!cb)
5262 return VINF_SUCCESS;
5263 AssertReturn(!(GCPhys & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
5264 AssertReturn(!(cb & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
5265 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
5266 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
5267 AssertReturn(enmProt >= PGMROMPROT_INVALID && enmProt <= PGMROMPROT_END, VERR_INVALID_PARAMETER);
5268
5269 /*
5270 * Process the request.
5271 */
5272 PGM_LOCK_VOID(pVM);
5273 int rc = VINF_SUCCESS;
5274 bool fFlushTLB = false;
5275 uint32_t const cRomRanges = RT_MIN(pVM->pgm.s.cRomRanges, RT_ELEMENTS(pVM->pgm.s.apRomRanges));
5276 for (uint32_t idx = 0; idx < cRomRanges; idx++)
5277 {
5278 PPGMROMRANGE const pRom = pVM->pgm.s.apRomRanges[idx];
5279 if ( GCPhys <= pRom->GCPhysLast
5280 && GCPhysLast >= pRom->GCPhys
5281 && (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED))
5282 {
5283 /*
5284 * Iterate the relevant pages and make necessary the changes.
5285 */
5286#ifdef VBOX_WITH_NATIVE_NEM
5287 PPGMRAMRANGE const pRam = pgmPhysGetRange(pVM, GCPhys);
5288 AssertPtrReturn(pRam, VERR_INTERNAL_ERROR_3);
5289#endif
5290 bool fChanges = false;
5291 uint32_t const cPages = pRom->GCPhysLast <= GCPhysLast
5292 ? pRom->cb >> GUEST_PAGE_SHIFT
5293 : (GCPhysLast - pRom->GCPhys + 1) >> GUEST_PAGE_SHIFT;
5294 for (uint32_t iPage = (GCPhys - pRom->GCPhys) >> GUEST_PAGE_SHIFT;
5295 iPage < cPages;
5296 iPage++)
5297 {
5298 PPGMROMPAGE pRomPage = &pRom->aPages[iPage];
5299 if (PGMROMPROT_IS_ROM(pRomPage->enmProt) != PGMROMPROT_IS_ROM(enmProt))
5300 {
5301 fChanges = true;
5302
5303 /* flush references to the page. */
5304 RTGCPHYS const GCPhysPage = pRom->GCPhys + (iPage << GUEST_PAGE_SHIFT);
5305 PPGMPAGE pRamPage = pgmPhysGetPage(pVM, GCPhysPage);
5306 int rc2 = pgmPoolTrackUpdateGCPhys(pVM, GCPhysPage, pRamPage, true /*fFlushPTEs*/, &fFlushTLB);
5307 if (rc2 != VINF_SUCCESS && (rc == VINF_SUCCESS || RT_FAILURE(rc2)))
5308 rc = rc2;
5309#ifdef VBOX_WITH_NATIVE_NEM
5310 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pRamPage);
5311#endif
5312
5313 PPGMPAGE pOld = PGMROMPROT_IS_ROM(pRomPage->enmProt) ? &pRomPage->Virgin : &pRomPage->Shadow;
5314 PPGMPAGE pNew = PGMROMPROT_IS_ROM(pRomPage->enmProt) ? &pRomPage->Shadow : &pRomPage->Virgin;
5315
5316 *pOld = *pRamPage;
5317 *pRamPage = *pNew;
5318 /** @todo preserve the volatile flags (handlers) when these have been moved out of HCPhys! */
5319
5320#ifdef VBOX_WITH_NATIVE_NEM
5321# ifdef VBOX_WITH_PGM_NEM_MODE
5322 /* In simplified mode we have to switch the page data around too. */
5323 if (PGM_IS_IN_NEM_MODE(pVM))
5324 {
5325 uint8_t abPage[GUEST_PAGE_SIZE];
5326 uint8_t * const pbRamPage = PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysPage);
5327 memcpy(abPage, &pRom->pbR3Alternate[(size_t)iPage << GUEST_PAGE_SHIFT], sizeof(abPage));
5328 memcpy(&pRom->pbR3Alternate[(size_t)iPage << GUEST_PAGE_SHIFT], pbRamPage, sizeof(abPage));
5329 memcpy(pbRamPage, abPage, sizeof(abPage));
5330 }
5331# endif
5332 /* Tell NEM about the backing and protection change. */
5333 if (VM_IS_NEM_ENABLED(pVM))
5334 {
5335 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pNew);
5336 NEMHCNotifyPhysPageChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pOld), PGM_PAGE_GET_HCPHYS(pNew),
5337 PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhysPage),
5338 pgmPhysPageCalcNemProtection(pRamPage, enmType), enmType, &u2State);
5339 PGM_PAGE_SET_NEM_STATE(pRamPage, u2State);
5340 }
5341#endif
5342 }
5343 pRomPage->enmProt = enmProt;
5344 }
5345
5346 /*
5347 * Reset the access handler if we made changes, no need to optimize this.
5348 */
5349 if (fChanges)
5350 {
5351 int rc2 = PGMHandlerPhysicalReset(pVM, pRom->GCPhys);
5352 if (RT_FAILURE(rc2))
5353 {
5354 PGM_UNLOCK(pVM);
5355 AssertRC(rc);
5356 return rc2;
5357 }
5358
5359 /* Explicitly flush IEM. Not sure if this is really necessary, but better
5360 be on the safe side. This shouldn't be a high volume flush source. */
5361 IEMTlbInvalidateAllPhysicalAllCpus(pVM, NIL_VMCPUID, IEMTLBPHYSFLUSHREASON_ROM_PROTECT);
5362 }
5363
5364 /* Advance - cb isn't updated. */
5365 GCPhys = pRom->GCPhys + (cPages << GUEST_PAGE_SHIFT);
5366 }
5367 }
5368 PGM_UNLOCK(pVM);
5369 if (fFlushTLB)
5370 PGM_INVL_ALL_VCPU_TLBS(pVM);
5371
5372 return rc;
5373}
5374
5375
5376
5377/*********************************************************************************************************************************
5378* Ballooning *
5379*********************************************************************************************************************************/
5380
5381#if HC_ARCH_BITS == 64 && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD))
5382
5383/**
5384 * Rendezvous callback used by PGMR3ChangeMemBalloon that changes the memory balloon size
5385 *
5386 * This is only called on one of the EMTs while the other ones are waiting for
5387 * it to complete this function.
5388 *
5389 * @returns VINF_SUCCESS (VBox strict status code).
5390 * @param pVM The cross context VM structure.
5391 * @param pVCpu The cross context virtual CPU structure of the calling EMT. Unused.
5392 * @param pvUser User parameter
5393 */
5394static DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysChangeMemBalloonRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
5395{
5396 uintptr_t *paUser = (uintptr_t *)pvUser;
5397 bool fInflate = !!paUser[0];
5398 unsigned cPages = paUser[1];
5399 RTGCPHYS *paPhysPage = (RTGCPHYS *)paUser[2];
5400 uint32_t cPendingPages = 0;
5401 PGMMFREEPAGESREQ pReq;
5402 int rc;
5403
5404 Log(("pgmR3PhysChangeMemBalloonRendezvous: %s %x pages\n", (fInflate) ? "inflate" : "deflate", cPages));
5405 PGM_LOCK_VOID(pVM);
5406
5407 if (fInflate)
5408 {
5409 /* Flush the PGM pool cache as we might have stale references to pages that we just freed. */
5410 pgmR3PoolClearAllRendezvous(pVM, pVCpu, NULL);
5411
5412 /* Replace pages with ZERO pages. */
5413 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
5414 if (RT_FAILURE(rc))
5415 {
5416 PGM_UNLOCK(pVM);
5417 AssertLogRelRC(rc);
5418 return rc;
5419 }
5420
5421 /* Iterate the pages. */
5422 for (unsigned i = 0; i < cPages; i++)
5423 {
5424 PPGMPAGE pPage = pgmPhysGetPage(pVM, paPhysPage[i]);
5425 if ( pPage == NULL
5426 || PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_RAM)
5427 {
5428 Log(("pgmR3PhysChangeMemBalloonRendezvous: invalid physical page %RGp pPage->u3Type=%d\n", paPhysPage[i], pPage ? PGM_PAGE_GET_TYPE(pPage) : 0));
5429 break;
5430 }
5431
5432 LogFlow(("balloon page: %RGp\n", paPhysPage[i]));
5433
5434 /* Flush the shadow PT if this page was previously used as a guest page table. */
5435 pgmPoolFlushPageByGCPhys(pVM, paPhysPage[i]);
5436
5437 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, paPhysPage[i], (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage));
5438 if (RT_FAILURE(rc))
5439 {
5440 PGM_UNLOCK(pVM);
5441 AssertLogRelRC(rc);
5442 return rc;
5443 }
5444 Assert(PGM_PAGE_IS_ZERO(pPage));
5445 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_BALLOONED);
5446 }
5447
5448 if (cPendingPages)
5449 {
5450 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
5451 if (RT_FAILURE(rc))
5452 {
5453 PGM_UNLOCK(pVM);
5454 AssertLogRelRC(rc);
5455 return rc;
5456 }
5457 }
5458 GMMR3FreePagesCleanup(pReq);
5459 }
5460 else
5461 {
5462 /* Iterate the pages. */
5463 for (unsigned i = 0; i < cPages; i++)
5464 {
5465 PPGMPAGE pPage = pgmPhysGetPage(pVM, paPhysPage[i]);
5466 AssertBreak(pPage && PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM);
5467
5468 LogFlow(("Free ballooned page: %RGp\n", paPhysPage[i]));
5469
5470 Assert(PGM_PAGE_IS_BALLOONED(pPage));
5471
5472 /* Change back to zero page. (NEM does not need to be informed.) */
5473 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ZERO);
5474 }
5475
5476 /* Note that we currently do not map any ballooned pages in our shadow page tables, so no need to flush the pgm pool. */
5477 }
5478
5479 /* Notify GMM about the balloon change. */
5480 rc = GMMR3BalloonedPages(pVM, (fInflate) ? GMMBALLOONACTION_INFLATE : GMMBALLOONACTION_DEFLATE, cPages);
5481 if (RT_SUCCESS(rc))
5482 {
5483 if (!fInflate)
5484 {
5485 Assert(pVM->pgm.s.cBalloonedPages >= cPages);
5486 pVM->pgm.s.cBalloonedPages -= cPages;
5487 }
5488 else
5489 pVM->pgm.s.cBalloonedPages += cPages;
5490 }
5491
5492 PGM_UNLOCK(pVM);
5493
5494 /* Flush the recompiler's TLB as well. */
5495 for (VMCPUID i = 0; i < pVM->cCpus; i++)
5496 CPUMSetChangedFlags(pVM->apCpusR3[i], CPUM_CHANGED_GLOBAL_TLB_FLUSH);
5497
5498 AssertLogRelRC(rc);
5499 return rc;
5500}
5501
5502
5503/**
5504 * Frees a range of ram pages, replacing them with ZERO pages; helper for PGMR3PhysFreeRamPages
5505 *
5506 * @param pVM The cross context VM structure.
5507 * @param fInflate Inflate or deflate memory balloon
5508 * @param cPages Number of pages to free
5509 * @param paPhysPage Array of guest physical addresses
5510 */
5511static DECLCALLBACK(void) pgmR3PhysChangeMemBalloonHelper(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)
5512{
5513 uintptr_t paUser[3];
5514
5515 paUser[0] = fInflate;
5516 paUser[1] = cPages;
5517 paUser[2] = (uintptr_t)paPhysPage;
5518 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysChangeMemBalloonRendezvous, (void *)paUser);
5519 AssertRC(rc);
5520
5521 /* Made a copy in PGMR3PhysFreeRamPages; free it here. */
5522 RTMemFree(paPhysPage);
5523}
5524
5525#endif /* 64-bit host && (Windows || Solaris || Linux || FreeBSD) */
5526
5527/**
5528 * Inflate or deflate a memory balloon
5529 *
5530 * @returns VBox status code.
5531 * @param pVM The cross context VM structure.
5532 * @param fInflate Inflate or deflate memory balloon
5533 * @param cPages Number of pages to free
5534 * @param paPhysPage Array of guest physical addresses
5535 */
5536VMMR3DECL(int) PGMR3PhysChangeMemBalloon(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)
5537{
5538 /* This must match GMMR0Init; currently we only support memory ballooning on all 64-bit hosts except Mac OS X */
5539#if HC_ARCH_BITS == 64 && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD))
5540 int rc;
5541
5542 /* Older additions (ancient non-functioning balloon code) pass wrong physical addresses. */
5543 AssertReturn(!(paPhysPage[0] & 0xfff), VERR_INVALID_PARAMETER);
5544
5545 /* We own the IOM lock here and could cause a deadlock by waiting for another VCPU that is blocking on the IOM lock.
5546 * In the SMP case we post a request packet to postpone the job.
5547 */
5548 if (pVM->cCpus > 1)
5549 {
5550 unsigned cbPhysPage = cPages * sizeof(paPhysPage[0]);
5551 RTGCPHYS *paPhysPageCopy = (RTGCPHYS *)RTMemAlloc(cbPhysPage);
5552 AssertReturn(paPhysPageCopy, VERR_NO_MEMORY);
5553
5554 memcpy(paPhysPageCopy, paPhysPage, cbPhysPage);
5555
5556 rc = VMR3ReqCallNoWait(pVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3PhysChangeMemBalloonHelper, 4,
5557 pVM, fInflate, cPages, paPhysPageCopy);
5558 AssertRC(rc);
5559 }
5560 else
5561 {
5562 uintptr_t paUser[3];
5563
5564 paUser[0] = fInflate;
5565 paUser[1] = cPages;
5566 paUser[2] = (uintptr_t)paPhysPage;
5567 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysChangeMemBalloonRendezvous, (void *)paUser);
5568 AssertRC(rc);
5569 }
5570 return rc;
5571
5572#else
5573 NOREF(pVM); NOREF(fInflate); NOREF(cPages); NOREF(paPhysPage);
5574 return VERR_NOT_IMPLEMENTED;
5575#endif
5576}
5577
5578
5579
5580/*********************************************************************************************************************************
5581* Write Monitoring *
5582*********************************************************************************************************************************/
5583
5584/**
5585 * Rendezvous callback used by PGMR3WriteProtectRAM that write protects all
5586 * physical RAM.
5587 *
5588 * This is only called on one of the EMTs while the other ones are waiting for
5589 * it to complete this function.
5590 *
5591 * @returns VINF_SUCCESS (VBox strict status code).
5592 * @param pVM The cross context VM structure.
5593 * @param pVCpu The cross context virtual CPU structure of the calling EMT. Unused.
5594 * @param pvUser User parameter, unused.
5595 */
5596static DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysWriteProtectRAMRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
5597{
5598 int rc = VINF_SUCCESS;
5599 NOREF(pvUser); NOREF(pVCpu);
5600
5601 PGM_LOCK_VOID(pVM);
5602#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
5603 pgmPoolResetDirtyPages(pVM);
5604#endif
5605
5606 uint32_t const cLookupEntries = RT_MIN(pVM->pgm.s.RamRangeUnion.cLookupEntries, RT_ELEMENTS(pVM->pgm.s.aRamRangeLookup));
5607 for (uint32_t idxLookup = 0; idxLookup < cLookupEntries; idxLookup++)
5608 {
5609 uint32_t const idRamRange = PGMRAMRANGELOOKUPENTRY_GET_ID(pVM->pgm.s.aRamRangeLookup[idxLookup]);
5610 AssertContinue(idRamRange < RT_ELEMENTS(pVM->pgm.s.apRamRanges));
5611 PPGMRAMRANGE const pRam = pVM->pgm.s.apRamRanges[idRamRange];
5612 AssertContinue(pRam);
5613
5614 uint32_t cPages = pRam->cb >> GUEST_PAGE_SHIFT;
5615 for (uint32_t iPage = 0; iPage < cPages; iPage++)
5616 {
5617 PPGMPAGE const pPage = &pRam->aPages[iPage];
5618 PGMPAGETYPE const enmPageType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
5619
5620 if ( RT_LIKELY(enmPageType == PGMPAGETYPE_RAM)
5621 || enmPageType == PGMPAGETYPE_MMIO2)
5622 {
5623 /*
5624 * A RAM page.
5625 */
5626 switch (PGM_PAGE_GET_STATE(pPage))
5627 {
5628 case PGM_PAGE_STATE_ALLOCATED:
5629 /** @todo Optimize this: Don't always re-enable write
5630 * monitoring if the page is known to be very busy. */
5631 if (PGM_PAGE_IS_WRITTEN_TO(pPage))
5632 PGM_PAGE_CLEAR_WRITTEN_TO(pVM, pPage);
5633
5634 pgmPhysPageWriteMonitor(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT));
5635 break;
5636
5637 case PGM_PAGE_STATE_SHARED:
5638 AssertFailed();
5639 break;
5640
5641 case PGM_PAGE_STATE_WRITE_MONITORED: /* nothing to change. */
5642 default:
5643 break;
5644 }
5645 }
5646 }
5647 }
5648 pgmR3PoolWriteProtectPages(pVM);
5649 PGM_INVL_ALL_VCPU_TLBS(pVM);
5650 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
5651 CPUMSetChangedFlags(pVM->apCpusR3[idCpu], CPUM_CHANGED_GLOBAL_TLB_FLUSH);
5652
5653 PGM_UNLOCK(pVM);
5654 return rc;
5655}
5656
5657/**
5658 * Protect all physical RAM to monitor writes
5659 *
5660 * @returns VBox status code.
5661 * @param pVM The cross context VM structure.
5662 */
5663VMMR3DECL(int) PGMR3PhysWriteProtectRAM(PVM pVM)
5664{
5665 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
5666
5667 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysWriteProtectRAMRendezvous, NULL);
5668 AssertRC(rc);
5669 return rc;
5670}
5671
5672
5673/*********************************************************************************************************************************
5674* Stats. *
5675*********************************************************************************************************************************/
5676
5677/**
5678 * Query the amount of free memory inside VMMR0
5679 *
5680 * @returns VBox status code.
5681 * @param pUVM The user mode VM handle.
5682 * @param pcbAllocMem Where to return the amount of memory allocated
5683 * by VMs.
5684 * @param pcbFreeMem Where to return the amount of memory that is
5685 * allocated from the host but not currently used
5686 * by any VMs.
5687 * @param pcbBallonedMem Where to return the sum of memory that is
5688 * currently ballooned by the VMs.
5689 * @param pcbSharedMem Where to return the amount of memory that is
5690 * currently shared.
5691 */
5692VMMR3DECL(int) PGMR3QueryGlobalMemoryStats(PUVM pUVM, uint64_t *pcbAllocMem, uint64_t *pcbFreeMem,
5693 uint64_t *pcbBallonedMem, uint64_t *pcbSharedMem)
5694{
5695 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
5696 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
5697
5698 uint64_t cAllocPages = 0;
5699 uint64_t cFreePages = 0;
5700 uint64_t cBalloonPages = 0;
5701 uint64_t cSharedPages = 0;
5702 if (!SUPR3IsDriverless())
5703 {
5704 int rc = GMMR3QueryHypervisorMemoryStats(pUVM->pVM, &cAllocPages, &cFreePages, &cBalloonPages, &cSharedPages);
5705 AssertRCReturn(rc, rc);
5706 }
5707
5708 if (pcbAllocMem)
5709 *pcbAllocMem = cAllocPages * _4K;
5710
5711 if (pcbFreeMem)
5712 *pcbFreeMem = cFreePages * _4K;
5713
5714 if (pcbBallonedMem)
5715 *pcbBallonedMem = cBalloonPages * _4K;
5716
5717 if (pcbSharedMem)
5718 *pcbSharedMem = cSharedPages * _4K;
5719
5720 Log(("PGMR3QueryVMMMemoryStats: all=%llx free=%llx ballooned=%llx shared=%llx\n",
5721 cAllocPages, cFreePages, cBalloonPages, cSharedPages));
5722 return VINF_SUCCESS;
5723}
5724
5725
5726/**
5727 * Query memory stats for the VM.
5728 *
5729 * @returns VBox status code.
5730 * @param pUVM The user mode VM handle.
5731 * @param pcbTotalMem Where to return total amount memory the VM may
5732 * possibly use.
5733 * @param pcbPrivateMem Where to return the amount of private memory
5734 * currently allocated.
5735 * @param pcbSharedMem Where to return the amount of actually shared
5736 * memory currently used by the VM.
5737 * @param pcbZeroMem Where to return the amount of memory backed by
5738 * zero pages.
5739 *
5740 * @remarks The total mem is normally larger than the sum of the three
5741 * components. There are two reasons for this, first the amount of
5742 * shared memory is what we're sure is shared instead of what could
5743 * possibly be shared with someone. Secondly, because the total may
5744 * include some pure MMIO pages that doesn't go into any of the three
5745 * sub-counts.
5746 *
5747 * @todo Why do we return reused shared pages instead of anything that could
5748 * potentially be shared? Doesn't this mean the first VM gets a much
5749 * lower number of shared pages?
5750 */
5751VMMR3DECL(int) PGMR3QueryMemoryStats(PUVM pUVM, uint64_t *pcbTotalMem, uint64_t *pcbPrivateMem,
5752 uint64_t *pcbSharedMem, uint64_t *pcbZeroMem)
5753{
5754 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
5755 PVM pVM = pUVM->pVM;
5756 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
5757
5758 if (pcbTotalMem)
5759 *pcbTotalMem = (uint64_t)pVM->pgm.s.cAllPages * GUEST_PAGE_SIZE;
5760
5761 if (pcbPrivateMem)
5762 *pcbPrivateMem = (uint64_t)pVM->pgm.s.cPrivatePages * GUEST_PAGE_SIZE;
5763
5764 if (pcbSharedMem)
5765 *pcbSharedMem = (uint64_t)pVM->pgm.s.cReusedSharedPages * GUEST_PAGE_SIZE;
5766
5767 if (pcbZeroMem)
5768 *pcbZeroMem = (uint64_t)pVM->pgm.s.cZeroPages * GUEST_PAGE_SIZE;
5769
5770 Log(("PGMR3QueryMemoryStats: all=%x private=%x reused=%x zero=%x\n", pVM->pgm.s.cAllPages, pVM->pgm.s.cPrivatePages, pVM->pgm.s.cReusedSharedPages, pVM->pgm.s.cZeroPages));
5771 return VINF_SUCCESS;
5772}
5773
5774
5775
5776/*********************************************************************************************************************************
5777* Chunk Mappings and Page Allocation *
5778*********************************************************************************************************************************/
5779
5780/**
5781 * Tree enumeration callback for dealing with age rollover.
5782 * It will perform a simple compression of the current age.
5783 */
5784static DECLCALLBACK(int) pgmR3PhysChunkAgeingRolloverCallback(PAVLU32NODECORE pNode, void *pvUser)
5785{
5786 /* Age compression - ASSUMES iNow == 4. */
5787 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)pNode;
5788 if (pChunk->iLastUsed >= UINT32_C(0xffffff00))
5789 pChunk->iLastUsed = 3;
5790 else if (pChunk->iLastUsed >= UINT32_C(0xfffff000))
5791 pChunk->iLastUsed = 2;
5792 else if (pChunk->iLastUsed)
5793 pChunk->iLastUsed = 1;
5794 else /* iLastUsed = 0 */
5795 pChunk->iLastUsed = 4;
5796
5797 NOREF(pvUser);
5798 return 0;
5799}
5800
5801
5802/**
5803 * The structure passed in the pvUser argument of pgmR3PhysChunkUnmapCandidateCallback().
5804 */
5805typedef struct PGMR3PHYSCHUNKUNMAPCB
5806{
5807 PVM pVM; /**< Pointer to the VM. */
5808 PPGMCHUNKR3MAP pChunk; /**< The chunk to unmap. */
5809} PGMR3PHYSCHUNKUNMAPCB, *PPGMR3PHYSCHUNKUNMAPCB;
5810
5811
5812/**
5813 * Callback used to find the mapping that's been unused for
5814 * the longest time.
5815 */
5816static DECLCALLBACK(int) pgmR3PhysChunkUnmapCandidateCallback(PAVLU32NODECORE pNode, void *pvUser)
5817{
5818 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)pNode;
5819 PPGMR3PHYSCHUNKUNMAPCB pArg = (PPGMR3PHYSCHUNKUNMAPCB)pvUser;
5820
5821 /*
5822 * Check for locks and compare when last used.
5823 */
5824 if (pChunk->cRefs)
5825 return 0;
5826 if (pChunk->cPermRefs)
5827 return 0;
5828 if ( pArg->pChunk
5829 && pChunk->iLastUsed >= pArg->pChunk->iLastUsed)
5830 return 0;
5831
5832 /*
5833 * Check that it's not in any of the TLBs.
5834 */
5835 PVM pVM = pArg->pVM;
5836 if ( pVM->pgm.s.ChunkR3Map.Tlb.aEntries[PGM_CHUNKR3MAPTLB_IDX(pChunk->Core.Key)].idChunk
5837 == pChunk->Core.Key)
5838 {
5839 pChunk = NULL;
5840 return 0;
5841 }
5842#ifdef VBOX_STRICT
5843 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.ChunkR3Map.Tlb.aEntries); i++)
5844 {
5845 Assert(pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].pChunk != pChunk);
5846 Assert(pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].idChunk != pChunk->Core.Key);
5847 }
5848#endif
5849
5850#if 0 /* This is too much work with the PGMCPU::PhysTlb as well. We flush them all instead. */
5851 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.PhysTlbR3.aEntries); i++)
5852 if (pVM->pgm.s.PhysTlbR3.aEntries[i].pMap == pChunk)
5853 return 0;
5854#endif
5855
5856 pArg->pChunk = pChunk;
5857 return 0;
5858}
5859
5860
5861/**
5862 * Finds a good candidate for unmapping when the ring-3 mapping cache is full.
5863 *
5864 * The candidate will not be part of any TLBs, so no need to flush
5865 * anything afterwards.
5866 *
5867 * @returns Chunk id.
5868 * @param pVM The cross context VM structure.
5869 */
5870static int32_t pgmR3PhysChunkFindUnmapCandidate(PVM pVM)
5871{
5872 PGM_LOCK_ASSERT_OWNER(pVM);
5873
5874 /*
5875 * Enumerate the age tree starting with the left most node.
5876 */
5877 STAM_PROFILE_START(&pVM->pgm.s.Stats.StatChunkFindCandidate, a);
5878 PGMR3PHYSCHUNKUNMAPCB Args;
5879 Args.pVM = pVM;
5880 Args.pChunk = NULL;
5881 RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkUnmapCandidateCallback, &Args);
5882 Assert(Args.pChunk);
5883 if (Args.pChunk)
5884 {
5885 Assert(Args.pChunk->cRefs == 0);
5886 Assert(Args.pChunk->cPermRefs == 0);
5887 STAM_PROFILE_STOP(&pVM->pgm.s.Stats.StatChunkFindCandidate, a);
5888 return Args.pChunk->Core.Key;
5889 }
5890
5891 STAM_PROFILE_STOP(&pVM->pgm.s.Stats.StatChunkFindCandidate, a);
5892 return INT32_MAX;
5893}
5894
5895
5896/**
5897 * Rendezvous callback used by pgmR3PhysUnmapChunk that unmaps a chunk
5898 *
5899 * This is only called on one of the EMTs while the other ones are waiting for
5900 * it to complete this function.
5901 *
5902 * @returns VINF_SUCCESS (VBox strict status code).
5903 * @param pVM The cross context VM structure.
5904 * @param pVCpu The cross context virtual CPU structure of the calling EMT. Unused.
5905 * @param pvUser User pointer. Unused
5906 *
5907 */
5908static DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysUnmapChunkRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
5909{
5910 int rc = VINF_SUCCESS;
5911 PGM_LOCK_VOID(pVM);
5912 NOREF(pVCpu); NOREF(pvUser);
5913
5914 if (pVM->pgm.s.ChunkR3Map.c >= pVM->pgm.s.ChunkR3Map.cMax)
5915 {
5916 /* Flush the pgm pool cache; call the internal rendezvous handler as we're already in a rendezvous handler here. */
5917 /** @todo also not really efficient to unmap a chunk that contains PD
5918 * or PT pages. */
5919 pgmR3PoolClearAllRendezvous(pVM, pVM->apCpusR3[0], NULL /* no need to flush the REM TLB as we already did that above */);
5920
5921 /*
5922 * Request the ring-0 part to unmap a chunk to make space in the mapping cache.
5923 */
5924 GMMMAPUNMAPCHUNKREQ Req;
5925 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
5926 Req.Hdr.cbReq = sizeof(Req);
5927 Req.pvR3 = NULL;
5928 Req.idChunkMap = NIL_GMM_CHUNKID;
5929 Req.idChunkUnmap = pgmR3PhysChunkFindUnmapCandidate(pVM);
5930 if (Req.idChunkUnmap != INT32_MAX)
5931 {
5932 STAM_PROFILE_START(&pVM->pgm.s.Stats.StatChunkUnmap, a);
5933 rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
5934 STAM_PROFILE_STOP(&pVM->pgm.s.Stats.StatChunkUnmap, a);
5935 if (RT_SUCCESS(rc))
5936 {
5937 /*
5938 * Remove the unmapped one.
5939 */
5940 PPGMCHUNKR3MAP pUnmappedChunk = (PPGMCHUNKR3MAP)RTAvlU32Remove(&pVM->pgm.s.ChunkR3Map.pTree, Req.idChunkUnmap);
5941 AssertRelease(pUnmappedChunk);
5942 AssertRelease(!pUnmappedChunk->cRefs);
5943 AssertRelease(!pUnmappedChunk->cPermRefs);
5944 pUnmappedChunk->pv = NULL;
5945 pUnmappedChunk->Core.Key = UINT32_MAX;
5946 MMR3HeapFree(pUnmappedChunk);
5947 pVM->pgm.s.ChunkR3Map.c--;
5948 pVM->pgm.s.cUnmappedChunks++;
5949
5950 /*
5951 * Flush dangling PGM pointers (R3 & R0 ptrs to GC physical addresses).
5952 */
5953 /** @todo We should not flush chunks which include cr3 mappings. */
5954 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
5955 {
5956 PPGMCPU pPGM = &pVM->apCpusR3[idCpu]->pgm.s;
5957
5958 pPGM->pGst32BitPdR3 = NULL;
5959 pPGM->pGstPaePdptR3 = NULL;
5960 pPGM->pGstAmd64Pml4R3 = NULL;
5961 pPGM->pGstEptPml4R3 = NULL;
5962 pPGM->pGst32BitPdR0 = NIL_RTR0PTR;
5963 pPGM->pGstPaePdptR0 = NIL_RTR0PTR;
5964 pPGM->pGstAmd64Pml4R0 = NIL_RTR0PTR;
5965 pPGM->pGstEptPml4R0 = NIL_RTR0PTR;
5966 for (unsigned i = 0; i < RT_ELEMENTS(pPGM->apGstPaePDsR3); i++)
5967 {
5968 pPGM->apGstPaePDsR3[i] = NULL;
5969 pPGM->apGstPaePDsR0[i] = NIL_RTR0PTR;
5970 }
5971
5972 /* Flush REM TLBs. */
5973 CPUMSetChangedFlags(pVM->apCpusR3[idCpu], CPUM_CHANGED_GLOBAL_TLB_FLUSH);
5974 }
5975
5976 pgmR3PhysChunkInvalidateTLB(pVM, true /*fInRendezvous*/); /* includes pgmPhysInvalidatePageMapTLB call */
5977 }
5978 }
5979 }
5980 PGM_UNLOCK(pVM);
5981 return rc;
5982}
5983
5984/**
5985 * Unmap a chunk to free up virtual address space (request packet handler for pgmR3PhysChunkMap)
5986 *
5987 * @param pVM The cross context VM structure.
5988 */
5989static DECLCALLBACK(void) pgmR3PhysUnmapChunk(PVM pVM)
5990{
5991 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysUnmapChunkRendezvous, NULL);
5992 AssertRC(rc);
5993}
5994
5995
5996/**
5997 * Maps the given chunk into the ring-3 mapping cache.
5998 *
5999 * This will call ring-0.
6000 *
6001 * @returns VBox status code.
6002 * @param pVM The cross context VM structure.
6003 * @param idChunk The chunk in question.
6004 * @param ppChunk Where to store the chunk tracking structure.
6005 *
6006 * @remarks Called from within the PGM critical section.
6007 * @remarks Can be called from any thread!
6008 */
6009int pgmR3PhysChunkMap(PVM pVM, uint32_t idChunk, PPPGMCHUNKR3MAP ppChunk)
6010{
6011 int rc;
6012
6013 PGM_LOCK_ASSERT_OWNER(pVM);
6014
6015 /*
6016 * Move the chunk time forward.
6017 */
6018 pVM->pgm.s.ChunkR3Map.iNow++;
6019 if (pVM->pgm.s.ChunkR3Map.iNow == 0)
6020 {
6021 pVM->pgm.s.ChunkR3Map.iNow = 4;
6022 RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkAgeingRolloverCallback, NULL);
6023 }
6024
6025 /*
6026 * Allocate a new tracking structure first.
6027 */
6028 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)MMR3HeapAllocZ(pVM, MM_TAG_PGM_CHUNK_MAPPING, sizeof(*pChunk));
6029 AssertReturn(pChunk, VERR_NO_MEMORY);
6030 pChunk->Core.Key = idChunk;
6031 pChunk->iLastUsed = pVM->pgm.s.ChunkR3Map.iNow;
6032
6033 /*
6034 * Request the ring-0 part to map the chunk in question.
6035 */
6036 GMMMAPUNMAPCHUNKREQ Req;
6037 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
6038 Req.Hdr.cbReq = sizeof(Req);
6039 Req.pvR3 = NULL;
6040 Req.idChunkMap = idChunk;
6041 Req.idChunkUnmap = NIL_GMM_CHUNKID;
6042
6043 /* Must be callable from any thread, so can't use VMMR3CallR0. */
6044 STAM_PROFILE_START(&pVM->pgm.s.Stats.StatChunkMap, a);
6045 rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), NIL_VMCPUID, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
6046 STAM_PROFILE_STOP(&pVM->pgm.s.Stats.StatChunkMap, a);
6047 if (RT_SUCCESS(rc))
6048 {
6049 pChunk->pv = Req.pvR3;
6050
6051 /*
6052 * If we're running out of virtual address space, then we should
6053 * unmap another chunk.
6054 *
6055 * Currently, an unmap operation requires that all other virtual CPUs
6056 * are idling and not by chance making use of the memory we're
6057 * unmapping. So, we create an async unmap operation here.
6058 *
6059 * Now, when creating or restoring a saved state this wont work very
6060 * well since we may want to restore all guest RAM + a little something.
6061 * So, we have to do the unmap synchronously. Fortunately for us
6062 * though, during these operations the other virtual CPUs are inactive
6063 * and it should be safe to do this.
6064 */
6065 /** @todo Eventually we should lock all memory when used and do
6066 * map+unmap as one kernel call without any rendezvous or
6067 * other precautions. */
6068 if (pVM->pgm.s.ChunkR3Map.c + 1 >= pVM->pgm.s.ChunkR3Map.cMax)
6069 {
6070 switch (VMR3GetState(pVM))
6071 {
6072 case VMSTATE_LOADING:
6073 case VMSTATE_SAVING:
6074 {
6075 PVMCPU pVCpu = VMMGetCpu(pVM);
6076 if ( pVCpu
6077 && pVM->pgm.s.cDeprecatedPageLocks == 0)
6078 {
6079 pgmR3PhysUnmapChunkRendezvous(pVM, pVCpu, NULL);
6080 break;
6081 }
6082 }
6083 RT_FALL_THRU();
6084 default:
6085 rc = VMR3ReqCallNoWait(pVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3PhysUnmapChunk, 1, pVM);
6086 AssertRC(rc);
6087 break;
6088 }
6089 }
6090
6091 /*
6092 * Update the tree. We must do this after any unmapping to make sure
6093 * the chunk we're going to return isn't unmapped by accident.
6094 */
6095 AssertPtr(Req.pvR3);
6096 bool fRc = RTAvlU32Insert(&pVM->pgm.s.ChunkR3Map.pTree, &pChunk->Core);
6097 AssertRelease(fRc);
6098 pVM->pgm.s.ChunkR3Map.c++;
6099 pVM->pgm.s.cMappedChunks++;
6100 }
6101 else
6102 {
6103 /** @todo this may fail because of /proc/sys/vm/max_map_count, so we
6104 * should probably restrict ourselves on linux. */
6105 AssertRC(rc);
6106 MMR3HeapFree(pChunk);
6107 pChunk = NULL;
6108 }
6109
6110 *ppChunk = pChunk;
6111 return rc;
6112}
6113
6114
6115/**
6116 * Invalidates the TLB for the ring-3 mapping cache.
6117 *
6118 * @param pVM The cross context VM structure.
6119 * @param fInRendezvous Set if we're in a rendezvous.
6120 */
6121DECLHIDDEN(void) pgmR3PhysChunkInvalidateTLB(PVM pVM, bool fInRendezvous)
6122{
6123 PGM_LOCK_VOID(pVM);
6124 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.ChunkR3Map.Tlb.aEntries); i++)
6125 {
6126 pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].idChunk = NIL_GMM_CHUNKID;
6127 pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].pChunk = NULL;
6128 }
6129 /* The page map TLB references chunks, so invalidate that one too. */
6130 pgmPhysInvalidatePageMapTLB(pVM, fInRendezvous);
6131 PGM_UNLOCK(pVM);
6132}
6133
6134
6135/**
6136 * Response to VM_FF_PGM_NEED_HANDY_PAGES and helper for pgmPhysEnsureHandyPage.
6137 *
6138 * This function will also work the VM_FF_PGM_NO_MEMORY force action flag, to
6139 * signal and clear the out of memory condition. When called, this API is used
6140 * to try clear the condition when the user wants to resume.
6141 *
6142 * @returns The following VBox status codes.
6143 * @retval VINF_SUCCESS on success. FFs cleared.
6144 * @retval VINF_EM_NO_MEMORY if we're out of memory. The FF is not cleared in
6145 * this case and it gets accompanied by VM_FF_PGM_NO_MEMORY.
6146 *
6147 * @param pVM The cross context VM structure.
6148 *
6149 * @remarks The VINF_EM_NO_MEMORY status is for the benefit of the FF processing
6150 * in EM.cpp and shouldn't be propagated outside TRPM, HM, EM and
6151 * pgmPhysEnsureHandyPage. There is one exception to this in the \#PF
6152 * handler.
6153 */
6154VMMR3DECL(int) PGMR3PhysAllocateHandyPages(PVM pVM)
6155{
6156 PGM_LOCK_VOID(pVM);
6157
6158 /*
6159 * Allocate more pages, noting down the index of the first new page.
6160 */
6161 uint32_t iClear = pVM->pgm.s.cHandyPages;
6162 AssertMsgReturn(iClear <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), ("%d", iClear), VERR_PGM_HANDY_PAGE_IPE);
6163 Log(("PGMR3PhysAllocateHandyPages: %d -> %d\n", iClear, RT_ELEMENTS(pVM->pgm.s.aHandyPages)));
6164 int rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES, 0, NULL);
6165 /** @todo we should split this up into an allocate and flush operation. sometimes you want to flush and not allocate more (which will trigger the vm account limit error) */
6166 if ( rc == VERR_GMM_HIT_VM_ACCOUNT_LIMIT
6167 && pVM->pgm.s.cHandyPages > 0)
6168 {
6169 /* Still handy pages left, so don't panic. */
6170 rc = VINF_SUCCESS;
6171 }
6172
6173 if (RT_SUCCESS(rc))
6174 {
6175 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
6176 Assert(pVM->pgm.s.cHandyPages > 0);
6177#ifdef VBOX_STRICT
6178 uint32_t i;
6179 for (i = iClear; i < pVM->pgm.s.cHandyPages; i++)
6180 if ( pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID
6181 || pVM->pgm.s.aHandyPages[i].idSharedPage != NIL_GMM_PAGEID
6182 || (pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & GUEST_PAGE_OFFSET_MASK))
6183 break;
6184 if (i != pVM->pgm.s.cHandyPages)
6185 {
6186 RTAssertMsg1Weak(NULL, __LINE__, __FILE__, __FUNCTION__);
6187 RTAssertMsg2Weak("i=%d iClear=%d cHandyPages=%d\n", i, iClear, pVM->pgm.s.cHandyPages);
6188 for (uint32_t j = iClear; j < pVM->pgm.s.cHandyPages; j++)
6189 RTAssertMsg2Add("%03d: idPage=%d HCPhysGCPhys=%RHp idSharedPage=%d%s\n", j,
6190 pVM->pgm.s.aHandyPages[j].idPage,
6191 pVM->pgm.s.aHandyPages[j].HCPhysGCPhys,
6192 pVM->pgm.s.aHandyPages[j].idSharedPage,
6193 j == i ? " <---" : "");
6194 RTAssertPanic();
6195 }
6196#endif
6197 }
6198 else
6199 {
6200 /*
6201 * We should never get here unless there is a genuine shortage of
6202 * memory (or some internal error). Flag the error so the VM can be
6203 * suspended ASAP and the user informed. If we're totally out of
6204 * handy pages we will return failure.
6205 */
6206 /* Report the failure. */
6207 LogRel(("PGM: Failed to procure handy pages; rc=%Rrc cHandyPages=%#x\n"
6208 " cAllPages=%#x cPrivatePages=%#x cSharedPages=%#x cZeroPages=%#x\n",
6209 rc, pVM->pgm.s.cHandyPages,
6210 pVM->pgm.s.cAllPages, pVM->pgm.s.cPrivatePages, pVM->pgm.s.cSharedPages, pVM->pgm.s.cZeroPages));
6211
6212 if ( rc != VERR_NO_MEMORY
6213 && rc != VERR_NO_PHYS_MEMORY
6214 && rc != VERR_LOCK_FAILED)
6215 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
6216 {
6217 LogRel(("PGM: aHandyPages[#%#04x] = {.HCPhysGCPhys=%RHp, .idPage=%#08x, .idSharedPage=%#08x}\n",
6218 i, pVM->pgm.s.aHandyPages[i].HCPhysGCPhys, pVM->pgm.s.aHandyPages[i].idPage,
6219 pVM->pgm.s.aHandyPages[i].idSharedPage));
6220 uint32_t const idPage = pVM->pgm.s.aHandyPages[i].idPage;
6221 if (idPage != NIL_GMM_PAGEID)
6222 {
6223 uint32_t const idRamRangeMax = RT_MIN(pVM->pgm.s.idRamRangeMax, RT_ELEMENTS(pVM->pgm.s.apRamRanges) - 1U);
6224 for (uint32_t idRamRange = 0; idRamRange <= idRamRangeMax; idRamRange++)
6225 {
6226 PPGMRAMRANGE const pRam = pVM->pgm.s.apRamRanges[idRamRange];
6227 Assert(pRam || idRamRange == 0);
6228 if (!pRam) continue;
6229 Assert(pRam->idRange == idRamRange);
6230
6231 uint32_t const cPages = pRam->cb >> GUEST_PAGE_SHIFT;
6232 for (uint32_t iPage = 0; iPage < cPages; iPage++)
6233 if (PGM_PAGE_GET_PAGEID(&pRam->aPages[iPage]) == idPage)
6234 LogRel(("PGM: Used by %RGp %R[pgmpage] (%s)\n",
6235 pRam->GCPhys + ((RTGCPHYS)iPage << GUEST_PAGE_SHIFT), &pRam->aPages[iPage], pRam->pszDesc));
6236 }
6237 }
6238 }
6239
6240 if (rc == VERR_NO_MEMORY)
6241 {
6242 uint64_t cbHostRamAvail = 0;
6243 int rc2 = RTSystemQueryAvailableRam(&cbHostRamAvail);
6244 if (RT_SUCCESS(rc2))
6245 LogRel(("Host RAM: %RU64MB available\n", cbHostRamAvail / _1M));
6246 else
6247 LogRel(("Cannot determine the amount of available host memory\n"));
6248 }
6249
6250 /* Set the FFs and adjust rc. */
6251 VM_FF_SET(pVM, VM_FF_PGM_NEED_HANDY_PAGES);
6252 VM_FF_SET(pVM, VM_FF_PGM_NO_MEMORY);
6253 if ( rc == VERR_NO_MEMORY
6254 || rc == VERR_NO_PHYS_MEMORY
6255 || rc == VERR_LOCK_FAILED)
6256 rc = VINF_EM_NO_MEMORY;
6257 }
6258
6259 PGM_UNLOCK(pVM);
6260 return rc;
6261}
6262
6263
6264/*********************************************************************************************************************************
6265* Other Stuff *
6266*********************************************************************************************************************************/
6267
6268#if !defined(VBOX_VMM_TARGET_ARMV8)
6269/**
6270 * Sets the Address Gate 20 state.
6271 *
6272 * @param pVCpu The cross context virtual CPU structure.
6273 * @param fEnable True if the gate should be enabled.
6274 * False if the gate should be disabled.
6275 */
6276VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable)
6277{
6278 LogFlow(("PGMR3PhysSetA20 %d (was %d)\n", fEnable, pVCpu->pgm.s.fA20Enabled));
6279 if (pVCpu->pgm.s.fA20Enabled != fEnable)
6280 {
6281#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
6282 PCCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
6283 if ( CPUMIsGuestInVmxRootMode(pCtx)
6284 && !fEnable)
6285 {
6286 Log(("Cannot enter A20M mode while in VMX root mode\n"));
6287 return;
6288 }
6289#endif
6290 pVCpu->pgm.s.fA20Enabled = fEnable;
6291 pVCpu->pgm.s.GCPhysA20Mask = ~((RTGCPHYS)!fEnable << 20);
6292 if (VM_IS_NEM_ENABLED(pVCpu->CTX_SUFF(pVM)))
6293 NEMR3NotifySetA20(pVCpu, fEnable);
6294#ifdef PGM_WITH_A20
6295 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
6296 pgmR3RefreshShadowModeAfterA20Change(pVCpu);
6297 HMFlushTlb(pVCpu);
6298#endif
6299#if 0 /* PGMGetPage will apply the A20 mask to the GCPhys it returns, so we must invalid both sides of the TLB. */
6300 IEMTlbInvalidateAllPhysical(pVCpu);
6301#else
6302 IEMTlbInvalidateAllGlobal(pVCpu);
6303#endif
6304 STAM_REL_COUNTER_INC(&pVCpu->pgm.s.cA20Changes);
6305 }
6306}
6307#endif
6308
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