VirtualBox

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

Last change on this file since 30231 was 30231, checked in by vboxsync, 15 years ago

Chunk mapping calls can arrive from any thread now because of page fusion (shared page already mapped into the address space, but ring-3
data not updated yet)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 138.8 KB
Line 
1/* $Id: PGMPhys.cpp 30231 2010-06-16 09:32:13Z 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/pgm.h>
24#include <VBox/iom.h>
25#include <VBox/mm.h>
26#include <VBox/stam.h>
27#include <VBox/rem.h>
28#include <VBox/pdmdev.h>
29#include "PGMInternal.h"
30#include <VBox/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
42
43/*******************************************************************************
44* Defined Constants And Macros *
45*******************************************************************************/
46/** The number of pages to free in one batch. */
47#define PGMPHYS_FREE_PAGE_BATCH_SIZE 128
48
49
50/*******************************************************************************
51* Internal Functions *
52*******************************************************************************/
53static DECLCALLBACK(int) pgmR3PhysRomWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
54static int pgmPhysFreePage(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t *pcPendingPages, PPGMPAGE pPage, RTGCPHYS GCPhys);
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 * Write to 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 write to.
104 * @param pvBuf What to write.
105 * @param cbWrite How many bytes to write.
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 = pVM->pgm.s.CTX_SUFF(pRamRanges);
122 for (;;)
123 {
124 /* Find range. */
125 while (pRam && GCPhys > pRam->GCPhysLast)
126 pRam = pRam->CTX_SUFF(pNext);
127 /* Inside range or not? */
128 if (pRam && GCPhys >= pRam->GCPhys)
129 {
130 /*
131 * Must work our way thru this page by page.
132 */
133 RTGCPHYS off = GCPhys - pRam->GCPhys;
134 while (off < pRam->cb)
135 {
136 unsigned iPage = off >> PAGE_SHIFT;
137 PPGMPAGE pPage = &pRam->aPages[iPage];
138
139 /*
140 * If the page has an ALL access handler, we'll have to
141 * delegate the job to EMT.
142 */
143 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
144 {
145 pgmUnlock(pVM);
146
147 return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysReadExternalEMT, 4,
148 pVM, &GCPhys, pvBuf, cbRead);
149 }
150 Assert(!PGM_PAGE_IS_MMIO(pPage));
151
152 /*
153 * Simple stuff, go ahead.
154 */
155 size_t cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
156 if (cb > cbRead)
157 cb = cbRead;
158 const void *pvSrc;
159 int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, pRam->GCPhys + off, &pvSrc);
160 if (RT_SUCCESS(rc))
161 memcpy(pvBuf, pvSrc, cb);
162 else
163 {
164 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
165 pRam->GCPhys + off, pPage, rc));
166 memset(pvBuf, 0xff, cb);
167 }
168
169 /* next page */
170 if (cb >= cbRead)
171 {
172 pgmUnlock(pVM);
173 return VINF_SUCCESS;
174 }
175 cbRead -= cb;
176 off += cb;
177 GCPhys += cb;
178 pvBuf = (char *)pvBuf + cb;
179 } /* walk pages in ram range. */
180 }
181 else
182 {
183 LogFlow(("PGMPhysRead: Unassigned %RGp size=%u\n", GCPhys, cbRead));
184
185 /*
186 * Unassigned address space.
187 */
188 if (!pRam)
189 break;
190 size_t cb = pRam->GCPhys - GCPhys;
191 if (cb >= cbRead)
192 {
193 memset(pvBuf, 0xff, cbRead);
194 break;
195 }
196 memset(pvBuf, 0xff, cb);
197
198 cbRead -= cb;
199 pvBuf = (char *)pvBuf + cb;
200 GCPhys += cb;
201 }
202 } /* Ram range walk */
203
204 pgmUnlock(pVM);
205
206 return VINF_SUCCESS;
207}
208
209
210/**
211 * EMT worker for PGMR3PhysWriteExternal.
212 */
213static DECLCALLBACK(int) pgmR3PhysWriteExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, const void *pvBuf, size_t cbWrite)
214{
215 /** @todo VERR_EM_NO_MEMORY */
216 PGMPhysWrite(pVM, *pGCPhys, pvBuf, cbWrite);
217 return VINF_SUCCESS;
218}
219
220
221/**
222 * Write to physical memory, external users.
223 *
224 * @returns VBox status code.
225 * @retval VINF_SUCCESS.
226 * @retval VERR_EM_NO_MEMORY.
227 *
228 * @param pVM VM Handle.
229 * @param GCPhys Physical address to write to.
230 * @param pvBuf What to write.
231 * @param cbWrite How many bytes to write.
232 * @param pszWho Who is writing. For tracking down who is writing
233 * after we've saved the state.
234 *
235 * @thread Any but EMTs.
236 */
237VMMDECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, const char *pszWho)
238{
239 VM_ASSERT_OTHER_THREAD(pVM);
240
241 AssertMsg(!pVM->pgm.s.fNoMorePhysWrites,
242 ("Calling PGMR3PhysWriteExternal after pgmR3Save()! GCPhys=%RGp cbWrite=%#x pszWho=%s\n",
243 GCPhys, cbWrite, pszWho));
244 AssertMsgReturn(cbWrite > 0, ("don't even think about writing zero bytes!\n"), VINF_SUCCESS);
245 LogFlow(("PGMR3PhysWriteExternal: %RGp %d\n", GCPhys, cbWrite));
246
247 pgmLock(pVM);
248
249 /*
250 * Copy loop on ram ranges, stop when we hit something difficult.
251 */
252 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
253 for (;;)
254 {
255 /* Find range. */
256 while (pRam && GCPhys > pRam->GCPhysLast)
257 pRam = pRam->CTX_SUFF(pNext);
258 /* Inside range or not? */
259 if (pRam && GCPhys >= pRam->GCPhys)
260 {
261 /*
262 * Must work our way thru this page by page.
263 */
264 RTGCPTR off = GCPhys - pRam->GCPhys;
265 while (off < pRam->cb)
266 {
267 RTGCPTR iPage = off >> PAGE_SHIFT;
268 PPGMPAGE pPage = &pRam->aPages[iPage];
269
270 /*
271 * Is the page problematic, we have to do the work on the EMT.
272 *
273 * Allocating writable pages and access handlers are
274 * problematic, write monitored pages are simple and can be
275 * dealth with here.
276 */
277 if ( PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
278 || PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
279 {
280 if ( PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
281 && !PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
282 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage);
283 else
284 {
285 pgmUnlock(pVM);
286
287 return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysWriteExternalEMT, 4,
288 pVM, &GCPhys, pvBuf, cbWrite);
289 }
290 }
291 Assert(!PGM_PAGE_IS_MMIO(pPage));
292
293 /*
294 * Simple stuff, go ahead.
295 */
296 size_t cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
297 if (cb > cbWrite)
298 cb = cbWrite;
299 void *pvDst;
300 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pRam->GCPhys + off, &pvDst);
301 if (RT_SUCCESS(rc))
302 memcpy(pvDst, pvBuf, cb);
303 else
304 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
305 pRam->GCPhys + off, pPage, rc));
306
307 /* next page */
308 if (cb >= cbWrite)
309 {
310 pgmUnlock(pVM);
311 return VINF_SUCCESS;
312 }
313
314 cbWrite -= cb;
315 off += cb;
316 GCPhys += cb;
317 pvBuf = (const char *)pvBuf + cb;
318 } /* walk pages in ram range */
319 }
320 else
321 {
322 /*
323 * Unassigned address space, skip it.
324 */
325 if (!pRam)
326 break;
327 size_t cb = pRam->GCPhys - GCPhys;
328 if (cb >= cbWrite)
329 break;
330 cbWrite -= cb;
331 pvBuf = (const char *)pvBuf + cb;
332 GCPhys += cb;
333 }
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->pgm.s, *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->pgm.s, 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->pgm.s, 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.pRamRangesR3; 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.pRamRangesR3; 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.pRamRangesR3;
608 if (pCur)
609 {
610 pVM->pgm.s.pRamRangesR0 = pCur->pSelfR0;
611 pVM->pgm.s.pRamRangesRC = 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.pRamRangesR0 == NIL_RTR0PTR);
625 Assert(pVM->pgm.s.pRamRangesRC == 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.pRamRangesR3;
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.pRamRangesR3 = pNew;
660 pVM->pgm.s.pRamRangesR0 = pNew->pSelfR0;
661 pVM->pgm.s.pRamRangesRC = 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.pRamRangesR3 == 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.pRamRangesR3 == pRam);
693 pVM->pgm.s.pRamRangesR3 = pNext;
694 pVM->pgm.s.pRamRangesR0 = pNext ? pNext->pSelfR0 : NIL_RTR0PTR;
695 pVM->pgm.s.pRamRangesRC = 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.pRamRangesR3;
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->pgm.s, 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->pgm.s, 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 (unsigned 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 * Query the amount of free memory inside VMMR0
963 *
964 * @returns VBox status code.
965 * @param pVM The VM handle.
966 * @param puTotalAllocSize Pointer to total allocated memory inside VMMR0 (in bytes)
967 * @param puTotalFreeSize Pointer to total free (allocated but not used yet) memory inside VMMR0 (in bytes)
968 * @param puTotalBalloonSize Pointer to total ballooned memory inside VMMR0 (in bytes)
969 * @param puTotalSharedSize Pointer to total shared memory inside VMMR0 (in bytes)
970 */
971VMMR3DECL(int) PGMR3QueryVMMMemoryStats(PVM pVM, uint64_t *puTotalAllocSize, uint64_t *puTotalFreeSize, uint64_t *puTotalBalloonSize, uint64_t *puTotalSharedSize)
972{
973 int rc;
974
975 uint64_t cAllocPages = 0, cFreePages = 0, cBalloonPages = 0, cSharedPages = 0;
976 rc = GMMR3QueryHypervisorMemoryStats(pVM, &cAllocPages, &cFreePages, &cBalloonPages, &cSharedPages);
977 AssertRCReturn(rc, rc);
978
979 if (puTotalAllocSize)
980 *puTotalAllocSize = cAllocPages * _4K;
981
982 if (puTotalFreeSize)
983 *puTotalFreeSize = cFreePages * _4K;
984
985 if (puTotalBalloonSize)
986 *puTotalBalloonSize = cBalloonPages * _4K;
987
988 if (puTotalSharedSize)
989 *puTotalSharedSize = cSharedPages * _4K;
990
991 Log(("PGMR3QueryVMMMemoryStats: all=%x free=%x ballooned=%x shared=%x\n", cAllocPages, cFreePages, cBalloonPages, cSharedPages));
992 return VINF_SUCCESS;
993}
994
995/**
996 * Query memory stats for the VM
997 *
998 * @returns VBox status code.
999 * @param pVM The VM handle.
1000 * @param puTotalAllocSize Pointer to total allocated memory inside the VM (in bytes)
1001 * @param puTotalFreeSize Pointer to total free (allocated but not used yet) memory inside the VM (in bytes)
1002 * @param puTotalBalloonSize Pointer to total ballooned memory inside the VM (in bytes)
1003 * @param puTotalSharedSize Pointer to total shared memory inside the VM (in bytes)
1004 */
1005VMMR3DECL(int) PGMR3QueryMemoryStats(PVM pVM, uint64_t *pulTotalMem, uint64_t *pulPrivateMem, uint64_t *puTotalSharedMem, uint64_t *puTotalZeroMem)
1006{
1007 if (pulTotalMem)
1008 *pulTotalMem = (uint64_t)pVM->pgm.s.cAllPages * _4K;
1009
1010 if (pulPrivateMem)
1011 *pulPrivateMem = (uint64_t)pVM->pgm.s.cPrivatePages * _4K;
1012
1013 if (puTotalSharedMem)
1014 *puTotalSharedMem = (uint64_t)pVM->pgm.s.cReusedSharedPages * _4K;
1015
1016 if (puTotalZeroMem)
1017 *puTotalZeroMem = (uint64_t)pVM->pgm.s.cZeroPages * _4K;
1018
1019 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));
1020 return VINF_SUCCESS;
1021}
1022
1023/**
1024 * PGMR3PhysRegisterRam worker that initializes and links a RAM range.
1025 *
1026 * @param pVM The VM handle.
1027 * @param pNew The new RAM range.
1028 * @param GCPhys The address of the RAM range.
1029 * @param GCPhysLast The last address of the RAM range.
1030 * @param RCPtrNew The RC address if the range is floating. NIL_RTRCPTR
1031 * if in HMA.
1032 * @param R0PtrNew Ditto for R0.
1033 * @param pszDesc The description.
1034 * @param pPrev The previous RAM range (for linking).
1035 */
1036static void pgmR3PhysInitAndLinkRamRange(PVM pVM, PPGMRAMRANGE pNew, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
1037 RTRCPTR RCPtrNew, RTR0PTR R0PtrNew, const char *pszDesc, PPGMRAMRANGE pPrev)
1038{
1039 /*
1040 * Initialize the range.
1041 */
1042 pNew->pSelfR0 = R0PtrNew != NIL_RTR0PTR ? R0PtrNew : MMHyperCCToR0(pVM, pNew);
1043 pNew->pSelfRC = RCPtrNew != NIL_RTRCPTR ? RCPtrNew : MMHyperCCToRC(pVM, pNew);
1044 pNew->GCPhys = GCPhys;
1045 pNew->GCPhysLast = GCPhysLast;
1046 pNew->cb = GCPhysLast - GCPhys + 1;
1047 pNew->pszDesc = pszDesc;
1048 pNew->fFlags = RCPtrNew != NIL_RTRCPTR ? PGM_RAM_RANGE_FLAGS_FLOATING : 0;
1049 pNew->pvR3 = NULL;
1050 pNew->paLSPages = NULL;
1051
1052 uint32_t const cPages = pNew->cb >> PAGE_SHIFT;
1053 RTGCPHYS iPage = cPages;
1054 while (iPage-- > 0)
1055 PGM_PAGE_INIT_ZERO(&pNew->aPages[iPage], pVM, PGMPAGETYPE_RAM);
1056
1057 /* Update the page count stats. */
1058 pVM->pgm.s.cZeroPages += cPages;
1059 pVM->pgm.s.cAllPages += cPages;
1060
1061 /*
1062 * Link it.
1063 */
1064 pgmR3PhysLinkRamRange(pVM, pNew, pPrev);
1065}
1066
1067
1068/**
1069 * Relocate a floating RAM range.
1070 *
1071 * @copydoc FNPGMRELOCATE.
1072 */
1073static DECLCALLBACK(bool) pgmR3PhysRamRangeRelocate(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser)
1074{
1075 PPGMRAMRANGE pRam = (PPGMRAMRANGE)pvUser;
1076 Assert(pRam->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING);
1077 Assert(pRam->pSelfRC == GCPtrOld + PAGE_SIZE);
1078
1079 switch (enmMode)
1080 {
1081 case PGMRELOCATECALL_SUGGEST:
1082 return true;
1083 case PGMRELOCATECALL_RELOCATE:
1084 {
1085 /* Update myself and then relink all the ranges. */
1086 pgmLock(pVM);
1087 pRam->pSelfRC = (RTRCPTR)(GCPtrNew + PAGE_SIZE);
1088 pgmR3PhysRelinkRamRanges(pVM);
1089 pgmUnlock(pVM);
1090 return true;
1091 }
1092
1093 default:
1094 AssertFailedReturn(false);
1095 }
1096}
1097
1098
1099/**
1100 * PGMR3PhysRegisterRam worker that registers a high chunk.
1101 *
1102 * @returns VBox status code.
1103 * @param pVM The VM handle.
1104 * @param GCPhys The address of the RAM.
1105 * @param cRamPages The number of RAM pages to register.
1106 * @param cbChunk The size of the PGMRAMRANGE guest mapping.
1107 * @param iChunk The chunk number.
1108 * @param pszDesc The RAM range description.
1109 * @param ppPrev Previous RAM range pointer. In/Out.
1110 */
1111static int pgmR3PhysRegisterHighRamChunk(PVM pVM, RTGCPHYS GCPhys, uint32_t cRamPages,
1112 uint32_t cbChunk, uint32_t iChunk, const char *pszDesc,
1113 PPGMRAMRANGE *ppPrev)
1114{
1115 const char *pszDescChunk = iChunk == 0
1116 ? pszDesc
1117 : MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS, "%s (#%u)", pszDesc, iChunk + 1);
1118 AssertReturn(pszDescChunk, VERR_NO_MEMORY);
1119
1120 /*
1121 * Allocate memory for the new chunk.
1122 */
1123 size_t const cChunkPages = RT_ALIGN_Z(RT_UOFFSETOF(PGMRAMRANGE, aPages[cRamPages]), PAGE_SIZE) >> PAGE_SHIFT;
1124 PSUPPAGE paChunkPages = (PSUPPAGE)RTMemTmpAllocZ(sizeof(SUPPAGE) * cChunkPages);
1125 AssertReturn(paChunkPages, VERR_NO_TMP_MEMORY);
1126 RTR0PTR R0PtrChunk = NIL_RTR0PTR;
1127 void *pvChunk = NULL;
1128 int rc = SUPR3PageAllocEx(cChunkPages, 0 /*fFlags*/, &pvChunk,
1129#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
1130 VMMIsHwVirtExtForced(pVM) ? &R0PtrChunk : NULL,
1131#else
1132 NULL,
1133#endif
1134 paChunkPages);
1135 if (RT_SUCCESS(rc))
1136 {
1137#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
1138 if (!VMMIsHwVirtExtForced(pVM))
1139 R0PtrChunk = NIL_RTR0PTR;
1140#else
1141 R0PtrChunk = (uintptr_t)pvChunk;
1142#endif
1143 memset(pvChunk, 0, cChunkPages << PAGE_SHIFT);
1144
1145 PPGMRAMRANGE pNew = (PPGMRAMRANGE)pvChunk;
1146
1147 /*
1148 * Create a mapping and map the pages into it.
1149 * We push these in below the HMA.
1150 */
1151 RTGCPTR GCPtrChunkMap = pVM->pgm.s.GCPtrPrevRamRangeMapping - cbChunk;
1152 rc = PGMR3MapPT(pVM, GCPtrChunkMap, cbChunk, 0 /*fFlags*/, pgmR3PhysRamRangeRelocate, pNew, pszDescChunk);
1153 if (RT_SUCCESS(rc))
1154 {
1155 pVM->pgm.s.GCPtrPrevRamRangeMapping = GCPtrChunkMap;
1156
1157 RTGCPTR const GCPtrChunk = GCPtrChunkMap + PAGE_SIZE;
1158 RTGCPTR GCPtrPage = GCPtrChunk;
1159 for (uint32_t iPage = 0; iPage < cChunkPages && RT_SUCCESS(rc); iPage++, GCPtrPage += PAGE_SIZE)
1160 rc = PGMMap(pVM, GCPtrPage, paChunkPages[iPage].Phys, PAGE_SIZE, 0);
1161 if (RT_SUCCESS(rc))
1162 {
1163 /*
1164 * Ok, init and link the range.
1165 */
1166 pgmR3PhysInitAndLinkRamRange(pVM, pNew, GCPhys, GCPhys + ((RTGCPHYS)cRamPages << PAGE_SHIFT) - 1,
1167 (RTRCPTR)GCPtrChunk, R0PtrChunk, pszDescChunk, *ppPrev);
1168 *ppPrev = pNew;
1169 }
1170 }
1171
1172 if (RT_FAILURE(rc))
1173 SUPR3PageFreeEx(pvChunk, cChunkPages);
1174 }
1175
1176 RTMemTmpFree(paChunkPages);
1177 return rc;
1178}
1179
1180
1181/**
1182 * Sets up a range RAM.
1183 *
1184 * This will check for conflicting registrations, make a resource
1185 * reservation for the memory (with GMM), and setup the per-page
1186 * tracking structures (PGMPAGE).
1187 *
1188 * @returns VBox stutus code.
1189 * @param pVM Pointer to the shared VM structure.
1190 * @param GCPhys The physical address of the RAM.
1191 * @param cb The size of the RAM.
1192 * @param pszDesc The description - not copied, so, don't free or change it.
1193 */
1194VMMR3DECL(int) PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, const char *pszDesc)
1195{
1196 /*
1197 * Validate input.
1198 */
1199 Log(("PGMR3PhysRegisterRam: GCPhys=%RGp cb=%RGp pszDesc=%s\n", GCPhys, cb, pszDesc));
1200 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
1201 AssertReturn(RT_ALIGN_T(cb, PAGE_SIZE, RTGCPHYS) == cb, VERR_INVALID_PARAMETER);
1202 AssertReturn(cb > 0, VERR_INVALID_PARAMETER);
1203 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
1204 AssertMsgReturn(GCPhysLast > GCPhys, ("The range wraps! GCPhys=%RGp cb=%RGp\n", GCPhys, cb), VERR_INVALID_PARAMETER);
1205 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
1206 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1207
1208 pgmLock(pVM);
1209
1210 /*
1211 * Find range location and check for conflicts.
1212 * (We don't lock here because the locking by EMT is only required on update.)
1213 */
1214 PPGMRAMRANGE pPrev = NULL;
1215 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
1216 while (pRam && GCPhysLast >= pRam->GCPhys)
1217 {
1218 if ( GCPhysLast >= pRam->GCPhys
1219 && GCPhys <= pRam->GCPhysLast)
1220 AssertLogRelMsgFailedReturn(("%RGp-%RGp (%s) conflicts with existing %RGp-%RGp (%s)\n",
1221 GCPhys, GCPhysLast, pszDesc,
1222 pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
1223 VERR_PGM_RAM_CONFLICT);
1224
1225 /* next */
1226 pPrev = pRam;
1227 pRam = pRam->pNextR3;
1228 }
1229
1230 /*
1231 * Register it with GMM (the API bitches).
1232 */
1233 const RTGCPHYS cPages = cb >> PAGE_SHIFT;
1234 int rc = MMR3IncreaseBaseReservation(pVM, cPages);
1235 if (RT_FAILURE(rc))
1236 {
1237 pgmUnlock(pVM);
1238 return rc;
1239 }
1240
1241 if ( GCPhys >= _4G
1242 && cPages > 256)
1243 {
1244 /*
1245 * The PGMRAMRANGE structures for the high memory can get very big.
1246 * In order to avoid SUPR3PageAllocEx allocation failures due to the
1247 * allocation size limit there and also to avoid being unable to find
1248 * guest mapping space for them, we split this memory up into 4MB in
1249 * (potential) raw-mode configs and 16MB chunks in forced AMD-V/VT-x
1250 * mode.
1251 *
1252 * The first and last page of each mapping are guard pages and marked
1253 * not-present. So, we've got 4186112 and 16769024 bytes available for
1254 * the PGMRAMRANGE structure.
1255 *
1256 * Note! The sizes used here will influence the saved state.
1257 */
1258 uint32_t cbChunk;
1259 uint32_t cPagesPerChunk;
1260 if (VMMIsHwVirtExtForced(pVM))
1261 {
1262 cbChunk = 16U*_1M;
1263 cPagesPerChunk = 1048048; /* max ~1048059 */
1264 AssertCompile(sizeof(PGMRAMRANGE) + sizeof(PGMPAGE) * 1048048 < 16U*_1M - PAGE_SIZE * 2);
1265 }
1266 else
1267 {
1268 cbChunk = 4U*_1M;
1269 cPagesPerChunk = 261616; /* max ~261627 */
1270 AssertCompile(sizeof(PGMRAMRANGE) + sizeof(PGMPAGE) * 261616 < 4U*_1M - PAGE_SIZE * 2);
1271 }
1272 AssertRelease(RT_UOFFSETOF(PGMRAMRANGE, aPages[cPagesPerChunk]) + PAGE_SIZE * 2 <= cbChunk);
1273
1274 RTGCPHYS cPagesLeft = cPages;
1275 RTGCPHYS GCPhysChunk = GCPhys;
1276 uint32_t iChunk = 0;
1277 while (cPagesLeft > 0)
1278 {
1279 uint32_t cPagesInChunk = cPagesLeft;
1280 if (cPagesInChunk > cPagesPerChunk)
1281 cPagesInChunk = cPagesPerChunk;
1282
1283 rc = pgmR3PhysRegisterHighRamChunk(pVM, GCPhysChunk, cPagesInChunk, cbChunk, iChunk, pszDesc, &pPrev);
1284 AssertRCReturn(rc, rc);
1285
1286 /* advance */
1287 GCPhysChunk += (RTGCPHYS)cPagesInChunk << PAGE_SHIFT;
1288 cPagesLeft -= cPagesInChunk;
1289 iChunk++;
1290 }
1291 }
1292 else
1293 {
1294 /*
1295 * Allocate, initialize and link the new RAM range.
1296 */
1297 const size_t cbRamRange = RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]);
1298 PPGMRAMRANGE pNew;
1299 rc = MMR3HyperAllocOnceNoRel(pVM, cbRamRange, 0, MM_TAG_PGM_PHYS, (void **)&pNew);
1300 AssertLogRelMsgRCReturn(rc, ("cbRamRange=%zu\n", cbRamRange), rc);
1301
1302 pgmR3PhysInitAndLinkRamRange(pVM, pNew, GCPhys, GCPhysLast, NIL_RTRCPTR, NIL_RTR0PTR, pszDesc, pPrev);
1303 }
1304 PGMPhysInvalidatePageMapTLB(pVM);
1305 pgmUnlock(pVM);
1306
1307 /*
1308 * Notify REM.
1309 */
1310 REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_RAM);
1311
1312 return VINF_SUCCESS;
1313}
1314
1315
1316/**
1317 * Worker called by PGMR3InitFinalize if we're configured to pre-allocate RAM.
1318 *
1319 * We do this late in the init process so that all the ROM and MMIO ranges have
1320 * been registered already and we don't go wasting memory on them.
1321 *
1322 * @returns VBox status code.
1323 *
1324 * @param pVM Pointer to the shared VM structure.
1325 */
1326int pgmR3PhysRamPreAllocate(PVM pVM)
1327{
1328 Assert(pVM->pgm.s.fRamPreAlloc);
1329 Log(("pgmR3PhysRamPreAllocate: enter\n"));
1330
1331 /*
1332 * Walk the RAM ranges and allocate all RAM pages, halt at
1333 * the first allocation error.
1334 */
1335 uint64_t cPages = 0;
1336 uint64_t NanoTS = RTTimeNanoTS();
1337 pgmLock(pVM);
1338 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3; pRam; pRam = pRam->pNextR3)
1339 {
1340 PPGMPAGE pPage = &pRam->aPages[0];
1341 RTGCPHYS GCPhys = pRam->GCPhys;
1342 uint32_t cLeft = pRam->cb >> PAGE_SHIFT;
1343 while (cLeft-- > 0)
1344 {
1345 if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM)
1346 {
1347 switch (PGM_PAGE_GET_STATE(pPage))
1348 {
1349 case PGM_PAGE_STATE_ZERO:
1350 {
1351 int rc = pgmPhysAllocPage(pVM, pPage, GCPhys);
1352 if (RT_FAILURE(rc))
1353 {
1354 LogRel(("PGM: RAM Pre-allocation failed at %RGp (in %s) with rc=%Rrc\n", GCPhys, pRam->pszDesc, rc));
1355 pgmUnlock(pVM);
1356 return rc;
1357 }
1358 cPages++;
1359 break;
1360 }
1361
1362 case PGM_PAGE_STATE_BALLOONED:
1363 case PGM_PAGE_STATE_ALLOCATED:
1364 case PGM_PAGE_STATE_WRITE_MONITORED:
1365 case PGM_PAGE_STATE_SHARED:
1366 /* nothing to do here. */
1367 break;
1368 }
1369 }
1370
1371 /* next */
1372 pPage++;
1373 GCPhys += PAGE_SIZE;
1374 }
1375 }
1376 pgmUnlock(pVM);
1377 NanoTS = RTTimeNanoTS() - NanoTS;
1378
1379 LogRel(("PGM: Pre-allocated %llu pages in %llu ms\n", cPages, NanoTS / 1000000));
1380 Log(("pgmR3PhysRamPreAllocate: returns VINF_SUCCESS\n"));
1381 return VINF_SUCCESS;
1382}
1383
1384
1385/**
1386 * Resets (zeros) the RAM.
1387 *
1388 * ASSUMES that the caller owns the PGM lock.
1389 *
1390 * @returns VBox status code.
1391 * @param pVM Pointer to the shared VM structure.
1392 */
1393int pgmR3PhysRamReset(PVM pVM)
1394{
1395 Assert(PGMIsLockOwner(pVM));
1396
1397 /* Reset the memory balloon. */
1398 int rc = GMMR3BalloonedPages(pVM, GMMBALLOONACTION_RESET, 0);
1399 AssertRC(rc);
1400
1401#ifdef VBOX_WITH_PAGE_SHARING
1402 /* Clear all registered shared modules. */
1403 rc = GMMR3ResetSharedModules(pVM);
1404 AssertRC(rc);
1405#endif
1406 /* Reset counter. */
1407 pVM->pgm.s.cReusedSharedPages = 0;
1408
1409 /*
1410 * We batch up pages that should be freed instead of calling GMM for
1411 * each and every one of them.
1412 */
1413 uint32_t cPendingPages = 0;
1414 PGMMFREEPAGESREQ pReq;
1415 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
1416 AssertLogRelRCReturn(rc, rc);
1417
1418 /*
1419 * Walk the ram ranges.
1420 */
1421 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3; pRam; pRam = pRam->pNextR3)
1422 {
1423 uint32_t iPage = pRam->cb >> PAGE_SHIFT;
1424 AssertMsg(((RTGCPHYS)iPage << PAGE_SHIFT) == pRam->cb, ("%RGp %RGp\n", (RTGCPHYS)iPage << PAGE_SHIFT, pRam->cb));
1425
1426 if (!pVM->pgm.s.fRamPreAlloc)
1427 {
1428 /* Replace all RAM pages by ZERO pages. */
1429 while (iPage-- > 0)
1430 {
1431 PPGMPAGE pPage = &pRam->aPages[iPage];
1432 switch (PGM_PAGE_GET_TYPE(pPage))
1433 {
1434 case PGMPAGETYPE_RAM:
1435 /* Do not replace pages part of a 2 MB continuous range with zero pages, but zero them instead. */
1436 if (PGM_PAGE_GET_PDE_TYPE(pPage) == PGM_PAGE_PDE_TYPE_PDE)
1437 {
1438 void *pvPage;
1439 rc = pgmPhysPageMap(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), &pvPage);
1440 AssertLogRelRCReturn(rc, rc);
1441 ASMMemZeroPage(pvPage);
1442 }
1443 else
1444 if (PGM_PAGE_IS_BALLOONED(pPage))
1445 {
1446 /* Turn into a zero page; the balloon status is lost when the VM reboots. */
1447 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ZERO);
1448 }
1449 else
1450 if (!PGM_PAGE_IS_ZERO(pPage))
1451 {
1452 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1453 AssertLogRelRCReturn(rc, rc);
1454 }
1455 break;
1456
1457 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
1458 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1459 break;
1460
1461 case PGMPAGETYPE_MMIO2:
1462 case PGMPAGETYPE_ROM_SHADOW: /* handled by pgmR3PhysRomReset. */
1463 case PGMPAGETYPE_ROM:
1464 case PGMPAGETYPE_MMIO:
1465 break;
1466 default:
1467 AssertFailed();
1468 }
1469 } /* for each page */
1470 }
1471 else
1472 {
1473 /* Zero the memory. */
1474 while (iPage-- > 0)
1475 {
1476 PPGMPAGE pPage = &pRam->aPages[iPage];
1477 switch (PGM_PAGE_GET_TYPE(pPage))
1478 {
1479 case PGMPAGETYPE_RAM:
1480 switch (PGM_PAGE_GET_STATE(pPage))
1481 {
1482 case PGM_PAGE_STATE_ZERO:
1483 break;
1484
1485 case PGM_PAGE_STATE_BALLOONED:
1486 /* Turn into a zero page; the balloon status is lost when the VM reboots. */
1487 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ZERO);
1488 break;
1489
1490 case PGM_PAGE_STATE_SHARED:
1491 case PGM_PAGE_STATE_WRITE_MONITORED:
1492 rc = pgmPhysPageMakeWritable(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1493 AssertLogRelRCReturn(rc, rc);
1494 /* no break */
1495
1496 case PGM_PAGE_STATE_ALLOCATED:
1497 {
1498 void *pvPage;
1499 rc = pgmPhysPageMap(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), &pvPage);
1500 AssertLogRelRCReturn(rc, rc);
1501 ASMMemZeroPage(pvPage);
1502 break;
1503 }
1504 }
1505 break;
1506
1507 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
1508 pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1509 break;
1510
1511 case PGMPAGETYPE_MMIO2:
1512 case PGMPAGETYPE_ROM_SHADOW:
1513 case PGMPAGETYPE_ROM:
1514 case PGMPAGETYPE_MMIO:
1515 break;
1516 default:
1517 AssertFailed();
1518
1519 }
1520 } /* for each page */
1521 }
1522
1523 }
1524
1525 /*
1526 * Finish off any pages pending freeing.
1527 */
1528 if (cPendingPages)
1529 {
1530 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
1531 AssertLogRelRCReturn(rc, rc);
1532 }
1533 GMMR3FreePagesCleanup(pReq);
1534
1535 return VINF_SUCCESS;
1536}
1537
1538/**
1539 * Frees all RAM during VM termination
1540 *
1541 * ASSUMES that the caller owns the PGM lock.
1542 *
1543 * @returns VBox status code.
1544 * @param pVM Pointer to the shared VM structure.
1545 */
1546int pgmR3PhysRamTerm(PVM pVM)
1547{
1548 Assert(PGMIsLockOwner(pVM));
1549
1550 /* Reset the memory balloon. */
1551 int rc = GMMR3BalloonedPages(pVM, GMMBALLOONACTION_RESET, 0);
1552 AssertRC(rc);
1553
1554#ifdef VBOX_WITH_PAGE_SHARING
1555 /* Clear all registered shared modules. */
1556 rc = GMMR3ResetSharedModules(pVM);
1557 AssertRC(rc);
1558#endif
1559
1560 /*
1561 * We batch up pages that should be freed instead of calling GMM for
1562 * each and every one of them.
1563 */
1564 uint32_t cPendingPages = 0;
1565 PGMMFREEPAGESREQ pReq;
1566 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
1567 AssertLogRelRCReturn(rc, rc);
1568
1569 /*
1570 * Walk the ram ranges.
1571 */
1572 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3; pRam; pRam = pRam->pNextR3)
1573 {
1574 uint32_t iPage = pRam->cb >> PAGE_SHIFT;
1575 AssertMsg(((RTGCPHYS)iPage << PAGE_SHIFT) == pRam->cb, ("%RGp %RGp\n", (RTGCPHYS)iPage << PAGE_SHIFT, pRam->cb));
1576
1577 /* Replace all RAM pages by ZERO pages. */
1578 while (iPage-- > 0)
1579 {
1580 PPGMPAGE pPage = &pRam->aPages[iPage];
1581 switch (PGM_PAGE_GET_TYPE(pPage))
1582 {
1583 case PGMPAGETYPE_RAM:
1584 /* Free all shared pages. Private pages are automatically freed during GMM VM cleanup. */
1585 if (PGM_PAGE_IS_SHARED(pPage))
1586 {
1587 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
1588 AssertLogRelRCReturn(rc, rc);
1589 }
1590 break;
1591
1592 case PGMPAGETYPE_MMIO2_ALIAS_MMIO:
1593 case PGMPAGETYPE_MMIO2:
1594 case PGMPAGETYPE_ROM_SHADOW: /* handled by pgmR3PhysRomReset. */
1595 case PGMPAGETYPE_ROM:
1596 case PGMPAGETYPE_MMIO:
1597 break;
1598 default:
1599 AssertFailed();
1600 }
1601 } /* for each page */
1602 }
1603
1604 /*
1605 * Finish off any pages pending freeing.
1606 */
1607 if (cPendingPages)
1608 {
1609 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
1610 AssertLogRelRCReturn(rc, rc);
1611 }
1612 GMMR3FreePagesCleanup(pReq);
1613 return VINF_SUCCESS;
1614}
1615
1616/**
1617 * This is the interface IOM is using to register an MMIO region.
1618 *
1619 * It will check for conflicts and ensure that a RAM range structure
1620 * is present before calling the PGMR3HandlerPhysicalRegister API to
1621 * register the callbacks.
1622 *
1623 * @returns VBox status code.
1624 *
1625 * @param pVM Pointer to the shared VM structure.
1626 * @param GCPhys The start of the MMIO region.
1627 * @param cb The size of the MMIO region.
1628 * @param pfnHandlerR3 The address of the ring-3 handler. (IOMR3MMIOHandler)
1629 * @param pvUserR3 The user argument for R3.
1630 * @param pfnHandlerR0 The address of the ring-0 handler. (IOMMMIOHandler)
1631 * @param pvUserR0 The user argument for R0.
1632 * @param pfnHandlerRC The address of the RC handler. (IOMMMIOHandler)
1633 * @param pvUserRC The user argument for RC.
1634 * @param pszDesc The description of the MMIO region.
1635 */
1636VMMR3DECL(int) PGMR3PhysMMIORegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb,
1637 R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3,
1638 R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0,
1639 RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC, RTRCPTR pvUserRC,
1640 R3PTRTYPE(const char *) pszDesc)
1641{
1642 /*
1643 * Assert on some assumption.
1644 */
1645 VM_ASSERT_EMT(pVM);
1646 AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
1647 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
1648 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
1649 AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
1650
1651 /*
1652 * Make sure there's a RAM range structure for the region.
1653 */
1654 int rc;
1655 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
1656 bool fRamExists = false;
1657 PPGMRAMRANGE pRamPrev = NULL;
1658 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
1659 while (pRam && GCPhysLast >= pRam->GCPhys)
1660 {
1661 if ( GCPhysLast >= pRam->GCPhys
1662 && GCPhys <= pRam->GCPhysLast)
1663 {
1664 /* Simplification: all within the same range. */
1665 AssertLogRelMsgReturn( GCPhys >= pRam->GCPhys
1666 && GCPhysLast <= pRam->GCPhysLast,
1667 ("%RGp-%RGp (MMIO/%s) falls partly outside %RGp-%RGp (%s)\n",
1668 GCPhys, GCPhysLast, pszDesc,
1669 pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
1670 VERR_PGM_RAM_CONFLICT);
1671
1672 /* Check that it's all RAM or MMIO pages. */
1673 PCPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
1674 uint32_t cLeft = cb >> PAGE_SHIFT;
1675 while (cLeft-- > 0)
1676 {
1677 AssertLogRelMsgReturn( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
1678 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO,
1679 ("%RGp-%RGp (MMIO/%s): %RGp is not a RAM or MMIO page - type=%d desc=%s\n",
1680 GCPhys, GCPhysLast, pszDesc, PGM_PAGE_GET_TYPE(pPage), pRam->pszDesc),
1681 VERR_PGM_RAM_CONFLICT);
1682 pPage++;
1683 }
1684
1685 /* Looks good. */
1686 fRamExists = true;
1687 break;
1688 }
1689
1690 /* next */
1691 pRamPrev = pRam;
1692 pRam = pRam->pNextR3;
1693 }
1694 PPGMRAMRANGE pNew;
1695 if (fRamExists)
1696 {
1697 pNew = NULL;
1698
1699 /*
1700 * Make all the pages in the range MMIO/ZERO pages, freeing any
1701 * RAM pages currently mapped here. This might not be 100% correct
1702 * for PCI memory, but we're doing the same thing for MMIO2 pages.
1703 */
1704 rc = pgmLock(pVM);
1705 if (RT_SUCCESS(rc))
1706 {
1707 rc = pgmR3PhysFreePageRange(pVM, pRam, GCPhys, GCPhysLast, PGMPAGETYPE_MMIO);
1708 pgmUnlock(pVM);
1709 }
1710 AssertRCReturn(rc, rc);
1711
1712 /* Force a PGM pool flush as guest ram references have been changed. */
1713 /** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
1714 PVMCPU pVCpu = VMMGetCpu(pVM);
1715 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
1716 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
1717 }
1718 else
1719 {
1720 pgmLock(pVM);
1721
1722 /*
1723 * No RAM range, insert an ad hoc one.
1724 *
1725 * Note that we don't have to tell REM about this range because
1726 * PGMHandlerPhysicalRegisterEx will do that for us.
1727 */
1728 Log(("PGMR3PhysMMIORegister: Adding ad hoc MMIO range for %RGp-%RGp %s\n", GCPhys, GCPhysLast, pszDesc));
1729
1730 const uint32_t cPages = cb >> PAGE_SHIFT;
1731 const size_t cbRamRange = RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]);
1732 rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]), 16, MM_TAG_PGM_PHYS, (void **)&pNew);
1733 AssertLogRelMsgRCReturn(rc, ("cbRamRange=%zu\n", cbRamRange), rc);
1734
1735 /* Initialize the range. */
1736 pNew->pSelfR0 = MMHyperCCToR0(pVM, pNew);
1737 pNew->pSelfRC = MMHyperCCToRC(pVM, pNew);
1738 pNew->GCPhys = GCPhys;
1739 pNew->GCPhysLast = GCPhysLast;
1740 pNew->cb = cb;
1741 pNew->pszDesc = pszDesc;
1742 pNew->fFlags = PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO;
1743 pNew->pvR3 = NULL;
1744 pNew->paLSPages = NULL;
1745
1746 uint32_t iPage = cPages;
1747 while (iPage-- > 0)
1748 PGM_PAGE_INIT_ZERO(&pNew->aPages[iPage], pVM, PGMPAGETYPE_MMIO);
1749 Assert(PGM_PAGE_GET_TYPE(&pNew->aPages[0]) == PGMPAGETYPE_MMIO);
1750
1751 /* update the page count stats. */
1752 pVM->pgm.s.cPureMmioPages += cPages;
1753 pVM->pgm.s.cAllPages += cPages;
1754
1755 /* link it */
1756 pgmR3PhysLinkRamRange(pVM, pNew, pRamPrev);
1757
1758 pgmUnlock(pVM);
1759 }
1760
1761 /*
1762 * Register the access handler.
1763 */
1764 rc = PGMHandlerPhysicalRegisterEx(pVM, PGMPHYSHANDLERTYPE_MMIO, GCPhys, GCPhysLast,
1765 pfnHandlerR3, pvUserR3,
1766 pfnHandlerR0, pvUserR0,
1767 pfnHandlerRC, pvUserRC, pszDesc);
1768 if ( RT_FAILURE(rc)
1769 && !fRamExists)
1770 {
1771 pVM->pgm.s.cPureMmioPages -= cb >> PAGE_SHIFT;
1772 pVM->pgm.s.cAllPages -= cb >> PAGE_SHIFT;
1773
1774 /* remove the ad hoc range. */
1775 pgmR3PhysUnlinkRamRange2(pVM, pNew, pRamPrev);
1776 pNew->cb = pNew->GCPhys = pNew->GCPhysLast = NIL_RTGCPHYS;
1777 MMHyperFree(pVM, pRam);
1778 }
1779 PGMPhysInvalidatePageMapTLB(pVM);
1780
1781 return rc;
1782}
1783
1784
1785/**
1786 * This is the interface IOM is using to register an MMIO region.
1787 *
1788 * It will take care of calling PGMHandlerPhysicalDeregister and clean up
1789 * any ad hoc PGMRAMRANGE left behind.
1790 *
1791 * @returns VBox status code.
1792 * @param pVM Pointer to the shared VM structure.
1793 * @param GCPhys The start of the MMIO region.
1794 * @param cb The size of the MMIO region.
1795 */
1796VMMR3DECL(int) PGMR3PhysMMIODeregister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb)
1797{
1798 VM_ASSERT_EMT(pVM);
1799
1800 /*
1801 * First deregister the handler, then check if we should remove the ram range.
1802 */
1803 int rc = PGMHandlerPhysicalDeregister(pVM, GCPhys);
1804 if (RT_SUCCESS(rc))
1805 {
1806 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
1807 PPGMRAMRANGE pRamPrev = NULL;
1808 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
1809 while (pRam && GCPhysLast >= pRam->GCPhys)
1810 {
1811 /** @todo We're being a bit too careful here. rewrite. */
1812 if ( GCPhysLast == pRam->GCPhysLast
1813 && GCPhys == pRam->GCPhys)
1814 {
1815 Assert(pRam->cb == cb);
1816
1817 /*
1818 * See if all the pages are dead MMIO pages.
1819 */
1820 uint32_t const cPages = cb >> PAGE_SHIFT;
1821 bool fAllMMIO = true;
1822 uint32_t iPage = 0;
1823 uint32_t cLeft = cPages;
1824 while (cLeft-- > 0)
1825 {
1826 PPGMPAGE pPage = &pRam->aPages[iPage];
1827 if ( PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO
1828 /*|| not-out-of-action later */)
1829 {
1830 fAllMMIO = false;
1831 Assert(PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO2_ALIAS_MMIO);
1832 AssertMsgFailed(("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
1833 break;
1834 }
1835 Assert(PGM_PAGE_IS_ZERO(pPage));
1836 pPage++;
1837 }
1838 if (fAllMMIO)
1839 {
1840 /*
1841 * Ad-hoc range, unlink and free it.
1842 */
1843 Log(("PGMR3PhysMMIODeregister: Freeing ad hoc MMIO range for %RGp-%RGp %s\n",
1844 GCPhys, GCPhysLast, pRam->pszDesc));
1845
1846 pVM->pgm.s.cAllPages -= cPages;
1847 pVM->pgm.s.cPureMmioPages -= cPages;
1848
1849 pgmR3PhysUnlinkRamRange2(pVM, pRam, pRamPrev);
1850 pRam->cb = pRam->GCPhys = pRam->GCPhysLast = NIL_RTGCPHYS;
1851 MMHyperFree(pVM, pRam);
1852 break;
1853 }
1854 }
1855
1856 /*
1857 * Range match? It will all be within one range (see PGMAllHandler.cpp).
1858 */
1859 if ( GCPhysLast >= pRam->GCPhys
1860 && GCPhys <= pRam->GCPhysLast)
1861 {
1862 Assert(GCPhys >= pRam->GCPhys);
1863 Assert(GCPhysLast <= pRam->GCPhysLast);
1864
1865 /*
1866 * Turn the pages back into RAM pages.
1867 */
1868 uint32_t iPage = (GCPhys - pRam->GCPhys) >> PAGE_SHIFT;
1869 uint32_t cLeft = cb >> PAGE_SHIFT;
1870 while (cLeft--)
1871 {
1872 PPGMPAGE pPage = &pRam->aPages[iPage];
1873 AssertMsg(PGM_PAGE_IS_MMIO(pPage), ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
1874 AssertMsg(PGM_PAGE_IS_ZERO(pPage), ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
1875 if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO)
1876 PGM_PAGE_SET_TYPE(pPage, PGMPAGETYPE_RAM);
1877 }
1878 break;
1879 }
1880
1881 /* next */
1882 pRamPrev = pRam;
1883 pRam = pRam->pNextR3;
1884 }
1885 }
1886
1887 /* Force a PGM pool flush as guest ram references have been changed. */
1888 /** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
1889 PVMCPU pVCpu = VMMGetCpu(pVM);
1890 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
1891 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
1892
1893 PGMPhysInvalidatePageMapTLB(pVM);
1894 return rc;
1895}
1896
1897
1898/**
1899 * Locate a MMIO2 range.
1900 *
1901 * @returns Pointer to the MMIO2 range.
1902 * @param pVM Pointer to the shared VM structure.
1903 * @param pDevIns The device instance owning the region.
1904 * @param iRegion The region.
1905 */
1906DECLINLINE(PPGMMMIO2RANGE) pgmR3PhysMMIO2Find(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion)
1907{
1908 /*
1909 * Search the list.
1910 */
1911 for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
1912 if ( pCur->pDevInsR3 == pDevIns
1913 && pCur->iRegion == iRegion)
1914 return pCur;
1915 return NULL;
1916}
1917
1918
1919/**
1920 * Allocate and register an MMIO2 region.
1921 *
1922 * As mentioned elsewhere, MMIO2 is just RAM spelled differently. It's
1923 * RAM associated with a device. It is also non-shared memory with a
1924 * permanent ring-3 mapping and page backing (presently).
1925 *
1926 * A MMIO2 range may overlap with base memory if a lot of RAM
1927 * is configured for the VM, in which case we'll drop the base
1928 * memory pages. Presently we will make no attempt to preserve
1929 * anything that happens to be present in the base memory that
1930 * is replaced, this is of course incorrectly but it's too much
1931 * effort.
1932 *
1933 * @returns VBox status code.
1934 * @retval VINF_SUCCESS on success, *ppv pointing to the R3 mapping of the memory.
1935 * @retval VERR_ALREADY_EXISTS if the region already exists.
1936 *
1937 * @param pVM Pointer to the shared VM structure.
1938 * @param pDevIns The device instance owning the region.
1939 * @param iRegion The region number. If the MMIO2 memory is a PCI I/O region
1940 * this number has to be the number of that region. Otherwise
1941 * it can be any number safe UINT8_MAX.
1942 * @param cb The size of the region. Must be page aligned.
1943 * @param fFlags Reserved for future use, must be zero.
1944 * @param ppv Where to store the pointer to the ring-3 mapping of the memory.
1945 * @param pszDesc The description.
1946 */
1947VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc)
1948{
1949 /*
1950 * Validate input.
1951 */
1952 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1953 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
1954 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
1955 AssertPtrReturn(ppv, VERR_INVALID_POINTER);
1956 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
1957 AssertReturn(*pszDesc, VERR_INVALID_PARAMETER);
1958 AssertReturn(pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion) == NULL, VERR_ALREADY_EXISTS);
1959 AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
1960 AssertReturn(cb, VERR_INVALID_PARAMETER);
1961 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
1962
1963 const uint32_t cPages = cb >> PAGE_SHIFT;
1964 AssertLogRelReturn(((RTGCPHYS)cPages << PAGE_SHIFT) == cb, VERR_INVALID_PARAMETER);
1965 AssertLogRelReturn(cPages <= INT32_MAX / 2, VERR_NO_MEMORY);
1966
1967 /*
1968 * For the 2nd+ instance, mangle the description string so it's unique.
1969 */
1970 if (pDevIns->iInstance > 0) /** @todo Move to PDMDevHlp.cpp and use a real string cache. */
1971 {
1972 pszDesc = MMR3HeapAPrintf(pVM, MM_TAG_PGM_PHYS, "%s [%u]", pszDesc, pDevIns->iInstance);
1973 if (!pszDesc)
1974 return VERR_NO_MEMORY;
1975 }
1976
1977 /*
1978 * Try reserve and allocate the backing memory first as this is what is
1979 * most likely to fail.
1980 */
1981 int rc = MMR3AdjustFixedReservation(pVM, cPages, pszDesc);
1982 if (RT_SUCCESS(rc))
1983 {
1984 void *pvPages;
1985 PSUPPAGE paPages = (PSUPPAGE)RTMemTmpAlloc(cPages * sizeof(SUPPAGE));
1986 if (RT_SUCCESS(rc))
1987 rc = SUPR3PageAllocEx(cPages, 0 /*fFlags*/, &pvPages, NULL /*pR0Ptr*/, paPages);
1988 if (RT_SUCCESS(rc))
1989 {
1990 memset(pvPages, 0, cPages * PAGE_SIZE);
1991
1992 /*
1993 * Create the MMIO2 range record for it.
1994 */
1995 const size_t cbRange = RT_OFFSETOF(PGMMMIO2RANGE, RamRange.aPages[cPages]);
1996 PPGMMMIO2RANGE pNew;
1997 rc = MMR3HyperAllocOnceNoRel(pVM, cbRange, 0, MM_TAG_PGM_PHYS, (void **)&pNew);
1998 AssertLogRelMsgRC(rc, ("cbRamRange=%zu\n", cbRange));
1999 if (RT_SUCCESS(rc))
2000 {
2001 pNew->pDevInsR3 = pDevIns;
2002 pNew->pvR3 = pvPages;
2003 //pNew->pNext = NULL;
2004 //pNew->fMapped = false;
2005 //pNew->fOverlapping = false;
2006 pNew->iRegion = iRegion;
2007 pNew->idSavedState = UINT8_MAX;
2008 pNew->RamRange.pSelfR0 = MMHyperCCToR0(pVM, &pNew->RamRange);
2009 pNew->RamRange.pSelfRC = MMHyperCCToRC(pVM, &pNew->RamRange);
2010 pNew->RamRange.GCPhys = NIL_RTGCPHYS;
2011 pNew->RamRange.GCPhysLast = NIL_RTGCPHYS;
2012 pNew->RamRange.pszDesc = pszDesc;
2013 pNew->RamRange.cb = cb;
2014 pNew->RamRange.fFlags = PGM_RAM_RANGE_FLAGS_AD_HOC_MMIO2;
2015 pNew->RamRange.pvR3 = pvPages;
2016 //pNew->RamRange.paLSPages = NULL;
2017
2018 uint32_t iPage = cPages;
2019 while (iPage-- > 0)
2020 {
2021 PGM_PAGE_INIT(&pNew->RamRange.aPages[iPage],
2022 paPages[iPage].Phys, NIL_GMM_PAGEID,
2023 PGMPAGETYPE_MMIO2, PGM_PAGE_STATE_ALLOCATED);
2024 }
2025
2026 /* update page count stats */
2027 pVM->pgm.s.cAllPages += cPages;
2028 pVM->pgm.s.cPrivatePages += cPages;
2029
2030 /*
2031 * Link it into the list.
2032 * Since there is no particular order, just push it.
2033 */
2034 pgmLock(pVM);
2035 pNew->pNextR3 = pVM->pgm.s.pMmio2RangesR3;
2036 pVM->pgm.s.pMmio2RangesR3 = pNew;
2037 pgmUnlock(pVM);
2038
2039 *ppv = pvPages;
2040 RTMemTmpFree(paPages);
2041 PGMPhysInvalidatePageMapTLB(pVM);
2042 return VINF_SUCCESS;
2043 }
2044
2045 SUPR3PageFreeEx(pvPages, cPages);
2046 }
2047 RTMemTmpFree(paPages);
2048 MMR3AdjustFixedReservation(pVM, -(int32_t)cPages, pszDesc);
2049 }
2050 if (pDevIns->iInstance > 0)
2051 MMR3HeapFree((void *)pszDesc);
2052 return rc;
2053}
2054
2055
2056/**
2057 * Deregisters and frees an MMIO2 region.
2058 *
2059 * Any physical (and virtual) access handlers registered for the region must
2060 * be deregistered before calling this function.
2061 *
2062 * @returns VBox status code.
2063 * @param pVM Pointer to the shared VM structure.
2064 * @param pDevIns The device instance owning the region.
2065 * @param iRegion The region. If it's UINT32_MAX it'll be a wildcard match.
2066 */
2067VMMR3DECL(int) PGMR3PhysMMIO2Deregister(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion)
2068{
2069 /*
2070 * Validate input.
2071 */
2072 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2073 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2074 AssertReturn(iRegion <= UINT8_MAX || iRegion == UINT32_MAX, VERR_INVALID_PARAMETER);
2075
2076 pgmLock(pVM);
2077 int rc = VINF_SUCCESS;
2078 unsigned cFound = 0;
2079 PPGMMMIO2RANGE pPrev = NULL;
2080 PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3;
2081 while (pCur)
2082 {
2083 if ( pCur->pDevInsR3 == pDevIns
2084 && ( iRegion == UINT32_MAX
2085 || pCur->iRegion == iRegion))
2086 {
2087 cFound++;
2088
2089 /*
2090 * Unmap it if it's mapped.
2091 */
2092 if (pCur->fMapped)
2093 {
2094 int rc2 = PGMR3PhysMMIO2Unmap(pVM, pCur->pDevInsR3, pCur->iRegion, pCur->RamRange.GCPhys);
2095 AssertRC(rc2);
2096 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
2097 rc = rc2;
2098 }
2099
2100 /*
2101 * Unlink it
2102 */
2103 PPGMMMIO2RANGE pNext = pCur->pNextR3;
2104 if (pPrev)
2105 pPrev->pNextR3 = pNext;
2106 else
2107 pVM->pgm.s.pMmio2RangesR3 = pNext;
2108 pCur->pNextR3 = NULL;
2109
2110 /*
2111 * Free the memory.
2112 */
2113 int rc2 = SUPR3PageFreeEx(pCur->pvR3, pCur->RamRange.cb >> PAGE_SHIFT);
2114 AssertRC(rc2);
2115 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
2116 rc = rc2;
2117
2118 uint32_t const cPages = pCur->RamRange.cb >> PAGE_SHIFT;
2119 rc2 = MMR3AdjustFixedReservation(pVM, -(int32_t)cPages, pCur->RamRange.pszDesc);
2120 AssertRC(rc2);
2121 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
2122 rc = rc2;
2123
2124 /* we're leaking hyper memory here if done at runtime. */
2125#ifdef VBOX_STRICT
2126 VMSTATE const enmState = VMR3GetState(pVM);
2127 AssertMsg( enmState == VMSTATE_POWERING_OFF
2128 || enmState == VMSTATE_POWERING_OFF_LS
2129 || enmState == VMSTATE_OFF
2130 || enmState == VMSTATE_OFF_LS
2131 || enmState == VMSTATE_DESTROYING
2132 || enmState == VMSTATE_TERMINATED
2133 || enmState == VMSTATE_CREATING
2134 , ("%s\n", VMR3GetStateName(enmState)));
2135#endif
2136 /*rc = MMHyperFree(pVM, pCur);
2137 AssertRCReturn(rc, rc); - not safe, see the alloc call. */
2138
2139
2140 /* update page count stats */
2141 pVM->pgm.s.cAllPages -= cPages;
2142 pVM->pgm.s.cPrivatePages -= cPages;
2143
2144 /* next */
2145 pCur = pNext;
2146 }
2147 else
2148 {
2149 pPrev = pCur;
2150 pCur = pCur->pNextR3;
2151 }
2152 }
2153 PGMPhysInvalidatePageMapTLB(pVM);
2154 pgmUnlock(pVM);
2155 return !cFound && iRegion != UINT32_MAX ? VERR_NOT_FOUND : rc;
2156}
2157
2158
2159/**
2160 * Maps a MMIO2 region.
2161 *
2162 * This is done when a guest / the bios / state loading changes the
2163 * PCI config. The replacing of base memory has the same restrictions
2164 * as during registration, of course.
2165 *
2166 * @returns VBox status code.
2167 *
2168 * @param pVM Pointer to the shared VM structure.
2169 * @param pDevIns The
2170 */
2171VMMR3DECL(int) PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
2172{
2173 /*
2174 * Validate input
2175 */
2176 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2177 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2178 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2179 AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
2180 AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
2181 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2182
2183 PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
2184 AssertReturn(pCur, VERR_NOT_FOUND);
2185 AssertReturn(!pCur->fMapped, VERR_WRONG_ORDER);
2186 Assert(pCur->RamRange.GCPhys == NIL_RTGCPHYS);
2187 Assert(pCur->RamRange.GCPhysLast == NIL_RTGCPHYS);
2188
2189 const RTGCPHYS GCPhysLast = GCPhys + pCur->RamRange.cb - 1;
2190 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
2191
2192 /*
2193 * Find our location in the ram range list, checking for
2194 * restriction we don't bother implementing yet (partially overlapping).
2195 */
2196 bool fRamExists = false;
2197 PPGMRAMRANGE pRamPrev = NULL;
2198 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
2199 while (pRam && GCPhysLast >= pRam->GCPhys)
2200 {
2201 if ( GCPhys <= pRam->GCPhysLast
2202 && GCPhysLast >= pRam->GCPhys)
2203 {
2204 /* completely within? */
2205 AssertLogRelMsgReturn( GCPhys >= pRam->GCPhys
2206 && GCPhysLast <= pRam->GCPhysLast,
2207 ("%RGp-%RGp (MMIO2/%s) falls partly outside %RGp-%RGp (%s)\n",
2208 GCPhys, GCPhysLast, pCur->RamRange.pszDesc,
2209 pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
2210 VERR_PGM_RAM_CONFLICT);
2211 fRamExists = true;
2212 break;
2213 }
2214
2215 /* next */
2216 pRamPrev = pRam;
2217 pRam = pRam->pNextR3;
2218 }
2219 if (fRamExists)
2220 {
2221 PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2222 uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
2223 while (cPagesLeft-- > 0)
2224 {
2225 AssertLogRelMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
2226 ("%RGp isn't a RAM page (%d) - mapping %RGp-%RGp (MMIO2/%s).\n",
2227 GCPhys, PGM_PAGE_GET_TYPE(pPage), GCPhys, GCPhysLast, pCur->RamRange.pszDesc),
2228 VERR_PGM_RAM_CONFLICT);
2229 pPage++;
2230 }
2231 }
2232 Log(("PGMR3PhysMMIO2Map: %RGp-%RGp fRamExists=%RTbool %s\n",
2233 GCPhys, GCPhysLast, fRamExists, pCur->RamRange.pszDesc));
2234
2235 /*
2236 * Make the changes.
2237 */
2238 pgmLock(pVM);
2239
2240 pCur->RamRange.GCPhys = GCPhys;
2241 pCur->RamRange.GCPhysLast = GCPhysLast;
2242 pCur->fMapped = true;
2243 pCur->fOverlapping = fRamExists;
2244
2245 if (fRamExists)
2246 {
2247/** @todo use pgmR3PhysFreePageRange here. */
2248 uint32_t cPendingPages = 0;
2249 PGMMFREEPAGESREQ pReq;
2250 int rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
2251 AssertLogRelRCReturn(rc, rc);
2252
2253 /* replace the pages, freeing all present RAM pages. */
2254 PPGMPAGE pPageSrc = &pCur->RamRange.aPages[0];
2255 PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2256 uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
2257 while (cPagesLeft-- > 0)
2258 {
2259 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPageDst, GCPhys);
2260 AssertLogRelRCReturn(rc, rc); /* We're done for if this goes wrong. */
2261
2262 RTHCPHYS const HCPhys = PGM_PAGE_GET_HCPHYS(pPageSrc);
2263 PGM_PAGE_SET_HCPHYS(pPageDst, HCPhys);
2264 PGM_PAGE_SET_TYPE(pPageDst, PGMPAGETYPE_MMIO2);
2265 PGM_PAGE_SET_STATE(pPageDst, PGM_PAGE_STATE_ALLOCATED);
2266 PGM_PAGE_SET_PDE_TYPE(pPageDst, PGM_PAGE_PDE_TYPE_DONTCARE);
2267 PGM_PAGE_SET_PTE_INDEX(pPageDst, 0);
2268 PGM_PAGE_SET_TRACKING(pPageDst, 0);
2269
2270 pVM->pgm.s.cZeroPages--;
2271 GCPhys += PAGE_SIZE;
2272 pPageSrc++;
2273 pPageDst++;
2274 }
2275
2276 /* Flush physical page map TLB. */
2277 PGMPhysInvalidatePageMapTLB(pVM);
2278
2279 if (cPendingPages)
2280 {
2281 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
2282 AssertLogRelRCReturn(rc, rc);
2283 }
2284 GMMR3FreePagesCleanup(pReq);
2285
2286 /* Force a PGM pool flush as guest ram references have been changed. */
2287 /** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
2288 PVMCPU pVCpu = VMMGetCpu(pVM);
2289 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2290 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2291
2292 pgmUnlock(pVM);
2293 }
2294 else
2295 {
2296 RTGCPHYS cb = pCur->RamRange.cb;
2297
2298 /* Clear the tracking data of pages we're going to reactivate. */
2299 PPGMPAGE pPageSrc = &pCur->RamRange.aPages[0];
2300 uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
2301 while (cPagesLeft-- > 0)
2302 {
2303 PGM_PAGE_SET_TRACKING(pPageSrc, 0);
2304 PGM_PAGE_SET_PTE_INDEX(pPageSrc, 0);
2305 pPageSrc++;
2306 }
2307
2308 /* link in the ram range */
2309 pgmR3PhysLinkRamRange(pVM, &pCur->RamRange, pRamPrev);
2310 pgmUnlock(pVM);
2311
2312 REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_MMIO2);
2313 }
2314
2315 PGMPhysInvalidatePageMapTLB(pVM);
2316 return VINF_SUCCESS;
2317}
2318
2319
2320/**
2321 * Unmaps a MMIO2 region.
2322 *
2323 * This is done when a guest / the bios / state loading changes the
2324 * PCI config. The replacing of base memory has the same restrictions
2325 * as during registration, of course.
2326 */
2327VMMR3DECL(int) PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS GCPhys)
2328{
2329 /*
2330 * Validate input
2331 */
2332 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2333 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2334 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2335 AssertReturn(GCPhys != NIL_RTGCPHYS, VERR_INVALID_PARAMETER);
2336 AssertReturn(GCPhys != 0, VERR_INVALID_PARAMETER);
2337 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
2338
2339 PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
2340 AssertReturn(pCur, VERR_NOT_FOUND);
2341 AssertReturn(pCur->fMapped, VERR_WRONG_ORDER);
2342 AssertReturn(pCur->RamRange.GCPhys == GCPhys, VERR_INVALID_PARAMETER);
2343 Assert(pCur->RamRange.GCPhysLast != NIL_RTGCPHYS);
2344
2345 Log(("PGMR3PhysMMIO2Unmap: %RGp-%RGp %s\n",
2346 pCur->RamRange.GCPhys, pCur->RamRange.GCPhysLast, pCur->RamRange.pszDesc));
2347
2348 /*
2349 * Unmap it.
2350 */
2351 pgmLock(pVM);
2352
2353 RTGCPHYS GCPhysRangeREM;
2354 RTGCPHYS cbRangeREM;
2355 bool fInformREM;
2356 if (pCur->fOverlapping)
2357 {
2358 /* Restore the RAM pages we've replaced. */
2359 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
2360 while (pRam->GCPhys > pCur->RamRange.GCPhysLast)
2361 pRam = pRam->pNextR3;
2362
2363 PPGMPAGE pPageDst = &pRam->aPages[(pCur->RamRange.GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2364 uint32_t cPagesLeft = pCur->RamRange.cb >> PAGE_SHIFT;
2365 while (cPagesLeft-- > 0)
2366 {
2367 PGM_PAGE_INIT_ZERO(pPageDst, pVM, PGMPAGETYPE_RAM);
2368 pVM->pgm.s.cZeroPages++;
2369 pPageDst++;
2370 }
2371
2372 /* Flush physical page map TLB. */
2373 PGMPhysInvalidatePageMapTLB(pVM);
2374
2375 GCPhysRangeREM = NIL_RTGCPHYS; /* shuts up gcc */
2376 cbRangeREM = RTGCPHYS_MAX; /* ditto */
2377 fInformREM = false;
2378 }
2379 else
2380 {
2381 GCPhysRangeREM = pCur->RamRange.GCPhys;
2382 cbRangeREM = pCur->RamRange.cb;
2383 fInformREM = true;
2384
2385 pgmR3PhysUnlinkRamRange(pVM, &pCur->RamRange);
2386 }
2387
2388 pCur->RamRange.GCPhys = NIL_RTGCPHYS;
2389 pCur->RamRange.GCPhysLast = NIL_RTGCPHYS;
2390 pCur->fOverlapping = false;
2391 pCur->fMapped = false;
2392
2393 /* Force a PGM pool flush as guest ram references have been changed. */
2394 /** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
2395 PVMCPU pVCpu = VMMGetCpu(pVM);
2396 pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_CLEAR_PGM_POOL;
2397 VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
2398
2399 PGMPhysInvalidatePageMapTLB(pVM);
2400 pgmUnlock(pVM);
2401
2402 if (fInformREM)
2403 REMR3NotifyPhysRamDeregister(pVM, GCPhysRangeREM, cbRangeREM);
2404
2405 return VINF_SUCCESS;
2406}
2407
2408
2409/**
2410 * Checks if the given address is an MMIO2 base address or not.
2411 *
2412 * @returns true/false accordingly.
2413 * @param pVM Pointer to the shared VM structure.
2414 * @param pDevIns The owner of the memory, optional.
2415 * @param GCPhys The address to check.
2416 */
2417VMMR3DECL(bool) PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
2418{
2419 /*
2420 * Validate input
2421 */
2422 VM_ASSERT_EMT_RETURN(pVM, false);
2423 AssertPtrReturn(pDevIns, false);
2424 AssertReturn(GCPhys != NIL_RTGCPHYS, false);
2425 AssertReturn(GCPhys != 0, false);
2426 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), false);
2427
2428 /*
2429 * Search the list.
2430 */
2431 pgmLock(pVM);
2432 for (PPGMMMIO2RANGE pCur = pVM->pgm.s.pMmio2RangesR3; pCur; pCur = pCur->pNextR3)
2433 if (pCur->RamRange.GCPhys == GCPhys)
2434 {
2435 Assert(pCur->fMapped);
2436 pgmUnlock(pVM);
2437 return true;
2438 }
2439 pgmUnlock(pVM);
2440 return false;
2441}
2442
2443
2444/**
2445 * Gets the HC physical address of a page in the MMIO2 region.
2446 *
2447 * This is API is intended for MMHyper and shouldn't be called
2448 * by anyone else...
2449 *
2450 * @returns VBox status code.
2451 * @param pVM Pointer to the shared VM structure.
2452 * @param pDevIns The owner of the memory, optional.
2453 * @param iRegion The region.
2454 * @param off The page expressed an offset into the MMIO2 region.
2455 * @param pHCPhys Where to store the result.
2456 */
2457VMMR3DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys)
2458{
2459 /*
2460 * Validate input
2461 */
2462 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2463 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2464 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2465
2466 pgmLock(pVM);
2467 PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
2468 AssertReturn(pCur, VERR_NOT_FOUND);
2469 AssertReturn(off < pCur->RamRange.cb, VERR_INVALID_PARAMETER);
2470
2471 PCPGMPAGE pPage = &pCur->RamRange.aPages[off >> PAGE_SHIFT];
2472 *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage);
2473 pgmUnlock(pVM);
2474 return VINF_SUCCESS;
2475}
2476
2477
2478/**
2479 * Maps a portion of an MMIO2 region into kernel space (host).
2480 *
2481 * The kernel mapping will become invalid when the MMIO2 memory is deregistered
2482 * or the VM is terminated.
2483 *
2484 * @return VBox status code.
2485 *
2486 * @param pVM Pointer to the shared VM structure.
2487 * @param pDevIns The device owning the MMIO2 memory.
2488 * @param iRegion The region.
2489 * @param off The offset into the region. Must be page aligned.
2490 * @param cb The number of bytes to map. Must be page aligned.
2491 * @param pszDesc Mapping description.
2492 * @param pR0Ptr Where to store the R0 address.
2493 */
2494VMMR3DECL(int) PGMR3PhysMMIO2MapKernel(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
2495 const char *pszDesc, PRTR0PTR pR0Ptr)
2496{
2497 /*
2498 * Validate input.
2499 */
2500 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
2501 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2502 AssertReturn(iRegion <= UINT8_MAX, VERR_INVALID_PARAMETER);
2503
2504 PPGMMMIO2RANGE pCur = pgmR3PhysMMIO2Find(pVM, pDevIns, iRegion);
2505 AssertReturn(pCur, VERR_NOT_FOUND);
2506 AssertReturn(off < pCur->RamRange.cb, VERR_INVALID_PARAMETER);
2507 AssertReturn(cb <= pCur->RamRange.cb, VERR_INVALID_PARAMETER);
2508 AssertReturn(off + cb <= pCur->RamRange.cb, VERR_INVALID_PARAMETER);
2509
2510 /*
2511 * Pass the request on to the support library/driver.
2512 */
2513 int rc = SUPR3PageMapKernel(pCur->pvR3, off, cb, 0, pR0Ptr);
2514
2515 return rc;
2516}
2517
2518
2519/**
2520 * Registers a ROM image.
2521 *
2522 * Shadowed ROM images requires double the amount of backing memory, so,
2523 * don't use that unless you have to. Shadowing of ROM images is process
2524 * where we can select where the reads go and where the writes go. On real
2525 * hardware the chipset provides means to configure this. We provide
2526 * PGMR3PhysProtectROM() for this purpose.
2527 *
2528 * A read-only copy of the ROM image will always be kept around while we
2529 * will allocate RAM pages for the changes on demand (unless all memory
2530 * is configured to be preallocated).
2531 *
2532 * @returns VBox status.
2533 * @param pVM VM Handle.
2534 * @param pDevIns The device instance owning the ROM.
2535 * @param GCPhys First physical address in the range.
2536 * Must be page aligned!
2537 * @param cbRange The size of the range (in bytes).
2538 * Must be page aligned!
2539 * @param pvBinary Pointer to the binary data backing the ROM image.
2540 * This must be exactly \a cbRange in size.
2541 * @param fFlags Mask of flags. PGMPHYS_ROM_FLAGS_SHADOWED
2542 * and/or PGMPHYS_ROM_FLAGS_PERMANENT_BINARY.
2543 * @param pszDesc Pointer to description string. This must not be freed.
2544 *
2545 * @remark There is no way to remove the rom, automatically on device cleanup or
2546 * manually from the device yet. This isn't difficult in any way, it's
2547 * just not something we expect to be necessary for a while.
2548 */
2549VMMR3DECL(int) PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb,
2550 const void *pvBinary, uint32_t fFlags, const char *pszDesc)
2551{
2552 Log(("PGMR3PhysRomRegister: pDevIns=%p GCPhys=%RGp(-%RGp) cb=%RGp pvBinary=%p fFlags=%#x pszDesc=%s\n",
2553 pDevIns, GCPhys, GCPhys + cb, cb, pvBinary, fFlags, pszDesc));
2554
2555 /*
2556 * Validate input.
2557 */
2558 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
2559 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
2560 AssertReturn(RT_ALIGN_T(cb, PAGE_SIZE, RTGCPHYS) == cb, VERR_INVALID_PARAMETER);
2561 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
2562 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
2563 AssertPtrReturn(pvBinary, VERR_INVALID_PARAMETER);
2564 AssertPtrReturn(pszDesc, VERR_INVALID_POINTER);
2565 AssertReturn(!(fFlags & ~(PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY)), VERR_INVALID_PARAMETER);
2566 VM_ASSERT_STATE_RETURN(pVM, VMSTATE_CREATING, VERR_VM_INVALID_VM_STATE);
2567
2568 const uint32_t cPages = cb >> PAGE_SHIFT;
2569
2570 /*
2571 * Find the ROM location in the ROM list first.
2572 */
2573 PPGMROMRANGE pRomPrev = NULL;
2574 PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3;
2575 while (pRom && GCPhysLast >= pRom->GCPhys)
2576 {
2577 if ( GCPhys <= pRom->GCPhysLast
2578 && GCPhysLast >= pRom->GCPhys)
2579 AssertLogRelMsgFailedReturn(("%RGp-%RGp (%s) conflicts with existing %RGp-%RGp (%s)\n",
2580 GCPhys, GCPhysLast, pszDesc,
2581 pRom->GCPhys, pRom->GCPhysLast, pRom->pszDesc),
2582 VERR_PGM_RAM_CONFLICT);
2583 /* next */
2584 pRomPrev = pRom;
2585 pRom = pRom->pNextR3;
2586 }
2587
2588 /*
2589 * Find the RAM location and check for conflicts.
2590 *
2591 * Conflict detection is a bit different than for RAM
2592 * registration since a ROM can be located within a RAM
2593 * range. So, what we have to check for is other memory
2594 * types (other than RAM that is) and that we don't span
2595 * more than one RAM range (layz).
2596 */
2597 bool fRamExists = false;
2598 PPGMRAMRANGE pRamPrev = NULL;
2599 PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
2600 while (pRam && GCPhysLast >= pRam->GCPhys)
2601 {
2602 if ( GCPhys <= pRam->GCPhysLast
2603 && GCPhysLast >= pRam->GCPhys)
2604 {
2605 /* completely within? */
2606 AssertLogRelMsgReturn( GCPhys >= pRam->GCPhys
2607 && GCPhysLast <= pRam->GCPhysLast,
2608 ("%RGp-%RGp (%s) falls partly outside %RGp-%RGp (%s)\n",
2609 GCPhys, GCPhysLast, pszDesc,
2610 pRam->GCPhys, pRam->GCPhysLast, pRam->pszDesc),
2611 VERR_PGM_RAM_CONFLICT);
2612 fRamExists = true;
2613 break;
2614 }
2615
2616 /* next */
2617 pRamPrev = pRam;
2618 pRam = pRam->pNextR3;
2619 }
2620 if (fRamExists)
2621 {
2622 PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2623 uint32_t cPagesLeft = cPages;
2624 while (cPagesLeft-- > 0)
2625 {
2626 AssertLogRelMsgReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM,
2627 ("%RGp (%R[pgmpage]) isn't a RAM page - registering %RGp-%RGp (%s).\n",
2628 pRam->GCPhys + ((RTGCPHYS)(uintptr_t)(pPage - &pRam->aPages[0]) << PAGE_SHIFT),
2629 pPage, GCPhys, GCPhysLast, pszDesc), VERR_PGM_RAM_CONFLICT);
2630 Assert(PGM_PAGE_IS_ZERO(pPage));
2631 pPage++;
2632 }
2633 }
2634
2635 /*
2636 * Update the base memory reservation if necessary.
2637 */
2638 uint32_t cExtraBaseCost = fRamExists ? 0 : cPages;
2639 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
2640 cExtraBaseCost += cPages;
2641 if (cExtraBaseCost)
2642 {
2643 int rc = MMR3IncreaseBaseReservation(pVM, cExtraBaseCost);
2644 if (RT_FAILURE(rc))
2645 return rc;
2646 }
2647
2648 /*
2649 * Allocate memory for the virgin copy of the RAM.
2650 */
2651 PGMMALLOCATEPAGESREQ pReq;
2652 int rc = GMMR3AllocatePagesPrepare(pVM, &pReq, cPages, GMMACCOUNT_BASE);
2653 AssertRCReturn(rc, rc);
2654
2655 for (uint32_t iPage = 0; iPage < cPages; iPage++)
2656 {
2657 pReq->aPages[iPage].HCPhysGCPhys = GCPhys + (iPage << PAGE_SHIFT);
2658 pReq->aPages[iPage].idPage = NIL_GMM_PAGEID;
2659 pReq->aPages[iPage].idSharedPage = NIL_GMM_PAGEID;
2660 }
2661
2662 pgmLock(pVM);
2663 rc = GMMR3AllocatePagesPerform(pVM, pReq);
2664 pgmUnlock(pVM);
2665 if (RT_FAILURE(rc))
2666 {
2667 GMMR3AllocatePagesCleanup(pReq);
2668 return rc;
2669 }
2670
2671 /*
2672 * Allocate the new ROM range and RAM range (if necessary).
2673 */
2674 PPGMROMRANGE pRomNew;
2675 rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMROMRANGE, aPages[cPages]), 0, MM_TAG_PGM_PHYS, (void **)&pRomNew);
2676 if (RT_SUCCESS(rc))
2677 {
2678 PPGMRAMRANGE pRamNew = NULL;
2679 if (!fRamExists)
2680 rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]), sizeof(PGMPAGE), MM_TAG_PGM_PHYS, (void **)&pRamNew);
2681 if (RT_SUCCESS(rc))
2682 {
2683 pgmLock(pVM);
2684
2685 /*
2686 * Initialize and insert the RAM range (if required).
2687 */
2688 PPGMROMPAGE pRomPage = &pRomNew->aPages[0];
2689 if (!fRamExists)
2690 {
2691 pRamNew->pSelfR0 = MMHyperCCToR0(pVM, pRamNew);
2692 pRamNew->pSelfRC = MMHyperCCToRC(pVM, pRamNew);
2693 pRamNew->GCPhys = GCPhys;
2694 pRamNew->GCPhysLast = GCPhysLast;
2695 pRamNew->cb = cb;
2696 pRamNew->pszDesc = pszDesc;
2697 pRamNew->fFlags = PGM_RAM_RANGE_FLAGS_AD_HOC_ROM;
2698 pRamNew->pvR3 = NULL;
2699 pRamNew->paLSPages = NULL;
2700
2701 PPGMPAGE pPage = &pRamNew->aPages[0];
2702 for (uint32_t iPage = 0; iPage < cPages; iPage++, pPage++, pRomPage++)
2703 {
2704 PGM_PAGE_INIT(pPage,
2705 pReq->aPages[iPage].HCPhysGCPhys,
2706 pReq->aPages[iPage].idPage,
2707 PGMPAGETYPE_ROM,
2708 PGM_PAGE_STATE_ALLOCATED);
2709
2710 pRomPage->Virgin = *pPage;
2711 }
2712
2713 pVM->pgm.s.cAllPages += cPages;
2714 pgmR3PhysLinkRamRange(pVM, pRamNew, pRamPrev);
2715 }
2716 else
2717 {
2718 PPGMPAGE pPage = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
2719 for (uint32_t iPage = 0; iPage < cPages; iPage++, pPage++, pRomPage++)
2720 {
2721 PGM_PAGE_SET_TYPE(pPage, PGMPAGETYPE_ROM);
2722 PGM_PAGE_SET_HCPHYS(pPage, pReq->aPages[iPage].HCPhysGCPhys);
2723 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ALLOCATED);
2724 PGM_PAGE_SET_PAGEID(pPage, pReq->aPages[iPage].idPage);
2725 PGM_PAGE_SET_PDE_TYPE(pPage, PGM_PAGE_PDE_TYPE_DONTCARE);
2726 PGM_PAGE_SET_PTE_INDEX(pPage, 0);
2727 PGM_PAGE_SET_TRACKING(pPage, 0);
2728
2729 pRomPage->Virgin = *pPage;
2730 }
2731
2732 pRamNew = pRam;
2733
2734 pVM->pgm.s.cZeroPages -= cPages;
2735 }
2736 pVM->pgm.s.cPrivatePages += cPages;
2737
2738 /* Flush physical page map TLB. */
2739 PGMPhysInvalidatePageMapTLB(pVM);
2740
2741 pgmUnlock(pVM);
2742
2743
2744 /*
2745 * !HACK ALERT! REM + (Shadowed) ROM ==> mess.
2746 *
2747 * If it's shadowed we'll register the handler after the ROM notification
2748 * so we get the access handler callbacks that we should. If it isn't
2749 * shadowed we'll do it the other way around to make REM use the built-in
2750 * ROM behavior and not the handler behavior (which is to route all access
2751 * to PGM atm).
2752 */
2753 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
2754 {
2755 REMR3NotifyPhysRomRegister(pVM, GCPhys, cb, NULL, true /* fShadowed */);
2756 rc = PGMR3HandlerPhysicalRegister(pVM,
2757 fFlags & PGMPHYS_ROM_FLAGS_SHADOWED
2758 ? PGMPHYSHANDLERTYPE_PHYSICAL_ALL
2759 : PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
2760 GCPhys, GCPhysLast,
2761 pgmR3PhysRomWriteHandler, pRomNew,
2762 NULL, "pgmPhysRomWriteHandler", MMHyperCCToR0(pVM, pRomNew),
2763 NULL, "pgmPhysRomWriteHandler", MMHyperCCToRC(pVM, pRomNew), pszDesc);
2764 }
2765 else
2766 {
2767 rc = PGMR3HandlerPhysicalRegister(pVM,
2768 fFlags & PGMPHYS_ROM_FLAGS_SHADOWED
2769 ? PGMPHYSHANDLERTYPE_PHYSICAL_ALL
2770 : PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
2771 GCPhys, GCPhysLast,
2772 pgmR3PhysRomWriteHandler, pRomNew,
2773 NULL, "pgmPhysRomWriteHandler", MMHyperCCToR0(pVM, pRomNew),
2774 NULL, "pgmPhysRomWriteHandler", MMHyperCCToRC(pVM, pRomNew), pszDesc);
2775 REMR3NotifyPhysRomRegister(pVM, GCPhys, cb, NULL, false /* fShadowed */);
2776 }
2777 if (RT_SUCCESS(rc))
2778 {
2779 pgmLock(pVM);
2780
2781 /*
2782 * Copy the image over to the virgin pages.
2783 * This must be done after linking in the RAM range.
2784 */
2785 PPGMPAGE pRamPage = &pRamNew->aPages[(GCPhys - pRamNew->GCPhys) >> PAGE_SHIFT];
2786 for (uint32_t iPage = 0; iPage < cPages; iPage++, pRamPage++)
2787 {
2788 void *pvDstPage;
2789 rc = pgmPhysPageMap(pVM, pRamPage, GCPhys + (iPage << PAGE_SHIFT), &pvDstPage);
2790 if (RT_FAILURE(rc))
2791 {
2792 VMSetError(pVM, rc, RT_SRC_POS, "Failed to map virgin ROM page at %RGp", GCPhys);
2793 break;
2794 }
2795 memcpy(pvDstPage, (const uint8_t *)pvBinary + (iPage << PAGE_SHIFT), PAGE_SIZE);
2796 }
2797 if (RT_SUCCESS(rc))
2798 {
2799 /*
2800 * Initialize the ROM range.
2801 * Note that the Virgin member of the pages has already been initialized above.
2802 */
2803 pRomNew->GCPhys = GCPhys;
2804 pRomNew->GCPhysLast = GCPhysLast;
2805 pRomNew->cb = cb;
2806 pRomNew->fFlags = fFlags;
2807 pRomNew->idSavedState = UINT8_MAX;
2808 pRomNew->pvOriginal = fFlags & PGMPHYS_ROM_FLAGS_PERMANENT_BINARY ? pvBinary : NULL;
2809 pRomNew->pszDesc = pszDesc;
2810
2811 for (unsigned iPage = 0; iPage < cPages; iPage++)
2812 {
2813 PPGMROMPAGE pPage = &pRomNew->aPages[iPage];
2814 pPage->enmProt = PGMROMPROT_READ_ROM_WRITE_IGNORE;
2815 PGM_PAGE_INIT_ZERO(&pPage->Shadow, pVM, PGMPAGETYPE_ROM_SHADOW);
2816 }
2817
2818 /* update the page count stats for the shadow pages. */
2819 if (fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
2820 {
2821 pVM->pgm.s.cZeroPages += cPages;
2822 pVM->pgm.s.cAllPages += cPages;
2823 }
2824
2825 /*
2826 * Insert the ROM range, tell REM and return successfully.
2827 */
2828 pRomNew->pNextR3 = pRom;
2829 pRomNew->pNextR0 = pRom ? MMHyperCCToR0(pVM, pRom) : NIL_RTR0PTR;
2830 pRomNew->pNextRC = pRom ? MMHyperCCToRC(pVM, pRom) : NIL_RTRCPTR;
2831
2832 if (pRomPrev)
2833 {
2834 pRomPrev->pNextR3 = pRomNew;
2835 pRomPrev->pNextR0 = MMHyperCCToR0(pVM, pRomNew);
2836 pRomPrev->pNextRC = MMHyperCCToRC(pVM, pRomNew);
2837 }
2838 else
2839 {
2840 pVM->pgm.s.pRomRangesR3 = pRomNew;
2841 pVM->pgm.s.pRomRangesR0 = MMHyperCCToR0(pVM, pRomNew);
2842 pVM->pgm.s.pRomRangesRC = MMHyperCCToRC(pVM, pRomNew);
2843 }
2844
2845 PGMPhysInvalidatePageMapTLB(pVM);
2846 GMMR3AllocatePagesCleanup(pReq);
2847 pgmUnlock(pVM);
2848 return VINF_SUCCESS;
2849 }
2850
2851 /* bail out */
2852
2853 pgmUnlock(pVM);
2854 int rc2 = PGMHandlerPhysicalDeregister(pVM, GCPhys);
2855 AssertRC(rc2);
2856 pgmLock(pVM);
2857 }
2858
2859 if (!fRamExists)
2860 {
2861 pgmR3PhysUnlinkRamRange2(pVM, pRamNew, pRamPrev);
2862 MMHyperFree(pVM, pRamNew);
2863 }
2864 }
2865 MMHyperFree(pVM, pRomNew);
2866 }
2867
2868 /** @todo Purge the mapping cache or something... */
2869 GMMR3FreeAllocatedPages(pVM, pReq);
2870 GMMR3AllocatePagesCleanup(pReq);
2871 pgmUnlock(pVM);
2872 return rc;
2873}
2874
2875
2876/**
2877 * \#PF Handler callback for ROM write accesses.
2878 *
2879 * @returns VINF_SUCCESS if the handler have carried out the operation.
2880 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
2881 * @param pVM VM Handle.
2882 * @param GCPhys The physical address the guest is writing to.
2883 * @param pvPhys The HC mapping of that address.
2884 * @param pvBuf What the guest is reading/writing.
2885 * @param cbBuf How much it's reading/writing.
2886 * @param enmAccessType The access type.
2887 * @param pvUser User argument.
2888 */
2889static DECLCALLBACK(int) pgmR3PhysRomWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
2890{
2891 PPGMROMRANGE pRom = (PPGMROMRANGE)pvUser;
2892 const uint32_t iPage = (GCPhys - pRom->GCPhys) >> PAGE_SHIFT;
2893 Assert(iPage < (pRom->cb >> PAGE_SHIFT));
2894 PPGMROMPAGE pRomPage = &pRom->aPages[iPage];
2895 Log5(("pgmR3PhysRomWriteHandler: %d %c %#08RGp %#04zx\n", pRomPage->enmProt, enmAccessType == PGMACCESSTYPE_READ ? 'R' : 'W', GCPhys, cbBuf));
2896
2897 if (enmAccessType == PGMACCESSTYPE_READ)
2898 {
2899 switch (pRomPage->enmProt)
2900 {
2901 /*
2902 * Take the default action.
2903 */
2904 case PGMROMPROT_READ_ROM_WRITE_IGNORE:
2905 case PGMROMPROT_READ_RAM_WRITE_IGNORE:
2906 case PGMROMPROT_READ_ROM_WRITE_RAM:
2907 case PGMROMPROT_READ_RAM_WRITE_RAM:
2908 return VINF_PGM_HANDLER_DO_DEFAULT;
2909
2910 default:
2911 AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhys=%RGp\n",
2912 pRom->aPages[iPage].enmProt, iPage, GCPhys),
2913 VERR_INTERNAL_ERROR);
2914 }
2915 }
2916 else
2917 {
2918 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
2919 switch (pRomPage->enmProt)
2920 {
2921 /*
2922 * Ignore writes.
2923 */
2924 case PGMROMPROT_READ_ROM_WRITE_IGNORE:
2925 case PGMROMPROT_READ_RAM_WRITE_IGNORE:
2926 return VINF_SUCCESS;
2927
2928 /*
2929 * Write to the ram page.
2930 */
2931 case PGMROMPROT_READ_ROM_WRITE_RAM:
2932 case PGMROMPROT_READ_RAM_WRITE_RAM: /* yes this will get here too, it's *way* simpler that way. */
2933 {
2934 /* This should be impossible now, pvPhys doesn't work cross page anylonger. */
2935 Assert(((GCPhys - pRom->GCPhys + cbBuf - 1) >> PAGE_SHIFT) == iPage);
2936
2937 /*
2938 * Take the lock, do lazy allocation, map the page and copy the data.
2939 *
2940 * Note that we have to bypass the mapping TLB since it works on
2941 * guest physical addresses and entering the shadow page would
2942 * kind of screw things up...
2943 */
2944 int rc = pgmLock(pVM);
2945 AssertRC(rc);
2946
2947 PPGMPAGE pShadowPage = &pRomPage->Shadow;
2948 if (!PGMROMPROT_IS_ROM(pRomPage->enmProt))
2949 {
2950 pShadowPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
2951 AssertLogRelReturn(pShadowPage, VERR_INTERNAL_ERROR);
2952 }
2953
2954 void *pvDstPage;
2955 rc = pgmPhysPageMakeWritableAndMap(pVM, pShadowPage, GCPhys & X86_PTE_PG_MASK, &pvDstPage);
2956 if (RT_SUCCESS(rc))
2957 {
2958 memcpy((uint8_t *)pvDstPage + (GCPhys & PAGE_OFFSET_MASK), pvBuf, cbBuf);
2959 pRomPage->LiveSave.fWrittenTo = true;
2960 }
2961
2962 pgmUnlock(pVM);
2963 return rc;
2964 }
2965
2966 default:
2967 AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhys=%RGp\n",
2968 pRom->aPages[iPage].enmProt, iPage, GCPhys),
2969 VERR_INTERNAL_ERROR);
2970 }
2971 }
2972}
2973
2974
2975/**
2976 * Called by PGMR3Reset to reset the shadow, switch to the virgin,
2977 * and verify that the virgin part is untouched.
2978 *
2979 * This is done after the normal memory has been cleared.
2980 *
2981 * ASSUMES that the caller owns the PGM lock.
2982 *
2983 * @param pVM The VM handle.
2984 */
2985int pgmR3PhysRomReset(PVM pVM)
2986{
2987 Assert(PGMIsLockOwner(pVM));
2988 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)
2989 {
2990 const uint32_t cPages = pRom->cb >> PAGE_SHIFT;
2991
2992 if (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)
2993 {
2994 /*
2995 * Reset the physical handler.
2996 */
2997 int rc = PGMR3PhysRomProtect(pVM, pRom->GCPhys, pRom->cb, PGMROMPROT_READ_ROM_WRITE_IGNORE);
2998 AssertRCReturn(rc, rc);
2999
3000 /*
3001 * What we do with the shadow pages depends on the memory
3002 * preallocation option. If not enabled, we'll just throw
3003 * out all the dirty pages and replace them by the zero page.
3004 */
3005 if (!pVM->pgm.s.fRamPreAlloc)
3006 {
3007 /* Free the dirty pages. */
3008 uint32_t cPendingPages = 0;
3009 PGMMFREEPAGESREQ pReq;
3010 rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
3011 AssertRCReturn(rc, rc);
3012
3013 for (uint32_t iPage = 0; iPage < cPages; iPage++)
3014 if ( !PGM_PAGE_IS_ZERO(&pRom->aPages[iPage].Shadow)
3015 && !PGM_PAGE_IS_BALLOONED(&pRom->aPages[iPage].Shadow))
3016 {
3017 Assert(PGM_PAGE_GET_STATE(&pRom->aPages[iPage].Shadow) == PGM_PAGE_STATE_ALLOCATED);
3018 rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, &pRom->aPages[iPage].Shadow, pRom->GCPhys + (iPage << PAGE_SHIFT));
3019 AssertLogRelRCReturn(rc, rc);
3020 }
3021
3022 if (cPendingPages)
3023 {
3024 rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
3025 AssertLogRelRCReturn(rc, rc);
3026 }
3027 GMMR3FreePagesCleanup(pReq);
3028 }
3029 else
3030 {
3031 /* clear all the shadow pages. */
3032 for (uint32_t iPage = 0; iPage < cPages; iPage++)
3033 {
3034 Assert(!PGM_PAGE_IS_ZERO(&pRom->aPages[iPage].Shadow) && !PGM_PAGE_IS_BALLOONED(&pRom->aPages[iPage].Shadow));
3035 void *pvDstPage;
3036 const RTGCPHYS GCPhys = pRom->GCPhys + (iPage << PAGE_SHIFT);
3037 rc = pgmPhysPageMakeWritableAndMap(pVM, &pRom->aPages[iPage].Shadow, GCPhys, &pvDstPage);
3038 if (RT_FAILURE(rc))
3039 break;
3040 ASMMemZeroPage(pvDstPage);
3041 }
3042 AssertRCReturn(rc, rc);
3043 }
3044 }
3045
3046#ifdef VBOX_STRICT
3047 /*
3048 * Verify that the virgin page is unchanged if possible.
3049 */
3050 if (pRom->pvOriginal)
3051 {
3052 uint8_t const *pbSrcPage = (uint8_t const *)pRom->pvOriginal;
3053 for (uint32_t iPage = 0; iPage < cPages; iPage++, pbSrcPage += PAGE_SIZE)
3054 {
3055 const RTGCPHYS GCPhys = pRom->GCPhys + (iPage << PAGE_SHIFT);
3056 void const *pvDstPage;
3057 int rc = pgmPhysPageMapReadOnly(pVM, &pRom->aPages[iPage].Virgin, GCPhys, &pvDstPage);
3058 if (RT_FAILURE(rc))
3059 break;
3060 if (memcmp(pvDstPage, pbSrcPage, PAGE_SIZE))
3061 LogRel(("pgmR3PhysRomReset: %RGp rom page changed (%s) - loaded saved state?\n",
3062 GCPhys, pRom->pszDesc));
3063 }
3064 }
3065#endif
3066 }
3067
3068 return VINF_SUCCESS;
3069}
3070
3071
3072/**
3073 * Change the shadowing of a range of ROM pages.
3074 *
3075 * This is intended for implementing chipset specific memory registers
3076 * and will not be very strict about the input. It will silently ignore
3077 * any pages that are not the part of a shadowed ROM.
3078 *
3079 * @returns VBox status code.
3080 * @retval VINF_PGM_SYNC_CR3
3081 *
3082 * @param pVM Pointer to the shared VM structure.
3083 * @param GCPhys Where to start. Page aligned.
3084 * @param cb How much to change. Page aligned.
3085 * @param enmProt The new ROM protection.
3086 */
3087VMMR3DECL(int) PGMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMROMPROT enmProt)
3088{
3089 /*
3090 * Check input
3091 */
3092 if (!cb)
3093 return VINF_SUCCESS;
3094 AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
3095 AssertReturn(!(cb & PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
3096 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
3097 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
3098 AssertReturn(enmProt >= PGMROMPROT_INVALID && enmProt <= PGMROMPROT_END, VERR_INVALID_PARAMETER);
3099
3100 /*
3101 * Process the request.
3102 */
3103 pgmLock(pVM);
3104 int rc = VINF_SUCCESS;
3105 bool fFlushTLB = false;
3106 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)
3107 {
3108 if ( GCPhys <= pRom->GCPhysLast
3109 && GCPhysLast >= pRom->GCPhys
3110 && (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED))
3111 {
3112 /*
3113 * Iterate the relevant pages and make necessary the changes.
3114 */
3115 bool fChanges = false;
3116 uint32_t const cPages = pRom->GCPhysLast <= GCPhysLast
3117 ? pRom->cb >> PAGE_SHIFT
3118 : (GCPhysLast - pRom->GCPhys + 1) >> PAGE_SHIFT;
3119 for (uint32_t iPage = (GCPhys - pRom->GCPhys) >> PAGE_SHIFT;
3120 iPage < cPages;
3121 iPage++)
3122 {
3123 PPGMROMPAGE pRomPage = &pRom->aPages[iPage];
3124 if (PGMROMPROT_IS_ROM(pRomPage->enmProt) != PGMROMPROT_IS_ROM(enmProt))
3125 {
3126 fChanges = true;
3127
3128 /* flush references to the page. */
3129 PPGMPAGE pRamPage = pgmPhysGetPage(&pVM->pgm.s, pRom->GCPhys + (iPage << PAGE_SHIFT));
3130 int rc2 = pgmPoolTrackFlushGCPhys(pVM, pRom->GCPhys + (iPage << PAGE_SHIFT), pRamPage, &fFlushTLB);
3131 if (rc2 != VINF_SUCCESS && (rc == VINF_SUCCESS || RT_FAILURE(rc2)))
3132 rc = rc2;
3133
3134 PPGMPAGE pOld = PGMROMPROT_IS_ROM(pRomPage->enmProt) ? &pRomPage->Virgin : &pRomPage->Shadow;
3135 PPGMPAGE pNew = PGMROMPROT_IS_ROM(pRomPage->enmProt) ? &pRomPage->Shadow : &pRomPage->Virgin;
3136
3137 *pOld = *pRamPage;
3138 *pRamPage = *pNew;
3139 /** @todo preserve the volatile flags (handlers) when these have been moved out of HCPhys! */
3140 }
3141 pRomPage->enmProt = enmProt;
3142 }
3143
3144 /*
3145 * Reset the access handler if we made changes, no need
3146 * to optimize this.
3147 */
3148 if (fChanges)
3149 {
3150 int rc2 = PGMHandlerPhysicalReset(pVM, pRom->GCPhys);
3151 if (RT_FAILURE(rc2))
3152 {
3153 pgmUnlock(pVM);
3154 AssertRC(rc);
3155 return rc2;
3156 }
3157 }
3158
3159 /* Advance - cb isn't updated. */
3160 GCPhys = pRom->GCPhys + (cPages << PAGE_SHIFT);
3161 }
3162 }
3163 pgmUnlock(pVM);
3164 if (fFlushTLB)
3165 PGM_INVL_ALL_VCPU_TLBS(pVM);
3166
3167 return rc;
3168}
3169
3170
3171/**
3172 * Sets the Address Gate 20 state.
3173 *
3174 * @param pVCpu The VCPU to operate on.
3175 * @param fEnable True if the gate should be enabled.
3176 * False if the gate should be disabled.
3177 */
3178VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable)
3179{
3180 LogFlow(("PGMR3PhysSetA20 %d (was %d)\n", fEnable, pVCpu->pgm.s.fA20Enabled));
3181 if (pVCpu->pgm.s.fA20Enabled != fEnable)
3182 {
3183 pVCpu->pgm.s.fA20Enabled = fEnable;
3184 pVCpu->pgm.s.GCPhysA20Mask = ~(RTGCPHYS)(!fEnable << 20);
3185 REMR3A20Set(pVCpu->pVMR3, pVCpu, fEnable);
3186 /** @todo we're not handling this correctly for VT-x / AMD-V. See #2911 */
3187 }
3188}
3189
3190
3191/**
3192 * Tree enumeration callback for dealing with age rollover.
3193 * It will perform a simple compression of the current age.
3194 */
3195static DECLCALLBACK(int) pgmR3PhysChunkAgeingRolloverCallback(PAVLU32NODECORE pNode, void *pvUser)
3196{
3197 Assert(PGMIsLockOwner((PVM)pvUser));
3198 /* Age compression - ASSUMES iNow == 4. */
3199 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)pNode;
3200 if (pChunk->iAge >= UINT32_C(0xffffff00))
3201 pChunk->iAge = 3;
3202 else if (pChunk->iAge >= UINT32_C(0xfffff000))
3203 pChunk->iAge = 2;
3204 else if (pChunk->iAge)
3205 pChunk->iAge = 1;
3206 else /* iAge = 0 */
3207 pChunk->iAge = 4;
3208
3209 /* reinsert */
3210 PVM pVM = (PVM)pvUser;
3211 RTAvllU32Remove(&pVM->pgm.s.ChunkR3Map.pAgeTree, pChunk->AgeCore.Key);
3212 pChunk->AgeCore.Key = pChunk->iAge;
3213 RTAvllU32Insert(&pVM->pgm.s.ChunkR3Map.pAgeTree, &pChunk->AgeCore);
3214 return 0;
3215}
3216
3217
3218/**
3219 * Tree enumeration callback that updates the chunks that have
3220 * been used since the last
3221 */
3222static DECLCALLBACK(int) pgmR3PhysChunkAgeingCallback(PAVLU32NODECORE pNode, void *pvUser)
3223{
3224 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)pNode;
3225 if (!pChunk->iAge)
3226 {
3227 PVM pVM = (PVM)pvUser;
3228 RTAvllU32Remove(&pVM->pgm.s.ChunkR3Map.pAgeTree, pChunk->AgeCore.Key);
3229 pChunk->AgeCore.Key = pChunk->iAge = pVM->pgm.s.ChunkR3Map.iNow;
3230 RTAvllU32Insert(&pVM->pgm.s.ChunkR3Map.pAgeTree, &pChunk->AgeCore);
3231 }
3232
3233 return 0;
3234}
3235
3236
3237/**
3238 * Performs ageing of the ring-3 chunk mappings.
3239 *
3240 * @param pVM The VM handle.
3241 */
3242VMMR3DECL(void) PGMR3PhysChunkAgeing(PVM pVM)
3243{
3244 pgmLock(pVM);
3245 pVM->pgm.s.ChunkR3Map.AgeingCountdown = RT_MIN(pVM->pgm.s.ChunkR3Map.cMax / 4, 1024);
3246 pVM->pgm.s.ChunkR3Map.iNow++;
3247 if (pVM->pgm.s.ChunkR3Map.iNow == 0)
3248 {
3249 pVM->pgm.s.ChunkR3Map.iNow = 4;
3250 RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkAgeingRolloverCallback, pVM);
3251 }
3252 else
3253 RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkAgeingCallback, pVM);
3254 pgmUnlock(pVM);
3255}
3256
3257
3258/**
3259 * The structure passed in the pvUser argument of pgmR3PhysChunkUnmapCandidateCallback().
3260 */
3261typedef struct PGMR3PHYSCHUNKUNMAPCB
3262{
3263 PVM pVM; /**< The VM handle. */
3264 PPGMCHUNKR3MAP pChunk; /**< The chunk to unmap. */
3265} PGMR3PHYSCHUNKUNMAPCB, *PPGMR3PHYSCHUNKUNMAPCB;
3266
3267
3268/**
3269 * Callback used to find the mapping that's been unused for
3270 * the longest time.
3271 */
3272static DECLCALLBACK(int) pgmR3PhysChunkUnmapCandidateCallback(PAVLLU32NODECORE pNode, void *pvUser)
3273{
3274 do
3275 {
3276 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)((uint8_t *)pNode - RT_OFFSETOF(PGMCHUNKR3MAP, AgeCore));
3277 if ( pChunk->iAge
3278 && !pChunk->cRefs)
3279 {
3280 /*
3281 * Check that it's not in any of the TLBs.
3282 */
3283 PVM pVM = ((PPGMR3PHYSCHUNKUNMAPCB)pvUser)->pVM;
3284 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.ChunkR3Map.Tlb.aEntries); i++)
3285 if (pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].pChunk == pChunk)
3286 {
3287 pChunk = NULL;
3288 break;
3289 }
3290 if (pChunk)
3291 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.PhysTlbHC.aEntries); i++)
3292 if (pVM->pgm.s.PhysTlbHC.aEntries[i].pMap == pChunk)
3293 {
3294 pChunk = NULL;
3295 break;
3296 }
3297 if (pChunk)
3298 {
3299 ((PPGMR3PHYSCHUNKUNMAPCB)pvUser)->pChunk = pChunk;
3300 return 1; /* done */
3301 }
3302 }
3303
3304 /* next with the same age - this version of the AVL API doesn't enumerate the list, so we have to do it. */
3305 pNode = pNode->pList;
3306 } while (pNode);
3307 return 0;
3308}
3309
3310
3311/**
3312 * Finds a good candidate for unmapping when the ring-3 mapping cache is full.
3313 *
3314 * The candidate will not be part of any TLBs, so no need to flush
3315 * anything afterwards.
3316 *
3317 * @returns Chunk id.
3318 * @param pVM The VM handle.
3319 */
3320static int32_t pgmR3PhysChunkFindUnmapCandidate(PVM pVM)
3321{
3322 Assert(PGMIsLockOwner(pVM));
3323
3324 /*
3325 * Do tree ageing first?
3326 */
3327 if (pVM->pgm.s.ChunkR3Map.AgeingCountdown-- == 0)
3328 PGMR3PhysChunkAgeing(pVM);
3329
3330 /*
3331 * Enumerate the age tree starting with the left most node.
3332 */
3333 PGMR3PHYSCHUNKUNMAPCB Args;
3334 Args.pVM = pVM;
3335 Args.pChunk = NULL;
3336 if (RTAvllU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pAgeTree, true /*fFromLeft*/, pgmR3PhysChunkUnmapCandidateCallback, pVM))
3337 return Args.pChunk->Core.Key;
3338 return INT32_MAX;
3339}
3340
3341
3342/**
3343 * Maps the given chunk into the ring-3 mapping cache.
3344 *
3345 * This will call ring-0.
3346 *
3347 * @returns VBox status code.
3348 * @param pVM The VM handle.
3349 * @param idChunk The chunk in question.
3350 * @param ppChunk Where to store the chunk tracking structure.
3351 *
3352 * @remarks Called from within the PGM critical section.
3353 */
3354int pgmR3PhysChunkMap(PVM pVM, uint32_t idChunk, PPPGMCHUNKR3MAP ppChunk)
3355{
3356 int rc;
3357
3358 Assert(PGMIsLockOwner(pVM));
3359 /*
3360 * Allocate a new tracking structure first.
3361 */
3362#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3363 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)MMR3HeapAlloc(pVM, MM_TAG_PGM_CHUNK_MAPPING, sizeof(*pChunk));
3364#else
3365 PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)MMR3UkHeapAlloc(pVM, MM_TAG_PGM_CHUNK_MAPPING, sizeof(*pChunk), NULL);
3366#endif
3367 AssertReturn(pChunk, VERR_NO_MEMORY);
3368 pChunk->Core.Key = idChunk;
3369 pChunk->AgeCore.Key = pVM->pgm.s.ChunkR3Map.iNow;
3370 pChunk->iAge = 0;
3371 pChunk->cRefs = 0;
3372 pChunk->cPermRefs = 0;
3373 pChunk->pv = NULL;
3374
3375 /*
3376 * Request the ring-0 part to map the chunk in question and if
3377 * necessary unmap another one to make space in the mapping cache.
3378 */
3379 GMMMAPUNMAPCHUNKREQ Req;
3380 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
3381 Req.Hdr.cbReq = sizeof(Req);
3382 Req.pvR3 = NULL;
3383 Req.idChunkMap = idChunk;
3384 Req.idChunkUnmap = NIL_GMM_CHUNKID;
3385 if (pVM->pgm.s.ChunkR3Map.c >= pVM->pgm.s.ChunkR3Map.cMax)
3386 Req.idChunkUnmap = pgmR3PhysChunkFindUnmapCandidate(pVM);
3387
3388 /* Must be callable from any thread, so can't use VMMR3CallR0. */
3389 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, pVCpu->idCpu, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
3390 if (RT_SUCCESS(rc))
3391 {
3392 /*
3393 * Update the tree.
3394 */
3395 /* insert the new one. */
3396 AssertPtr(Req.pvR3);
3397 pChunk->pv = Req.pvR3;
3398 bool fRc = RTAvlU32Insert(&pVM->pgm.s.ChunkR3Map.pTree, &pChunk->Core);
3399 AssertRelease(fRc);
3400 pVM->pgm.s.ChunkR3Map.c++;
3401
3402 fRc = RTAvllU32Insert(&pVM->pgm.s.ChunkR3Map.pAgeTree, &pChunk->AgeCore);
3403 AssertRelease(fRc);
3404
3405 /* remove the unmapped one. */
3406 if (Req.idChunkUnmap != NIL_GMM_CHUNKID)
3407 {
3408 PPGMCHUNKR3MAP pUnmappedChunk = (PPGMCHUNKR3MAP)RTAvlU32Remove(&pVM->pgm.s.ChunkR3Map.pTree, Req.idChunkUnmap);
3409 AssertRelease(pUnmappedChunk);
3410 pUnmappedChunk->pv = NULL;
3411 pUnmappedChunk->Core.Key = UINT32_MAX;
3412#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3413 MMR3HeapFree(pUnmappedChunk);
3414#else
3415 MMR3UkHeapFree(pVM, pUnmappedChunk, MM_TAG_PGM_CHUNK_MAPPING);
3416#endif
3417 pVM->pgm.s.ChunkR3Map.c--;
3418
3419 /* Chunk removed, so clear the page map TBL as well (might still be referenced). */
3420 PGMPhysInvalidatePageMapTLB(pVM);
3421 }
3422 }
3423 else
3424 {
3425 AssertRC(rc);
3426#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
3427 MMR3HeapFree(pChunk);
3428#else
3429 MMR3UkHeapFree(pVM, pChunk, MM_TAG_PGM_CHUNK_MAPPING);
3430#endif
3431 pChunk = NULL;
3432 }
3433
3434 *ppChunk = pChunk;
3435 return rc;
3436}
3437
3438
3439/**
3440 * For VMMCALLRING3_PGM_MAP_CHUNK, considered internal.
3441 *
3442 * @returns see pgmR3PhysChunkMap.
3443 * @param pVM The VM handle.
3444 * @param idChunk The chunk to map.
3445 */
3446VMMR3DECL(int) PGMR3PhysChunkMap(PVM pVM, uint32_t idChunk)
3447{
3448 PPGMCHUNKR3MAP pChunk;
3449 int rc;
3450
3451 pgmLock(pVM);
3452 rc = pgmR3PhysChunkMap(pVM, idChunk, &pChunk);
3453 pgmUnlock(pVM);
3454 return rc;
3455}
3456
3457
3458/**
3459 * Invalidates the TLB for the ring-3 mapping cache.
3460 *
3461 * @param pVM The VM handle.
3462 */
3463VMMR3DECL(void) PGMR3PhysChunkInvalidateTLB(PVM pVM)
3464{
3465 pgmLock(pVM);
3466 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.ChunkR3Map.Tlb.aEntries); i++)
3467 {
3468 pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].idChunk = NIL_GMM_CHUNKID;
3469 pVM->pgm.s.ChunkR3Map.Tlb.aEntries[i].pChunk = NULL;
3470 }
3471 /* The page map TLB references chunks, so invalidate that one too. */
3472 PGMPhysInvalidatePageMapTLB(pVM);
3473 pgmUnlock(pVM);
3474}
3475
3476
3477/**
3478 * Response to VMMCALLRING3_PGM_ALLOCATE_LARGE_PAGE to allocate a large (2MB) page
3479 * for use with a nested paging PDE.
3480 *
3481 * @returns The following VBox status codes.
3482 * @retval VINF_SUCCESS on success.
3483 * @retval VINF_EM_NO_MEMORY if we're out of memory.
3484 *
3485 * @param pVM The VM handle.
3486 * @param GCPhys GC physical start address of the 2 MB range
3487 */
3488VMMR3DECL(int) PGMR3PhysAllocateLargeHandyPage(PVM pVM, RTGCPHYS GCPhys)
3489{
3490 pgmLock(pVM);
3491
3492 STAM_PROFILE_START(&pVM->pgm.s.StatAllocLargePage, a);
3493 int rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_ALLOCATE_LARGE_HANDY_PAGE, 0, NULL);
3494 STAM_PROFILE_STOP(&pVM->pgm.s.StatAllocLargePage, a);
3495 if (RT_SUCCESS(rc))
3496 {
3497 Assert(pVM->pgm.s.cLargeHandyPages == 1);
3498
3499 uint32_t idPage = pVM->pgm.s.aLargeHandyPage[0].idPage;
3500 RTHCPHYS HCPhys = pVM->pgm.s.aLargeHandyPage[0].HCPhysGCPhys;
3501
3502 void *pv;
3503
3504 /* Map the large page into our address space.
3505 *
3506 * Note: assuming that within the 2 MB range:
3507 * - GCPhys + PAGE_SIZE = HCPhys + PAGE_SIZE (whole point of this exercise)
3508 * - user space mapping is continuous as well
3509 * - page id (GCPhys) + 1 = page id (GCPhys + PAGE_SIZE)
3510 */
3511 rc = pgmPhysPageMapByPageID(pVM, idPage, HCPhys, &pv);
3512 AssertLogRelMsg(RT_SUCCESS(rc), ("idPage=%#x HCPhysGCPhys=%RHp rc=%Rrc", idPage, HCPhys, rc));
3513
3514 if (RT_SUCCESS(rc))
3515 {
3516 /*
3517 * Clear the pages.
3518 */
3519 STAM_PROFILE_START(&pVM->pgm.s.StatClearLargePage, b);
3520 for (unsigned i = 0; i < _2M/PAGE_SIZE; i++)
3521 {
3522 ASMMemZeroPage(pv);
3523
3524 PPGMPAGE pPage;
3525 rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhys, &pPage);
3526 AssertRC(rc);
3527
3528 Assert(PGM_PAGE_IS_ZERO(pPage));
3529 STAM_COUNTER_INC(&pVM->pgm.s.StatRZPageReplaceZero);
3530 pVM->pgm.s.cZeroPages--;
3531
3532 /*
3533 * Do the PGMPAGE modifications.
3534 */
3535 pVM->pgm.s.cPrivatePages++;
3536 PGM_PAGE_SET_HCPHYS(pPage, HCPhys);
3537 PGM_PAGE_SET_PAGEID(pPage, idPage);
3538 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ALLOCATED);
3539 PGM_PAGE_SET_PDE_TYPE(pPage, PGM_PAGE_PDE_TYPE_PDE);
3540 PGM_PAGE_SET_PTE_INDEX(pPage, 0);
3541 PGM_PAGE_SET_TRACKING(pPage, 0);
3542
3543 /* Somewhat dirty assumption that page ids are increasing. */
3544 idPage++;
3545
3546 HCPhys += PAGE_SIZE;
3547 GCPhys += PAGE_SIZE;
3548
3549 pv = (void *)((uintptr_t)pv + PAGE_SIZE);
3550
3551 Log3(("PGMR3PhysAllocateLargePage: idPage=%#x HCPhys=%RGp\n", idPage, HCPhys));
3552 }
3553 STAM_PROFILE_STOP(&pVM->pgm.s.StatClearLargePage, b);
3554
3555 /* Flush all TLBs. */
3556 PGM_INVL_ALL_VCPU_TLBS(pVM);
3557 PGMPhysInvalidatePageMapTLB(pVM);
3558 }
3559 pVM->pgm.s.cLargeHandyPages = 0;
3560 }
3561
3562 pgmUnlock(pVM);
3563 return rc;
3564}
3565
3566
3567/**
3568 * Response to VM_FF_PGM_NEED_HANDY_PAGES and VMMCALLRING3_PGM_ALLOCATE_HANDY_PAGES.
3569 *
3570 * This function will also work the VM_FF_PGM_NO_MEMORY force action flag, to
3571 * signal and clear the out of memory condition. When contracted, this API is
3572 * used to try clear the condition when the user wants to resume.
3573 *
3574 * @returns The following VBox status codes.
3575 * @retval VINF_SUCCESS on success. FFs cleared.
3576 * @retval VINF_EM_NO_MEMORY if we're out of memory. The FF is not cleared in
3577 * this case and it gets accompanied by VM_FF_PGM_NO_MEMORY.
3578 *
3579 * @param pVM The VM handle.
3580 *
3581 * @remarks The VINF_EM_NO_MEMORY status is for the benefit of the FF processing
3582 * in EM.cpp and shouldn't be propagated outside TRPM, HWACCM, EM and
3583 * pgmPhysEnsureHandyPage. There is one exception to this in the \#PF
3584 * handler.
3585 */
3586VMMR3DECL(int) PGMR3PhysAllocateHandyPages(PVM pVM)
3587{
3588 pgmLock(pVM);
3589
3590 /*
3591 * Allocate more pages, noting down the index of the first new page.
3592 */
3593 uint32_t iClear = pVM->pgm.s.cHandyPages;
3594 AssertMsgReturn(iClear <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), ("%d", iClear), VERR_INTERNAL_ERROR);
3595 Log(("PGMR3PhysAllocateHandyPages: %d -> %d\n", iClear, RT_ELEMENTS(pVM->pgm.s.aHandyPages)));
3596 int rcAlloc = VINF_SUCCESS;
3597 int rcSeed = VINF_SUCCESS;
3598 int rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES, 0, NULL);
3599 while (rc == VERR_GMM_SEED_ME)
3600 {
3601 void *pvChunk;
3602 rcAlloc = rc = SUPR3PageAlloc(GMM_CHUNK_SIZE >> PAGE_SHIFT, &pvChunk);
3603 if (RT_SUCCESS(rc))
3604 {
3605 rcSeed = rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_SEED_CHUNK, (uintptr_t)pvChunk, NULL);
3606 if (RT_FAILURE(rc))
3607 SUPR3PageFree(pvChunk, GMM_CHUNK_SIZE >> PAGE_SHIFT);
3608 }
3609 if (RT_SUCCESS(rc))
3610 rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES, 0, NULL);
3611 }
3612
3613 if (RT_SUCCESS(rc))
3614 {
3615 AssertMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
3616 Assert(pVM->pgm.s.cHandyPages > 0);
3617 VM_FF_CLEAR(pVM, VM_FF_PGM_NEED_HANDY_PAGES);
3618 VM_FF_CLEAR(pVM, VM_FF_PGM_NO_MEMORY);
3619
3620 /*
3621 * Clear the pages.
3622 */
3623 while (iClear < pVM->pgm.s.cHandyPages)
3624 {
3625 PGMMPAGEDESC pPage = &pVM->pgm.s.aHandyPages[iClear];
3626 void *pv;
3627 rc = pgmPhysPageMapByPageID(pVM, pPage->idPage, pPage->HCPhysGCPhys, &pv);
3628 AssertLogRelMsgBreak(RT_SUCCESS(rc), ("idPage=%#x HCPhysGCPhys=%RHp rc=%Rrc", pPage->idPage, pPage->HCPhysGCPhys, rc));
3629 ASMMemZeroPage(pv);
3630 iClear++;
3631 Log3(("PGMR3PhysAllocateHandyPages: idPage=%#x HCPhys=%RGp\n", pPage->idPage, pPage->HCPhysGCPhys));
3632 }
3633 }
3634 else
3635 {
3636 uint64_t cAllocPages, cMaxPages, cBalloonPages;
3637
3638 /*
3639 * We should never get here unless there is a genuine shortage of
3640 * memory (or some internal error). Flag the error so the VM can be
3641 * suspended ASAP and the user informed. If we're totally out of
3642 * handy pages we will return failure.
3643 */
3644 /* Report the failure. */
3645 LogRel(("PGM: Failed to procure handy pages; rc=%Rrc rcAlloc=%Rrc rcSeed=%Rrc cHandyPages=%#x\n"
3646 " cAllPages=%#x cPrivatePages=%#x cSharedPages=%#x cZeroPages=%#x\n",
3647 rc, rcAlloc, rcSeed,
3648 pVM->pgm.s.cHandyPages,
3649 pVM->pgm.s.cAllPages,
3650 pVM->pgm.s.cPrivatePages,
3651 pVM->pgm.s.cSharedPages,
3652 pVM->pgm.s.cZeroPages));
3653
3654 if (GMMR3QueryMemoryStats(pVM, &cAllocPages, &cMaxPages, &cBalloonPages) == VINF_SUCCESS)
3655 {
3656 LogRel(("GMM: Statistics:\n"
3657 " Allocated pages: %RX64\n"
3658 " Maximum pages: %RX64\n"
3659 " Ballooned pages: %RX64\n", cAllocPages, cMaxPages, cBalloonPages));
3660 }
3661
3662 if ( rc != VERR_NO_MEMORY
3663 && rc != VERR_LOCK_FAILED)
3664 {
3665 for (uint32_t i = 0; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
3666 {
3667 LogRel(("PGM: aHandyPages[#%#04x] = {.HCPhysGCPhys=%RHp, .idPage=%#08x, .idSharedPage=%#08x}\n",
3668 i, pVM->pgm.s.aHandyPages[i].HCPhysGCPhys, pVM->pgm.s.aHandyPages[i].idPage,
3669 pVM->pgm.s.aHandyPages[i].idSharedPage));
3670 uint32_t const idPage = pVM->pgm.s.aHandyPages[i].idPage;
3671 if (idPage != NIL_GMM_PAGEID)
3672 {
3673 for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesR3;
3674 pRam;
3675 pRam = pRam->pNextR3)
3676 {
3677 uint32_t const cPages = pRam->cb >> PAGE_SHIFT;
3678 for (uint32_t iPage = 0; iPage < cPages; iPage++)
3679 if (PGM_PAGE_GET_PAGEID(&pRam->aPages[iPage]) == idPage)
3680 LogRel(("PGM: Used by %RGp %R[pgmpage] (%s)\n",
3681 pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), &pRam->aPages[iPage], pRam->pszDesc));
3682 }
3683 }
3684 }
3685 }
3686
3687 /* Set the FFs and adjust rc. */
3688 VM_FF_SET(pVM, VM_FF_PGM_NEED_HANDY_PAGES);
3689 VM_FF_SET(pVM, VM_FF_PGM_NO_MEMORY);
3690 if ( rc == VERR_NO_MEMORY
3691 || rc == VERR_LOCK_FAILED)
3692 rc = VINF_EM_NO_MEMORY;
3693 }
3694
3695 pgmUnlock(pVM);
3696 return rc;
3697}
3698
3699
3700/**
3701 * Frees the specified RAM page and replaces it with the ZERO page.
3702 *
3703 * This is used by ballooning, remapping MMIO2 and RAM reset.
3704 *
3705 * @param pVM Pointer to the shared VM structure.
3706 * @param pReq Pointer to the request.
3707 * @param pPage Pointer to the page structure.
3708 * @param GCPhys The guest physical address of the page, if applicable.
3709 *
3710 * @remarks The caller must own the PGM lock.
3711 */
3712static int pgmPhysFreePage(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t *pcPendingPages, PPGMPAGE pPage, RTGCPHYS GCPhys)
3713{
3714 /*
3715 * Assert sanity.
3716 */
3717 Assert(PGMIsLockOwner(pVM));
3718 if (RT_UNLIKELY( PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_RAM
3719 && PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_ROM_SHADOW))
3720 {
3721 AssertMsgFailed(("GCPhys=%RGp pPage=%R[pgmpage]\n", GCPhys, pPage));
3722 return VMSetError(pVM, VERR_PGM_PHYS_NOT_RAM, RT_SRC_POS, "GCPhys=%RGp type=%d", GCPhys, PGM_PAGE_GET_TYPE(pPage));
3723 }
3724
3725 if ( PGM_PAGE_IS_ZERO(pPage)
3726 || PGM_PAGE_IS_BALLOONED(pPage))
3727 return VINF_SUCCESS;
3728
3729 const uint32_t idPage = PGM_PAGE_GET_PAGEID(pPage);
3730 Log3(("pgmPhysFreePage: idPage=%#x HCPhys=%RGp pPage=%R[pgmpage]\n", idPage, pPage));
3731 if (RT_UNLIKELY( idPage == NIL_GMM_PAGEID
3732 || idPage > GMM_PAGEID_LAST
3733 || PGM_PAGE_GET_CHUNKID(pPage) == NIL_GMM_CHUNKID))
3734 {
3735 AssertMsgFailed(("GCPhys=%RGp pPage=%R[pgmpage]\n", GCPhys, pPage));
3736 return VMSetError(pVM, VERR_PGM_PHYS_INVALID_PAGE_ID, RT_SRC_POS, "GCPhys=%RGp idPage=%#x", GCPhys, pPage);
3737 }
3738
3739 /* update page count stats. */
3740 if (PGM_PAGE_IS_SHARED(pPage))
3741 pVM->pgm.s.cSharedPages--;
3742 else
3743 pVM->pgm.s.cPrivatePages--;
3744 pVM->pgm.s.cZeroPages++;
3745
3746 /* Deal with write monitored pages. */
3747 if (PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED)
3748 {
3749 PGM_PAGE_SET_WRITTEN_TO(pPage);
3750 pVM->pgm.s.cWrittenToPages++;
3751 }
3752
3753 /*
3754 * pPage = ZERO page.
3755 */
3756 PGM_PAGE_SET_HCPHYS(pPage, pVM->pgm.s.HCPhysZeroPg);
3757 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ZERO);
3758 PGM_PAGE_SET_PAGEID(pPage, NIL_GMM_PAGEID);
3759 PGM_PAGE_SET_PDE_TYPE(pPage, PGM_PAGE_PDE_TYPE_DONTCARE);
3760 PGM_PAGE_SET_PTE_INDEX(pPage, 0);
3761 PGM_PAGE_SET_TRACKING(pPage, 0);
3762
3763 /* Flush physical page map TLB entry. */
3764 PGMPhysInvalidatePageMapTLBEntry(pVM, GCPhys);
3765
3766 /*
3767 * Make sure it's not in the handy page array.
3768 */
3769 for (uint32_t i = pVM->pgm.s.cHandyPages; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
3770 {
3771 if (pVM->pgm.s.aHandyPages[i].idPage == idPage)
3772 {
3773 pVM->pgm.s.aHandyPages[i].idPage = NIL_GMM_PAGEID;
3774 break;
3775 }
3776 if (pVM->pgm.s.aHandyPages[i].idSharedPage == idPage)
3777 {
3778 pVM->pgm.s.aHandyPages[i].idSharedPage = NIL_GMM_PAGEID;
3779 break;
3780 }
3781 }
3782
3783 /*
3784 * Push it onto the page array.
3785 */
3786 uint32_t iPage = *pcPendingPages;
3787 Assert(iPage < PGMPHYS_FREE_PAGE_BATCH_SIZE);
3788 *pcPendingPages += 1;
3789
3790 pReq->aPages[iPage].idPage = idPage;
3791
3792 if (iPage + 1 < PGMPHYS_FREE_PAGE_BATCH_SIZE)
3793 return VINF_SUCCESS;
3794
3795 /*
3796 * Flush the pages.
3797 */
3798 int rc = GMMR3FreePagesPerform(pVM, pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE);
3799 if (RT_SUCCESS(rc))
3800 {
3801 GMMR3FreePagesRePrep(pVM, pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
3802 *pcPendingPages = 0;
3803 }
3804 return rc;
3805}
3806
3807
3808/**
3809 * Converts a GC physical address to a HC ring-3 pointer, with some
3810 * additional checks.
3811 *
3812 * @returns VBox status code.
3813 * @retval VINF_SUCCESS on success.
3814 * @retval VINF_PGM_PHYS_TLB_CATCH_WRITE and *ppv set if the page has a write
3815 * access handler of some kind.
3816 * @retval VERR_PGM_PHYS_TLB_CATCH_ALL if the page has a handler catching all
3817 * accesses or is odd in any way.
3818 * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist.
3819 *
3820 * @param pVM The VM handle.
3821 * @param GCPhys The GC physical address to convert.
3822 * @param fWritable Whether write access is required.
3823 * @param ppv Where to store the pointer corresponding to GCPhys on
3824 * success.
3825 */
3826VMMR3DECL(int) PGMR3PhysTlbGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, void **ppv)
3827{
3828 pgmLock(pVM);
3829
3830 PPGMRAMRANGE pRam;
3831 PPGMPAGE pPage;
3832 int rc = pgmPhysGetPageAndRangeEx(&pVM->pgm.s, GCPhys, &pPage, &pRam);
3833 if (RT_SUCCESS(rc))
3834 {
3835 if (PGM_PAGE_IS_BALLOONED(pPage))
3836 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
3837 else if (!PGM_PAGE_HAS_ANY_HANDLERS(pPage))
3838 rc = VINF_SUCCESS;
3839 else
3840 {
3841 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)) /* catches MMIO */
3842 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3843 else if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
3844 {
3845 /** @todo Handle TLB loads of virtual handlers so ./test.sh can be made to work
3846 * in -norawr0 mode. */
3847 if (fWritable)
3848 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
3849 }
3850 else
3851 {
3852 /* Temporarily disabled physical handler(s), since the recompiler
3853 doesn't get notified when it's reset we'll have to pretend it's
3854 operating normally. */
3855 if (pgmHandlerPhysicalIsAll(pVM, GCPhys))
3856 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3857 else
3858 rc = VINF_PGM_PHYS_TLB_CATCH_WRITE;
3859 }
3860 }
3861 if (RT_SUCCESS(rc))
3862 {
3863 int rc2;
3864
3865 /* Make sure what we return is writable. */
3866 if (fWritable && rc != VINF_PGM_PHYS_TLB_CATCH_WRITE)
3867 switch (PGM_PAGE_GET_STATE(pPage))
3868 {
3869 case PGM_PAGE_STATE_ALLOCATED:
3870 break;
3871 case PGM_PAGE_STATE_BALLOONED:
3872 AssertFailed();
3873 break;
3874 case PGM_PAGE_STATE_ZERO:
3875 case PGM_PAGE_STATE_SHARED:
3876 case PGM_PAGE_STATE_WRITE_MONITORED:
3877 rc2 = pgmPhysPageMakeWritable(pVM, pPage, GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK);
3878 AssertLogRelRCReturn(rc2, rc2);
3879 break;
3880 }
3881
3882 /* Get a ring-3 mapping of the address. */
3883 PPGMPAGER3MAPTLBE pTlbe;
3884 rc2 = pgmPhysPageQueryTlbe(&pVM->pgm.s, GCPhys, &pTlbe);
3885 AssertLogRelRCReturn(rc2, rc2);
3886 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & PAGE_OFFSET_MASK));
3887 /** @todo mapping/locking hell; this isn't horribly efficient since
3888 * pgmPhysPageLoadIntoTlb will repeat the lookup we've done here. */
3889
3890 Log6(("PGMR3PhysTlbGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage] *ppv=%p\n", GCPhys, rc, pPage, *ppv));
3891 }
3892 else
3893 Log6(("PGMR3PhysTlbGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage]\n", GCPhys, rc, pPage));
3894
3895 /* else: handler catching all access, no pointer returned. */
3896 }
3897 else
3898 rc = VERR_PGM_PHYS_TLB_UNASSIGNED;
3899
3900 pgmUnlock(pVM);
3901 return rc;
3902}
3903
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