VirtualBox

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

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

PGM: Avoid requiring a full tree walk to age the mapping chunks (changes the age into a time stamp).

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette