VirtualBox

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

Last change on this file since 99314 was 99314, checked in by vboxsync, 20 months ago

VMM/PGMPhys: Set the remaining buffer to a known value when returning early due to an error, bugref:10412

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 146.7 KB
Line 
1/* $Id: PGMAllPhys.cpp 99314 2023-04-06 07:41:57Z 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 * @returns VBox strict status code.
1214 *
1215 * @param pVM The cross context VM structure.
1216 * @param pPage The physical page tracking structure.
1217 * @param GCPhys The guest physical address of the page.
1218 * PGMPhysReleasePageMappingLock() passes NIL_RTGCPHYS in a
1219 * very unlikely situation where it is okay that we let NEM
1220 * fix the page access in a lazy fasion.
1221 *
1222 * @remarks Called from within the PGM critical section.
1223 */
1224void pgmPhysPageMakeWriteMonitoredWritable(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
1225{
1226 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED);
1227 PGM_PAGE_SET_WRITTEN_TO(pVM, pPage);
1228 PGM_PAGE_SET_STATE(pVM, pPage, PGM_PAGE_STATE_ALLOCATED);
1229 Assert(pVM->pgm.s.cMonitoredPages > 0);
1230 pVM->pgm.s.cMonitoredPages--;
1231 pVM->pgm.s.cWrittenToPages++;
1232
1233#ifdef VBOX_WITH_NATIVE_NEM
1234 /*
1235 * Notify NEM about the protection change so we won't spin forever.
1236 *
1237 * Note! NEM need to be handle to lazily correct page protection as we cannot
1238 * really get it 100% right here it seems. The page pool does this too.
1239 */
1240 if (VM_IS_NEM_ENABLED(pVM) && GCPhys != NIL_RTGCPHYS)
1241 {
1242 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(pPage);
1243 PGMPAGETYPE enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
1244 PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys);
1245 NEMHCNotifyPhysPageProtChanged(pVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage),
1246 pRam ? PGM_RAMRANGE_CALC_PAGE_R3PTR(pRam, GCPhys) : NULL,
1247 pgmPhysPageCalcNemProtection(pPage, enmType), enmType, &u2State);
1248 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
1249 }
1250#else
1251 RT_NOREF(GCPhys);
1252#endif
1253}
1254
1255
1256/**
1257 * Deal with pages that are not writable, i.e. not in the ALLOCATED state.
1258 *
1259 * @returns VBox strict status code.
1260 * @retval VINF_SUCCESS on success.
1261 * @retval VINF_PGM_SYNC_CR3 on success and a page pool flush is pending.
1262 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1263 *
1264 * @param pVM The cross context VM structure.
1265 * @param pPage The physical page tracking structure.
1266 * @param GCPhys The address of the page.
1267 *
1268 * @remarks Called from within the PGM critical section.
1269 */
1270int pgmPhysPageMakeWritable(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
1271{
1272 PGM_LOCK_ASSERT_OWNER(pVM);
1273 switch (PGM_PAGE_GET_STATE(pPage))
1274 {
1275 case PGM_PAGE_STATE_WRITE_MONITORED:
1276 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, GCPhys);
1277 RT_FALL_THRU();
1278 default: /* to shut up GCC */
1279 case PGM_PAGE_STATE_ALLOCATED:
1280 return VINF_SUCCESS;
1281
1282 /*
1283 * Zero pages can be dummy pages for MMIO or reserved memory,
1284 * so we need to check the flags before joining cause with
1285 * shared page replacement.
1286 */
1287 case PGM_PAGE_STATE_ZERO:
1288 if (PGM_PAGE_IS_MMIO(pPage))
1289 return VERR_PGM_PHYS_PAGE_RESERVED;
1290 RT_FALL_THRU();
1291 case PGM_PAGE_STATE_SHARED:
1292 return pgmPhysAllocPage(pVM, pPage, GCPhys);
1293
1294 /* Not allowed to write to ballooned pages. */
1295 case PGM_PAGE_STATE_BALLOONED:
1296 return VERR_PGM_PHYS_PAGE_BALLOONED;
1297 }
1298}
1299
1300
1301/**
1302 * Internal usage: Map the page specified by its GMM ID.
1303 *
1304 * This is similar to pgmPhysPageMap
1305 *
1306 * @returns VBox status code.
1307 *
1308 * @param pVM The cross context VM structure.
1309 * @param idPage The Page ID.
1310 * @param HCPhys The physical address (for SUPR0HCPhysToVirt).
1311 * @param ppv Where to store the mapping address.
1312 *
1313 * @remarks Called from within the PGM critical section. The mapping is only
1314 * valid while you are inside this section.
1315 */
1316int pgmPhysPageMapByPageID(PVMCC pVM, uint32_t idPage, RTHCPHYS HCPhys, void **ppv)
1317{
1318 /*
1319 * Validation.
1320 */
1321 PGM_LOCK_ASSERT_OWNER(pVM);
1322 AssertReturn(HCPhys && !(HCPhys & GUEST_PAGE_OFFSET_MASK), VERR_INVALID_PARAMETER);
1323 const uint32_t idChunk = idPage >> GMM_CHUNKID_SHIFT;
1324 AssertReturn(idChunk != NIL_GMM_CHUNKID, VERR_INVALID_PARAMETER);
1325
1326#ifdef IN_RING0
1327# ifdef VBOX_WITH_LINEAR_HOST_PHYS_MEM
1328 return SUPR0HCPhysToVirt(HCPhys & ~(RTHCPHYS)GUEST_PAGE_OFFSET_MASK, ppv);
1329# else
1330 return GMMR0PageIdToVirt(pVM, idPage, ppv);
1331# endif
1332
1333#else
1334 /*
1335 * Find/make Chunk TLB entry for the mapping chunk.
1336 */
1337 PPGMCHUNKR3MAP pMap;
1338 PPGMCHUNKR3MAPTLBE pTlbe = &pVM->pgm.s.ChunkR3Map.Tlb.aEntries[PGM_CHUNKR3MAPTLB_IDX(idChunk)];
1339 if (pTlbe->idChunk == idChunk)
1340 {
1341 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,ChunkR3MapTlbHits));
1342 pMap = pTlbe->pChunk;
1343 }
1344 else
1345 {
1346 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,ChunkR3MapTlbMisses));
1347
1348 /*
1349 * Find the chunk, map it if necessary.
1350 */
1351 pMap = (PPGMCHUNKR3MAP)RTAvlU32Get(&pVM->pgm.s.ChunkR3Map.pTree, idChunk);
1352 if (pMap)
1353 pMap->iLastUsed = pVM->pgm.s.ChunkR3Map.iNow;
1354 else
1355 {
1356 int rc = pgmR3PhysChunkMap(pVM, idChunk, &pMap);
1357 if (RT_FAILURE(rc))
1358 return rc;
1359 }
1360
1361 /*
1362 * Enter it into the Chunk TLB.
1363 */
1364 pTlbe->idChunk = idChunk;
1365 pTlbe->pChunk = pMap;
1366 }
1367
1368 *ppv = (uint8_t *)pMap->pv + ((idPage & GMM_PAGEID_IDX_MASK) << GUEST_PAGE_SHIFT);
1369 return VINF_SUCCESS;
1370#endif
1371}
1372
1373
1374/**
1375 * Maps a page into the current virtual address space so it can be accessed.
1376 *
1377 * @returns VBox status code.
1378 * @retval VINF_SUCCESS on success.
1379 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1380 *
1381 * @param pVM The cross context VM structure.
1382 * @param pPage The physical page tracking structure.
1383 * @param GCPhys The address of the page.
1384 * @param ppMap Where to store the address of the mapping tracking structure.
1385 * @param ppv Where to store the mapping address of the page. The page
1386 * offset is masked off!
1387 *
1388 * @remarks Called from within the PGM critical section.
1389 */
1390static int pgmPhysPageMapCommon(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMPAGEMAP ppMap, void **ppv)
1391{
1392 PGM_LOCK_ASSERT_OWNER(pVM);
1393 NOREF(GCPhys);
1394
1395 /*
1396 * Special cases: MMIO2, ZERO and specially aliased MMIO pages.
1397 */
1398 if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2
1399 || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO)
1400 {
1401 /* Decode the page id to a page in a MMIO2 ram range. */
1402 uint8_t idMmio2 = PGM_MMIO2_PAGEID_GET_MMIO2_ID(PGM_PAGE_GET_PAGEID(pPage));
1403 uint32_t iPage = PGM_MMIO2_PAGEID_GET_IDX(PGM_PAGE_GET_PAGEID(pPage));
1404 AssertLogRelMsgReturn((uint8_t)(idMmio2 - 1U) < RT_ELEMENTS(pVM->pgm.s.CTX_SUFF(apMmio2Ranges)),
1405 ("idMmio2=%u size=%u type=%u GCPHys=%#RGp Id=%u State=%u", idMmio2,
1406 RT_ELEMENTS(pVM->pgm.s.CTX_SUFF(apMmio2Ranges)), PGM_PAGE_GET_TYPE(pPage), GCPhys,
1407 pPage->s.idPage, pPage->s.uStateY),
1408 VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
1409 PPGMREGMMIO2RANGE pMmio2Range = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[idMmio2 - 1];
1410 AssertLogRelReturn(pMmio2Range, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
1411 AssertLogRelReturn(pMmio2Range->idMmio2 == idMmio2, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
1412 AssertLogRelReturn(iPage < (pMmio2Range->RamRange.cb >> GUEST_PAGE_SHIFT), VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE);
1413 *ppMap = NULL;
1414# if defined(IN_RING0) && defined(VBOX_WITH_LINEAR_HOST_PHYS_MEM)
1415 return SUPR0HCPhysToVirt(PGM_PAGE_GET_HCPHYS(pPage), ppv);
1416# elif defined(IN_RING0)
1417 *ppv = (uint8_t *)pMmio2Range->pvR0 + ((uintptr_t)iPage << GUEST_PAGE_SHIFT);
1418 return VINF_SUCCESS;
1419# else
1420 *ppv = (uint8_t *)pMmio2Range->RamRange.pvR3 + ((uintptr_t)iPage << GUEST_PAGE_SHIFT);
1421 return VINF_SUCCESS;
1422# endif
1423 }
1424
1425# ifdef VBOX_WITH_PGM_NEM_MODE
1426 if (pVM->pgm.s.fNemMode)
1427 {
1428# ifdef IN_RING3
1429 /*
1430 * Find the corresponding RAM range and use that to locate the mapping address.
1431 */
1432 /** @todo Use the page ID for some kind of indexing as we do with MMIO2 above. */
1433 PPGMRAMRANGE const pRam = pgmPhysGetRange(pVM, GCPhys);
1434 AssertLogRelMsgReturn(pRam, ("%RTGp\n", GCPhys), VERR_INTERNAL_ERROR_3);
1435 size_t const idxPage = (GCPhys - pRam->GCPhys) >> GUEST_PAGE_SHIFT;
1436 Assert(pPage == &pRam->aPages[idxPage]);
1437 *ppMap = NULL;
1438 *ppv = (uint8_t *)pRam->pvR3 + (idxPage << GUEST_PAGE_SHIFT);
1439 return VINF_SUCCESS;
1440# else
1441 AssertFailedReturn(VERR_INTERNAL_ERROR_2);
1442# endif
1443 }
1444# endif
1445
1446 const uint32_t idChunk = PGM_PAGE_GET_CHUNKID(pPage);
1447 if (idChunk == NIL_GMM_CHUNKID)
1448 {
1449 AssertMsgReturn(PGM_PAGE_GET_PAGEID(pPage) == NIL_GMM_PAGEID, ("pPage=%R[pgmpage]\n", pPage),
1450 VERR_PGM_PHYS_PAGE_MAP_IPE_1);
1451 if (!PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
1452 {
1453 AssertMsgReturn(PGM_PAGE_IS_ZERO(pPage), ("pPage=%R[pgmpage]\n", pPage),
1454 VERR_PGM_PHYS_PAGE_MAP_IPE_3);
1455 AssertMsgReturn(PGM_PAGE_GET_HCPHYS(pPage)== pVM->pgm.s.HCPhysZeroPg, ("pPage=%R[pgmpage]\n", pPage),
1456 VERR_PGM_PHYS_PAGE_MAP_IPE_4);
1457 *ppv = pVM->pgm.s.abZeroPg;
1458 }
1459 else
1460 *ppv = pVM->pgm.s.abZeroPg;
1461 *ppMap = NULL;
1462 return VINF_SUCCESS;
1463 }
1464
1465# if defined(IN_RING0) && defined(VBOX_WITH_LINEAR_HOST_PHYS_MEM)
1466 /*
1467 * Just use the physical address.
1468 */
1469 *ppMap = NULL;
1470 return SUPR0HCPhysToVirt(PGM_PAGE_GET_HCPHYS(pPage), ppv);
1471
1472# elif defined(IN_RING0)
1473 /*
1474 * Go by page ID thru GMMR0.
1475 */
1476 *ppMap = NULL;
1477 return GMMR0PageIdToVirt(pVM, PGM_PAGE_GET_PAGEID(pPage), ppv);
1478
1479# else
1480 /*
1481 * Find/make Chunk TLB entry for the mapping chunk.
1482 */
1483 PPGMCHUNKR3MAP pMap;
1484 PPGMCHUNKR3MAPTLBE pTlbe = &pVM->pgm.s.ChunkR3Map.Tlb.aEntries[PGM_CHUNKR3MAPTLB_IDX(idChunk)];
1485 if (pTlbe->idChunk == idChunk)
1486 {
1487 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,ChunkR3MapTlbHits));
1488 pMap = pTlbe->pChunk;
1489 AssertPtr(pMap->pv);
1490 }
1491 else
1492 {
1493 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,ChunkR3MapTlbMisses));
1494
1495 /*
1496 * Find the chunk, map it if necessary.
1497 */
1498 pMap = (PPGMCHUNKR3MAP)RTAvlU32Get(&pVM->pgm.s.ChunkR3Map.pTree, idChunk);
1499 if (pMap)
1500 {
1501 AssertPtr(pMap->pv);
1502 pMap->iLastUsed = pVM->pgm.s.ChunkR3Map.iNow;
1503 }
1504 else
1505 {
1506 int rc = pgmR3PhysChunkMap(pVM, idChunk, &pMap);
1507 if (RT_FAILURE(rc))
1508 return rc;
1509 AssertPtr(pMap->pv);
1510 }
1511
1512 /*
1513 * Enter it into the Chunk TLB.
1514 */
1515 pTlbe->idChunk = idChunk;
1516 pTlbe->pChunk = pMap;
1517 }
1518
1519 *ppv = (uint8_t *)pMap->pv + (PGM_PAGE_GET_PAGE_IN_CHUNK(pPage) << GUEST_PAGE_SHIFT);
1520 *ppMap = pMap;
1521 return VINF_SUCCESS;
1522# endif /* !IN_RING0 */
1523}
1524
1525
1526/**
1527 * Combination of pgmPhysPageMakeWritable and pgmPhysPageMapWritable.
1528 *
1529 * This is typically used is paths where we cannot use the TLB methods (like ROM
1530 * pages) or where there is no point in using them since we won't get many hits.
1531 *
1532 * @returns VBox strict status code.
1533 * @retval VINF_SUCCESS on success.
1534 * @retval VINF_PGM_SYNC_CR3 on success and a page pool flush is pending.
1535 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1536 *
1537 * @param pVM The cross context VM structure.
1538 * @param pPage The physical page tracking structure.
1539 * @param GCPhys The address of the page.
1540 * @param ppv Where to store the mapping address of the page. The page
1541 * offset is masked off!
1542 *
1543 * @remarks Called from within the PGM critical section. The mapping is only
1544 * valid while you are inside section.
1545 */
1546int pgmPhysPageMakeWritableAndMap(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void **ppv)
1547{
1548 int rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1549 if (RT_SUCCESS(rc))
1550 {
1551 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 /* returned */, ("%Rrc\n", rc));
1552 PPGMPAGEMAP pMapIgnore;
1553 int rc2 = pgmPhysPageMapCommon(pVM, pPage, GCPhys, &pMapIgnore, ppv);
1554 if (RT_FAILURE(rc2)) /* preserve rc */
1555 rc = rc2;
1556 }
1557 return rc;
1558}
1559
1560
1561/**
1562 * Maps a page into the current virtual address space so it can be accessed for
1563 * both writing and reading.
1564 *
1565 * This is typically used is paths where we cannot use the TLB methods (like ROM
1566 * pages) or where there is no point in using them since we won't get many hits.
1567 *
1568 * @returns VBox status code.
1569 * @retval VINF_SUCCESS on success.
1570 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1571 *
1572 * @param pVM The cross context VM structure.
1573 * @param pPage The physical page tracking structure. Must be in the
1574 * allocated state.
1575 * @param GCPhys The address of the page.
1576 * @param ppv Where to store the mapping address of the page. The page
1577 * offset is masked off!
1578 *
1579 * @remarks Called from within the PGM critical section. The mapping is only
1580 * valid while you are inside section.
1581 */
1582int pgmPhysPageMap(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void **ppv)
1583{
1584 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED);
1585 PPGMPAGEMAP pMapIgnore;
1586 return pgmPhysPageMapCommon(pVM, pPage, GCPhys, &pMapIgnore, ppv);
1587}
1588
1589
1590/**
1591 * Maps a page into the current virtual address space so it can be accessed for
1592 * reading.
1593 *
1594 * This is typically used is paths where we cannot use the TLB methods (like ROM
1595 * pages) or where there is no point in using them since we won't get many hits.
1596 *
1597 * @returns VBox status code.
1598 * @retval VINF_SUCCESS on success.
1599 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1600 *
1601 * @param pVM The cross context VM structure.
1602 * @param pPage The physical page tracking structure.
1603 * @param GCPhys The address of the page.
1604 * @param ppv Where to store the mapping address of the page. The page
1605 * offset is masked off!
1606 *
1607 * @remarks Called from within the PGM critical section. The mapping is only
1608 * valid while you are inside this section.
1609 */
1610int pgmPhysPageMapReadOnly(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void const **ppv)
1611{
1612 PPGMPAGEMAP pMapIgnore;
1613 return pgmPhysPageMapCommon(pVM, pPage, GCPhys, &pMapIgnore, (void **)ppv);
1614}
1615
1616
1617/**
1618 * Load a guest page into the ring-3 physical TLB.
1619 *
1620 * @returns VBox status code.
1621 * @retval VINF_SUCCESS on success
1622 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1623 * @param pVM The cross context VM structure.
1624 * @param GCPhys The guest physical address in question.
1625 */
1626int pgmPhysPageLoadIntoTlb(PVMCC pVM, RTGCPHYS GCPhys)
1627{
1628 PGM_LOCK_ASSERT_OWNER(pVM);
1629
1630 /*
1631 * Find the ram range and page and hand it over to the with-page function.
1632 * 99.8% of requests are expected to be in the first range.
1633 */
1634 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
1635 if (!pPage)
1636 {
1637 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PageMapTlbMisses));
1638 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
1639 }
1640
1641 return pgmPhysPageLoadIntoTlbWithPage(pVM, pPage, GCPhys);
1642}
1643
1644
1645/**
1646 * Load a guest page into the ring-3 physical TLB.
1647 *
1648 * @returns VBox status code.
1649 * @retval VINF_SUCCESS on success
1650 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1651 *
1652 * @param pVM The cross context VM structure.
1653 * @param pPage Pointer to the PGMPAGE structure corresponding to
1654 * GCPhys.
1655 * @param GCPhys The guest physical address in question.
1656 */
1657int pgmPhysPageLoadIntoTlbWithPage(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
1658{
1659 PGM_LOCK_ASSERT_OWNER(pVM);
1660 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PageMapTlbMisses));
1661
1662 /*
1663 * Map the page.
1664 * Make a special case for the zero page as it is kind of special.
1665 */
1666 PPGMPAGEMAPTLBE pTlbe = &pVM->pgm.s.CTX_SUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
1667 if ( !PGM_PAGE_IS_ZERO(pPage)
1668 && !PGM_PAGE_IS_BALLOONED(pPage))
1669 {
1670 void *pv;
1671 PPGMPAGEMAP pMap;
1672 int rc = pgmPhysPageMapCommon(pVM, pPage, GCPhys, &pMap, &pv);
1673 if (RT_FAILURE(rc))
1674 return rc;
1675# ifndef IN_RING0
1676 pTlbe->pMap = pMap;
1677# endif
1678 pTlbe->pv = pv;
1679 Assert(!((uintptr_t)pTlbe->pv & GUEST_PAGE_OFFSET_MASK));
1680 }
1681 else
1682 {
1683 AssertMsg(PGM_PAGE_GET_HCPHYS(pPage) == pVM->pgm.s.HCPhysZeroPg, ("%RGp/%R[pgmpage]\n", GCPhys, pPage));
1684# ifndef IN_RING0
1685 pTlbe->pMap = NULL;
1686# endif
1687 pTlbe->pv = pVM->pgm.s.abZeroPg;
1688 }
1689# ifdef PGM_WITH_PHYS_TLB
1690 if ( PGM_PAGE_GET_TYPE(pPage) < PGMPAGETYPE_ROM_SHADOW
1691 || PGM_PAGE_GET_TYPE(pPage) > PGMPAGETYPE_ROM)
1692 pTlbe->GCPhys = GCPhys & X86_PTE_PAE_PG_MASK;
1693 else
1694 pTlbe->GCPhys = NIL_RTGCPHYS; /* ROM: Problematic because of the two pages. :-/ */
1695# else
1696 pTlbe->GCPhys = NIL_RTGCPHYS;
1697# endif
1698 pTlbe->pPage = pPage;
1699 return VINF_SUCCESS;
1700}
1701
1702
1703/**
1704 * Internal version of PGMPhysGCPhys2CCPtr that expects the caller to
1705 * own the PGM lock and therefore not need to lock the mapped page.
1706 *
1707 * @returns VBox status code.
1708 * @retval VINF_SUCCESS on success.
1709 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1710 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1711 *
1712 * @param pVM The cross context VM structure.
1713 * @param GCPhys The guest physical address of the page that should be mapped.
1714 * @param pPage Pointer to the PGMPAGE structure for the page.
1715 * @param ppv Where to store the address corresponding to GCPhys.
1716 *
1717 * @internal
1718 * @deprecated Use pgmPhysGCPhys2CCPtrInternalEx.
1719 */
1720int pgmPhysGCPhys2CCPtrInternalDepr(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void **ppv)
1721{
1722 int rc;
1723 AssertReturn(pPage, VERR_PGM_PHYS_NULL_PAGE_PARAM);
1724 PGM_LOCK_ASSERT_OWNER(pVM);
1725 pVM->pgm.s.cDeprecatedPageLocks++;
1726
1727 /*
1728 * Make sure the page is writable.
1729 */
1730 if (RT_UNLIKELY(PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED))
1731 {
1732 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1733 if (RT_FAILURE(rc))
1734 return rc;
1735 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 /* not returned */, ("%Rrc\n", rc));
1736 }
1737 Assert(PGM_PAGE_GET_HCPHYS(pPage) != 0);
1738
1739 /*
1740 * Get the mapping address.
1741 */
1742 PPGMPAGEMAPTLBE pTlbe;
1743 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
1744 if (RT_FAILURE(rc))
1745 return rc;
1746 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
1747 return VINF_SUCCESS;
1748}
1749
1750
1751/**
1752 * Locks a page mapping for writing.
1753 *
1754 * @param pVM The cross context VM structure.
1755 * @param pPage The page.
1756 * @param pTlbe The mapping TLB entry for the page.
1757 * @param pLock The lock structure (output).
1758 */
1759DECLINLINE(void) pgmPhysPageMapLockForWriting(PVM pVM, PPGMPAGE pPage, PPGMPAGEMAPTLBE pTlbe, PPGMPAGEMAPLOCK pLock)
1760{
1761# ifndef IN_RING0
1762 PPGMPAGEMAP pMap = pTlbe->pMap;
1763 if (pMap)
1764 pMap->cRefs++;
1765# else
1766 RT_NOREF(pTlbe);
1767# endif
1768
1769 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
1770 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
1771 {
1772 if (cLocks == 0)
1773 pVM->pgm.s.cWriteLockedPages++;
1774 PGM_PAGE_INC_WRITE_LOCKS(pPage);
1775 }
1776 else if (cLocks != PGM_PAGE_MAX_LOCKS)
1777 {
1778 PGM_PAGE_INC_WRITE_LOCKS(pPage);
1779 AssertMsgFailed(("%R[pgmpage] is entering permanent write locked state!\n", pPage));
1780# ifndef IN_RING0
1781 if (pMap)
1782 pMap->cRefs++; /* Extra ref to prevent it from going away. */
1783# endif
1784 }
1785
1786 pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_WRITE;
1787# ifndef IN_RING0
1788 pLock->pvMap = pMap;
1789# else
1790 pLock->pvMap = NULL;
1791# endif
1792}
1793
1794/**
1795 * Locks a page mapping for reading.
1796 *
1797 * @param pVM The cross context VM structure.
1798 * @param pPage The page.
1799 * @param pTlbe The mapping TLB entry for the page.
1800 * @param pLock The lock structure (output).
1801 */
1802DECLINLINE(void) pgmPhysPageMapLockForReading(PVM pVM, PPGMPAGE pPage, PPGMPAGEMAPTLBE pTlbe, PPGMPAGEMAPLOCK pLock)
1803{
1804# ifndef IN_RING0
1805 PPGMPAGEMAP pMap = pTlbe->pMap;
1806 if (pMap)
1807 pMap->cRefs++;
1808# else
1809 RT_NOREF(pTlbe);
1810# endif
1811
1812 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
1813 if (RT_LIKELY(cLocks < PGM_PAGE_MAX_LOCKS - 1))
1814 {
1815 if (cLocks == 0)
1816 pVM->pgm.s.cReadLockedPages++;
1817 PGM_PAGE_INC_READ_LOCKS(pPage);
1818 }
1819 else if (cLocks != PGM_PAGE_MAX_LOCKS)
1820 {
1821 PGM_PAGE_INC_READ_LOCKS(pPage);
1822 AssertMsgFailed(("%R[pgmpage] is entering permanent read locked state!\n", pPage));
1823# ifndef IN_RING0
1824 if (pMap)
1825 pMap->cRefs++; /* Extra ref to prevent it from going away. */
1826# endif
1827 }
1828
1829 pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_READ;
1830# ifndef IN_RING0
1831 pLock->pvMap = pMap;
1832# else
1833 pLock->pvMap = NULL;
1834# endif
1835}
1836
1837
1838/**
1839 * Internal version of PGMPhysGCPhys2CCPtr that expects the caller to
1840 * own the PGM lock and have access to the page structure.
1841 *
1842 * @returns VBox status code.
1843 * @retval VINF_SUCCESS on success.
1844 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1845 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1846 *
1847 * @param pVM The cross context VM structure.
1848 * @param GCPhys The guest physical address of the page that should be mapped.
1849 * @param pPage Pointer to the PGMPAGE structure for the page.
1850 * @param ppv Where to store the address corresponding to GCPhys.
1851 * @param pLock Where to store the lock information that
1852 * pgmPhysReleaseInternalPageMappingLock needs.
1853 *
1854 * @internal
1855 */
1856int pgmPhysGCPhys2CCPtrInternal(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
1857{
1858 int rc;
1859 AssertReturn(pPage, VERR_PGM_PHYS_NULL_PAGE_PARAM);
1860 PGM_LOCK_ASSERT_OWNER(pVM);
1861
1862 /*
1863 * Make sure the page is writable.
1864 */
1865 if (RT_UNLIKELY(PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED))
1866 {
1867 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1868 if (RT_FAILURE(rc))
1869 return rc;
1870 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 /* not returned */, ("%Rrc\n", rc));
1871 }
1872 Assert(PGM_PAGE_GET_HCPHYS(pPage) != 0);
1873
1874 /*
1875 * Do the job.
1876 */
1877 PPGMPAGEMAPTLBE pTlbe;
1878 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
1879 if (RT_FAILURE(rc))
1880 return rc;
1881 pgmPhysPageMapLockForWriting(pVM, pPage, pTlbe, pLock);
1882 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
1883 return VINF_SUCCESS;
1884}
1885
1886
1887/**
1888 * Internal version of PGMPhysGCPhys2CCPtrReadOnly that expects the caller to
1889 * own the PGM lock and have access to the page structure.
1890 *
1891 * @returns VBox status code.
1892 * @retval VINF_SUCCESS on success.
1893 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1894 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1895 *
1896 * @param pVM The cross context VM structure.
1897 * @param GCPhys The guest physical address of the page that should be mapped.
1898 * @param pPage Pointer to the PGMPAGE structure for the page.
1899 * @param ppv Where to store the address corresponding to GCPhys.
1900 * @param pLock Where to store the lock information that
1901 * pgmPhysReleaseInternalPageMappingLock needs.
1902 *
1903 * @internal
1904 */
1905int pgmPhysGCPhys2CCPtrInternalReadOnly(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, const void **ppv, PPGMPAGEMAPLOCK pLock)
1906{
1907 AssertReturn(pPage, VERR_PGM_PHYS_NULL_PAGE_PARAM);
1908 PGM_LOCK_ASSERT_OWNER(pVM);
1909 Assert(PGM_PAGE_GET_HCPHYS(pPage) != 0);
1910
1911 /*
1912 * Do the job.
1913 */
1914 PPGMPAGEMAPTLBE pTlbe;
1915 int rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
1916 if (RT_FAILURE(rc))
1917 return rc;
1918 pgmPhysPageMapLockForReading(pVM, pPage, pTlbe, pLock);
1919 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
1920 return VINF_SUCCESS;
1921}
1922
1923
1924/**
1925 * Requests the mapping of a guest page into the current context.
1926 *
1927 * This API should only be used for very short term, as it will consume scarse
1928 * resources (R0 and GC) in the mapping cache. When you're done with the page,
1929 * call PGMPhysReleasePageMappingLock() ASAP to release it.
1930 *
1931 * This API will assume your intention is to write to the page, and will
1932 * therefore replace shared and zero pages. If you do not intend to modify
1933 * the page, use the PGMPhysGCPhys2CCPtrReadOnly() API.
1934 *
1935 * @returns VBox status code.
1936 * @retval VINF_SUCCESS on success.
1937 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
1938 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
1939 *
1940 * @param pVM The cross context VM structure.
1941 * @param GCPhys The guest physical address of the page that should be
1942 * mapped.
1943 * @param ppv Where to store the address corresponding to GCPhys.
1944 * @param pLock Where to store the lock information that
1945 * PGMPhysReleasePageMappingLock needs.
1946 *
1947 * @remarks The caller is responsible for dealing with access handlers.
1948 * @todo Add an informational return code for pages with access handlers?
1949 *
1950 * @remark Avoid calling this API from within critical sections (other than
1951 * the PGM one) because of the deadlock risk. External threads may
1952 * need to delegate jobs to the EMTs.
1953 * @remarks Only one page is mapped! Make no assumption about what's after or
1954 * before the returned page!
1955 * @thread Any thread.
1956 */
1957VMM_INT_DECL(int) PGMPhysGCPhys2CCPtr(PVMCC pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
1958{
1959 int rc = PGM_LOCK(pVM);
1960 AssertRCReturn(rc, rc);
1961
1962 /*
1963 * Query the Physical TLB entry for the page (may fail).
1964 */
1965 PPGMPAGEMAPTLBE pTlbe;
1966 rc = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
1967 if (RT_SUCCESS(rc))
1968 {
1969 /*
1970 * If the page is shared, the zero page, or being write monitored
1971 * it must be converted to a page that's writable if possible.
1972 */
1973 PPGMPAGE pPage = pTlbe->pPage;
1974 if (RT_UNLIKELY(PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED))
1975 {
1976 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
1977 if (RT_SUCCESS(rc))
1978 {
1979 AssertMsg(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3 /* not returned */, ("%Rrc\n", rc));
1980 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
1981 }
1982 }
1983 if (RT_SUCCESS(rc))
1984 {
1985 /*
1986 * Now, just perform the locking and calculate the return address.
1987 */
1988 pgmPhysPageMapLockForWriting(pVM, pPage, pTlbe, pLock);
1989 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
1990 }
1991 }
1992
1993 PGM_UNLOCK(pVM);
1994 return rc;
1995}
1996
1997
1998/**
1999 * Requests the mapping of a guest page into the current context.
2000 *
2001 * This API should only be used for very short term, as it will consume scarse
2002 * resources (R0 and GC) in the mapping cache. When you're done with the page,
2003 * call PGMPhysReleasePageMappingLock() ASAP to release it.
2004 *
2005 * @returns VBox status code.
2006 * @retval VINF_SUCCESS on success.
2007 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
2008 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
2009 *
2010 * @param pVM The cross context VM structure.
2011 * @param GCPhys The guest physical address of the page that should be
2012 * mapped.
2013 * @param ppv Where to store the address corresponding to GCPhys.
2014 * @param pLock Where to store the lock information that
2015 * PGMPhysReleasePageMappingLock needs.
2016 *
2017 * @remarks The caller is responsible for dealing with access handlers.
2018 * @todo Add an informational return code for pages with access handlers?
2019 *
2020 * @remarks Avoid calling this API from within critical sections (other than
2021 * the PGM one) because of the deadlock risk.
2022 * @remarks Only one page is mapped! Make no assumption about what's after or
2023 * before the returned page!
2024 * @thread Any thread.
2025 */
2026VMM_INT_DECL(int) PGMPhysGCPhys2CCPtrReadOnly(PVMCC pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock)
2027{
2028 int rc = PGM_LOCK(pVM);
2029 AssertRCReturn(rc, rc);
2030
2031 /*
2032 * Query the Physical TLB entry for the page (may fail).
2033 */
2034 PPGMPAGEMAPTLBE pTlbe;
2035 rc = pgmPhysPageQueryTlbe(pVM, GCPhys, &pTlbe);
2036 if (RT_SUCCESS(rc))
2037 {
2038 /* MMIO pages doesn't have any readable backing. */
2039 PPGMPAGE pPage = pTlbe->pPage;
2040 if (RT_UNLIKELY(PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage)))
2041 rc = VERR_PGM_PHYS_PAGE_RESERVED;
2042 else
2043 {
2044 /*
2045 * Now, just perform the locking and calculate the return address.
2046 */
2047 pgmPhysPageMapLockForReading(pVM, pPage, pTlbe, pLock);
2048 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
2049 }
2050 }
2051
2052 PGM_UNLOCK(pVM);
2053 return rc;
2054}
2055
2056
2057/**
2058 * Requests the mapping of a guest page given by virtual address into the current context.
2059 *
2060 * This API should only be used for very short term, as it will consume
2061 * scarse resources (R0 and GC) in the mapping cache. When you're done
2062 * with the page, call PGMPhysReleasePageMappingLock() ASAP to release it.
2063 *
2064 * This API will assume your intention is to write to the page, and will
2065 * therefore replace shared and zero pages. If you do not intend to modify
2066 * the page, use the PGMPhysGCPtr2CCPtrReadOnly() API.
2067 *
2068 * @returns VBox status code.
2069 * @retval VINF_SUCCESS on success.
2070 * @retval VERR_PAGE_TABLE_NOT_PRESENT if the page directory for the virtual address isn't present.
2071 * @retval VERR_PAGE_NOT_PRESENT if the page at the virtual address isn't present.
2072 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
2073 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
2074 *
2075 * @param pVCpu The cross context virtual CPU structure.
2076 * @param GCPtr The guest physical address of the page that should be
2077 * mapped.
2078 * @param ppv Where to store the address corresponding to GCPhys.
2079 * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
2080 *
2081 * @remark Avoid calling this API from within critical sections (other than
2082 * the PGM one) because of the deadlock risk.
2083 * @thread EMT
2084 */
2085VMM_INT_DECL(int) PGMPhysGCPtr2CCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtr, void **ppv, PPGMPAGEMAPLOCK pLock)
2086{
2087 VM_ASSERT_EMT(pVCpu->CTX_SUFF(pVM));
2088 RTGCPHYS GCPhys;
2089 int rc = PGMPhysGCPtr2GCPhys(pVCpu, GCPtr, &GCPhys);
2090 if (RT_SUCCESS(rc))
2091 rc = PGMPhysGCPhys2CCPtr(pVCpu->CTX_SUFF(pVM), GCPhys, ppv, pLock);
2092 return rc;
2093}
2094
2095
2096/**
2097 * Requests the mapping of a guest page given by virtual address into the current context.
2098 *
2099 * This API should only be used for very short term, as it will consume
2100 * scarse resources (R0 and GC) in the mapping cache. When you're done
2101 * with the page, call PGMPhysReleasePageMappingLock() ASAP to release it.
2102 *
2103 * @returns VBox status code.
2104 * @retval VINF_SUCCESS on success.
2105 * @retval VERR_PAGE_TABLE_NOT_PRESENT if the page directory for the virtual address isn't present.
2106 * @retval VERR_PAGE_NOT_PRESENT if the page at the virtual address isn't present.
2107 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical backing.
2108 * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
2109 *
2110 * @param pVCpu The cross context virtual CPU structure.
2111 * @param GCPtr The guest physical address of the page that should be
2112 * mapped.
2113 * @param ppv Where to store the address corresponding to GCPtr.
2114 * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
2115 *
2116 * @remark Avoid calling this API from within critical sections (other than
2117 * the PGM one) because of the deadlock risk.
2118 * @thread EMT
2119 */
2120VMM_INT_DECL(int) PGMPhysGCPtr2CCPtrReadOnly(PVMCPUCC pVCpu, RTGCPTR GCPtr, void const **ppv, PPGMPAGEMAPLOCK pLock)
2121{
2122 VM_ASSERT_EMT(pVCpu->CTX_SUFF(pVM));
2123 RTGCPHYS GCPhys;
2124 int rc = PGMPhysGCPtr2GCPhys(pVCpu, GCPtr, &GCPhys);
2125 if (RT_SUCCESS(rc))
2126 rc = PGMPhysGCPhys2CCPtrReadOnly(pVCpu->CTX_SUFF(pVM), GCPhys, ppv, pLock);
2127 return rc;
2128}
2129
2130
2131/**
2132 * Release the mapping of a guest page.
2133 *
2134 * This is the counter part of PGMPhysGCPhys2CCPtr, PGMPhysGCPhys2CCPtrReadOnly
2135 * PGMPhysGCPtr2CCPtr and PGMPhysGCPtr2CCPtrReadOnly.
2136 *
2137 * @param pVM The cross context VM structure.
2138 * @param pLock The lock structure initialized by the mapping function.
2139 */
2140VMMDECL(void) PGMPhysReleasePageMappingLock(PVMCC pVM, PPGMPAGEMAPLOCK pLock)
2141{
2142# ifndef IN_RING0
2143 PPGMPAGEMAP pMap = (PPGMPAGEMAP)pLock->pvMap;
2144# endif
2145 PPGMPAGE pPage = (PPGMPAGE)(pLock->uPageAndType & ~PGMPAGEMAPLOCK_TYPE_MASK);
2146 bool fWriteLock = (pLock->uPageAndType & PGMPAGEMAPLOCK_TYPE_MASK) == PGMPAGEMAPLOCK_TYPE_WRITE;
2147
2148 pLock->uPageAndType = 0;
2149 pLock->pvMap = NULL;
2150
2151 PGM_LOCK_VOID(pVM);
2152 if (fWriteLock)
2153 {
2154 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
2155 Assert(cLocks > 0);
2156 if (RT_LIKELY(cLocks > 0 && cLocks < PGM_PAGE_MAX_LOCKS))
2157 {
2158 if (cLocks == 1)
2159 {
2160 Assert(pVM->pgm.s.cWriteLockedPages > 0);
2161 pVM->pgm.s.cWriteLockedPages--;
2162 }
2163 PGM_PAGE_DEC_WRITE_LOCKS(pPage);
2164 }
2165
2166 if (PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_WRITE_MONITORED)
2167 { /* probably extremely likely */ }
2168 else
2169 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, NIL_RTGCPHYS);
2170 }
2171 else
2172 {
2173 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
2174 Assert(cLocks > 0);
2175 if (RT_LIKELY(cLocks > 0 && cLocks < PGM_PAGE_MAX_LOCKS))
2176 {
2177 if (cLocks == 1)
2178 {
2179 Assert(pVM->pgm.s.cReadLockedPages > 0);
2180 pVM->pgm.s.cReadLockedPages--;
2181 }
2182 PGM_PAGE_DEC_READ_LOCKS(pPage);
2183 }
2184 }
2185
2186# ifndef IN_RING0
2187 if (pMap)
2188 {
2189 Assert(pMap->cRefs >= 1);
2190 pMap->cRefs--;
2191 }
2192# endif
2193 PGM_UNLOCK(pVM);
2194}
2195
2196
2197#ifdef IN_RING3
2198/**
2199 * Release the mapping of multiple guest pages.
2200 *
2201 * This is the counter part to PGMR3PhysBulkGCPhys2CCPtrExternal() and
2202 * PGMR3PhysBulkGCPhys2CCPtrReadOnlyExternal().
2203 *
2204 * @param pVM The cross context VM structure.
2205 * @param cPages Number of pages to unlock.
2206 * @param paLocks Array of locks lock structure initialized by the mapping
2207 * function.
2208 */
2209VMMDECL(void) PGMPhysBulkReleasePageMappingLocks(PVMCC pVM, uint32_t cPages, PPGMPAGEMAPLOCK paLocks)
2210{
2211 Assert(cPages > 0);
2212 bool const fWriteLock = (paLocks[0].uPageAndType & PGMPAGEMAPLOCK_TYPE_MASK) == PGMPAGEMAPLOCK_TYPE_WRITE;
2213#ifdef VBOX_STRICT
2214 for (uint32_t i = 1; i < cPages; i++)
2215 {
2216 Assert(fWriteLock == ((paLocks[i].uPageAndType & PGMPAGEMAPLOCK_TYPE_MASK) == PGMPAGEMAPLOCK_TYPE_WRITE));
2217 AssertPtr(paLocks[i].uPageAndType);
2218 }
2219#endif
2220
2221 PGM_LOCK_VOID(pVM);
2222 if (fWriteLock)
2223 {
2224 /*
2225 * Write locks:
2226 */
2227 for (uint32_t i = 0; i < cPages; i++)
2228 {
2229 PPGMPAGE pPage = (PPGMPAGE)(paLocks[i].uPageAndType & ~PGMPAGEMAPLOCK_TYPE_MASK);
2230 unsigned cLocks = PGM_PAGE_GET_WRITE_LOCKS(pPage);
2231 Assert(cLocks > 0);
2232 if (RT_LIKELY(cLocks > 0 && cLocks < PGM_PAGE_MAX_LOCKS))
2233 {
2234 if (cLocks == 1)
2235 {
2236 Assert(pVM->pgm.s.cWriteLockedPages > 0);
2237 pVM->pgm.s.cWriteLockedPages--;
2238 }
2239 PGM_PAGE_DEC_WRITE_LOCKS(pPage);
2240 }
2241
2242 if (PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_WRITE_MONITORED)
2243 { /* probably extremely likely */ }
2244 else
2245 pgmPhysPageMakeWriteMonitoredWritable(pVM, pPage, NIL_RTGCPHYS);
2246
2247 PPGMPAGEMAP pMap = (PPGMPAGEMAP)paLocks[i].pvMap;
2248 if (pMap)
2249 {
2250 Assert(pMap->cRefs >= 1);
2251 pMap->cRefs--;
2252 }
2253
2254 /* Yield the lock: */
2255 if ((i & 1023) == 1023 && i + 1 < cPages)
2256 {
2257 PGM_UNLOCK(pVM);
2258 PGM_LOCK_VOID(pVM);
2259 }
2260 }
2261 }
2262 else
2263 {
2264 /*
2265 * Read locks:
2266 */
2267 for (uint32_t i = 0; i < cPages; i++)
2268 {
2269 PPGMPAGE pPage = (PPGMPAGE)(paLocks[i].uPageAndType & ~PGMPAGEMAPLOCK_TYPE_MASK);
2270 unsigned cLocks = PGM_PAGE_GET_READ_LOCKS(pPage);
2271 Assert(cLocks > 0);
2272 if (RT_LIKELY(cLocks > 0 && cLocks < PGM_PAGE_MAX_LOCKS))
2273 {
2274 if (cLocks == 1)
2275 {
2276 Assert(pVM->pgm.s.cReadLockedPages > 0);
2277 pVM->pgm.s.cReadLockedPages--;
2278 }
2279 PGM_PAGE_DEC_READ_LOCKS(pPage);
2280 }
2281
2282 PPGMPAGEMAP pMap = (PPGMPAGEMAP)paLocks[i].pvMap;
2283 if (pMap)
2284 {
2285 Assert(pMap->cRefs >= 1);
2286 pMap->cRefs--;
2287 }
2288
2289 /* Yield the lock: */
2290 if ((i & 1023) == 1023 && i + 1 < cPages)
2291 {
2292 PGM_UNLOCK(pVM);
2293 PGM_LOCK_VOID(pVM);
2294 }
2295 }
2296 }
2297 PGM_UNLOCK(pVM);
2298
2299 RT_BZERO(paLocks, sizeof(paLocks[0]) * cPages);
2300}
2301#endif /* IN_RING3 */
2302
2303
2304/**
2305 * Release the internal mapping of a guest page.
2306 *
2307 * This is the counter part of pgmPhysGCPhys2CCPtrInternalEx and
2308 * pgmPhysGCPhys2CCPtrInternalReadOnly.
2309 *
2310 * @param pVM The cross context VM structure.
2311 * @param pLock The lock structure initialized by the mapping function.
2312 *
2313 * @remarks Caller must hold the PGM lock.
2314 */
2315void pgmPhysReleaseInternalPageMappingLock(PVMCC pVM, PPGMPAGEMAPLOCK pLock)
2316{
2317 PGM_LOCK_ASSERT_OWNER(pVM);
2318 PGMPhysReleasePageMappingLock(pVM, pLock); /* lazy for now */
2319}
2320
2321
2322/**
2323 * Converts a GC physical address to a HC ring-3 pointer.
2324 *
2325 * @returns VINF_SUCCESS on success.
2326 * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical
2327 * page but has no physical backing.
2328 * @returns VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid
2329 * GC physical address.
2330 * @returns VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY if the range crosses
2331 * a dynamic ram chunk boundary
2332 *
2333 * @param pVM The cross context VM structure.
2334 * @param GCPhys The GC physical address to convert.
2335 * @param pR3Ptr Where to store the R3 pointer on success.
2336 *
2337 * @deprecated Avoid when possible!
2338 */
2339int pgmPhysGCPhys2R3Ptr(PVMCC pVM, RTGCPHYS GCPhys, PRTR3PTR pR3Ptr)
2340{
2341/** @todo this is kind of hacky and needs some more work. */
2342#ifndef DEBUG_sandervl
2343 VM_ASSERT_EMT(pVM); /* no longer safe for use outside the EMT thread! */
2344#endif
2345
2346 Log(("pgmPhysGCPhys2R3Ptr(,%RGp,): dont use this API!\n", GCPhys)); /** @todo eliminate this API! */
2347 PGM_LOCK_VOID(pVM);
2348
2349 PPGMRAMRANGE pRam;
2350 PPGMPAGE pPage;
2351 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
2352 if (RT_SUCCESS(rc))
2353 rc = pgmPhysGCPhys2CCPtrInternalDepr(pVM, pPage, GCPhys, (void **)pR3Ptr);
2354
2355 PGM_UNLOCK(pVM);
2356 Assert(rc <= VINF_SUCCESS);
2357 return rc;
2358}
2359
2360
2361/**
2362 * Converts a guest pointer to a GC physical address.
2363 *
2364 * This uses the current CR3/CR0/CR4 of the guest.
2365 *
2366 * @returns VBox status code.
2367 * @param pVCpu The cross context virtual CPU structure.
2368 * @param GCPtr The guest pointer to convert.
2369 * @param pGCPhys Where to store the GC physical address.
2370 */
2371VMMDECL(int) PGMPhysGCPtr2GCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTGCPHYS pGCPhys)
2372{
2373 PGMPTWALK Walk;
2374 int rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtr, &Walk);
2375 if (pGCPhys && RT_SUCCESS(rc))
2376 *pGCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtr & GUEST_PAGE_OFFSET_MASK);
2377 return rc;
2378}
2379
2380
2381/**
2382 * Converts a guest pointer to a HC physical address.
2383 *
2384 * This uses the current CR3/CR0/CR4 of the guest.
2385 *
2386 * @returns VBox status code.
2387 * @param pVCpu The cross context virtual CPU structure.
2388 * @param GCPtr The guest pointer to convert.
2389 * @param pHCPhys Where to store the HC physical address.
2390 */
2391VMM_INT_DECL(int) PGMPhysGCPtr2HCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTHCPHYS pHCPhys)
2392{
2393 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
2394 PGMPTWALK Walk;
2395 int rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtr, &Walk);
2396 if (RT_SUCCESS(rc))
2397 rc = PGMPhysGCPhys2HCPhys(pVM, Walk.GCPhys | ((RTGCUINTPTR)GCPtr & GUEST_PAGE_OFFSET_MASK), pHCPhys);
2398 return rc;
2399}
2400
2401
2402
2403#undef LOG_GROUP
2404#define LOG_GROUP LOG_GROUP_PGM_PHYS_ACCESS
2405
2406
2407#if defined(IN_RING3) && defined(SOME_UNUSED_FUNCTION)
2408/**
2409 * Cache PGMPhys memory access
2410 *
2411 * @param pVM The cross context VM structure.
2412 * @param pCache Cache structure pointer
2413 * @param GCPhys GC physical address
2414 * @param pbR3 HC pointer corresponding to physical page
2415 *
2416 * @thread EMT.
2417 */
2418static void pgmPhysCacheAdd(PVM pVM, PGMPHYSCACHE *pCache, RTGCPHYS GCPhys, uint8_t *pbR3)
2419{
2420 uint32_t iCacheIndex;
2421
2422 Assert(VM_IS_EMT(pVM));
2423
2424 GCPhys &= ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
2425 pbR3 = (uint8_t *)((uintptr_t)pbR3 & ~(uintptr_t)GUEST_PAGE_OFFSET_MASK);
2426
2427 iCacheIndex = ((GCPhys >> GUEST_PAGE_SHIFT) & PGM_MAX_PHYSCACHE_ENTRIES_MASK);
2428
2429 ASMBitSet(&pCache->aEntries, iCacheIndex);
2430
2431 pCache->Entry[iCacheIndex].GCPhys = GCPhys;
2432 pCache->Entry[iCacheIndex].pbR3 = pbR3;
2433}
2434#endif /* IN_RING3 */
2435
2436
2437/**
2438 * Deals with reading from a page with one or more ALL access handlers.
2439 *
2440 * @returns Strict VBox status code in ring-0 and raw-mode, ignorable in ring-3.
2441 * See PGM_HANDLER_PHYS_IS_VALID_STATUS and
2442 * PGM_HANDLER_VIRT_IS_VALID_STATUS for details.
2443 *
2444 * @param pVM The cross context VM structure.
2445 * @param pPage The page descriptor.
2446 * @param GCPhys The physical address to start reading at.
2447 * @param pvBuf Where to put the bits we read.
2448 * @param cb How much to read - less or equal to a page.
2449 * @param enmOrigin The origin of this call.
2450 */
2451static VBOXSTRICTRC pgmPhysReadHandler(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void *pvBuf, size_t cb,
2452 PGMACCESSORIGIN enmOrigin)
2453{
2454 /*
2455 * The most frequent access here is MMIO and shadowed ROM.
2456 * The current code ASSUMES all these access handlers covers full pages!
2457 */
2458
2459 /*
2460 * Whatever we do we need the source page, map it first.
2461 */
2462 PGMPAGEMAPLOCK PgMpLck;
2463 const void *pvSrc = NULL;
2464 int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, GCPhys, &pvSrc, &PgMpLck);
2465/** @todo Check how this can work for MMIO pages? */
2466 if (RT_FAILURE(rc))
2467 {
2468 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
2469 GCPhys, pPage, rc));
2470 memset(pvBuf, 0xff, cb);
2471 return VINF_SUCCESS;
2472 }
2473
2474 VBOXSTRICTRC rcStrict = VINF_PGM_HANDLER_DO_DEFAULT;
2475
2476 /*
2477 * Deal with any physical handlers.
2478 */
2479 PVMCPUCC pVCpu = VMMGetCpu(pVM);
2480 if ( PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_ALL
2481 || PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
2482 {
2483 PPGMPHYSHANDLER pCur;
2484 rc = pgmHandlerPhysicalLookup(pVM, GCPhys, &pCur);
2485 if (RT_SUCCESS(rc))
2486 {
2487 Assert(pCur && GCPhys >= pCur->Key && GCPhys <= pCur->KeyLast);
2488 Assert((pCur->Key & GUEST_PAGE_OFFSET_MASK) == 0);
2489 Assert((pCur->KeyLast & GUEST_PAGE_OFFSET_MASK) == GUEST_PAGE_OFFSET_MASK);
2490#ifndef IN_RING3
2491 if (enmOrigin != PGMACCESSORIGIN_IEM)
2492 {
2493 /* Cannot reliably handle informational status codes in this context */
2494 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2495 return VERR_PGM_PHYS_WR_HIT_HANDLER;
2496 }
2497#endif
2498 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
2499 PFNPGMPHYSHANDLER const pfnHandler = pCurType->pfnHandler; Assert(pfnHandler);
2500 uint64_t const uUser = !pCurType->fRing0DevInsIdx ? pCur->uUser
2501 : (uintptr_t)PDMDeviceRing0IdxToInstance(pVM, pCur->uUser);
2502
2503 Log5(("pgmPhysReadHandler: GCPhys=%RGp cb=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cb, pPage, R3STRING(pCur->pszDesc) ));
2504 STAM_PROFILE_START(&pCur->Stat, h);
2505 PGM_LOCK_ASSERT_OWNER(pVM);
2506
2507 /* Release the PGM lock as MMIO handlers take the IOM lock. (deadlock prevention) */
2508 PGM_UNLOCK(pVM);
2509 rcStrict = pfnHandler(pVM, pVCpu, GCPhys, (void *)pvSrc, pvBuf, cb, PGMACCESSTYPE_READ, enmOrigin, uUser);
2510 PGM_LOCK_VOID(pVM);
2511
2512 STAM_PROFILE_STOP(&pCur->Stat, h); /* no locking needed, entry is unlikely reused before we get here. */
2513 pCur = NULL; /* might not be valid anymore. */
2514 AssertLogRelMsg(PGM_HANDLER_PHYS_IS_VALID_STATUS(rcStrict, false),
2515 ("rcStrict=%Rrc GCPhys=%RGp\n", VBOXSTRICTRC_VAL(rcStrict), GCPhys));
2516 if ( rcStrict != VINF_PGM_HANDLER_DO_DEFAULT
2517 && !PGM_PHYS_RW_IS_SUCCESS(rcStrict))
2518 {
2519 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2520 return rcStrict;
2521 }
2522 }
2523 else if (rc == VERR_NOT_FOUND)
2524 AssertLogRelMsgFailed(("rc=%Rrc GCPhys=%RGp cb=%#x\n", rc, GCPhys, cb));
2525 else
2526 AssertLogRelMsgFailedReturn(("rc=%Rrc GCPhys=%RGp cb=%#x\n", rc, GCPhys, cb), rc);
2527 }
2528
2529 /*
2530 * Take the default action.
2531 */
2532 if (rcStrict == VINF_PGM_HANDLER_DO_DEFAULT)
2533 {
2534 memcpy(pvBuf, pvSrc, cb);
2535 rcStrict = VINF_SUCCESS;
2536 }
2537 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2538 return rcStrict;
2539}
2540
2541
2542/**
2543 * Read physical memory.
2544 *
2545 * This API respects access handlers and MMIO. Use PGMPhysSimpleReadGCPhys() if you
2546 * want to ignore those.
2547 *
2548 * @returns Strict VBox status code in raw-mode and ring-0, normal VBox status
2549 * code in ring-3. Use PGM_PHYS_RW_IS_SUCCESS to check.
2550 * @retval VINF_SUCCESS in all context - read completed.
2551 *
2552 * @retval VINF_EM_OFF in RC and R0 - read completed.
2553 * @retval VINF_EM_SUSPEND in RC and R0 - read completed.
2554 * @retval VINF_EM_RESET in RC and R0 - read completed.
2555 * @retval VINF_EM_HALT in RC and R0 - read completed.
2556 * @retval VINF_SELM_SYNC_GDT in RC only - read completed.
2557 *
2558 * @retval VINF_EM_DBG_STOP in RC and R0 - read completed.
2559 * @retval VINF_EM_DBG_BREAKPOINT in RC and R0 - read completed.
2560 * @retval VINF_EM_RAW_EMULATE_INSTR in RC and R0 only.
2561 *
2562 * @retval VINF_IOM_R3_MMIO_READ in RC and R0.
2563 * @retval VINF_IOM_R3_MMIO_READ_WRITE in RC and R0.
2564 *
2565 * @retval VINF_PATM_CHECK_PATCH_PAGE in RC only.
2566 *
2567 * @retval VERR_PGM_PHYS_WR_HIT_HANDLER in RC and R0 for access origins that
2568 * haven't been cleared for strict status codes yet.
2569 *
2570 * @param pVM The cross context VM structure.
2571 * @param GCPhys Physical address start reading from.
2572 * @param pvBuf Where to put the read bits.
2573 * @param cbRead How many bytes to read.
2574 * @param enmOrigin The origin of this call.
2575 */
2576VMMDECL(VBOXSTRICTRC) PGMPhysRead(PVMCC pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin)
2577{
2578 AssertMsgReturn(cbRead > 0, ("don't even think about reading zero bytes!\n"), VINF_SUCCESS);
2579 LogFlow(("PGMPhysRead: %RGp %d\n", GCPhys, cbRead));
2580
2581 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysRead));
2582 STAM_COUNTER_ADD(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysReadBytes), cbRead);
2583
2584 PGM_LOCK_VOID(pVM);
2585
2586 /*
2587 * Copy loop on ram ranges.
2588 */
2589 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2590 PPGMRAMRANGE pRam = pgmPhysGetRangeAtOrAbove(pVM, GCPhys);
2591 for (;;)
2592 {
2593 /* Inside range or not? */
2594 if (pRam && GCPhys >= pRam->GCPhys)
2595 {
2596 /*
2597 * Must work our way thru this page by page.
2598 */
2599 RTGCPHYS off = GCPhys - pRam->GCPhys;
2600 while (off < pRam->cb)
2601 {
2602 unsigned iPage = off >> GUEST_PAGE_SHIFT;
2603 PPGMPAGE pPage = &pRam->aPages[iPage];
2604 size_t cb = GUEST_PAGE_SIZE - (off & GUEST_PAGE_OFFSET_MASK);
2605 if (cb > cbRead)
2606 cb = cbRead;
2607
2608 /*
2609 * Normal page? Get the pointer to it.
2610 */
2611 if ( !PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)
2612 && !PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
2613 {
2614 /*
2615 * Get the pointer to the page.
2616 */
2617 PGMPAGEMAPLOCK PgMpLck;
2618 const void *pvSrc;
2619 int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, pRam->GCPhys + off, &pvSrc, &PgMpLck);
2620 if (RT_SUCCESS(rc))
2621 {
2622 memcpy(pvBuf, pvSrc, cb);
2623 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2624 }
2625 else
2626 {
2627 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
2628 pRam->GCPhys + off, pPage, rc));
2629 memset(pvBuf, 0xff, cb);
2630 }
2631 }
2632 /*
2633 * Have ALL/MMIO access handlers.
2634 */
2635 else
2636 {
2637 VBOXSTRICTRC rcStrict2 = pgmPhysReadHandler(pVM, pPage, pRam->GCPhys + off, pvBuf, cb, enmOrigin);
2638 if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
2639 PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
2640 else
2641 {
2642 /* Set the remaining buffer to a known value. */
2643 memset(pvBuf, 0xff, cbRead);
2644 PGM_UNLOCK(pVM);
2645 return rcStrict2;
2646 }
2647 }
2648
2649 /* next page */
2650 if (cb >= cbRead)
2651 {
2652 PGM_UNLOCK(pVM);
2653 return rcStrict;
2654 }
2655 cbRead -= cb;
2656 off += cb;
2657 pvBuf = (char *)pvBuf + cb;
2658 } /* walk pages in ram range. */
2659
2660 GCPhys = pRam->GCPhysLast + 1;
2661 }
2662 else
2663 {
2664 LogFlow(("PGMPhysRead: Unassigned %RGp size=%u\n", GCPhys, cbRead));
2665
2666 /*
2667 * Unassigned address space.
2668 */
2669 size_t cb = pRam ? pRam->GCPhys - GCPhys : ~(size_t)0;
2670 if (cb >= cbRead)
2671 {
2672 memset(pvBuf, 0xff, cbRead);
2673 break;
2674 }
2675 memset(pvBuf, 0xff, cb);
2676
2677 cbRead -= cb;
2678 pvBuf = (char *)pvBuf + cb;
2679 GCPhys += cb;
2680 }
2681
2682 /* Advance range if necessary. */
2683 while (pRam && GCPhys > pRam->GCPhysLast)
2684 pRam = pRam->CTX_SUFF(pNext);
2685 } /* Ram range walk */
2686
2687 PGM_UNLOCK(pVM);
2688 return rcStrict;
2689}
2690
2691
2692/**
2693 * Deals with writing to a page with one or more WRITE or ALL access handlers.
2694 *
2695 * @returns Strict VBox status code in ring-0 and raw-mode, ignorable in ring-3.
2696 * See PGM_HANDLER_PHYS_IS_VALID_STATUS and
2697 * PGM_HANDLER_VIRT_IS_VALID_STATUS for details.
2698 *
2699 * @param pVM The cross context VM structure.
2700 * @param pPage The page descriptor.
2701 * @param GCPhys The physical address to start writing at.
2702 * @param pvBuf What to write.
2703 * @param cbWrite How much to write - less or equal to a page.
2704 * @param enmOrigin The origin of this call.
2705 */
2706static VBOXSTRICTRC pgmPhysWriteHandler(PVMCC pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void const *pvBuf, size_t cbWrite,
2707 PGMACCESSORIGIN enmOrigin)
2708{
2709 PGMPAGEMAPLOCK PgMpLck;
2710 void *pvDst = NULL;
2711 VBOXSTRICTRC rcStrict;
2712
2713 /*
2714 * Give priority to physical handlers (like #PF does).
2715 *
2716 * Hope for a lonely physical handler first that covers the whole write
2717 * area. This should be a pretty frequent case with MMIO and the heavy
2718 * usage of full page handlers in the page pool.
2719 */
2720 PVMCPUCC pVCpu = VMMGetCpu(pVM);
2721 PPGMPHYSHANDLER pCur;
2722 rcStrict = pgmHandlerPhysicalLookup(pVM, GCPhys, &pCur);
2723 if (RT_SUCCESS(rcStrict))
2724 {
2725 Assert(GCPhys >= pCur->Key && GCPhys <= pCur->KeyLast);
2726#ifndef IN_RING3
2727 if (enmOrigin != PGMACCESSORIGIN_IEM)
2728 /* Cannot reliably handle informational status codes in this context */
2729 return VERR_PGM_PHYS_WR_HIT_HANDLER;
2730#endif
2731 size_t cbRange = pCur->KeyLast - GCPhys + 1;
2732 if (cbRange > cbWrite)
2733 cbRange = cbWrite;
2734
2735 Assert(PGMPHYSHANDLER_GET_TYPE(pVM, pCur)->pfnHandler);
2736 Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n",
2737 GCPhys, cbRange, pPage, R3STRING(pCur->pszDesc) ));
2738 if (!PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))
2739 rcStrict = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &pvDst, &PgMpLck);
2740 else
2741 rcStrict = VINF_SUCCESS;
2742 if (RT_SUCCESS(rcStrict))
2743 {
2744 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pCur);
2745 PFNPGMPHYSHANDLER const pfnHandler = pCurType->pfnHandler;
2746 uint64_t const uUser = !pCurType->fRing0DevInsIdx ? pCur->uUser
2747 : (uintptr_t)PDMDeviceRing0IdxToInstance(pVM, pCur->uUser);
2748 STAM_PROFILE_START(&pCur->Stat, h);
2749
2750 /* Most handlers will want to release the PGM lock for deadlock prevention
2751 (esp. MMIO), though some PGM internal ones like the page pool and MMIO2
2752 dirty page trackers will want to keep it for performance reasons. */
2753 PGM_LOCK_ASSERT_OWNER(pVM);
2754 if (pCurType->fKeepPgmLock)
2755 rcStrict = pfnHandler(pVM, pVCpu, GCPhys, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, enmOrigin, uUser);
2756 else
2757 {
2758 PGM_UNLOCK(pVM);
2759 rcStrict = pfnHandler(pVM, pVCpu, GCPhys, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, enmOrigin, uUser);
2760 PGM_LOCK_VOID(pVM);
2761 }
2762
2763 STAM_PROFILE_STOP(&pCur->Stat, h); /* no locking needed, entry is unlikely reused before we get here. */
2764 pCur = NULL; /* might not be valid anymore. */
2765 if (rcStrict == VINF_PGM_HANDLER_DO_DEFAULT)
2766 {
2767 if (pvDst)
2768 memcpy(pvDst, pvBuf, cbRange);
2769 rcStrict = VINF_SUCCESS;
2770 }
2771 else
2772 AssertLogRelMsg(PGM_HANDLER_PHYS_IS_VALID_STATUS(rcStrict, true),
2773 ("rcStrict=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n",
2774 VBOXSTRICTRC_VAL(rcStrict), GCPhys, pPage, pCur ? R3STRING(pCur->pszDesc) : ""));
2775 }
2776 else
2777 AssertLogRelMsgFailedReturn(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
2778 GCPhys, pPage, VBOXSTRICTRC_VAL(rcStrict)), rcStrict);
2779 if (RT_LIKELY(cbRange == cbWrite) || !PGM_PHYS_RW_IS_SUCCESS(rcStrict))
2780 {
2781 if (pvDst)
2782 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2783 return rcStrict;
2784 }
2785
2786 /* more fun to be had below */
2787 cbWrite -= cbRange;
2788 GCPhys += cbRange;
2789 pvBuf = (uint8_t *)pvBuf + cbRange;
2790 pvDst = (uint8_t *)pvDst + cbRange;
2791 }
2792 else if (rcStrict == VERR_NOT_FOUND) /* The handler is somewhere else in the page, deal with it below. */
2793 rcStrict = VINF_SUCCESS;
2794 else
2795 AssertMsgFailedReturn(("rcStrict=%Rrc GCPhys=%RGp\n", VBOXSTRICTRC_VAL(rcStrict), GCPhys), rcStrict);
2796 Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)); /* MMIO handlers are all GUEST_PAGE_SIZEed! */
2797
2798 /*
2799 * Deal with all the odd ends (used to be deal with virt+phys).
2800 */
2801 Assert(rcStrict != VINF_PGM_HANDLER_DO_DEFAULT);
2802
2803 /* We need a writable destination page. */
2804 if (!pvDst)
2805 {
2806 int rc2 = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &pvDst, &PgMpLck);
2807 AssertLogRelMsgReturn(RT_SUCCESS(rc2),
2808 ("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n", GCPhys, pPage, rc2),
2809 rc2);
2810 }
2811
2812 /** @todo clean up this code some more now there are no virtual handlers any
2813 * more. */
2814 /* The loop state (big + ugly). */
2815 PPGMPHYSHANDLER pPhys = NULL;
2816 uint32_t offPhys = GUEST_PAGE_SIZE;
2817 uint32_t offPhysLast = GUEST_PAGE_SIZE;
2818 bool fMorePhys = PGM_PAGE_HAS_ACTIVE_PHYSICAL_HANDLERS(pPage);
2819
2820 /* The loop. */
2821 for (;;)
2822 {
2823 if (fMorePhys && !pPhys)
2824 {
2825 rcStrict = pgmHandlerPhysicalLookup(pVM, GCPhys, &pPhys);
2826 if (RT_SUCCESS_NP(rcStrict))
2827 {
2828 offPhys = 0;
2829 offPhysLast = pPhys->KeyLast - GCPhys; /* ASSUMES < 4GB handlers... */
2830 }
2831 else
2832 {
2833 AssertMsgReturn(rcStrict == VERR_NOT_FOUND, ("%Rrc GCPhys=%RGp\n", VBOXSTRICTRC_VAL(rcStrict), GCPhys), rcStrict);
2834
2835 rcStrict = pVM->VMCC_CTX(pgm).s.pPhysHandlerTree->lookupMatchingOrAbove(&pVM->VMCC_CTX(pgm).s.PhysHandlerAllocator,
2836 GCPhys, &pPhys);
2837 AssertMsgReturn(RT_SUCCESS(rcStrict) || rcStrict == VERR_NOT_FOUND,
2838 ("%Rrc GCPhys=%RGp\n", VBOXSTRICTRC_VAL(rcStrict), GCPhys), rcStrict);
2839
2840 if ( RT_SUCCESS(rcStrict)
2841 && pPhys->Key <= GCPhys + (cbWrite - 1))
2842 {
2843 offPhys = pPhys->Key - GCPhys;
2844 offPhysLast = pPhys->KeyLast - GCPhys; /* ASSUMES < 4GB handlers... */
2845 Assert(pPhys->KeyLast - pPhys->Key < _4G);
2846 }
2847 else
2848 {
2849 pPhys = NULL;
2850 fMorePhys = false;
2851 offPhys = offPhysLast = GUEST_PAGE_SIZE;
2852 }
2853 }
2854 }
2855
2856 /*
2857 * Handle access to space without handlers (that's easy).
2858 */
2859 VBOXSTRICTRC rcStrict2 = VINF_PGM_HANDLER_DO_DEFAULT;
2860 uint32_t cbRange = (uint32_t)cbWrite;
2861 Assert(cbRange == cbWrite);
2862
2863 /*
2864 * Physical handler.
2865 */
2866 if (!offPhys)
2867 {
2868#ifndef IN_RING3
2869 if (enmOrigin != PGMACCESSORIGIN_IEM)
2870 /* Cannot reliably handle informational status codes in this context */
2871 return VERR_PGM_PHYS_WR_HIT_HANDLER;
2872#endif
2873 if (cbRange > offPhysLast + 1)
2874 cbRange = offPhysLast + 1;
2875
2876 PCPGMPHYSHANDLERTYPEINT const pCurType = PGMPHYSHANDLER_GET_TYPE_NO_NULL(pVM, pPhys);
2877 PFNPGMPHYSHANDLER const pfnHandler = pCurType->pfnHandler;
2878 uint64_t const uUser = !pCurType->fRing0DevInsIdx ? pPhys->uUser
2879 : (uintptr_t)PDMDeviceRing0IdxToInstance(pVM, pPhys->uUser);
2880
2881 Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cbRange, pPage, R3STRING(pPhys->pszDesc) ));
2882 STAM_PROFILE_START(&pPhys->Stat, h);
2883
2884 /* Most handlers will want to release the PGM lock for deadlock prevention
2885 (esp. MMIO), though some PGM internal ones like the page pool and MMIO2
2886 dirty page trackers will want to keep it for performance reasons. */
2887 PGM_LOCK_ASSERT_OWNER(pVM);
2888 if (pCurType->fKeepPgmLock)
2889 rcStrict2 = pfnHandler(pVM, pVCpu, GCPhys, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, enmOrigin, uUser);
2890 else
2891 {
2892 PGM_UNLOCK(pVM);
2893 rcStrict2 = pfnHandler(pVM, pVCpu, GCPhys, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, enmOrigin, uUser);
2894 PGM_LOCK_VOID(pVM);
2895 }
2896
2897 STAM_PROFILE_STOP(&pPhys->Stat, h); /* no locking needed, entry is unlikely reused before we get here. */
2898 pPhys = NULL; /* might not be valid anymore. */
2899 AssertLogRelMsg(PGM_HANDLER_PHYS_IS_VALID_STATUS(rcStrict2, true),
2900 ("rcStrict2=%Rrc (rcStrict=%Rrc) GCPhys=%RGp pPage=%R[pgmpage] %s\n", VBOXSTRICTRC_VAL(rcStrict2),
2901 VBOXSTRICTRC_VAL(rcStrict), GCPhys, pPage, pPhys ? R3STRING(pPhys->pszDesc) : ""));
2902 }
2903
2904 /*
2905 * Execute the default action and merge the status codes.
2906 */
2907 if (rcStrict2 == VINF_PGM_HANDLER_DO_DEFAULT)
2908 {
2909 memcpy(pvDst, pvBuf, cbRange);
2910 rcStrict2 = VINF_SUCCESS;
2911 }
2912 else if (!PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
2913 {
2914 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2915 return rcStrict2;
2916 }
2917 else
2918 PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
2919
2920 /*
2921 * Advance if we've got more stuff to do.
2922 */
2923 if (cbRange >= cbWrite)
2924 {
2925 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
2926 return rcStrict;
2927 }
2928
2929
2930 cbWrite -= cbRange;
2931 GCPhys += cbRange;
2932 pvBuf = (uint8_t *)pvBuf + cbRange;
2933 pvDst = (uint8_t *)pvDst + cbRange;
2934
2935 offPhys -= cbRange;
2936 offPhysLast -= cbRange;
2937 }
2938}
2939
2940
2941/**
2942 * Write to physical memory.
2943 *
2944 * This API respects access handlers and MMIO. Use PGMPhysSimpleWriteGCPhys() if you
2945 * want to ignore those.
2946 *
2947 * @returns Strict VBox status code in raw-mode and ring-0, normal VBox status
2948 * code in ring-3. Use PGM_PHYS_RW_IS_SUCCESS to check.
2949 * @retval VINF_SUCCESS in all context - write completed.
2950 *
2951 * @retval VINF_EM_OFF in RC and R0 - write completed.
2952 * @retval VINF_EM_SUSPEND in RC and R0 - write completed.
2953 * @retval VINF_EM_RESET in RC and R0 - write completed.
2954 * @retval VINF_EM_HALT in RC and R0 - write completed.
2955 * @retval VINF_SELM_SYNC_GDT in RC only - write completed.
2956 *
2957 * @retval VINF_EM_DBG_STOP in RC and R0 - write completed.
2958 * @retval VINF_EM_DBG_BREAKPOINT in RC and R0 - write completed.
2959 * @retval VINF_EM_RAW_EMULATE_INSTR in RC and R0 only.
2960 *
2961 * @retval VINF_IOM_R3_MMIO_WRITE in RC and R0.
2962 * @retval VINF_IOM_R3_MMIO_READ_WRITE in RC and R0.
2963 * @retval VINF_IOM_R3_MMIO_COMMIT_WRITE in RC and R0.
2964 *
2965 * @retval VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT in RC only - write completed.
2966 * @retval VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT in RC only.
2967 * @retval VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT in RC only.
2968 * @retval VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT in RC only.
2969 * @retval VINF_CSAM_PENDING_ACTION in RC only.
2970 * @retval VINF_PATM_CHECK_PATCH_PAGE in RC only.
2971 *
2972 * @retval VERR_PGM_PHYS_WR_HIT_HANDLER in RC and R0 for access origins that
2973 * haven't been cleared for strict status codes yet.
2974 *
2975 *
2976 * @param pVM The cross context VM structure.
2977 * @param GCPhys Physical address to write to.
2978 * @param pvBuf What to write.
2979 * @param cbWrite How many bytes to write.
2980 * @param enmOrigin Who is calling.
2981 */
2982VMMDECL(VBOXSTRICTRC) PGMPhysWrite(PVMCC pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin)
2983{
2984 AssertMsg(!pVM->pgm.s.fNoMorePhysWrites, ("Calling PGMPhysWrite after pgmR3Save()! enmOrigin=%d\n", enmOrigin));
2985 AssertMsgReturn(cbWrite > 0, ("don't even think about writing zero bytes!\n"), VINF_SUCCESS);
2986 LogFlow(("PGMPhysWrite: %RGp %d\n", GCPhys, cbWrite));
2987
2988 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysWrite));
2989 STAM_COUNTER_ADD(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysWriteBytes), cbWrite);
2990
2991 PGM_LOCK_VOID(pVM);
2992
2993 /*
2994 * Copy loop on ram ranges.
2995 */
2996 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2997 PPGMRAMRANGE pRam = pgmPhysGetRangeAtOrAbove(pVM, GCPhys);
2998 for (;;)
2999 {
3000 /* Inside range or not? */
3001 if (pRam && GCPhys >= pRam->GCPhys)
3002 {
3003 /*
3004 * Must work our way thru this page by page.
3005 */
3006 RTGCPTR off = GCPhys - pRam->GCPhys;
3007 while (off < pRam->cb)
3008 {
3009 RTGCPTR iPage = off >> GUEST_PAGE_SHIFT;
3010 PPGMPAGE pPage = &pRam->aPages[iPage];
3011 size_t cb = GUEST_PAGE_SIZE - (off & GUEST_PAGE_OFFSET_MASK);
3012 if (cb > cbWrite)
3013 cb = cbWrite;
3014
3015 /*
3016 * Normal page? Get the pointer to it.
3017 */
3018 if ( !PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)
3019 && !PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
3020 {
3021 PGMPAGEMAPLOCK PgMpLck;
3022 void *pvDst;
3023 int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pRam->GCPhys + off, &pvDst, &PgMpLck);
3024 if (RT_SUCCESS(rc))
3025 {
3026 Assert(!PGM_PAGE_IS_BALLOONED(pPage));
3027 memcpy(pvDst, pvBuf, cb);
3028 pgmPhysReleaseInternalPageMappingLock(pVM, &PgMpLck);
3029 }
3030 /* Ignore writes to ballooned pages. */
3031 else if (!PGM_PAGE_IS_BALLOONED(pPage))
3032 AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
3033 pRam->GCPhys + off, pPage, rc));
3034 }
3035 /*
3036 * Active WRITE or ALL access handlers.
3037 */
3038 else
3039 {
3040 VBOXSTRICTRC rcStrict2 = pgmPhysWriteHandler(pVM, pPage, pRam->GCPhys + off, pvBuf, cb, enmOrigin);
3041 if (PGM_PHYS_RW_IS_SUCCESS(rcStrict2))
3042 PGM_PHYS_RW_DO_UPDATE_STRICT_RC(rcStrict, rcStrict2);
3043 else
3044 {
3045 PGM_UNLOCK(pVM);
3046 return rcStrict2;
3047 }
3048 }
3049
3050 /* next page */
3051 if (cb >= cbWrite)
3052 {
3053 PGM_UNLOCK(pVM);
3054 return rcStrict;
3055 }
3056
3057 cbWrite -= cb;
3058 off += cb;
3059 pvBuf = (const char *)pvBuf + cb;
3060 } /* walk pages in ram range */
3061
3062 GCPhys = pRam->GCPhysLast + 1;
3063 }
3064 else
3065 {
3066 /*
3067 * Unassigned address space, skip it.
3068 */
3069 if (!pRam)
3070 break;
3071 size_t cb = pRam->GCPhys - GCPhys;
3072 if (cb >= cbWrite)
3073 break;
3074 cbWrite -= cb;
3075 pvBuf = (const char *)pvBuf + cb;
3076 GCPhys += cb;
3077 }
3078
3079 /* Advance range if necessary. */
3080 while (pRam && GCPhys > pRam->GCPhysLast)
3081 pRam = pRam->CTX_SUFF(pNext);
3082 } /* Ram range walk */
3083
3084 PGM_UNLOCK(pVM);
3085 return rcStrict;
3086}
3087
3088
3089/**
3090 * Read from guest physical memory by GC physical address, bypassing
3091 * MMIO and access handlers.
3092 *
3093 * @returns VBox status code.
3094 * @param pVM The cross context VM structure.
3095 * @param pvDst The destination address.
3096 * @param GCPhysSrc The source address (GC physical address).
3097 * @param cb The number of bytes to read.
3098 */
3099VMMDECL(int) PGMPhysSimpleReadGCPhys(PVMCC pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb)
3100{
3101 /*
3102 * Treat the first page as a special case.
3103 */
3104 if (!cb)
3105 return VINF_SUCCESS;
3106
3107 /* map the 1st page */
3108 void const *pvSrc;
3109 PGMPAGEMAPLOCK Lock;
3110 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhysSrc, &pvSrc, &Lock);
3111 if (RT_FAILURE(rc))
3112 return rc;
3113
3114 /* optimize for the case where access is completely within the first page. */
3115 size_t cbPage = GUEST_PAGE_SIZE - (GCPhysSrc & GUEST_PAGE_OFFSET_MASK);
3116 if (RT_LIKELY(cb <= cbPage))
3117 {
3118 memcpy(pvDst, pvSrc, cb);
3119 PGMPhysReleasePageMappingLock(pVM, &Lock);
3120 return VINF_SUCCESS;
3121 }
3122
3123 /* copy to the end of the page. */
3124 memcpy(pvDst, pvSrc, cbPage);
3125 PGMPhysReleasePageMappingLock(pVM, &Lock);
3126 GCPhysSrc += cbPage;
3127 pvDst = (uint8_t *)pvDst + cbPage;
3128 cb -= cbPage;
3129
3130 /*
3131 * Page by page.
3132 */
3133 for (;;)
3134 {
3135 /* map the page */
3136 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhysSrc, &pvSrc, &Lock);
3137 if (RT_FAILURE(rc))
3138 return rc;
3139
3140 /* last page? */
3141 if (cb <= GUEST_PAGE_SIZE)
3142 {
3143 memcpy(pvDst, pvSrc, cb);
3144 PGMPhysReleasePageMappingLock(pVM, &Lock);
3145 return VINF_SUCCESS;
3146 }
3147
3148 /* copy the entire page and advance */
3149 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3150 PGMPhysReleasePageMappingLock(pVM, &Lock);
3151 GCPhysSrc += GUEST_PAGE_SIZE;
3152 pvDst = (uint8_t *)pvDst + GUEST_PAGE_SIZE;
3153 cb -= GUEST_PAGE_SIZE;
3154 }
3155 /* won't ever get here. */
3156}
3157
3158
3159/**
3160 * Write to guest physical memory referenced by GC pointer.
3161 * Write memory to GC physical address in guest physical memory.
3162 *
3163 * This will bypass MMIO and access handlers.
3164 *
3165 * @returns VBox status code.
3166 * @param pVM The cross context VM structure.
3167 * @param GCPhysDst The GC physical address of the destination.
3168 * @param pvSrc The source buffer.
3169 * @param cb The number of bytes to write.
3170 */
3171VMMDECL(int) PGMPhysSimpleWriteGCPhys(PVMCC pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb)
3172{
3173 LogFlow(("PGMPhysSimpleWriteGCPhys: %RGp %zu\n", GCPhysDst, cb));
3174
3175 /*
3176 * Treat the first page as a special case.
3177 */
3178 if (!cb)
3179 return VINF_SUCCESS;
3180
3181 /* map the 1st page */
3182 void *pvDst;
3183 PGMPAGEMAPLOCK Lock;
3184 int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysDst, &pvDst, &Lock);
3185 if (RT_FAILURE(rc))
3186 return rc;
3187
3188 /* optimize for the case where access is completely within the first page. */
3189 size_t cbPage = GUEST_PAGE_SIZE - (GCPhysDst & GUEST_PAGE_OFFSET_MASK);
3190 if (RT_LIKELY(cb <= cbPage))
3191 {
3192 memcpy(pvDst, pvSrc, cb);
3193 PGMPhysReleasePageMappingLock(pVM, &Lock);
3194 return VINF_SUCCESS;
3195 }
3196
3197 /* copy to the end of the page. */
3198 memcpy(pvDst, pvSrc, cbPage);
3199 PGMPhysReleasePageMappingLock(pVM, &Lock);
3200 GCPhysDst += cbPage;
3201 pvSrc = (const uint8_t *)pvSrc + cbPage;
3202 cb -= cbPage;
3203
3204 /*
3205 * Page by page.
3206 */
3207 for (;;)
3208 {
3209 /* map the page */
3210 rc = PGMPhysGCPhys2CCPtr(pVM, GCPhysDst, &pvDst, &Lock);
3211 if (RT_FAILURE(rc))
3212 return rc;
3213
3214 /* last page? */
3215 if (cb <= GUEST_PAGE_SIZE)
3216 {
3217 memcpy(pvDst, pvSrc, cb);
3218 PGMPhysReleasePageMappingLock(pVM, &Lock);
3219 return VINF_SUCCESS;
3220 }
3221
3222 /* copy the entire page and advance */
3223 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3224 PGMPhysReleasePageMappingLock(pVM, &Lock);
3225 GCPhysDst += GUEST_PAGE_SIZE;
3226 pvSrc = (const uint8_t *)pvSrc + GUEST_PAGE_SIZE;
3227 cb -= GUEST_PAGE_SIZE;
3228 }
3229 /* won't ever get here. */
3230}
3231
3232
3233/**
3234 * Read from guest physical memory referenced by GC pointer.
3235 *
3236 * This function uses the current CR3/CR0/CR4 of the guest and will
3237 * bypass access handlers and not set any accessed bits.
3238 *
3239 * @returns VBox status code.
3240 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3241 * @param pvDst The destination address.
3242 * @param GCPtrSrc The source address (GC pointer).
3243 * @param cb The number of bytes to read.
3244 */
3245VMMDECL(int) PGMPhysSimpleReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb)
3246{
3247 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3248/** @todo fix the macro / state handling: VMCPU_ASSERT_EMT_OR_GURU(pVCpu); */
3249
3250 /*
3251 * Treat the first page as a special case.
3252 */
3253 if (!cb)
3254 return VINF_SUCCESS;
3255
3256 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysSimpleRead));
3257 STAM_COUNTER_ADD(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysSimpleReadBytes), cb);
3258
3259 /* Take the PGM lock here, because many called functions take the lock for a very short period. That's counter-productive
3260 * when many VCPUs are fighting for the lock.
3261 */
3262 PGM_LOCK_VOID(pVM);
3263
3264 /* map the 1st page */
3265 void const *pvSrc;
3266 PGMPAGEMAPLOCK Lock;
3267 int rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, GCPtrSrc, &pvSrc, &Lock);
3268 if (RT_FAILURE(rc))
3269 {
3270 PGM_UNLOCK(pVM);
3271 return rc;
3272 }
3273
3274 /* optimize for the case where access is completely within the first page. */
3275 size_t cbPage = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
3276 if (RT_LIKELY(cb <= cbPage))
3277 {
3278 memcpy(pvDst, pvSrc, cb);
3279 PGMPhysReleasePageMappingLock(pVM, &Lock);
3280 PGM_UNLOCK(pVM);
3281 return VINF_SUCCESS;
3282 }
3283
3284 /* copy to the end of the page. */
3285 memcpy(pvDst, pvSrc, cbPage);
3286 PGMPhysReleasePageMappingLock(pVM, &Lock);
3287 GCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCPtrSrc + cbPage);
3288 pvDst = (uint8_t *)pvDst + cbPage;
3289 cb -= cbPage;
3290
3291 /*
3292 * Page by page.
3293 */
3294 for (;;)
3295 {
3296 /* map the page */
3297 rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, GCPtrSrc, &pvSrc, &Lock);
3298 if (RT_FAILURE(rc))
3299 {
3300 PGM_UNLOCK(pVM);
3301 return rc;
3302 }
3303
3304 /* last page? */
3305 if (cb <= GUEST_PAGE_SIZE)
3306 {
3307 memcpy(pvDst, pvSrc, cb);
3308 PGMPhysReleasePageMappingLock(pVM, &Lock);
3309 PGM_UNLOCK(pVM);
3310 return VINF_SUCCESS;
3311 }
3312
3313 /* copy the entire page and advance */
3314 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3315 PGMPhysReleasePageMappingLock(pVM, &Lock);
3316 GCPtrSrc = (RTGCPTR)((RTGCUINTPTR)GCPtrSrc + GUEST_PAGE_SIZE);
3317 pvDst = (uint8_t *)pvDst + GUEST_PAGE_SIZE;
3318 cb -= GUEST_PAGE_SIZE;
3319 }
3320 /* won't ever get here. */
3321}
3322
3323
3324/**
3325 * Write to guest physical memory referenced by GC pointer.
3326 *
3327 * This function uses the current CR3/CR0/CR4 of the guest and will
3328 * bypass access handlers and not set dirty or accessed bits.
3329 *
3330 * @returns VBox status code.
3331 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3332 * @param GCPtrDst The destination address (GC pointer).
3333 * @param pvSrc The source address.
3334 * @param cb The number of bytes to write.
3335 */
3336VMMDECL(int) PGMPhysSimpleWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
3337{
3338 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3339 VMCPU_ASSERT_EMT(pVCpu);
3340
3341 /*
3342 * Treat the first page as a special case.
3343 */
3344 if (!cb)
3345 return VINF_SUCCESS;
3346
3347 STAM_COUNTER_INC(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysSimpleWrite));
3348 STAM_COUNTER_ADD(&pVM->pgm.s.Stats.CTX_MID_Z(Stat,PhysSimpleWriteBytes), cb);
3349
3350 /* map the 1st page */
3351 void *pvDst;
3352 PGMPAGEMAPLOCK Lock;
3353 int rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);
3354 if (RT_FAILURE(rc))
3355 return rc;
3356
3357 /* optimize for the case where access is completely within the first page. */
3358 size_t cbPage = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3359 if (RT_LIKELY(cb <= cbPage))
3360 {
3361 memcpy(pvDst, pvSrc, cb);
3362 PGMPhysReleasePageMappingLock(pVM, &Lock);
3363 return VINF_SUCCESS;
3364 }
3365
3366 /* copy to the end of the page. */
3367 memcpy(pvDst, pvSrc, cbPage);
3368 PGMPhysReleasePageMappingLock(pVM, &Lock);
3369 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbPage);
3370 pvSrc = (const uint8_t *)pvSrc + cbPage;
3371 cb -= cbPage;
3372
3373 /*
3374 * Page by page.
3375 */
3376 for (;;)
3377 {
3378 /* map the page */
3379 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);
3380 if (RT_FAILURE(rc))
3381 return rc;
3382
3383 /* last page? */
3384 if (cb <= GUEST_PAGE_SIZE)
3385 {
3386 memcpy(pvDst, pvSrc, cb);
3387 PGMPhysReleasePageMappingLock(pVM, &Lock);
3388 return VINF_SUCCESS;
3389 }
3390
3391 /* copy the entire page and advance */
3392 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3393 PGMPhysReleasePageMappingLock(pVM, &Lock);
3394 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + GUEST_PAGE_SIZE);
3395 pvSrc = (const uint8_t *)pvSrc + GUEST_PAGE_SIZE;
3396 cb -= GUEST_PAGE_SIZE;
3397 }
3398 /* won't ever get here. */
3399}
3400
3401
3402/**
3403 * Write to guest physical memory referenced by GC pointer and update the PTE.
3404 *
3405 * This function uses the current CR3/CR0/CR4 of the guest and will
3406 * bypass access handlers but will set any dirty and accessed bits in the PTE.
3407 *
3408 * If you don't want to set the dirty bit, use PGMPhysSimpleWriteGCPtr().
3409 *
3410 * @returns VBox status code.
3411 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3412 * @param GCPtrDst The destination address (GC pointer).
3413 * @param pvSrc The source address.
3414 * @param cb The number of bytes to write.
3415 */
3416VMMDECL(int) PGMPhysSimpleDirtyWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
3417{
3418 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3419 VMCPU_ASSERT_EMT(pVCpu);
3420
3421 /*
3422 * Treat the first page as a special case.
3423 * Btw. this is the same code as in PGMPhyssimpleWriteGCPtr excep for the PGMGstModifyPage.
3424 */
3425 if (!cb)
3426 return VINF_SUCCESS;
3427
3428 /* map the 1st page */
3429 void *pvDst;
3430 PGMPAGEMAPLOCK Lock;
3431 int rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);
3432 if (RT_FAILURE(rc))
3433 return rc;
3434
3435 /* optimize for the case where access is completely within the first page. */
3436 size_t cbPage = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3437 if (RT_LIKELY(cb <= cbPage))
3438 {
3439 memcpy(pvDst, pvSrc, cb);
3440 PGMPhysReleasePageMappingLock(pVM, &Lock);
3441 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
3442 return VINF_SUCCESS;
3443 }
3444
3445 /* copy to the end of the page. */
3446 memcpy(pvDst, pvSrc, cbPage);
3447 PGMPhysReleasePageMappingLock(pVM, &Lock);
3448 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
3449 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + cbPage);
3450 pvSrc = (const uint8_t *)pvSrc + cbPage;
3451 cb -= cbPage;
3452
3453 /*
3454 * Page by page.
3455 */
3456 for (;;)
3457 {
3458 /* map the page */
3459 rc = PGMPhysGCPtr2CCPtr(pVCpu, GCPtrDst, &pvDst, &Lock);
3460 if (RT_FAILURE(rc))
3461 return rc;
3462
3463 /* last page? */
3464 if (cb <= GUEST_PAGE_SIZE)
3465 {
3466 memcpy(pvDst, pvSrc, cb);
3467 PGMPhysReleasePageMappingLock(pVM, &Lock);
3468 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
3469 return VINF_SUCCESS;
3470 }
3471
3472 /* copy the entire page and advance */
3473 memcpy(pvDst, pvSrc, GUEST_PAGE_SIZE);
3474 PGMPhysReleasePageMappingLock(pVM, &Lock);
3475 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
3476 GCPtrDst = (RTGCPTR)((RTGCUINTPTR)GCPtrDst + GUEST_PAGE_SIZE);
3477 pvSrc = (const uint8_t *)pvSrc + GUEST_PAGE_SIZE;
3478 cb -= GUEST_PAGE_SIZE;
3479 }
3480 /* won't ever get here. */
3481}
3482
3483
3484/**
3485 * Read from guest physical memory referenced by GC pointer.
3486 *
3487 * This function uses the current CR3/CR0/CR4 of the guest and will
3488 * respect access handlers and set accessed bits.
3489 *
3490 * @returns Strict VBox status, see PGMPhysRead for details.
3491 * @retval VERR_PAGE_TABLE_NOT_PRESENT if there is no page mapped at the
3492 * specified virtual address.
3493 *
3494 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3495 * @param pvDst The destination address.
3496 * @param GCPtrSrc The source address (GC pointer).
3497 * @param cb The number of bytes to read.
3498 * @param enmOrigin Who is calling.
3499 * @thread EMT(pVCpu)
3500 */
3501VMMDECL(VBOXSTRICTRC) PGMPhysReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, PGMACCESSORIGIN enmOrigin)
3502{
3503 int rc;
3504 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3505 VMCPU_ASSERT_EMT(pVCpu);
3506
3507 /*
3508 * Anything to do?
3509 */
3510 if (!cb)
3511 return VINF_SUCCESS;
3512
3513 LogFlow(("PGMPhysReadGCPtr: %RGv %zu\n", GCPtrSrc, cb));
3514
3515 /*
3516 * Optimize reads within a single page.
3517 */
3518 if (((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK) + cb <= GUEST_PAGE_SIZE)
3519 {
3520 /* Convert virtual to physical address + flags */
3521 PGMPTWALK Walk;
3522 rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtrSrc, &Walk);
3523 AssertMsgRCReturn(rc, ("GetPage failed with %Rrc for %RGv\n", rc, GCPtrSrc), rc);
3524 RTGCPHYS const GCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
3525
3526 /* mark the guest page as accessed. */
3527 if (!(Walk.fEffective & X86_PTE_A))
3528 {
3529 rc = PGMGstModifyPage(pVCpu, GCPtrSrc, 1, X86_PTE_A, ~(uint64_t)(X86_PTE_A));
3530 AssertRC(rc);
3531 }
3532
3533 return PGMPhysRead(pVM, GCPhys, pvDst, cb, enmOrigin);
3534 }
3535
3536 /*
3537 * Page by page.
3538 */
3539 for (;;)
3540 {
3541 /* Convert virtual to physical address + flags */
3542 PGMPTWALK Walk;
3543 rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtrSrc, &Walk);
3544 AssertMsgRCReturn(rc, ("GetPage failed with %Rrc for %RGv\n", rc, GCPtrSrc), rc);
3545 RTGCPHYS const GCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
3546
3547 /* mark the guest page as accessed. */
3548 if (!(Walk.fEffective & X86_PTE_A))
3549 {
3550 rc = PGMGstModifyPage(pVCpu, GCPtrSrc, 1, X86_PTE_A, ~(uint64_t)(X86_PTE_A));
3551 AssertRC(rc);
3552 }
3553
3554 /* copy */
3555 size_t cbRead = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrSrc & GUEST_PAGE_OFFSET_MASK);
3556 if (cbRead < cb)
3557 {
3558 VBOXSTRICTRC rcStrict = PGMPhysRead(pVM, GCPhys, pvDst, cbRead, enmOrigin);
3559 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
3560 { /* likely */ }
3561 else
3562 return rcStrict;
3563 }
3564 else /* Last page (cbRead is GUEST_PAGE_SIZE, we only need cb!) */
3565 return PGMPhysRead(pVM, GCPhys, pvDst, cb, enmOrigin);
3566
3567 /* next */
3568 Assert(cb > cbRead);
3569 cb -= cbRead;
3570 pvDst = (uint8_t *)pvDst + cbRead;
3571 GCPtrSrc += cbRead;
3572 }
3573}
3574
3575
3576/**
3577 * Write to guest physical memory referenced by GC pointer.
3578 *
3579 * This function uses the current CR3/CR0/CR4 of the guest and will
3580 * respect access handlers and set dirty and accessed bits.
3581 *
3582 * @returns Strict VBox status, see PGMPhysWrite for details.
3583 * @retval VERR_PAGE_TABLE_NOT_PRESENT if there is no page mapped at the
3584 * specified virtual address.
3585 *
3586 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
3587 * @param GCPtrDst The destination address (GC pointer).
3588 * @param pvSrc The source address.
3589 * @param cb The number of bytes to write.
3590 * @param enmOrigin Who is calling.
3591 */
3592VMMDECL(VBOXSTRICTRC) PGMPhysWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb, PGMACCESSORIGIN enmOrigin)
3593{
3594 int rc;
3595 PVMCC pVM = pVCpu->CTX_SUFF(pVM);
3596 VMCPU_ASSERT_EMT(pVCpu);
3597
3598 /*
3599 * Anything to do?
3600 */
3601 if (!cb)
3602 return VINF_SUCCESS;
3603
3604 LogFlow(("PGMPhysWriteGCPtr: %RGv %zu\n", GCPtrDst, cb));
3605
3606 /*
3607 * Optimize writes within a single page.
3608 */
3609 if (((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK) + cb <= GUEST_PAGE_SIZE)
3610 {
3611 /* Convert virtual to physical address + flags */
3612 PGMPTWALK Walk;
3613 rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtrDst, &Walk);
3614 AssertMsgRCReturn(rc, ("GetPage failed with %Rrc for %RGv\n", rc, GCPtrDst), rc);
3615 RTGCPHYS const GCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3616
3617 /* Mention when we ignore X86_PTE_RW... */
3618 if (!(Walk.fEffective & X86_PTE_RW))
3619 Log(("PGMPhysWriteGCPtr: Writing to RO page %RGv %#x\n", GCPtrDst, cb));
3620
3621 /* Mark the guest page as accessed and dirty if necessary. */
3622 if ((Walk.fEffective & (X86_PTE_A | X86_PTE_D)) != (X86_PTE_A | X86_PTE_D))
3623 {
3624 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
3625 AssertRC(rc);
3626 }
3627
3628 return PGMPhysWrite(pVM, GCPhys, pvSrc, cb, enmOrigin);
3629 }
3630
3631 /*
3632 * Page by page.
3633 */
3634 for (;;)
3635 {
3636 /* Convert virtual to physical address + flags */
3637 PGMPTWALK Walk;
3638 rc = PGMGstGetPage(pVCpu, (RTGCUINTPTR)GCPtrDst, &Walk);
3639 AssertMsgRCReturn(rc, ("GetPage failed with %Rrc for %RGv\n", rc, GCPtrDst), rc);
3640 RTGCPHYS const GCPhys = Walk.GCPhys | ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3641
3642 /* Mention when we ignore X86_PTE_RW... */
3643 if (!(Walk.fEffective & X86_PTE_RW))
3644 Log(("PGMPhysWriteGCPtr: Writing to RO page %RGv %#x\n", GCPtrDst, cb));
3645
3646 /* Mark the guest page as accessed and dirty if necessary. */
3647 if ((Walk.fEffective & (X86_PTE_A | X86_PTE_D)) != (X86_PTE_A | X86_PTE_D))
3648 {
3649 rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
3650 AssertRC(rc);
3651 }
3652
3653 /* copy */
3654 size_t cbWrite = GUEST_PAGE_SIZE - ((RTGCUINTPTR)GCPtrDst & GUEST_PAGE_OFFSET_MASK);
3655 if (cbWrite < cb)
3656 {
3657 VBOXSTRICTRC rcStrict = PGMPhysWrite(pVM, GCPhys, pvSrc, cbWrite, enmOrigin);
3658 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
3659 { /* likely */ }
3660 else
3661 return rcStrict;
3662 }
3663 else /* Last page (cbWrite is GUEST_PAGE_SIZE, we only need cb!) */
3664 return PGMPhysWrite(pVM, GCPhys, pvSrc, cb, enmOrigin);
3665
3666 /* next */
3667 Assert(cb > cbWrite);
3668 cb -= cbWrite;
3669 pvSrc = (uint8_t *)pvSrc + cbWrite;
3670 GCPtrDst += cbWrite;
3671 }
3672}
3673
3674
3675/**
3676 * Return the page type of the specified physical address.
3677 *
3678 * @returns The page type.
3679 * @param pVM The cross context VM structure.
3680 * @param GCPhys Guest physical address
3681 */
3682VMM_INT_DECL(PGMPAGETYPE) PGMPhysGetPageType(PVMCC pVM, RTGCPHYS GCPhys)
3683{
3684 PGM_LOCK_VOID(pVM);
3685 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
3686 PGMPAGETYPE enmPgType = pPage ? (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage) : PGMPAGETYPE_INVALID;
3687 PGM_UNLOCK(pVM);
3688
3689 return enmPgType;
3690}
3691
3692
3693/**
3694 * Converts a GC physical address to a HC ring-3 pointer, with some
3695 * additional checks.
3696 *
3697 * @returns VBox status code (no informational statuses).
3698 *
3699 * @param pVM The cross context VM structure.
3700 * @param pVCpu The cross context virtual CPU structure of the
3701 * calling EMT.
3702 * @param GCPhys The GC physical address to convert. This API mask
3703 * the A20 line when necessary.
3704 * @param puTlbPhysRev Where to read the physical TLB revision. Needs to
3705 * be done while holding the PGM lock.
3706 * @param ppb Where to store the pointer corresponding to GCPhys
3707 * on success.
3708 * @param pfTlb The TLB flags and revision. We only add stuff.
3709 *
3710 * @remarks This is more or a less a copy of PGMR3PhysTlbGCPhys2Ptr and
3711 * PGMPhysIemGCPhys2Ptr.
3712 *
3713 * @thread EMT(pVCpu).
3714 */
3715VMM_INT_DECL(int) PGMPhysIemGCPhys2PtrNoLock(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, uint64_t const volatile *puTlbPhysRev,
3716 R3R0PTRTYPE(uint8_t *) *ppb,
3717 uint64_t *pfTlb)
3718{
3719 PGM_A20_APPLY_TO_VAR(pVCpu, GCPhys);
3720 Assert(!(GCPhys & X86_PAGE_OFFSET_MASK));
3721
3722 PGM_LOCK_VOID(pVM);
3723
3724 PPGMRAMRANGE pRam;
3725 PPGMPAGE pPage;
3726 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
3727 if (RT_SUCCESS(rc))
3728 {
3729 if (!PGM_PAGE_IS_BALLOONED(pPage))
3730 {
3731 if (!PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
3732 {
3733 if (!PGM_PAGE_HAS_ANY_HANDLERS(pPage))
3734 {
3735 /*
3736 * No access handler.
3737 */
3738 switch (PGM_PAGE_GET_STATE(pPage))
3739 {
3740 case PGM_PAGE_STATE_ALLOCATED:
3741 *pfTlb |= *puTlbPhysRev;
3742 break;
3743 case PGM_PAGE_STATE_BALLOONED:
3744 AssertFailed();
3745 RT_FALL_THRU();
3746 case PGM_PAGE_STATE_ZERO:
3747 case PGM_PAGE_STATE_SHARED:
3748 case PGM_PAGE_STATE_WRITE_MONITORED:
3749 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE;
3750 break;
3751 }
3752
3753 PPGMPAGEMAPTLBE pTlbe;
3754 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
3755 AssertLogRelRCReturn(rc, rc);
3756 *ppb = (uint8_t *)pTlbe->pv;
3757 }
3758 else if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))
3759 {
3760 /*
3761 * MMIO or similar all access handler: Catch all access.
3762 */
3763 *pfTlb |= *puTlbPhysRev
3764 | PGMIEMGCPHYS2PTR_F_NO_WRITE | PGMIEMGCPHYS2PTR_F_NO_READ | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3;
3765 *ppb = NULL;
3766 }
3767 else
3768 {
3769 /*
3770 * Write access handler: Catch write accesses if active.
3771 */
3772 if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage))
3773 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE;
3774 else
3775 switch (PGM_PAGE_GET_STATE(pPage))
3776 {
3777 case PGM_PAGE_STATE_ALLOCATED:
3778 *pfTlb |= *puTlbPhysRev;
3779 break;
3780 case PGM_PAGE_STATE_BALLOONED:
3781 AssertFailed();
3782 RT_FALL_THRU();
3783 case PGM_PAGE_STATE_ZERO:
3784 case PGM_PAGE_STATE_SHARED:
3785 case PGM_PAGE_STATE_WRITE_MONITORED:
3786 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE;
3787 break;
3788 }
3789
3790 PPGMPAGEMAPTLBE pTlbe;
3791 rc = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
3792 AssertLogRelRCReturn(rc, rc);
3793 *ppb = (uint8_t *)pTlbe->pv;
3794 }
3795 }
3796 else
3797 {
3798 /* Alias MMIO: For now, we catch all access. */
3799 *pfTlb |= *puTlbPhysRev
3800 | PGMIEMGCPHYS2PTR_F_NO_WRITE | PGMIEMGCPHYS2PTR_F_NO_READ | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3;
3801 *ppb = NULL;
3802 }
3803 }
3804 else
3805 {
3806 /* Ballooned: Shouldn't get here, but we read zero page via PGMPhysRead and writes goes to /dev/null. */
3807 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE | PGMIEMGCPHYS2PTR_F_NO_READ | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3;
3808 *ppb = NULL;
3809 }
3810 Log6(("PGMPhysIemGCPhys2PtrNoLock: GCPhys=%RGp *ppb=%p *pfTlb=%#RX64 pPage=%R[pgmpage]\n", GCPhys, *ppb, *pfTlb, pPage));
3811 }
3812 else
3813 {
3814 *pfTlb |= *puTlbPhysRev | PGMIEMGCPHYS2PTR_F_NO_WRITE | PGMIEMGCPHYS2PTR_F_NO_READ
3815 | PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 | PGMIEMGCPHYS2PTR_F_UNASSIGNED;
3816 *ppb = NULL;
3817 Log6(("PGMPhysIemGCPhys2PtrNoLock: GCPhys=%RGp *ppb=%p *pfTlb=%#RX64 (rc=%Rrc)\n", GCPhys, *ppb, *pfTlb, rc));
3818 }
3819
3820 PGM_UNLOCK(pVM);
3821 return VINF_SUCCESS;
3822}
3823
3824
3825/**
3826 * Converts a GC physical address to a HC ring-3 pointer, with some
3827 * additional checks.
3828 *
3829 * @returns VBox status code (no informational statuses).
3830 * @retval VINF_SUCCESS on success.
3831 * @retval VERR_PGM_PHYS_TLB_CATCH_WRITE and *ppv set if the page has a write
3832 * access handler of some kind.
3833 * @retval VERR_PGM_PHYS_TLB_CATCH_ALL if the page has a handler catching all
3834 * accesses or is odd in any way.
3835 * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist.
3836 *
3837 * @param pVM The cross context VM structure.
3838 * @param pVCpu The cross context virtual CPU structure of the
3839 * calling EMT.
3840 * @param GCPhys The GC physical address to convert. This API mask
3841 * the A20 line when necessary.
3842 * @param fWritable Whether write access is required.
3843 * @param fByPassHandlers Whether to bypass access handlers.
3844 * @param ppv Where to store the pointer corresponding to GCPhys
3845 * on success.
3846 * @param pLock
3847 *
3848 * @remarks This is more or a less a copy of PGMR3PhysTlbGCPhys2Ptr.
3849 * @thread EMT(pVCpu).
3850 */
3851VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers,
3852 void **ppv, PPGMPAGEMAPLOCK pLock)
3853{
3854 PGM_A20_APPLY_TO_VAR(pVCpu, GCPhys);
3855
3856 PGM_LOCK_VOID(pVM);
3857
3858 PPGMRAMRANGE pRam;
3859 PPGMPAGE pPage;
3860 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
3861 if (RT_SUCCESS(rc))
3862 {
3863 if (PGM_PAGE_IS_BALLOONED(pPage))
3864 rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
3865 else if (PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
3866 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3867 else if ( !PGM_PAGE_HAS_ANY_HANDLERS(pPage)
3868 || (fByPassHandlers && !PGM_PAGE_IS_MMIO(pPage)) )
3869 rc = VINF_SUCCESS;
3870 else
3871 {
3872 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)) /* catches MMIO */
3873 {
3874 Assert(!fByPassHandlers || PGM_PAGE_IS_MMIO(pPage));
3875 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3876 }
3877 else if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage) && fWritable)
3878 {
3879 Assert(!fByPassHandlers);
3880 rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
3881 }
3882 }
3883 if (RT_SUCCESS(rc))
3884 {
3885 int rc2;
3886
3887 /* Make sure what we return is writable. */
3888 if (fWritable)
3889 switch (PGM_PAGE_GET_STATE(pPage))
3890 {
3891 case PGM_PAGE_STATE_ALLOCATED:
3892 break;
3893 case PGM_PAGE_STATE_BALLOONED:
3894 AssertFailed();
3895 break;
3896 case PGM_PAGE_STATE_ZERO:
3897 case PGM_PAGE_STATE_SHARED:
3898 case PGM_PAGE_STATE_WRITE_MONITORED:
3899 rc2 = pgmPhysPageMakeWritable(pVM, pPage, GCPhys & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK);
3900 AssertLogRelRCReturn(rc2, rc2);
3901 break;
3902 }
3903
3904 /* Get a ring-3 mapping of the address. */
3905 PPGMPAGEMAPTLBE pTlbe;
3906 rc2 = pgmPhysPageQueryTlbeWithPage(pVM, pPage, GCPhys, &pTlbe);
3907 AssertLogRelRCReturn(rc2, rc2);
3908
3909 /* Lock it and calculate the address. */
3910 if (fWritable)
3911 pgmPhysPageMapLockForWriting(pVM, pPage, pTlbe, pLock);
3912 else
3913 pgmPhysPageMapLockForReading(pVM, pPage, pTlbe, pLock);
3914 *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & GUEST_PAGE_OFFSET_MASK));
3915
3916 Log6(("PGMPhysIemGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage] *ppv=%p\n", GCPhys, rc, pPage, *ppv));
3917 }
3918 else
3919 Log6(("PGMPhysIemGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage]\n", GCPhys, rc, pPage));
3920
3921 /* else: handler catching all access, no pointer returned. */
3922 }
3923 else
3924 rc = VERR_PGM_PHYS_TLB_UNASSIGNED;
3925
3926 PGM_UNLOCK(pVM);
3927 return rc;
3928}
3929
3930
3931/**
3932 * Checks if the give GCPhys page requires special handling for the given access
3933 * because it's MMIO or otherwise monitored.
3934 *
3935 * @returns VBox status code (no informational statuses).
3936 * @retval VINF_SUCCESS on success.
3937 * @retval VERR_PGM_PHYS_TLB_CATCH_WRITE and *ppv set if the page has a write
3938 * access handler of some kind.
3939 * @retval VERR_PGM_PHYS_TLB_CATCH_ALL if the page has a handler catching all
3940 * accesses or is odd in any way.
3941 * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist.
3942 *
3943 * @param pVM The cross context VM structure.
3944 * @param GCPhys The GC physical address to convert. Since this is
3945 * only used for filling the REM TLB, the A20 mask must
3946 * be applied before calling this API.
3947 * @param fWritable Whether write access is required.
3948 * @param fByPassHandlers Whether to bypass access handlers.
3949 *
3950 * @remarks This is a watered down version PGMPhysIemGCPhys2Ptr and really just
3951 * a stop gap thing that should be removed once there is a better TLB
3952 * for virtual address accesses.
3953 */
3954VMM_INT_DECL(int) PGMPhysIemQueryAccess(PVMCC pVM, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers)
3955{
3956 PGM_LOCK_VOID(pVM);
3957 PGM_A20_ASSERT_MASKED(VMMGetCpu(pVM), GCPhys);
3958
3959 PPGMRAMRANGE pRam;
3960 PPGMPAGE pPage;
3961 int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam);
3962 if (RT_SUCCESS(rc))
3963 {
3964 if (PGM_PAGE_IS_BALLOONED(pPage))
3965 rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
3966 else if (PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))
3967 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3968 else if ( !PGM_PAGE_HAS_ANY_HANDLERS(pPage)
3969 || (fByPassHandlers && !PGM_PAGE_IS_MMIO(pPage)) )
3970 rc = VINF_SUCCESS;
3971 else
3972 {
3973 if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)) /* catches MMIO */
3974 {
3975 Assert(!fByPassHandlers || PGM_PAGE_IS_MMIO(pPage));
3976 rc = VERR_PGM_PHYS_TLB_CATCH_ALL;
3977 }
3978 else if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage) && fWritable)
3979 {
3980 Assert(!fByPassHandlers);
3981 rc = VERR_PGM_PHYS_TLB_CATCH_WRITE;
3982 }
3983 }
3984 }
3985
3986 PGM_UNLOCK(pVM);
3987 return rc;
3988}
3989
3990#ifdef VBOX_WITH_NATIVE_NEM
3991
3992/**
3993 * Interface used by NEM to check what to do on a memory access exit.
3994 *
3995 * @returns VBox status code.
3996 * @param pVM The cross context VM structure.
3997 * @param pVCpu The cross context per virtual CPU structure.
3998 * Optional.
3999 * @param GCPhys The guest physical address.
4000 * @param fMakeWritable Whether to try make the page writable or not. If it
4001 * cannot be made writable, NEM_PAGE_PROT_WRITE won't
4002 * be returned and the return code will be unaffected
4003 * @param pInfo Where to return the page information. This is
4004 * initialized even on failure.
4005 * @param pfnChecker Page in-sync checker callback. Optional.
4006 * @param pvUser User argument to pass to pfnChecker.
4007 */
4008VMM_INT_DECL(int) PGMPhysNemPageInfoChecker(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fMakeWritable, PPGMPHYSNEMPAGEINFO pInfo,
4009 PFNPGMPHYSNEMCHECKPAGE pfnChecker, void *pvUser)
4010{
4011 PGM_LOCK_VOID(pVM);
4012
4013 PPGMPAGE pPage;
4014 int rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage);
4015 if (RT_SUCCESS(rc))
4016 {
4017 /* Try make it writable if requested. */
4018 pInfo->u2OldNemState = PGM_PAGE_GET_NEM_STATE(pPage);
4019 if (fMakeWritable)
4020 switch (PGM_PAGE_GET_STATE(pPage))
4021 {
4022 case PGM_PAGE_STATE_SHARED:
4023 case PGM_PAGE_STATE_WRITE_MONITORED:
4024 case PGM_PAGE_STATE_ZERO:
4025 rc = pgmPhysPageMakeWritable(pVM, pPage, GCPhys);
4026 if (rc == VERR_PGM_PHYS_PAGE_RESERVED)
4027 rc = VINF_SUCCESS;
4028 break;
4029 }
4030
4031 /* Fill in the info. */
4032 pInfo->HCPhys = PGM_PAGE_GET_HCPHYS(pPage);
4033 pInfo->u2NemState = PGM_PAGE_GET_NEM_STATE(pPage);
4034 pInfo->fHasHandlers = PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage) ? 1 : 0;
4035 PGMPAGETYPE const enmType = (PGMPAGETYPE)PGM_PAGE_GET_TYPE(pPage);
4036 pInfo->enmType = enmType;
4037 pInfo->fNemProt = pgmPhysPageCalcNemProtection(pPage, enmType);
4038 switch (PGM_PAGE_GET_STATE(pPage))
4039 {
4040 case PGM_PAGE_STATE_ALLOCATED:
4041 pInfo->fZeroPage = 0;
4042 break;
4043
4044 case PGM_PAGE_STATE_ZERO:
4045 pInfo->fZeroPage = 1;
4046 break;
4047
4048 case PGM_PAGE_STATE_WRITE_MONITORED:
4049 pInfo->fZeroPage = 0;
4050 break;
4051
4052 case PGM_PAGE_STATE_SHARED:
4053 pInfo->fZeroPage = 0;
4054 break;
4055
4056 case PGM_PAGE_STATE_BALLOONED:
4057 pInfo->fZeroPage = 1;
4058 break;
4059
4060 default:
4061 pInfo->fZeroPage = 1;
4062 AssertFailedStmt(rc = VERR_PGM_PHYS_PAGE_GET_IPE);
4063 }
4064
4065 /* Call the checker and update NEM state. */
4066 if (pfnChecker)
4067 {
4068 rc = pfnChecker(pVM, pVCpu, GCPhys, pInfo, pvUser);
4069 PGM_PAGE_SET_NEM_STATE(pPage, pInfo->u2NemState);
4070 }
4071
4072 /* Done. */
4073 PGM_UNLOCK(pVM);
4074 }
4075 else
4076 {
4077 PGM_UNLOCK(pVM);
4078
4079 pInfo->HCPhys = NIL_RTHCPHYS;
4080 pInfo->fNemProt = NEM_PAGE_PROT_NONE;
4081 pInfo->u2NemState = 0;
4082 pInfo->fHasHandlers = 0;
4083 pInfo->fZeroPage = 0;
4084 pInfo->enmType = PGMPAGETYPE_INVALID;
4085 }
4086
4087 return rc;
4088}
4089
4090
4091/**
4092 * NEM helper that performs @a pfnCallback on pages with NEM state @a uMinState
4093 * or higher.
4094 *
4095 * @returns VBox status code from callback.
4096 * @param pVM The cross context VM structure.
4097 * @param pVCpu The cross context per CPU structure. This is
4098 * optional as its only for passing to callback.
4099 * @param uMinState The minimum NEM state value to call on.
4100 * @param pfnCallback The callback function.
4101 * @param pvUser User argument for the callback.
4102 */
4103VMM_INT_DECL(int) PGMPhysNemEnumPagesByState(PVMCC pVM, PVMCPUCC pVCpu, uint8_t uMinState,
4104 PFNPGMPHYSNEMENUMCALLBACK pfnCallback, void *pvUser)
4105{
4106 /*
4107 * Just brute force this problem.
4108 */
4109 PGM_LOCK_VOID(pVM);
4110 int rc = VINF_SUCCESS;
4111 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX); pRam; pRam = pRam->CTX_SUFF(pNext))
4112 {
4113 uint32_t const cPages = pRam->cb >> X86_PAGE_SHIFT;
4114 for (uint32_t iPage = 0; iPage < cPages; iPage++)
4115 {
4116 uint8_t u2State = PGM_PAGE_GET_NEM_STATE(&pRam->aPages[iPage]);
4117 if (u2State < uMinState)
4118 { /* likely */ }
4119 else
4120 {
4121 rc = pfnCallback(pVM, pVCpu, pRam->GCPhys + ((RTGCPHYS)iPage << X86_PAGE_SHIFT), &u2State, pvUser);
4122 if (RT_SUCCESS(rc))
4123 PGM_PAGE_SET_NEM_STATE(&pRam->aPages[iPage], u2State);
4124 else
4125 break;
4126 }
4127 }
4128 }
4129 PGM_UNLOCK(pVM);
4130
4131 return rc;
4132}
4133
4134
4135/**
4136 * Helper for setting the NEM state for a range of pages.
4137 *
4138 * @param paPages Array of pages to modify.
4139 * @param cPages How many pages to modify.
4140 * @param u2State The new state value.
4141 */
4142void pgmPhysSetNemStateForPages(PPGMPAGE paPages, RTGCPHYS cPages, uint8_t u2State)
4143{
4144 PPGMPAGE pPage = paPages;
4145 while (cPages-- > 0)
4146 {
4147 PGM_PAGE_SET_NEM_STATE(pPage, u2State);
4148 pPage++;
4149 }
4150}
4151
4152#endif /* VBOX_WITH_NATIVE_NEM */
4153
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