VirtualBox

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

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

More statistics

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

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