VirtualBox

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

Last change on this file since 36891 was 36891, checked in by vboxsync, 14 years ago

PGM: Put a TLB in front of the RAM ranges to speed up lookup (disabled).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 156.2 KB
Line 
1/* $Id: PGMPhys.cpp 36891 2011-04-29 13:22:57Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor, Physical Memory Addressing.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_PGM_PHYS
23#include <VBox/vmm/pgm.h>
24#include <VBox/vmm/iom.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/stam.h>
27#include <VBox/vmm/rem.h>
28#include <VBox/vmm/pdmdev.h>
29#include "PGMInternal.h"
30#include <VBox/vmm/vm.h>
31#include "PGMInline.h"
32#include <VBox/sup.h>
33#include <VBox/param.h>
34#include <VBox/err.h>
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/alloc.h>
38#include <iprt/asm.h>
39#include <iprt/thread.h>
40#include <iprt/string.h>
41#include <iprt/system.h>
42
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/** The number of pages to free in one batch. */
48#define PGMPHYS_FREE_PAGE_BATCH_SIZE 128
49
50
51/*******************************************************************************
52* Internal Functions *
53*******************************************************************************/
54static DECLCALLBACK(int) pgmR3PhysRomWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
55
56
57/*
58 * PGMR3PhysReadU8-64
59 * PGMR3PhysWriteU8-64
60 */
61#define PGMPHYSFN_READNAME PGMR3PhysReadU8
62#define PGMPHYSFN_WRITENAME PGMR3PhysWriteU8
63#define PGMPHYS_DATASIZE 1
64#define PGMPHYS_DATATYPE uint8_t
65#include "PGMPhysRWTmpl.h"
66
67#define PGMPHYSFN_READNAME PGMR3PhysReadU16
68#define PGMPHYSFN_WRITENAME PGMR3PhysWriteU16
69#define PGMPHYS_DATASIZE 2
70#define PGMPHYS_DATATYPE uint16_t
71#include "PGMPhysRWTmpl.h"
72
73#define PGMPHYSFN_READNAME PGMR3PhysReadU32
74#define PGMPHYSFN_WRITENAME PGMR3PhysWriteU32
75#define PGMPHYS_DATASIZE 4
76#define PGMPHYS_DATATYPE uint32_t
77#include "PGMPhysRWTmpl.h"
78
79#define PGMPHYSFN_READNAME PGMR3PhysReadU64
80#define PGMPHYSFN_WRITENAME PGMR3PhysWriteU64
81#define PGMPHYS_DATASIZE 8
82#define PGMPHYS_DATATYPE uint64_t
83#include "PGMPhysRWTmpl.h"
84
85
86/**
87 * EMT worker for PGMR3PhysReadExternal.
88 */
89static DECLCALLBACK(int) pgmR3PhysReadExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, void *pvBuf, size_t cbRead)
90{
91 PGMPhysRead(pVM, *pGCPhys, pvBuf, cbRead);
92 return VINF_SUCCESS;
93}
94
95
96/**
97 * Read from physical memory, external users.
98 *
99 * @returns VBox status code.
100 * @retval VINF_SUCCESS.
101 *
102 * @param pVM VM Handle.
103 * @param GCPhys Physical address to read from.
104 * @param pvBuf Where to read into.
105 * @param cbRead How many bytes to read.
106 *
107 * @thread Any but EMTs.
108 */
109VMMR3DECL(int) PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
110{
111 VM_ASSERT_OTHER_THREAD(pVM);
112
113 AssertMsgReturn(cbRead > 0, ("don't even think about reading zero bytes!\n"), VINF_SUCCESS);
114 LogFlow(("PGMR3PhysReadExternal: %RGp %d\n", GCPhys, cbRead));
115
116 pgmLock(pVM);
117
118 /*
119 * Copy loop on ram ranges.
120 */
121 PPGMRAMRANGE pRam = pgmPhysGetRangeAtOrAbove(pVM, GCPhys);
122 for (;;)
123 {
124 /* Inside range or not? */
125 if (pRam && GCPhys >= pRam->GCPhys)
126 {
127 /*
128 * Must work our way thru this page by page.
129 */
130 RTGCPHYS off = GCPhys - pRam->GCPhys;
131 while (off < pRam->cb)
132 {
133 unsigned iPage = off >> PAGE_SHIFT;
134 PPGMPAGE pPage = &pRam->aPages[iPage];
135
136 /*
137 * If the page has an ALL access handler, we'll have to
138 * delegate the job to EMT.
139 */
140 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
141 {
142 pgmUnlock(pVM);
143
144 return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysReadExternalEMT, 4,
145 pVM, &GCPhys, pvBuf, cbRead);
146 }
147 Assert(!PGM_PAGE_IS_MMIO(pPage));
148
149 /*
150 * Simple stuff, go ahead.
151 */
152 size_t cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
153 if (cb > cbRead)
154 cb = cbRead;
155 const void *pvSrc;
156 int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, pRam->GCPhys + off, &pvSrc);
157 if (RT_SUCCESS(rc))
158 memcpy(pvBuf, pvSrc, cb);
159 else
160 {
161 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
162 pRam->GCPhys + off, pPage, rc));
163 memset(pvBuf, 0xff, cb);
164 }
165
166 /* next page */
167 if (cb >= cbRead)
168 {
169 pgmUnlock(pVM);
170 return VINF_SUCCESS;
171 }
172 cbRead -= cb;
173 off += cb;
174 GCPhys += cb;
175 pvBuf = (char *)pvBuf + cb;
176 } /* walk pages in ram range. */
177 }
178 else
179 {
180 LogFlow(("PGMPhysRead: Unassigned %RGp size=%u\n", GCPhys, cbRead));
181
182 /*
183 * Unassigned address space.
184 */
185 size_t cb = pRam ? pRam->GCPhys - GCPhys : ~(size_t)0;
186 if (cb >= cbRead)
187 {
188 memset(pvBuf, 0xff, cbRead);
189 break;
190 }
191 memset(pvBuf, 0xff, cb);
192
193 cbRead -= cb;
194 pvBuf = (char *)pvBuf + cb;
195 GCPhys += cb;
196 }
197
198 /* Advance range if necessary. */
199 while (pRam && GCPhys > pRam->GCPhysLast)
200 pRam = pRam->CTX_SUFF(pNext);
201 } /* Ram range walk */
202
203 pgmUnlock(pVM);
204
205 return VINF_SUCCESS;
206}
207
208
209/**
210 * EMT worker for PGMR3PhysWriteExternal.
211 */
212static DECLCALLBACK(int) pgmR3PhysWriteExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, const void *pvBuf, size_t cbWrite)
213{
214 /** @todo VERR_EM_NO_MEMORY */
215 PGMPhysWrite(pVM, *pGCPhys, pvBuf, cbWrite);
216 return VINF_SUCCESS;
217}
218
219
220/**
221 * Write to physical memory, external users.
222 *
223 * @returns VBox status code.
224 * @retval VINF_SUCCESS.
225 * @retval VERR_EM_NO_MEMORY.
226 *
227 * @param pVM VM Handle.
228 * @param GCPhys Physical address to write to.
229 * @param pvBuf What to write.
230 * @param cbWrite How many bytes to write.
231 * @param pszWho Who is writing. For tracking down who is writing
232 * after we've saved the state.
233 *
234 * @thread Any but EMTs.
235 */
236VMMDECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, const char *pszWho)
237{
238 VM_ASSERT_OTHER_THREAD(pVM);
239
240 AssertMsg(!pVM->pgm.s.fNoMorePhysWrites,
241 ("Calling PGMR3PhysWriteExternal after pgmR3Save()! GCPhys=%RGp cbWrite=%#x pszWho=%s\n",
242 GCPhys, cbWrite, pszWho));
243 AssertMsgReturn(cbWrite > 0, ("don't even think about writing zero bytes!\n"), VINF_SUCCESS);
244 LogFlow(("PGMR3PhysWriteExternal: %RGp %d\n", GCPhys, cbWrite));
245
246 pgmLock(pVM);
247
248 /*
249 * Copy loop on ram ranges, stop when we hit something difficult.
250 */
251 PPGMRAMRANGE pRam = pgmPhysGetRangeAtOrAbove(pVM, GCPhys);
252 for (;;)
253 {
254 /* Inside range or not? */
255 if (pRam && GCPhys >= pRam->GCPhys)
256 {
257 /*
258 * Must work our way thru this page by page.
259 */
260 RTGCPTR off = GCPhys - pRam->GCPhys;
261 while (off < pRam->cb)
262 {
263 RTGCPTR iPage = off >> PAGE_SHIFT;
264 PPGMPAGE pPage = &pRam->aPages[iPage];
265
266 /*
267 * Is the page problematic, we have to do the work on the EMT.
268 *
269 * Allocating writable pages and access handlers are
270 * problematic, write monitored pages are simple and can be
271 * dealt with here.
272 */
273 if ( PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
274 || PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
275 {
276 if ( PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
277 && !PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
278 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage);
279 else
280 {
281 pgmUnlock(pVM);
282
283 return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysWriteExternalEMT, 4,
284 pVM, &GCPhys, pvBuf, cbWrite);
285 }
286 }
287 Assert(!PGM_PAGE_IS_MMIO(pPage));
288
289 /*
290 * Simple stuff, go ahead.
291 */
292 size_t cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
293 if (cb > cbWrite)
294 cb = cbWrite;
295 void *pvDst;
296 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pRam->GCPhys + off, &pvDst);
297 if (RT_SUCCESS(rc))
298 memcpy(pvDst, pvBuf, cb);
299 else
300 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
301 pRam->GCPhys + off, pPage, rc));
302
303 /* next page */
304 if (cb >= cbWrite)
305 {
306 pgmUnlock(pVM);
307 return VINF_SUCCESS;
308 }
309
310 cbWrite -= cb;
311 off += cb;
312 GCPhys += cb;
313 pvBuf = (const char *)pvBuf + cb;
314 } /* walk pages in ram range */
315 }
316 else
317 {
318 /*
319 * Unassigned address space, skip it.
320 */
321 if (!pRam)
322 break;
323 size_t cb = pRam->GCPhys - GCPhys;
324 if (cb >= cbWrite)
325 break;
326 cbWrite -= cb;
327 pvBuf = (const char *)pvBuf + cb;
328 GCPhys += cb;
329 }
330
331 /* Advance range if necessary. */
332 while (pRam && GCPhys > pRam->GCPhysLast)
333 pRam = pRam->CTX_SUFF(pNext);
334 } /* Ram range walk */
335
336 pgmUnlock(pVM);
337 return VINF_SUCCESS;
338}
339
340
341/**
342 * VMR3ReqCall worker for PGMR3PhysGCPhys2CCPtrExternal to make pages writable.
343 *
344 * @returns see PGMR3PhysGCPhys2CCPtrExternal
345 * @param pVM The VM handle.
346 * @param pGCPhys Pointer to the guest physical address.
347 * @param ppv Where to store the mapping address.
348 * @param pLock Where to store the lock.
349 */
350static DECLCALLBACK(int) pgmR3PhysGCPhys2CCPtrDelegated(PVM pVM, PRTGCPHYS pGCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
351{
352 /*
353 * Just hand it to PGMPhysGCPhys2CCPtr and check that it's not a page with
354 * an access handler after it succeeds.
355 */
356 int rc = pgmLock(pVM);
357 AssertRCReturn(rc, rc);
358
359 rc = PGMPhysGCPhys2CCPtr(pVM, *pGCPhys, ppv, pLock);
360 if (RT_SUCCESS(rc))
361 {
362 PPGMPAGEMAPTLBE pTlbe;
363 int rc2 = pgmPhysPageQueryTlbe(pVM, *pGCPhys, &pTlbe);
364 AssertFatalRC(rc2);
365 PPGMPAGE pPage = pTlbe->pPage;
366 if (PGM_PAGE_IS_MMIO(pPage))
367 {
368 PGMPhysReleasePageMappingLock(pVM, pLock);
369 rc = VERR_PGM_PHYS_PAGE_RESERVED;
370 }
371 else if ( PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
372#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
373 || pgmPoolIsDirtyPage(pVM, *pGCPhys)
374#endif
375 )
376 {
377 /* We *must* flush any corresponding pgm pool page here, otherwise we'll
378 * not be informed about writes and keep bogus gst->shw mappings around.
379 */
380 pgmPoolFlushPageByGCPhys(pVM, *pGCPhys);
381 Assert(!PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage));
382 /** @todo r=bird: return VERR_PGM_PHYS_PAGE_RESERVED here if it still has
383 * active handlers, see the PGMR3PhysGCPhys2CCPtrExternal docs. */
384 }
385 }
386
387 pgmUnlock(pVM);
388 return rc;
389}
390
391
392/**
393 * Requests the mapping of a guest page into ring-3, external threads.
394 *
395 * When you're done with the page, call PGMPhysReleasePageMappingLock() ASAP to
396 * release it.
397 *
398 * This API will assume your intention is to write to the page, and will
399 * therefore replace shared and zero pages. If you do not intend to modify the
400 * page, use the PGMR3PhysGCPhys2CCPtrReadOnlyExternal() API.
401 *
402 * @returns VBox status code.
403 * @retval VINF_SUCCESS on success.
404 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical
405 * backing or if the page has any active access handlers. The caller
406 * must fall back on using PGMR3PhysWriteExternal.
407 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
408 *
409 * @param pVM The VM handle.
410 * @param GCPhys The guest physical address of the page that should be mapped.
411 * @param ppv Where to store the address corresponding to GCPhys.
412 * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
413 *
414 * @remark Avoid calling this API from within critical sections (other than the
415 * PGM one) because of the deadlock risk when we have to delegating the
416 * task to an EMT.
417 * @thread Any.
418 */
419VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrExternal(PVM pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
420{
421 AssertPtr(ppv);
422 AssertPtr(pLock);
423
424 Assert(VM_IS_EMT(pVM) || !PGMIsLockOwner(pVM));
425
426 int rc = pgmLock(pVM);
427 AssertRCReturn(rc, rc);
428
429 /*
430 * Query the Physical TLB entry for the page (may fail).
431 */
432 PPGMPAGEMAPTLBE pTlbe;
433 rc = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
434 if (RT_SUCCESS(rc))
435 {
436 PPGMPAGE pPage = pTlbe->pPage;
437 if (PGM_PAGE_IS_MMIO(pPage))
438 rc = VERR_PGM_PHYS_PAGE_RESERVED;
439 else
440 {
441 /*
442 * If the page is shared, the zero page, or being write monitored
443 * it must be converted to an page that's writable if possible.
444 * We can only deal with write monitored pages here, the rest have
445 * to be on an EMT.
446 */
447 if ( PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
448 || PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
449#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
450 || pgmPoolIsDirtyPage(pVM, GCPhys)
451#endif
452 )
453 {
454 if ( PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
455 && !PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
456#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
457 && !pgmPoolIsDirtyPage(pVM, GCPhys)
458#endif
459 )
460 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage);
461 else
462 {
463 pgmUnlock(pVM);
464
465 return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysGCPhys2CCPtrDelegated, 4,
466 pVM, &GCPhys, ppv, pLock);
467 }
468 }
469
470 /*
471 * Now, just perform the locking and calculate the return address.
472 */
473 PPGMPAGEMAP pMap = pTlbe->pMap;
474 if (pMap)
475 pMap->cRefs++;
476
477 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
478 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
479 {
480 if (cLocks == 0)
481 pVM->pgm.s.cWriteLockedPages++;
482 PGM_PAGE_INC_WRITE_LOCKS(pPage);
483 }
484 else if (cLocks != PGM_PAGE_GET_WRITE_LOCKS(pPage))
485 {
486 PGM_PAGE_INC_WRITE_LOCKS(pPage);
487 AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent write locked state!\n", GCPhys, pPage));
488 if (pMap)
489 pMap->cRefs++; /* Extra ref to prevent it from going away. */
490 }
491
492 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & PAGE_OFFSET_MASK));
493 pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_WRITE;
494 pLock->pvMap = pMap;
495 }
496 }
497
498 pgmUnlock(pVM);
499 return rc;
500}
501
502
503/**
504 * Requests the mapping of a guest page into ring-3, external threads.
505 *
506 * When you're done with the page, call PGMPhysReleasePageMappingLock() ASAP to
507 * release it.
508 *
509 * @returns VBox status code.
510 * @retval VINF_SUCCESS on success.
511 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical
512 * backing or if the page as an active ALL access handler. The caller
513 * must fall back on using PGMPhysRead.
514 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
515 *
516 * @param pVM The VM handle.
517 * @param GCPhys The guest physical address of the page that should be mapped.
518 * @param ppv Where to store the address corresponding to GCPhys.
519 * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
520 *
521 * @remark Avoid calling this API from within critical sections (other than
522 * the PGM one) because of the deadlock risk.
523 * @thread Any.
524 */
525VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrReadOnlyExternal(PVM pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock)
526{
527 int rc = pgmLock(pVM);
528 AssertRCReturn(rc, rc);
529
530 /*
531 * Query the Physical TLB entry for the page (may fail).
532 */
533 PPGMPAGEMAPTLBE pTlbe;
534 rc = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
535 if (RT_SUCCESS(rc))
536 {
537 PPGMPAGE pPage = pTlbe->pPage;
538#if 1
539 /* MMIO pages doesn't have any readable backing. */
540 if (PGM_PAGE_IS_MMIO(pPage))
541 rc = VERR_PGM_PHYS_PAGE_RESERVED;
542#else
543 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
544 rc = VERR_PGM_PHYS_PAGE_RESERVED;
545#endif
546 else
547 {
548 /*
549 * Now, just perform the locking and calculate the return address.
550 */
551 PPGMPAGEMAP pMap = pTlbe->pMap;
552 if (pMap)
553 pMap->cRefs++;
554
555 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
556 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
557 {
558 if (cLocks == 0)
559 pVM->pgm.s.cReadLockedPages++;
560 PGM_PAGE_INC_READ_LOCKS(pPage);
561 }
562 else if (cLocks != PGM_PAGE_GET_READ_LOCKS(pPage))
563 {
564 PGM_PAGE_INC_READ_LOCKS(pPage);
565 AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent readonly locked state!\n", GCPhys, pPage));
566 if (pMap)
567 pMap->cRefs++; /* Extra ref to prevent it from going away. */
568 }
569
570 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & PAGE_OFFSET_MASK));
571 pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_READ;
572 pLock->pvMap = pMap;
573 }
574 }
575
576 pgmUnlock(pVM);
577 return rc;
578}
579
580
581/**
582 * Relinks the RAM ranges using the pSelfRC and pSelfR0 pointers.
583 *
584 * Called when anything was relocated.
585 *
586 * @param pVM Pointer to the shared VM structure.
587 */
588void pgmR3PhysRelinkRamRanges(PVM pVM)
589{
590 PPGMRAMRANGE pCur;
591
592#ifdef VBOX_STRICT
593 for (pCur = pVM->pgm.s.pRamRangesXR3; pCur; pCur = pCur->pNextR3)
594 {
595 Assert((pCur->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pCur->pSelfR0 == MMHyperCCToR0(pVM, pCur));
596 Assert((pCur->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pCur->pSelfRC == MMHyperCCToRC(pVM, pCur));
597 Assert((pCur->GCPhys & PAGE_OFFSET_MASK) == 0);
598 Assert((pCur->GCPhysLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
599 Assert((pCur->cb & PAGE_OFFSET_MASK) == 0);
600 Assert(pCur->cb == pCur->GCPhysLast - pCur->GCPhys + 1);
601 for (PPGMRAMRANGE pCur2 = pVM->pgm.s.pRamRangesXR3; pCur2; pCur2 = pCur2->pNextR3)
602 Assert( pCur2 == pCur
603 || strcmp(pCur2->pszDesc, pCur->pszDesc)); /** @todo fix MMIO ranges!! */
604 }
605#endif
606
607 pCur = pVM->pgm.s.pRamRangesXR3;
608 if (pCur)
609 {
610 pVM->pgm.s.pRamRangesXR0 = pCur->pSelfR0;
611 pVM->pgm.s.pRamRangesXRC = pCur->pSelfRC;
612
613 for (; pCur->pNextR3; pCur = pCur->pNextR3)
614 {
615 pCur->pNextR0 = pCur->pNextR3->pSelfR0;
616 pCur->pNextRC = pCur->pNextR3->pSelfRC;
617 }
618
619 Assert(pCur->pNextR0 == NIL_RTR0PTR);
620 Assert(pCur->pNextRC == NIL_RTRCPTR);
621 }
622 else
623 {
624 Assert(pVM->pgm.s.pRamRangesXR0 == NIL_RTR0PTR);
625 Assert(pVM->pgm.s.pRamRangesXRC == NIL_RTRCPTR);
626 }
627 ASMAtomicIncU32(&pVM->pgm.s.idRamRangesGen);
628}
629
630
631/**
632 * Links a new RAM range into the list.
633 *
634 * @param pVM Pointer to the shared VM structure.
635 * @param pNew Pointer to the new list entry.
636 * @param pPrev Pointer to the previous list entry. If NULL, insert as head.
637 */
638static void pgmR3PhysLinkRamRange(PVM pVM, PPGMRAMRANGE pNew, PPGMRAMRANGE pPrev)
639{
640 AssertMsg(pNew->pszDesc, ("%RGp-%RGp\n", pNew->GCPhys, pNew->GCPhysLast));
641 Assert((pNew->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pNew->pSelfR0 == MMHyperCCToR0(pVM, pNew));
642 Assert((pNew->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pNew->pSelfRC == MMHyperCCToRC(pVM, pNew));
643
644 pgmLock(pVM);
645
646 PPGMRAMRANGE pRam = pPrev ? pPrev->pNextR3 : pVM->pgm.s.pRamRangesXR3;
647 pNew->pNextR3 = pRam;
648 pNew->pNextR0 = pRam ? pRam->pSelfR0 : NIL_RTR0PTR;
649 pNew->pNextRC = pRam ? pRam->pSelfRC : NIL_RTRCPTR;
650
651 if (pPrev)
652 {
653 pPrev->pNextR3 = pNew;
654 pPrev->pNextR0 = pNew->pSelfR0;
655 pPrev->pNextRC = pNew->pSelfRC;
656 }
657 else
658 {
659 pVM->pgm.s.pRamRangesXR3 = pNew;
660 pVM->pgm.s.pRamRangesXR0 = pNew->pSelfR0;
661 pVM->pgm.s.pRamRangesXRC = pNew->pSelfRC;
662 }
663 ASMAtomicIncU32(&pVM->pgm.s.idRamRangesGen);
664 pgmUnlock(pVM);
665}
666
667
668/**
669 * Unlink an existing RAM range from the list.
670 *
671 * @param pVM Pointer to the shared VM structure.
672 * @param pRam Pointer to the new list entry.
673 * @param pPrev Pointer to the previous list entry. If NULL, insert as head.
674 */
675static void pgmR3PhysUnlinkRamRange2(PVM pVM, PPGMRAMRANGE pRam, PPGMRAMRANGE pPrev)
676{
677 Assert(pPrev ? pPrev->pNextR3 == pRam : pVM->pgm.s.pRamRangesXR3 == pRam);
678 Assert((pRam->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pRam->pSelfR0 == MMHyperCCToR0(pVM, pRam));
679 Assert((pRam->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pRam->pSelfRC == MMHyperCCToRC(pVM, pRam));
680
681 pgmLock(pVM);
682
683 PPGMRAMRANGE pNext = pRam->pNextR3;
684 if (pPrev)
685 {
686 pPrev->pNextR3 = pNext;
687 pPrev->pNextR0 = pNext ? pNext->pSelfR0 : NIL_RTR0PTR;
688 pPrev->pNextRC = pNext ? pNext->pSelfRC : NIL_RTRCPTR;
689 }
690 else
691 {
692 Assert(pVM->pgm.s.pRamRangesXR3 == pRam);
693 pVM->pgm.s.pRamRangesXR3 = pNext;
694 pVM->pgm.s.pRamRangesXR0 = pNext ? pNext->pSelfR0 : NIL_RTR0PTR;
695 pVM->pgm.s.pRamRangesXRC = pNext ? pNext->pSelfRC : NIL_RTRCPTR;
696 }
697 ASMAtomicIncU32(&pVM->pgm.s.idRamRangesGen);
698 pgmUnlock(pVM);
699}
700
701
702/**
703 * Unlink an existing RAM range from the list.
704 *
705 * @param pVM Pointer to the shared VM structure.
706 * @param pRam Pointer to the new list entry.
707 */
708static void pgmR3PhysUnlinkRamRange(PVM pVM, PPGMRAMRANGE pRam)
709{
710 pgmLock(pVM);
711
712 /* find prev. */
713 PPGMRAMRANGE pPrev = NULL;
714 PPGMRAMRANGE pCur = pVM->pgm.s.pRamRangesXR3;
715 while (pCur != pRam)
716 {
717 pPrev = pCur;
718 pCur = pCur->pNextR3;
719 }
720 AssertFatal(pCur);
721
722 pgmR3PhysUnlinkRamRange2(pVM, pRam, pPrev);
723 pgmUnlock(pVM);
724}
725
726
727/**
728 * Frees a range of pages, replacing them with ZERO pages of the specified type.
729 *
730 * @returns VBox status code.
731 * @param pVM The VM handle.
732 * @param pRam The RAM range in which the pages resides.
733 * @param GCPhys The address of the first page.
734 * @param GCPhysLast The address of the last page.
735 * @param uType The page type to replace then with.
736 */
737static int pgmR3PhysFreePageRange(PVM pVM, PPGMRAMRANGE pRam, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, uint8_t uType)
738{
739 Assert(PGMIsLockOwner(pVM));
740 uint32_t cPendingPages = 0;
741 PGMMFREEPAGESREQ pReq;
742 int rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
743 AssertLogRelRCReturn(rc, rc);
744
745 /* Iterate the pages. */
746 PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
747 uint32_t cPagesLeft = ((GCPhysLast - GCPhys) >> PAGE_SHIFT) + 1;
748 while (cPagesLeft-- > 0)
749 {
750 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPageDst, GCPhys);
751 AssertLogRelRCReturn(rc, rc); /* We're done for if this goes wrong. */
752
753 PGM_PAGE_SET_TYPE(pPageDst, uType);
754
755 GCPhys += PAGE_SIZE;
756 pPageDst++;
757 }
758
759 if (cPendingPages)
760 {
761 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
762 AssertLogRelRCReturn(rc, rc);
763 }
764 GMMR3FreePagesCleanup(pReq);
765
766 return rc;
767}
768
769#if HC_ARCH_BITS == 64 && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD))
770/**
771 * Rendezvous callback used by PGMR3ChangeMemBalloon that changes the memory balloon size
772 *
773 * This is only called on one of the EMTs while the other ones are waiting for
774 * it to complete this function.
775 *
776 * @returns VINF_SUCCESS (VBox strict status code).
777 * @param pVM The VM handle.
778 * @param pVCpu The VMCPU for the EMT we're being called on. Unused.
779 * @param pvUser User parameter
780 */
781static DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysChangeMemBalloonRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
782{
783 uintptr_t *paUser = (uintptr_t *)pvUser;
784 bool fInflate = !!paUser[0];
785 unsigned cPages = paUser[1];
786 RTGCPHYS *paPhysPage = (RTGCPHYS *)paUser[2];
787 uint32_t cPendingPages = 0;
788 PGMMFREEPAGESREQ pReq;
789 int rc;
790
791 Log(("pgmR3PhysChangeMemBalloonRendezvous: %s %x pages\n", (fInflate) ? "inflate" : "deflate", cPages));
792 pgmLock(pVM);
793
794 if (fInflate)
795 {
796 /* Flush the PGM pool cache as we might have stale references to pages that we just freed. */
797 pgmR3PoolClearAllRendezvous(pVM, pVCpu, NULL);
798
799 /* Replace pages with ZERO pages. */
800 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
801 if (RT_FAILURE(rc))
802 {
803 pgmUnlock(pVM);
804 AssertLogRelRC(rc);
805 return rc;
806 }
807
808 /* Iterate the pages. */
809 for (unsigned i = 0; i < cPages; i++)
810 {
811 PPGMPAGE pPage = pgmPhysGetPage(pVM, paPhysPage[i]);
812 if ( pPage == NULL
813 || pPage->uTypeY != PGMPAGETYPE_RAM)
814 {
815 Log(("pgmR3PhysChangeMemBalloonRendezvous: invalid physical page %RGp pPage->u3Type=%d\n", paPhysPage[i], (pPage) ? pPage->uTypeY : 0));
816 break;
817 }
818
819 LogFlow(("balloon page: %RGp\n", paPhysPage[i]));
820
821 /* Flush the shadow PT if this page was previously used as a guest page table. */
822 pgmPoolFlushPageByGCPhys(pVM, paPhysPage[i]);
823
824 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, paPhysPage[i]);
825 if (RT_FAILURE(rc))
826 {
827 pgmUnlock(pVM);
828 AssertLogRelRC(rc);
829 return rc;
830 }
831 Assert(PGM_PAGE_IS_ZERO(pPage));
832 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_BALLOONED);
833 }
834
835 if (cPendingPages)
836 {
837 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
838 if (RT_FAILURE(rc))
839 {
840 pgmUnlock(pVM);
841 AssertLogRelRC(rc);
842 return rc;
843 }
844 }
845 GMMR3FreePagesCleanup(pReq);
846 }
847 else
848 {
849 /* Iterate the pages. */
850 for (unsigned i = 0; i < cPages; i++)
851 {
852 PPGMPAGE pPage = pgmPhysGetPage(pVM, paPhysPage[i]);
853 AssertBreak(pPage && pPage->uTypeY == PGMPAGETYPE_RAM);
854
855 LogFlow(("Free ballooned page: %RGp\n", paPhysPage[i]));
856
857 Assert(PGM_PAGE_IS_BALLOONED(pPage));
858
859 /* Change back to zero page. */
860 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ZERO);
861 }
862
863 /* Note that we currently do not map any ballooned pages in our shadow page tables, so no need to flush the pgm pool. */
864 }
865
866 /* Notify GMM about the balloon change. */
867 rc = GMMR3BalloonedPages(pVM, (fInflate) ? GMMBALLOONACTION_INFLATE : GMMBALLOONACTION_DEFLATE, cPages);
868 if (RT_SUCCESS(rc))
869 {
870 if (!fInflate)
871 {
872 Assert(pVM->pgm.s.cBalloonedPages >= cPages);
873 pVM->pgm.s.cBalloonedPages -= cPages;
874 }
875 else
876 pVM->pgm.s.cBalloonedPages += cPages;
877 }
878
879 pgmUnlock(pVM);
880
881 /* Flush the recompiler's TLB as well. */
882 for (VMCPUID i = 0; i < pVM->cCpus; i++)
883 CPUMSetChangedFlags(&pVM->aCpus[i], CPUM_CHANGED_GLOBAL_TLB_FLUSH);
884
885 AssertLogRelRC(rc);
886 return rc;
887}
888
889/**
890 * Frees a range of ram pages, replacing them with ZERO pages; helper for PGMR3PhysFreeRamPages
891 *
892 * @returns VBox status code.
893 * @param pVM The VM handle.
894 * @param fInflate Inflate or deflate memory balloon
895 * @param cPages Number of pages to free
896 * @param paPhysPage Array of guest physical addresses
897 */
898static DECLCALLBACK(void) pgmR3PhysChangeMemBalloonHelper(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)
899{
900 uintptr_t paUser[3];
901
902 paUser[0] = fInflate;
903 paUser[1] = cPages;
904 paUser[2] = (uintptr_t)paPhysPage;
905 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysChangeMemBalloonRendezvous, (void *)paUser);
906 AssertRC(rc);
907
908 /* Made a copy in PGMR3PhysFreeRamPages; free it here. */
909 RTMemFree(paPhysPage);
910}
911#endif
912
913/**
914 * Inflate or deflate a memory balloon
915 *
916 * @returns VBox status code.
917 * @param pVM The VM handle.
918 * @param fInflate Inflate or deflate memory balloon
919 * @param cPages Number of pages to free
920 * @param paPhysPage Array of guest physical addresses
921 */
922VMMR3DECL(int) PGMR3PhysChangeMemBalloon(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)
923{
924 /* This must match GMMR0Init; currently we only support memory ballooning on all 64-bit hosts except Mac OS X */
925#if HC_ARCH_BITS == 64 && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD))
926 int rc;
927
928 /* Older additions (ancient non-functioning balloon code) pass wrong physical addresses. */
929 AssertReturn(!(paPhysPage[0] & 0xfff), VERR_INVALID_PARAMETER);
930
931 /* We own the IOM lock here and could cause a deadlock by waiting for another VCPU that is blocking on the IOM lock.
932 * In the SMP case we post a request packet to postpone the job.
933 */
934 if (pVM->cCpus > 1)
935 {
936 unsigned cbPhysPage = cPages * sizeof(paPhysPage[0]);
937 RTGCPHYS *paPhysPageCopy = (RTGCPHYS *)RTMemAlloc(cbPhysPage);
938 AssertReturn(paPhysPageCopy, VERR_NO_MEMORY);
939
940 memcpy(paPhysPageCopy, paPhysPage, cbPhysPage);
941
942 rc = VMR3ReqCallNoWait(pVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3PhysChangeMemBalloonHelper, 4, pVM, fInflate, cPages, paPhysPageCopy);
943 AssertRC(rc);
944 }
945 else
946 {
947 uintptr_t paUser[3];
948
949 paUser[0] = fInflate;
950 paUser[1] = cPages;
951 paUser[2] = (uintptr_t)paPhysPage;
952 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysChangeMemBalloonRendezvous, (void *)paUser);
953 AssertRC(rc);
954 }
955 return rc;
956#else
957 return VERR_NOT_IMPLEMENTED;
958#endif
959}
960
961/**
962 * Rendezvous callback used by PGMR3WriteProtectRAM that write protects all
963 * physical RAM.
964 *
965 * This is only called on one of the EMTs while the other ones are waiting for
966 * it to complete this function.
967 *
968 * @returns VINF_SUCCESS (VBox strict status code).
969 * @param pVM The VM handle.
970 * @param pVCpu The VMCPU for the EMT we're being called on. Unused.
971 * @param pvUser User parameter, unused.
972 */
973static DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysWriteProtectRAMRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
974{
975 int rc = VINF_SUCCESS;
976 NOREF(pvUser);
977
978 pgmLock(pVM);
979#ifdef PGMPOOL_WITH_OPTIMIZED_DIRTY_PT
980 pgmPoolResetDirtyPages(pVM);
981#endif
982
983 /** @todo pointless to write protect the physical page pointed to by RSP. */
984
985 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX);
986 pRam;
987 pRam = pRam->CTX_SUFF(pNext))
988 {
989 uint32_t cPages = pRam->cb >> PAGE_SHIFT;
990 for (uint32_t iPage = 0; iPage < cPages; iPage++)
991 {
992 PPGMPAGE pPage = &pRam->aPages[iPage];
993 PGMPAGETYPE enmPageType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
994
995 if ( RT_LIKELY(enmPageType == PGMPAGETYPE_RAM)
996 || enmPageType == PGMPAGETYPE_MMIO2)
997 {
998 /*
999 * A RAM page.
1000 */
1001 switch (PGM_PAGE_GET_STATE(pPage))
1002 {
1003 case PGM_PAGE_STATE_ALLOCATED:
1004 /** @todo Optimize this: Don't always re-enable write
1005 * monitoring if the page is known to be very busy. */
1006 if (PGM_PAGE_IS_WRITTEN_TO(pPage))
1007 {
1008 PGM_PAGE_CLEAR_WRITTEN_TO(pPage);
1009 /* Remember this dirty page for the next (memory) sync. */
1010 PGM_PAGE_SET_FT_DIRTY(pPage);
1011 }
1012
1013 pgmPhysPageWriteMonitor(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1014 break;
1015
1016 case PGM_PAGE_STATE_SHARED:
1017 AssertFailed();
1018 break;
1019
1020 case PGM_PAGE_STATE_WRITE_MONITORED: /* nothing to change. */
1021 default:
1022 break;
1023 }
1024 }
1025 }
1026 }
1027 pgmR3PoolWriteProtectPages(pVM);
1028 PGM_INVL_ALL_VCPU_TLBS(pVM);
1029 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1030 CPUMSetChangedFlags(&pVM->aCpus[idCpu], CPUM_CHANGED_GLOBAL_TLB_FLUSH);
1031
1032 pgmUnlock(pVM);
1033 return rc;
1034}
1035
1036/**
1037 * Protect all physical RAM to monitor writes
1038 *
1039 * @returns VBox status code.
1040 * @param pVM The VM handle.
1041 */
1042VMMR3DECL(int) PGMR3PhysWriteProtectRAM(PVM pVM)
1043{
1044 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1045
1046 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysWriteProtectRAMRendezvous, NULL);
1047 AssertRC(rc);
1048 return rc;
1049}
1050
1051/**
1052 * Enumerate all dirty FT pages.
1053 *
1054 * @returns VBox status code.
1055 * @param pVM The VM handle.
1056 * @param pfnEnum Enumerate callback handler.
1057 * @param pvUser Enumerate callback handler parameter.
1058 */
1059VMMR3DECL(int) PGMR3PhysEnumDirtyFTPages(PVM pVM, PFNPGMENUMDIRTYFTPAGES pfnEnum, void *pvUser)
1060{
1061 int rc = VINF_SUCCESS;
1062
1063 pgmLock(pVM);
1064 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX);
1065 pRam;
1066 pRam = pRam->CTX_SUFF(pNext))
1067 {
1068 uint32_t cPages = pRam->cb >> PAGE_SHIFT;
1069 for (uint32_t iPage = 0; iPage < cPages; iPage++)
1070 {
1071 PPGMPAGE pPage = &pRam->aPages[iPage];
1072 PGMPAGETYPE enmPageType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
1073
1074 if ( RT_LIKELY(enmPageType == PGMPAGETYPE_RAM)
1075 || enmPageType == PGMPAGETYPE_MMIO2)
1076 {
1077 /*
1078 * A RAM page.
1079 */
1080 switch (PGM_PAGE_GET_STATE(pPage))
1081 {
1082 case PGM_PAGE_STATE_ALLOCATED:
1083 case PGM_PAGE_STATE_WRITE_MONITORED:
1084 if ( !PGM_PAGE_IS_WRITTEN_TO(pPage) /* not very recently updated? */
1085 && PGM_PAGE_IS_FT_DIRTY(pPage))
1086 {
1087 unsigned cbPageRange = PAGE_SIZE;
1088 unsigned iPageClean = iPage + 1;
1089 RTGCPHYS GCPhysPage = pRam->GCPhys + iPage * PAGE_SIZE;
1090 uint8_t *pu8Page = NULL;
1091 PGMPAGEMAPLOCK Lock;
1092
1093 /* Find the next clean page, so we can merge adjacent dirty pages. */
1094 for (; iPageClean < cPages; iPageClean++)
1095 {
1096 PPGMPAGE pPageNext = &pRam->aPages[iPageClean];
1097 if ( RT_UNLIKELY(PGM_PAGE_GET_TYPE(pPageNext) != PGMPAGETYPE_RAM)
1098 || PGM_PAGE_GET_STATE(pPageNext) != PGM_PAGE_STATE_ALLOCATED
1099 || PGM_PAGE_IS_WRITTEN_TO(pPageNext)
1100 || !PGM_PAGE_IS_FT_DIRTY(pPageNext)
1101 /* Crossing a chunk boundary? */
1102 || (GCPhysPage & GMM_PAGEID_IDX_MASK) != ((GCPhysPage + cbPageRange) & GMM_PAGEID_IDX_MASK)
1103 )
1104 break;
1105
1106 cbPageRange += PAGE_SIZE;
1107 }
1108
1109 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhysPage, (const void **)&pu8Page, &Lock);
1110 if (RT_SUCCESS(rc))
1111 {
1112 /** @todo this is risky; the range might be changed, but little choice as the sync
1113 * costs a lot of time. */
1114 pgmUnlock(pVM);
1115 pfnEnum(pVM, GCPhysPage, pu8Page, cbPageRange, pvUser);
1116 pgmLock(pVM);
1117 PGMPhysReleasePageMappingLock(pVM, &Lock);
1118 }
1119
1120 for (iPage; iPage < iPageClean; iPage++)
1121 PGM_PAGE_CLEAR_FT_DIRTY(&pRam->aPages[iPage]);
1122
1123 iPage = iPageClean - 1;
1124 }
1125 break;
1126 }
1127 }
1128 }
1129 }
1130 pgmUnlock(pVM);
1131 return rc;
1132}
1133
1134
1135/**
1136 * Gets the number of ram ranges.
1137 *
1138 * @returns Number of ram ranges. Returns UINT32_MAX if @a pVM is invalid.
1139 * @param pVM The VM handle.
1140 */
1141VMMR3DECL(uint32_t) PGMR3PhysGetRamRangeCount(PVM pVM)
1142{
1143 VM_ASSERT_VALID_EXT_RETURN(pVM, UINT32_MAX);
1144
1145 pgmLock(pVM);
1146 uint32_t cRamRanges = 0;
1147 for (PPGMRAMRANGE pCur = pVM->pgm.s.CTX_SUFF(pRamRangesX); pCur; pCur = pCur->CTX_SUFF(pNext))
1148 cRamRanges++;
1149 pgmUnlock(pVM);
1150 return cRamRanges;
1151}
1152
1153
1154/**
1155 * Get information about a range.
1156 *
1157 * @returns VINF_SUCCESS or VERR_OUT_OF_RANGE.
1158 * @param pVM The VM handle
1159 * @param iRange The ordinal of the range.
1160 * @param pGCPhysStart Where to return the start of the range. Optional.
1161 * @param pGCPhysLast Where to return the address of the last byte in the
1162 * range. Optional.
1163 * @param pfIsMmio Where to indicate that this is a pure MMIO range.
1164 * Optional.
1165 */
1166VMMR3DECL(int) PGMR3PhysGetRange(PVM pVM, uint32_t iRange, PRTGCPHYS pGCPhysStart, PRTGCPHYS pGCPhysLast,
1167 const char **ppszDesc, bool *pfIsMmio)
1168{
1169 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1170
1171 pgmLock(pVM);
1172 uint32_t iCurRange = 0;
1173 for (PPGMRAMRANGE pCur = pVM->pgm.s.CTX_SUFF(pRamRangesX); pCur; pCur = pCur->CTX_SUFF(pNext), iCurRange++)
1174 if (iCurRange == iRange)
1175 {
1176 if (pGCPhysStart)
1177 *pGCPhysStart = pCur->GCPhys;
1178 if (pGCPhysLast)
1179 *pGCPhysLast = pCur->GCPhysLast;
1180 if (pfIsMmio)
1181 *pfIsMmio = !!(pCur->fFlags & PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO);
1182
1183 pgmUnlock(pVM);
1184 return VINF_SUCCESS;
1185 }
1186 pgmUnlock(pVM);
1187 return VERR_OUT_OF_RANGE;
1188}
1189
1190
1191/**
1192 * Query the amount of free memory inside VMMR0
1193 *
1194 * @returns VBox status code.
1195 * @param pVM The VM handle.
1196 * @param pcbAllocMem Where to return the amount of memory allocated
1197 * by VMs.
1198 * @param pcbFreeMem Where to return the amount of memory that is
1199 * allocated from the host but not currently used
1200 * by any VMs.
1201 * @param pcbBallonedMem Where to return the sum of memory that is
1202 * currently ballooned by the VMs.
1203 * @param pcbSharedMem Where to return the amount of memory that is
1204 * currently shared.
1205 */
1206VMMR3DECL(int) PGMR3QueryGlobalMemoryStats(PVM pVM, uint64_t *pcbAllocMem, uint64_t *pcbFreeMem,
1207 uint64_t *pcbBallonedMem, uint64_t *pcbSharedMem)
1208{
1209 uint64_t cAllocPages = 0;
1210 uint64_t cFreePages = 0;
1211 uint64_t cBalloonPages = 0;
1212 uint64_t cSharedPages = 0;
1213 int rc = GMMR3QueryHypervisorMemoryStats(pVM, &cAllocPages, &cFreePages, &cBalloonPages, &cSharedPages);
1214 AssertRCReturn(rc, rc);
1215
1216 if (pcbAllocMem)
1217 *pcbAllocMem = cAllocPages * _4K;
1218
1219 if (pcbFreeMem)
1220 *pcbFreeMem = cFreePages * _4K;
1221
1222 if (pcbBallonedMem)
1223 *pcbBallonedMem = cBalloonPages * _4K;
1224
1225 if (pcbSharedMem)
1226 *pcbSharedMem = cSharedPages * _4K;
1227
1228 Log(("PGMR3QueryVMMMemoryStats: all=%llx free=%llx ballooned=%llx shared=%llx\n",
1229 cAllocPages, cFreePages, cBalloonPages, cSharedPages));
1230 return VINF_SUCCESS;
1231}
1232
1233
1234/**
1235 * Query memory stats for the VM.
1236 *
1237 * @returns VBox status code.
1238 * @param pVM The VM handle.
1239 * @param pcbTotalMem Where to return total amount memory the VM may
1240 * possibly use.
1241 * @param pcbPrivateMem Where to return the amount of private memory
1242 * currently allocated.
1243 * @param pcbSharedMem Where to return the amount of actually shared
1244 * memory currently used by the VM.
1245 * @param pcbZeroMem Where to return the amount of memory backed by
1246 * zero pages.
1247 *
1248 * @remarks The total mem is normally larger than the sum of the three
1249 * components. There are two reasons for this, first the amount of
1250 * shared memory is what we're sure is shared instead of what could
1251 * possibly be shared with someone. Secondly, because the total may
1252 * include some pure MMIO pages that doesn't go into any of the three
1253 * sub-counts.
1254 *
1255 * @todo Why do we return reused shared pages instead of anything that could
1256 * potentially be shared? Doesn't this mean the first VM gets a much
1257 * lower number of shared pages?
1258 */
1259VMMR3DECL(int) PGMR3QueryMemoryStats(PVM pVM, uint64_t *pcbTotalMem, uint64_t *pcbPrivateMem,
1260 uint64_t *pcbSharedMem, uint64_t *pcbZeroMem)
1261{
1262 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1263
1264 if (pcbTotalMem)
1265 *pcbTotalMem = (uint64_t)pVM->pgm.s.cAllPages * PAGE_SIZE;
1266
1267 if (pcbPrivateMem)
1268 *pcbPrivateMem = (uint64_t)pVM->pgm.s.cPrivatePages * PAGE_SIZE;
1269
1270 if (pcbSharedMem)
1271 *pcbSharedMem = (uint64_t)pVM->pgm.s.cReusedSharedPages * PAGE_SIZE;
1272
1273 if (pcbZeroMem)
1274 *pcbZeroMem = (uint64_t)pVM->pgm.s.cZeroPages * PAGE_SIZE;
1275
1276 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));
1277 return VINF_SUCCESS;
1278}
1279
1280
1281/**
1282 * PGMR3PhysRegisterRam worker that initializes and links a RAM range.
1283 *
1284 * @param pVM The VM handle.
1285 * @param pNew The new RAM range.
1286 * @param GCPhys The address of the RAM range.
1287 * @param GCPhysLast The last address of the RAM range.
1288 * @param RCPtrNew The RC address if the range is floating. NIL_RTRCPTR
1289 * if in HMA.
1290 * @param R0PtrNew Ditto for R0.
1291 * @param pszDesc The description.
1292 * @param pPrev The previous RAM range (for linking).
1293 */
1294static void pgmR3PhysInitAndLinkRamRange(PVM pVM, PPGMRAMRANGE pNew, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
1295 RTRCPTR RCPtrNew, RTR0PTR R0PtrNew, const char *pszDesc, PPGMRAMRANGE pPrev)
1296{
1297 /*
1298 * Initialize the range.
1299 */
1300 pNew->pSelfR0 = R0PtrNew != NIL_RTR0PTR ? R0PtrNew : MMHyperCCToR0(pVM, pNew);
1301 pNew->pSelfRC = RCPtrNew != NIL_RTRCPTR ? RCPtrNew : MMHyperCCToRC(pVM, pNew);
1302 pNew->GCPhys = GCPhys;
1303 pNew->GCPhysLast = GCPhysLast;
1304 pNew->cb = GCPhysLast - GCPhys + 1;
1305 pNew->pszDesc = pszDesc;
1306 pNew->fFlags = RCPtrNew != NIL_RTRCPTR ? PGM_RAM_RANGE_FLAGS_FLOATING : 0;
1307 pNew->pvR3 = NULL;
1308 pNew->paLSPages = NULL;
1309
1310 uint32_t const cPages = pNew->cb >> PAGE_SHIFT;
1311 RTGCPHYS iPage = cPages;
1312 while (iPage-- > 0)
1313 PGM_PAGE_INIT_ZERO(&pNew->aPages[iPage], pVM, PGMPAGETYPE_RAM);
1314
1315 /* Update the page count stats. */
1316 pVM->pgm.s.cZeroPages += cPages;
1317 pVM->pgm.s.cAllPages += cPages;
1318
1319 /*
1320 * Link it.
1321 */
1322 pgmR3PhysLinkRamRange(pVM, pNew, pPrev);
1323}
1324
1325
1326/**
1327 * Relocate a floating RAM range.
1328 *
1329 * @copydoc FNPGMRELOCATE.
1330 */
1331static DECLCALLBACK(bool) pgmR3PhysRamRangeRelocate(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser)
1332{
1333 PPGMRAMRANGE pRam = (PPGMRAMRANGE)pvUser;
1334 Assert(pRam->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING);
1335 Assert(pRam->pSelfRC == GCPtrOld + PAGE_SIZE);
1336
1337 switch (enmMode)
1338 {
1339 case PGMRELOCATECALL_SUGGEST:
1340 return true;
1341
1342 case PGMRELOCATECALL_RELOCATE:
1343 {
1344 /*
1345 * Update myself, then relink all the ranges and flush the RC TLB.
1346 */
1347 pgmLock(pVM);
1348
1349 pRam->pSelfRC = (RTRCPTR)(GCPtrNew + PAGE_SIZE);
1350
1351 pgmR3PhysRelinkRamRanges(pVM);
1352#ifdef PGM_USE_RAMRANGE_TLB
1353 for (unsigned i = 0; i < PGM_RAMRANGE_TLB_ENTRIES; i++)
1354 pVM->pgm.s.apRamRangesTlbRC[i] = NIL_RTRCPTR;
1355#endif
1356
1357 pgmUnlock(pVM);
1358 return true;
1359 }
1360
1361 default:
1362 AssertFailedReturn(false);
1363 }
1364}
1365
1366
1367/**
1368 * PGMR3PhysRegisterRam worker that registers a high chunk.
1369 *
1370 * @returns VBox status code.
1371 * @param pVM The VM handle.
1372 * @param GCPhys The address of the RAM.
1373 * @param cRamPages The number of RAM pages to register.
1374 * @param cbChunk The size of the PGMRAMRANGE guest mapping.
1375 * @param iChunk The chunk number.
1376 * @param pszDesc The RAM range description.
1377 * @param ppPrev Previous RAM range pointer. In/Out.
1378 */
1379static int pgmR3PhysRegisterHighRamChunk(PVM pVM, RTGCPHYS GCPhys, uint32_t cRamPages,
1380 uint32_t cbChunk, uint32_t iChunk, const char *pszDesc,
1381 PPGMRAMRANGE *ppPrev)
1382{
1383 const char *pszDescChunk = iChunk == 0
1384 ? pszDesc
1385 : MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS, "%s (#%u)", pszDesc, iChunk + 1);
1386 AssertReturn(pszDescChunk, VERR_NO_MEMORY);
1387
1388 /*
1389 * Allocate memory for the new chunk.
1390 */
1391 size_t const cChunkPages = RT_ALIGN_Z(RT_UOFFSETOF(PGMRAMRANGE, aPages[cRamPages]), PAGE_SIZE) >> PAGE_SHIFT;
1392 PSUPPAGE paChunkPages = (PSUPPAGE)RTMemTmpAllocZ(sizeof(SUPPAGE) * cChunkPages);
1393 AssertReturn(paChunkPages, VERR_NO_TMP_MEMORY);
1394 RTR0PTR R0PtrChunk = NIL_RTR0PTR;
1395 void *pvChunk = NULL;
1396 int rc = SUPR3PageAllocEx(cChunkPages, 0 /*fFlags*/, &pvChunk,
1397#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
1398 VMMIsHwVirtExtForced(pVM) ? &R0PtrChunk : NULL,
1399#else
1400 NULL,
1401#endif
1402 paChunkPages);
1403 if (RT_SUCCESS(rc))
1404 {
1405#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
1406 if (!VMMIsHwVirtExtForced(pVM))
1407 R0PtrChunk = NIL_RTR0PTR;
1408#else
1409 R0PtrChunk = (uintptr_t)pvChunk;
1410#endif
1411 memset(pvChunk, 0, cChunkPages << PAGE_SHIFT);
1412
1413 PPGMRAMRANGE pNew = (PPGMRAMRANGE)pvChunk;
1414
1415 /*
1416 * Create a mapping and map the pages into it.
1417 * We push these in below the HMA.
1418 */
1419 RTGCPTR GCPtrChunkMap = pVM->pgm.s.GCPtrPrevRamRangeMapping - cbChunk;
1420 rc = PGMR3MapPT(pVM, GCPtrChunkMap, cbChunk, 0 /*fFlags*/, pgmR3PhysRamRangeRelocate, pNew, pszDescChunk);
1421 if (RT_SUCCESS(rc))
1422 {
1423 pVM->pgm.s.GCPtrPrevRamRangeMapping = GCPtrChunkMap;
1424
1425 RTGCPTR const GCPtrChunk = GCPtrChunkMap + PAGE_SIZE;
1426 RTGCPTR GCPtrPage = GCPtrChunk;
1427 for (uint32_t iPage = 0; iPage < cChunkPages && RT_SUCCESS(rc); iPage++, GCPtrPage += PAGE_SIZE)
1428 rc = PGMMap(pVM, GCPtrPage, paChunkPages[iPage].Phys, PAGE_SIZE, 0);
1429 if (RT_SUCCESS(rc))
1430 {
1431 /*
1432 * Ok, init and link the range.
1433 */
1434 pgmR3PhysInitAndLinkRamRange(pVM, pNew, GCPhys, GCPhys + ((RTGCPHYS)cRamPages << PAGE_SHIFT) - 1,
1435 (RTRCPTR)GCPtrChunk, R0PtrChunk, pszDescChunk, *ppPrev);
1436 *ppPrev = pNew;
1437 }
1438 }
1439
1440 if (RT_FAILURE(rc))
1441 SUPR3PageFreeEx(pvChunk, cChunkPages);
1442 }
1443
1444 RTMemTmpFree(paChunkPages);
1445 return rc;
1446}
1447
1448
1449/**
1450 * Sets up a range RAM.
1451 *
1452 * This will check for conflicting registrations, make a resource
1453 * reservation for the memory (with GMM), and setup the per-page
1454 * tracking structures (PGMPAGE).
1455 *
1456 * @returns VBox status code.
1457 * @param pVM Pointer to the shared VM structure.
1458 * @param GCPhys The physical address of the RAM.
1459 * @param cb The size of the RAM.
1460 * @param pszDesc The description - not copied, so, don't free or change it.
1461 */
1462VMMR3DECL(int) PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, const char *pszDesc)
1463{
1464 /*
1465 * Validate input.
1466 */
1467 Log(("PGMR3PhysRegisterRam: GCPhys=%RGp cb=%RGp pszDesc=%s\n", GCPhys, cb, pszDesc));
1468 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
1469 AssertReturn(RT_ALIGN_T(cb, PAGE_SIZE, RTGCPHYS) == cb, VERR_INVALID_PARAMETER);
1470 AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
1471 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
1472 AssertMsgReturn(GCPhysLast > GCPhys, ("The range wraps! GCPhys=%RGp cb=%RGp\n", GCPhys, cb), VERR_INVALID_PARAMETER);
1473 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
1474 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1475
1476 pgmLock(pVM);
1477
1478 /*
1479 * Find range location and check for conflicts.
1480 * (We don't lock here because the locking by EMT is only required on update.)
1481 */
1482 PPGMRAMRANGE pPrev = NULL;
1483 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
1484 while (pRam && GCPhysLast >= pRam->GCPhys)
1485 {
1486 if ( GCPhysLast >= pRam->GCPhys
1487 && GCPhys <= pRam->GCPhysLast)
1488 AssertLogRelMsgFailedReturn(("%RGp-%RGp (%s) conflicts with existing %RGp-%RGp (%s)\n",
1489 GCPhys, GCPhysLast, pszDesc,
1490 pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
1491 VERR_PGM_RAM_CONFLICT);
1492
1493 /* next */
1494 pPrev = pRam;
1495 pRam = pRam->pNextR3;
1496 }
1497
1498 /*
1499 * Register it with GMM (the API bitches).
1500 */
1501 const RTGCPHYS cPages = cb >> PAGE_SHIFT;
1502 int rc = MMR3IncreaseBaseReservation(pVM, cPages);
1503 if (RT_FAILURE(rc))
1504 {
1505 pgmUnlock(pVM);
1506 return rc;
1507 }
1508
1509 if ( GCPhys >= _4G
1510 && cPages > 256)
1511 {
1512 /*
1513 * The PGMRAMRANGE structures for the high memory can get very big.
1514 * In order to avoid SUPR3PageAllocEx allocation failures due to the
1515 * allocation size limit there and also to avoid being unable to find
1516 * guest mapping space for them, we split this memory up into 4MB in
1517 * (potential) raw-mode configs and 16MB chunks in forced AMD-V/VT-x
1518 * mode.
1519 *
1520 * The first and last page of each mapping are guard pages and marked
1521 * not-present. So, we've got 4186112 and 16769024 bytes available for
1522 * the PGMRAMRANGE structure.
1523 *
1524 * Note! The sizes used here will influence the saved state.
1525 */
1526 uint32_t cbChunk;
1527 uint32_t cPagesPerChunk;
1528 if (VMMIsHwVirtExtForced(pVM))
1529 {
1530 cbChunk = 16U*_1M;
1531 cPagesPerChunk = 1048048; /* max ~1048059 */
1532 AssertCompile(sizeof(PGMRAMRANGE) + sizeof(PGMPAGE) * 1048048 < 16U*_1M - PAGE_SIZE * 2);
1533 }
1534 else
1535 {
1536 cbChunk = 4U*_1M;
1537 cPagesPerChunk = 261616; /* max ~261627 */
1538 AssertCompile(sizeof(PGMRAMRANGE) + sizeof(PGMPAGE) * 261616 < 4U*_1M - PAGE_SIZE * 2);
1539 }
1540 AssertRelease(RT_UOFFSETOF(PGMRAMRANGE, aPages[cPagesPerChunk]) + PAGE_SIZE * 2 <= cbChunk);
1541
1542 RTGCPHYS cPagesLeft = cPages;
1543 RTGCPHYS GCPhysChunk = GCPhys;
1544 uint32_t iChunk = 0;
1545 while (cPagesLeft > 0)
1546 {
1547 uint32_t cPagesInChunk = cPagesLeft;
1548 if (cPagesInChunk > cPagesPerChunk)
1549 cPagesInChunk = cPagesPerChunk;
1550
1551 rc = pgmR3PhysRegisterHighRamChunk(pVM, GCPhysChunk, cPagesInChunk, cbChunk, iChunk, pszDesc, &pPrev);
1552 AssertRCReturn(rc, rc);
1553
1554 /* advance */
1555 GCPhysChunk += (RTGCPHYS)cPagesInChunk << PAGE_SHIFT;
1556 cPagesLeft -= cPagesInChunk;
1557 iChunk++;
1558 }
1559 }
1560 else
1561 {
1562 /*
1563 * Allocate, initialize and link the new RAM range.
1564 */
1565 const size_t cbRamRange = RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]);
1566 PPGMRAMRANGE pNew;
1567 rc = MMR3HyperAllocOnceNoRel(pVM, cbRamRange, 0, MM_TAG_PGM_PHYS, (void **)&pNew);
1568 AssertLogRelMsgRCReturn(rc, ("cbRamRange=%zu\n", cbRamRange), rc);
1569
1570 pgmR3PhysInitAndLinkRamRange(pVM, pNew, GCPhys, GCPhysLast, NIL_RTRCPTR, NIL_RTR0PTR, pszDesc, pPrev);
1571 }
1572 PGMPhysInvalidatePageMapTLB(pVM);
1573 pgmUnlock(pVM);
1574
1575 /*
1576 * Notify REM.
1577 */
1578 REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_RAM);
1579
1580 return VINF_SUCCESS;
1581}
1582
1583
1584/**
1585 * Worker called by PGMR3InitFinalize if we're configured to pre-allocate RAM.
1586 *
1587 * We do this late in the init process so that all the ROM and MMIO ranges have
1588 * been registered already and we don't go wasting memory on them.
1589 *
1590 * @returns VBox status code.
1591 *
1592 * @param pVM Pointer to the shared VM structure.
1593 */
1594int pgmR3PhysRamPreAllocate(PVM pVM)
1595{
1596 Assert(pVM->pgm.s.fRamPreAlloc);
1597 Log(("pgmR3PhysRamPreAllocate: enter\n"));
1598
1599 /*
1600 * Walk the RAM ranges and allocate all RAM pages, halt at
1601 * the first allocation error.
1602 */
1603 uint64_t cPages = 0;
1604 uint64_t NanoTS = RTTimeNanoTS();
1605 pgmLock(pVM);
1606 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3; pRam; pRam = pRam->pNextR3)
1607 {
1608 PPGMPAGE pPage = &pRam->aPages[0];
1609 RTGCPHYS GCPhys = pRam->GCPhys;
1610 uint32_t cLeft = pRam->cb >> PAGE_SHIFT;
1611 while (cLeft-- > 0)
1612 {
1613 if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM)
1614 {
1615 switch (PGM_PAGE_GET_STATE(pPage))
1616 {
1617 case PGM_PAGE_STATE_ZERO:
1618 {
1619 int rc = pgmPhysAllocPage(pVM, pPage, GCPhys);
1620 if (RT_FAILURE(rc))
1621 {
1622 LogRel(("PGM: RAM Pre-allocation failed at %RGp (in %s) with rc=%Rrc\n", GCPhys, pRam->pszDesc, rc));
1623 pgmUnlock(pVM);
1624 return rc;
1625 }
1626 cPages++;
1627 break;
1628 }
1629
1630 case PGM_PAGE_STATE_BALLOONED:
1631 case PGM_PAGE_STATE_ALLOCATED:
1632 case PGM_PAGE_STATE_WRITE_MONITORED:
1633 case PGM_PAGE_STATE_SHARED:
1634 /* nothing to do here. */
1635 break;
1636 }
1637 }
1638
1639 /* next */
1640 pPage++;
1641 GCPhys += PAGE_SIZE;
1642 }
1643 }
1644 pgmUnlock(pVM);
1645 NanoTS = RTTimeNanoTS() - NanoTS;
1646
1647 LogRel(("PGM: Pre-allocated %llu pages in %llu ms\n", cPages, NanoTS / 1000000));
1648 Log(("pgmR3PhysRamPreAllocate: returns VINF_SUCCESS\n"));
1649 return VINF_SUCCESS;
1650}
1651
1652
1653/**
1654 * Resets (zeros) the RAM.
1655 *
1656 * ASSUMES that the caller owns the PGM lock.
1657 *
1658 * @returns VBox status code.
1659 * @param pVM Pointer to the shared VM structure.
1660 */
1661int pgmR3PhysRamReset(PVM pVM)
1662{
1663 Assert(PGMIsLockOwner(pVM));
1664
1665 /* Reset the memory balloon. */
1666 int rc = GMMR3BalloonedPages(pVM, GMMBALLOONACTION_RESET, 0);
1667 AssertRC(rc);
1668
1669#ifdef VBOX_WITH_PAGE_SHARING
1670 /* Clear all registered shared modules. */
1671 rc = GMMR3ResetSharedModules(pVM);
1672 AssertRC(rc);
1673#endif
1674 /* Reset counters. */
1675 pVM->pgm.s.cReusedSharedPages = 0;
1676 pVM->pgm.s.cBalloonedPages = 0;
1677
1678 /*
1679 * We batch up pages that should be freed instead of calling GMM for
1680 * each and every one of them.
1681 */
1682 uint32_t cPendingPages = 0;
1683 PGMMFREEPAGESREQ pReq;
1684 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
1685 AssertLogRelRCReturn(rc, rc);
1686
1687 /*
1688 * Walk the ram ranges.
1689 */
1690 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3; pRam; pRam = pRam->pNextR3)
1691 {
1692 uint32_t iPage = pRam->cb >> PAGE_SHIFT;
1693 AssertMsg(((RTGCPHYS)iPage << PAGE_SHIFT) == pRam->cb, ("%RGp %RGp\n", (RTGCPHYS)iPage << PAGE_SHIFT, pRam->cb));
1694
1695 if (!pVM->pgm.s.fRamPreAlloc)
1696 {
1697 /* Replace all RAM pages by ZERO pages. */
1698 while (iPage-- > 0)
1699 {
1700 PPGMPAGE pPage = &pRam->aPages[iPage];
1701 switch (PGM_PAGE_GET_TYPE(pPage))
1702 {
1703 case PGMPAGETYPE_RAM:
1704 /* Do not replace pages part of a 2 MB continuous range
1705 with zero pages, but zero them instead. */
1706 if ( PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE
1707 || PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE_DISABLED)
1708 {
1709 void *pvPage;
1710 rc = pgmPhysPageMap(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), &pvPage);
1711 AssertLogRelRCReturn(rc, rc);
1712 ASMMemZeroPage(pvPage);
1713 }
1714 else if (PGM_PAGE_IS_BALLOONED(pPage))
1715 {
1716 /* Turn into a zero page; the balloon status is lost when the VM reboots. */
1717 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ZERO);
1718 }
1719 else if (!PGM_PAGE_IS_ZERO(pPage))
1720 {
1721 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1722 AssertLogRelRCReturn(rc, rc);
1723 }
1724 break;
1725
1726 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
1727 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT),
1728 true /*fDoAccounting*/);
1729 break;
1730
1731 case PGMPAGETYPE_MMIO2:
1732 case PGMPAGETYPE_ROM_SHADOW: /* handled by pgmR3PhysRomReset. */
1733 case PGMPAGETYPE_ROM:
1734 case PGMPAGETYPE_MMIO:
1735 break;
1736 default:
1737 AssertFailed();
1738 }
1739 } /* for each page */
1740 }
1741 else
1742 {
1743 /* Zero the memory. */
1744 while (iPage-- > 0)
1745 {
1746 PPGMPAGE pPage = &pRam->aPages[iPage];
1747 switch (PGM_PAGE_GET_TYPE(pPage))
1748 {
1749 case PGMPAGETYPE_RAM:
1750 switch (PGM_PAGE_GET_STATE(pPage))
1751 {
1752 case PGM_PAGE_STATE_ZERO:
1753 break;
1754
1755 case PGM_PAGE_STATE_BALLOONED:
1756 /* Turn into a zero page; the balloon status is lost when the VM reboots. */
1757 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ZERO);
1758 break;
1759
1760 case PGM_PAGE_STATE_SHARED:
1761 case PGM_PAGE_STATE_WRITE_MONITORED:
1762 rc = pgmPhysPageMakeWritable(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1763 AssertLogRelRCReturn(rc, rc);
1764 /* no break */
1765
1766 case PGM_PAGE_STATE_ALLOCATED:
1767 {
1768 void *pvPage;
1769 rc = pgmPhysPageMap(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), &pvPage);
1770 AssertLogRelRCReturn(rc, rc);
1771 ASMMemZeroPage(pvPage);
1772 break;
1773 }
1774 }
1775 break;
1776
1777 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
1778 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT),
1779 true /*fDoAccounting*/);
1780 break;
1781
1782 case PGMPAGETYPE_MMIO2:
1783 case PGMPAGETYPE_ROM_SHADOW:
1784 case PGMPAGETYPE_ROM:
1785 case PGMPAGETYPE_MMIO:
1786 break;
1787 default:
1788 AssertFailed();
1789
1790 }
1791 } /* for each page */
1792 }
1793
1794 }
1795
1796 /*
1797 * Finish off any pages pending freeing.
1798 */
1799 if (cPendingPages)
1800 {
1801 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
1802 AssertLogRelRCReturn(rc, rc);
1803 }
1804 GMMR3FreePagesCleanup(pReq);
1805
1806 return VINF_SUCCESS;
1807}
1808
1809/**
1810 * Frees all RAM during VM termination
1811 *
1812 * ASSUMES that the caller owns the PGM lock.
1813 *
1814 * @returns VBox status code.
1815 * @param pVM Pointer to the shared VM structure.
1816 */
1817int pgmR3PhysRamTerm(PVM pVM)
1818{
1819 Assert(PGMIsLockOwner(pVM));
1820
1821 /* Reset the memory balloon. */
1822 int rc = GMMR3BalloonedPages(pVM, GMMBALLOONACTION_RESET, 0);
1823 AssertRC(rc);
1824
1825#ifdef VBOX_WITH_PAGE_SHARING
1826 /* Clear all registered shared modules. */
1827 rc = GMMR3ResetSharedModules(pVM);
1828 AssertRC(rc);
1829#endif
1830
1831 /*
1832 * We batch up pages that should be freed instead of calling GMM for
1833 * each and every one of them.
1834 */
1835 uint32_t cPendingPages = 0;
1836 PGMMFREEPAGESREQ pReq;
1837 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
1838 AssertLogRelRCReturn(rc, rc);
1839
1840 /*
1841 * Walk the ram ranges.
1842 */
1843 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3; pRam; pRam = pRam->pNextR3)
1844 {
1845 uint32_t iPage = pRam->cb >> PAGE_SHIFT;
1846 AssertMsg(((RTGCPHYS)iPage << PAGE_SHIFT) == pRam->cb, ("%RGp %RGp\n", (RTGCPHYS)iPage << PAGE_SHIFT, pRam->cb));
1847
1848 /* Replace all RAM pages by ZERO pages. */
1849 while (iPage-- > 0)
1850 {
1851 PPGMPAGE pPage = &pRam->aPages[iPage];
1852 switch (PGM_PAGE_GET_TYPE(pPage))
1853 {
1854 case PGMPAGETYPE_RAM:
1855 /* Free all shared pages. Private pages are automatically freed during GMM VM cleanup. */
1856 if (PGM_PAGE_IS_SHARED(pPage))
1857 {
1858 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1859 AssertLogRelRCReturn(rc, rc);
1860 }
1861 break;
1862
1863 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
1864 case PGMPAGETYPE_MMIO2:
1865 case PGMPAGETYPE_ROM_SHADOW: /* handled by pgmR3PhysRomReset. */
1866 case PGMPAGETYPE_ROM:
1867 case PGMPAGETYPE_MMIO:
1868 break;
1869 default:
1870 AssertFailed();
1871 }
1872 } /* for each page */
1873 }
1874
1875 /*
1876 * Finish off any pages pending freeing.
1877 */
1878 if (cPendingPages)
1879 {
1880 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
1881 AssertLogRelRCReturn(rc, rc);
1882 }
1883 GMMR3FreePagesCleanup(pReq);
1884 return VINF_SUCCESS;
1885}
1886
1887/**
1888 * This is the interface IOM is using to register an MMIO region.
1889 *
1890 * It will check for conflicts and ensure that a RAM range structure
1891 * is present before calling the PGMR3HandlerPhysicalRegister API to
1892 * register the callbacks.
1893 *
1894 * @returns VBox status code.
1895 *
1896 * @param pVM Pointer to the shared VM structure.
1897 * @param GCPhys The start of the MMIO region.
1898 * @param cb The size of the MMIO region.
1899 * @param pfnHandlerR3 The address of the ring-3 handler. (IOMR3MMIOHandler)
1900 * @param pvUserR3 The user argument for R3.
1901 * @param pfnHandlerR0 The address of the ring-0 handler. (IOMMMIOHandler)
1902 * @param pvUserR0 The user argument for R0.
1903 * @param pfnHandlerRC The address of the RC handler. (IOMMMIOHandler)
1904 * @param pvUserRC The user argument for RC.
1905 * @param pszDesc The description of the MMIO region.
1906 */
1907VMMR3DECL(int) PGMR3PhysMMIORegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb,
1908 R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3,
1909 R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0,
1910 RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC, RTRCPTR pvUserRC,
1911 R3PTRTYPE(const char *) pszDesc)
1912{
1913 /*
1914 * Assert on some assumption.
1915 */
1916 VM_ASSERT_EMT(pVM);
1917 AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
1918 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
1919 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
1920 AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
1921
1922 /*
1923 * Make sure there's a RAM range structure for the region.
1924 */
1925 int rc;
1926 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
1927 bool fRamExists = false;
1928 PPGMRAMRANGE pRamPrev = NULL;
1929 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
1930 while (pRam && GCPhysLast >= pRam->GCPhys)
1931 {
1932 if ( GCPhysLast >= pRam->GCPhys
1933 && GCPhys <= pRam->GCPhysLast)
1934 {
1935 /* Simplification: all within the same range. */
1936 AssertLogRelMsgReturn( GCPhys >= pRam->GCPhys
1937 && GCPhysLast <= pRam->GCPhysLast,
1938 ("%RGp-%RGp (MMIO/%s) falls partly outside %RGp-%RGp (%s)\n",
1939 GCPhys, GCPhysLast, pszDesc,
1940 pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
1941 VERR_PGM_RAM_CONFLICT);
1942
1943 /* Check that it's all RAM or MMIO pages. */
1944 PCPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
1945 uint32_t cLeft = cb >> PAGE_SHIFT;
1946 while (cLeft-- > 0)
1947 {
1948 AssertLogRelMsgReturn( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
1949 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO,
1950 ("%RGp-%RGp (MMIO/%s): %RGp is not a RAM or MMIO page - type=%d desc=%s\n",
1951 GCPhys, GCPhysLast, pszDesc, PGM_PAGE_GET_TYPE(pPage), pRam->pszDesc),
1952 VERR_PGM_RAM_CONFLICT);
1953 pPage++;
1954 }
1955
1956 /* Looks good. */
1957 fRamExists = true;
1958 break;
1959 }
1960
1961 /* next */
1962 pRamPrev = pRam;
1963 pRam = pRam->pNextR3;
1964 }
1965 PPGMRAMRANGE pNew;
1966 if (fRamExists)
1967 {
1968 pNew = NULL;
1969
1970 /*
1971 * Make all the pages in the range MMIO/ZERO pages, freeing any
1972 * RAM pages currently mapped here. This might not be 100% correct
1973 * for PCI memory, but we're doing the same thing for MMIO2 pages.
1974 */
1975 rc = pgmLock(pVM);
1976 if (RT_SUCCESS(rc))
1977 {
1978 rc = pgmR3PhysFreePageRange(pVM, pRam, GCPhys, GCPhysLast, PGMPAGETYPE_MMIO);
1979 pgmUnlock(pVM);
1980 }
1981 AssertRCReturn(rc, rc);
1982
1983 /* Force a PGM pool flush as guest ram references have been changed. */
1984 /** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
1985 PVMCPU pVCpu = VMMGetCpu(pVM);
1986 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
1987 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
1988 }
1989 else
1990 {
1991 pgmLock(pVM);
1992
1993 /*
1994 * No RAM range, insert an ad hoc one.
1995 *
1996 * Note that we don't have to tell REM about this range because
1997 * PGMHandlerPhysicalRegisterEx will do that for us.
1998 */
1999 Log(("PGMR3PhysMMIORegister: Adding ad hoc MMIO range for %RGp-%RGp %s\n", GCPhys, GCPhysLast, pszDesc));
2000
2001 const uint32_t cPages = cb >> PAGE_SHIFT;
2002 const size_t cbRamRange = RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]);
2003 rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]), 16, MM_TAG_PGM_PHYS, (void **)&pNew);
2004 AssertLogRelMsgRCReturn(rc, ("cbRamRange=%zu\n", cbRamRange), rc);
2005
2006 /* Initialize the range. */
2007 pNew->pSelfR0 = MMHyperCCToR0(pVM, pNew);
2008 pNew->pSelfRC = MMHyperCCToRC(pVM, pNew);
2009 pNew->GCPhys = GCPhys;
2010 pNew->GCPhysLast = GCPhysLast;
2011 pNew->cb = cb;
2012 pNew->pszDesc = pszDesc;
2013 pNew->fFlags = PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO;
2014 pNew->pvR3 = NULL;
2015 pNew->paLSPages = NULL;
2016
2017 uint32_t iPage = cPages;
2018 while (iPage-- > 0)
2019 PGM_PAGE_INIT_ZERO(&pNew->aPages[iPage], pVM, PGMPAGETYPE_MMIO);
2020 Assert(PGM_PAGE_GET_TYPE(&pNew->aPages[0]) == PGMPAGETYPE_MMIO);
2021
2022 /* update the page count stats. */
2023 pVM->pgm.s.cPureMmioPages += cPages;
2024 pVM->pgm.s.cAllPages += cPages;
2025
2026 /* link it */
2027 pgmR3PhysLinkRamRange(pVM, pNew, pRamPrev);
2028
2029 pgmUnlock(pVM);
2030 }
2031
2032 /*
2033 * Register the access handler.
2034 */
2035 rc = PGMHandlerPhysicalRegisterEx(pVM, PGMPHYSHANDLERTYPE_MMIO, GCPhys, GCPhysLast,
2036 pfnHandlerR3, pvUserR3,
2037 pfnHandlerR0, pvUserR0,
2038 pfnHandlerRC, pvUserRC, pszDesc);
2039 if ( RT_FAILURE(rc)
2040 && !fRamExists)
2041 {
2042 pVM->pgm.s.cPureMmioPages -= cb >> PAGE_SHIFT;
2043 pVM->pgm.s.cAllPages -= cb >> PAGE_SHIFT;
2044
2045 /* remove the ad hoc range. */
2046 pgmR3PhysUnlinkRamRange2(pVM, pNew, pRamPrev);
2047 pNew->cb = pNew->GCPhys = pNew->GCPhysLast = NIL_RTGCPHYS;
2048 MMHyperFree(pVM, pRam);
2049 }
2050 PGMPhysInvalidatePageMapTLB(pVM);
2051
2052 return rc;
2053}
2054
2055
2056/**
2057 * This is the interface IOM is using to register an MMIO region.
2058 *
2059 * It will take care of calling PGMHandlerPhysicalDeregister and clean up
2060 * any ad hoc PGMRAMRANGE left behind.
2061 *
2062 * @returns VBox status code.
2063 * @param pVM Pointer to the shared VM structure.
2064 * @param GCPhys The start of the MMIO region.
2065 * @param cb The size of the MMIO region.
2066 */
2067VMMR3DECL(int) PGMR3PhysMMIODeregister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb)
2068{
2069 VM_ASSERT_EMT(pVM);
2070
2071/** @todo this needs to own the PGM lock! */
2072 /*
2073 * First deregister the handler, then check if we should remove the ram range.
2074 */
2075 int rc = PGMHandlerPhysicalDeregister(pVM, GCPhys);
2076 if (RT_SUCCESS(rc))
2077 {
2078 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
2079 PPGMRAMRANGE pRamPrev = NULL;
2080 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
2081 while (pRam && GCPhysLast >= pRam->GCPhys)
2082 {
2083 /** @todo We're being a bit too careful here. rewrite. */
2084 if ( GCPhysLast == pRam->GCPhysLast
2085 && GCPhys == pRam->GCPhys)
2086 {
2087 Assert(pRam->cb == cb);
2088
2089 /*
2090 * See if all the pages are dead MMIO pages.
2091 */
2092 uint32_t const cPages = cb >> PAGE_SHIFT;
2093 bool fAllMMIO = true;
2094 uint32_t iPage = 0;
2095 uint32_t cLeft = cPages;
2096 while (cLeft-- > 0)
2097 {
2098 PPGMPAGE pPage = &pRam->aPages[iPage];
2099 if ( PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO
2100 /*|| not-out-of-action later */)
2101 {
2102 fAllMMIO = false;
2103 Assert(PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO2_ALIAS_MMIO);
2104 AssertMsgFailed(("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
2105 break;
2106 }
2107 Assert(PGM_PAGE_IS_ZERO(pPage));
2108 pPage++;
2109 }
2110 if (fAllMMIO)
2111 {
2112 /*
2113 * Ad-hoc range, unlink and free it.
2114 */
2115 Log(("PGMR3PhysMMIODeregister: Freeing ad hoc MMIO range for %RGp-%RGp %s\n",
2116 GCPhys, GCPhysLast, pRam->pszDesc));
2117
2118 pVM->pgm.s.cAllPages -= cPages;
2119 pVM->pgm.s.cPureMmioPages -= cPages;
2120
2121 pgmR3PhysUnlinkRamRange2(pVM, pRam, pRamPrev);
2122 pRam->cb = pRam->GCPhys = pRam->GCPhysLast = NIL_RTGCPHYS;
2123 MMHyperFree(pVM, pRam);
2124 break;
2125 }
2126 }
2127
2128 /*
2129 * Range match? It will all be within one range (see PGMAllHandler.cpp).
2130 */
2131 if ( GCPhysLast >= pRam->GCPhys
2132 && GCPhys <= pRam->GCPhysLast)
2133 {
2134 Assert(GCPhys >= pRam->GCPhys);
2135 Assert(GCPhysLast <= pRam->GCPhysLast);
2136
2137 /*
2138 * Turn the pages back into RAM pages.
2139 */
2140 uint32_t iPage = (GCPhys - pRam->GCPhys) >> PAGE_SHIFT;
2141 uint32_t cLeft = cb >> PAGE_SHIFT;
2142 while (cLeft--)
2143 {
2144 PPGMPAGE pPage = &pRam->aPages[iPage];
2145 AssertMsg(PGM_PAGE_IS_MMIO(pPage), ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
2146 AssertMsg(PGM_PAGE_IS_ZERO(pPage), ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
2147 if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO)
2148 PGM_PAGE_SET_TYPE(pPage, PGMPAGETYPE_RAM);
2149 }
2150 break;
2151 }
2152
2153 /* next */
2154 pRamPrev = pRam;
2155 pRam = pRam->pNextR3;
2156 }
2157 }
2158
2159 /* Force a PGM pool flush as guest ram references have been changed. */
2160 /** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
2161 PVMCPU pVCpu = VMMGetCpu(pVM);
2162 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2163 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2164
2165 PGMPhysInvalidatePageMapTLB(pVM);
2166#ifdef PGM_USE_RAMRANGE_TLB
2167 pgmPhysInvalidRamRangeTlbs(pVM);
2168#endif
2169 return rc;
2170}
2171
2172
2173/**
2174 * Locate a MMIO2 range.
2175 *
2176 * @returns Pointer to the MMIO2 range.
2177 * @param pVM Pointer to the shared VM structure.
2178 * @param pDevIns The device instance owning the region.
2179 * @param iRegion The region.
2180 */
2181DECLINLINE(PPGMMMIO2RANGE) pgmR3PhysMMIO2Find(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion)
2182{
2183 /*
2184 * Search the list.
2185 */
2186 for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
2187 if ( pCur->pDevInsR3 == pDevIns
2188 && pCur->iRegion == iRegion)
2189 return pCur;
2190 return NULL;
2191}
2192
2193
2194/**
2195 * Allocate and register an MMIO2 region.
2196 *
2197 * As mentioned elsewhere, MMIO2 is just RAM spelled differently. It's RAM
2198 * associated with a device. It is also non-shared memory with a permanent
2199 * ring-3 mapping and page backing (presently).
2200 *
2201 * A MMIO2 range may overlap with base memory if a lot of RAM is configured for
2202 * the VM, in which case we'll drop the base memory pages. Presently we will
2203 * make no attempt to preserve anything that happens to be present in the base
2204 * memory that is replaced, this is of course incorrectly but it's too much
2205 * effort.
2206 *
2207 * @returns VBox status code.
2208 * @retval VINF_SUCCESS on success, *ppv pointing to the R3 mapping of the
2209 * memory.
2210 * @retval VERR_ALREADY_EXISTS if the region already exists.
2211 *
2212 * @param pVM Pointer to the shared VM structure.
2213 * @param pDevIns The device instance owning the region.
2214 * @param iRegion The region number. If the MMIO2 memory is a PCI
2215 * I/O region this number has to be the number of that
2216 * region. Otherwise it can be any number safe
2217 * UINT8_MAX.
2218 * @param cb The size of the region. Must be page aligned.
2219 * @param fFlags Reserved for future use, must be zero.
2220 * @param ppv Where to store the pointer to the ring-3 mapping of
2221 * the memory.
2222 * @param pszDesc The description.
2223 */
2224VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc)
2225{
2226 /*
2227 * Validate input.
2228 */
2229 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2230 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2231 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2232 AssertPtrReturn(ppv, VERR_INVALID_POINTER);
2233 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
2234 AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
2235 AssertReturn(pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion) == NULL, VERR_ALREADY_EXISTS);
2236 AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2237 AssertReturn(cb, VERR_INVALID_PARAMETER);
2238 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
2239
2240 const uint32_t cPages = cb >> PAGE_SHIFT;
2241 AssertLogRelReturn(((RTGCPHYS)cPages << PAGE_SHIFT) == cb, VERR_INVALID_PARAMETER);
2242 AssertLogRelReturn(cPages <= INT32_MAX / 2, VERR_NO_MEMORY);
2243
2244 /*
2245 * For the 2nd+ instance, mangle the description string so it's unique.
2246 */
2247 if (pDevIns->iInstance > 0) /** @todo Move to PDMDevHlp.cpp and use a real string cache. */
2248 {
2249 pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS, "%s [%u]", pszDesc, pDevIns->iInstance);
2250 if (!pszDesc)
2251 return VERR_NO_MEMORY;
2252 }
2253
2254 /*
2255 * Try reserve and allocate the backing memory first as this is what is
2256 * most likely to fail.
2257 */
2258 int rc = MMR3AdjustFixedReservation(pVM, cPages, pszDesc);
2259 if (RT_SUCCESS(rc))
2260 {
2261 void *pvPages;
2262 PSUPPAGE paPages = (PSUPPAGE)RTMemTmpAlloc(cPages * sizeof(SUPPAGE));
2263 if (RT_SUCCESS(rc))
2264 rc = SUPR3PageAllocEx(cPages, 0 /*fFlags*/, &pvPages, NULL /*pR0Ptr*/, paPages);
2265 if (RT_SUCCESS(rc))
2266 {
2267 memset(pvPages, 0, cPages * PAGE_SIZE);
2268
2269 /*
2270 * Create the MMIO2 range record for it.
2271 */
2272 const size_t cbRange = RT_OFFSETOF(PGMMMIO2RANGE, RamRange.aPages[cPages]);
2273 PPGMMMIO2RANGE pNew;
2274 rc = MMR3HyperAllocOnceNoRel(pVM, cbRange, 0, MM_TAG_PGM_PHYS, (void **)&pNew);
2275 AssertLogRelMsgRC(rc, ("cbRamRange=%zu\n", cbRange));
2276 if (RT_SUCCESS(rc))
2277 {
2278 pNew->pDevInsR3 = pDevIns;
2279 pNew->pvR3 = pvPages;
2280 //pNew->pNext = NULL;
2281 //pNew->fMapped = false;
2282 //pNew->fOverlapping = false;
2283 pNew->iRegion = iRegion;
2284 pNew->idSavedState = UINT8_MAX;
2285 pNew->RamRange.pSelfR0 = MMHyperCCToR0(pVM, &pNew->RamRange);
2286 pNew->RamRange.pSelfRC = MMHyperCCToRC(pVM, &pNew->RamRange);
2287 pNew->RamRange.GCPhys = NIL_RTGCPHYS;
2288 pNew->RamRange.GCPhysLast = NIL_RTGCPHYS;
2289 pNew->RamRange.pszDesc = pszDesc;
2290 pNew->RamRange.cb = cb;
2291 pNew->RamRange.fFlags = PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO2;
2292 pNew->RamRange.pvR3 = pvPages;
2293 //pNew->RamRange.paLSPages = NULL;
2294
2295 uint32_t iPage = cPages;
2296 while (iPage-- > 0)
2297 {
2298 PGM_PAGE_INIT(&pNew->RamRange.aPages[iPage],
2299 paPages[iPage].Phys, NIL_GMM_PAGEID,
2300 PGMPAGETYPE_MMIO2, PGM_PAGE_STATE_ALLOCATED);
2301 }
2302
2303 /* update page count stats */
2304 pVM->pgm.s.cAllPages += cPages;
2305 pVM->pgm.s.cPrivatePages += cPages;
2306
2307 /*
2308 * Link it into the list.
2309 * Since there is no particular order, just push it.
2310 */
2311 pgmLock(pVM);
2312 pNew->pNextR3 = pVM->pgm.s.pMmio2RangesR3;
2313 pVM->pgm.s.pMmio2RangesR3 = pNew;
2314 pgmUnlock(pVM);
2315
2316 *ppv = pvPages;
2317 RTMemTmpFree(paPages);
2318 PGMPhysInvalidatePageMapTLB(pVM);
2319 return VINF_SUCCESS;
2320 }
2321
2322 SUPR3PageFreeEx(pvPages, cPages);
2323 }
2324 RTMemTmpFree(paPages);
2325 MMR3AdjustFixedReservation(pVM, -(int32_t)cPages, pszDesc);
2326 }
2327 if (pDevIns->iInstance > 0)
2328 MMR3HeapFree((void *)pszDesc);
2329 return rc;
2330}
2331
2332
2333/**
2334 * Deregisters and frees an MMIO2 region.
2335 *
2336 * Any physical (and virtual) access handlers registered for the region must
2337 * be deregistered before calling this function.
2338 *
2339 * @returns VBox status code.
2340 * @param pVM Pointer to the shared VM structure.
2341 * @param pDevIns The device instance owning the region.
2342 * @param iRegion The region. If it's UINT32_MAX it'll be a wildcard match.
2343 */
2344VMMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion)
2345{
2346 /*
2347 * Validate input.
2348 */
2349 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2350 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2351 AssertReturn(iRegion <= UINT8_MAX || iRegion == UINT32_MAX, VERR_INVALID_PARAMETER);
2352
2353 pgmLock(pVM);
2354 int rc = VINF_SUCCESS;
2355 unsigned cFound = 0;
2356 PPGMMMIO2RANGE pPrev = NULL;
2357 PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3;
2358 while (pCur)
2359 {
2360 if ( pCur->pDevInsR3 == pDevIns
2361 && ( iRegion == UINT32_MAX
2362 || pCur->iRegion == iRegion))
2363 {
2364 cFound++;
2365
2366 /*
2367 * Unmap it if it's mapped.
2368 */
2369 if (pCur->fMapped)
2370 {
2371 int rc2 = PGMR3PhysMMIO2Unmap(pVM, pCur->pDevInsR3, pCur->iRegion, pCur->RamRange.GCPhys);
2372 AssertRC(rc2);
2373 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
2374 rc = rc2;
2375 }
2376
2377 /*
2378 * Unlink it
2379 */
2380 PPGMMMIO2RANGE pNext = pCur->pNextR3;
2381 if (pPrev)
2382 pPrev->pNextR3 = pNext;
2383 else
2384 pVM->pgm.s.pMmio2RangesR3 = pNext;
2385 pCur->pNextR3 = NULL;
2386
2387 /*
2388 * Free the memory.
2389 */
2390 int rc2 = SUPR3PageFreeEx(pCur->pvR3, pCur->RamRange.cb >> PAGE_SHIFT);
2391 AssertRC(rc2);
2392 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
2393 rc = rc2;
2394
2395 uint32_t const cPages = pCur->RamRange.cb >> PAGE_SHIFT;
2396 rc2 = MMR3AdjustFixedReservation(pVM, -(int32_t)cPages, pCur->RamRange.pszDesc);
2397 AssertRC(rc2);
2398 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
2399 rc = rc2;
2400
2401 /* we're leaking hyper memory here if done at runtime. */
2402#ifdef VBOX_STRICT
2403 VMSTATE const enmState = VMR3GetState(pVM);
2404 AssertMsg( enmState == VMSTATE_POWERING_OFF
2405 || enmState == VMSTATE_POWERING_OFF_LS
2406 || enmState == VMSTATE_OFF
2407 || enmState == VMSTATE_OFF_LS
2408 || enmState == VMSTATE_DESTROYING
2409 || enmState == VMSTATE_TERMINATED
2410 || enmState == VMSTATE_CREATING
2411 , ("%s\n", VMR3GetStateName(enmState)));
2412#endif
2413 /*rc = MMHyperFree(pVM, pCur);
2414 AssertRCReturn(rc, rc); - not safe, see the alloc call. */
2415
2416
2417 /* update page count stats */
2418 pVM->pgm.s.cAllPages -= cPages;
2419 pVM->pgm.s.cPrivatePages -= cPages;
2420
2421 /* next */
2422 pCur = pNext;
2423 }
2424 else
2425 {
2426 pPrev = pCur;
2427 pCur = pCur->pNextR3;
2428 }
2429 }
2430 PGMPhysInvalidatePageMapTLB(pVM);
2431 pgmUnlock(pVM);
2432 return !cFound && iRegion != UINT32_MAX ? VERR_NOT_FOUND : rc;
2433}
2434
2435
2436/**
2437 * Maps a MMIO2 region.
2438 *
2439 * This is done when a guest / the bios / state loading changes the
2440 * PCI config. The replacing of base memory has the same restrictions
2441 * as during registration, of course.
2442 *
2443 * @returns VBox status code.
2444 *
2445 * @param pVM Pointer to the shared VM structure.
2446 * @param pDevIns The
2447 */
2448VMMR3DECL(int) PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
2449{
2450 /*
2451 * Validate input
2452 */
2453 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2454 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2455 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2456 AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
2457 AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
2458 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2459
2460 PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
2461 AssertReturn(pCur, VERR_NOT_FOUND);
2462 AssertReturn(!pCur->fMapped, VERR_WRONG_ORDER);
2463 Assert(pCur->RamRange.GCPhys == NIL_RTGCPHYS);
2464 Assert(pCur->RamRange.GCPhysLast == NIL_RTGCPHYS);
2465
2466 const RTGCPHYS GCPhysLast = GCPhys + pCur->RamRange.cb - 1;
2467 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
2468
2469 /*
2470 * Find our location in the ram range list, checking for
2471 * restriction we don't bother implementing yet (partially overlapping).
2472 */
2473 bool fRamExists = false;
2474 PPGMRAMRANGE pRamPrev = NULL;
2475 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
2476 while (pRam && GCPhysLast >= pRam->GCPhys)
2477 {
2478 if ( GCPhys <= pRam->GCPhysLast
2479 && GCPhysLast >= pRam->GCPhys)
2480 {
2481 /* completely within? */
2482 AssertLogRelMsgReturn( GCPhys >= pRam->GCPhys
2483 && GCPhysLast <= pRam->GCPhysLast,
2484 ("%RGp-%RGp (MMIO2/%s) falls partly outside %RGp-%RGp (%s)\n",
2485 GCPhys, GCPhysLast, pCur->RamRange.pszDesc,
2486 pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
2487 VERR_PGM_RAM_CONFLICT);
2488 fRamExists = true;
2489 break;
2490 }
2491
2492 /* next */
2493 pRamPrev = pRam;
2494 pRam = pRam->pNextR3;
2495 }
2496 if (fRamExists)
2497 {
2498 PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2499 uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
2500 while (cPagesLeft-- > 0)
2501 {
2502 AssertLogRelMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
2503 ("%RGp isn't a RAM page (%d) - mapping %RGp-%RGp (MMIO2/%s).\n",
2504 GCPhys, PGM_PAGE_GET_TYPE(pPage), GCPhys, GCPhysLast, pCur->RamRange.pszDesc),
2505 VERR_PGM_RAM_CONFLICT);
2506 pPage++;
2507 }
2508 }
2509 Log(("PGMR3PhysMMIO2Map: %RGp-%RGp fRamExists=%RTbool %s\n",
2510 GCPhys, GCPhysLast, fRamExists, pCur->RamRange.pszDesc));
2511
2512 /*
2513 * Make the changes.
2514 */
2515 pgmLock(pVM);
2516
2517 pCur->RamRange.GCPhys = GCPhys;
2518 pCur->RamRange.GCPhysLast = GCPhysLast;
2519 pCur->fMapped = true;
2520 pCur->fOverlapping = fRamExists;
2521
2522 if (fRamExists)
2523 {
2524/** @todo use pgmR3PhysFreePageRange here. */
2525 uint32_t cPendingPages = 0;
2526 PGMMFREEPAGESREQ pReq;
2527 int rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
2528 AssertLogRelRCReturn(rc, rc);
2529
2530 /* replace the pages, freeing all present RAM pages. */
2531 PPGMPAGE pPageSrc = &pCur->RamRange.aPages[0];
2532 PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2533 uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
2534 while (cPagesLeft-- > 0)
2535 {
2536 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPageDst, GCPhys);
2537 AssertLogRelRCReturn(rc, rc); /* We're done for if this goes wrong. */
2538
2539 RTHCPHYS const HCPhys = PGM_PAGE_GET_HCPHYS(pPageSrc);
2540 PGM_PAGE_SET_HCPHYS(pPageDst, HCPhys);
2541 PGM_PAGE_SET_TYPE(pPageDst, PGMPAGETYPE_MMIO2);
2542 PGM_PAGE_SET_STATE(pPageDst, PGM_PAGE_STATE_ALLOCATED);
2543 PGM_PAGE_SET_PDE_TYPE(pPageDst, PGM_PAGE_PDE_TYPE_DONTCARE);
2544 PGM_PAGE_SET_PTE_INDEX(pPageDst, 0);
2545 PGM_PAGE_SET_TRACKING(pPageDst, 0);
2546
2547 pVM->pgm.s.cZeroPages--;
2548 GCPhys += PAGE_SIZE;
2549 pPageSrc++;
2550 pPageDst++;
2551 }
2552
2553 /* Flush physical page map TLB. */
2554 PGMPhysInvalidatePageMapTLB(pVM);
2555
2556 if (cPendingPages)
2557 {
2558 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
2559 AssertLogRelRCReturn(rc, rc);
2560 }
2561 GMMR3FreePagesCleanup(pReq);
2562
2563 /* Force a PGM pool flush as guest ram references have been changed. */
2564 /** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
2565 PVMCPU pVCpu = VMMGetCpu(pVM);
2566 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2567 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2568
2569 pgmUnlock(pVM);
2570 }
2571 else
2572 {
2573 RTGCPHYS cb = pCur->RamRange.cb;
2574
2575 /* Clear the tracking data of pages we're going to reactivate. */
2576 PPGMPAGE pPageSrc = &pCur->RamRange.aPages[0];
2577 uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
2578 while (cPagesLeft-- > 0)
2579 {
2580 PGM_PAGE_SET_TRACKING(pPageSrc, 0);
2581 PGM_PAGE_SET_PTE_INDEX(pPageSrc, 0);
2582 pPageSrc++;
2583 }
2584
2585 /* link in the ram range */
2586 pgmR3PhysLinkRamRange(pVM, &pCur->RamRange, pRamPrev);
2587 pgmUnlock(pVM);
2588
2589 REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_MMIO2);
2590 }
2591
2592 PGMPhysInvalidatePageMapTLB(pVM);
2593 return VINF_SUCCESS;
2594}
2595
2596
2597/**
2598 * Unmaps a MMIO2 region.
2599 *
2600 * This is done when a guest / the bios / state loading changes the
2601 * PCI config. The replacing of base memory has the same restrictions
2602 * as during registration, of course.
2603 */
2604VMMR3DECL(int) PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
2605{
2606 /*
2607 * Validate input
2608 */
2609 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2610 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2611 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2612 AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
2613 AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
2614 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2615
2616 PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
2617 AssertReturn(pCur, VERR_NOT_FOUND);
2618 AssertReturn(pCur->fMapped, VERR_WRONG_ORDER);
2619 AssertReturn(pCur->RamRange.GCPhys == GCPhys, VERR_INVALID_PARAMETER);
2620 Assert(pCur->RamRange.GCPhysLast != NIL_RTGCPHYS);
2621
2622 Log(("PGMR3PhysMMIO2Unmap: %RGp-%RGp %s\n",
2623 pCur->RamRange.GCPhys, pCur->RamRange.GCPhysLast, pCur->RamRange.pszDesc));
2624
2625 /*
2626 * Unmap it.
2627 */
2628 pgmLock(pVM);
2629
2630 RTGCPHYS GCPhysRangeREM;
2631 RTGCPHYS cbRangeREM;
2632 bool fInformREM;
2633 if (pCur->fOverlapping)
2634 {
2635 /* Restore the RAM pages we've replaced. */
2636 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
2637 while (pRam->GCPhys > pCur->RamRange.GCPhysLast)
2638 pRam = pRam->pNextR3;
2639
2640 PPGMPAGE pPageDst = &pRam->aPages[(pCur->RamRange.GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2641 uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
2642 while (cPagesLeft-- > 0)
2643 {
2644 PGM_PAGE_INIT_ZERO(pPageDst, pVM, PGMPAGETYPE_RAM);
2645 pVM->pgm.s.cZeroPages++;
2646 pPageDst++;
2647 }
2648
2649 /* Flush physical page map TLB. */
2650 PGMPhysInvalidatePageMapTLB(pVM);
2651
2652 GCPhysRangeREM = NIL_RTGCPHYS; /* shuts up gcc */
2653 cbRangeREM = RTGCPHYS_MAX; /* ditto */
2654 fInformREM = false;
2655 }
2656 else
2657 {
2658 GCPhysRangeREM = pCur->RamRange.GCPhys;
2659 cbRangeREM = pCur->RamRange.cb;
2660 fInformREM = true;
2661
2662 pgmR3PhysUnlinkRamRange(pVM, &pCur->RamRange);
2663 }
2664
2665 pCur->RamRange.GCPhys = NIL_RTGCPHYS;
2666 pCur->RamRange.GCPhysLast = NIL_RTGCPHYS;
2667 pCur->fOverlapping = false;
2668 pCur->fMapped = false;
2669
2670 /* Force a PGM pool flush as guest ram references have been changed. */
2671 /** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
2672 PVMCPU pVCpu = VMMGetCpu(pVM);
2673 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2674 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2675
2676 PGMPhysInvalidatePageMapTLB(pVM);
2677#ifdef PGM_USE_RAMRANGE_TLB
2678 pgmPhysInvalidRamRangeTlbs(pVM);
2679#endif
2680 pgmUnlock(pVM);
2681
2682 if (fInformREM)
2683 REMR3NotifyPhysRamDeregister(pVM, GCPhysRangeREM, cbRangeREM);
2684
2685 return VINF_SUCCESS;
2686}
2687
2688
2689/**
2690 * Checks if the given address is an MMIO2 base address or not.
2691 *
2692 * @returns true/false accordingly.
2693 * @param pVM Pointer to the shared VM structure.
2694 * @param pDevIns The owner of the memory, optional.
2695 * @param GCPhys The address to check.
2696 */
2697VMMR3DECL(bool) PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
2698{
2699 /*
2700 * Validate input
2701 */
2702 VM_ASSERT_EMT_RETURN(pVM, false);
2703 AssertPtrReturn(pDevIns, false);
2704 AssertReturn(GCPhys != NIL_RTGCPHYS, false);
2705 AssertReturn(GCPhys != 0, false);
2706 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), false);
2707
2708 /*
2709 * Search the list.
2710 */
2711 pgmLock(pVM);
2712 for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
2713 if (pCur->RamRange.GCPhys == GCPhys)
2714 {
2715 Assert(pCur->fMapped);
2716 pgmUnlock(pVM);
2717 return true;
2718 }
2719 pgmUnlock(pVM);
2720 return false;
2721}
2722
2723
2724/**
2725 * Gets the HC physical address of a page in the MMIO2 region.
2726 *
2727 * This is API is intended for MMHyper and shouldn't be called
2728 * by anyone else...
2729 *
2730 * @returns VBox status code.
2731 * @param pVM Pointer to the shared VM structure.
2732 * @param pDevIns The owner of the memory, optional.
2733 * @param iRegion The region.
2734 * @param off The page expressed an offset into the MMIO2 region.
2735 * @param pHCPhys Where to store the result.
2736 */
2737VMMR3DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys)
2738{
2739 /*
2740 * Validate input
2741 */
2742 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2743 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2744 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2745
2746 pgmLock(pVM);
2747 PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
2748 AssertReturn(pCur, VERR_NOT_FOUND);
2749 AssertReturn(off < pCur->RamRange.cb, VERR_INVALID_PARAMETER);
2750
2751 PCPGMPAGE pPage = &pCur->RamRange.aPages[off >> PAGE_SHIFT];
2752 *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage);
2753 pgmUnlock(pVM);
2754 return VINF_SUCCESS;
2755}
2756
2757
2758/**
2759 * Maps a portion of an MMIO2 region into kernel space (host).
2760 *
2761 * The kernel mapping will become invalid when the MMIO2 memory is deregistered
2762 * or the VM is terminated.
2763 *
2764 * @return VBox status code.
2765 *
2766 * @param pVM Pointer to the shared VM structure.
2767 * @param pDevIns The device owning the MMIO2 memory.
2768 * @param iRegion The region.
2769 * @param off The offset into the region. Must be page aligned.
2770 * @param cb The number of bytes to map. Must be page aligned.
2771 * @param pszDesc Mapping description.
2772 * @param pR0Ptr Where to store the R0 address.
2773 */
2774VMMR3DECL(int) PGMR3PhysMMIO2MapKernel(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
2775 const char *pszDesc, PRTR0PTR pR0Ptr)
2776{
2777 /*
2778 * Validate input.
2779 */
2780 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2781 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2782 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2783
2784 PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
2785 AssertReturn(pCur, VERR_NOT_FOUND);
2786 AssertReturn(off < pCur->RamRange.cb, VERR_INVALID_PARAMETER);
2787 AssertReturn(cb <= pCur->RamRange.cb, VERR_INVALID_PARAMETER);
2788 AssertReturn(off + cb <= pCur->RamRange.cb, VERR_INVALID_PARAMETER);
2789
2790 /*
2791 * Pass the request on to the support library/driver.
2792 */
2793 int rc = SUPR3PageMapKernel(pCur->pvR3, off, cb, 0, pR0Ptr);
2794
2795 return rc;
2796}
2797
2798
2799/**
2800 * Registers a ROM image.
2801 *
2802 * Shadowed ROM images requires double the amount of backing memory, so,
2803 * don't use that unless you have to. Shadowing of ROM images is process
2804 * where we can select where the reads go and where the writes go. On real
2805 * hardware the chipset provides means to configure this. We provide
2806 * PGMR3PhysProtectROM() for this purpose.
2807 *
2808 * A read-only copy of the ROM image will always be kept around while we
2809 * will allocate RAM pages for the changes on demand (unless all memory
2810 * is configured to be preallocated).
2811 *
2812 * @returns VBox status.
2813 * @param pVM VM Handle.
2814 * @param pDevIns The device instance owning the ROM.
2815 * @param GCPhys First physical address in the range.
2816 * Must be page aligned!
2817 * @param cb The size of the range (in bytes).
2818 * Must be page aligned!
2819 * @param pvBinary Pointer to the binary data backing the ROM image.
2820 * @param cbBinary The size of the binary data pvBinary points to.
2821 * This must be less or equal to @a cb.
2822 * @param fFlags Mask of flags. PGMPHYS_ROM_FLAGS_SHADOWED
2823 * and/or PGMPHYS_ROM_FLAGS_PERMANENT_BINARY.
2824 * @param pszDesc Pointer to description string. This must not be freed.
2825 *
2826 * @remark There is no way to remove the rom, automatically on device cleanup or
2827 * manually from the device yet. This isn't difficult in any way, it's
2828 * just not something we expect to be necessary for a while.
2829 */
2830VMMR3DECL(int) PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb,
2831 const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc)
2832{
2833 Log(("PGMR3PhysRomRegister: pDevIns=%p GCPhys=%RGp(-%RGp) cb=%RGp pvBinary=%p cbBinary=%#x fFlags=%#x pszDesc=%s\n",
2834 pDevIns, GCPhys, GCPhys + cb, cb, pvBinary, cbBinary, fFlags, pszDesc));
2835
2836 /*
2837 * Validate input.
2838 */
2839 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2840 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
2841 AssertReturn(RT_ALIGN_T(cb, PAGE_SIZE, RTGCPHYS) == cb, VERR_INVALID_PARAMETER);
2842 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
2843 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
2844 AssertPtrReturn(pvBinary, VERR_INVALID_PARAMETER);
2845 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
2846 AssertReturn(!(fFlags & ~(PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY)), VERR_INVALID_PARAMETER);
2847 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
2848
2849 const uint32_t cPages = cb >> PAGE_SHIFT;
2850
2851 /*
2852 * Find the ROM location in the ROM list first.
2853 */
2854 PPGMROMRANGE pRomPrev = NULL;
2855 PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3;
2856 while (pRom && GCPhysLast >= pRom->GCPhys)
2857 {
2858 if ( GCPhys <= pRom->GCPhysLast
2859 && GCPhysLast >= pRom->GCPhys)
2860 AssertLogRelMsgFailedReturn(("%RGp-%RGp (%s) conflicts with existing %RGp-%RGp (%s)\n",
2861 GCPhys, GCPhysLast, pszDesc,
2862 pRom->GCPhys, pRom->GCPhysLast, pRom->pszDesc),
2863 VERR_PGM_RAM_CONFLICT);
2864 /* next */
2865 pRomPrev = pRom;
2866 pRom = pRom->pNextR3;
2867 }
2868
2869 /*
2870 * Find the RAM location and check for conflicts.
2871 *
2872 * Conflict detection is a bit different than for RAM
2873 * registration since a ROM can be located within a RAM
2874 * range. So, what we have to check for is other memory
2875 * types (other than RAM that is) and that we don't span
2876 * more than one RAM range (layz).
2877 */
2878 bool fRamExists = false;
2879 PPGMRAMRANGE pRamPrev = NULL;
2880 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
2881 while (pRam && GCPhysLast >= pRam->GCPhys)
2882 {
2883 if ( GCPhys <= pRam->GCPhysLast
2884 && GCPhysLast >= pRam->GCPhys)
2885 {
2886 /* completely within? */
2887 AssertLogRelMsgReturn( GCPhys >= pRam->GCPhys
2888 && GCPhysLast <= pRam->GCPhysLast,
2889 ("%RGp-%RGp (%s) falls partly outside %RGp-%RGp (%s)\n",
2890 GCPhys, GCPhysLast, pszDesc,
2891 pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
2892 VERR_PGM_RAM_CONFLICT);
2893 fRamExists = true;
2894 break;
2895 }
2896
2897 /* next */
2898 pRamPrev = pRam;
2899 pRam = pRam->pNextR3;
2900 }
2901 if (fRamExists)
2902 {
2903 PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2904 uint32_t cPagesLeft = cPages;
2905 while (cPagesLeft-- > 0)
2906 {
2907 AssertLogRelMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
2908 ("%RGp (%R[pgmpage]) isn't a RAM page - registering %RGp-%RGp (%s).\n",
2909 pRam->GCPhys + ((RTGCPHYS)(uintptr_t)(pPage - &pRam->aPages[0]) << PAGE_SHIFT),
2910 pPage, GCPhys, GCPhysLast, pszDesc), VERR_PGM_RAM_CONFLICT);
2911 Assert(PGM_PAGE_IS_ZERO(pPage));
2912 pPage++;
2913 }
2914 }
2915
2916 /*
2917 * Update the base memory reservation if necessary.
2918 */
2919 uint32_t cExtraBaseCost = fRamExists ? 0 : cPages;
2920 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
2921 cExtraBaseCost += cPages;
2922 if (cExtraBaseCost)
2923 {
2924 int rc = MMR3IncreaseBaseReservation(pVM, cExtraBaseCost);
2925 if (RT_FAILURE(rc))
2926 return rc;
2927 }
2928
2929 /*
2930 * Allocate memory for the virgin copy of the RAM.
2931 */
2932 PGMMALLOCATEPAGESREQ pReq;
2933 int rc = GMMR3AllocatePagesPrepare(pVM, &pReq, cPages, GMMACCOUNT_BASE);
2934 AssertRCReturn(rc, rc);
2935
2936 for (uint32_t iPage = 0; iPage < cPages; iPage++)
2937 {
2938 pReq->aPages[iPage].HCPhysGCPhys = GCPhys + (iPage << PAGE_SHIFT);
2939 pReq->aPages[iPage].idPage = NIL_GMM_PAGEID;
2940 pReq->aPages[iPage].idSharedPage = NIL_GMM_PAGEID;
2941 }
2942
2943 pgmLock(pVM);
2944 rc = GMMR3AllocatePagesPerform(pVM, pReq);
2945 pgmUnlock(pVM);
2946 if (RT_FAILURE(rc))
2947 {
2948 GMMR3AllocatePagesCleanup(pReq);
2949 return rc;
2950 }
2951
2952 /*
2953 * Allocate the new ROM range and RAM range (if necessary).
2954 */
2955 PPGMROMRANGE pRomNew;
2956 rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMROMRANGE, aPages[cPages]), 0, MM_TAG_PGM_PHYS, (void **)&pRomNew);
2957 if (RT_SUCCESS(rc))
2958 {
2959 PPGMRAMRANGE pRamNew = NULL;
2960 if (!fRamExists)
2961 rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]), sizeof(PGMPAGE), MM_TAG_PGM_PHYS, (void **)&pRamNew);
2962 if (RT_SUCCESS(rc))
2963 {
2964 pgmLock(pVM);
2965
2966 /*
2967 * Initialize and insert the RAM range (if required).
2968 */
2969 PPGMROMPAGE pRomPage = &pRomNew->aPages[0];
2970 if (!fRamExists)
2971 {
2972 pRamNew->pSelfR0 = MMHyperCCToR0(pVM, pRamNew);
2973 pRamNew->pSelfRC = MMHyperCCToRC(pVM, pRamNew);
2974 pRamNew->GCPhys = GCPhys;
2975 pRamNew->GCPhysLast = GCPhysLast;
2976 pRamNew->cb = cb;
2977 pRamNew->pszDesc = pszDesc;
2978 pRamNew->fFlags = PGM_RAM_RANGE_FLAGS_AD_HOC_ROM;
2979 pRamNew->pvR3 = NULL;
2980 pRamNew->paLSPages = NULL;
2981
2982 PPGMPAGE pPage = &pRamNew->aPages[0];
2983 for (uint32_t iPage = 0; iPage < cPages; iPage++, pPage++, pRomPage++)
2984 {
2985 PGM_PAGE_INIT(pPage,
2986 pReq->aPages[iPage].HCPhysGCPhys,
2987 pReq->aPages[iPage].idPage,
2988 PGMPAGETYPE_ROM,
2989 PGM_PAGE_STATE_ALLOCATED);
2990
2991 pRomPage->Virgin = *pPage;
2992 }
2993
2994 pVM->pgm.s.cAllPages += cPages;
2995 pgmR3PhysLinkRamRange(pVM, pRamNew, pRamPrev);
2996 }
2997 else
2998 {
2999 PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
3000 for (uint32_t iPage = 0; iPage < cPages; iPage++, pPage++, pRomPage++)
3001 {
3002 PGM_PAGE_SET_TYPE(pPage, PGMPAGETYPE_ROM);
3003 PGM_PAGE_SET_HCPHYS(pPage, pReq->aPages[iPage].HCPhysGCPhys);
3004 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ALLOCATED);
3005 PGM_PAGE_SET_PAGEID(pPage, pReq->aPages[iPage].idPage);
3006 PGM_PAGE_SET_PDE_TYPE(pPage, PGM_PAGE_PDE_TYPE_DONTCARE);
3007 PGM_PAGE_SET_PTE_INDEX(pPage, 0);
3008 PGM_PAGE_SET_TRACKING(pPage, 0);
3009
3010 pRomPage->Virgin = *pPage;
3011 }
3012
3013 pRamNew = pRam;
3014
3015 pVM->pgm.s.cZeroPages -= cPages;
3016 }
3017 pVM->pgm.s.cPrivatePages += cPages;
3018
3019 /* Flush physical page map TLB. */
3020 PGMPhysInvalidatePageMapTLB(pVM);
3021
3022 pgmUnlock(pVM);
3023
3024
3025 /*
3026 * !HACK ALERT! REM + (Shadowed) ROM ==> mess.
3027 *
3028 * If it's shadowed we'll register the handler after the ROM notification
3029 * so we get the access handler callbacks that we should. If it isn't
3030 * shadowed we'll do it the other way around to make REM use the built-in
3031 * ROM behavior and not the handler behavior (which is to route all access
3032 * to PGM atm).
3033 */
3034 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
3035 {
3036 REMR3NotifyPhysRomRegister(pVM, GCPhys, cb, NULL, true /* fShadowed */);
3037 rc = PGMR3HandlerPhysicalRegister(pVM,
3038 fFlags & PGMPHYS_ROM_FLAGS_SHADOWED
3039 ? PGMPHYSHANDLERTYPE_PHYSICAL_ALL
3040 : PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
3041 GCPhys, GCPhysLast,
3042 pgmR3PhysRomWriteHandler, pRomNew,
3043 NULL, "pgmPhysRomWriteHandler", MMHyperCCToR0(pVM, pRomNew),
3044 NULL, "pgmPhysRomWriteHandler", MMHyperCCToRC(pVM, pRomNew), pszDesc);
3045 }
3046 else
3047 {
3048 rc = PGMR3HandlerPhysicalRegister(pVM,
3049 fFlags & PGMPHYS_ROM_FLAGS_SHADOWED
3050 ? PGMPHYSHANDLERTYPE_PHYSICAL_ALL
3051 : PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
3052 GCPhys, GCPhysLast,
3053 pgmR3PhysRomWriteHandler, pRomNew,
3054 NULL, "pgmPhysRomWriteHandler", MMHyperCCToR0(pVM, pRomNew),
3055 NULL, "pgmPhysRomWriteHandler", MMHyperCCToRC(pVM, pRomNew), pszDesc);
3056 REMR3NotifyPhysRomRegister(pVM, GCPhys, cb, NULL, false /* fShadowed */);
3057 }
3058 if (RT_SUCCESS(rc))
3059 {
3060 pgmLock(pVM);
3061
3062 /*
3063 * Copy the image over to the virgin pages.
3064 * This must be done after linking in the RAM range.
3065 */
3066 size_t cbBinaryLeft = cbBinary;
3067 PPGMPAGE pRamPage = &pRamNew->aPages[(GCPhys - pRamNew->GCPhys) >> PAGE_SHIFT];
3068 for (uint32_t iPage = 0; iPage < cPages; iPage++, pRamPage++)
3069 {
3070 void *pvDstPage;
3071 rc = pgmPhysPageMap(pVM, pRamPage, GCPhys + (iPage << PAGE_SHIFT), &pvDstPage);
3072 if (RT_FAILURE(rc))
3073 {
3074 VMSetError(pVM, rc, RT_SRC_POS, "Failed to map virgin ROM page at %RGp", GCPhys);
3075 break;
3076 }
3077 if (cbBinaryLeft >= PAGE_SIZE)
3078 {
3079 memcpy(pvDstPage, (uint8_t const *)pvBinary + ((size_t)iPage << PAGE_SHIFT), PAGE_SIZE);
3080 cbBinaryLeft -= PAGE_SIZE;
3081 }
3082 else
3083 {
3084 ASMMemZeroPage(pvDstPage); /* (shouldn't be necessary, but can't hurt either) */
3085 if (cbBinaryLeft > 0)
3086 {
3087 memcpy(pvDstPage, (uint8_t const *)pvBinary + ((size_t)iPage << PAGE_SHIFT), cbBinaryLeft);
3088 cbBinaryLeft = 0;
3089 }
3090 }
3091 }
3092 if (RT_SUCCESS(rc))
3093 {
3094 /*
3095 * Initialize the ROM range.
3096 * Note that the Virgin member of the pages has already been initialized above.
3097 */
3098 pRomNew->GCPhys = GCPhys;
3099 pRomNew->GCPhysLast = GCPhysLast;
3100 pRomNew->cb = cb;
3101 pRomNew->fFlags = fFlags;
3102 pRomNew->idSavedState = UINT8_MAX;
3103 pRomNew->cbOriginal = cbBinary;
3104#ifdef VBOX_STRICT
3105 pRomNew->pvOriginal = fFlags & PGMPHYS_ROM_FLAGS_PERMANENT_BINARY
3106 ? pvBinary : RTMemDup(pvBinary, cbBinary);
3107#else
3108 pRomNew->pvOriginal = fFlags & PGMPHYS_ROM_FLAGS_PERMANENT_BINARY ? pvBinary : NULL;
3109#endif
3110 pRomNew->pszDesc = pszDesc;
3111
3112 for (unsigned iPage = 0; iPage < cPages; iPage++)
3113 {
3114 PPGMROMPAGE pPage = &pRomNew->aPages[iPage];
3115 pPage->enmProt = PGMROMPROT_READ_ROM_WRITE_IGNORE;
3116 PGM_PAGE_INIT_ZERO(&pPage->Shadow, pVM, PGMPAGETYPE_ROM_SHADOW);
3117 }
3118
3119 /* update the page count stats for the shadow pages. */
3120 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
3121 {
3122 pVM->pgm.s.cZeroPages += cPages;
3123 pVM->pgm.s.cAllPages += cPages;
3124 }
3125
3126 /*
3127 * Insert the ROM range, tell REM and return successfully.
3128 */
3129 pRomNew->pNextR3 = pRom;
3130 pRomNew->pNextR0 = pRom ? MMHyperCCToR0(pVM, pRom) : NIL_RTR0PTR;
3131 pRomNew->pNextRC = pRom ? MMHyperCCToRC(pVM, pRom) : NIL_RTRCPTR;
3132
3133 if (pRomPrev)
3134 {
3135 pRomPrev->pNextR3 = pRomNew;
3136 pRomPrev->pNextR0 = MMHyperCCToR0(pVM, pRomNew);
3137 pRomPrev->pNextRC = MMHyperCCToRC(pVM, pRomNew);
3138 }
3139 else
3140 {
3141 pVM->pgm.s.pRomRangesR3 = pRomNew;
3142 pVM->pgm.s.pRomRangesR0 = MMHyperCCToR0(pVM, pRomNew);
3143 pVM->pgm.s.pRomRangesRC = MMHyperCCToRC(pVM, pRomNew);
3144 }
3145
3146 PGMPhysInvalidatePageMapTLB(pVM);
3147 GMMR3AllocatePagesCleanup(pReq);
3148 pgmUnlock(pVM);
3149 return VINF_SUCCESS;
3150 }
3151
3152 /* bail out */
3153
3154 pgmUnlock(pVM);
3155 int rc2 = PGMHandlerPhysicalDeregister(pVM, GCPhys);
3156 AssertRC(rc2);
3157 pgmLock(pVM);
3158 }
3159
3160 if (!fRamExists)
3161 {
3162 pgmR3PhysUnlinkRamRange2(pVM, pRamNew, pRamPrev);
3163 MMHyperFree(pVM, pRamNew);
3164 }
3165 }
3166 MMHyperFree(pVM, pRomNew);
3167 }
3168
3169 /** @todo Purge the mapping cache or something... */
3170 GMMR3FreeAllocatedPages(pVM, pReq);
3171 GMMR3AllocatePagesCleanup(pReq);
3172 pgmUnlock(pVM);
3173 return rc;
3174}
3175
3176
3177/**
3178 * \#PF Handler callback for ROM write accesses.
3179 *
3180 * @returns VINF_SUCCESS if the handler have carried out the operation.
3181 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
3182 * @param pVM VM Handle.
3183 * @param GCPhys The physical address the guest is writing to.
3184 * @param pvPhys The HC mapping of that address.
3185 * @param pvBuf What the guest is reading/writing.
3186 * @param cbBuf How much it's reading/writing.
3187 * @param enmAccessType The access type.
3188 * @param pvUser User argument.
3189 */
3190static DECLCALLBACK(int) pgmR3PhysRomWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
3191 PGMACCESSTYPE enmAccessType, void *pvUser)
3192{
3193 PPGMROMRANGE pRom = (PPGMROMRANGE)pvUser;
3194 const uint32_t iPage = (GCPhys - pRom->GCPhys) >> PAGE_SHIFT;
3195 Assert(iPage < (pRom->cb >> PAGE_SHIFT));
3196 PPGMROMPAGE pRomPage = &pRom->aPages[iPage];
3197 Log5(("pgmR3PhysRomWriteHandler: %d %c %#08RGp %#04zx\n", pRomPage->enmProt, enmAccessType == PGMACCESSTYPE_READ ? 'R' : 'W', GCPhys, cbBuf));
3198
3199 if (enmAccessType == PGMACCESSTYPE_READ)
3200 {
3201 switch (pRomPage->enmProt)
3202 {
3203 /*
3204 * Take the default action.
3205 */
3206 case PGMROMPROT_READ_ROM_WRITE_IGNORE:
3207 case PGMROMPROT_READ_RAM_WRITE_IGNORE:
3208 case PGMROMPROT_READ_ROM_WRITE_RAM:
3209 case PGMROMPROT_READ_RAM_WRITE_RAM:
3210 return VINF_PGM_HANDLER_DO_DEFAULT;
3211
3212 default:
3213 AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhys=%RGp\n",
3214 pRom->aPages[iPage].enmProt, iPage, GCPhys),
3215 VERR_INTERNAL_ERROR);
3216 }
3217 }
3218 else
3219 {
3220 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
3221 switch (pRomPage->enmProt)
3222 {
3223 /*
3224 * Ignore writes.
3225 */
3226 case PGMROMPROT_READ_ROM_WRITE_IGNORE:
3227 case PGMROMPROT_READ_RAM_WRITE_IGNORE:
3228 return VINF_SUCCESS;
3229
3230 /*
3231 * Write to the RAM page.
3232 */
3233 case PGMROMPROT_READ_ROM_WRITE_RAM:
3234 case PGMROMPROT_READ_RAM_WRITE_RAM: /* yes this will get here too, it's *way* simpler that way. */
3235 {
3236 /* This should be impossible now, pvPhys doesn't work cross page anylonger. */
3237 Assert(((GCPhys - pRom->GCPhys + cbBuf - 1) >> PAGE_SHIFT) == iPage);
3238
3239 /*
3240 * Take the lock, do lazy allocation, map the page and copy the data.
3241 *
3242 * Note that we have to bypass the mapping TLB since it works on
3243 * guest physical addresses and entering the shadow page would
3244 * kind of screw things up...
3245 */
3246 int rc = pgmLock(pVM);
3247 AssertRC(rc);
3248
3249 PPGMPAGE pShadowPage = &pRomPage->Shadow;
3250 if (!PGMROMPROT_IS_ROM(pRomPage->enmProt))
3251 {
3252 pShadowPage = pgmPhysGetPage(pVM, GCPhys);
3253 AssertLogRelReturn(pShadowPage, VERR_INTERNAL_ERROR);
3254 }
3255
3256 void *pvDstPage;
3257 rc = pgmPhysPageMakeWritableAndMap(pVM, pShadowPage, GCPhys & X86_PTE_PG_MASK, &pvDstPage);
3258 if (RT_SUCCESS(rc))
3259 {
3260 memcpy((uint8_t *)pvDstPage + (GCPhys & PAGE_OFFSET_MASK), pvBuf, cbBuf);
3261 pRomPage->LiveSave.fWrittenTo = true;
3262 }
3263
3264 pgmUnlock(pVM);
3265 return rc;
3266 }
3267
3268 default:
3269 AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhys=%RGp\n",
3270 pRom->aPages[iPage].enmProt, iPage, GCPhys),
3271 VERR_INTERNAL_ERROR);
3272 }
3273 }
3274}
3275
3276
3277/**
3278 * Called by PGMR3Reset to reset the shadow, switch to the virgin,
3279 * and verify that the virgin part is untouched.
3280 *
3281 * This is done after the normal memory has been cleared.
3282 *
3283 * ASSUMES that the caller owns the PGM lock.
3284 *
3285 * @param pVM The VM handle.
3286 */
3287int pgmR3PhysRomReset(PVM pVM)
3288{
3289 Assert(PGMIsLockOwner(pVM));
3290 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)
3291 {
3292 const uint32_t cPages = pRom->cb >> PAGE_SHIFT;
3293
3294 if (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
3295 {
3296 /*
3297 * Reset the physical handler.
3298 */
3299 int rc = PGMR3PhysRomProtect(pVM, pRom->GCPhys, pRom->cb, PGMROMPROT_READ_ROM_WRITE_IGNORE);
3300 AssertRCReturn(rc, rc);
3301
3302 /*
3303 * What we do with the shadow pages depends on the memory
3304 * preallocation option. If not enabled, we'll just throw
3305 * out all the dirty pages and replace them by the zero page.
3306 */
3307 if (!pVM->pgm.s.fRamPreAlloc)
3308 {
3309 /* Free the dirty pages. */
3310 uint32_t cPendingPages = 0;
3311 PGMMFREEPAGESREQ pReq;
3312 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
3313 AssertRCReturn(rc, rc);
3314
3315 for (uint32_t iPage = 0; iPage < cPages; iPage++)
3316 if ( !PGM_PAGE_IS_ZERO(&pRom->aPages[iPage].Shadow)
3317 && !PGM_PAGE_IS_BALLOONED(&pRom->aPages[iPage].Shadow))
3318 {
3319 Assert(PGM_PAGE_GET_STATE(&pRom->aPages[iPage].Shadow) == PGM_PAGE_STATE_ALLOCATED);
3320 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, &pRom->aPages[iPage].Shadow,
3321 pRom->GCPhys + (iPage << PAGE_SHIFT));
3322 AssertLogRelRCReturn(rc, rc);
3323 }
3324
3325 if (cPendingPages)
3326 {
3327 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
3328 AssertLogRelRCReturn(rc, rc);
3329 }
3330 GMMR3FreePagesCleanup(pReq);
3331 }
3332 else
3333 {
3334 /* clear all the shadow pages. */
3335 for (uint32_t iPage = 0; iPage < cPages; iPage++)
3336 {
3337 if (PGM_PAGE_IS_ZERO(&pRom->aPages[iPage].Shadow))
3338 continue;
3339 Assert(!PGM_PAGE_IS_BALLOONED(&pRom->aPages[iPage].Shadow));
3340 void *pvDstPage;
3341 const RTGCPHYS GCPhys = pRom->GCPhys + (iPage << PAGE_SHIFT);
3342 rc = pgmPhysPageMakeWritableAndMap(pVM, &pRom->aPages[iPage].Shadow, GCPhys, &pvDstPage);
3343 if (RT_FAILURE(rc))
3344 break;
3345 ASMMemZeroPage(pvDstPage);
3346 }
3347 AssertRCReturn(rc, rc);
3348 }
3349 }
3350
3351#ifdef VBOX_STRICT
3352 /*
3353 * Verify that the virgin page is unchanged if possible.
3354 */
3355 if (pRom->pvOriginal)
3356 {
3357 size_t cbSrcLeft = pRom->cbOriginal;
3358 uint8_t const *pbSrcPage = (uint8_t const *)pRom->pvOriginal;
3359 for (uint32_t iPage = 0; iPage < cPages && cbSrcLeft > 0; iPage++, pbSrcPage += PAGE_SIZE)
3360 {
3361 const RTGCPHYS GCPhys = pRom->GCPhys + (iPage << PAGE_SHIFT);
3362 void const *pvDstPage;
3363 int rc = pgmPhysPageMapReadOnly(pVM, &pRom->aPages[iPage].Virgin, GCPhys, &pvDstPage);
3364 if (RT_FAILURE(rc))
3365 break;
3366
3367 if (memcmp(pvDstPage, pbSrcPage, RT_MIN(cbSrcLeft, PAGE_SIZE)))
3368 LogRel(("pgmR3PhysRomReset: %RGp rom page changed (%s) - loaded saved state?\n",
3369 GCPhys, pRom->pszDesc));
3370 cbSrcLeft -= RT_MIN(cbSrcLeft, PAGE_SIZE);
3371 }
3372 }
3373#endif
3374 }
3375
3376 return VINF_SUCCESS;
3377}
3378
3379
3380/**
3381 * Called by PGMR3Term to free resources.
3382 *
3383 * ASSUMES that the caller owns the PGM lock.
3384 *
3385 * @param pVM The VM handle.
3386 */
3387void pgmR3PhysRomTerm(PVM pVM)
3388{
3389#ifdef RT_STRICT
3390 /*
3391 * Free the heap copy of the original bits.
3392 */
3393 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)
3394 {
3395 if ( pRom->pvOriginal
3396 && !(pRom->fFlags & PGMPHYS_ROM_FLAGS_PERMANENT_BINARY))
3397 {
3398 RTMemFree((void *)pRom->pvOriginal);
3399 pRom->pvOriginal = NULL;
3400 }
3401 }
3402#endif
3403}
3404
3405
3406/**
3407 * Change the shadowing of a range of ROM pages.
3408 *
3409 * This is intended for implementing chipset specific memory registers
3410 * and will not be very strict about the input. It will silently ignore
3411 * any pages that are not the part of a shadowed ROM.
3412 *
3413 * @returns VBox status code.
3414 * @retval VINF_PGM_SYNC_CR3
3415 *
3416 * @param pVM Pointer to the shared VM structure.
3417 * @param GCPhys Where to start. Page aligned.
3418 * @param cb How much to change. Page aligned.
3419 * @param enmProt The new ROM protection.
3420 */
3421VMMR3DECL(int) PGMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMROMPROT enmProt)
3422{
3423 /*
3424 * Check input
3425 */
3426 if (!cb)
3427 return VINF_SUCCESS;
3428 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
3429 AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
3430 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
3431 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
3432 AssertReturn(enmProt >= PGMROMPROT_INVALID && enmProt <= PGMROMPROT_END, VERR_INVALID_PARAMETER);
3433
3434 /*
3435 * Process the request.
3436 */
3437 pgmLock(pVM);
3438 int rc = VINF_SUCCESS;
3439 bool fFlushTLB = false;
3440 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)
3441 {
3442 if ( GCPhys <= pRom->GCPhysLast
3443 && GCPhysLast >= pRom->GCPhys
3444 && (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED))
3445 {
3446 /*
3447 * Iterate the relevant pages and make necessary the changes.
3448 */
3449 bool fChanges = false;
3450 uint32_t const cPages = pRom->GCPhysLast <= GCPhysLast
3451 ? pRom->cb >> PAGE_SHIFT
3452 : (GCPhysLast - pRom->GCPhys + 1) >> PAGE_SHIFT;
3453 for (uint32_t iPage = (GCPhys - pRom->GCPhys) >> PAGE_SHIFT;
3454 iPage < cPages;
3455 iPage++)
3456 {
3457 PPGMROMPAGE pRomPage = &pRom->aPages[iPage];
3458 if (PGMROMPROT_IS_ROM(pRomPage->enmProt) != PGMROMPROT_IS_ROM(enmProt))
3459 {
3460 fChanges = true;
3461
3462 /* flush references to the page. */
3463 PPGMPAGE pRamPage = pgmPhysGetPage(pVM, pRom->GCPhys + (iPage << PAGE_SHIFT));
3464 int rc2 = pgmPoolTrackUpdateGCPhys(pVM, pRom->GCPhys + (iPage << PAGE_SHIFT), pRamPage,
3465 true /*fFlushPTEs*/, &fFlushTLB);
3466 if (rc2 != VINF_SUCCESS && (rc == VINF_SUCCESS || RT_FAILURE(rc2)))
3467 rc = rc2;
3468
3469 PPGMPAGE pOld = PGMROMPROT_IS_ROM(pRomPage->enmProt) ? &pRomPage->Virgin : &pRomPage->Shadow;
3470 PPGMPAGE pNew = PGMROMPROT_IS_ROM(pRomPage->enmProt) ? &pRomPage->Shadow : &pRomPage->Virgin;
3471
3472 *pOld = *pRamPage;
3473 *pRamPage = *pNew;
3474 /** @todo preserve the volatile flags (handlers) when these have been moved out of HCPhys! */
3475 }
3476 pRomPage->enmProt = enmProt;
3477 }
3478
3479 /*
3480 * Reset the access handler if we made changes, no need
3481 * to optimize this.
3482 */
3483 if (fChanges)
3484 {
3485 int rc2 = PGMHandlerPhysicalReset(pVM, pRom->GCPhys);
3486 if (RT_FAILURE(rc2))
3487 {
3488 pgmUnlock(pVM);
3489 AssertRC(rc);
3490 return rc2;
3491 }
3492 }
3493
3494 /* Advance - cb isn't updated. */
3495 GCPhys = pRom->GCPhys + (cPages << PAGE_SHIFT);
3496 }
3497 }
3498 pgmUnlock(pVM);
3499 if (fFlushTLB)
3500 PGM_INVL_ALL_VCPU_TLBS(pVM);
3501
3502 return rc;
3503}
3504
3505
3506/**
3507 * Sets the Address Gate 20 state.
3508 *
3509 * @param pVCpu The VCPU to operate on.
3510 * @param fEnable True if the gate should be enabled.
3511 * False if the gate should be disabled.
3512 */
3513VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable)
3514{
3515 LogFlow(("PGMR3PhysSetA20 %d (was %d)\n", fEnable, pVCpu->pgm.s.fA20Enabled));
3516 if (pVCpu->pgm.s.fA20Enabled != fEnable)
3517 {
3518 pVCpu->pgm.s.fA20Enabled = fEnable;
3519 pVCpu->pgm.s.GCPhysA20Mask = ~(RTGCPHYS)(!fEnable << 20);
3520 REMR3A20Set(pVCpu->pVMR3, pVCpu, fEnable);
3521 /** @todo we're not handling this correctly for VT-x / AMD-V. See #2911 */
3522 }
3523}
3524
3525#ifdef PGM_WITH_LARGE_ADDRESS_SPACE_ON_32_BIT_HOST
3526/**
3527 * Tree enumeration callback for dealing with age rollover.
3528 * It will perform a simple compression of the current age.
3529 */
3530static DECLCALLBACK(int) pgmR3PhysChunkAgeingRolloverCallback(PAVLU32NODECORE pNode, void *pvUser)
3531{
3532 Assert(PGMIsLockOwner((PVM)pvUser));
3533 /* Age compression - ASSUMES iNow == 4. */
3534 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)pNode;
3535 if (pChunk->iAge >= UINT32_C(0xffffff00))
3536 pChunk->iAge = 3;
3537 else if (pChunk->iAge >= UINT32_C(0xfffff000))
3538 pChunk->iAge = 2;
3539 else if (pChunk->iAge)
3540 pChunk->iAge = 1;
3541 else /* iAge = 0 */
3542 pChunk->iAge = 4;
3543 return 0;
3544}
3545
3546
3547/**
3548 * Tree enumeration callback that updates the chunks that have
3549 * been used since the last
3550 */
3551static DECLCALLBACK(int) pgmR3PhysChunkAgeingCallback(PAVLU32NODECORE pNode, void *pvUser)
3552{
3553 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)pNode;
3554 if (!pChunk->iAge)
3555 {
3556 PVM pVM = (PVM)pvUser;
3557 pChunk->iAge = pVM->pgm.s.ChunkR3Map.iNow;
3558 }
3559 return 0;
3560}
3561
3562
3563/**
3564 * Performs ageing of the ring-3 chunk mappings.
3565 *
3566 * @param pVM The VM handle.
3567 */
3568VMMR3DECL(void) PGMR3PhysChunkAgeing(PVM pVM)
3569{
3570 pgmLock(pVM);
3571 pVM->pgm.s.ChunkR3Map.AgeingCountdown = RT_MIN(pVM->pgm.s.ChunkR3Map.cMax / 4, 1024);
3572 pVM->pgm.s.ChunkR3Map.iNow++;
3573 if (pVM->pgm.s.ChunkR3Map.iNow == 0)
3574 {
3575 pVM->pgm.s.ChunkR3Map.iNow = 4;
3576 RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkAgeingRolloverCallback, pVM);
3577 }
3578 else
3579 RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkAgeingCallback, pVM);
3580 pgmUnlock(pVM);
3581}
3582
3583
3584/**
3585 * The structure passed in the pvUser argument of pgmR3PhysChunkUnmapCandidateCallback().
3586 */
3587typedef struct PGMR3PHYSCHUNKUNMAPCB
3588{
3589 PVM pVM; /**< The VM handle. */
3590 PPGMCHUNKR3MAP pChunk; /**< The chunk to unmap. */
3591 uint32_t iLastAge; /**< Highest age found so far. */
3592} PGMR3PHYSCHUNKUNMAPCB, *PPGMR3PHYSCHUNKUNMAPCB;
3593
3594
3595/**
3596 * Callback used to find the mapping that's been unused for
3597 * the longest time.
3598 */
3599static DECLCALLBACK(int) pgmR3PhysChunkUnmapCandidateCallback(PAVLU32NODECORE pNode, void *pvUser)
3600{
3601 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)pNode;
3602 PPGMR3PHYSCHUNKUNMAPCB pArg = (PPGMR3PHYSCHUNKUNMAPCB)pvUser;
3603
3604 if ( pChunk->iAge
3605 && !pChunk->cRefs
3606 && pArg->iLastAge < pChunk->iAge)
3607 {
3608 /*
3609 * Check that it's not in any of the TLBs.
3610 */
3611 PVM pVM = pArg->pVM;
3612 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.ChunkR3Map.Tlb.aEntries); i++)
3613 if (pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].pChunk == pChunk)
3614 {
3615 pChunk = NULL;
3616 break;
3617 }
3618 if (pChunk)
3619 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.PhysTlbHC.aEntries); i++)
3620 if (pVM->pgm.s.PhysTlbHC.aEntries[i].pMap == pChunk)
3621 {
3622 pChunk = NULL;
3623 break;
3624 }
3625 if (pChunk)
3626 {
3627 pArg->pChunk = pChunk;
3628 pArg->iLastAge = pChunk->iAge;
3629 }
3630 }
3631 return 0;
3632}
3633
3634
3635/**
3636 * Finds a good candidate for unmapping when the ring-3 mapping cache is full.
3637 *
3638 * The candidate will not be part of any TLBs, so no need to flush
3639 * anything afterwards.
3640 *
3641 * @returns Chunk id.
3642 * @param pVM The VM handle.
3643 */
3644static int32_t pgmR3PhysChunkFindUnmapCandidate(PVM pVM)
3645{
3646 Assert(PGMIsLockOwner(pVM));
3647
3648 /*
3649 * Do tree ageing first?
3650 */
3651 if (pVM->pgm.s.ChunkR3Map.AgeingCountdown-- == 0)
3652 {
3653 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkAging, a);
3654 PGMR3PhysChunkAgeing(pVM);
3655 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkAging, a);
3656 }
3657
3658 /*
3659 * Enumerate the age tree starting with the left most node.
3660 */
3661 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkFindCandidate, a);
3662 PGMR3PHYSCHUNKUNMAPCB Args;
3663 Args.pVM = pVM;
3664 Args.pChunk = NULL;
3665 Args.iLastAge = 0;
3666 RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkUnmapCandidateCallback, &Args);
3667 Assert(Args.pChunk);
3668 if (Args.pChunk)
3669 {
3670 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkFindCandidate, a);
3671 return Args.pChunk->Core.Key;
3672 }
3673
3674 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkFindCandidate, a);
3675 return INT32_MAX;
3676}
3677
3678/**
3679 * Rendezvous callback used by pgmR3PhysUnmapChunk that unmaps a chunk
3680 *
3681 * This is only called on one of the EMTs while the other ones are waiting for
3682 * it to complete this function.
3683 *
3684 * @returns VINF_SUCCESS (VBox strict status code).
3685 * @param pVM The VM handle.
3686 * @param pVCpu The VMCPU for the EMT we're being called on. Unused.
3687 * @param pvUser User pointer. Unused
3688 *
3689 */
3690DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysUnmapChunkRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
3691{
3692 int rc = VINF_SUCCESS;
3693 pgmLock(pVM);
3694
3695 if (pVM->pgm.s.ChunkR3Map.c >= pVM->pgm.s.ChunkR3Map.cMax)
3696 {
3697 /* Flush the pgm pool cache; call the internal rendezvous handler as we're already in a rendezvous handler here. */
3698 /* todo: also not really efficient to unmap a chunk that contains PD or PT pages. */
3699 pgmR3PoolClearAllRendezvous(pVM, &pVM->aCpus[0], NULL /* no need to flush the REM TLB as we already did that above */);
3700
3701 /*
3702 * Request the ring-0 part to unmap a chunk to make space in the mapping cache.
3703 */
3704 GMMMAPUNMAPCHUNKREQ Req;
3705 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
3706 Req.Hdr.cbReq = sizeof(Req);
3707 Req.pvR3 = NULL;
3708 Req.idChunkMap = NIL_GMM_CHUNKID;
3709 Req.idChunkUnmap = pgmR3PhysChunkFindUnmapCandidate(pVM);
3710
3711 if (Req.idChunkUnmap != INT32_MAX)
3712 {
3713 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkUnmap, a);
3714 rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
3715 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkUnmap, a);
3716 if (RT_SUCCESS(rc))
3717 {
3718 /* remove the unmapped one. */
3719 PPGMCHUNKR3MAP pUnmappedChunk = (PPGMCHUNKR3MAP)RTAvlU32Remove(&pVM->pgm.s.ChunkR3Map.pTree, Req.idChunkUnmap);
3720 AssertRelease(pUnmappedChunk);
3721 pUnmappedChunk->pv = NULL;
3722 pUnmappedChunk->Core.Key = UINT32_MAX;
3723#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3724 MMR3HeapFree(pUnmappedChunk);
3725#else
3726 MMR3UkHeapFree(pVM, pUnmappedChunk, MM_TAG_PGM_CHUNK_MAPPING);
3727#endif
3728 pVM->pgm.s.ChunkR3Map.c--;
3729 pVM->pgm.s.cUnmappedChunks++;
3730
3731 /* Flush dangling PGM pointers (R3 & R0 ptrs to GC physical addresses) */
3732 /* todo: we should not flush chunks which include cr3 mappings. */
3733 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
3734 {
3735 PPGMCPU pPGM = &pVM->aCpus[idCpu].pgm.s;
3736
3737 pPGM->pGst32BitPdR3 = NULL;
3738 pPGM->pGstPaePdptR3 = NULL;
3739 pPGM->pGstAmd64Pml4R3 = NULL;
3740#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
3741 pPGM->pGst32BitPdR0 = NIL_RTR0PTR;
3742 pPGM->pGstPaePdptR0 = NIL_RTR0PTR;
3743 pPGM->pGstAmd64Pml4R0 = NIL_RTR0PTR;
3744#endif
3745 for (unsigned i = 0; i < RT_ELEMENTS(pPGM->apGstPaePDsR3); i++)
3746 {
3747 pPGM->apGstPaePDsR3[i] = NULL;
3748#ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
3749 pPGM->apGstPaePDsR0[i] = NIL_RTR0PTR;
3750#endif
3751 }
3752
3753 /* Flush REM TLBs. */
3754 CPUMSetChangedFlags(&pVM->aCpus[idCpu], CPUM_CHANGED_GLOBAL_TLB_FLUSH);
3755 }
3756
3757 /* Flush REM translation blocks. */
3758 REMFlushTBs(pVM);
3759 }
3760 }
3761 }
3762 pgmUnlock(pVM);
3763 return rc;
3764}
3765
3766/**
3767 * Unmap a chunk to free up virtual address space (request packet handler for pgmR3PhysChunkMap)
3768 *
3769 * @returns VBox status code.
3770 * @param pVM The VM to operate on.
3771 */
3772void pgmR3PhysUnmapChunk(PVM pVM)
3773{
3774 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysUnmapChunkRendezvous, NULL);
3775 AssertRC(rc);
3776}
3777#endif /* PGM_WITH_LARGE_ADDRESS_SPACE_ON_32_BIT_HOST */
3778
3779/**
3780 * Maps the given chunk into the ring-3 mapping cache.
3781 *
3782 * This will call ring-0.
3783 *
3784 * @returns VBox status code.
3785 * @param pVM The VM handle.
3786 * @param idChunk The chunk in question.
3787 * @param ppChunk Where to store the chunk tracking structure.
3788 *
3789 * @remarks Called from within the PGM critical section.
3790 * @remarks Can be called from any thread!
3791 */
3792int pgmR3PhysChunkMap(PVM pVM, uint32_t idChunk, PPPGMCHUNKR3MAP ppChunk)
3793{
3794 int rc;
3795
3796 Assert(PGMIsLockOwner(pVM));
3797 /*
3798 * Allocate a new tracking structure first.
3799 */
3800#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3801 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)MMR3HeapAllocZ(pVM, MM_TAG_PGM_CHUNK_MAPPING, sizeof(*pChunk));
3802#else
3803 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)MMR3UkHeapAllocZ(pVM, MM_TAG_PGM_CHUNK_MAPPING, sizeof(*pChunk), NULL);
3804#endif
3805 AssertReturn(pChunk, VERR_NO_MEMORY);
3806 pChunk->Core.Key = idChunk;
3807
3808 /*
3809 * Request the ring-0 part to map the chunk in question.
3810 */
3811 GMMMAPUNMAPCHUNKREQ Req;
3812 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
3813 Req.Hdr.cbReq = sizeof(Req);
3814 Req.pvR3 = NULL;
3815 Req.idChunkMap = idChunk;
3816 Req.idChunkUnmap = NIL_GMM_CHUNKID;
3817
3818 /* Must be callable from any thread, so can't use VMMR3CallR0. */
3819 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkMap, a);
3820 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, NIL_VMCPUID, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
3821 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatChunkMap, a);
3822 if (RT_SUCCESS(rc))
3823 {
3824 /*
3825 * Update the tree.
3826 */
3827 /* insert the new one. */
3828 AssertPtr(Req.pvR3);
3829 pChunk->pv = Req.pvR3;
3830 bool fRc = RTAvlU32Insert(&pVM->pgm.s.ChunkR3Map.pTree, &pChunk->Core);
3831 AssertRelease(fRc);
3832 pVM->pgm.s.ChunkR3Map.c++;
3833 pVM->pgm.s.cMappedChunks++;
3834
3835 /* If we're running out of virtual address space, then we should unmap another chunk. */
3836 if (pVM->pgm.s.ChunkR3Map.c >= pVM->pgm.s.ChunkR3Map.cMax)
3837 {
3838#ifdef PGM_WITH_LARGE_ADDRESS_SPACE_ON_32_BIT_HOST
3839 /* Postpone the unmap operation (which requires a rendezvous operation) as we own the PGM lock here. */
3840 rc = VMR3ReqCallNoWaitU(pVM->pUVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3PhysUnmapChunk, 1, pVM);
3841 AssertRC(rc);
3842#else
3843 AssertFatalFailed(); /* can't happen */
3844#endif
3845 }
3846 }
3847 else
3848 {
3849 AssertRC(rc);
3850#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3851 MMR3HeapFree(pChunk);
3852#else
3853 MMR3UkHeapFree(pVM, pChunk, MM_TAG_PGM_CHUNK_MAPPING);
3854#endif
3855 pChunk = NULL;
3856 }
3857
3858 *ppChunk = pChunk;
3859 return rc;
3860}
3861
3862
3863/**
3864 * For VMMCALLRING3_PGM_MAP_CHUNK, considered internal.
3865 *
3866 * @returns see pgmR3PhysChunkMap.
3867 * @param pVM The VM handle.
3868 * @param idChunk The chunk to map.
3869 */
3870VMMR3DECL(int) PGMR3PhysChunkMap(PVM pVM, uint32_t idChunk)
3871{
3872 PPGMCHUNKR3MAP pChunk;
3873 int rc;
3874
3875 pgmLock(pVM);
3876 rc = pgmR3PhysChunkMap(pVM, idChunk, &pChunk);
3877 pgmUnlock(pVM);
3878 return rc;
3879}
3880
3881
3882/**
3883 * Invalidates the TLB for the ring-3 mapping cache.
3884 *
3885 * @param pVM The VM handle.
3886 */
3887VMMR3DECL(void) PGMR3PhysChunkInvalidateTLB(PVM pVM)
3888{
3889 pgmLock(pVM);
3890 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.ChunkR3Map.Tlb.aEntries); i++)
3891 {
3892 pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].idChunk = NIL_GMM_CHUNKID;
3893 pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].pChunk = NULL;
3894 }
3895 /* The page map TLB references chunks, so invalidate that one too. */
3896 PGMPhysInvalidatePageMapTLB(pVM);
3897 pgmUnlock(pVM);
3898}
3899
3900
3901/**
3902 * Response to VMMCALLRING3_PGM_ALLOCATE_LARGE_PAGE to allocate a large (2MB) page
3903 * for use with a nested paging PDE.
3904 *
3905 * @returns The following VBox status codes.
3906 * @retval VINF_SUCCESS on success.
3907 * @retval VINF_EM_NO_MEMORY if we're out of memory.
3908 *
3909 * @param pVM The VM handle.
3910 * @param GCPhys GC physical start address of the 2 MB range
3911 */
3912VMMR3DECL(int) PGMR3PhysAllocateLargeHandyPage(PVM pVM, RTGCPHYS GCPhys)
3913{
3914#ifdef PGM_WITH_LARGE_PAGES
3915 uint64_t u64TimeStamp1, u64TimeStamp2;
3916
3917 pgmLock(pVM);
3918
3919 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->StatAllocLargePage, a);
3920 u64TimeStamp1 = RTTimeMilliTS();
3921 int rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_ALLOCATE_LARGE_HANDY_PAGE, 0, NULL);
3922 u64TimeStamp2 = RTTimeMilliTS();
3923 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatAllocLargePage, a);
3924 if (RT_SUCCESS(rc))
3925 {
3926 Assert(pVM->pgm.s.cLargeHandyPages == 1);
3927
3928 uint32_t idPage = pVM->pgm.s.aLargeHandyPage[0].idPage;
3929 RTHCPHYS HCPhys = pVM->pgm.s.aLargeHandyPage[0].HCPhysGCPhys;
3930
3931 void *pv;
3932
3933 /* Map the large page into our address space.
3934 *
3935 * Note: assuming that within the 2 MB range:
3936 * - GCPhys + PAGE_SIZE = HCPhys + PAGE_SIZE (whole point of this exercise)
3937 * - user space mapping is continuous as well
3938 * - page id (GCPhys) + 1 = page id (GCPhys + PAGE_SIZE)
3939 */
3940 rc = pgmPhysPageMapByPageID(pVM, idPage, HCPhys, &pv);
3941 AssertLogRelMsg(RT_SUCCESS(rc), ("idPage=%#x HCPhysGCPhys=%RHp rc=%Rrc\n", idPage, HCPhys, rc));
3942
3943 if (RT_SUCCESS(rc))
3944 {
3945 /*
3946 * Clear the pages.
3947 */
3948 STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pStats)->StatClearLargePage, b);
3949 for (unsigned i = 0; i < _2M/PAGE_SIZE; i++)
3950 {
3951 ASMMemZeroPage(pv);
3952
3953 PPGMPAGE pPage;
3954 rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage);
3955 AssertRC(rc);
3956
3957 Assert(PGM_PAGE_IS_ZERO(pPage));
3958 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatRZPageReplaceZero);
3959 pVM->pgm.s.cZeroPages--;
3960
3961 /*
3962 * Do the PGMPAGE modifications.
3963 */
3964 pVM->pgm.s.cPrivatePages++;
3965 PGM_PAGE_SET_HCPHYS(pPage, HCPhys);
3966 PGM_PAGE_SET_PAGEID(pPage, idPage);
3967 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ALLOCATED);
3968 PGM_PAGE_SET_PDE_TYPE(pPage, PGM_PAGE_PDE_TYPE_PDE);
3969 PGM_PAGE_SET_PTE_INDEX(pPage, 0);
3970 PGM_PAGE_SET_TRACKING(pPage, 0);
3971
3972 /* Somewhat dirty assumption that page ids are increasing. */
3973 idPage++;
3974
3975 HCPhys += PAGE_SIZE;
3976 GCPhys += PAGE_SIZE;
3977
3978 pv = (void *)((uintptr_t)pv + PAGE_SIZE);
3979
3980 Log3(("PGMR3PhysAllocateLargePage: idPage=%#x HCPhys=%RGp\n", idPage, HCPhys));
3981 }
3982 STAM_PROFILE_STOP(&pVM->pgm.s.CTX_SUFF(pStats)->StatClearLargePage, b);
3983
3984 /* Flush all TLBs. */
3985 PGM_INVL_ALL_VCPU_TLBS(pVM);
3986 PGMPhysInvalidatePageMapTLB(pVM);
3987 }
3988 pVM->pgm.s.cLargeHandyPages = 0;
3989 }
3990
3991 if (RT_SUCCESS(rc))
3992 {
3993 static uint32_t cTimeOut = 0;
3994 uint64_t u64TimeStampDelta = u64TimeStamp2 - u64TimeStamp1;
3995
3996 if (u64TimeStampDelta > 100)
3997 {
3998 STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->StatLargePageOverflow);
3999 if ( ++cTimeOut > 10
4000 || u64TimeStampDelta > 1000 /* more than one second forces an early retirement from allocating large pages. */)
4001 {
4002 /* If repeated attempts to allocate a large page takes more than 100 ms, then we fall back to normal 4k pages.
4003 * E.g. Vista 64 tries to move memory around, which takes a huge amount of time.
4004 */
4005 LogRel(("PGMR3PhysAllocateLargePage: allocating large pages takes too long (last attempt %d ms; nr of timeouts %d); DISABLE\n", u64TimeStampDelta, cTimeOut));
4006 PGMSetLargePageUsage(pVM, false);
4007 }
4008 }
4009 else
4010 if (cTimeOut > 0)
4011 cTimeOut--;
4012 }
4013
4014 pgmUnlock(pVM);
4015 return rc;
4016#else
4017 return VERR_NOT_IMPLEMENTED;
4018#endif /* PGM_WITH_LARGE_PAGES */
4019}
4020
4021
4022/**
4023 * Response to VM_FF_PGM_NEED_HANDY_PAGES and VMMCALLRING3_PGM_ALLOCATE_HANDY_PAGES.
4024 *
4025 * This function will also work the VM_FF_PGM_NO_MEMORY force action flag, to
4026 * signal and clear the out of memory condition. When contracted, this API is
4027 * used to try clear the condition when the user wants to resume.
4028 *
4029 * @returns The following VBox status codes.
4030 * @retval VINF_SUCCESS on success. FFs cleared.
4031 * @retval VINF_EM_NO_MEMORY if we're out of memory. The FF is not cleared in
4032 * this case and it gets accompanied by VM_FF_PGM_NO_MEMORY.
4033 *
4034 * @param pVM The VM handle.
4035 *
4036 * @remarks The VINF_EM_NO_MEMORY status is for the benefit of the FF processing
4037 * in EM.cpp and shouldn't be propagated outside TRPM, HWACCM, EM and
4038 * pgmPhysEnsureHandyPage. There is one exception to this in the \#PF
4039 * handler.
4040 */
4041VMMR3DECL(int) PGMR3PhysAllocateHandyPages(PVM pVM)
4042{
4043 pgmLock(pVM);
4044
4045 /*
4046 * Allocate more pages, noting down the index of the first new page.
4047 */
4048 uint32_t iClear = pVM->pgm.s.cHandyPages;
4049 AssertMsgReturn(iClear <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), ("%d", iClear), VERR_INTERNAL_ERROR);
4050 Log(("PGMR3PhysAllocateHandyPages: %d -> %d\n", iClear, RT_ELEMENTS(pVM->pgm.s.aHandyPages)));
4051 int rcAlloc = VINF_SUCCESS;
4052 int rcSeed = VINF_SUCCESS;
4053 int rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES, 0, NULL);
4054 while (rc == VERR_GMM_SEED_ME)
4055 {
4056 void *pvChunk;
4057 rcAlloc = rc = SUPR3PageAlloc(GMM_CHUNK_SIZE >> PAGE_SHIFT, &pvChunk);
4058 if (RT_SUCCESS(rc))
4059 {
4060 rcSeed = rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_SEED_CHUNK, (uintptr_t)pvChunk, NULL);
4061 if (RT_FAILURE(rc))
4062 SUPR3PageFree(pvChunk, GMM_CHUNK_SIZE >> PAGE_SHIFT);
4063 }
4064 if (RT_SUCCESS(rc))
4065 rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES, 0, NULL);
4066 }
4067
4068 /* 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) */
4069 if ( rc == VERR_GMM_HIT_VM_ACCOUNT_LIMIT
4070 && pVM->pgm.s.cHandyPages > 0)
4071 {
4072 /* Still handy pages left, so don't panic. */
4073 rc = VINF_SUCCESS;
4074 }
4075
4076 if (RT_SUCCESS(rc))
4077 {
4078 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
4079 Assert(pVM->pgm.s.cHandyPages > 0);
4080 VM_FF_CLEAR(pVM, VM_FF_PGM_NEED_HANDY_PAGES);
4081 VM_FF_CLEAR(pVM, VM_FF_PGM_NO_MEMORY);
4082
4083 /*
4084 * Clear the pages.
4085 */
4086 while (iClear < pVM->pgm.s.cHandyPages)
4087 {
4088 PGMMPAGEDESC pPage = &pVM->pgm.s.aHandyPages[iClear];
4089 void *pv;
4090 rc = pgmPhysPageMapByPageID(pVM, pPage->idPage, pPage->HCPhysGCPhys, &pv);
4091 AssertLogRelMsgBreak(RT_SUCCESS(rc), ("idPage=%#x HCPhysGCPhys=%RHp rc=%Rrc\n", pPage->idPage, pPage->HCPhysGCPhys, rc));
4092 ASMMemZeroPage(pv);
4093 iClear++;
4094 Log3(("PGMR3PhysAllocateHandyPages: idPage=%#x HCPhys=%RGp\n", pPage->idPage, pPage->HCPhysGCPhys));
4095 }
4096 }
4097 else
4098 {
4099 uint64_t cAllocPages, cMaxPages, cBalloonPages;
4100
4101 /*
4102 * We should never get here unless there is a genuine shortage of
4103 * memory (or some internal error). Flag the error so the VM can be
4104 * suspended ASAP and the user informed. If we're totally out of
4105 * handy pages we will return failure.
4106 */
4107 /* Report the failure. */
4108 LogRel(("PGM: Failed to procure handy pages; rc=%Rrc rcAlloc=%Rrc rcSeed=%Rrc cHandyPages=%#x\n"
4109 " cAllPages=%#x cPrivatePages=%#x cSharedPages=%#x cZeroPages=%#x\n",
4110 rc, rcAlloc, rcSeed,
4111 pVM->pgm.s.cHandyPages,
4112 pVM->pgm.s.cAllPages,
4113 pVM->pgm.s.cPrivatePages,
4114 pVM->pgm.s.cSharedPages,
4115 pVM->pgm.s.cZeroPages));
4116
4117 if (GMMR3QueryMemoryStats(pVM, &cAllocPages, &cMaxPages, &cBalloonPages) == VINF_SUCCESS)
4118 {
4119 LogRel(("GMM: Statistics:\n"
4120 " Allocated pages: %RX64\n"
4121 " Maximum pages: %RX64\n"
4122 " Ballooned pages: %RX64\n", cAllocPages, cMaxPages, cBalloonPages));
4123 }
4124
4125 if ( rc != VERR_NO_MEMORY
4126 && rc != VERR_LOCK_FAILED)
4127 {
4128 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
4129 {
4130 LogRel(("PGM: aHandyPages[#%#04x] = {.HCPhysGCPhys=%RHp, .idPage=%#08x, .idSharedPage=%#08x}\n",
4131 i, pVM->pgm.s.aHandyPages[i].HCPhysGCPhys, pVM->pgm.s.aHandyPages[i].idPage,
4132 pVM->pgm.s.aHandyPages[i].idSharedPage));
4133 uint32_t const idPage = pVM->pgm.s.aHandyPages[i].idPage;
4134 if (idPage != NIL_GMM_PAGEID)
4135 {
4136 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR3;
4137 pRam;
4138 pRam = pRam->pNextR3)
4139 {
4140 uint32_t const cPages = pRam->cb >> PAGE_SHIFT;
4141 for (uint32_t iPage = 0; iPage < cPages; iPage++)
4142 if (PGM_PAGE_GET_PAGEID(&pRam->aPages[iPage]) == idPage)
4143 LogRel(("PGM: Used by %RGp %R[pgmpage] (%s)\n",
4144 pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), &pRam->aPages[iPage], pRam->pszDesc));
4145 }
4146 }
4147 }
4148 }
4149
4150 /* Set the FFs and adjust rc. */
4151 VM_FF_SET(pVM, VM_FF_PGM_NEED_HANDY_PAGES);
4152 VM_FF_SET(pVM, VM_FF_PGM_NO_MEMORY);
4153 if ( rc == VERR_NO_MEMORY
4154 || rc == VERR_LOCK_FAILED)
4155 rc = VINF_EM_NO_MEMORY;
4156 }
4157
4158 pgmUnlock(pVM);
4159 return rc;
4160}
4161
4162
4163/**
4164 * Frees the specified RAM page and replaces it with the ZERO page.
4165 *
4166 * This is used by ballooning, remapping MMIO2, RAM reset and state loading.
4167 *
4168 * @param pVM Pointer to the shared VM structure.
4169 * @param pReq Pointer to the request.
4170 * @param pcPendingPages Where the number of pages waiting to be freed are
4171 * kept. This will normally be incremented.
4172 * @param pPage Pointer to the page structure.
4173 * @param GCPhys The guest physical address of the page, if applicable.
4174 *
4175 * @remarks The caller must own the PGM lock.
4176 */
4177int pgmPhysFreePage(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t *pcPendingPages, PPGMPAGE pPage, RTGCPHYS GCPhys)
4178{
4179 /*
4180 * Assert sanity.
4181 */
4182 Assert(PGMIsLockOwner(pVM));
4183 if (RT_UNLIKELY( PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_RAM
4184 && PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_ROM_SHADOW))
4185 {
4186 AssertMsgFailed(("GCPhys=%RGp pPage=%R[pgmpage]\n", GCPhys, pPage));
4187 return VMSetError(pVM, VERR_PGM_PHYS_NOT_RAM, RT_SRC_POS, "GCPhys=%RGp type=%d", GCPhys, PGM_PAGE_GET_TYPE(pPage));
4188 }
4189
4190 /** @todo What about ballooning of large pages??! */
4191 Assert( PGM_PAGE_GET_PDE_TYPE(pPage) != PGM_PAGE_PDE_TYPE_PDE
4192 && PGM_PAGE_GET_PDE_TYPE(pPage) != PGM_PAGE_PDE_TYPE_PDE_DISABLED);
4193
4194 if ( PGM_PAGE_IS_ZERO(pPage)
4195 || PGM_PAGE_IS_BALLOONED(pPage))
4196 return VINF_SUCCESS;
4197
4198 const uint32_t idPage = PGM_PAGE_GET_PAGEID(pPage);
4199 Log3(("pgmPhysFreePage: idPage=%#x GCPhys=%RGp pPage=%R[pgmpage]\n", idPage, GCPhys, pPage));
4200 if (RT_UNLIKELY( idPage == NIL_GMM_PAGEID
4201 || idPage > GMM_PAGEID_LAST
4202 || PGM_PAGE_GET_CHUNKID(pPage) == NIL_GMM_CHUNKID))
4203 {
4204 AssertMsgFailed(("GCPhys=%RGp pPage=%R[pgmpage]\n", GCPhys, pPage));
4205 return VMSetError(pVM, VERR_PGM_PHYS_INVALID_PAGE_ID, RT_SRC_POS, "GCPhys=%RGp idPage=%#x", GCPhys, pPage);
4206 }
4207
4208 /* update page count stats. */
4209 if (PGM_PAGE_IS_SHARED(pPage))
4210 pVM->pgm.s.cSharedPages--;
4211 else
4212 pVM->pgm.s.cPrivatePages--;
4213 pVM->pgm.s.cZeroPages++;
4214
4215 /* Deal with write monitored pages. */
4216 if (PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED)
4217 {
4218 PGM_PAGE_SET_WRITTEN_TO(pPage);
4219 pVM->pgm.s.cWrittenToPages++;
4220 }
4221
4222 /*
4223 * pPage = ZERO page.
4224 */
4225 PGM_PAGE_SET_HCPHYS(pPage, pVM->pgm.s.HCPhysZeroPg);
4226 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ZERO);
4227 PGM_PAGE_SET_PAGEID(pPage, NIL_GMM_PAGEID);
4228 PGM_PAGE_SET_PDE_TYPE(pPage, PGM_PAGE_PDE_TYPE_DONTCARE);
4229 PGM_PAGE_SET_PTE_INDEX(pPage, 0);
4230 PGM_PAGE_SET_TRACKING(pPage, 0);
4231
4232 /* Flush physical page map TLB entry. */
4233 PGMPhysInvalidatePageMapTLBEntry(pVM, GCPhys);
4234
4235 /*
4236 * Make sure it's not in the handy page array.
4237 */
4238 for (uint32_t i = pVM->pgm.s.cHandyPages; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
4239 {
4240 if (pVM->pgm.s.aHandyPages[i].idPage == idPage)
4241 {
4242 pVM->pgm.s.aHandyPages[i].idPage = NIL_GMM_PAGEID;
4243 break;
4244 }
4245 if (pVM->pgm.s.aHandyPages[i].idSharedPage == idPage)
4246 {
4247 pVM->pgm.s.aHandyPages[i].idSharedPage = NIL_GMM_PAGEID;
4248 break;
4249 }
4250 }
4251
4252 /*
4253 * Push it onto the page array.
4254 */
4255 uint32_t iPage = *pcPendingPages;
4256 Assert(iPage < PGMPHYS_FREE_PAGE_BATCH_SIZE);
4257 *pcPendingPages += 1;
4258
4259 pReq->aPages[iPage].idPage = idPage;
4260
4261 if (iPage + 1 < PGMPHYS_FREE_PAGE_BATCH_SIZE)
4262 return VINF_SUCCESS;
4263
4264 /*
4265 * Flush the pages.
4266 */
4267 int rc = GMMR3FreePagesPerform(pVM, pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE);
4268 if (RT_SUCCESS(rc))
4269 {
4270 GMMR3FreePagesRePrep(pVM, pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
4271 *pcPendingPages = 0;
4272 }
4273 return rc;
4274}
4275
4276
4277/**
4278 * Converts a GC physical address to a HC ring-3 pointer, with some
4279 * additional checks.
4280 *
4281 * @returns VBox status code.
4282 * @retval VINF_SUCCESS on success.
4283 * @retval VINF_PGM_PHYS_TLB_CATCH_WRITE and *ppv set if the page has a write
4284 * access handler of some kind.
4285 * @retval VERR_PGM_PHYS_TLB_CATCH_ALL if the page has a handler catching all
4286 * accesses or is odd in any way.
4287 * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist.
4288 *
4289 * @param pVM The VM handle.
4290 * @param GCPhys The GC physical address to convert.
4291 * @param fWritable Whether write access is required.
4292 * @param ppv Where to store the pointer corresponding to GCPhys on
4293 * success.
4294 */
4295VMMR3DECL(int) PGMR3PhysTlbGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, void **ppv)
4296{
4297 pgmLock(pVM);
4298
4299 PPGMRAMRANGE pRam;
4300 PPGMPAGE pPage;
4301 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
4302 if (RT_SUCCESS(rc))
4303 {
4304 if (PGM_PAGE_IS_BALLOONED(pPage))
4305 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
4306 else if (!PGM_PAGE_HAS_ANY_HANDLERS(pPage))
4307 rc = VINF_SUCCESS;
4308 else
4309 {
4310 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)) /* catches MMIO */
4311 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
4312 else if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
4313 {
4314 /** @todo Handle TLB loads of virtual handlers so ./test.sh can be made to work
4315 * in -norawr0 mode. */
4316 if (fWritable)
4317 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
4318 }
4319 else
4320 {
4321 /* Temporarily disabled physical handler(s), since the recompiler
4322 doesn't get notified when it's reset we'll have to pretend it's
4323 operating normally. */
4324 if (pgmHandlerPhysicalIsAll(pVM, GCPhys))
4325 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
4326 else
4327 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
4328 }
4329 }
4330 if (RT_SUCCESS(rc))
4331 {
4332 int rc2;
4333
4334 /* Make sure what we return is writable. */
4335 if (fWritable)
4336 switch (PGM_PAGE_GET_STATE(pPage))
4337 {
4338 case PGM_PAGE_STATE_ALLOCATED:
4339 break;
4340 case PGM_PAGE_STATE_BALLOONED:
4341 AssertFailed();
4342 break;
4343 case PGM_PAGE_STATE_ZERO:
4344 case PGM_PAGE_STATE_SHARED:
4345 if (rc == VINF_PGM_PHYS_TLB_CATCH_WRITE)
4346 break;
4347 case PGM_PAGE_STATE_WRITE_MONITORED:
4348 rc2 = pgmPhysPageMakeWritable(pVM, pPage, GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK);
4349 AssertLogRelRCReturn(rc2, rc2);
4350 break;
4351 }
4352
4353 /* Get a ring-3 mapping of the address. */
4354 PPGMPAGER3MAPTLBE pTlbe;
4355 rc2 = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
4356 AssertLogRelRCReturn(rc2, rc2);
4357 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & PAGE_OFFSET_MASK));
4358 /** @todo mapping/locking hell; this isn't horribly efficient since
4359 * pgmPhysPageLoadIntoTlb will repeat the lookup we've done here. */
4360
4361 Log6(("PGMR3PhysTlbGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage] *ppv=%p\n", GCPhys, rc, pPage, *ppv));
4362 }
4363 else
4364 Log6(("PGMR3PhysTlbGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage]\n", GCPhys, rc, pPage));
4365
4366 /* else: handler catching all access, no pointer returned. */
4367 }
4368 else
4369 rc = VERR_PGM_PHYS_TLB_UNASSIGNED;
4370
4371 pgmUnlock(pVM);
4372 return rc;
4373}
4374
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