VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/PGMAllPhys.cpp@ 99748

Last change on this file since 99748 was 99739, checked in by vboxsync, 21 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 146.7 KB
Line 
1/* $Id: PGMAllPhys.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor, Physical Memory Addressing.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_PGM_PHYS
33#define VBOX_WITHOUT_PAGING_BIT_FIELDS /* 64-bit bitfields are just asking for trouble. See @bugref{9841} and others. */
34#include <VBox/vmm/pgm.h>
35#include <VBox/vmm/trpm.h>
36#include <VBox/vmm/vmm.h>
37#include <VBox/vmm/iem.h>
38#include <VBox/vmm/iom.h>
39#include <VBox/vmm/em.h>
40#include <VBox/vmm/nem.h>
41#include "PGMInternal.h"
42#include <VBox/vmm/vmcc.h>
43#include "PGMInline.h"
44#include <VBox/param.h>
45#include <VBox/err.h>
46#include <iprt/assert.h>
47#include <iprt/string.h>
48#include <VBox/log.h>
49#ifdef IN_RING3
50# include <iprt/thread.h>
51#endif
52
53
54/*********************************************************************************************************************************
55* Defined Constants And Macros *
56*********************************************************************************************************************************/
57/** Enable the physical TLB. */
58#define PGM_WITH_PHYS_TLB
59
60/** @def PGM_HANDLER_PHYS_IS_VALID_STATUS
61 * Checks if valid physical access handler return code (normal handler, not PF).
62 *
63 * Checks if the given strict status code is one of the expected ones for a
64 * physical access handler in the current context.
65 *
66 * @returns true or false.
67 * @param a_rcStrict The status code.
68 * @param a_fWrite Whether it is a write or read being serviced.
69 *
70 * @remarks We wish to keep the list of statuses here as short as possible.
71 * When changing, please make sure to update the PGMPhysRead,
72 * PGMPhysWrite, PGMPhysReadGCPtr and PGMPhysWriteGCPtr docs too.
73 */
74#ifdef IN_RING3
75# define PGM_HANDLER_PHYS_IS_VALID_STATUS(a_rcStrict, a_fWrite) \
76 ( (a_rcStrict) == VINF_SUCCESS \
77 || (a_rcStrict) == VINF_PGM_HANDLER_DO_DEFAULT)
78#elif defined(IN_RING0)
79#define PGM_HANDLER_PHYS_IS_VALID_STATUS(a_rcStrict, a_fWrite) \
80 ( (a_rcStrict) == VINF_SUCCESS \
81 || (a_rcStrict) == VINF_PGM_HANDLER_DO_DEFAULT \
82 \
83 || (a_rcStrict) == ((a_fWrite) ? VINF_IOM_R3_MMIO_WRITE : VINF_IOM_R3_MMIO_READ) \
84 || (a_rcStrict) == VINF_IOM_R3_MMIO_READ_WRITE \
85 || ((a_rcStrict) == VINF_IOM_R3_MMIO_COMMIT_WRITE && (a_fWrite)) \
86 \
87 || (a_rcStrict) == VINF_EM_RAW_EMULATE_INSTR \
88 || (a_rcStrict) == VINF_EM_DBG_STOP \
89 || (a_rcStrict) == VINF_EM_DBG_EVENT \
90 || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \
91 || (a_rcStrict) == VINF_EM_OFF \
92 || (a_rcStrict) == VINF_EM_SUSPEND \
93 || (a_rcStrict) == VINF_EM_RESET \
94 )
95#else
96# error "Context?"
97#endif
98
99/** @def PGM_HANDLER_VIRT_IS_VALID_STATUS
100 * Checks if valid virtual access handler return code (normal handler, not PF).
101 *
102 * Checks if the given strict status code is one of the expected ones for a
103 * virtual access handler in the current context.
104 *
105 * @returns true or false.
106 * @param a_rcStrict The status code.
107 * @param a_fWrite Whether it is a write or read being serviced.
108 *
109 * @remarks We wish to keep the list of statuses here as short as possible.
110 * When changing, please make sure to update the PGMPhysRead,
111 * PGMPhysWrite, PGMPhysReadGCPtr and PGMPhysWriteGCPtr docs too.
112 */
113#ifdef IN_RING3
114# define PGM_HANDLER_VIRT_IS_VALID_STATUS(a_rcStrict, a_fWrite) \
115 ( (a_rcStrict) == VINF_SUCCESS \
116 || (a_rcStrict) == VINF_PGM_HANDLER_DO_DEFAULT)
117#elif defined(IN_RING0)
118# define PGM_HANDLER_VIRT_IS_VALID_STATUS(a_rcStrict, a_fWrite) \
119 (false /* no virtual handlers in ring-0! */ )
120#else
121# error "Context?"
122#endif
123
124
125
126/**
127 * Calculate the actual table size.
128 *
129 * The memory is layed out like this:
130 * - PGMPHYSHANDLERTREE (8 bytes)
131 * - Allocation bitmap (8-byte size align)
132 * - Slab of PGMPHYSHANDLER. Start is 64 byte aligned.
133 */
134uint32_t pgmHandlerPhysicalCalcTableSizes(uint32_t *pcEntries, uint32_t *pcbTreeAndBitmap)
135{
136 /*
137 * A minimum of 64 entries and a maximum of ~64K.
138 */
139 uint32_t cEntries = *pcEntries;
140 if (cEntries <= 64)
141 cEntries = 64;
142 else if (cEntries >= _64K)
143 cEntries = _64K;
144 else
145 cEntries = RT_ALIGN_32(cEntries, 16);
146
147 /*
148 * Do the initial calculation.
149 */
150 uint32_t cbBitmap = RT_ALIGN_32(cEntries, 64) / 8;
151 uint32_t cbTreeAndBitmap = RT_ALIGN_32(sizeof(PGMPHYSHANDLERTREE) + cbBitmap, 64);
152 uint32_t cbTable = cEntries * sizeof(PGMPHYSHANDLER);
153 uint32_t cbTotal = cbTreeAndBitmap + cbTable;
154
155 /*
156 * Align the total and try use up extra space from that.
157 */
158 uint32_t cbTotalAligned = RT_ALIGN_32(cbTotal, RT_MAX(HOST_PAGE_SIZE, _16K));
159 uint32_t cAvail = cbTotalAligned - cbTotal;
160 cAvail /= sizeof(PGMPHYSHANDLER);
161 if (cAvail >= 1)
162 for (;;)
163 {
164 cbBitmap = RT_ALIGN_32(cEntries, 64) / 8;
165 cbTreeAndBitmap = RT_ALIGN_32(sizeof(PGMPHYSHANDLERTREE) + cbBitmap, 64);
166 cbTable = cEntries * sizeof(PGMPHYSHANDLER);
167 cbTotal = cbTreeAndBitmap + cbTable;
168 if (cbTotal <= cbTotalAligned)
169 break;
170 cEntries--;
171 Assert(cEntries >= 16);
172 }
173
174 /*
175 * Return the result.
176 */
177 *pcbTreeAndBitmap = cbTreeAndBitmap;
178 *pcEntries = cEntries;
179 return cbTotalAligned;
180}
181
182
183/**
184 * Looks up a ROM range by its PGMROMRANGE::GCPhys value.
185 */
186DECLINLINE(PPGMROMRANGE) pgmPhysRomLookupByBase(PVMCC pVM, RTGCPHYS GCPhys)
187{
188 for (PPGMROMRANGE pRom = pVM->pgm.s.CTX_SUFF(pRomRanges); pRom; pRom = pRom->CTX_SUFF(pNext))
189 if (pRom->GCPhys == GCPhys)
190 return pRom;
191 return NULL;
192}
193
194#ifndef IN_RING3
195
196/**
197 * @callback_method_impl{FNPGMRZPHYSPFHANDLER,
198 * \#PF access handler callback for guest ROM range write access.}
199 *
200 * @remarks The @a uUser argument is the PGMROMRANGE::GCPhys value.
201 */
202DECLCALLBACK(VBOXSTRICTRC) pgmPhysRomWritePfHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTX pCtx,
203 RTGCPTR pvFault, RTGCPHYS GCPhysFault, uint64_t uUser)
204
205{
206 PPGMROMRANGE const pRom = pgmPhysRomLookupByBase(pVM, uUser);
207 AssertReturn(pRom, VINF_EM_RAW_EMULATE_INSTR);
208 uint32_t const iPage = (GCPhysFault - pRom->GCPhys) >> GUEST_PAGE_SHIFT;
209 int rc;
210 RT_NOREF(uErrorCode, pvFault);
211
212 Assert(uErrorCode & X86_TRAP_PF_RW); /* This shall not be used for read access! */
213
214 Assert(iPage < (pRom->cb >> GUEST_PAGE_SHIFT));
215 switch (pRom->aPages[iPage].enmProt)
216 {
217 case PGMROMPROT_READ_ROM_WRITE_IGNORE:
218 case PGMROMPROT_READ_RAM_WRITE_IGNORE:
219 {
220 /*
221 * If it's a simple instruction which doesn't change the cpu state
222 * we will simply skip it. Otherwise we'll have to defer it to REM.
223 */
224 uint32_t cbOp;
225 PDISSTATE pDis = &pVCpu->pgm.s.Dis;
226 rc = EMInterpretDisasCurrent(pVCpu, pDis, &cbOp);
227 if ( RT_SUCCESS(rc)
228 && pDis->uCpuMode == DISCPUMODE_32BIT /** @todo why does this matter? */
229 && !(pDis->arch.x86.fPrefix & (DISPREFIX_REPNE | DISPREFIX_REP | DISPREFIX_SEG)))
230 {
231 switch (pDis->arch.x86.bOpCode)
232 {
233 /** @todo Find other instructions we can safely skip, possibly
234 * adding this kind of detection to DIS or EM. */
235 case OP_MOV:
236 pCtx->rip += cbOp;
237 STAM_COUNTER_INC(&pVCpu->pgm.s.Stats.StatRZGuestROMWriteHandled);
238 return VINF_SUCCESS;
239 }
240 }
241 break;
242 }
243
244 case PGMROMPROT_READ_RAM_WRITE_RAM:
245 pRom->aPages[iPage].LiveSave.fWrittenTo = true;
246 rc = PGMHandlerPhysicalPageTempOff(pVM, pRom->GCPhys, GCPhysFault & X86_PTE_PG_MASK);
247 AssertRC(rc);
248 break; /** @todo Must edit the shadow PT and restart the instruction, not use the interpreter! */
249
250 case PGMROMPROT_READ_ROM_WRITE_RAM:
251 /* Handle it in ring-3 because it's *way* easier there. */
252 pRom->aPages[iPage].LiveSave.fWrittenTo = true;
253 break;
254
255 default:
256 AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhysFault=%RGp\n",
257 pRom->aPages[iPage].enmProt, iPage, GCPhysFault),
258 VERR_IPE_NOT_REACHED_DEFAULT_CASE);
259 }
260
261 STAM_COUNTER_INC(&pVCpu->pgm.s.Stats.StatRZGuestROMWriteUnhandled);
262 return VINF_EM_RAW_EMULATE_INSTR;
263}
264
265#endif /* !IN_RING3 */
266
267
268/**
269 * @callback_method_impl{FNPGMPHYSHANDLER,
270 * Access handler callback for ROM write accesses.}
271 *
272 * @remarks The @a uUser argument is the PGMROMRANGE::GCPhys value.
273 */
274DECLCALLBACK(VBOXSTRICTRC)
275pgmPhysRomWriteHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
276 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, uint64_t uUser)
277{
278 PPGMROMRANGE const pRom = pgmPhysRomLookupByBase(pVM, uUser);
279 AssertReturn(pRom, VERR_INTERNAL_ERROR_3);
280 uint32_t const iPage = (GCPhys - pRom->GCPhys) >> GUEST_PAGE_SHIFT;
281 Assert(iPage < (pRom->cb >> GUEST_PAGE_SHIFT));
282 PPGMROMPAGE const pRomPage = &pRom->aPages[iPage];
283
284 Log5(("pgmPhysRomWriteHandler: %d %c %#08RGp %#04zx\n", pRomPage->enmProt, enmAccessType == PGMACCESSTYPE_READ ? 'R' : 'W', GCPhys, cbBuf));
285 RT_NOREF(pVCpu, pvPhys, enmOrigin);
286
287 if (enmAccessType == PGMACCESSTYPE_READ)
288 {
289 switch (pRomPage->enmProt)
290 {
291 /*
292 * Take the default action.
293 */
294 case PGMROMPROT_READ_ROM_WRITE_IGNORE:
295 case PGMROMPROT_READ_RAM_WRITE_IGNORE:
296 case PGMROMPROT_READ_ROM_WRITE_RAM:
297 case PGMROMPROT_READ_RAM_WRITE_RAM:
298 return VINF_PGM_HANDLER_DO_DEFAULT;
299
300 default:
301 AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhys=%RGp\n",
302 pRom->aPages[iPage].enmProt, iPage, GCPhys),
303 VERR_IPE_NOT_REACHED_DEFAULT_CASE);
304 }
305 }
306 else
307 {
308 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
309 switch (pRomPage->enmProt)
310 {
311 /*
312 * Ignore writes.
313 */
314 case PGMROMPROT_READ_ROM_WRITE_IGNORE:
315 case PGMROMPROT_READ_RAM_WRITE_IGNORE:
316 return VINF_SUCCESS;
317
318 /*
319 * Write to the RAM page.
320 */
321 case PGMROMPROT_READ_ROM_WRITE_RAM:
322 case PGMROMPROT_READ_RAM_WRITE_RAM: /* yes this will get here too, it's *way* simpler that way. */
323 {
324 /* This should be impossible now, pvPhys doesn't work cross page anylonger. */
325 Assert(((GCPhys - pRom->GCPhys + cbBuf - 1) >> GUEST_PAGE_SHIFT) == iPage);
326
327 /*
328 * Take the lock, do lazy allocation, map the page and copy the data.
329 *
330 * Note that we have to bypass the mapping TLB since it works on
331 * guest physical addresses and entering the shadow page would
332 * kind of screw things up...
333 */
334 PGM_LOCK_VOID(pVM);
335
336 PPGMPAGE pShadowPage = &pRomPage->Shadow;
337 if (!PGMROMPROT_IS_ROM(pRomPage->enmProt))
338 {
339 pShadowPage = pgmPhysGetPage(pVM, GCPhys);
340 AssertLogRelMsgReturnStmt(pShadowPage, ("%RGp\n", GCPhys), PGM_UNLOCK(pVM), VERR_PGM_PHYS_PAGE_GET_IPE);
341 }
342
343 void *pvDstPage;
344 int rc;
345#if defined(VBOX_WITH_PGM_NEM_MODE) && defined(IN_RING3)
346 if (PGM_IS_IN_NEM_MODE(pVM) && PGMROMPROT_IS_ROM(pRomPage->enmProt))
347 {
348 pvDstPage = &pRom->pbR3Alternate[GCPhys - pRom->GCPhys];
349 rc = VINF_SUCCESS;
350 }
351 else
352#endif
353 {
354 rc = pgmPhysPageMakeWritableAndMap(pVM, pShadowPage, GCPhys & X86_PTE_PG_MASK, &pvDstPage);
355 if (RT_SUCCESS(rc))
356 pvDstPage = (uint8_t *)pvDstPage + (GCPhys & GUEST_PAGE_OFFSET_MASK);
357 }
358 if (RT_SUCCESS(rc))
359 {
360 memcpy((uint8_t *)pvDstPage + (GCPhys & GUEST_PAGE_OFFSET_MASK), pvBuf, cbBuf);
361 pRomPage->LiveSave.fWrittenTo = true;
362
363 AssertMsg( rc == VINF_SUCCESS
364 || ( rc == VINF_PGM_SYNC_CR3
365 && VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
366 , ("%Rrc\n", rc));
367 rc = VINF_SUCCESS;
368 }
369
370 PGM_UNLOCK(pVM);
371 return rc;
372 }
373
374 default:
375 AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhys=%RGp\n",
376 pRom->aPages[iPage].enmProt, iPage, GCPhys),
377 VERR_IPE_NOT_REACHED_DEFAULT_CASE);
378 }
379 }
380}
381
382
383/**
384 * Common worker for pgmPhysMmio2WriteHandler and pgmPhysMmio2WritePfHandler.
385 */
386static VBOXSTRICTRC pgmPhysMmio2WriteHandlerCommon(PVMCC pVM, PVMCPUCC pVCpu, uint64_t hMmio2, RTGCPHYS GCPhys, RTGCPTR GCPtr)
387{
388 /*
389 * Get the MMIO2 range.
390 */
391 AssertReturn(hMmio2 < RT_ELEMENTS(pVM->pgm.s.apMmio2RangesR3), VERR_INTERNAL_ERROR_3);
392 AssertReturn(hMmio2 != 0, VERR_INTERNAL_ERROR_3);
393 PPGMREGMMIO2RANGE pMmio2 = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[hMmio2 - 1];
394 Assert(pMmio2->idMmio2 == hMmio2);
395 AssertReturn((pMmio2->fFlags & PGMREGMMIO2RANGE_F_TRACK_DIRTY_PAGES) == PGMREGMMIO2RANGE_F_TRACK_DIRTY_PAGES,
396 VERR_INTERNAL_ERROR_4);
397
398 /*
399 * Get the page and make sure it's an MMIO2 page.
400 */
401 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
402 AssertReturn(pPage, VINF_EM_RAW_EMULATE_INSTR);
403 AssertReturn(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2, VINF_EM_RAW_EMULATE_INSTR);
404
405 /*
406 * Set the dirty flag so we can avoid scanning all the pages when it isn't dirty.
407 * (The PGM_PAGE_HNDL_PHYS_STATE_DISABLED handler state indicates that a single
408 * page is dirty, saving the need for additional storage (bitmap).)
409 */
410 pMmio2->fFlags |= PGMREGMMIO2RANGE_F_IS_DIRTY;
411
412 /*
413 * Disable the handler for this page.
414 */
415 int rc = PGMHandlerPhysicalPageTempOff(pVM, pMmio2->RamRange.GCPhys, GCPhys & X86_PTE_PG_MASK);
416 AssertRC(rc);
417#ifndef IN_RING3
418 if (RT_SUCCESS(rc) && GCPtr != ~(RTGCPTR)0)
419 {
420 rc = PGMShwMakePageWritable(pVCpu, GCPtr, PGM_MK_PG_IS_MMIO2 | PGM_MK_PG_IS_WRITE_FAULT);
421 AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_PAGE_TABLE_NOT_PRESENT,
422 ("PGMShwModifyPage -> GCPtr=%RGv rc=%d\n", GCPtr, rc), rc);
423 }
424#else
425 RT_NOREF(pVCpu, GCPtr);
426#endif
427 return VINF_SUCCESS;
428}
429
430
431#ifndef IN_RING3
432/**
433 * @callback_method_impl{FNPGMRZPHYSPFHANDLER,
434 * \#PF access handler callback for guest MMIO2 dirty page tracing.}
435 *
436 * @remarks The @a uUser is the MMIO2 index.
437 */
438DECLCALLBACK(VBOXSTRICTRC) pgmPhysMmio2WritePfHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTX pCtx,
439 RTGCPTR pvFault, RTGCPHYS GCPhysFault, uint64_t uUser)
440{
441 RT_NOREF(pVCpu, uErrorCode, pCtx);
442 VBOXSTRICTRC rcStrict = PGM_LOCK(pVM); /* We should already have it, but just make sure we do. */
443 if (RT_SUCCESS(rcStrict))
444 {
445 rcStrict = pgmPhysMmio2WriteHandlerCommon(pVM, pVCpu, uUser, GCPhysFault, pvFault);
446 PGM_UNLOCK(pVM);
447 }
448 return rcStrict;
449}
450#endif /* !IN_RING3 */
451
452
453/**
454 * @callback_method_impl{FNPGMPHYSHANDLER,
455 * Access handler callback for MMIO2 dirty page tracing.}
456 *
457 * @remarks The @a uUser is the MMIO2 index.
458 */
459DECLCALLBACK(VBOXSTRICTRC)
460pgmPhysMmio2WriteHandler(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf,
461 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, uint64_t uUser)
462{
463 VBOXSTRICTRC rcStrict = PGM_LOCK(pVM); /* We should already have it, but just make sure we do. */
464 if (RT_SUCCESS(rcStrict))
465 {
466 rcStrict = pgmPhysMmio2WriteHandlerCommon(pVM, pVCpu, uUser, GCPhys, ~(RTGCPTR)0);
467 PGM_UNLOCK(pVM);
468 if (rcStrict == VINF_SUCCESS)
469 rcStrict = VINF_PGM_HANDLER_DO_DEFAULT;
470 }
471 RT_NOREF(pvPhys, pvBuf, cbBuf, enmAccessType, enmOrigin);
472 return rcStrict;
473}
474
475
476/**
477 * Invalidates the RAM range TLBs.
478 *
479 * @param pVM The cross context VM structure.
480 */
481void pgmPhysInvalidRamRangeTlbs(PVMCC pVM)
482{
483 PGM_LOCK_VOID(pVM);
484 RT_ZERO(pVM->pgm.s.apRamRangesTlbR3);
485 RT_ZERO(pVM->pgm.s.apRamRangesTlbR0);
486 PGM_UNLOCK(pVM);
487}
488
489
490/**
491 * Tests if a value of type RTGCPHYS is negative if the type had been signed
492 * instead of unsigned.
493 *
494 * @returns @c true if negative, @c false if positive or zero.
495 * @param a_GCPhys The value to test.
496 * @todo Move me to iprt/types.h.
497 */
498#define RTGCPHYS_IS_NEGATIVE(a_GCPhys) ((a_GCPhys) & ((RTGCPHYS)1 << (sizeof(RTGCPHYS)*8 - 1)))
499
500
501/**
502 * Slow worker for pgmPhysGetRange.
503 *
504 * @copydoc pgmPhysGetRange
505 */
506PPGMRAMRANGE pgmPhysGetRangeSlow(PVM pVM, RTGCPHYS GCPhys)
507{
508 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbMisses));
509
510 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangeTree);
511 while (pRam)
512 {
513 RTGCPHYS off = GCPhys - pRam->GCPhys;
514 if (off < pRam->cb)
515 {
516 pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)] = pRam;
517 return pRam;
518 }
519 if (RTGCPHYS_IS_NEGATIVE(off))
520 pRam = pRam->CTX_SUFF(pLeft);
521 else
522 pRam = pRam->CTX_SUFF(pRight);
523 }
524 return NULL;
525}
526
527
528/**
529 * Slow worker for pgmPhysGetRangeAtOrAbove.
530 *
531 * @copydoc pgmPhysGetRangeAtOrAbove
532 */
533PPGMRAMRANGE pgmPhysGetRangeAtOrAboveSlow(PVM pVM, RTGCPHYS GCPhys)
534{
535 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbMisses));
536
537 PPGMRAMRANGE pLastLeft = NULL;
538 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangeTree);
539 while (pRam)
540 {
541 RTGCPHYS off = GCPhys - pRam->GCPhys;
542 if (off < pRam->cb)
543 {
544 pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)] = pRam;
545 return pRam;
546 }
547 if (RTGCPHYS_IS_NEGATIVE(off))
548 {
549 pLastLeft = pRam;
550 pRam = pRam->CTX_SUFF(pLeft);
551 }
552 else
553 pRam = pRam->CTX_SUFF(pRight);
554 }
555 return pLastLeft;
556}
557
558
559/**
560 * Slow worker for pgmPhysGetPage.
561 *
562 * @copydoc pgmPhysGetPage
563 */
564PPGMPAGE pgmPhysGetPageSlow(PVM pVM, RTGCPHYS GCPhys)
565{
566 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbMisses));
567
568 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangeTree);
569 while (pRam)
570 {
571 RTGCPHYS off = GCPhys - pRam->GCPhys;
572 if (off < pRam->cb)
573 {
574 pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)] = pRam;
575 return &pRam->aPages[off >> GUEST_PAGE_SHIFT];
576 }
577
578 if (RTGCPHYS_IS_NEGATIVE(off))
579 pRam = pRam->CTX_SUFF(pLeft);
580 else
581 pRam = pRam->CTX_SUFF(pRight);
582 }
583 return NULL;
584}
585
586
587/**
588 * Slow worker for pgmPhysGetPageEx.
589 *
590 * @copydoc pgmPhysGetPageEx
591 */
592int pgmPhysGetPageExSlow(PVM pVM, RTGCPHYS GCPhys, PPPGMPAGE ppPage)
593{
594 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbMisses));
595
596 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangeTree);
597 while (pRam)
598 {
599 RTGCPHYS off = GCPhys - pRam->GCPhys;
600 if (off < pRam->cb)
601 {
602 pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)] = pRam;
603 *ppPage = &pRam->aPages[off >> GUEST_PAGE_SHIFT];
604 return VINF_SUCCESS;
605 }
606
607 if (RTGCPHYS_IS_NEGATIVE(off))
608 pRam = pRam->CTX_SUFF(pLeft);
609 else
610 pRam = pRam->CTX_SUFF(pRight);
611 }
612
613 *ppPage = NULL;
614 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
615}
616
617
618/**
619 * Slow worker for pgmPhysGetPageAndRangeEx.
620 *
621 * @copydoc pgmPhysGetPageAndRangeEx
622 */
623int pgmPhysGetPageAndRangeExSlow(PVM pVM, RTGCPHYS GCPhys, PPPGMPAGE ppPage, PPGMRAMRANGE *ppRam)
624{
625 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,RamRangeTlbMisses));
626
627 PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangeTree);
628 while (pRam)
629 {
630 RTGCPHYS off = GCPhys - pRam->GCPhys;
631 if (off < pRam->cb)
632 {
633 pVM->pgm.s.CTX_SUFF(apRamRangesTlb)[PGM_RAMRANGE_TLB_IDX(GCPhys)] = pRam;
634 *ppRam = pRam;
635 *ppPage = &pRam->aPages[off >> GUEST_PAGE_SHIFT];
636 return VINF_SUCCESS;
637 }
638
639 if (RTGCPHYS_IS_NEGATIVE(off))
640 pRam = pRam->CTX_SUFF(pLeft);
641 else
642 pRam = pRam->CTX_SUFF(pRight);
643 }
644
645 *ppRam = NULL;
646 *ppPage = NULL;
647 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
648}
649
650
651/**
652 * Checks if Address Gate 20 is enabled or not.
653 *
654 * @returns true if enabled.
655 * @returns false if disabled.
656 * @param pVCpu The cross context virtual CPU structure.
657 */
658VMMDECL(bool) PGMPhysIsA20Enabled(PVMCPU pVCpu)
659{
660 LogFlow(("PGMPhysIsA20Enabled %d\n", pVCpu->pgm.s.fA20Enabled));
661 return pVCpu->pgm.s.fA20Enabled;
662}
663
664
665/**
666 * Validates a GC physical address.
667 *
668 * @returns true if valid.
669 * @returns false if invalid.
670 * @param pVM The cross context VM structure.
671 * @param GCPhys The physical address to validate.
672 */
673VMMDECL(bool) PGMPhysIsGCPhysValid(PVMCC pVM, RTGCPHYS GCPhys)
674{
675 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
676 return pPage != NULL;
677}
678
679
680/**
681 * Checks if a GC physical address is a normal page,
682 * i.e. not ROM, MMIO or reserved.
683 *
684 * @returns true if normal.
685 * @returns false if invalid, ROM, MMIO or reserved page.
686 * @param pVM The cross context VM structure.
687 * @param GCPhys The physical address to check.
688 */
689VMMDECL(bool) PGMPhysIsGCPhysNormal(PVMCC pVM, RTGCPHYS GCPhys)
690{
691 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
692 return pPage
693 && PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM;
694}
695
696
697/**
698 * Converts a GC physical address to a HC physical address.
699 *
700 * @returns VINF_SUCCESS on success.
701 * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical
702 * page but has no physical backing.
703 * @returns VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid
704 * GC physical address.
705 *
706 * @param pVM The cross context VM structure.
707 * @param GCPhys The GC physical address to convert.
708 * @param pHCPhys Where to store the HC physical address on success.
709 */
710VMM_INT_DECL(int) PGMPhysGCPhys2HCPhys(PVMCC pVM, RTGCPHYS GCPhys, PRTHCPHYS pHCPhys)
711{
712 PGM_LOCK_VOID(pVM);
713 PPGMPAGE pPage;
714 int rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage);
715 if (RT_SUCCESS(rc))
716 *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage) | (GCPhys & GUEST_PAGE_OFFSET_MASK);
717 PGM_UNLOCK(pVM);
718 return rc;
719}
720
721
722/**
723 * Invalidates all page mapping TLBs.
724 *
725 * @param pVM The cross context VM structure.
726 */
727void pgmPhysInvalidatePageMapTLB(PVMCC pVM)
728{
729 PGM_LOCK_VOID(pVM);
730 STAM_COUNTER_INC(&pVM->pgm.s.Stats.StatPageMapTlbFlushes);
731
732 /* Clear the R3 & R0 TLBs completely. */
733 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.PhysTlbR0.aEntries); i++)
734 {
735 pVM->pgm.s.PhysTlbR0.aEntries[i].GCPhys = NIL_RTGCPHYS;
736 pVM->pgm.s.PhysTlbR0.aEntries[i].pPage = 0;
737 pVM->pgm.s.PhysTlbR0.aEntries[i].pv = 0;
738 }
739
740 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.PhysTlbR3.aEntries); i++)
741 {
742 pVM->pgm.s.PhysTlbR3.aEntries[i].GCPhys = NIL_RTGCPHYS;
743 pVM->pgm.s.PhysTlbR3.aEntries[i].pPage = 0;
744 pVM->pgm.s.PhysTlbR3.aEntries[i].pMap = 0;
745 pVM->pgm.s.PhysTlbR3.aEntries[i].pv = 0;
746 }
747
748 IEMTlbInvalidateAllPhysicalAllCpus(pVM, NIL_VMCPUID);
749 PGM_UNLOCK(pVM);
750}
751
752
753/**
754 * Invalidates a page mapping TLB entry
755 *
756 * @param pVM The cross context VM structure.
757 * @param GCPhys GCPhys entry to flush
758 *
759 * @note Caller is responsible for calling IEMTlbInvalidateAllPhysicalAllCpus
760 * when needed.
761 */
762void pgmPhysInvalidatePageMapTLBEntry(PVMCC pVM, RTGCPHYS GCPhys)
763{
764 PGM_LOCK_ASSERT_OWNER(pVM);
765
766 STAM_COUNTER_INC(&pVM->pgm.s.Stats.StatPageMapTlbFlushEntry);
767
768 unsigned const idx = PGM_PAGER3MAPTLB_IDX(GCPhys);
769
770 pVM->pgm.s.PhysTlbR0.aEntries[idx].GCPhys = NIL_RTGCPHYS;
771 pVM->pgm.s.PhysTlbR0.aEntries[idx].pPage = 0;
772 pVM->pgm.s.PhysTlbR0.aEntries[idx].pv = 0;
773
774 pVM->pgm.s.PhysTlbR3.aEntries[idx].GCPhys = NIL_RTGCPHYS;
775 pVM->pgm.s.PhysTlbR3.aEntries[idx].pPage = 0;
776 pVM->pgm.s.PhysTlbR3.aEntries[idx].pMap = 0;
777 pVM->pgm.s.PhysTlbR3.aEntries[idx].pv = 0;
778}
779
780
781/**
782 * Makes sure that there is at least one handy page ready for use.
783 *
784 * This will also take the appropriate actions when reaching water-marks.
785 *
786 * @returns VBox status code.
787 * @retval VINF_SUCCESS on success.
788 * @retval VERR_EM_NO_MEMORY if we're really out of memory.
789 *
790 * @param pVM The cross context VM structure.
791 *
792 * @remarks Must be called from within the PGM critical section. It may
793 * nip back to ring-3/0 in some cases.
794 */
795static int pgmPhysEnsureHandyPage(PVMCC pVM)
796{
797 AssertMsg(pVM->pgm.s.cHandyPages <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), ("%d\n", pVM->pgm.s.cHandyPages));
798
799 /*
800 * Do we need to do anything special?
801 */
802#ifdef IN_RING3
803 if (pVM->pgm.s.cHandyPages <= RT_MAX(PGM_HANDY_PAGES_SET_FF, PGM_HANDY_PAGES_R3_ALLOC))
804#else
805 if (pVM->pgm.s.cHandyPages <= RT_MAX(PGM_HANDY_PAGES_SET_FF, PGM_HANDY_PAGES_RZ_TO_R3))
806#endif
807 {
808 /*
809 * Allocate pages only if we're out of them, or in ring-3, almost out.
810 */
811#ifdef IN_RING3
812 if (pVM->pgm.s.cHandyPages <= PGM_HANDY_PAGES_R3_ALLOC)
813#else
814 if (pVM->pgm.s.cHandyPages <= PGM_HANDY_PAGES_RZ_ALLOC)
815#endif
816 {
817 Log(("PGM: cHandyPages=%u out of %u -> allocate more; VM_FF_PGM_NO_MEMORY=%RTbool\n",
818 pVM->pgm.s.cHandyPages, RT_ELEMENTS(pVM->pgm.s.aHandyPages), VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY) ));
819#ifdef IN_RING3
820 int rc = PGMR3PhysAllocateHandyPages(pVM);
821#else
822 int rc = pgmR0PhysAllocateHandyPages(pVM, VMMGetCpuId(pVM), false /*fRing3*/);
823#endif
824 if (RT_UNLIKELY(rc != VINF_SUCCESS))
825 {
826 if (RT_FAILURE(rc))
827 return rc;
828 AssertMsgReturn(rc == VINF_EM_NO_MEMORY, ("%Rrc\n", rc), VERR_IPE_UNEXPECTED_INFO_STATUS);
829 if (!pVM->pgm.s.cHandyPages)
830 {
831 LogRel(("PGM: no more handy pages!\n"));
832 return VERR_EM_NO_MEMORY;
833 }
834 Assert(VM_FF_IS_SET(pVM, VM_FF_PGM_NEED_HANDY_PAGES));
835 Assert(VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY));
836#ifndef IN_RING3
837 VMCPU_FF_SET(VMMGetCpu(pVM), VMCPU_FF_TO_R3); /* paranoia */
838#endif
839 }
840 AssertMsgReturn( pVM->pgm.s.cHandyPages > 0
841 && pVM->pgm.s.cHandyPages <= RT_ELEMENTS(pVM->pgm.s.aHandyPages),
842 ("%u\n", pVM->pgm.s.cHandyPages),
843 VERR_PGM_HANDY_PAGE_IPE);
844 }
845 else
846 {
847 if (pVM->pgm.s.cHandyPages <= PGM_HANDY_PAGES_SET_FF)
848 VM_FF_SET(pVM, VM_FF_PGM_NEED_HANDY_PAGES);
849#ifndef IN_RING3
850 if (pVM->pgm.s.cHandyPages <= PGM_HANDY_PAGES_RZ_TO_R3)
851 {
852 Log(("PGM: VM_FF_TO_R3 - cHandyPages=%u out of %u\n", pVM->pgm.s.cHandyPages, RT_ELEMENTS(pVM->pgm.s.aHandyPages)));
853 VMCPU_FF_SET(VMMGetCpu(pVM), VMCPU_FF_TO_R3);
854 }
855#endif
856 }
857 }
858
859 return VINF_SUCCESS;
860}
861
862
863/**
864 * Replace a zero or shared page with new page that we can write to.
865 *
866 * @returns The following VBox status codes.
867 * @retval VINF_SUCCESS on success, pPage is modified.
868 * @retval VINF_PGM_SYNC_CR3 on success and a page pool flush is pending.
869 * @retval VERR_EM_NO_MEMORY if we're totally out of memory.
870 *
871 * @todo Propagate VERR_EM_NO_MEMORY up the call tree.
872 *
873 * @param pVM The cross context VM structure.
874 * @param pPage The physical page tracking structure. This will
875 * be modified on success.
876 * @param GCPhys The address of the page.
877 *
878 * @remarks Must be called from within the PGM critical section. It may
879 * nip back to ring-3/0 in some cases.
880 *
881 * @remarks This function shouldn't really fail, however if it does
882 * it probably means we've screwed up the size of handy pages and/or
883 * the low-water mark. Or, that some device I/O is causing a lot of
884 * pages to be allocated while while the host is in a low-memory
885 * condition. This latter should be handled elsewhere and in a more
886 * controlled manner, it's on the @bugref{3170} todo list...
887 */
888int pgmPhysAllocPage(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
889{
890 LogFlow(("pgmPhysAllocPage: %R[pgmpage] %RGp\n", pPage, GCPhys));
891
892 /*
893 * Prereqs.
894 */
895 PGM_LOCK_ASSERT_OWNER(pVM);
896 AssertMsg(PGM_PAGE_IS_ZERO(pPage) || PGM_PAGE_IS_SHARED(pPage), ("%R[pgmpage] %RGp\n", pPage, GCPhys));
897 Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage));
898
899# ifdef PGM_WITH_LARGE_PAGES
900 /*
901 * Try allocate a large page if applicable.
902 */
903 if ( PGMIsUsingLargePages(pVM)
904 && PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
905 && !VM_IS_NEM_ENABLED(pVM)) /** @todo NEM: Implement large pages support. */
906 {
907 RTGCPHYS GCPhysBase = GCPhys & X86_PDE2M_PAE_PG_MASK;
908 PPGMPAGE pBasePage;
909
910 int rc = pgmPhysGetPageEx(pVM, GCPhysBase, &pBasePage);
911 AssertRCReturn(rc, rc); /* paranoia; can't happen. */
912 if (PGM_PAGE_GET_PDE_TYPE(pBasePage) == PGM_PAGE_PDE_TYPE_DONTCARE)
913 {
914 rc = pgmPhysAllocLargePage(pVM, GCPhys);
915 if (rc == VINF_SUCCESS)
916 return rc;
917 }
918 /* Mark the base as type page table, so we don't check over and over again. */
919 PGM_PAGE_SET_PDE_TYPE(pVM, pBasePage, PGM_PAGE_PDE_TYPE_PT);
920
921 /* fall back to 4KB pages. */
922 }
923# endif
924
925 /*
926 * Flush any shadow page table mappings of the page.
927 * When VBOX_WITH_NEW_LAZY_PAGE_ALLOC isn't defined, there shouldn't be any.
928 */
929 bool fFlushTLBs = false;
930 int rc = pgmPoolTrackUpdateGCPhys(pVM, GCPhys, pPage, true /*fFlushTLBs*/, &fFlushTLBs);
931 AssertMsgReturn(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3, ("%Rrc\n", rc), RT_FAILURE(rc) ? rc : VERR_IPE_UNEXPECTED_STATUS);
932
933 /*
934 * Ensure that we've got a page handy, take it and use it.
935 */
936 int rc2 = pgmPhysEnsureHandyPage(pVM);
937 if (RT_FAILURE(rc2))
938 {
939 if (fFlushTLBs)
940 PGM_INVL_ALL_VCPU_TLBS(pVM);
941 Assert(rc2 == VERR_EM_NO_MEMORY);
942 return rc2;
943 }
944 /* re-assert preconditions since pgmPhysEnsureHandyPage may do a context switch. */
945 PGM_LOCK_ASSERT_OWNER(pVM);
946 AssertMsg(PGM_PAGE_IS_ZERO(pPage) || PGM_PAGE_IS_SHARED(pPage), ("%R[pgmpage] %RGp\n", pPage, GCPhys));
947 Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage));
948
949 uint32_t iHandyPage = --pVM->pgm.s.cHandyPages;
950 AssertMsg(iHandyPage < RT_ELEMENTS(pVM->pgm.s.aHandyPages), ("%d\n", iHandyPage));
951 Assert(pVM->pgm.s.aHandyPages[iHandyPage].HCPhysGCPhys != NIL_GMMPAGEDESC_PHYS);
952 Assert(!(pVM->pgm.s.aHandyPages[iHandyPage].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
953 Assert(pVM->pgm.s.aHandyPages[iHandyPage].idPage != NIL_GMM_PAGEID);
954 Assert(pVM->pgm.s.aHandyPages[iHandyPage].idSharedPage == NIL_GMM_PAGEID);
955
956 /*
957 * There are one or two action to be taken the next time we allocate handy pages:
958 * - Tell the GMM (global memory manager) what the page is being used for.
959 * (Speeds up replacement operations - sharing and defragmenting.)
960 * - If the current backing is shared, it must be freed.
961 */
962 const RTHCPHYS HCPhys = pVM->pgm.s.aHandyPages[iHandyPage].HCPhysGCPhys;
963 pVM->pgm.s.aHandyPages[iHandyPage].HCPhysGCPhys = GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
964
965 void const *pvSharedPage = NULL;
966 if (PGM_PAGE_IS_SHARED(pPage))
967 {
968 /* Mark this shared page for freeing/dereferencing. */
969 pVM->pgm.s.aHandyPages[iHandyPage].idSharedPage = PGM_PAGE_GET_PAGEID(pPage);
970 Assert(PGM_PAGE_GET_PAGEID(pPage) != NIL_GMM_PAGEID);
971
972 Log(("PGM: Replaced shared page %#x at %RGp with %#x / %RHp\n", PGM_PAGE_GET_PAGEID(pPage),
973 GCPhys, pVM->pgm.s.aHandyPages[iHandyPage].idPage, HCPhys));
974 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PageReplaceShared));
975 pVM->pgm.s.cSharedPages--;
976
977 /* Grab the address of the page so we can make a copy later on. (safe) */
978 rc = pgmPhysPageMapReadOnly(pVM, pPage, GCPhys, &pvSharedPage);
979 AssertRC(rc);
980 }
981 else
982 {
983 Log2(("PGM: Replaced zero page %RGp with %#x / %RHp\n", GCPhys, pVM->pgm.s.aHandyPages[iHandyPage].idPage, HCPhys));
984 STAM_COUNTER_INC(&pVM->pgm.s.Stats.StatRZPageReplaceZero);
985 pVM->pgm.s.cZeroPages--;
986 }
987
988 /*
989 * Do the PGMPAGE modifications.
990 */
991 pVM->pgm.s.cPrivatePages++;
992 PGM_PAGE_SET_HCPHYS(pVM, pPage, HCPhys);
993 PGM_PAGE_SET_PAGEID(pVM, pPage, pVM->pgm.s.aHandyPages[iHandyPage].idPage);
994 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ALLOCATED);
995 PGM_PAGE_SET_PDE_TYPE(pVM, pPage, PGM_PAGE_PDE_TYPE_PT);
996 pgmPhysInvalidatePageMapTLBEntry(pVM, GCPhys);
997 IEMTlbInvalidateAllPhysicalAllCpus(pVM, NIL_VMCPUID);
998
999 /* Copy the shared page contents to the replacement page. */
1000 if (pvSharedPage)
1001 {
1002 /* Get the virtual address of the new page. */
1003 PGMPAGEMAPLOCK PgMpLck;
1004 void *pvNewPage;
1005 rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &pvNewPage, &PgMpLck); AssertRC(rc);
1006 if (RT_SUCCESS(rc))
1007 {
1008 memcpy(pvNewPage, pvSharedPage, GUEST_PAGE_SIZE); /** @todo todo write ASMMemCopyPage */
1009 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
1010 }
1011 }
1012
1013 if ( fFlushTLBs
1014 && rc != VINF_PGM_GCPHYS_ALIASED)
1015 PGM_INVL_ALL_VCPU_TLBS(pVM);
1016
1017 /*
1018 * Notify NEM about the mapping change for this page.
1019 *
1020 * Note! Shadow ROM pages are complicated as they can definitely be
1021 * allocated while not visible, so play safe.
1022 */
1023 if (VM_IS_NEM_ENABLED(pVM))
1024 {
1025 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
1026 if ( enmType != PGMPAGETYPE_ROM_SHADOW
1027 || pgmPhysGetPage(pVM, GCPhys) == pPage)
1028 {
1029 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
1030 rc2 = NEMHCNotifyPhysPageAllocated(pVM, GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK, HCPhys,
1031 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
1032 if (RT_SUCCESS(rc))
1033 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
1034 else
1035 rc = rc2;
1036 }
1037 }
1038
1039 return rc;
1040}
1041
1042#ifdef PGM_WITH_LARGE_PAGES
1043
1044/**
1045 * Replace a 2 MB range of zero pages with new pages that we can write to.
1046 *
1047 * @returns The following VBox status codes.
1048 * @retval VINF_SUCCESS on success, pPage is modified.
1049 * @retval VINF_PGM_SYNC_CR3 on success and a page pool flush is pending.
1050 * @retval VERR_EM_NO_MEMORY if we're totally out of memory.
1051 *
1052 * @todo Propagate VERR_EM_NO_MEMORY up the call tree.
1053 *
1054 * @param pVM The cross context VM structure.
1055 * @param GCPhys The address of the page.
1056 *
1057 * @remarks Must be called from within the PGM critical section. It may block
1058 * on GMM and host mutexes/locks, leaving HM context.
1059 */
1060int pgmPhysAllocLargePage(PVMCC pVM, RTGCPHYS GCPhys)
1061{
1062 RTGCPHYS GCPhysBase = GCPhys & X86_PDE2M_PAE_PG_MASK;
1063 LogFlow(("pgmPhysAllocLargePage: %RGp base %RGp\n", GCPhys, GCPhysBase));
1064 Assert(!VM_IS_NEM_ENABLED(pVM)); /** @todo NEM: Large page support. */
1065
1066 /*
1067 * Check Prereqs.
1068 */
1069 PGM_LOCK_ASSERT_OWNER(pVM);
1070 Assert(PGMIsUsingLargePages(pVM));
1071
1072 /*
1073 * All the pages must be unallocated RAM pages, i.e. mapping the ZERO page.
1074 */
1075 PPGMPAGE pFirstPage;
1076 int rc = pgmPhysGetPageEx(pVM, GCPhysBase, &pFirstPage);
1077 if ( RT_SUCCESS(rc)
1078 && PGM_PAGE_GET_TYPE(pFirstPage) == PGMPAGETYPE_RAM
1079 && PGM_PAGE_GET_STATE(pFirstPage) == PGM_PAGE_STATE_ZERO)
1080 {
1081 /*
1082 * Further they should have PDE type set to PGM_PAGE_PDE_TYPE_DONTCARE,
1083 * since they are unallocated.
1084 */
1085 unsigned uPDEType = PGM_PAGE_GET_PDE_TYPE(pFirstPage);
1086 Assert(uPDEType != PGM_PAGE_PDE_TYPE_PDE);
1087 if (uPDEType == PGM_PAGE_PDE_TYPE_DONTCARE)
1088 {
1089 /*
1090 * Now, make sure all the other pages in the 2 MB is in the same state.
1091 */
1092 GCPhys = GCPhysBase;
1093 unsigned cLeft = _2M / GUEST_PAGE_SIZE;
1094 while (cLeft-- > 0)
1095 {
1096 PPGMPAGE pSubPage = pgmPhysGetPage(pVM, GCPhys);
1097 if ( pSubPage
1098 && PGM_PAGE_GET_TYPE(pSubPage) == PGMPAGETYPE_RAM /* Anything other than ram implies monitoring. */
1099 && PGM_PAGE_GET_STATE(pSubPage) == PGM_PAGE_STATE_ZERO) /* Allocated, monitored or shared means we can't use a large page here */
1100 {
1101 Assert(PGM_PAGE_GET_PDE_TYPE(pSubPage) == PGM_PAGE_PDE_TYPE_DONTCARE);
1102 GCPhys += GUEST_PAGE_SIZE;
1103 }
1104 else
1105 {
1106 LogFlow(("pgmPhysAllocLargePage: Found page %RGp with wrong attributes (type=%d; state=%d); cancel check.\n",
1107 GCPhys, pSubPage ? PGM_PAGE_GET_TYPE(pSubPage) : -1, pSubPage ? PGM_PAGE_GET_STATE(pSubPage) : -1));
1108
1109 /* Failed. Mark as requiring a PT so we don't check the whole thing again in the future. */
1110 STAM_REL_COUNTER_INC(&pVM->pgm.s.StatLargePageRefused);
1111 PGM_PAGE_SET_PDE_TYPE(pVM, pFirstPage, PGM_PAGE_PDE_TYPE_PT);
1112 return VERR_PGM_INVALID_LARGE_PAGE_RANGE;
1113 }
1114 }
1115
1116 /*
1117 * Do the allocation.
1118 */
1119# ifdef IN_RING3
1120 rc = VMMR3CallR0(pVM, VMMR0_DO_PGM_ALLOCATE_LARGE_PAGE, GCPhysBase, NULL);
1121# elif defined(IN_RING0)
1122 rc = pgmR0PhysAllocateLargePage(pVM, VMMGetCpuId(pVM), GCPhysBase);
1123# else
1124# error "Port me"
1125# endif
1126 if (RT_SUCCESS(rc))
1127 {
1128 Assert(PGM_PAGE_GET_STATE(pFirstPage) == PGM_PAGE_STATE_ALLOCATED);
1129 pVM->pgm.s.cLargePages++;
1130 return VINF_SUCCESS;
1131 }
1132
1133 /* If we fail once, it most likely means the host's memory is too
1134 fragmented; don't bother trying again. */
1135 LogFlow(("pgmPhysAllocLargePage failed with %Rrc\n", rc));
1136 return rc;
1137 }
1138 }
1139 return VERR_PGM_INVALID_LARGE_PAGE_RANGE;
1140}
1141
1142
1143/**
1144 * Recheck the entire 2 MB range to see if we can use it again as a large page.
1145 *
1146 * @returns The following VBox status codes.
1147 * @retval VINF_SUCCESS on success, the large page can be used again
1148 * @retval VERR_PGM_INVALID_LARGE_PAGE_RANGE if it can't be reused
1149 *
1150 * @param pVM The cross context VM structure.
1151 * @param GCPhys The address of the page.
1152 * @param pLargePage Page structure of the base page
1153 */
1154int pgmPhysRecheckLargePage(PVMCC pVM, RTGCPHYS GCPhys, PPGMPAGE pLargePage)
1155{
1156 STAM_REL_COUNTER_INC(&pVM->pgm.s.StatLargePageRecheck);
1157
1158 Assert(!VM_IS_NEM_ENABLED(pVM)); /** @todo NEM: Large page support. */
1159
1160 AssertCompile(X86_PDE2M_PAE_PG_MASK == EPT_PDE2M_PG_MASK); /* Paranoia: Caller uses this for guest EPT tables as well. */
1161 GCPhys &= X86_PDE2M_PAE_PG_MASK;
1162
1163 /* Check the base page. */
1164 Assert(PGM_PAGE_GET_PDE_TYPE(pLargePage) == PGM_PAGE_PDE_TYPE_PDE_DISABLED);
1165 if ( PGM_PAGE_GET_STATE(pLargePage) != PGM_PAGE_STATE_ALLOCATED
1166 || PGM_PAGE_GET_TYPE(pLargePage) != PGMPAGETYPE_RAM
1167 || PGM_PAGE_GET_HNDL_PHYS_STATE(pLargePage) != PGM_PAGE_HNDL_PHYS_STATE_NONE)
1168 {
1169 LogFlow(("pgmPhysRecheckLargePage: checks failed for base page %x %x %x\n", PGM_PAGE_GET_STATE(pLargePage), PGM_PAGE_GET_TYPE(pLargePage), PGM_PAGE_GET_HNDL_PHYS_STATE(pLargePage)));
1170 return VERR_PGM_INVALID_LARGE_PAGE_RANGE;
1171 }
1172
1173 STAM_PROFILE_START(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,IsValidLargePage), a);
1174 /* Check all remaining pages in the 2 MB range. */
1175 unsigned i;
1176 GCPhys += GUEST_PAGE_SIZE;
1177 for (i = 1; i < _2M / GUEST_PAGE_SIZE; i++)
1178 {
1179 PPGMPAGE pPage;
1180 int rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage);
1181 AssertRCBreak(rc);
1182
1183 if ( PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
1184 || PGM_PAGE_GET_PDE_TYPE(pPage) != PGM_PAGE_PDE_TYPE_PDE
1185 || PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_RAM
1186 || PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_NONE)
1187 {
1188 LogFlow(("pgmPhysRecheckLargePage: checks failed for page %d; %x %x %x\n", i, PGM_PAGE_GET_STATE(pPage), PGM_PAGE_GET_TYPE(pPage), PGM_PAGE_GET_HNDL_PHYS_STATE(pPage)));
1189 break;
1190 }
1191
1192 GCPhys += GUEST_PAGE_SIZE;
1193 }
1194 STAM_PROFILE_STOP(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,IsValidLargePage), a);
1195
1196 if (i == _2M / GUEST_PAGE_SIZE)
1197 {
1198 PGM_PAGE_SET_PDE_TYPE(pVM, pLargePage, PGM_PAGE_PDE_TYPE_PDE);
1199 pVM->pgm.s.cLargePagesDisabled--;
1200 Log(("pgmPhysRecheckLargePage: page %RGp can be reused!\n", GCPhys - _2M));
1201 return VINF_SUCCESS;
1202 }
1203
1204 return VERR_PGM_INVALID_LARGE_PAGE_RANGE;
1205}
1206
1207#endif /* PGM_WITH_LARGE_PAGES */
1208
1209
1210/**
1211 * Deal with a write monitored page.
1212 *
1213 * @param pVM The cross context VM structure.
1214 * @param pPage The physical page tracking structure.
1215 * @param GCPhys The guest physical address of the page.
1216 * PGMPhysReleasePageMappingLock() passes NIL_RTGCPHYS in a
1217 * very unlikely situation where it is okay that we let NEM
1218 * fix the page access in a lazy fasion.
1219 *
1220 * @remarks Called from within the PGM critical section.
1221 */
1222void pgmPhysPageMakeWriteMonitoredWritable(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
1223{
1224 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED);
1225 PGM_PAGE_SET_WRITTEN_TO(pVM, pPage);
1226 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ALLOCATED);
1227 Assert(pVM->pgm.s.cMonitoredPages > 0);
1228 pVM->pgm.s.cMonitoredPages--;
1229 pVM->pgm.s.cWrittenToPages++;
1230
1231#ifdef VBOX_WITH_NATIVE_NEM
1232 /*
1233 * Notify NEM about the protection change so we won't spin forever.
1234 *
1235 * Note! NEM need to be handle to lazily correct page protection as we cannot
1236 * really get it 100% right here it seems. The page pool does this too.
1237 */
1238 if (VM_IS_NEM_ENABLED(pVM) && GCPhys != NIL_RTGCPHYS)
1239 {
1240 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
1241 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
1242 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
1243 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
1244 pRam ? PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhys) : NULL,
1245 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
1246 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
1247 }
1248#else
1249 RT_NOREF(GCPhys);
1250#endif
1251}
1252
1253
1254/**
1255 * Deal with pages that are not writable, i.e. not in the ALLOCATED state.
1256 *
1257 * @returns VBox strict status code.
1258 * @retval VINF_SUCCESS on success.
1259 * @retval VINF_PGM_SYNC_CR3 on success and a page pool flush is pending.
1260 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1261 *
1262 * @param pVM The cross context VM structure.
1263 * @param pPage The physical page tracking structure.
1264 * @param GCPhys The address of the page.
1265 *
1266 * @remarks Called from within the PGM critical section.
1267 */
1268int pgmPhysPageMakeWritable(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
1269{
1270 PGM_LOCK_ASSERT_OWNER(pVM);
1271 switch (PGM_PAGE_GET_STATE(pPage))
1272 {
1273 case PGM_PAGE_STATE_WRITE_MONITORED:
1274 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, GCPhys);
1275 RT_FALL_THRU();
1276 default: /* to shut up GCC */
1277 case PGM_PAGE_STATE_ALLOCATED:
1278 return VINF_SUCCESS;
1279
1280 /*
1281 * Zero pages can be dummy pages for MMIO or reserved memory,
1282 * so we need to check the flags before joining cause with
1283 * shared page replacement.
1284 */
1285 case PGM_PAGE_STATE_ZERO:
1286 if (PGM_PAGE_IS_MMIO(pPage))
1287 return VERR_PGM_PHYS_PAGE_RESERVED;
1288 RT_FALL_THRU();
1289 case PGM_PAGE_STATE_SHARED:
1290 return pgmPhysAllocPage(pVM, pPage, GCPhys);
1291
1292 /* Not allowed to write to ballooned pages. */
1293 case PGM_PAGE_STATE_BALLOONED:
1294 return VERR_PGM_PHYS_PAGE_BALLOONED;
1295 }
1296}
1297
1298
1299/**
1300 * Internal usage: Map the page specified by its GMM ID.
1301 *
1302 * This is similar to pgmPhysPageMap
1303 *
1304 * @returns VBox status code.
1305 *
1306 * @param pVM The cross context VM structure.
1307 * @param idPage The Page ID.
1308 * @param HCPhys The physical address (for SUPR0HCPhysToVirt).
1309 * @param ppv Where to store the mapping address.
1310 *
1311 * @remarks Called from within the PGM critical section. The mapping is only
1312 * valid while you are inside this section.
1313 */
1314int pgmPhysPageMapByPageID(PVMCC pVM, uint32_t idPage, RTHCPHYS HCPhys, void **ppv)
1315{
1316 /*
1317 * Validation.
1318 */
1319 PGM_LOCK_ASSERT_OWNER(pVM);
1320 AssertReturn(HCPhys && !(HCPhys & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
1321 const uint32_t idChunk = idPage >> GMM_CHUNKID_SHIFT;
1322 AssertReturn(idChunk != NIL_GMM_CHUNKID, VERR_INVALID_PARAMETER);
1323
1324#ifdef IN_RING0
1325# ifdef VBOX_WITH_LINEAR_HOST_PHYS_MEM
1326 return SUPR0HCPhysToVirt(HCPhys & ~(RTHCPHYS)GUEST_PAGE_OFFSET_MASK, ppv);
1327# else
1328 return GMMR0PageIdToVirt(pVM, idPage, ppv);
1329# endif
1330
1331#else
1332 /*
1333 * Find/make Chunk TLB entry for the mapping chunk.
1334 */
1335 PPGMCHUNKR3MAP pMap;
1336 PPGMCHUNKR3MAPTLBE pTlbe = &pVM->pgm.s.ChunkR3Map.Tlb.aEntries[PGM_CHUNKR3MAPTLB_IDX(idChunk)];
1337 if (pTlbe->idChunk == idChunk)
1338 {
1339 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,ChunkR3MapTlbHits));
1340 pMap = pTlbe->pChunk;
1341 }
1342 else
1343 {
1344 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,ChunkR3MapTlbMisses));
1345
1346 /*
1347 * Find the chunk, map it if necessary.
1348 */
1349 pMap = (PPGMCHUNKR3MAP)RTAvlU32Get(&pVM->pgm.s.ChunkR3Map.pTree, idChunk);
1350 if (pMap)
1351 pMap->iLastUsed = pVM->pgm.s.ChunkR3Map.iNow;
1352 else
1353 {
1354 int rc = pgmR3PhysChunkMap(pVM, idChunk, &pMap);
1355 if (RT_FAILURE(rc))
1356 return rc;
1357 }
1358
1359 /*
1360 * Enter it into the Chunk TLB.
1361 */
1362 pTlbe->idChunk = idChunk;
1363 pTlbe->pChunk = pMap;
1364 }
1365
1366 *ppv = (uint8_t *)pMap->pv + ((idPage & GMM_PAGEID_IDX_MASK) << GUEST_PAGE_SHIFT);
1367 return VINF_SUCCESS;
1368#endif
1369}
1370
1371
1372/**
1373 * Maps a page into the current virtual address space so it can be accessed.
1374 *
1375 * @returns VBox status code.
1376 * @retval VINF_SUCCESS on success.
1377 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1378 *
1379 * @param pVM The cross context VM structure.
1380 * @param pPage The physical page tracking structure.
1381 * @param GCPhys The address of the page.
1382 * @param ppMap Where to store the address of the mapping tracking structure.
1383 * @param ppv Where to store the mapping address of the page. The page
1384 * offset is masked off!
1385 *
1386 * @remarks Called from within the PGM critical section.
1387 */
1388static int pgmPhysPageMapCommon(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMPAGEMAP ppMap, void **ppv)
1389{
1390 PGM_LOCK_ASSERT_OWNER(pVM);
1391 NOREF(GCPhys);
1392
1393 /*
1394 * Special cases: MMIO2, ZERO and specially aliased MMIO pages.
1395 */
1396 if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2
1397 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO)
1398 {
1399 /* Decode the page id to a page in a MMIO2 ram range. */
1400 uint8_t idMmio2 = PGM_MMIO2_PAGEID_GET_MMIO2_ID(PGM_PAGE_GET_PAGEID(pPage));
1401 uint32_t iPage = PGM_MMIO2_PAGEID_GET_IDX(PGM_PAGE_GET_PAGEID(pPage));
1402 AssertLogRelMsgReturn((uint8_t)(idMmio2 - 1U) < RT_ELEMENTS(pVM->pgm.s.CTX_SUFF(apMmio2Ranges)),
1403 ("idMmio2=%u size=%u type=%u GCPHys=%#RGp Id=%u State=%u", idMmio2,
1404 RT_ELEMENTS(pVM->pgm.s.CTX_SUFF(apMmio2Ranges)), PGM_PAGE_GET_TYPE(pPage), GCPhys,
1405 pPage->s.idPage, pPage->s.uStateY),
1406 VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
1407 PPGMREGMMIO2RANGE pMmio2Range = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[idMmio2 - 1];
1408 AssertLogRelReturn(pMmio2Range, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
1409 AssertLogRelReturn(pMmio2Range->idMmio2 == idMmio2, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
1410 AssertLogRelReturn(iPage < (pMmio2Range->RamRange.cb >> GUEST_PAGE_SHIFT), VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
1411 *ppMap = NULL;
1412# if defined(IN_RING0) && defined(VBOX_WITH_LINEAR_HOST_PHYS_MEM)
1413 return SUPR0HCPhysToVirt(PGM_PAGE_GET_HCPHYS(pPage), ppv);
1414# elif defined(IN_RING0)
1415 *ppv = (uint8_t *)pMmio2Range->pvR0 + ((uintptr_t)iPage << GUEST_PAGE_SHIFT);
1416 return VINF_SUCCESS;
1417# else
1418 *ppv = (uint8_t *)pMmio2Range->RamRange.pvR3 + ((uintptr_t)iPage << GUEST_PAGE_SHIFT);
1419 return VINF_SUCCESS;
1420# endif
1421 }
1422
1423# ifdef VBOX_WITH_PGM_NEM_MODE
1424 if (pVM->pgm.s.fNemMode)
1425 {
1426# ifdef IN_RING3
1427 /*
1428 * Find the corresponding RAM range and use that to locate the mapping address.
1429 */
1430 /** @todo Use the page ID for some kind of indexing as we do with MMIO2 above. */
1431 PPGMRAMRANGE const pRam = pgmPhysGetRange(pVM, GCPhys);
1432 AssertLogRelMsgReturn(pRam, ("%RTGp\n", GCPhys), VERR_INTERNAL_ERROR_3);
1433 size_t const idxPage = (GCPhys - pRam->GCPhys) >> GUEST_PAGE_SHIFT;
1434 Assert(pPage == &pRam->aPages[idxPage]);
1435 *ppMap = NULL;
1436 *ppv = (uint8_t *)pRam->pvR3 + (idxPage << GUEST_PAGE_SHIFT);
1437 return VINF_SUCCESS;
1438# else
1439 AssertFailedReturn(VERR_INTERNAL_ERROR_2);
1440# endif
1441 }
1442# endif
1443
1444 const uint32_t idChunk = PGM_PAGE_GET_CHUNKID(pPage);
1445 if (idChunk == NIL_GMM_CHUNKID)
1446 {
1447 AssertMsgReturn(PGM_PAGE_GET_PAGEID(pPage) == NIL_GMM_PAGEID, ("pPage=%R[pgmpage]\n", pPage),
1448 VERR_PGM_PHYS_PAGE_MAP_IPE_1);
1449 if (!PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
1450 {
1451 AssertMsgReturn(PGM_PAGE_IS_ZERO(pPage), ("pPage=%R[pgmpage]\n", pPage),
1452 VERR_PGM_PHYS_PAGE_MAP_IPE_3);
1453 AssertMsgReturn(PGM_PAGE_GET_HCPHYS(pPage)== pVM->pgm.s.HCPhysZeroPg, ("pPage=%R[pgmpage]\n", pPage),
1454 VERR_PGM_PHYS_PAGE_MAP_IPE_4);
1455 *ppv = pVM->pgm.s.abZeroPg;
1456 }
1457 else
1458 *ppv = pVM->pgm.s.abZeroPg;
1459 *ppMap = NULL;
1460 return VINF_SUCCESS;
1461 }
1462
1463# if defined(IN_RING0) && defined(VBOX_WITH_LINEAR_HOST_PHYS_MEM)
1464 /*
1465 * Just use the physical address.
1466 */
1467 *ppMap = NULL;
1468 return SUPR0HCPhysToVirt(PGM_PAGE_GET_HCPHYS(pPage), ppv);
1469
1470# elif defined(IN_RING0)
1471 /*
1472 * Go by page ID thru GMMR0.
1473 */
1474 *ppMap = NULL;
1475 return GMMR0PageIdToVirt(pVM, PGM_PAGE_GET_PAGEID(pPage), ppv);
1476
1477# else
1478 /*
1479 * Find/make Chunk TLB entry for the mapping chunk.
1480 */
1481 PPGMCHUNKR3MAP pMap;
1482 PPGMCHUNKR3MAPTLBE pTlbe = &pVM->pgm.s.ChunkR3Map.Tlb.aEntries[PGM_CHUNKR3MAPTLB_IDX(idChunk)];
1483 if (pTlbe->idChunk == idChunk)
1484 {
1485 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,ChunkR3MapTlbHits));
1486 pMap = pTlbe->pChunk;
1487 AssertPtr(pMap->pv);
1488 }
1489 else
1490 {
1491 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,ChunkR3MapTlbMisses));
1492
1493 /*
1494 * Find the chunk, map it if necessary.
1495 */
1496 pMap = (PPGMCHUNKR3MAP)RTAvlU32Get(&pVM->pgm.s.ChunkR3Map.pTree, idChunk);
1497 if (pMap)
1498 {
1499 AssertPtr(pMap->pv);
1500 pMap->iLastUsed = pVM->pgm.s.ChunkR3Map.iNow;
1501 }
1502 else
1503 {
1504 int rc = pgmR3PhysChunkMap(pVM, idChunk, &pMap);
1505 if (RT_FAILURE(rc))
1506 return rc;
1507 AssertPtr(pMap->pv);
1508 }
1509
1510 /*
1511 * Enter it into the Chunk TLB.
1512 */
1513 pTlbe->idChunk = idChunk;
1514 pTlbe->pChunk = pMap;
1515 }
1516
1517 *ppv = (uint8_t *)pMap->pv + (PGM_PAGE_GET_PAGE_IN_CHUNK(pPage) << GUEST_PAGE_SHIFT);
1518 *ppMap = pMap;
1519 return VINF_SUCCESS;
1520# endif /* !IN_RING0 */
1521}
1522
1523
1524/**
1525 * Combination of pgmPhysPageMakeWritable and pgmPhysPageMapWritable.
1526 *
1527 * This is typically used is paths where we cannot use the TLB methods (like ROM
1528 * pages) or where there is no point in using them since we won't get many hits.
1529 *
1530 * @returns VBox strict status code.
1531 * @retval VINF_SUCCESS on success.
1532 * @retval VINF_PGM_SYNC_CR3 on success and a page pool flush is pending.
1533 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1534 *
1535 * @param pVM The cross context VM structure.
1536 * @param pPage The physical page tracking structure.
1537 * @param GCPhys The address of the page.
1538 * @param ppv Where to store the mapping address of the page. The page
1539 * offset is masked off!
1540 *
1541 * @remarks Called from within the PGM critical section. The mapping is only
1542 * valid while you are inside section.
1543 */
1544int pgmPhysPageMakeWritableAndMap(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void **ppv)
1545{
1546 int rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1547 if (RT_SUCCESS(rc))
1548 {
1549 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 /* returned */, ("%Rrc\n", rc));
1550 PPGMPAGEMAP pMapIgnore;
1551 int rc2 = pgmPhysPageMapCommon(pVM, pPage, GCPhys, &pMapIgnore, ppv);
1552 if (RT_FAILURE(rc2)) /* preserve rc */
1553 rc = rc2;
1554 }
1555 return rc;
1556}
1557
1558
1559/**
1560 * Maps a page into the current virtual address space so it can be accessed for
1561 * both writing and reading.
1562 *
1563 * This is typically used is paths where we cannot use the TLB methods (like ROM
1564 * pages) or where there is no point in using them since we won't get many hits.
1565 *
1566 * @returns VBox status code.
1567 * @retval VINF_SUCCESS on success.
1568 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1569 *
1570 * @param pVM The cross context VM structure.
1571 * @param pPage The physical page tracking structure. Must be in the
1572 * allocated state.
1573 * @param GCPhys The address of the page.
1574 * @param ppv Where to store the mapping address of the page. The page
1575 * offset is masked off!
1576 *
1577 * @remarks Called from within the PGM critical section. The mapping is only
1578 * valid while you are inside section.
1579 */
1580int pgmPhysPageMap(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void **ppv)
1581{
1582 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED);
1583 PPGMPAGEMAP pMapIgnore;
1584 return pgmPhysPageMapCommon(pVM, pPage, GCPhys, &pMapIgnore, ppv);
1585}
1586
1587
1588/**
1589 * Maps a page into the current virtual address space so it can be accessed for
1590 * reading.
1591 *
1592 * This is typically used is paths where we cannot use the TLB methods (like ROM
1593 * pages) or where there is no point in using them since we won't get many hits.
1594 *
1595 * @returns VBox status code.
1596 * @retval VINF_SUCCESS on success.
1597 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1598 *
1599 * @param pVM The cross context VM structure.
1600 * @param pPage The physical page tracking structure.
1601 * @param GCPhys The address of the page.
1602 * @param ppv Where to store the mapping address of the page. The page
1603 * offset is masked off!
1604 *
1605 * @remarks Called from within the PGM critical section. The mapping is only
1606 * valid while you are inside this section.
1607 */
1608int pgmPhysPageMapReadOnly(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void const **ppv)
1609{
1610 PPGMPAGEMAP pMapIgnore;
1611 return pgmPhysPageMapCommon(pVM, pPage, GCPhys, &pMapIgnore, (void **)ppv);
1612}
1613
1614
1615/**
1616 * Load a guest page into the ring-3 physical TLB.
1617 *
1618 * @returns VBox status code.
1619 * @retval VINF_SUCCESS on success
1620 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1621 * @param pVM The cross context VM structure.
1622 * @param GCPhys The guest physical address in question.
1623 */
1624int pgmPhysPageLoadIntoTlb(PVMCC pVM, RTGCPHYS GCPhys)
1625{
1626 PGM_LOCK_ASSERT_OWNER(pVM);
1627
1628 /*
1629 * Find the ram range and page and hand it over to the with-page function.
1630 * 99.8% of requests are expected to be in the first range.
1631 */
1632 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
1633 if (!pPage)
1634 {
1635 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PageMapTlbMisses));
1636 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
1637 }
1638
1639 return pgmPhysPageLoadIntoTlbWithPage(pVM, pPage, GCPhys);
1640}
1641
1642
1643/**
1644 * Load a guest page into the ring-3 physical TLB.
1645 *
1646 * @returns VBox status code.
1647 * @retval VINF_SUCCESS on success
1648 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1649 *
1650 * @param pVM The cross context VM structure.
1651 * @param pPage Pointer to the PGMPAGE structure corresponding to
1652 * GCPhys.
1653 * @param GCPhys The guest physical address in question.
1654 */
1655int pgmPhysPageLoadIntoTlbWithPage(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
1656{
1657 PGM_LOCK_ASSERT_OWNER(pVM);
1658 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PageMapTlbMisses));
1659
1660 /*
1661 * Map the page.
1662 * Make a special case for the zero page as it is kind of special.
1663 */
1664 PPGMPAGEMAPTLBE pTlbe = &pVM->pgm.s.CTX_SUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
1665 if ( !PGM_PAGE_IS_ZERO(pPage)
1666 && !PGM_PAGE_IS_BALLOONED(pPage))
1667 {
1668 void *pv;
1669 PPGMPAGEMAP pMap;
1670 int rc = pgmPhysPageMapCommon(pVM, pPage, GCPhys, &pMap, &pv);
1671 if (RT_FAILURE(rc))
1672 return rc;
1673# ifndef IN_RING0
1674 pTlbe->pMap = pMap;
1675# endif
1676 pTlbe->pv = pv;
1677 Assert(!((uintptr_t)pTlbe->pv & GUEST_PAGE_OFFSET_MASK));
1678 }
1679 else
1680 {
1681 AssertMsg(PGM_PAGE_GET_HCPHYS(pPage) == pVM->pgm.s.HCPhysZeroPg, ("%RGp/%R[pgmpage]\n", GCPhys, pPage));
1682# ifndef IN_RING0
1683 pTlbe->pMap = NULL;
1684# endif
1685 pTlbe->pv = pVM->pgm.s.abZeroPg;
1686 }
1687# ifdef PGM_WITH_PHYS_TLB
1688 if ( PGM_PAGE_GET_TYPE(pPage) < PGMPAGETYPE_ROM_SHADOW
1689 || PGM_PAGE_GET_TYPE(pPage) > PGMPAGETYPE_ROM)
1690 pTlbe->GCPhys = GCPhys & X86_PTE_PAE_PG_MASK;
1691 else
1692 pTlbe->GCPhys = NIL_RTGCPHYS; /* ROM: Problematic because of the two pages. :-/ */
1693# else
1694 pTlbe->GCPhys = NIL_RTGCPHYS;
1695# endif
1696 pTlbe->pPage = pPage;
1697 return VINF_SUCCESS;
1698}
1699
1700
1701/**
1702 * Internal version of PGMPhysGCPhys2CCPtr that expects the caller to
1703 * own the PGM lock and therefore not need to lock the mapped page.
1704 *
1705 * @returns VBox status code.
1706 * @retval VINF_SUCCESS on success.
1707 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1708 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1709 *
1710 * @param pVM The cross context VM structure.
1711 * @param GCPhys The guest physical address of the page that should be mapped.
1712 * @param pPage Pointer to the PGMPAGE structure for the page.
1713 * @param ppv Where to store the address corresponding to GCPhys.
1714 *
1715 * @internal
1716 * @deprecated Use pgmPhysGCPhys2CCPtrInternalEx.
1717 */
1718int pgmPhysGCPhys2CCPtrInternalDepr(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void **ppv)
1719{
1720 int rc;
1721 AssertReturn(pPage, VERR_PGM_PHYS_NULL_PAGE_PARAM);
1722 PGM_LOCK_ASSERT_OWNER(pVM);
1723 pVM->pgm.s.cDeprecatedPageLocks++;
1724
1725 /*
1726 * Make sure the page is writable.
1727 */
1728 if (RT_UNLIKELY(PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED))
1729 {
1730 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1731 if (RT_FAILURE(rc))
1732 return rc;
1733 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 /* not returned */, ("%Rrc\n", rc));
1734 }
1735 Assert(PGM_PAGE_GET_HCPHYS(pPage) != 0);
1736
1737 /*
1738 * Get the mapping address.
1739 */
1740 PPGMPAGEMAPTLBE pTlbe;
1741 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
1742 if (RT_FAILURE(rc))
1743 return rc;
1744 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
1745 return VINF_SUCCESS;
1746}
1747
1748
1749/**
1750 * Locks a page mapping for writing.
1751 *
1752 * @param pVM The cross context VM structure.
1753 * @param pPage The page.
1754 * @param pTlbe The mapping TLB entry for the page.
1755 * @param pLock The lock structure (output).
1756 */
1757DECLINLINE(void) pgmPhysPageMapLockForWriting(PVM pVM, PPGMPAGE pPage, PPGMPAGEMAPTLBE pTlbe, PPGMPAGEMAPLOCK pLock)
1758{
1759# ifndef IN_RING0
1760 PPGMPAGEMAP pMap = pTlbe->pMap;
1761 if (pMap)
1762 pMap->cRefs++;
1763# else
1764 RT_NOREF(pTlbe);
1765# endif
1766
1767 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
1768 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
1769 {
1770 if (cLocks == 0)
1771 pVM->pgm.s.cWriteLockedPages++;
1772 PGM_PAGE_INC_WRITE_LOCKS(pPage);
1773 }
1774 else if (cLocks != PGM_PAGE_MAX_LOCKS)
1775 {
1776 PGM_PAGE_INC_WRITE_LOCKS(pPage);
1777 AssertMsgFailed(("%R[pgmpage] is entering permanent write locked state!\n", pPage));
1778# ifndef IN_RING0
1779 if (pMap)
1780 pMap->cRefs++; /* Extra ref to prevent it from going away. */
1781# endif
1782 }
1783
1784 pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_WRITE;
1785# ifndef IN_RING0
1786 pLock->pvMap = pMap;
1787# else
1788 pLock->pvMap = NULL;
1789# endif
1790}
1791
1792/**
1793 * Locks a page mapping for reading.
1794 *
1795 * @param pVM The cross context VM structure.
1796 * @param pPage The page.
1797 * @param pTlbe The mapping TLB entry for the page.
1798 * @param pLock The lock structure (output).
1799 */
1800DECLINLINE(void) pgmPhysPageMapLockForReading(PVM pVM, PPGMPAGE pPage, PPGMPAGEMAPTLBE pTlbe, PPGMPAGEMAPLOCK pLock)
1801{
1802# ifndef IN_RING0
1803 PPGMPAGEMAP pMap = pTlbe->pMap;
1804 if (pMap)
1805 pMap->cRefs++;
1806# else
1807 RT_NOREF(pTlbe);
1808# endif
1809
1810 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
1811 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
1812 {
1813 if (cLocks == 0)
1814 pVM->pgm.s.cReadLockedPages++;
1815 PGM_PAGE_INC_READ_LOCKS(pPage);
1816 }
1817 else if (cLocks != PGM_PAGE_MAX_LOCKS)
1818 {
1819 PGM_PAGE_INC_READ_LOCKS(pPage);
1820 AssertMsgFailed(("%R[pgmpage] is entering permanent read locked state!\n", pPage));
1821# ifndef IN_RING0
1822 if (pMap)
1823 pMap->cRefs++; /* Extra ref to prevent it from going away. */
1824# endif
1825 }
1826
1827 pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_READ;
1828# ifndef IN_RING0
1829 pLock->pvMap = pMap;
1830# else
1831 pLock->pvMap = NULL;
1832# endif
1833}
1834
1835
1836/**
1837 * Internal version of PGMPhysGCPhys2CCPtr that expects the caller to
1838 * own the PGM lock and have access to the page structure.
1839 *
1840 * @returns VBox status code.
1841 * @retval VINF_SUCCESS on success.
1842 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1843 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1844 *
1845 * @param pVM The cross context VM structure.
1846 * @param GCPhys The guest physical address of the page that should be mapped.
1847 * @param pPage Pointer to the PGMPAGE structure for the page.
1848 * @param ppv Where to store the address corresponding to GCPhys.
1849 * @param pLock Where to store the lock information that
1850 * pgmPhysReleaseInternalPageMappingLock needs.
1851 *
1852 * @internal
1853 */
1854int pgmPhysGCPhys2CCPtrInternal(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
1855{
1856 int rc;
1857 AssertReturn(pPage, VERR_PGM_PHYS_NULL_PAGE_PARAM);
1858 PGM_LOCK_ASSERT_OWNER(pVM);
1859
1860 /*
1861 * Make sure the page is writable.
1862 */
1863 if (RT_UNLIKELY(PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED))
1864 {
1865 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1866 if (RT_FAILURE(rc))
1867 return rc;
1868 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 /* not returned */, ("%Rrc\n", rc));
1869 }
1870 Assert(PGM_PAGE_GET_HCPHYS(pPage) != 0);
1871
1872 /*
1873 * Do the job.
1874 */
1875 PPGMPAGEMAPTLBE pTlbe;
1876 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
1877 if (RT_FAILURE(rc))
1878 return rc;
1879 pgmPhysPageMapLockForWriting(pVM, pPage, pTlbe, pLock);
1880 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
1881 return VINF_SUCCESS;
1882}
1883
1884
1885/**
1886 * Internal version of PGMPhysGCPhys2CCPtrReadOnly that expects the caller to
1887 * own the PGM lock and have access to the page structure.
1888 *
1889 * @returns VBox status code.
1890 * @retval VINF_SUCCESS on success.
1891 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1892 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1893 *
1894 * @param pVM The cross context VM structure.
1895 * @param GCPhys The guest physical address of the page that should be mapped.
1896 * @param pPage Pointer to the PGMPAGE structure for the page.
1897 * @param ppv Where to store the address corresponding to GCPhys.
1898 * @param pLock Where to store the lock information that
1899 * pgmPhysReleaseInternalPageMappingLock needs.
1900 *
1901 * @internal
1902 */
1903int pgmPhysGCPhys2CCPtrInternalReadOnly(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, const void **ppv, PPGMPAGEMAPLOCK pLock)
1904{
1905 AssertReturn(pPage, VERR_PGM_PHYS_NULL_PAGE_PARAM);
1906 PGM_LOCK_ASSERT_OWNER(pVM);
1907 Assert(PGM_PAGE_GET_HCPHYS(pPage) != 0);
1908
1909 /*
1910 * Do the job.
1911 */
1912 PPGMPAGEMAPTLBE pTlbe;
1913 int rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
1914 if (RT_FAILURE(rc))
1915 return rc;
1916 pgmPhysPageMapLockForReading(pVM, pPage, pTlbe, pLock);
1917 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
1918 return VINF_SUCCESS;
1919}
1920
1921
1922/**
1923 * Requests the mapping of a guest page into the current context.
1924 *
1925 * This API should only be used for very short term, as it will consume scarse
1926 * resources (R0 and GC) in the mapping cache. When you're done with the page,
1927 * call PGMPhysReleasePageMappingLock() ASAP to release it.
1928 *
1929 * This API will assume your intention is to write to the page, and will
1930 * therefore replace shared and zero pages. If you do not intend to modify
1931 * the page, use the PGMPhysGCPhys2CCPtrReadOnly() API.
1932 *
1933 * @returns VBox status code.
1934 * @retval VINF_SUCCESS on success.
1935 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1936 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1937 *
1938 * @param pVM The cross context VM structure.
1939 * @param GCPhys The guest physical address of the page that should be
1940 * mapped.
1941 * @param ppv Where to store the address corresponding to GCPhys.
1942 * @param pLock Where to store the lock information that
1943 * PGMPhysReleasePageMappingLock needs.
1944 *
1945 * @remarks The caller is responsible for dealing with access handlers.
1946 * @todo Add an informational return code for pages with access handlers?
1947 *
1948 * @remark Avoid calling this API from within critical sections (other than
1949 * the PGM one) because of the deadlock risk. External threads may
1950 * need to delegate jobs to the EMTs.
1951 * @remarks Only one page is mapped! Make no assumption about what's after or
1952 * before the returned page!
1953 * @thread Any thread.
1954 */
1955VMM_INT_DECL(int) PGMPhysGCPhys2CCPtr(PVMCC pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
1956{
1957 int rc = PGM_LOCK(pVM);
1958 AssertRCReturn(rc, rc);
1959
1960 /*
1961 * Query the Physical TLB entry for the page (may fail).
1962 */
1963 PPGMPAGEMAPTLBE pTlbe;
1964 rc = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
1965 if (RT_SUCCESS(rc))
1966 {
1967 /*
1968 * If the page is shared, the zero page, or being write monitored
1969 * it must be converted to a page that's writable if possible.
1970 */
1971 PPGMPAGE pPage = pTlbe->pPage;
1972 if (RT_UNLIKELY(PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED))
1973 {
1974 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1975 if (RT_SUCCESS(rc))
1976 {
1977 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 /* not returned */, ("%Rrc\n", rc));
1978 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
1979 }
1980 }
1981 if (RT_SUCCESS(rc))
1982 {
1983 /*
1984 * Now, just perform the locking and calculate the return address.
1985 */
1986 pgmPhysPageMapLockForWriting(pVM, pPage, pTlbe, pLock);
1987 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
1988 }
1989 }
1990
1991 PGM_UNLOCK(pVM);
1992 return rc;
1993}
1994
1995
1996/**
1997 * Requests the mapping of a guest page into the current context.
1998 *
1999 * This API should only be used for very short term, as it will consume scarse
2000 * resources (R0 and GC) in the mapping cache. When you're done with the page,
2001 * call PGMPhysReleasePageMappingLock() ASAP to release it.
2002 *
2003 * @returns VBox status code.
2004 * @retval VINF_SUCCESS on success.
2005 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
2006 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
2007 *
2008 * @param pVM The cross context VM structure.
2009 * @param GCPhys The guest physical address of the page that should be
2010 * mapped.
2011 * @param ppv Where to store the address corresponding to GCPhys.
2012 * @param pLock Where to store the lock information that
2013 * PGMPhysReleasePageMappingLock needs.
2014 *
2015 * @remarks The caller is responsible for dealing with access handlers.
2016 * @todo Add an informational return code for pages with access handlers?
2017 *
2018 * @remarks Avoid calling this API from within critical sections (other than
2019 * the PGM one) because of the deadlock risk.
2020 * @remarks Only one page is mapped! Make no assumption about what's after or
2021 * before the returned page!
2022 * @thread Any thread.
2023 */
2024VMM_INT_DECL(int) PGMPhysGCPhys2CCPtrReadOnly(PVMCC pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock)
2025{
2026 int rc = PGM_LOCK(pVM);
2027 AssertRCReturn(rc, rc);
2028
2029 /*
2030 * Query the Physical TLB entry for the page (may fail).
2031 */
2032 PPGMPAGEMAPTLBE pTlbe;
2033 rc = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
2034 if (RT_SUCCESS(rc))
2035 {
2036 /* MMIO pages doesn't have any readable backing. */
2037 PPGMPAGE pPage = pTlbe->pPage;
2038 if (RT_UNLIKELY(PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage)))
2039 rc = VERR_PGM_PHYS_PAGE_RESERVED;
2040 else
2041 {
2042 /*
2043 * Now, just perform the locking and calculate the return address.
2044 */
2045 pgmPhysPageMapLockForReading(pVM, pPage, pTlbe, pLock);
2046 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
2047 }
2048 }
2049
2050 PGM_UNLOCK(pVM);
2051 return rc;
2052}
2053
2054
2055/**
2056 * Requests the mapping of a guest page given by virtual address into the current context.
2057 *
2058 * This API should only be used for very short term, as it will consume
2059 * scarse resources (R0 and GC) in the mapping cache. When you're done
2060 * with the page, call PGMPhysReleasePageMappingLock() ASAP to release it.
2061 *
2062 * This API will assume your intention is to write to the page, and will
2063 * therefore replace shared and zero pages. If you do not intend to modify
2064 * the page, use the PGMPhysGCPtr2CCPtrReadOnly() API.
2065 *
2066 * @returns VBox status code.
2067 * @retval VINF_SUCCESS on success.
2068 * @retval VERR_PAGE_TABLE_NOT_PRESENT if the page directory for the virtual address isn't present.
2069 * @retval VERR_PAGE_NOT_PRESENT if the page at the virtual address isn't present.
2070 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
2071 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
2072 *
2073 * @param pVCpu The cross context virtual CPU structure.
2074 * @param GCPtr The guest physical address of the page that should be
2075 * mapped.
2076 * @param ppv Where to store the address corresponding to GCPhys.
2077 * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
2078 *
2079 * @remark Avoid calling this API from within critical sections (other than
2080 * the PGM one) because of the deadlock risk.
2081 * @thread EMT
2082 */
2083VMM_INT_DECL(int) PGMPhysGCPtr2CCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr, void **ppv, PPGMPAGEMAPLOCK pLock)
2084{
2085 VM_ASSERT_EMT(pVCpu->CTX_SUFF(pVM));
2086 RTGCPHYS GCPhys;
2087 int rc = PGMPhysGCPtr2GCPhys(pVCpu, GCPtr, &GCPhys);
2088 if (RT_SUCCESS(rc))
2089 rc = PGMPhysGCPhys2CCPtr(pVCpu->CTX_SUFF(pVM), GCPhys, ppv, pLock);
2090 return rc;
2091}
2092
2093
2094/**
2095 * Requests the mapping of a guest page given by virtual address into the current context.
2096 *
2097 * This API should only be used for very short term, as it will consume
2098 * scarse resources (R0 and GC) in the mapping cache. When you're done
2099 * with the page, call PGMPhysReleasePageMappingLock() ASAP to release it.
2100 *
2101 * @returns VBox status code.
2102 * @retval VINF_SUCCESS on success.
2103 * @retval VERR_PAGE_TABLE_NOT_PRESENT if the page directory for the virtual address isn't present.
2104 * @retval VERR_PAGE_NOT_PRESENT if the page at the virtual address isn't present.
2105 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
2106 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
2107 *
2108 * @param pVCpu The cross context virtual CPU structure.
2109 * @param GCPtr The guest physical address of the page that should be
2110 * mapped.
2111 * @param ppv Where to store the address corresponding to GCPtr.
2112 * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
2113 *
2114 * @remark Avoid calling this API from within critical sections (other than
2115 * the PGM one) because of the deadlock risk.
2116 * @thread EMT
2117 */
2118VMM_INT_DECL(int) PGMPhysGCPtr2CCPtrReadOnly(PVMCPUCC pVCpu, RTGCPTR GCPtr, void const **ppv, PPGMPAGEMAPLOCK pLock)
2119{
2120 VM_ASSERT_EMT(pVCpu->CTX_SUFF(pVM));
2121 RTGCPHYS GCPhys;
2122 int rc = PGMPhysGCPtr2GCPhys(pVCpu, GCPtr, &GCPhys);
2123 if (RT_SUCCESS(rc))
2124 rc = PGMPhysGCPhys2CCPtrReadOnly(pVCpu->CTX_SUFF(pVM), GCPhys, ppv, pLock);
2125 return rc;
2126}
2127
2128
2129/**
2130 * Release the mapping of a guest page.
2131 *
2132 * This is the counter part of PGMPhysGCPhys2CCPtr, PGMPhysGCPhys2CCPtrReadOnly
2133 * PGMPhysGCPtr2CCPtr and PGMPhysGCPtr2CCPtrReadOnly.
2134 *
2135 * @param pVM The cross context VM structure.
2136 * @param pLock The lock structure initialized by the mapping function.
2137 */
2138VMMDECL(void) PGMPhysReleasePageMappingLock(PVMCC pVM, PPGMPAGEMAPLOCK pLock)
2139{
2140# ifndef IN_RING0
2141 PPGMPAGEMAP pMap = (PPGMPAGEMAP)pLock->pvMap;
2142# endif
2143 PPGMPAGE pPage = (PPGMPAGE)(pLock->uPageAndType & ~PGMPAGEMAPLOCK_TYPE_MASK);
2144 bool fWriteLock = (pLock->uPageAndType & PGMPAGEMAPLOCK_TYPE_MASK) == PGMPAGEMAPLOCK_TYPE_WRITE;
2145
2146 pLock->uPageAndType = 0;
2147 pLock->pvMap = NULL;
2148
2149 PGM_LOCK_VOID(pVM);
2150 if (fWriteLock)
2151 {
2152 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
2153 Assert(cLocks > 0);
2154 if (RT_LIKELY(cLocks > 0 && cLocks < PGM_PAGE_MAX_LOCKS))
2155 {
2156 if (cLocks == 1)
2157 {
2158 Assert(pVM->pgm.s.cWriteLockedPages > 0);
2159 pVM->pgm.s.cWriteLockedPages--;
2160 }
2161 PGM_PAGE_DEC_WRITE_LOCKS(pPage);
2162 }
2163
2164 if (PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_WRITE_MONITORED)
2165 { /* probably extremely likely */ }
2166 else
2167 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, NIL_RTGCPHYS);
2168 }
2169 else
2170 {
2171 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
2172 Assert(cLocks > 0);
2173 if (RT_LIKELY(cLocks > 0 && cLocks < PGM_PAGE_MAX_LOCKS))
2174 {
2175 if (cLocks == 1)
2176 {
2177 Assert(pVM->pgm.s.cReadLockedPages > 0);
2178 pVM->pgm.s.cReadLockedPages--;
2179 }
2180 PGM_PAGE_DEC_READ_LOCKS(pPage);
2181 }
2182 }
2183
2184# ifndef IN_RING0
2185 if (pMap)
2186 {
2187 Assert(pMap->cRefs >= 1);
2188 pMap->cRefs--;
2189 }
2190# endif
2191 PGM_UNLOCK(pVM);
2192}
2193
2194
2195#ifdef IN_RING3
2196/**
2197 * Release the mapping of multiple guest pages.
2198 *
2199 * This is the counter part to PGMR3PhysBulkGCPhys2CCPtrExternal() and
2200 * PGMR3PhysBulkGCPhys2CCPtrReadOnlyExternal().
2201 *
2202 * @param pVM The cross context VM structure.
2203 * @param cPages Number of pages to unlock.
2204 * @param paLocks Array of locks lock structure initialized by the mapping
2205 * function.
2206 */
2207VMMDECL(void) PGMPhysBulkReleasePageMappingLocks(PVMCC pVM, uint32_t cPages, PPGMPAGEMAPLOCK paLocks)
2208{
2209 Assert(cPages > 0);
2210 bool const fWriteLock = (paLocks[0].uPageAndType & PGMPAGEMAPLOCK_TYPE_MASK) == PGMPAGEMAPLOCK_TYPE_WRITE;
2211#ifdef VBOX_STRICT
2212 for (uint32_t i = 1; i < cPages; i++)
2213 {
2214 Assert(fWriteLock == ((paLocks[i].uPageAndType & PGMPAGEMAPLOCK_TYPE_MASK) == PGMPAGEMAPLOCK_TYPE_WRITE));
2215 AssertPtr(paLocks[i].uPageAndType);
2216 }
2217#endif
2218
2219 PGM_LOCK_VOID(pVM);
2220 if (fWriteLock)
2221 {
2222 /*
2223 * Write locks:
2224 */
2225 for (uint32_t i = 0; i < cPages; i++)
2226 {
2227 PPGMPAGE pPage = (PPGMPAGE)(paLocks[i].uPageAndType & ~PGMPAGEMAPLOCK_TYPE_MASK);
2228 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
2229 Assert(cLocks > 0);
2230 if (RT_LIKELY(cLocks > 0 && cLocks < PGM_PAGE_MAX_LOCKS))
2231 {
2232 if (cLocks == 1)
2233 {
2234 Assert(pVM->pgm.s.cWriteLockedPages > 0);
2235 pVM->pgm.s.cWriteLockedPages--;
2236 }
2237 PGM_PAGE_DEC_WRITE_LOCKS(pPage);
2238 }
2239
2240 if (PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_WRITE_MONITORED)
2241 { /* probably extremely likely */ }
2242 else
2243 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, NIL_RTGCPHYS);
2244
2245 PPGMPAGEMAP pMap = (PPGMPAGEMAP)paLocks[i].pvMap;
2246 if (pMap)
2247 {
2248 Assert(pMap->cRefs >= 1);
2249 pMap->cRefs--;
2250 }
2251
2252 /* Yield the lock: */
2253 if ((i & 1023) == 1023 && i + 1 < cPages)
2254 {
2255 PGM_UNLOCK(pVM);
2256 PGM_LOCK_VOID(pVM);
2257 }
2258 }
2259 }
2260 else
2261 {
2262 /*
2263 * Read locks:
2264 */
2265 for (uint32_t i = 0; i < cPages; i++)
2266 {
2267 PPGMPAGE pPage = (PPGMPAGE)(paLocks[i].uPageAndType & ~PGMPAGEMAPLOCK_TYPE_MASK);
2268 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
2269 Assert(cLocks > 0);
2270 if (RT_LIKELY(cLocks > 0 && cLocks < PGM_PAGE_MAX_LOCKS))
2271 {
2272 if (cLocks == 1)
2273 {
2274 Assert(pVM->pgm.s.cReadLockedPages > 0);
2275 pVM->pgm.s.cReadLockedPages--;
2276 }
2277 PGM_PAGE_DEC_READ_LOCKS(pPage);
2278 }
2279
2280 PPGMPAGEMAP pMap = (PPGMPAGEMAP)paLocks[i].pvMap;
2281 if (pMap)
2282 {
2283 Assert(pMap->cRefs >= 1);
2284 pMap->cRefs--;
2285 }
2286
2287 /* Yield the lock: */
2288 if ((i & 1023) == 1023 && i + 1 < cPages)
2289 {
2290 PGM_UNLOCK(pVM);
2291 PGM_LOCK_VOID(pVM);
2292 }
2293 }
2294 }
2295 PGM_UNLOCK(pVM);
2296
2297 RT_BZERO(paLocks, sizeof(paLocks[0]) * cPages);
2298}
2299#endif /* IN_RING3 */
2300
2301
2302/**
2303 * Release the internal mapping of a guest page.
2304 *
2305 * This is the counter part of pgmPhysGCPhys2CCPtrInternalEx and
2306 * pgmPhysGCPhys2CCPtrInternalReadOnly.
2307 *
2308 * @param pVM The cross context VM structure.
2309 * @param pLock The lock structure initialized by the mapping function.
2310 *
2311 * @remarks Caller must hold the PGM lock.
2312 */
2313void pgmPhysReleaseInternalPageMappingLock(PVMCC pVM, PPGMPAGEMAPLOCK pLock)
2314{
2315 PGM_LOCK_ASSERT_OWNER(pVM);
2316 PGMPhysReleasePageMappingLock(pVM, pLock); /* lazy for now */
2317}
2318
2319
2320/**
2321 * Converts a GC physical address to a HC ring-3 pointer.
2322 *
2323 * @returns VINF_SUCCESS on success.
2324 * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical
2325 * page but has no physical backing.
2326 * @returns VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid
2327 * GC physical address.
2328 * @returns VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY if the range crosses
2329 * a dynamic ram chunk boundary
2330 *
2331 * @param pVM The cross context VM structure.
2332 * @param GCPhys The GC physical address to convert.
2333 * @param pR3Ptr Where to store the R3 pointer on success.
2334 *
2335 * @deprecated Avoid when possible!
2336 */
2337int pgmPhysGCPhys2R3Ptr(PVMCC pVM, RTGCPHYS GCPhys, PRTR3PTR pR3Ptr)
2338{
2339/** @todo this is kind of hacky and needs some more work. */
2340#ifndef DEBUG_sandervl
2341 VM_ASSERT_EMT(pVM); /* no longer safe for use outside the EMT thread! */
2342#endif
2343
2344 Log(("pgmPhysGCPhys2R3Ptr(,%RGp,): dont use this API!\n", GCPhys)); /** @todo eliminate this API! */
2345 PGM_LOCK_VOID(pVM);
2346
2347 PPGMRAMRANGE pRam;
2348 PPGMPAGE pPage;
2349 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
2350 if (RT_SUCCESS(rc))
2351 rc = pgmPhysGCPhys2CCPtrInternalDepr(pVM, pPage, GCPhys, (void **)pR3Ptr);
2352
2353 PGM_UNLOCK(pVM);
2354 Assert(rc <= VINF_SUCCESS);
2355 return rc;
2356}
2357
2358
2359/**
2360 * Converts a guest pointer to a GC physical address.
2361 *
2362 * This uses the current CR3/CR0/CR4 of the guest.
2363 *
2364 * @returns VBox status code.
2365 * @param pVCpu The cross context virtual CPU structure.
2366 * @param GCPtr The guest pointer to convert.
2367 * @param pGCPhys Where to store the GC physical address.
2368 */
2369VMMDECL(int) PGMPhysGCPtr2GCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTGCPHYS pGCPhys)
2370{
2371 PGMPTWALK Walk;
2372 int rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtr, &Walk);
2373 if (pGCPhys && RT_SUCCESS(rc))
2374 *pGCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtr & GUEST_PAGE_OFFSET_MASK);
2375 return rc;
2376}
2377
2378
2379/**
2380 * Converts a guest pointer to a HC physical address.
2381 *
2382 * This uses the current CR3/CR0/CR4 of the guest.
2383 *
2384 * @returns VBox status code.
2385 * @param pVCpu The cross context virtual CPU structure.
2386 * @param GCPtr The guest pointer to convert.
2387 * @param pHCPhys Where to store the HC physical address.
2388 */
2389VMM_INT_DECL(int) PGMPhysGCPtr2HCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTHCPHYS pHCPhys)
2390{
2391 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2392 PGMPTWALK Walk;
2393 int rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtr, &Walk);
2394 if (RT_SUCCESS(rc))
2395 rc = PGMPhysGCPhys2HCPhys(pVM, Walk.GCPhys | ((RTGCUINTPTR)GCPtr & GUEST_PAGE_OFFSET_MASK), pHCPhys);
2396 return rc;
2397}
2398
2399
2400
2401#undef LOG_GROUP
2402#define LOG_GROUP LOG_GROUP_PGM_PHYS_ACCESS
2403
2404
2405#if defined(IN_RING3) && defined(SOME_UNUSED_FUNCTION)
2406/**
2407 * Cache PGMPhys memory access
2408 *
2409 * @param pVM The cross context VM structure.
2410 * @param pCache Cache structure pointer
2411 * @param GCPhys GC physical address
2412 * @param pbR3 HC pointer corresponding to physical page
2413 *
2414 * @thread EMT.
2415 */
2416static void pgmPhysCacheAdd(PVM pVM, PGMPHYSCACHE *pCache, RTGCPHYS GCPhys, uint8_t *pbR3)
2417{
2418 uint32_t iCacheIndex;
2419
2420 Assert(VM_IS_EMT(pVM));
2421
2422 GCPhys &= ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
2423 pbR3 = (uint8_t *)((uintptr_t)pbR3 & ~(uintptr_t)GUEST_PAGE_OFFSET_MASK);
2424
2425 iCacheIndex = ((GCPhys >> GUEST_PAGE_SHIFT) & PGM_MAX_PHYSCACHE_ENTRIES_MASK);
2426
2427 ASMBitSet(&pCache->aEntries, iCacheIndex);
2428
2429 pCache->Entry[iCacheIndex].GCPhys = GCPhys;
2430 pCache->Entry[iCacheIndex].pbR3 = pbR3;
2431}
2432#endif /* IN_RING3 */
2433
2434
2435/**
2436 * Deals with reading from a page with one or more ALL access handlers.
2437 *
2438 * @returns Strict VBox status code in ring-0 and raw-mode, ignorable in ring-3.
2439 * See PGM_HANDLER_PHYS_IS_VALID_STATUS and
2440 * PGM_HANDLER_VIRT_IS_VALID_STATUS for details.
2441 *
2442 * @param pVM The cross context VM structure.
2443 * @param pPage The page descriptor.
2444 * @param GCPhys The physical address to start reading at.
2445 * @param pvBuf Where to put the bits we read.
2446 * @param cb How much to read - less or equal to a page.
2447 * @param enmOrigin The origin of this call.
2448 */
2449static VBOXSTRICTRC pgmPhysReadHandler(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void *pvBuf, size_t cb,
2450 PGMACCESSORIGIN enmOrigin)
2451{
2452 /*
2453 * The most frequent access here is MMIO and shadowed ROM.
2454 * The current code ASSUMES all these access handlers covers full pages!
2455 */
2456
2457 /*
2458 * Whatever we do we need the source page, map it first.
2459 */
2460 PGMPAGEMAPLOCK PgMpLck;
2461 const void *pvSrc = NULL;
2462 int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, GCPhys, &pvSrc, &PgMpLck);
2463/** @todo Check how this can work for MMIO pages? */
2464 if (RT_FAILURE(rc))
2465 {
2466 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
2467 GCPhys, pPage, rc));
2468 memset(pvBuf, 0xff, cb);
2469 return VINF_SUCCESS;
2470 }
2471
2472 VBOXSTRICTRC rcStrict = VINF_PGM_HANDLER_DO_DEFAULT;
2473
2474 /*
2475 * Deal with any physical handlers.
2476 */
2477 PVMCPUCC pVCpu = VMMGetCpu(pVM);
2478 if ( PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_ALL
2479 || PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
2480 {
2481 PPGMPHYSHANDLER pCur;
2482 rc = pgmHandlerPhysicalLookup(pVM, GCPhys, &pCur);
2483 if (RT_SUCCESS(rc))
2484 {
2485 Assert(pCur && GCPhys >= pCur->Key && GCPhys <= pCur->KeyLast);
2486 Assert((pCur->Key & GUEST_PAGE_OFFSET_MASK) == 0);
2487 Assert((pCur->KeyLast & GUEST_PAGE_OFFSET_MASK) == GUEST_PAGE_OFFSET_MASK);
2488#ifndef IN_RING3
2489 if (enmOrigin != PGMACCESSORIGIN_IEM)
2490 {
2491 /* Cannot reliably handle informational status codes in this context */
2492 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2493 return VERR_PGM_PHYS_WR_HIT_HANDLER;
2494 }
2495#endif
2496 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
2497 PFNPGMPHYSHANDLER const pfnHandler = pCurType->pfnHandler; Assert(pfnHandler);
2498 uint64_t const uUser = !pCurType->fRing0DevInsIdx ? pCur->uUser
2499 : (uintptr_t)PDMDeviceRing0IdxToInstance(pVM, pCur->uUser);
2500
2501 Log5(("pgmPhysReadHandler: GCPhys=%RGp cb=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cb, pPage, R3STRING(pCur->pszDesc) ));
2502 STAM_PROFILE_START(&pCur->Stat, h);
2503 PGM_LOCK_ASSERT_OWNER(pVM);
2504
2505 /* Release the PGM lock as MMIO handlers take the IOM lock. (deadlock prevention) */
2506 PGM_UNLOCK(pVM);
2507 rcStrict = pfnHandler(pVM, pVCpu, GCPhys, (void *)pvSrc, pvBuf, cb, PGMACCESSTYPE_READ, enmOrigin, uUser);
2508 PGM_LOCK_VOID(pVM);
2509
2510 STAM_PROFILE_STOP(&pCur->Stat, h); /* no locking needed, entry is unlikely reused before we get here. */
2511 pCur = NULL; /* might not be valid anymore. */
2512 AssertLogRelMsg(PGM_HANDLER_PHYS_IS_VALID_STATUS(rcStrict, false),
2513 ("rcStrict=%Rrc GCPhys=%RGp\n", VBOXSTRICTRC_VAL(rcStrict), GCPhys));
2514 if ( rcStrict != VINF_PGM_HANDLER_DO_DEFAULT
2515 && !PGM_PHYS_RW_IS_SUCCESS(rcStrict))
2516 {
2517 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2518 return rcStrict;
2519 }
2520 }
2521 else if (rc == VERR_NOT_FOUND)
2522 AssertLogRelMsgFailed(("rc=%Rrc GCPhys=%RGp cb=%#x\n", rc, GCPhys, cb));
2523 else
2524 AssertLogRelMsgFailedReturn(("rc=%Rrc GCPhys=%RGp cb=%#x\n", rc, GCPhys, cb), rc);
2525 }
2526
2527 /*
2528 * Take the default action.
2529 */
2530 if (rcStrict == VINF_PGM_HANDLER_DO_DEFAULT)
2531 {
2532 memcpy(pvBuf, pvSrc, cb);
2533 rcStrict = VINF_SUCCESS;
2534 }
2535 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2536 return rcStrict;
2537}
2538
2539
2540/**
2541 * Read physical memory.
2542 *
2543 * This API respects access handlers and MMIO. Use PGMPhysSimpleReadGCPhys() if you
2544 * want to ignore those.
2545 *
2546 * @returns Strict VBox status code in raw-mode and ring-0, normal VBox status
2547 * code in ring-3. Use PGM_PHYS_RW_IS_SUCCESS to check.
2548 * @retval VINF_SUCCESS in all context - read completed.
2549 *
2550 * @retval VINF_EM_OFF in RC and R0 - read completed.
2551 * @retval VINF_EM_SUSPEND in RC and R0 - read completed.
2552 * @retval VINF_EM_RESET in RC and R0 - read completed.
2553 * @retval VINF_EM_HALT in RC and R0 - read completed.
2554 * @retval VINF_SELM_SYNC_GDT in RC only - read completed.
2555 *
2556 * @retval VINF_EM_DBG_STOP in RC and R0 - read completed.
2557 * @retval VINF_EM_DBG_BREAKPOINT in RC and R0 - read completed.
2558 * @retval VINF_EM_RAW_EMULATE_INSTR in RC and R0 only.
2559 *
2560 * @retval VINF_IOM_R3_MMIO_READ in RC and R0.
2561 * @retval VINF_IOM_R3_MMIO_READ_WRITE in RC and R0.
2562 *
2563 * @retval VINF_PATM_CHECK_PATCH_PAGE in RC only.
2564 *
2565 * @retval VERR_PGM_PHYS_WR_HIT_HANDLER in RC and R0 for access origins that
2566 * haven't been cleared for strict status codes yet.
2567 *
2568 * @param pVM The cross context VM structure.
2569 * @param GCPhys Physical address start reading from.
2570 * @param pvBuf Where to put the read bits.
2571 * @param cbRead How many bytes to read.
2572 * @param enmOrigin The origin of this call.
2573 */
2574VMMDECL(VBOXSTRICTRC) PGMPhysRead(PVMCC pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin)
2575{
2576 AssertMsgReturn(cbRead > 0, ("don't even think about reading zero bytes!\n"), VINF_SUCCESS);
2577 LogFlow(("PGMPhysRead: %RGp %d\n", GCPhys, cbRead));
2578
2579 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysRead));
2580 STAM_COUNTER_ADD(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysReadBytes), cbRead);
2581
2582 PGM_LOCK_VOID(pVM);
2583
2584 /*
2585 * Copy loop on ram ranges.
2586 */
2587 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2588 PPGMRAMRANGE pRam = pgmPhysGetRangeAtOrAbove(pVM, GCPhys);
2589 for (;;)
2590 {
2591 /* Inside range or not? */
2592 if (pRam && GCPhys >= pRam->GCPhys)
2593 {
2594 /*
2595 * Must work our way thru this page by page.
2596 */
2597 RTGCPHYS off = GCPhys - pRam->GCPhys;
2598 while (off < pRam->cb)
2599 {
2600 unsigned iPage = off >> GUEST_PAGE_SHIFT;
2601 PPGMPAGE pPage = &pRam->aPages[iPage];
2602 size_t cb = GUEST_PAGE_SIZE - (off & GUEST_PAGE_OFFSET_MASK);
2603 if (cb > cbRead)
2604 cb = cbRead;
2605
2606 /*
2607 * Normal page? Get the pointer to it.
2608 */
2609 if ( !PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)
2610 && !PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
2611 {
2612 /*
2613 * Get the pointer to the page.
2614 */
2615 PGMPAGEMAPLOCK PgMpLck;
2616 const void *pvSrc;
2617 int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, pRam->GCPhys + off, &pvSrc, &PgMpLck);
2618 if (RT_SUCCESS(rc))
2619 {
2620 memcpy(pvBuf, pvSrc, cb);
2621 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2622 }
2623 else
2624 {
2625 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
2626 pRam->GCPhys + off, pPage, rc));
2627 memset(pvBuf, 0xff, cb);
2628 }
2629 }
2630 /*
2631 * Have ALL/MMIO access handlers.
2632 */
2633 else
2634 {
2635 VBOXSTRICTRC rcStrict2 = pgmPhysReadHandler(pVM, pPage, pRam->GCPhys + off, pvBuf, cb, enmOrigin);
2636 if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
2637 PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
2638 else
2639 {
2640 /* Set the remaining buffer to a known value. */
2641 memset(pvBuf, 0xff, cbRead);
2642 PGM_UNLOCK(pVM);
2643 return rcStrict2;
2644 }
2645 }
2646
2647 /* next page */
2648 if (cb >= cbRead)
2649 {
2650 PGM_UNLOCK(pVM);
2651 return rcStrict;
2652 }
2653 cbRead -= cb;
2654 off += cb;
2655 pvBuf = (char *)pvBuf + cb;
2656 } /* walk pages in ram range. */
2657
2658 GCPhys = pRam->GCPhysLast + 1;
2659 }
2660 else
2661 {
2662 LogFlow(("PGMPhysRead: Unassigned %RGp size=%u\n", GCPhys, cbRead));
2663
2664 /*
2665 * Unassigned address space.
2666 */
2667 size_t cb = pRam ? pRam->GCPhys - GCPhys : ~(size_t)0;
2668 if (cb >= cbRead)
2669 {
2670 memset(pvBuf, 0xff, cbRead);
2671 break;
2672 }
2673 memset(pvBuf, 0xff, cb);
2674
2675 cbRead -= cb;
2676 pvBuf = (char *)pvBuf + cb;
2677 GCPhys += cb;
2678 }
2679
2680 /* Advance range if necessary. */
2681 while (pRam && GCPhys > pRam->GCPhysLast)
2682 pRam = pRam->CTX_SUFF(pNext);
2683 } /* Ram range walk */
2684
2685 PGM_UNLOCK(pVM);
2686 return rcStrict;
2687}
2688
2689
2690/**
2691 * Deals with writing to a page with one or more WRITE or ALL access handlers.
2692 *
2693 * @returns Strict VBox status code in ring-0 and raw-mode, ignorable in ring-3.
2694 * See PGM_HANDLER_PHYS_IS_VALID_STATUS and
2695 * PGM_HANDLER_VIRT_IS_VALID_STATUS for details.
2696 *
2697 * @param pVM The cross context VM structure.
2698 * @param pPage The page descriptor.
2699 * @param GCPhys The physical address to start writing at.
2700 * @param pvBuf What to write.
2701 * @param cbWrite How much to write - less or equal to a page.
2702 * @param enmOrigin The origin of this call.
2703 */
2704static VBOXSTRICTRC pgmPhysWriteHandler(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void const *pvBuf, size_t cbWrite,
2705 PGMACCESSORIGIN enmOrigin)
2706{
2707 PGMPAGEMAPLOCK PgMpLck;
2708 void *pvDst = NULL;
2709 VBOXSTRICTRC rcStrict;
2710
2711 /*
2712 * Give priority to physical handlers (like #PF does).
2713 *
2714 * Hope for a lonely physical handler first that covers the whole write
2715 * area. This should be a pretty frequent case with MMIO and the heavy
2716 * usage of full page handlers in the page pool.
2717 */
2718 PVMCPUCC pVCpu = VMMGetCpu(pVM);
2719 PPGMPHYSHANDLER pCur;
2720 rcStrict = pgmHandlerPhysicalLookup(pVM, GCPhys, &pCur);
2721 if (RT_SUCCESS(rcStrict))
2722 {
2723 Assert(GCPhys >= pCur->Key && GCPhys <= pCur->KeyLast);
2724#ifndef IN_RING3
2725 if (enmOrigin != PGMACCESSORIGIN_IEM)
2726 /* Cannot reliably handle informational status codes in this context */
2727 return VERR_PGM_PHYS_WR_HIT_HANDLER;
2728#endif
2729 size_t cbRange = pCur->KeyLast - GCPhys + 1;
2730 if (cbRange > cbWrite)
2731 cbRange = cbWrite;
2732
2733 Assert(PGMPHYSHANDLER_GET_TYPE(pVM, pCur)->pfnHandler);
2734 Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n",
2735 GCPhys, cbRange, pPage, R3STRING(pCur->pszDesc) ));
2736 if (!PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
2737 rcStrict = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &pvDst, &PgMpLck);
2738 else
2739 rcStrict = VINF_SUCCESS;
2740 if (RT_SUCCESS(rcStrict))
2741 {
2742 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
2743 PFNPGMPHYSHANDLER const pfnHandler = pCurType->pfnHandler;
2744 uint64_t const uUser = !pCurType->fRing0DevInsIdx ? pCur->uUser
2745 : (uintptr_t)PDMDeviceRing0IdxToInstance(pVM, pCur->uUser);
2746 STAM_PROFILE_START(&pCur->Stat, h);
2747
2748 /* Most handlers will want to release the PGM lock for deadlock prevention
2749 (esp. MMIO), though some PGM internal ones like the page pool and MMIO2
2750 dirty page trackers will want to keep it for performance reasons. */
2751 PGM_LOCK_ASSERT_OWNER(pVM);
2752 if (pCurType->fKeepPgmLock)
2753 rcStrict = pfnHandler(pVM, pVCpu, GCPhys, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, enmOrigin, uUser);
2754 else
2755 {
2756 PGM_UNLOCK(pVM);
2757 rcStrict = pfnHandler(pVM, pVCpu, GCPhys, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, enmOrigin, uUser);
2758 PGM_LOCK_VOID(pVM);
2759 }
2760
2761 STAM_PROFILE_STOP(&pCur->Stat, h); /* no locking needed, entry is unlikely reused before we get here. */
2762 pCur = NULL; /* might not be valid anymore. */
2763 if (rcStrict == VINF_PGM_HANDLER_DO_DEFAULT)
2764 {
2765 if (pvDst)
2766 memcpy(pvDst, pvBuf, cbRange);
2767 rcStrict = VINF_SUCCESS;
2768 }
2769 else
2770 AssertLogRelMsg(PGM_HANDLER_PHYS_IS_VALID_STATUS(rcStrict, true),
2771 ("rcStrict=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n",
2772 VBOXSTRICTRC_VAL(rcStrict), GCPhys, pPage, pCur ? R3STRING(pCur->pszDesc) : ""));
2773 }
2774 else
2775 AssertLogRelMsgFailedReturn(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
2776 GCPhys, pPage, VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
2777 if (RT_LIKELY(cbRange == cbWrite) || !PGM_PHYS_RW_IS_SUCCESS(rcStrict))
2778 {
2779 if (pvDst)
2780 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2781 return rcStrict;
2782 }
2783
2784 /* more fun to be had below */
2785 cbWrite -= cbRange;
2786 GCPhys += cbRange;
2787 pvBuf = (uint8_t *)pvBuf + cbRange;
2788 pvDst = (uint8_t *)pvDst + cbRange;
2789 }
2790 else if (rcStrict == VERR_NOT_FOUND) /* The handler is somewhere else in the page, deal with it below. */
2791 rcStrict = VINF_SUCCESS;
2792 else
2793 AssertMsgFailedReturn(("rcStrict=%Rrc GCPhys=%RGp\n", VBOXSTRICTRC_VAL(rcStrict), GCPhys), rcStrict);
2794 Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)); /* MMIO handlers are all GUEST_PAGE_SIZEed! */
2795
2796 /*
2797 * Deal with all the odd ends (used to be deal with virt+phys).
2798 */
2799 Assert(rcStrict != VINF_PGM_HANDLER_DO_DEFAULT);
2800
2801 /* We need a writable destination page. */
2802 if (!pvDst)
2803 {
2804 int rc2 = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &pvDst, &PgMpLck);
2805 AssertLogRelMsgReturn(RT_SUCCESS(rc2),
2806 ("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n", GCPhys, pPage, rc2),
2807 rc2);
2808 }
2809
2810 /** @todo clean up this code some more now there are no virtual handlers any
2811 * more. */
2812 /* The loop state (big + ugly). */
2813 PPGMPHYSHANDLER pPhys = NULL;
2814 uint32_t offPhys = GUEST_PAGE_SIZE;
2815 uint32_t offPhysLast = GUEST_PAGE_SIZE;
2816 bool fMorePhys = PGM_PAGE_HAS_ACTIVE_PHYSICAL_HANDLERS(pPage);
2817
2818 /* The loop. */
2819 for (;;)
2820 {
2821 if (fMorePhys && !pPhys)
2822 {
2823 rcStrict = pgmHandlerPhysicalLookup(pVM, GCPhys, &pPhys);
2824 if (RT_SUCCESS_NP(rcStrict))
2825 {
2826 offPhys = 0;
2827 offPhysLast = pPhys->KeyLast - GCPhys; /* ASSUMES < 4GB handlers... */
2828 }
2829 else
2830 {
2831 AssertMsgReturn(rcStrict == VERR_NOT_FOUND, ("%Rrc GCPhys=%RGp\n", VBOXSTRICTRC_VAL(rcStrict), GCPhys), rcStrict);
2832
2833 rcStrict = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookupMatchingOrAbove(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator,
2834 GCPhys, &pPhys);
2835 AssertMsgReturn(RT_SUCCESS(rcStrict) || rcStrict == VERR_NOT_FOUND,
2836 ("%Rrc GCPhys=%RGp\n", VBOXSTRICTRC_VAL(rcStrict), GCPhys), rcStrict);
2837
2838 if ( RT_SUCCESS(rcStrict)
2839 && pPhys->Key <= GCPhys + (cbWrite - 1))
2840 {
2841 offPhys = pPhys->Key - GCPhys;
2842 offPhysLast = pPhys->KeyLast - GCPhys; /* ASSUMES < 4GB handlers... */
2843 Assert(pPhys->KeyLast - pPhys->Key < _4G);
2844 }
2845 else
2846 {
2847 pPhys = NULL;
2848 fMorePhys = false;
2849 offPhys = offPhysLast = GUEST_PAGE_SIZE;
2850 }
2851 }
2852 }
2853
2854 /*
2855 * Handle access to space without handlers (that's easy).
2856 */
2857 VBOXSTRICTRC rcStrict2 = VINF_PGM_HANDLER_DO_DEFAULT;
2858 uint32_t cbRange = (uint32_t)cbWrite;
2859 Assert(cbRange == cbWrite);
2860
2861 /*
2862 * Physical handler.
2863 */
2864 if (!offPhys)
2865 {
2866#ifndef IN_RING3
2867 if (enmOrigin != PGMACCESSORIGIN_IEM)
2868 /* Cannot reliably handle informational status codes in this context */
2869 return VERR_PGM_PHYS_WR_HIT_HANDLER;
2870#endif
2871 if (cbRange > offPhysLast + 1)
2872 cbRange = offPhysLast + 1;
2873
2874 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pPhys);
2875 PFNPGMPHYSHANDLER const pfnHandler = pCurType->pfnHandler;
2876 uint64_t const uUser = !pCurType->fRing0DevInsIdx ? pPhys->uUser
2877 : (uintptr_t)PDMDeviceRing0IdxToInstance(pVM, pPhys->uUser);
2878
2879 Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cbRange, pPage, R3STRING(pPhys->pszDesc) ));
2880 STAM_PROFILE_START(&pPhys->Stat, h);
2881
2882 /* Most handlers will want to release the PGM lock for deadlock prevention
2883 (esp. MMIO), though some PGM internal ones like the page pool and MMIO2
2884 dirty page trackers will want to keep it for performance reasons. */
2885 PGM_LOCK_ASSERT_OWNER(pVM);
2886 if (pCurType->fKeepPgmLock)
2887 rcStrict2 = pfnHandler(pVM, pVCpu, GCPhys, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, enmOrigin, uUser);
2888 else
2889 {
2890 PGM_UNLOCK(pVM);
2891 rcStrict2 = pfnHandler(pVM, pVCpu, GCPhys, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, enmOrigin, uUser);
2892 PGM_LOCK_VOID(pVM);
2893 }
2894
2895 STAM_PROFILE_STOP(&pPhys->Stat, h); /* no locking needed, entry is unlikely reused before we get here. */
2896 pPhys = NULL; /* might not be valid anymore. */
2897 AssertLogRelMsg(PGM_HANDLER_PHYS_IS_VALID_STATUS(rcStrict2, true),
2898 ("rcStrict2=%Rrc (rcStrict=%Rrc) GCPhys=%RGp pPage=%R[pgmpage] %s\n", VBOXSTRICTRC_VAL(rcStrict2),
2899 VBOXSTRICTRC_VAL(rcStrict), GCPhys, pPage, pPhys ? R3STRING(pPhys->pszDesc) : ""));
2900 }
2901
2902 /*
2903 * Execute the default action and merge the status codes.
2904 */
2905 if (rcStrict2 == VINF_PGM_HANDLER_DO_DEFAULT)
2906 {
2907 memcpy(pvDst, pvBuf, cbRange);
2908 rcStrict2 = VINF_SUCCESS;
2909 }
2910 else if (!PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
2911 {
2912 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2913 return rcStrict2;
2914 }
2915 else
2916 PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
2917
2918 /*
2919 * Advance if we've got more stuff to do.
2920 */
2921 if (cbRange >= cbWrite)
2922 {
2923 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2924 return rcStrict;
2925 }
2926
2927
2928 cbWrite -= cbRange;
2929 GCPhys += cbRange;
2930 pvBuf = (uint8_t *)pvBuf + cbRange;
2931 pvDst = (uint8_t *)pvDst + cbRange;
2932
2933 offPhys -= cbRange;
2934 offPhysLast -= cbRange;
2935 }
2936}
2937
2938
2939/**
2940 * Write to physical memory.
2941 *
2942 * This API respects access handlers and MMIO. Use PGMPhysSimpleWriteGCPhys() if you
2943 * want to ignore those.
2944 *
2945 * @returns Strict VBox status code in raw-mode and ring-0, normal VBox status
2946 * code in ring-3. Use PGM_PHYS_RW_IS_SUCCESS to check.
2947 * @retval VINF_SUCCESS in all context - write completed.
2948 *
2949 * @retval VINF_EM_OFF in RC and R0 - write completed.
2950 * @retval VINF_EM_SUSPEND in RC and R0 - write completed.
2951 * @retval VINF_EM_RESET in RC and R0 - write completed.
2952 * @retval VINF_EM_HALT in RC and R0 - write completed.
2953 * @retval VINF_SELM_SYNC_GDT in RC only - write completed.
2954 *
2955 * @retval VINF_EM_DBG_STOP in RC and R0 - write completed.
2956 * @retval VINF_EM_DBG_BREAKPOINT in RC and R0 - write completed.
2957 * @retval VINF_EM_RAW_EMULATE_INSTR in RC and R0 only.
2958 *
2959 * @retval VINF_IOM_R3_MMIO_WRITE in RC and R0.
2960 * @retval VINF_IOM_R3_MMIO_READ_WRITE in RC and R0.
2961 * @retval VINF_IOM_R3_MMIO_COMMIT_WRITE in RC and R0.
2962 *
2963 * @retval VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT in RC only - write completed.
2964 * @retval VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT in RC only.
2965 * @retval VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT in RC only.
2966 * @retval VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT in RC only.
2967 * @retval VINF_CSAM_PENDING_ACTION in RC only.
2968 * @retval VINF_PATM_CHECK_PATCH_PAGE in RC only.
2969 *
2970 * @retval VERR_PGM_PHYS_WR_HIT_HANDLER in RC and R0 for access origins that
2971 * haven't been cleared for strict status codes yet.
2972 *
2973 *
2974 * @param pVM The cross context VM structure.
2975 * @param GCPhys Physical address to write to.
2976 * @param pvBuf What to write.
2977 * @param cbWrite How many bytes to write.
2978 * @param enmOrigin Who is calling.
2979 */
2980VMMDECL(VBOXSTRICTRC) PGMPhysWrite(PVMCC pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin)
2981{
2982 AssertMsg(!pVM->pgm.s.fNoMorePhysWrites, ("Calling PGMPhysWrite after pgmR3Save()! enmOrigin=%d\n", enmOrigin));
2983 AssertMsgReturn(cbWrite > 0, ("don't even think about writing zero bytes!\n"), VINF_SUCCESS);
2984 LogFlow(("PGMPhysWrite: %RGp %d\n", GCPhys, cbWrite));
2985
2986 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysWrite));
2987 STAM_COUNTER_ADD(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysWriteBytes), cbWrite);
2988
2989 PGM_LOCK_VOID(pVM);
2990
2991 /*
2992 * Copy loop on ram ranges.
2993 */
2994 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2995 PPGMRAMRANGE pRam = pgmPhysGetRangeAtOrAbove(pVM, GCPhys);
2996 for (;;)
2997 {
2998 /* Inside range or not? */
2999 if (pRam && GCPhys >= pRam->GCPhys)
3000 {
3001 /*
3002 * Must work our way thru this page by page.
3003 */
3004 RTGCPTR off = GCPhys - pRam->GCPhys;
3005 while (off < pRam->cb)
3006 {
3007 RTGCPTR iPage = off >> GUEST_PAGE_SHIFT;
3008 PPGMPAGE pPage = &pRam->aPages[iPage];
3009 size_t cb = GUEST_PAGE_SIZE - (off & GUEST_PAGE_OFFSET_MASK);
3010 if (cb > cbWrite)
3011 cb = cbWrite;
3012
3013 /*
3014 * Normal page? Get the pointer to it.
3015 */
3016 if ( !PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
3017 && !PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
3018 {
3019 PGMPAGEMAPLOCK PgMpLck;
3020 void *pvDst;
3021 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pRam->GCPhys + off, &pvDst, &PgMpLck);
3022 if (RT_SUCCESS(rc))
3023 {
3024 Assert(!PGM_PAGE_IS_BALLOONED(pPage));
3025 memcpy(pvDst, pvBuf, cb);
3026 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
3027 }
3028 /* Ignore writes to ballooned pages. */
3029 else if (!PGM_PAGE_IS_BALLOONED(pPage))
3030 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
3031 pRam->GCPhys + off, pPage, rc));
3032 }
3033 /*
3034 * Active WRITE or ALL access handlers.
3035 */
3036 else
3037 {
3038 VBOXSTRICTRC rcStrict2 = pgmPhysWriteHandler(pVM, pPage, pRam->GCPhys + off, pvBuf, cb, enmOrigin);
3039 if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
3040 PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
3041 else
3042 {
3043 PGM_UNLOCK(pVM);
3044 return rcStrict2;
3045 }
3046 }
3047
3048 /* next page */
3049 if (cb >= cbWrite)
3050 {
3051 PGM_UNLOCK(pVM);
3052 return rcStrict;
3053 }
3054
3055 cbWrite -= cb;
3056 off += cb;
3057 pvBuf = (const char *)pvBuf + cb;
3058 } /* walk pages in ram range */
3059
3060 GCPhys = pRam->GCPhysLast + 1;
3061 }
3062 else
3063 {
3064 /*
3065 * Unassigned address space, skip it.
3066 */
3067 if (!pRam)
3068 break;
3069 size_t cb = pRam->GCPhys - GCPhys;
3070 if (cb >= cbWrite)
3071 break;
3072 cbWrite -= cb;
3073 pvBuf = (const char *)pvBuf + cb;
3074 GCPhys += cb;
3075 }
3076
3077 /* Advance range if necessary. */
3078 while (pRam && GCPhys > pRam->GCPhysLast)
3079 pRam = pRam->CTX_SUFF(pNext);
3080 } /* Ram range walk */
3081
3082 PGM_UNLOCK(pVM);
3083 return rcStrict;
3084}
3085
3086
3087/**
3088 * Read from guest physical memory by GC physical address, bypassing
3089 * MMIO and access handlers.
3090 *
3091 * @returns VBox status code.
3092 * @param pVM The cross context VM structure.
3093 * @param pvDst The destination address.
3094 * @param GCPhysSrc The source address (GC physical address).
3095 * @param cb The number of bytes to read.
3096 */
3097VMMDECL(int) PGMPhysSimpleReadGCPhys(PVMCC pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb)
3098{
3099 /*
3100 * Treat the first page as a special case.
3101 */
3102 if (!cb)
3103 return VINF_SUCCESS;
3104
3105 /* map the 1st page */
3106 void const *pvSrc;
3107 PGMPAGEMAPLOCK Lock;
3108 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhysSrc, &pvSrc, &Lock);
3109 if (RT_FAILURE(rc))
3110 return rc;
3111
3112 /* optimize for the case where access is completely within the first page. */
3113 size_t cbPage = GUEST_PAGE_SIZE - (GCPhysSrc & GUEST_PAGE_OFFSET_MASK);
3114 if (RT_LIKELY(cb <= cbPage))
3115 {
3116 memcpy(pvDst, pvSrc, cb);
3117 PGMPhysReleasePageMappingLock(pVM, &Lock);
3118 return VINF_SUCCESS;
3119 }
3120
3121 /* copy to the end of the page. */
3122 memcpy(pvDst, pvSrc, cbPage);
3123 PGMPhysReleasePageMappingLock(pVM, &Lock);
3124 GCPhysSrc += cbPage;
3125 pvDst = (uint8_t *)pvDst + cbPage;
3126 cb -= cbPage;
3127
3128 /*
3129 * Page by page.
3130 */
3131 for (;;)
3132 {
3133 /* map the page */
3134 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhysSrc, &pvSrc, &Lock);
3135 if (RT_FAILURE(rc))
3136 return rc;
3137
3138 /* last page? */
3139 if (cb <= GUEST_PAGE_SIZE)
3140 {
3141 memcpy(pvDst, pvSrc, cb);
3142 PGMPhysReleasePageMappingLock(pVM, &Lock);
3143 return VINF_SUCCESS;
3144 }
3145
3146 /* copy the entire page and advance */
3147 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3148 PGMPhysReleasePageMappingLock(pVM, &Lock);
3149 GCPhysSrc += GUEST_PAGE_SIZE;
3150 pvDst = (uint8_t *)pvDst + GUEST_PAGE_SIZE;
3151 cb -= GUEST_PAGE_SIZE;
3152 }
3153 /* won't ever get here. */
3154}
3155
3156
3157/**
3158 * Write to guest physical memory referenced by GC pointer.
3159 * Write memory to GC physical address in guest physical memory.
3160 *
3161 * This will bypass MMIO and access handlers.
3162 *
3163 * @returns VBox status code.
3164 * @param pVM The cross context VM structure.
3165 * @param GCPhysDst The GC physical address of the destination.
3166 * @param pvSrc The source buffer.
3167 * @param cb The number of bytes to write.
3168 */
3169VMMDECL(int) PGMPhysSimpleWriteGCPhys(PVMCC pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb)
3170{
3171 LogFlow(("PGMPhysSimpleWriteGCPhys: %RGp %zu\n", GCPhysDst, cb));
3172
3173 /*
3174 * Treat the first page as a special case.
3175 */
3176 if (!cb)
3177 return VINF_SUCCESS;
3178
3179 /* map the 1st page */
3180 void *pvDst;
3181 PGMPAGEMAPLOCK Lock;
3182 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysDst, &pvDst, &Lock);
3183 if (RT_FAILURE(rc))
3184 return rc;
3185
3186 /* optimize for the case where access is completely within the first page. */
3187 size_t cbPage = GUEST_PAGE_SIZE - (GCPhysDst & GUEST_PAGE_OFFSET_MASK);
3188 if (RT_LIKELY(cb <= cbPage))
3189 {
3190 memcpy(pvDst, pvSrc, cb);
3191 PGMPhysReleasePageMappingLock(pVM, &Lock);
3192 return VINF_SUCCESS;
3193 }
3194
3195 /* copy to the end of the page. */
3196 memcpy(pvDst, pvSrc, cbPage);
3197 PGMPhysReleasePageMappingLock(pVM, &Lock);
3198 GCPhysDst += cbPage;
3199 pvSrc = (const uint8_t *)pvSrc + cbPage;
3200 cb -= cbPage;
3201
3202 /*
3203 * Page by page.
3204 */
3205 for (;;)
3206 {
3207 /* map the page */
3208 rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysDst, &pvDst, &Lock);
3209 if (RT_FAILURE(rc))
3210 return rc;
3211
3212 /* last page? */
3213 if (cb <= GUEST_PAGE_SIZE)
3214 {
3215 memcpy(pvDst, pvSrc, cb);
3216 PGMPhysReleasePageMappingLock(pVM, &Lock);
3217 return VINF_SUCCESS;
3218 }
3219
3220 /* copy the entire page and advance */
3221 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3222 PGMPhysReleasePageMappingLock(pVM, &Lock);
3223 GCPhysDst += GUEST_PAGE_SIZE;
3224 pvSrc = (const uint8_t *)pvSrc + GUEST_PAGE_SIZE;
3225 cb -= GUEST_PAGE_SIZE;
3226 }
3227 /* won't ever get here. */
3228}
3229
3230
3231/**
3232 * Read from guest physical memory referenced by GC pointer.
3233 *
3234 * This function uses the current CR3/CR0/CR4 of the guest and will
3235 * bypass access handlers and not set any accessed bits.
3236 *
3237 * @returns VBox status code.
3238 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3239 * @param pvDst The destination address.
3240 * @param GCPtrSrc The source address (GC pointer).
3241 * @param cb The number of bytes to read.
3242 */
3243VMMDECL(int) PGMPhysSimpleReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb)
3244{
3245 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3246/** @todo fix the macro / state handling: VMCPU_ASSERT_EMT_OR_GURU(pVCpu); */
3247
3248 /*
3249 * Treat the first page as a special case.
3250 */
3251 if (!cb)
3252 return VINF_SUCCESS;
3253
3254 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysSimpleRead));
3255 STAM_COUNTER_ADD(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysSimpleReadBytes), cb);
3256
3257 /* Take the PGM lock here, because many called functions take the lock for a very short period. That's counter-productive
3258 * when many VCPUs are fighting for the lock.
3259 */
3260 PGM_LOCK_VOID(pVM);
3261
3262 /* map the 1st page */
3263 void const *pvSrc;
3264 PGMPAGEMAPLOCK Lock;
3265 int rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, GCPtrSrc, &pvSrc, &Lock);
3266 if (RT_FAILURE(rc))
3267 {
3268 PGM_UNLOCK(pVM);
3269 return rc;
3270 }
3271
3272 /* optimize for the case where access is completely within the first page. */
3273 size_t cbPage = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
3274 if (RT_LIKELY(cb <= cbPage))
3275 {
3276 memcpy(pvDst, pvSrc, cb);
3277 PGMPhysReleasePageMappingLock(pVM, &Lock);
3278 PGM_UNLOCK(pVM);
3279 return VINF_SUCCESS;
3280 }
3281
3282 /* copy to the end of the page. */
3283 memcpy(pvDst, pvSrc, cbPage);
3284 PGMPhysReleasePageMappingLock(pVM, &Lock);
3285 GCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCPtrSrc + cbPage);
3286 pvDst = (uint8_t *)pvDst + cbPage;
3287 cb -= cbPage;
3288
3289 /*
3290 * Page by page.
3291 */
3292 for (;;)
3293 {
3294 /* map the page */
3295 rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, GCPtrSrc, &pvSrc, &Lock);
3296 if (RT_FAILURE(rc))
3297 {
3298 PGM_UNLOCK(pVM);
3299 return rc;
3300 }
3301
3302 /* last page? */
3303 if (cb <= GUEST_PAGE_SIZE)
3304 {
3305 memcpy(pvDst, pvSrc, cb);
3306 PGMPhysReleasePageMappingLock(pVM, &Lock);
3307 PGM_UNLOCK(pVM);
3308 return VINF_SUCCESS;
3309 }
3310
3311 /* copy the entire page and advance */
3312 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3313 PGMPhysReleasePageMappingLock(pVM, &Lock);
3314 GCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCPtrSrc + GUEST_PAGE_SIZE);
3315 pvDst = (uint8_t *)pvDst + GUEST_PAGE_SIZE;
3316 cb -= GUEST_PAGE_SIZE;
3317 }
3318 /* won't ever get here. */
3319}
3320
3321
3322/**
3323 * Write to guest physical memory referenced by GC pointer.
3324 *
3325 * This function uses the current CR3/CR0/CR4 of the guest and will
3326 * bypass access handlers and not set dirty or accessed bits.
3327 *
3328 * @returns VBox status code.
3329 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3330 * @param GCPtrDst The destination address (GC pointer).
3331 * @param pvSrc The source address.
3332 * @param cb The number of bytes to write.
3333 */
3334VMMDECL(int) PGMPhysSimpleWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
3335{
3336 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3337 VMCPU_ASSERT_EMT(pVCpu);
3338
3339 /*
3340 * Treat the first page as a special case.
3341 */
3342 if (!cb)
3343 return VINF_SUCCESS;
3344
3345 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysSimpleWrite));
3346 STAM_COUNTER_ADD(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysSimpleWriteBytes), cb);
3347
3348 /* map the 1st page */
3349 void *pvDst;
3350 PGMPAGEMAPLOCK Lock;
3351 int rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);
3352 if (RT_FAILURE(rc))
3353 return rc;
3354
3355 /* optimize for the case where access is completely within the first page. */
3356 size_t cbPage = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3357 if (RT_LIKELY(cb <= cbPage))
3358 {
3359 memcpy(pvDst, pvSrc, cb);
3360 PGMPhysReleasePageMappingLock(pVM, &Lock);
3361 return VINF_SUCCESS;
3362 }
3363
3364 /* copy to the end of the page. */
3365 memcpy(pvDst, pvSrc, cbPage);
3366 PGMPhysReleasePageMappingLock(pVM, &Lock);
3367 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbPage);
3368 pvSrc = (const uint8_t *)pvSrc + cbPage;
3369 cb -= cbPage;
3370
3371 /*
3372 * Page by page.
3373 */
3374 for (;;)
3375 {
3376 /* map the page */
3377 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);
3378 if (RT_FAILURE(rc))
3379 return rc;
3380
3381 /* last page? */
3382 if (cb <= GUEST_PAGE_SIZE)
3383 {
3384 memcpy(pvDst, pvSrc, cb);
3385 PGMPhysReleasePageMappingLock(pVM, &Lock);
3386 return VINF_SUCCESS;
3387 }
3388
3389 /* copy the entire page and advance */
3390 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3391 PGMPhysReleasePageMappingLock(pVM, &Lock);
3392 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + GUEST_PAGE_SIZE);
3393 pvSrc = (const uint8_t *)pvSrc + GUEST_PAGE_SIZE;
3394 cb -= GUEST_PAGE_SIZE;
3395 }
3396 /* won't ever get here. */
3397}
3398
3399
3400/**
3401 * Write to guest physical memory referenced by GC pointer and update the PTE.
3402 *
3403 * This function uses the current CR3/CR0/CR4 of the guest and will
3404 * bypass access handlers but will set any dirty and accessed bits in the PTE.
3405 *
3406 * If you don't want to set the dirty bit, use PGMPhysSimpleWriteGCPtr().
3407 *
3408 * @returns VBox status code.
3409 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3410 * @param GCPtrDst The destination address (GC pointer).
3411 * @param pvSrc The source address.
3412 * @param cb The number of bytes to write.
3413 */
3414VMMDECL(int) PGMPhysSimpleDirtyWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
3415{
3416 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3417 VMCPU_ASSERT_EMT(pVCpu);
3418
3419 /*
3420 * Treat the first page as a special case.
3421 * Btw. this is the same code as in PGMPhyssimpleWriteGCPtr excep for the PGMGstModifyPage.
3422 */
3423 if (!cb)
3424 return VINF_SUCCESS;
3425
3426 /* map the 1st page */
3427 void *pvDst;
3428 PGMPAGEMAPLOCK Lock;
3429 int rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);
3430 if (RT_FAILURE(rc))
3431 return rc;
3432
3433 /* optimize for the case where access is completely within the first page. */
3434 size_t cbPage = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3435 if (RT_LIKELY(cb <= cbPage))
3436 {
3437 memcpy(pvDst, pvSrc, cb);
3438 PGMPhysReleasePageMappingLock(pVM, &Lock);
3439 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
3440 return VINF_SUCCESS;
3441 }
3442
3443 /* copy to the end of the page. */
3444 memcpy(pvDst, pvSrc, cbPage);
3445 PGMPhysReleasePageMappingLock(pVM, &Lock);
3446 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
3447 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbPage);
3448 pvSrc = (const uint8_t *)pvSrc + cbPage;
3449 cb -= cbPage;
3450
3451 /*
3452 * Page by page.
3453 */
3454 for (;;)
3455 {
3456 /* map the page */
3457 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);
3458 if (RT_FAILURE(rc))
3459 return rc;
3460
3461 /* last page? */
3462 if (cb <= GUEST_PAGE_SIZE)
3463 {
3464 memcpy(pvDst, pvSrc, cb);
3465 PGMPhysReleasePageMappingLock(pVM, &Lock);
3466 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
3467 return VINF_SUCCESS;
3468 }
3469
3470 /* copy the entire page and advance */
3471 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3472 PGMPhysReleasePageMappingLock(pVM, &Lock);
3473 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
3474 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + GUEST_PAGE_SIZE);
3475 pvSrc = (const uint8_t *)pvSrc + GUEST_PAGE_SIZE;
3476 cb -= GUEST_PAGE_SIZE;
3477 }
3478 /* won't ever get here. */
3479}
3480
3481
3482/**
3483 * Read from guest physical memory referenced by GC pointer.
3484 *
3485 * This function uses the current CR3/CR0/CR4 of the guest and will
3486 * respect access handlers and set accessed bits.
3487 *
3488 * @returns Strict VBox status, see PGMPhysRead for details.
3489 * @retval VERR_PAGE_TABLE_NOT_PRESENT if there is no page mapped at the
3490 * specified virtual address.
3491 *
3492 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3493 * @param pvDst The destination address.
3494 * @param GCPtrSrc The source address (GC pointer).
3495 * @param cb The number of bytes to read.
3496 * @param enmOrigin Who is calling.
3497 * @thread EMT(pVCpu)
3498 */
3499VMMDECL(VBOXSTRICTRC) PGMPhysReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, PGMACCESSORIGIN enmOrigin)
3500{
3501 int rc;
3502 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3503 VMCPU_ASSERT_EMT(pVCpu);
3504
3505 /*
3506 * Anything to do?
3507 */
3508 if (!cb)
3509 return VINF_SUCCESS;
3510
3511 LogFlow(("PGMPhysReadGCPtr: %RGv %zu\n", GCPtrSrc, cb));
3512
3513 /*
3514 * Optimize reads within a single page.
3515 */
3516 if (((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK) + cb <= GUEST_PAGE_SIZE)
3517 {
3518 /* Convert virtual to physical address + flags */
3519 PGMPTWALK Walk;
3520 rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtrSrc, &Walk);
3521 AssertMsgRCReturn(rc, ("GetPage failed with %Rrc for %RGv\n", rc, GCPtrSrc), rc);
3522 RTGCPHYS const GCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
3523
3524 /* mark the guest page as accessed. */
3525 if (!(Walk.fEffective & X86_PTE_A))
3526 {
3527 rc = PGMGstModifyPage(pVCpu, GCPtrSrc, 1, X86_PTE_A, ~(uint64_t)(X86_PTE_A));
3528 AssertRC(rc);
3529 }
3530
3531 return PGMPhysRead(pVM, GCPhys, pvDst, cb, enmOrigin);
3532 }
3533
3534 /*
3535 * Page by page.
3536 */
3537 for (;;)
3538 {
3539 /* Convert virtual to physical address + flags */
3540 PGMPTWALK Walk;
3541 rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtrSrc, &Walk);
3542 AssertMsgRCReturn(rc, ("GetPage failed with %Rrc for %RGv\n", rc, GCPtrSrc), rc);
3543 RTGCPHYS const GCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
3544
3545 /* mark the guest page as accessed. */
3546 if (!(Walk.fEffective & X86_PTE_A))
3547 {
3548 rc = PGMGstModifyPage(pVCpu, GCPtrSrc, 1, X86_PTE_A, ~(uint64_t)(X86_PTE_A));
3549 AssertRC(rc);
3550 }
3551
3552 /* copy */
3553 size_t cbRead = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
3554 if (cbRead < cb)
3555 {
3556 VBOXSTRICTRC rcStrict = PGMPhysRead(pVM, GCPhys, pvDst, cbRead, enmOrigin);
3557 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
3558 { /* likely */ }
3559 else
3560 return rcStrict;
3561 }
3562 else /* Last page (cbRead is GUEST_PAGE_SIZE, we only need cb!) */
3563 return PGMPhysRead(pVM, GCPhys, pvDst, cb, enmOrigin);
3564
3565 /* next */
3566 Assert(cb > cbRead);
3567 cb -= cbRead;
3568 pvDst = (uint8_t *)pvDst + cbRead;
3569 GCPtrSrc += cbRead;
3570 }
3571}
3572
3573
3574/**
3575 * Write to guest physical memory referenced by GC pointer.
3576 *
3577 * This function uses the current CR3/CR0/CR4 of the guest and will
3578 * respect access handlers and set dirty and accessed bits.
3579 *
3580 * @returns Strict VBox status, see PGMPhysWrite for details.
3581 * @retval VERR_PAGE_TABLE_NOT_PRESENT if there is no page mapped at the
3582 * specified virtual address.
3583 *
3584 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3585 * @param GCPtrDst The destination address (GC pointer).
3586 * @param pvSrc The source address.
3587 * @param cb The number of bytes to write.
3588 * @param enmOrigin Who is calling.
3589 */
3590VMMDECL(VBOXSTRICTRC) PGMPhysWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb, PGMACCESSORIGIN enmOrigin)
3591{
3592 int rc;
3593 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3594 VMCPU_ASSERT_EMT(pVCpu);
3595
3596 /*
3597 * Anything to do?
3598 */
3599 if (!cb)
3600 return VINF_SUCCESS;
3601
3602 LogFlow(("PGMPhysWriteGCPtr: %RGv %zu\n", GCPtrDst, cb));
3603
3604 /*
3605 * Optimize writes within a single page.
3606 */
3607 if (((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK) + cb <= GUEST_PAGE_SIZE)
3608 {
3609 /* Convert virtual to physical address + flags */
3610 PGMPTWALK Walk;
3611 rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtrDst, &Walk);
3612 AssertMsgRCReturn(rc, ("GetPage failed with %Rrc for %RGv\n", rc, GCPtrDst), rc);
3613 RTGCPHYS const GCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3614
3615 /* Mention when we ignore X86_PTE_RW... */
3616 if (!(Walk.fEffective & X86_PTE_RW))
3617 Log(("PGMPhysWriteGCPtr: Writing to RO page %RGv %#x\n", GCPtrDst, cb));
3618
3619 /* Mark the guest page as accessed and dirty if necessary. */
3620 if ((Walk.fEffective & (X86_PTE_A | X86_PTE_D)) != (X86_PTE_A | X86_PTE_D))
3621 {
3622 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
3623 AssertRC(rc);
3624 }
3625
3626 return PGMPhysWrite(pVM, GCPhys, pvSrc, cb, enmOrigin);
3627 }
3628
3629 /*
3630 * Page by page.
3631 */
3632 for (;;)
3633 {
3634 /* Convert virtual to physical address + flags */
3635 PGMPTWALK Walk;
3636 rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtrDst, &Walk);
3637 AssertMsgRCReturn(rc, ("GetPage failed with %Rrc for %RGv\n", rc, GCPtrDst), rc);
3638 RTGCPHYS const GCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3639
3640 /* Mention when we ignore X86_PTE_RW... */
3641 if (!(Walk.fEffective & X86_PTE_RW))
3642 Log(("PGMPhysWriteGCPtr: Writing to RO page %RGv %#x\n", GCPtrDst, cb));
3643
3644 /* Mark the guest page as accessed and dirty if necessary. */
3645 if ((Walk.fEffective & (X86_PTE_A | X86_PTE_D)) != (X86_PTE_A | X86_PTE_D))
3646 {
3647 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
3648 AssertRC(rc);
3649 }
3650
3651 /* copy */
3652 size_t cbWrite = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3653 if (cbWrite < cb)
3654 {
3655 VBOXSTRICTRC rcStrict = PGMPhysWrite(pVM, GCPhys, pvSrc, cbWrite, enmOrigin);
3656 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
3657 { /* likely */ }
3658 else
3659 return rcStrict;
3660 }
3661 else /* Last page (cbWrite is GUEST_PAGE_SIZE, we only need cb!) */
3662 return PGMPhysWrite(pVM, GCPhys, pvSrc, cb, enmOrigin);
3663
3664 /* next */
3665 Assert(cb > cbWrite);
3666 cb -= cbWrite;
3667 pvSrc = (uint8_t *)pvSrc + cbWrite;
3668 GCPtrDst += cbWrite;
3669 }
3670}
3671
3672
3673/**
3674 * Return the page type of the specified physical address.
3675 *
3676 * @returns The page type.
3677 * @param pVM The cross context VM structure.
3678 * @param GCPhys Guest physical address
3679 */
3680VMM_INT_DECL(PGMPAGETYPE) PGMPhysGetPageType(PVMCC pVM, RTGCPHYS GCPhys)
3681{
3682 PGM_LOCK_VOID(pVM);
3683 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
3684 PGMPAGETYPE enmPgType = pPage ? (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage) : PGMPAGETYPE_INVALID;
3685 PGM_UNLOCK(pVM);
3686
3687 return enmPgType;
3688}
3689
3690
3691/**
3692 * Converts a GC physical address to a HC ring-3 pointer, with some
3693 * additional checks.
3694 *
3695 * @returns VBox status code (no informational statuses).
3696 *
3697 * @param pVM The cross context VM structure.
3698 * @param pVCpu The cross context virtual CPU structure of the
3699 * calling EMT.
3700 * @param GCPhys The GC physical address to convert. This API mask
3701 * the A20 line when necessary.
3702 * @param puTlbPhysRev Where to read the physical TLB revision. Needs to
3703 * be done while holding the PGM lock.
3704 * @param ppb Where to store the pointer corresponding to GCPhys
3705 * on success.
3706 * @param pfTlb The TLB flags and revision. We only add stuff.
3707 *
3708 * @remarks This is more or a less a copy of PGMR3PhysTlbGCPhys2Ptr and
3709 * PGMPhysIemGCPhys2Ptr.
3710 *
3711 * @thread EMT(pVCpu).
3712 */
3713VMM_INT_DECL(int) PGMPhysIemGCPhys2PtrNoLock(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, uint64_t const volatile *puTlbPhysRev,
3714 R3R0PTRTYPE(uint8_t *) *ppb,
3715 uint64_t *pfTlb)
3716{
3717 PGM_A20_APPLY_TO_VAR(pVCpu, GCPhys);
3718 Assert(!(GCPhys & X86_PAGE_OFFSET_MASK));
3719
3720 PGM_LOCK_VOID(pVM);
3721
3722 PPGMRAMRANGE pRam;
3723 PPGMPAGE pPage;
3724 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
3725 if (RT_SUCCESS(rc))
3726 {
3727 if (!PGM_PAGE_IS_BALLOONED(pPage))
3728 {
3729 if (!PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
3730 {
3731 if (!PGM_PAGE_HAS_ANY_HANDLERS(pPage))
3732 {
3733 /*
3734 * No access handler.
3735 */
3736 switch (PGM_PAGE_GET_STATE(pPage))
3737 {
3738 case PGM_PAGE_STATE_ALLOCATED:
3739 *pfTlb |= *puTlbPhysRev;
3740 break;
3741 case PGM_PAGE_STATE_BALLOONED:
3742 AssertFailed();
3743 RT_FALL_THRU();
3744 case PGM_PAGE_STATE_ZERO:
3745 case PGM_PAGE_STATE_SHARED:
3746 case PGM_PAGE_STATE_WRITE_MONITORED:
3747 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE;
3748 break;
3749 }
3750
3751 PPGMPAGEMAPTLBE pTlbe;
3752 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
3753 AssertLogRelRCReturn(rc, rc);
3754 *ppb = (uint8_t *)pTlbe->pv;
3755 }
3756 else if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
3757 {
3758 /*
3759 * MMIO or similar all access handler: Catch all access.
3760 */
3761 *pfTlb |= *puTlbPhysRev
3762 | PGMIEMGCPHYS2PTR_F_NO_WRITE | PGMIEMGCPHYS2PTR_F_NO_READ | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3;
3763 *ppb = NULL;
3764 }
3765 else
3766 {
3767 /*
3768 * Write access handler: Catch write accesses if active.
3769 */
3770 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
3771 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE;
3772 else
3773 switch (PGM_PAGE_GET_STATE(pPage))
3774 {
3775 case PGM_PAGE_STATE_ALLOCATED:
3776 *pfTlb |= *puTlbPhysRev;
3777 break;
3778 case PGM_PAGE_STATE_BALLOONED:
3779 AssertFailed();
3780 RT_FALL_THRU();
3781 case PGM_PAGE_STATE_ZERO:
3782 case PGM_PAGE_STATE_SHARED:
3783 case PGM_PAGE_STATE_WRITE_MONITORED:
3784 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE;
3785 break;
3786 }
3787
3788 PPGMPAGEMAPTLBE pTlbe;
3789 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
3790 AssertLogRelRCReturn(rc, rc);
3791 *ppb = (uint8_t *)pTlbe->pv;
3792 }
3793 }
3794 else
3795 {
3796 /* Alias MMIO: For now, we catch all access. */
3797 *pfTlb |= *puTlbPhysRev
3798 | PGMIEMGCPHYS2PTR_F_NO_WRITE | PGMIEMGCPHYS2PTR_F_NO_READ | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3;
3799 *ppb = NULL;
3800 }
3801 }
3802 else
3803 {
3804 /* Ballooned: Shouldn't get here, but we read zero page via PGMPhysRead and writes goes to /dev/null. */
3805 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE | PGMIEMGCPHYS2PTR_F_NO_READ | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3;
3806 *ppb = NULL;
3807 }
3808 Log6(("PGMPhysIemGCPhys2PtrNoLock: GCPhys=%RGp *ppb=%p *pfTlb=%#RX64 pPage=%R[pgmpage]\n", GCPhys, *ppb, *pfTlb, pPage));
3809 }
3810 else
3811 {
3812 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE | PGMIEMGCPHYS2PTR_F_NO_READ
3813 | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 | PGMIEMGCPHYS2PTR_F_UNASSIGNED;
3814 *ppb = NULL;
3815 Log6(("PGMPhysIemGCPhys2PtrNoLock: GCPhys=%RGp *ppb=%p *pfTlb=%#RX64 (rc=%Rrc)\n", GCPhys, *ppb, *pfTlb, rc));
3816 }
3817
3818 PGM_UNLOCK(pVM);
3819 return VINF_SUCCESS;
3820}
3821
3822
3823/**
3824 * Converts a GC physical address to a HC ring-3 pointer, with some
3825 * additional checks.
3826 *
3827 * @returns VBox status code (no informational statuses).
3828 * @retval VINF_SUCCESS on success.
3829 * @retval VERR_PGM_PHYS_TLB_CATCH_WRITE and *ppv set if the page has a write
3830 * access handler of some kind.
3831 * @retval VERR_PGM_PHYS_TLB_CATCH_ALL if the page has a handler catching all
3832 * accesses or is odd in any way.
3833 * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist.
3834 *
3835 * @param pVM The cross context VM structure.
3836 * @param pVCpu The cross context virtual CPU structure of the
3837 * calling EMT.
3838 * @param GCPhys The GC physical address to convert. This API mask
3839 * the A20 line when necessary.
3840 * @param fWritable Whether write access is required.
3841 * @param fByPassHandlers Whether to bypass access handlers.
3842 * @param ppv Where to store the pointer corresponding to GCPhys
3843 * on success.
3844 * @param pLock
3845 *
3846 * @remarks This is more or a less a copy of PGMR3PhysTlbGCPhys2Ptr.
3847 * @thread EMT(pVCpu).
3848 */
3849VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers,
3850 void **ppv, PPGMPAGEMAPLOCK pLock)
3851{
3852 PGM_A20_APPLY_TO_VAR(pVCpu, GCPhys);
3853
3854 PGM_LOCK_VOID(pVM);
3855
3856 PPGMRAMRANGE pRam;
3857 PPGMPAGE pPage;
3858 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
3859 if (RT_SUCCESS(rc))
3860 {
3861 if (PGM_PAGE_IS_BALLOONED(pPage))
3862 rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
3863 else if (PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
3864 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3865 else if ( !PGM_PAGE_HAS_ANY_HANDLERS(pPage)
3866 || (fByPassHandlers && !PGM_PAGE_IS_MMIO(pPage)) )
3867 rc = VINF_SUCCESS;
3868 else
3869 {
3870 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)) /* catches MMIO */
3871 {
3872 Assert(!fByPassHandlers || PGM_PAGE_IS_MMIO(pPage));
3873 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3874 }
3875 else if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage) && fWritable)
3876 {
3877 Assert(!fByPassHandlers);
3878 rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
3879 }
3880 }
3881 if (RT_SUCCESS(rc))
3882 {
3883 int rc2;
3884
3885 /* Make sure what we return is writable. */
3886 if (fWritable)
3887 switch (PGM_PAGE_GET_STATE(pPage))
3888 {
3889 case PGM_PAGE_STATE_ALLOCATED:
3890 break;
3891 case PGM_PAGE_STATE_BALLOONED:
3892 AssertFailed();
3893 break;
3894 case PGM_PAGE_STATE_ZERO:
3895 case PGM_PAGE_STATE_SHARED:
3896 case PGM_PAGE_STATE_WRITE_MONITORED:
3897 rc2 = pgmPhysPageMakeWritable(pVM, pPage, GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK);
3898 AssertLogRelRCReturn(rc2, rc2);
3899 break;
3900 }
3901
3902 /* Get a ring-3 mapping of the address. */
3903 PPGMPAGEMAPTLBE pTlbe;
3904 rc2 = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
3905 AssertLogRelRCReturn(rc2, rc2);
3906
3907 /* Lock it and calculate the address. */
3908 if (fWritable)
3909 pgmPhysPageMapLockForWriting(pVM, pPage, pTlbe, pLock);
3910 else
3911 pgmPhysPageMapLockForReading(pVM, pPage, pTlbe, pLock);
3912 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
3913
3914 Log6(("PGMPhysIemGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage] *ppv=%p\n", GCPhys, rc, pPage, *ppv));
3915 }
3916 else
3917 Log6(("PGMPhysIemGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage]\n", GCPhys, rc, pPage));
3918
3919 /* else: handler catching all access, no pointer returned. */
3920 }
3921 else
3922 rc = VERR_PGM_PHYS_TLB_UNASSIGNED;
3923
3924 PGM_UNLOCK(pVM);
3925 return rc;
3926}
3927
3928
3929/**
3930 * Checks if the give GCPhys page requires special handling for the given access
3931 * because it's MMIO or otherwise monitored.
3932 *
3933 * @returns VBox status code (no informational statuses).
3934 * @retval VINF_SUCCESS on success.
3935 * @retval VERR_PGM_PHYS_TLB_CATCH_WRITE and *ppv set if the page has a write
3936 * access handler of some kind.
3937 * @retval VERR_PGM_PHYS_TLB_CATCH_ALL if the page has a handler catching all
3938 * accesses or is odd in any way.
3939 * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist.
3940 *
3941 * @param pVM The cross context VM structure.
3942 * @param GCPhys The GC physical address to convert. Since this is
3943 * only used for filling the REM TLB, the A20 mask must
3944 * be applied before calling this API.
3945 * @param fWritable Whether write access is required.
3946 * @param fByPassHandlers Whether to bypass access handlers.
3947 *
3948 * @remarks This is a watered down version PGMPhysIemGCPhys2Ptr and really just
3949 * a stop gap thing that should be removed once there is a better TLB
3950 * for virtual address accesses.
3951 */
3952VMM_INT_DECL(int) PGMPhysIemQueryAccess(PVMCC pVM, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers)
3953{
3954 PGM_LOCK_VOID(pVM);
3955 PGM_A20_ASSERT_MASKED(VMMGetCpu(pVM), GCPhys);
3956
3957 PPGMRAMRANGE pRam;
3958 PPGMPAGE pPage;
3959 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
3960 if (RT_SUCCESS(rc))
3961 {
3962 if (PGM_PAGE_IS_BALLOONED(pPage))
3963 rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
3964 else if (PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
3965 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3966 else if ( !PGM_PAGE_HAS_ANY_HANDLERS(pPage)
3967 || (fByPassHandlers && !PGM_PAGE_IS_MMIO(pPage)) )
3968 rc = VINF_SUCCESS;
3969 else
3970 {
3971 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)) /* catches MMIO */
3972 {
3973 Assert(!fByPassHandlers || PGM_PAGE_IS_MMIO(pPage));
3974 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3975 }
3976 else if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage) && fWritable)
3977 {
3978 Assert(!fByPassHandlers);
3979 rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
3980 }
3981 }
3982 }
3983
3984 PGM_UNLOCK(pVM);
3985 return rc;
3986}
3987
3988#ifdef VBOX_WITH_NATIVE_NEM
3989
3990/**
3991 * Interface used by NEM to check what to do on a memory access exit.
3992 *
3993 * @returns VBox status code.
3994 * @param pVM The cross context VM structure.
3995 * @param pVCpu The cross context per virtual CPU structure.
3996 * Optional.
3997 * @param GCPhys The guest physical address.
3998 * @param fMakeWritable Whether to try make the page writable or not. If it
3999 * cannot be made writable, NEM_PAGE_PROT_WRITE won't
4000 * be returned and the return code will be unaffected
4001 * @param pInfo Where to return the page information. This is
4002 * initialized even on failure.
4003 * @param pfnChecker Page in-sync checker callback. Optional.
4004 * @param pvUser User argument to pass to pfnChecker.
4005 */
4006VMM_INT_DECL(int) PGMPhysNemPageInfoChecker(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fMakeWritable, PPGMPHYSNEMPAGEINFO pInfo,
4007 PFNPGMPHYSNEMCHECKPAGE pfnChecker, void *pvUser)
4008{
4009 PGM_LOCK_VOID(pVM);
4010
4011 PPGMPAGE pPage;
4012 int rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage);
4013 if (RT_SUCCESS(rc))
4014 {
4015 /* Try make it writable if requested. */
4016 pInfo->u2OldNemState = PGM_PAGE_GET_NEM_STATE(pPage);
4017 if (fMakeWritable)
4018 switch (PGM_PAGE_GET_STATE(pPage))
4019 {
4020 case PGM_PAGE_STATE_SHARED:
4021 case PGM_PAGE_STATE_WRITE_MONITORED:
4022 case PGM_PAGE_STATE_ZERO:
4023 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
4024 if (rc == VERR_PGM_PHYS_PAGE_RESERVED)
4025 rc = VINF_SUCCESS;
4026 break;
4027 }
4028
4029 /* Fill in the info. */
4030 pInfo->HCPhys = PGM_PAGE_GET_HCPHYS(pPage);
4031 pInfo->u2NemState = PGM_PAGE_GET_NEM_STATE(pPage);
4032 pInfo->fHasHandlers = PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage) ? 1 : 0;
4033 PGMPAGETYPE const enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
4034 pInfo->enmType = enmType;
4035 pInfo->fNemProt = pgmPhysPageCalcNemProtection(pPage, enmType);
4036 switch (PGM_PAGE_GET_STATE(pPage))
4037 {
4038 case PGM_PAGE_STATE_ALLOCATED:
4039 pInfo->fZeroPage = 0;
4040 break;
4041
4042 case PGM_PAGE_STATE_ZERO:
4043 pInfo->fZeroPage = 1;
4044 break;
4045
4046 case PGM_PAGE_STATE_WRITE_MONITORED:
4047 pInfo->fZeroPage = 0;
4048 break;
4049
4050 case PGM_PAGE_STATE_SHARED:
4051 pInfo->fZeroPage = 0;
4052 break;
4053
4054 case PGM_PAGE_STATE_BALLOONED:
4055 pInfo->fZeroPage = 1;
4056 break;
4057
4058 default:
4059 pInfo->fZeroPage = 1;
4060 AssertFailedStmt(rc = VERR_PGM_PHYS_PAGE_GET_IPE);
4061 }
4062
4063 /* Call the checker and update NEM state. */
4064 if (pfnChecker)
4065 {
4066 rc = pfnChecker(pVM, pVCpu, GCPhys, pInfo, pvUser);
4067 PGM_PAGE_SET_NEM_STATE(pPage, pInfo->u2NemState);
4068 }
4069
4070 /* Done. */
4071 PGM_UNLOCK(pVM);
4072 }
4073 else
4074 {
4075 PGM_UNLOCK(pVM);
4076
4077 pInfo->HCPhys = NIL_RTHCPHYS;
4078 pInfo->fNemProt = NEM_PAGE_PROT_NONE;
4079 pInfo->u2NemState = 0;
4080 pInfo->fHasHandlers = 0;
4081 pInfo->fZeroPage = 0;
4082 pInfo->enmType = PGMPAGETYPE_INVALID;
4083 }
4084
4085 return rc;
4086}
4087
4088
4089/**
4090 * NEM helper that performs @a pfnCallback on pages with NEM state @a uMinState
4091 * or higher.
4092 *
4093 * @returns VBox status code from callback.
4094 * @param pVM The cross context VM structure.
4095 * @param pVCpu The cross context per CPU structure. This is
4096 * optional as its only for passing to callback.
4097 * @param uMinState The minimum NEM state value to call on.
4098 * @param pfnCallback The callback function.
4099 * @param pvUser User argument for the callback.
4100 */
4101VMM_INT_DECL(int) PGMPhysNemEnumPagesByState(PVMCC pVM, PVMCPUCC pVCpu, uint8_t uMinState,
4102 PFNPGMPHYSNEMENUMCALLBACK pfnCallback, void *pvUser)
4103{
4104 /*
4105 * Just brute force this problem.
4106 */
4107 PGM_LOCK_VOID(pVM);
4108 int rc = VINF_SUCCESS;
4109 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX); pRam; pRam = pRam->CTX_SUFF(pNext))
4110 {
4111 uint32_t const cPages = pRam->cb >> X86_PAGE_SHIFT;
4112 for (uint32_t iPage = 0; iPage < cPages; iPage++)
4113 {
4114 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(&pRam->aPages[iPage]);
4115 if (u2State < uMinState)
4116 { /* likely */ }
4117 else
4118 {
4119 rc = pfnCallback(pVM, pVCpu, pRam->GCPhys + ((RTGCPHYS)iPage << X86_PAGE_SHIFT), &u2State, pvUser);
4120 if (RT_SUCCESS(rc))
4121 PGM_PAGE_SET_NEM_STATE(&pRam->aPages[iPage], u2State);
4122 else
4123 break;
4124 }
4125 }
4126 }
4127 PGM_UNLOCK(pVM);
4128
4129 return rc;
4130}
4131
4132
4133/**
4134 * Helper for setting the NEM state for a range of pages.
4135 *
4136 * @param paPages Array of pages to modify.
4137 * @param cPages How many pages to modify.
4138 * @param u2State The new state value.
4139 */
4140void pgmPhysSetNemStateForPages(PPGMPAGE paPages, RTGCPHYS cPages, uint8_t u2State)
4141{
4142 PPGMPAGE pPage = paPages;
4143 while (cPages-- > 0)
4144 {
4145 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
4146 pPage++;
4147 }
4148}
4149
4150#endif /* VBOX_WITH_NATIVE_NEM */
4151
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