VirtualBox

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

Last change on this file since 1828 was 1828, checked in by vboxsync, 18 years ago

Cleaned up cpl checking.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 62.3 KB
Line 
1/* $Id: PGMAllPhys.cpp 1828 2007-03-30 12:52:55Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor, Physical Memory Addressing.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22/** @def PGM_IGNORE_RAM_FLAGS_RESERVED
23 * Don't respect the MM_RAM_FLAGS_RESERVED flag when converting to HC addresses.
24 *
25 * Since this flag is currently incorrectly kept set for ROM regions we will
26 * have to ignore it for now so we don't break stuff.
27 */
28#define PGM_IGNORE_RAM_FLAGS_RESERVED
29
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#define LOG_GROUP LOG_GROUP_PGM_PHYS
35#include <VBox/pgm.h>
36#include <VBox/trpm.h>
37#include <VBox/vmm.h>
38#include "PGMInternal.h"
39#include <VBox/vm.h>
40#include <VBox/param.h>
41#include <VBox/err.h>
42#include <iprt/assert.h>
43#include <iprt/string.h>
44#include <iprt/asm.h>
45#include <VBox/log.h>
46#ifdef IN_RING3
47# include <iprt/thread.h>
48#endif
49
50
51
52/**
53 * Checks if Address Gate 20 is enabled or not.
54 *
55 * @returns true if enabled.
56 * @returns false if disabled.
57 * @param pVM VM handle.
58 */
59PGMDECL(bool) PGMPhysIsA20Enabled(PVM pVM)
60{
61 LogFlow(("PGMPhysIsA20Enabled %d\n", pVM->pgm.s.fA20Enabled));
62 return !!pVM->pgm.s.fA20Enabled ; /* stupid MS compiler doesn't trust me. */
63}
64
65
66/**
67 * Validates a GC physical address.
68 *
69 * @returns true if valid.
70 * @returns false if invalid.
71 * @param pVM The VM handle.
72 * @param GCPhys The physical address to validate.
73 */
74PGMDECL(bool) PGMPhysIsGCPhysValid(PVM pVM, RTGCPHYS GCPhys)
75{
76 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
77 pRam;
78 pRam = CTXSUFF(pRam->pNext))
79 {
80 RTGCPHYS off = GCPhys - pRam->GCPhys;
81 if (off < pRam->cb)
82 return true;
83 }
84 return false;
85}
86
87
88/**
89 * Checks if a GC physical address is a normal page,
90 * i.e. not ROM, MMIO or reserved.
91 *
92 * @returns true if normal.
93 * @returns false if invalid, ROM, MMIO or reserved page.
94 * @param pVM The VM handle.
95 * @param GCPhys The physical address to check.
96 */
97PGMDECL(bool) PGMPhysIsGCPhysNormal(PVM pVM, RTGCPHYS GCPhys)
98{
99 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
100 pRam;
101 pRam = CTXSUFF(pRam->pNext))
102 {
103 RTGCPHYS off = GCPhys - pRam->GCPhys;
104 if (off < pRam->cb)
105 return !(pRam->aHCPhys[off >> PAGE_SHIFT] & (MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_MMIO2));
106 }
107 return false;
108}
109
110
111/**
112 * Converts a GC physical address to a HC physical address.
113 *
114 * @returns VINF_SUCCESS on success.
115 * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical
116 * page but has no physical backing.
117 * @returns VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid
118 * GC physical address.
119 * @param pVM The VM handle.
120 * @param GCPhys The GC physical address to convert.
121 * @param pHCPhys Where to store the HC physical address on success.
122 */
123PGMDECL(int) PGMPhysGCPhys2HCPhys(PVM pVM, RTGCPHYS GCPhys, PRTHCPHYS pHCPhys)
124{
125 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
126 pRam;
127 pRam = CTXSUFF(pRam->pNext))
128 {
129 RTGCPHYS off = GCPhys - pRam->GCPhys;
130 if (off < pRam->cb)
131 {
132 if ( pRam->pvHC
133 || (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC))
134 {
135 unsigned iPage = off >> PAGE_SHIFT;
136 if (RT_UNLIKELY(!(pRam->aHCPhys[iPage] & X86_PTE_PAE_PG_MASK)))
137 {
138#ifdef IN_RING3
139 int rc = pgmr3PhysGrowRange(pVM, GCPhys);
140#else
141 int rc = CTXALLMID(VMM, CallHost)(pVM, VMMCALLHOST_PGM_RAM_GROW_RANGE, GCPhys);
142#endif
143 if (rc != VINF_SUCCESS)
144 return rc;
145 }
146
147 RTHCPHYS HCPhys = pRam->aHCPhys[off >> PAGE_SHIFT];
148#ifndef PGM_IGNORE_RAM_FLAGS_RESERVED
149 if (!(HCPhys & MM_RAM_FLAGS_RESERVED))
150#endif
151 {
152 *pHCPhys = (HCPhys & X86_PTE_PAE_PG_MASK)
153 | (off & PAGE_OFFSET_MASK);
154 return VINF_SUCCESS;
155 }
156 }
157 return VERR_PGM_PHYS_PAGE_RESERVED;
158 }
159 }
160 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
161}
162
163
164/**
165 * Converts a GC physical address to a HC pointer.
166 *
167 * @returns VINF_SUCCESS on success.
168 * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical
169 * page but has no physical backing.
170 * @returns VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid
171 * GC physical address.
172 * @returns VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY if the range crosses
173 * a dynamic ram chunk boundary
174 * @param pVM The VM handle.
175 * @param GCPhys The GC physical address to convert.
176 * @param cbRange Physical range
177 * @param pHCPtr Where to store the HC pointer on success.
178 */
179PGMDECL(int) PGMPhysGCPhys2HCPtr(PVM pVM, RTGCPHYS GCPhys, RTUINT cbRange, PRTHCPTR pHCPtr)
180{
181#ifdef PGM_DYNAMIC_RAM_ALLOC
182 if ((GCPhys & PGM_DYNAMIC_CHUNK_BASE_MASK) != ((GCPhys+cbRange-1) & PGM_DYNAMIC_CHUNK_BASE_MASK))
183 {
184 AssertMsgFailed(("PGMPhysGCPhys2HCPtr %VGp - %VGp crosses a chunk boundary!!\n", GCPhys, GCPhys+cbRange));
185 return VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY;
186 }
187#endif
188
189 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
190 pRam;
191 pRam = CTXSUFF(pRam->pNext))
192 {
193 RTGCPHYS off = GCPhys - pRam->GCPhys;
194 if (off < pRam->cb)
195 {
196 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
197 {
198 unsigned iPage = off >> PAGE_SHIFT;
199 if (RT_UNLIKELY(!(pRam->aHCPhys[iPage] & X86_PTE_PAE_PG_MASK)))
200 {
201#ifdef IN_RING3
202 int rc = pgmr3PhysGrowRange(pVM, GCPhys);
203#else
204 int rc = CTXALLMID(VMM, CallHost)(pVM, VMMCALLHOST_PGM_RAM_GROW_RANGE, GCPhys);
205#endif
206 if (rc != VINF_SUCCESS)
207 return rc;
208 }
209 unsigned idx = (off >> PGM_DYNAMIC_CHUNK_SHIFT);
210 *pHCPtr = (RTHCPTR)((RTHCUINTPTR)CTXSUFF(pRam->pavHCChunk)[idx] + (off & PGM_DYNAMIC_CHUNK_OFFSET_MASK));
211 return VINF_SUCCESS;
212 }
213 if (pRam->pvHC)
214 {
215#ifndef PGM_IGNORE_RAM_FLAGS_RESERVED
216 if (!(pRam->aHCPhys[off >> PAGE_SHIFT] & MM_RAM_FLAGS_RESERVED))
217#endif
218 {
219 *pHCPtr = (RTHCPTR)((RTHCUINTPTR)pRam->pvHC + off);
220 return VINF_SUCCESS;
221 }
222 }
223 return VERR_PGM_PHYS_PAGE_RESERVED;
224 }
225 }
226 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
227}
228
229
230/**
231 * Validates a HC pointer.
232 *
233 * @returns true if valid.
234 * @returns false if invalid.
235 * @param pVM The VM handle.
236 * @param HCPtr The pointer to validate.
237 */
238PGMDECL(bool) PGMPhysIsHCPtrValid(PVM pVM, RTHCPTR HCPtr)
239{
240 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
241 pRam;
242 pRam = CTXSUFF(pRam->pNext))
243 {
244 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
245 {
246 /** @note this is quite slow */
247 for (unsigned iChunk = 0; iChunk < (pRam->cb >> PGM_DYNAMIC_CHUNK_SHIFT); iChunk++)
248 {
249 if (CTXSUFF(pRam->pavHCChunk)[iChunk])
250 {
251 RTHCUINTPTR off = (RTHCUINTPTR)HCPtr - (RTHCUINTPTR)CTXSUFF(pRam->pavHCChunk)[iChunk];
252 if (off < PGM_DYNAMIC_CHUNK_SIZE)
253 return true;
254 }
255 }
256 }
257 else if (pRam->pvHC)
258 {
259 RTHCUINTPTR off = (RTHCUINTPTR)HCPtr - (RTHCUINTPTR)pRam->pvHC;
260
261 if (off < pRam->cb)
262 return true;
263 }
264 }
265 return false;
266}
267
268
269/**
270 * Converts a HC pointer to a GC physical address.
271 *
272 * @returns VINF_SUCCESS on success.
273 * @returns VERR_INVALID_POINTER if the pointer is not within the
274 * GC physical memory.
275 * @param pVM The VM handle.
276 * @param HCPtr The HC pointer to convert.
277 * @param pGCPhys Where to store the GC physical address on success.
278 */
279PGMDECL(int) PGMPhysHCPtr2GCPhys(PVM pVM, RTHCPTR HCPtr, PRTGCPHYS pGCPhys)
280{
281 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
282 pRam;
283 pRam = CTXSUFF(pRam->pNext))
284 {
285 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
286 {
287 /** @note this is quite slow */
288 for (unsigned iChunk = 0; iChunk < (pRam->cb >> PGM_DYNAMIC_CHUNK_SHIFT); iChunk++)
289 {
290 if (CTXSUFF(pRam->pavHCChunk)[iChunk])
291 {
292 RTHCUINTPTR off = (RTHCUINTPTR)HCPtr - (RTHCUINTPTR)CTXSUFF(pRam->pavHCChunk)[iChunk];
293 if (off < PGM_DYNAMIC_CHUNK_SIZE)
294 {
295 *pGCPhys = pRam->GCPhys + iChunk*PGM_DYNAMIC_CHUNK_SIZE + off;
296 return VINF_SUCCESS;
297 }
298 }
299 }
300 }
301 else if (pRam->pvHC)
302 {
303 RTHCUINTPTR off = (RTHCUINTPTR)HCPtr - (RTHCUINTPTR)pRam->pvHC;
304 if (off < pRam->cb)
305 {
306 *pGCPhys = pRam->GCPhys + off;
307 return VINF_SUCCESS;
308 }
309 }
310 }
311 return VERR_INVALID_POINTER;
312}
313
314
315/**
316 * Converts a HC pointer to a GC physical address.
317 *
318 * @returns VINF_SUCCESS on success.
319 * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical
320 * page but has no physical backing.
321 * @returns VERR_INVALID_POINTER if the pointer is not within the
322 * GC physical memory.
323 * @param pVM The VM handle.
324 * @param HCPtr The HC pointer to convert.
325 * @param pHCPhys Where to store the HC physical address on success.
326 */
327PGMDECL(int) PGMPhysHCPtr2HCPhys(PVM pVM, RTHCPTR HCPtr, PRTHCPHYS pHCPhys)
328{
329 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
330 pRam;
331 pRam = CTXSUFF(pRam->pNext))
332 {
333 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
334 {
335 /** @note this is quite slow */
336 for (unsigned iChunk = 0; iChunk < (pRam->cb >> PGM_DYNAMIC_CHUNK_SHIFT); iChunk++)
337 {
338 if (CTXSUFF(pRam->pavHCChunk)[iChunk])
339 {
340 RTHCUINTPTR off = (RTHCUINTPTR)HCPtr - (RTHCUINTPTR)CTXSUFF(pRam->pavHCChunk)[iChunk];
341 if (off < PGM_DYNAMIC_CHUNK_SIZE)
342 {
343 RTHCPHYS HCPhys = pRam->aHCPhys[off >> PAGE_SHIFT];
344#ifndef PGM_IGNORE_RAM_FLAGS_RESERVED
345 if (!(HCPhys & MM_RAM_FLAGS_RESERVED))
346#endif
347 {
348 *pHCPhys = (HCPhys & X86_PTE_PAE_PG_MASK)
349 | (off & PAGE_OFFSET_MASK);
350 return VINF_SUCCESS;
351 }
352 return VERR_PGM_PHYS_PAGE_RESERVED;
353 }
354 }
355 }
356 }
357 else if (pRam->pvHC)
358 {
359 RTHCUINTPTR off = (RTHCUINTPTR)HCPtr - (RTHCUINTPTR)pRam->pvHC;
360 if (off < pRam->cb)
361 {
362 RTHCPHYS HCPhys = pRam->aHCPhys[off >> PAGE_SHIFT];
363#ifndef PGM_IGNORE_RAM_FLAGS_RESERVED
364 if (!(HCPhys & MM_RAM_FLAGS_RESERVED))
365#endif
366 {
367 *pHCPhys = (HCPhys & X86_PTE_PAE_PG_MASK)
368 | (off & PAGE_OFFSET_MASK);
369 return VINF_SUCCESS;
370 }
371 return VERR_PGM_PHYS_PAGE_RESERVED;
372 }
373 }
374 }
375 return VERR_INVALID_POINTER;
376}
377
378
379/**
380 * Validates a HC Physical address.
381 *
382 * This is an extremely slow API, don't use it!
383 *
384 * @returns true if valid.
385 * @returns false if invalid.
386 * @param pVM The VM handle.
387 * @param HCPhys The physical address to validate.
388 */
389PGMDECL(bool) PGMPhysIsHCPhysValid(PVM pVM, RTHCPHYS HCPhys)
390{
391 RTGCPHYS GCPhys;
392 int rc = PGMPhysHCPhys2GCPhys(pVM, HCPhys, &GCPhys);
393 return VBOX_SUCCESS(rc);
394}
395
396
397/**
398 * Converts a HC physical address to a GC physical address.
399 *
400 * This is an extremely slow API, don't use it!
401 *
402 * @returns VINF_SUCCESS on success.
403 * @returns VERR_INVALID_POINTER if the HC physical address is
404 * not within the GC physical memory.
405 * @param pVM The VM handle.
406 * @param HCPhys The HC physical address to convert.
407 * @param pGCPhys Where to store the GC physical address on success.
408 */
409PGMDECL(int) PGMPhysHCPhys2GCPhys(PVM pVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys)
410{
411 unsigned off = HCPhys & PAGE_OFFSET_MASK;
412 HCPhys &= X86_PTE_PAE_PG_MASK;
413 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
414 pRam;
415 pRam = CTXSUFF(pRam->pNext))
416 {
417 if ( pRam->pvHC
418 || (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC))
419 {
420 unsigned iPage = pRam->cb >> PAGE_SHIFT;
421 while (iPage-- > 0)
422#ifndef PGM_IGNORE_RAM_FLAGS_RESERVED
423 if ((pRam->aHCPhys[iPage] & (X86_PTE_PAE_PG_MASK | MM_RAM_FLAGS_RESERVED)) == HCPhys)
424#else
425 if ((pRam->aHCPhys[iPage] & (X86_PTE_PAE_PG_MASK)) == HCPhys)
426#endif
427 {
428 *pGCPhys = pRam->GCPhys + (iPage << PAGE_SHIFT) + off;
429 return VINF_SUCCESS;
430 }
431 }
432 }
433 return VERR_INVALID_POINTER;
434}
435
436
437/**
438 * Converts a HC physical address to a HC pointer.
439 *
440 * This is an extremely slow API, don't use it!
441 *
442 * @returns VINF_SUCCESS on success.
443 * @returns VERR_INVALID_POINTER if the HC physical address is
444 * not within the GC physical memory.
445 * @param pVM The VM handle.
446 * @param HCPhys The HC physical address to convert.
447 * @param pHCPtr Where to store the HC pointer on success.
448 */
449PGMDECL(int) PGMPhysHCPhys2HCPtr(PVM pVM, RTHCPHYS HCPhys, PRTHCPTR pHCPtr)
450{
451 unsigned off = HCPhys & PAGE_OFFSET_MASK;
452 HCPhys &= X86_PTE_PAE_PG_MASK;
453 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
454 pRam;
455 pRam = CTXSUFF(pRam->pNext))
456 {
457 if ( pRam->pvHC
458 || (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC))
459 {
460 unsigned iPage = pRam->cb >> PAGE_SHIFT;
461 while (iPage-- > 0)
462#ifndef PGM_IGNORE_RAM_FLAGS_RESERVED
463 if ((pRam->aHCPhys[iPage] & (X86_PTE_PAE_PG_MASK | MM_RAM_FLAGS_RESERVED)) == HCPhys)
464#else
465 if ((pRam->aHCPhys[iPage] & (X86_PTE_PAE_PG_MASK)) == HCPhys)
466#endif
467 {
468 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
469 {
470 unsigned idx = (iPage >> (PGM_DYNAMIC_CHUNK_SHIFT - PAGE_SHIFT));
471
472 *pHCPtr = (RTHCPTR)((RTHCUINTPTR)CTXSUFF(pRam->pavHCChunk)[idx] + ((iPage << PAGE_SHIFT) & PGM_DYNAMIC_CHUNK_OFFSET_MASK) + off);
473 }
474 else
475 *pHCPtr = (RTHCPTR)((RTHCUINTPTR)pRam->pvHC + (iPage << PAGE_SHIFT) + off);
476
477 return VINF_SUCCESS;
478 }
479 }
480 }
481 return VERR_INVALID_POINTER;
482}
483
484
485/**
486 * Converts a guest pointer to a GC physical address.
487 *
488 * This uses the current CR3/CR0/CR4 of the guest.
489 *
490 * @returns VBox status code.
491 * @param pVM The VM Handle
492 * @param GCPtr The guest pointer to convert.
493 * @param pGCPhys Where to store the HC physical address.
494 */
495PGMDECL(int) PGMPhysGCPtr2GCPhys(PVM pVM, RTGCPTR GCPtr, PRTGCPHYS pGCPhys)
496{
497 int rc = PGM_GST_PFN(GetPage,pVM)(pVM, (RTGCUINTPTR)GCPtr, NULL, pGCPhys);
498 /** @todo real mode & protected mode? */
499 return rc;
500}
501
502
503/**
504 * Converts a guest pointer to a HC physical address.
505 *
506 * This uses the current CR3/CR0/CR4 of the guest.
507 *
508 * @returns VBox status code.
509 * @param pVM The VM Handle
510 * @param GCPtr The guest pointer to convert.
511 * @param pHCPhys Where to store the HC physical address.
512 */
513PGMDECL(int) PGMPhysGCPtr2HCPhys(PVM pVM, RTGCPTR GCPtr, PRTHCPHYS pHCPhys)
514{
515 RTGCPHYS GCPhys;
516 int rc = PGM_GST_PFN(GetPage,pVM)(pVM, (RTGCUINTPTR)GCPtr, NULL, &GCPhys);
517 if (VBOX_SUCCESS(rc))
518 rc = PGMPhysGCPhys2HCPhys(pVM, GCPhys | ((RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK), pHCPhys);
519 /** @todo real mode & protected mode? */
520 return rc;
521}
522
523
524/**
525 * Converts a guest pointer to a HC pointer.
526 *
527 * This uses the current CR3/CR0/CR4 of the guest.
528 *
529 * @returns VBox status code.
530 * @param pVM The VM Handle
531 * @param GCPtr The guest pointer to convert.
532 * @param pHCPtr Where to store the HC virtual address.
533 */
534PGMDECL(int) PGMPhysGCPtr2HCPtr(PVM pVM, RTGCPTR GCPtr, PRTHCPTR pHCPtr)
535{
536 RTGCPHYS GCPhys;
537 int rc = PGM_GST_PFN(GetPage,pVM)(pVM, (RTGCUINTPTR)GCPtr, NULL, &GCPhys);
538 if (VBOX_SUCCESS(rc))
539 rc = PGMPhysGCPhys2HCPtr(pVM, GCPhys | ((RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK), 1 /* we always stay within one page */, pHCPtr);
540 /** @todo real mode & protected mode? */
541 return rc;
542}
543
544
545/**
546 * Converts a guest virtual address to a HC pointer by specfied CR3 and flags.
547 *
548 * @returns VBox status code.
549 * @param pVM The VM Handle
550 * @param GCPtr The guest pointer to convert.
551 * @param cr3 The guest CR3.
552 * @param fFlags Flags used for interpreting the PD correctly: X86_CR4_PSE and X86_CR4_PAE
553 * @param pHCPtr Where to store the HC pointer.
554 *
555 * @remark This function is used by the REM at a time where PGM could
556 * potentially not be in sync. It could also be used by a
557 * future DBGF API to cpu state independent conversions.
558 */
559PGMDECL(int) PGMPhysGCPtr2HCPtrByGstCR3(PVM pVM, RTGCPTR GCPtr, uint32_t cr3, unsigned fFlags, PRTHCPTR pHCPtr)
560{
561 /*
562 * PAE or 32-bit?
563 */
564 int rc;
565 if (!(fFlags & X86_CR4_PAE))
566 {
567 PX86PD pPD;
568 rc = PGM_GCPHYS_2_PTR(pVM, cr3 & X86_CR3_PAGE_MASK, &pPD);
569 if (VBOX_SUCCESS(rc))
570 {
571 VBOXPDE Pde = pPD->a[(RTGCUINTPTR)GCPtr >> X86_PD_SHIFT];
572 if (Pde.n.u1Present)
573 {
574 if ((fFlags & X86_CR4_PSE) && Pde.b.u1Size)
575 { /* (big page) */
576 rc = PGMPhysGCPhys2HCPtr(pVM, (Pde.u & X86_PDE4M_PG_MASK) | ((RTGCUINTPTR)GCPtr & X86_PAGE_4M_OFFSET_MASK), 1 /* we always stay within one page */, pHCPtr);
577 }
578 else
579 { /* (normal page) */
580 PVBOXPT pPT;
581 rc = PGM_GCPHYS_2_PTR(pVM, Pde.u & X86_PDE_PG_MASK, &pPT);
582 if (VBOX_SUCCESS(rc))
583 {
584 VBOXPTE Pte = pPT->a[((RTGCUINTPTR)GCPtr >> X86_PT_SHIFT) & X86_PT_MASK];
585 if (Pte.n.u1Present)
586 return PGMPhysGCPhys2HCPtr(pVM, (Pte.u & X86_PTE_PG_MASK) | ((RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK), 1 /* we always stay within one page */, pHCPtr);
587 rc = VERR_PAGE_NOT_PRESENT;
588 }
589 }
590 }
591 else
592 rc = VERR_PAGE_TABLE_NOT_PRESENT;
593 }
594 }
595 else
596 {
597 /** @todo long mode! */
598 PX86PDPTR pPdptr;
599 rc = PGM_GCPHYS_2_PTR(pVM, cr3 & X86_CR3_PAE_PAGE_MASK, &pPdptr);
600 if (VBOX_SUCCESS(rc))
601 {
602 X86PDPE Pdpe = pPdptr->a[((RTGCUINTPTR)GCPtr >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK];
603 if (Pdpe.n.u1Present)
604 {
605 PX86PDPAE pPD;
606 rc = PGM_GCPHYS_2_PTR(pVM, Pdpe.u & X86_PDPE_PG_MASK, &pPD);
607 if (VBOX_SUCCESS(rc))
608 {
609 X86PDEPAE Pde = pPD->a[((RTGCUINTPTR)GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK];
610 if (Pde.n.u1Present)
611 {
612 if ((fFlags & X86_CR4_PSE) && Pde.b.u1Size)
613 { /* (big page) */
614 rc = PGMPhysGCPhys2HCPtr(pVM, (Pde.u & X86_PDE4M_PAE_PG_MASK) | ((RTGCUINTPTR)GCPtr & X86_PAGE_4M_OFFSET_MASK), 1 /* we always stay within one page */, pHCPtr);
615 }
616 else
617 { /* (normal page) */
618 PX86PTPAE pPT;
619 rc = PGM_GCPHYS_2_PTR(pVM, (Pde.u & X86_PDE_PAE_PG_MASK), &pPT);
620 if (VBOX_SUCCESS(rc))
621 {
622 X86PTEPAE Pte = pPT->a[((RTGCUINTPTR)GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK];
623 if (Pte.n.u1Present)
624 return PGMPhysGCPhys2HCPtr(pVM, (Pte.u & X86_PTE_PAE_PG_MASK) | ((RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK), 1 /* we always stay within one page */, pHCPtr);
625 rc = VERR_PAGE_NOT_PRESENT;
626 }
627 }
628 }
629 else
630 rc = VERR_PAGE_TABLE_NOT_PRESENT;
631 }
632 }
633 else
634 rc = VERR_PAGE_TABLE_NOT_PRESENT;
635 }
636 }
637 return rc;
638}
639
640
641#undef LOG_GROUP
642#define LOG_GROUP LOG_GROUP_PGM_PHYS_ACCESS
643
644
645#ifdef IN_RING3
646/**
647 * Cache PGMPhys memory access
648 *
649 * @param pVM VM Handle.
650 * @param pCache Cache structure pointer
651 * @param GCPhys GC physical address
652 * @param pbHC HC pointer corresponding to physical page
653 */
654static void pgmPhysCacheAdd(PVM pVM, PGMPHYSCACHE *pCache, RTGCPHYS GCPhys, uint8_t *pbHC)
655{
656 uint32_t iCacheIndex;
657
658 GCPhys = PAGE_ADDRESS(GCPhys);
659 pbHC = (uint8_t *)PAGE_ADDRESS(pbHC);
660
661 iCacheIndex = ((GCPhys >> PAGE_SHIFT) & PGM_MAX_PHYSCACHE_ENTRIES_MASK);
662
663 ASMBitSet(&pCache->aEntries, iCacheIndex);
664
665 pCache->Entry[iCacheIndex].GCPhys = GCPhys;
666 pCache->Entry[iCacheIndex].pbHC = pbHC;
667}
668#endif
669
670/**
671 * Read physical memory.
672 *
673 * This API respects access handlers and MMIO. Use PGMPhysReadGCPhys() if you
674 * want to ignore those.
675 *
676 * @param pVM VM Handle.
677 * @param GCPhys Physical address start reading from.
678 * @param pvBuf Where to put the read bits.
679 * @param cbRead How many bytes to read.
680 */
681PGMDECL(void) PGMPhysRead(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
682{
683#ifdef IN_RING3
684 bool fGrabbedLock = false;
685#endif
686
687 AssertMsg(cbRead > 0, ("don't even think about reading zero bytes!\n"));
688 if (cbRead == 0)
689 return;
690
691 LogFlow(("PGMPhysRead: %VGp %d\n", GCPhys, cbRead));
692
693#ifdef IN_RING3
694 if (!VM_IS_EMT(pVM))
695 {
696 pgmLock(pVM);
697 fGrabbedLock = true;
698 }
699#endif
700
701 /*
702 * Copy loop on ram ranges.
703 */
704 PPGMRAMRANGE pCur = CTXSUFF(pVM->pgm.s.pRamRanges);
705 for (;;)
706 {
707 /* Find range. */
708 while (pCur && GCPhys > pCur->GCPhysLast)
709 pCur = CTXSUFF(pCur->pNext);
710 /* Inside range or not? */
711 if (pCur && GCPhys >= pCur->GCPhys)
712 {
713 /*
714 * Must work our way thru this page by page.
715 */
716 RTGCPHYS off = GCPhys - pCur->GCPhys;
717 while (off < pCur->cb)
718 {
719 unsigned iPage = off >> PAGE_SHIFT;
720
721 /* Physical chunk in dynamically allocated range not present? */
722 if (RT_UNLIKELY(!(pCur->aHCPhys[iPage] & X86_PTE_PAE_PG_MASK)))
723 {
724 int rc;
725#ifdef IN_RING3
726 if (fGrabbedLock)
727 {
728 pgmUnlock(pVM);
729 rc = pgmr3PhysGrowRange(pVM, GCPhys);
730 if (rc == VINF_SUCCESS)
731 PGMPhysRead(pVM, GCPhys, pvBuf, cbRead); /* try again; can't assume pCur is still valid (paranoia) */
732 return;
733 }
734 rc = pgmr3PhysGrowRange(pVM, GCPhys);
735#else
736 rc = CTXALLMID(VMM, CallHost)(pVM, VMMCALLHOST_PGM_RAM_GROW_RANGE, GCPhys);
737#endif
738 if (rc != VINF_SUCCESS)
739 goto end;
740 }
741
742 size_t cb;
743 RTHCPHYS HCPhys = pCur->aHCPhys[iPage];
744 switch (HCPhys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_VIRTUAL_ALL | MM_RAM_FLAGS_PHYSICAL_ALL | MM_RAM_FLAGS_ROM))
745 {
746 /*
747 * Normal memory or ROM.
748 */
749 case 0:
750 case MM_RAM_FLAGS_ROM:
751 case MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_RESERVED:
752 case MM_RAM_FLAGS_PHYSICAL_WRITE:
753 case MM_RAM_FLAGS_MMIO2 | MM_RAM_FLAGS_PHYSICAL_WRITE:
754 case MM_RAM_FLAGS_VIRTUAL_WRITE:
755 {
756#ifdef IN_GC
757 void *pvSrc = NULL;
758 PGMGCDynMapHCPage(pVM, HCPhys & X86_PTE_PAE_PG_MASK, &pvSrc);
759 pvSrc = (char *)pvSrc + (off & PAGE_OFFSET_MASK);
760#else
761 void *pvSrc = PGMRAMRANGE_GETHCPTR(pCur, off)
762#endif
763 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
764 if (cb >= cbRead)
765 {
766#if defined(IN_RING3) && defined(PGM_PHYSMEMACCESS_CACHING)
767 if (cbRead <= 4)
768 pgmPhysCacheAdd(pVM, &pVM->pgm.s.pgmphysreadcache, GCPhys, (uint8_t*)pvSrc);
769#endif /* IN_RING3 && PGM_PHYSMEMACCESS_CACHING */
770 memcpy(pvBuf, pvSrc, cbRead);
771 goto end;
772 }
773 memcpy(pvBuf, pvSrc, cb);
774 break;
775 }
776
777 /*
778 * All reserved, nothing there.
779 */
780 case MM_RAM_FLAGS_RESERVED:
781 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
782 if (cb >= cbRead)
783 {
784 memset(pvBuf, 0, cbRead);
785 goto end;
786 }
787 memset(pvBuf, 0, cb);
788 break;
789
790 /*
791 * Physical handler.
792 */
793 case MM_RAM_FLAGS_PHYSICAL_ALL:
794 case MM_RAM_FLAGS_MMIO2 | MM_RAM_FLAGS_PHYSICAL_ALL: /** r=bird: MMIO2 isn't in the mask! */
795 {
796 int rc = VINF_PGM_HANDLER_DO_DEFAULT;
797 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
798#ifdef IN_RING3 /** @todo deal with this in GC and R0! */
799
800 /* find and call the handler */
801 PPGMPHYSHANDLER pNode = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.pTreesHC->PhysHandlers, GCPhys);
802 if (pNode && pNode->pfnHandlerR3)
803 {
804 size_t cbRange = pNode->Core.KeyLast - GCPhys + 1;
805 if (cbRange < cb)
806 cb = cbRange;
807 if (cb > cbRead)
808 cb = cbRead;
809
810 void *pvSrc = PGMRAMRANGE_GETHCPTR(pCur, off)
811
812 /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */
813 rc = pNode->pfnHandlerR3(pVM, GCPhys, pvSrc, pvBuf, cb, PGMACCESSTYPE_READ, pNode->pvUserR3);
814 }
815#endif /* IN_RING3 */
816 if (rc == VINF_PGM_HANDLER_DO_DEFAULT)
817 {
818#ifdef IN_GC
819 void *pvSrc = NULL;
820 PGMGCDynMapHCPage(pVM, HCPhys & X86_PTE_PAE_PG_MASK, &pvSrc);
821 pvSrc = (char *)pvSrc + (off & PAGE_OFFSET_MASK);
822#else
823 void *pvSrc = PGMRAMRANGE_GETHCPTR(pCur, off)
824#endif
825
826 if (cb >= cbRead)
827 {
828 memcpy(pvBuf, pvSrc, cbRead);
829 goto end;
830 }
831 memcpy(pvBuf, pvSrc, cb);
832 }
833 else if (cb >= cbRead)
834 goto end;
835 break;
836 }
837
838 case MM_RAM_FLAGS_VIRTUAL_ALL:
839 {
840 int rc = VINF_PGM_HANDLER_DO_DEFAULT;
841 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
842#ifdef IN_RING3 /** @todo deal with this in GC and R0! */
843 /* Search the whole tree for matching physical addresses (rather expensive!) */
844 PPGMVIRTHANDLER pNode;
845 unsigned iPage;
846 int rc2 = pgmHandlerVirtualFindByPhysAddr(pVM, GCPhys, &pNode, &iPage);
847 if (VBOX_SUCCESS(rc2) && pNode->pfnHandlerHC)
848 {
849 size_t cbRange = pNode->Core.KeyLast - GCPhys + 1;
850 if (cbRange < cb)
851 cb = cbRange;
852 if (cb > cbRead)
853 cb = cbRead;
854 RTGCUINTPTR GCPtr = ((RTGCUINTPTR)pNode->GCPtr & PAGE_BASE_GC_MASK)
855 + (iPage << PAGE_SHIFT) + (off & PAGE_OFFSET_MASK);
856
857 void *pvSrc = PGMRAMRANGE_GETHCPTR(pCur, off)
858
859 /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */
860 rc = pNode->pfnHandlerHC(pVM, (RTGCPTR)GCPtr, pvSrc, pvBuf, cb, PGMACCESSTYPE_READ, 0);
861 }
862#endif /* IN_RING3 */
863 if (rc == VINF_PGM_HANDLER_DO_DEFAULT)
864 {
865#ifdef IN_GC
866 void *pvSrc = NULL;
867 PGMGCDynMapHCPage(pVM, HCPhys & X86_PTE_PAE_PG_MASK, &pvSrc);
868 pvSrc = (char *)pvSrc + (off & PAGE_OFFSET_MASK);
869#else
870 void *pvSrc = PGMRAMRANGE_GETHCPTR(pCur, off)
871#endif
872 if (cb >= cbRead)
873 {
874 memcpy(pvBuf, pvSrc, cbRead);
875 goto end;
876 }
877 memcpy(pvBuf, pvSrc, cb);
878 }
879 else if (cb >= cbRead)
880 goto end;
881 break;
882 }
883
884 /*
885 * The rest needs to be taken more carefully.
886 */
887 default:
888#if 1 /** @todo r=bird: Can you do this properly please. */
889 /** @todo Try MMIO; quick hack */
890 if (cbRead <= 4 && IOMMMIORead(pVM, GCPhys, (uint32_t *)pvBuf, cbRead) == VINF_SUCCESS)
891 goto end;
892#endif
893
894 /** @todo fix me later. */
895 AssertReleaseMsgFailed(("Unknown read at %VGp size %d implement the complex physical reading case %x\n",
896 GCPhys, cbRead,
897 HCPhys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_VIRTUAL_ALL | MM_RAM_FLAGS_PHYSICAL_ALL | MM_RAM_FLAGS_ROM)));
898 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
899 break;
900 }
901
902 cbRead -= cb;
903 off += cb;
904 pvBuf = (char *)pvBuf + cb;
905 }
906
907 GCPhys = pCur->GCPhysLast + 1;
908 }
909 else
910 {
911 LogFlow(("PGMPhysRead: Unassigned %VGp size=%d\n", GCPhys, cbRead));
912
913 /*
914 * Unassigned address space.
915 */
916 size_t cb;
917 if ( !pCur
918 || (cb = pCur->GCPhys - GCPhys) >= cbRead)
919 {
920 memset(pvBuf, 0, cbRead);
921 goto end;
922 }
923
924 memset(pvBuf, 0, cb);
925 cbRead -= cb;
926 pvBuf = (char *)pvBuf + cb;
927 GCPhys += cb;
928 }
929 }
930end:
931#ifdef IN_RING3
932 if (fGrabbedLock)
933 pgmUnlock(pVM);
934#endif
935 return;
936}
937
938/**
939 * Write to physical memory.
940 *
941 * This API respects access handlers and MMIO. Use PGMPhysReadGCPhys() if you
942 * want to ignore those.
943 *
944 * @param pVM VM Handle.
945 * @param GCPhys Physical address to write to.
946 * @param pvBuf What to write.
947 * @param cbWrite How many bytes to write.
948 */
949PGMDECL(void) PGMPhysWrite(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
950{
951#ifdef IN_RING3
952 bool fGrabbedLock = false;
953#endif
954
955 AssertMsg(cbWrite > 0, ("don't even think about writing zero bytes!\n"));
956 if (cbWrite == 0)
957 return;
958
959 LogFlow(("PGMPhysWrite: %VGp %d\n", GCPhys, cbWrite));
960
961#ifdef IN_RING3
962 if (!VM_IS_EMT(pVM))
963 {
964 pgmLock(pVM);
965 fGrabbedLock = true;
966 }
967#endif
968 /*
969 * Copy loop on ram ranges.
970 */
971 PPGMRAMRANGE pCur = CTXSUFF(pVM->pgm.s.pRamRanges);
972 for (;;)
973 {
974 /* Find range. */
975 while (pCur && GCPhys > pCur->GCPhysLast)
976 pCur = CTXSUFF(pCur->pNext);
977 /* Inside range or not? */
978 if (pCur && GCPhys >= pCur->GCPhys)
979 {
980 /*
981 * Must work our way thru this page by page.
982 */
983 unsigned off = GCPhys - pCur->GCPhys;
984 while (off < pCur->cb)
985 {
986 unsigned iPage = off >> PAGE_SHIFT;
987
988 /* Physical chunk in dynamically allocated range not present? */
989 if (RT_UNLIKELY(!(pCur->aHCPhys[iPage] & X86_PTE_PAE_PG_MASK)))
990 {
991 int rc;
992#ifdef IN_RING3
993 if (fGrabbedLock)
994 {
995 pgmUnlock(pVM);
996 rc = pgmr3PhysGrowRange(pVM, GCPhys);
997 if (rc == VINF_SUCCESS)
998 PGMPhysWrite(pVM, GCPhys, pvBuf, cbWrite); /* try again; can't assume pCur is still valid (paranoia) */
999 return;
1000 }
1001 rc = pgmr3PhysGrowRange(pVM, GCPhys);
1002#else
1003 rc = CTXALLMID(VMM, CallHost)(pVM, VMMCALLHOST_PGM_RAM_GROW_RANGE, GCPhys);
1004#endif
1005 if (rc != VINF_SUCCESS)
1006 goto end;
1007 }
1008
1009 size_t cb;
1010 RTHCPHYS HCPhys = pCur->aHCPhys[iPage];
1011 /** @todo r=bird: missing MM_RAM_FLAGS_ROM here, we shall not allow anyone to overwrite the ROM! */
1012 switch (HCPhys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2 | MM_RAM_FLAGS_VIRTUAL_ALL | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_PHYSICAL_ALL | MM_RAM_FLAGS_PHYSICAL_WRITE))
1013 {
1014 /*
1015 * Normal memory.
1016 */
1017 case 0:
1018 case MM_RAM_FLAGS_MMIO2:
1019 {
1020#ifdef IN_GC
1021 void *pvDst = NULL;
1022 PGMGCDynMapHCPage(pVM, HCPhys & X86_PTE_PAE_PG_MASK, &pvDst);
1023 pvDst = (char *)pvDst + (off & PAGE_OFFSET_MASK);
1024#else
1025 void *pvDst = PGMRAMRANGE_GETHCPTR(pCur, off)
1026#endif
1027 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
1028 if (cb >= cbWrite)
1029 {
1030#if defined(IN_RING3) && defined(PGM_PHYSMEMACCESS_CACHING)
1031 if (cbWrite <= 4)
1032 pgmPhysCacheAdd(pVM, &pVM->pgm.s.pgmphyswritecache, GCPhys, (uint8_t*)pvDst);
1033#endif /* IN_RING3 && PGM_PHYSMEMACCESS_CACHING */
1034 memcpy(pvDst, pvBuf, cbWrite);
1035 goto end;
1036 }
1037 memcpy(pvDst, pvBuf, cb);
1038 break;
1039 }
1040
1041 /*
1042 * All reserved, nothing there.
1043 */
1044 case MM_RAM_FLAGS_RESERVED:
1045 case MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_MMIO2:
1046 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
1047 if (cb >= cbWrite)
1048 goto end;
1049 break;
1050
1051 /*
1052 * Physical handler.
1053 */
1054 case MM_RAM_FLAGS_PHYSICAL_ALL:
1055 case MM_RAM_FLAGS_PHYSICAL_WRITE:
1056 case MM_RAM_FLAGS_MMIO2 | MM_RAM_FLAGS_PHYSICAL_ALL:
1057 case MM_RAM_FLAGS_MMIO2 | MM_RAM_FLAGS_PHYSICAL_WRITE:
1058 {
1059 int rc = VINF_PGM_HANDLER_DO_DEFAULT;
1060 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
1061#ifdef IN_RING3 /** @todo deal with this in GC and R0! */
1062 /* find and call the handler */
1063 PPGMPHYSHANDLER pNode = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.pTreesHC->PhysHandlers, GCPhys);
1064 if (pNode && pNode->pfnHandlerR3)
1065 {
1066 size_t cbRange = pNode->Core.KeyLast - GCPhys + 1;
1067 if (cbRange < cb)
1068 cb = cbRange;
1069 if (cb > cbWrite)
1070 cb = cbWrite;
1071
1072 void *pvDst = PGMRAMRANGE_GETHCPTR(pCur, off)
1073
1074 /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */
1075 rc = pNode->pfnHandlerR3(pVM, GCPhys, pvDst, (void *)pvBuf, cb, PGMACCESSTYPE_WRITE, pNode->pvUserR3);
1076 }
1077#endif /* IN_RING3 */
1078 if (rc == VINF_PGM_HANDLER_DO_DEFAULT)
1079 {
1080#ifdef IN_GC
1081 void *pvDst = NULL;
1082 PGMGCDynMapHCPage(pVM, HCPhys & X86_PTE_PAE_PG_MASK, &pvDst);
1083 pvDst = (char *)pvDst + (off & PAGE_OFFSET_MASK);
1084#else
1085 void *pvDst = PGMRAMRANGE_GETHCPTR(pCur, off)
1086#endif
1087 if (cb >= cbWrite)
1088 {
1089 memcpy(pvDst, pvBuf, cbWrite);
1090 goto end;
1091 }
1092 memcpy(pvDst, pvBuf, cb);
1093 }
1094 else if (cb >= cbWrite)
1095 goto end;
1096 break;
1097 }
1098
1099 case MM_RAM_FLAGS_VIRTUAL_ALL:
1100 case MM_RAM_FLAGS_VIRTUAL_WRITE:
1101 {
1102 int rc = VINF_PGM_HANDLER_DO_DEFAULT;
1103 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
1104#ifdef IN_RING3
1105/** @todo deal with this in GC and R0! */
1106 /* Search the whole tree for matching physical addresses (rather expensive!) */
1107 PPGMVIRTHANDLER pNode;
1108 unsigned iPage;
1109 int rc2 = pgmHandlerVirtualFindByPhysAddr(pVM, GCPhys, &pNode, &iPage);
1110 if (VBOX_SUCCESS(rc2) && pNode->pfnHandlerHC)
1111 {
1112 size_t cbRange = pNode->Core.KeyLast - GCPhys + 1;
1113 if (cbRange < cb)
1114 cb = cbRange;
1115 if (cb > cbWrite)
1116 cb = cbWrite;
1117 RTGCUINTPTR GCPtr = ((RTGCUINTPTR)pNode->GCPtr & PAGE_BASE_GC_MASK)
1118 + (iPage << PAGE_SHIFT) + (off & PAGE_OFFSET_MASK);
1119
1120 void *pvDst = PGMRAMRANGE_GETHCPTR(pCur, off)
1121
1122 /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */
1123 rc = pNode->pfnHandlerHC(pVM, (RTGCPTR)GCPtr, pvDst, (void *)pvBuf, cb, PGMACCESSTYPE_WRITE, 0);
1124 }
1125#endif /* IN_RING3 */
1126 if (rc == VINF_PGM_HANDLER_DO_DEFAULT)
1127 {
1128#ifdef IN_GC
1129 void *pvDst = NULL;
1130 PGMGCDynMapHCPage(pVM, HCPhys & X86_PTE_PAE_PG_MASK, &pvDst);
1131 pvDst = (char *)pvDst + (off & PAGE_OFFSET_MASK);
1132#else
1133 void *pvDst = PGMRAMRANGE_GETHCPTR(pCur, off)
1134#endif
1135 if (cb >= cbWrite)
1136 {
1137 memcpy(pvDst, pvBuf, cbWrite);
1138 goto end;
1139 }
1140 memcpy(pvDst, pvBuf, cb);
1141 }
1142 else if (cb >= cbWrite)
1143 goto end;
1144 break;
1145 }
1146
1147 /*
1148 * Physical write handler + virtual write handler.
1149 * Consider this a quick workaround for the CSAM + shadow caching problem.
1150 *
1151 * We hand it to the shadow caching first since it requires the unchanged
1152 * data. CSAM will have to put up with it already being changed.
1153 */
1154 case MM_RAM_FLAGS_PHYSICAL_WRITE | MM_RAM_FLAGS_VIRTUAL_WRITE:
1155 {
1156 int rc = VINF_PGM_HANDLER_DO_DEFAULT;
1157 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
1158#ifdef IN_RING3 /** @todo deal with this in GC and R0! */
1159 /* 1. The physical handler */
1160 PPGMPHYSHANDLER pPhysNode = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.pTreesHC->PhysHandlers, GCPhys);
1161 if (pPhysNode && pPhysNode->pfnHandlerR3)
1162 {
1163 size_t cbRange = pPhysNode->Core.KeyLast - GCPhys + 1;
1164 if (cbRange < cb)
1165 cb = cbRange;
1166 if (cb > cbWrite)
1167 cb = cbWrite;
1168
1169 void *pvDst = PGMRAMRANGE_GETHCPTR(pCur, off)
1170
1171 /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */
1172 rc = pPhysNode->pfnHandlerR3(pVM, GCPhys, pvDst, (void *)pvBuf, cb, PGMACCESSTYPE_WRITE, pPhysNode->pvUserR3);
1173 }
1174
1175 /* 2. The virtual handler (will see incorrect data) */
1176 PPGMVIRTHANDLER pVirtNode;
1177 unsigned iPage;
1178 int rc2 = pgmHandlerVirtualFindByPhysAddr(pVM, GCPhys, &pVirtNode, &iPage);
1179 if (VBOX_SUCCESS(rc2) && pVirtNode->pfnHandlerHC)
1180 {
1181 size_t cbRange = pVirtNode->Core.KeyLast - GCPhys + 1;
1182 if (cbRange < cb)
1183 cb = cbRange;
1184 if (cb > cbWrite)
1185 cb = cbWrite;
1186 RTGCUINTPTR GCPtr = ((RTGCUINTPTR)pVirtNode->GCPtr & PAGE_BASE_GC_MASK)
1187 + (iPage << PAGE_SHIFT) + (off & PAGE_OFFSET_MASK);
1188
1189 void *pvDst = PGMRAMRANGE_GETHCPTR(pCur, off)
1190
1191 /** @note Dangerous assumption that HC handlers don't do anything that really requires an EMT lock! */
1192 rc2 = pVirtNode->pfnHandlerHC(pVM, (RTGCPTR)GCPtr, pvDst, (void *)pvBuf, cb, PGMACCESSTYPE_WRITE, 0);
1193 if ( ( rc2 != VINF_PGM_HANDLER_DO_DEFAULT
1194 && rc == VINF_PGM_HANDLER_DO_DEFAULT)
1195 || ( VBOX_FAILURE(rc2)
1196 && VBOX_SUCCESS(rc)))
1197 rc = rc2;
1198 }
1199#endif /* IN_RING3 */
1200 if (rc == VINF_PGM_HANDLER_DO_DEFAULT)
1201 {
1202#ifdef IN_GC
1203 void *pvDst = NULL;
1204 PGMGCDynMapHCPage(pVM, HCPhys & X86_PTE_PAE_PG_MASK, &pvDst);
1205 pvDst = (char *)pvDst + (off & PAGE_OFFSET_MASK);
1206#else
1207 void *pvDst = PGMRAMRANGE_GETHCPTR(pCur, off)
1208#endif
1209 if (cb >= cbWrite)
1210 {
1211 memcpy(pvDst, pvBuf, cbWrite);
1212 goto end;
1213 }
1214 memcpy(pvDst, pvBuf, cb);
1215 }
1216 else if (cb >= cbWrite)
1217 goto end;
1218 break;
1219 }
1220
1221
1222 /*
1223 * The rest needs to be taken more carefully.
1224 */
1225 default:
1226#if 1 /** @todo r=bird: Can you do this properly please. */
1227 /** @todo Try MMIO; quick hack */
1228 if (cbWrite <= 4 && IOMMMIOWrite(pVM, GCPhys, *(uint32_t *)pvBuf, cbWrite) == VINF_SUCCESS)
1229 goto end;
1230#endif
1231
1232 /** @todo fix me later. */
1233 AssertReleaseMsgFailed(("Unknown write at %VGp size %d implement the complex physical writing case %x\n",
1234 GCPhys, cbWrite,
1235 (HCPhys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2 | MM_RAM_FLAGS_VIRTUAL_ALL | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_PHYSICAL_ALL | MM_RAM_FLAGS_PHYSICAL_WRITE))));
1236 cb = PAGE_SIZE - (off & PAGE_OFFSET_MASK);
1237 break;
1238 }
1239
1240 cbWrite -= cb;
1241 off += cb;
1242 pvBuf = (const char *)pvBuf + cb;
1243 }
1244
1245 GCPhys = pCur->GCPhysLast + 1;
1246 }
1247 else
1248 {
1249 /*
1250 * Unassigned address space.
1251 */
1252 size_t cb;
1253 if ( !pCur
1254 || (cb = pCur->GCPhys - GCPhys) >= cbWrite)
1255 goto end;
1256
1257 cbWrite -= cb;
1258 pvBuf = (const char *)pvBuf + cb;
1259 GCPhys += cb;
1260 }
1261 }
1262end:
1263#ifdef IN_RING3
1264 if (fGrabbedLock)
1265 pgmUnlock(pVM);
1266#endif
1267 return;
1268}
1269
1270#ifndef IN_GC /* Ring 0 & 3 only */
1271
1272/**
1273 * Read from guest physical memory by GC physical address, bypassing
1274 * MMIO and access handlers.
1275 *
1276 * @returns VBox status.
1277 * @param pVM VM handle.
1278 * @param pvDst The destination address.
1279 * @param GCPhysSrc The source address (GC physical address).
1280 * @param cb The number of bytes to read.
1281 */
1282PGMDECL(int) PGMPhysReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb)
1283{
1284 /*
1285 * Anything to be done?
1286 */
1287 if (!cb)
1288 return VINF_SUCCESS;
1289
1290 /*
1291 * Loop ram ranges.
1292 */
1293 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
1294 pRam;
1295 pRam = pRam->CTXSUFF(pNext))
1296 {
1297 RTGCPHYS off = GCPhysSrc - pRam->GCPhys;
1298 if (off < pRam->cb)
1299 {
1300 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
1301 {
1302 /* Copy page by page as we're not dealing with a linear HC range. */
1303 for (;;)
1304 {
1305 /* convert */
1306 void *pvSrc;
1307 int rc = PGMRamGCPhys2HCPtr(pVM, pRam, GCPhysSrc, &pvSrc);
1308 if (VBOX_FAILURE(rc))
1309 return rc;
1310
1311 /* copy */
1312 size_t cbRead = PAGE_SIZE - ((RTGCUINTPTR)GCPhysSrc & PAGE_OFFSET_MASK);
1313 if (cbRead >= cb)
1314 {
1315 memcpy(pvDst, pvSrc, cb);
1316 return VINF_SUCCESS;
1317 }
1318 memcpy(pvDst, pvSrc, cbRead);
1319
1320 /* next */
1321 cb -= cbRead;
1322 pvDst = (uint8_t *)pvDst + cbRead;
1323 GCPhysSrc += cbRead;
1324 }
1325 }
1326 else if (pRam->pvHC)
1327 {
1328 /* read */
1329 size_t cbRead = pRam->cb - off;
1330 if (cbRead >= cb)
1331 {
1332 memcpy(pvDst, (uint8_t *)pRam->pvHC + off, cb);
1333 return VINF_SUCCESS;
1334 }
1335 memcpy(pvDst, (uint8_t *)pRam->pvHC + off, cbRead);
1336
1337 /* next */
1338 cb -= cbRead;
1339 pvDst = (uint8_t *)pvDst + cbRead;
1340 GCPhysSrc += cbRead;
1341 }
1342 else
1343 return VERR_PGM_PHYS_PAGE_RESERVED;
1344 }
1345 else if (GCPhysSrc < pRam->GCPhysLast)
1346 break;
1347 }
1348 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
1349}
1350
1351
1352/**
1353 * Write to guest physical memory referenced by GC pointer.
1354 * Write memory to GC physical address in guest physical memory.
1355 *
1356 * This will bypass MMIO and access handlers.
1357 *
1358 * @returns VBox status.
1359 * @param pVM VM handle.
1360 * @param GCPhysDst The GC physical address of the destination.
1361 * @param pvSrc The source buffer.
1362 * @param cb The number of bytes to write.
1363 */
1364PGMDECL(int) PGMPhysWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb)
1365{
1366 /*
1367 * Anything to be done?
1368 */
1369 if (!cb)
1370 return VINF_SUCCESS;
1371
1372 LogFlow(("PGMPhysWriteGCPhys: %VGp %d\n", GCPhysDst, cb));
1373
1374 /*
1375 * Loop ram ranges.
1376 */
1377 for (PPGMRAMRANGE pRam = CTXSUFF(pVM->pgm.s.pRamRanges);
1378 pRam;
1379 pRam = pRam->CTXSUFF(pNext))
1380 {
1381 RTGCPHYS off = GCPhysDst - pRam->GCPhys;
1382 if (off < pRam->cb)
1383 {
1384 if (pRam->fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
1385 {
1386 /* Copy page by page as we're not dealing with a linear HC range. */
1387 for (;;)
1388 {
1389 /* convert */
1390 void *pvDst;
1391 int rc = PGMRamGCPhys2HCPtr(pVM, pRam, GCPhysDst, &pvDst);
1392 if (VBOX_FAILURE(rc))
1393 return rc;
1394
1395 /* copy */
1396 size_t cbWrite = PAGE_SIZE - ((RTGCUINTPTR)GCPhysDst & PAGE_OFFSET_MASK);
1397 if (cbWrite >= cb)
1398 {
1399 memcpy(pvDst, pvSrc, cb);
1400 return VINF_SUCCESS;
1401 }
1402 memcpy(pvDst, pvSrc, cbWrite);
1403
1404 /* next */
1405 cb -= cbWrite;
1406 pvSrc = (uint8_t *)pvSrc + cbWrite;
1407 GCPhysDst += cbWrite;
1408 }
1409 }
1410 else if (pRam->pvHC)
1411 {
1412 /* write */
1413 size_t cbWrite = pRam->cb - off;
1414 if (cbWrite >= cb)
1415 {
1416 memcpy((uint8_t *)pRam->pvHC + off, pvSrc, cb);
1417 return VINF_SUCCESS;
1418 }
1419 memcpy((uint8_t *)pRam->pvHC + off, pvSrc, cbWrite);
1420
1421 /* next */
1422 cb -= cbWrite;
1423 GCPhysDst += cbWrite;
1424 pvSrc = (uint8_t *)pvSrc + cbWrite;
1425 }
1426 else
1427 return VERR_PGM_PHYS_PAGE_RESERVED;
1428 }
1429 else if (GCPhysDst < pRam->GCPhysLast)
1430 break;
1431 }
1432 return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
1433}
1434
1435
1436/**
1437 * Read from guest physical memory referenced by GC pointer.
1438 *
1439 * This function uses the current CR3/CR0/CR4 of the guest and will
1440 * bypass access handlers and not set any accessed bits.
1441 *
1442 * @returns VBox status.
1443 * @param pVM VM handle.
1444 * @param pvDst The destination address.
1445 * @param GCPtrSrc The source address (GC pointer).
1446 * @param cb The number of bytes to read.
1447 */
1448PGMDECL(int) PGMPhysReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb)
1449{
1450 /*
1451 * Anything to do?
1452 */
1453 if (!cb)
1454 return VINF_SUCCESS;
1455
1456 /*
1457 * Optimize reads within a single page.
1458 */
1459 if (((RTGCUINTPTR)GCPtrSrc & PAGE_OFFSET_MASK) + cb <= PAGE_SIZE)
1460 {
1461 void *pvSrc;
1462 int rc = PGMPhysGCPtr2HCPtr(pVM, GCPtrSrc, &pvSrc);
1463 if (VBOX_FAILURE(rc))
1464 return rc;
1465 memcpy(pvDst, pvSrc, cb);
1466 return VINF_SUCCESS;
1467 }
1468
1469 /*
1470 * Page by page.
1471 */
1472 for (;;)
1473 {
1474 /* convert */
1475 void *pvSrc;
1476 int rc = PGMPhysGCPtr2HCPtr(pVM, GCPtrSrc, &pvSrc);
1477 if (VBOX_FAILURE(rc))
1478 return rc;
1479
1480 /* copy */
1481 size_t cbRead = PAGE_SIZE - ((RTGCUINTPTR)GCPtrSrc & PAGE_OFFSET_MASK);
1482 if (cbRead >= cb)
1483 {
1484 memcpy(pvDst, pvSrc, cb);
1485 return VINF_SUCCESS;
1486 }
1487 memcpy(pvDst, pvSrc, cbRead);
1488
1489 /* next */
1490 cb -= cbRead;
1491 pvDst = (uint8_t *)pvDst + cbRead;
1492 GCPtrSrc += cbRead;
1493 }
1494}
1495
1496
1497/**
1498 * Write to guest physical memory referenced by GC pointer.
1499 *
1500 * This function uses the current CR3/CR0/CR4 of the guest and will
1501 * bypass access handlers and not set dirty or accessed bits.
1502 *
1503 * @returns VBox status.
1504 * @param pVM VM handle.
1505 * @param GCPtrDst The destination address (GC pointer).
1506 * @param pvSrc The source address.
1507 * @param cb The number of bytes to write.
1508 */
1509PGMDECL(int) PGMPhysWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
1510{
1511 /*
1512 * Anything to do?
1513 */
1514 if (!cb)
1515 return VINF_SUCCESS;
1516
1517 LogFlow(("PGMPhysWriteGCPtr: %VGv %d\n", GCPtrDst, cb));
1518
1519 /*
1520 * Optimize writes within a single page.
1521 */
1522 if (((RTGCUINTPTR)GCPtrDst & PAGE_OFFSET_MASK) + cb <= PAGE_SIZE)
1523 {
1524 void *pvDst;
1525 int rc = PGMPhysGCPtr2HCPtr(pVM, GCPtrDst, &pvDst);
1526 if (VBOX_FAILURE(rc))
1527 return rc;
1528 memcpy(pvDst, pvSrc, cb);
1529 return VINF_SUCCESS;
1530 }
1531
1532 /*
1533 * Page by page.
1534 */
1535 for (;;)
1536 {
1537 /* convert */
1538 void *pvDst;
1539 int rc = PGMPhysGCPtr2HCPtr(pVM, GCPtrDst, &pvDst);
1540 if (VBOX_FAILURE(rc))
1541 return rc;
1542
1543 /* copy */
1544 size_t cbWrite = PAGE_SIZE - ((RTGCUINTPTR)GCPtrDst & PAGE_OFFSET_MASK);
1545 if (cbWrite >= cb)
1546 {
1547 memcpy(pvDst, pvSrc, cb);
1548 return VINF_SUCCESS;
1549 }
1550 memcpy(pvDst, pvSrc, cbWrite);
1551
1552 /* next */
1553 cb -= cbWrite;
1554 pvSrc = (uint8_t *)pvSrc + cbWrite;
1555 GCPtrDst += cbWrite;
1556 }
1557}
1558
1559
1560/**
1561 * Write to guest physical memory referenced by GC pointer and update the PTE.
1562 *
1563 * This function uses the current CR3/CR0/CR4 of the guest and will
1564 * bypass access handlers and set any dirty and accessed bits in the PTE.
1565 *
1566 * If you don't want to set the dirty bit, use PGMPhysWriteGCPtr().
1567 *
1568 * @returns VBox status.
1569 * @param pVM VM handle.
1570 * @param GCPtrDst The destination address (GC pointer).
1571 * @param pvSrc The source address.
1572 * @param cb The number of bytes to write.
1573 */
1574PGMDECL(int) PGMPhysWriteGCPtrDirty(PVM pVM, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
1575{
1576 /*
1577 * Anything to do?
1578 */
1579 if (!cb)
1580 return VINF_SUCCESS;
1581
1582 /*
1583 * Optimize writes within a single page.
1584 */
1585 if (((RTGCUINTPTR)GCPtrDst & PAGE_OFFSET_MASK) + cb <= PAGE_SIZE)
1586 {
1587 void *pvDst;
1588 int rc = PGMPhysGCPtr2HCPtr(pVM, GCPtrDst, &pvDst);
1589 if (VBOX_FAILURE(rc))
1590 return rc;
1591 memcpy(pvDst, pvSrc, cb);
1592 rc = PGMGstModifyPage(pVM, GCPtrDst, cb, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
1593 AssertRC(rc);
1594 return VINF_SUCCESS;
1595 }
1596
1597 /*
1598 * Page by page.
1599 */
1600 for (;;)
1601 {
1602 /* convert */
1603 void *pvDst;
1604 int rc = PGMPhysGCPtr2HCPtr(pVM, GCPtrDst, &pvDst);
1605 if (VBOX_FAILURE(rc))
1606 return rc;
1607
1608 /* mark the guest page as accessed and dirty. */
1609 rc = PGMGstModifyPage(pVM, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
1610 AssertRC(rc);
1611
1612 /* copy */
1613 size_t cbWrite = PAGE_SIZE - ((RTGCUINTPTR)GCPtrDst & PAGE_OFFSET_MASK);
1614 if (cbWrite >= cb)
1615 {
1616 memcpy(pvDst, pvSrc, cb);
1617 return VINF_SUCCESS;
1618 }
1619 memcpy(pvDst, pvSrc, cbWrite);
1620
1621 /* next */
1622 cb -= cbWrite;
1623 GCPtrDst += cbWrite;
1624 pvSrc = (char *)pvSrc + cbWrite;
1625 }
1626}
1627
1628#endif /* !IN_GC */
1629
1630
1631
1632/**
1633 * Performs a read of guest virtual memory for instruction emulation.
1634 *
1635 * This will check permissions, raise exceptions and update the access bits.
1636 *
1637 * The current implementation will bypass all access handlers. It may later be
1638 * changed to at least respect MMIO.
1639 *
1640 *
1641 * @returns VBox status code suitable to scheduling.
1642 * @retval VINF_SUCCESS if the read was performed successfully.
1643 * @retval VINF_EM_RAW_GUEST_TRAP if an exception was raised but not dispatched yet.
1644 * @retval VINF_TRPM_XCPT_DISPATCHED if an exception was raised and dispatched.
1645 *
1646 * @param pVM The VM handle.
1647 * @param pCtxCore The context core.
1648 * @param pvDst Where to put the bytes we've read.
1649 * @param GCPtrSrc The source address.
1650 * @param cb The number of bytes to read. Not more than a page.
1651 *
1652 * @remark This function will dynamically map physical pages in GC. This may unmap
1653 * mappings done by the caller. Be careful!
1654 */
1655PGMDECL(int) PGMPhysInterpretedRead(PVM pVM, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCUINTPTR GCPtrSrc, size_t cb)
1656{
1657 Assert(cb <= PAGE_SIZE);
1658
1659/** @todo r=bird: This isn't perfect!
1660 * -# It's not checking for reserved bits being 1.
1661 * -# It's not correctly dealing with the access bit.
1662 * -# It's not respecting MMIO memory or any other access handlers.
1663 */
1664 /*
1665 * 1. Translate virtual to physical. This may fault.
1666 * 2. Map the physical address.
1667 * 3. Do the read operation.
1668 * 4. Set access bits if required.
1669 */
1670 int rc;
1671 unsigned cb1 = PAGE_SIZE - (GCPtrSrc & PAGE_OFFSET_MASK);
1672 if (cb <= cb1)
1673 {
1674 /*
1675 * Not crossing pages.
1676 */
1677 RTGCPHYS GCPhys;
1678 uint64_t fFlags;
1679 rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrSrc, &fFlags, &GCPhys);
1680 if (VBOX_SUCCESS(rc))
1681 {
1682 /** @todo we should check reserved bits ... */
1683 void *pvSrc;
1684 rc = PGM_GCPHYS_2_PTR(pVM, GCPhys, &pvSrc);
1685 switch (rc)
1686 {
1687 case VINF_SUCCESS:
1688Log(("PGMPhysInterpretedRead: pvDst=%p pvSrc=%p cb=%d\n", pvDst, (uint8_t *)pvSrc + (GCPtrSrc & PAGE_OFFSET_MASK), cb));
1689 memcpy(pvDst, (uint8_t *)pvSrc + (GCPtrSrc & PAGE_OFFSET_MASK), cb);
1690 break;
1691 case VERR_PGM_PHYS_PAGE_RESERVED:
1692 case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
1693 memset(pvDst, 0, cb);
1694 break;
1695 default:
1696 return rc;
1697 }
1698
1699 /** @todo access bit emulation isn't 100% correct. */
1700 if (!(fFlags & X86_PTE_A))
1701 {
1702 rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrSrc, 1, X86_PTE_A, ~(uint64_t)X86_PTE_A);
1703 AssertRC(rc);
1704 }
1705 return VINF_SUCCESS;
1706 }
1707 }
1708 else
1709 {
1710 /*
1711 * Crosses pages.
1712 */
1713 unsigned cb2 = cb - cb1;
1714 uint64_t fFlags1;
1715 RTGCPHYS GCPhys1;
1716 uint64_t fFlags2;
1717 RTGCPHYS GCPhys2;
1718 rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrSrc, &fFlags1, &GCPhys1);
1719 if (VBOX_SUCCESS(rc))
1720 rc = PGM_GST_PFN(GetPage,pVM)(pVM, GCPtrSrc + cb1, &fFlags2, &GCPhys2);
1721 if (VBOX_SUCCESS(rc))
1722 {
1723 /** @todo we should check reserved bits ... */
1724AssertMsgFailed(("cb=%d cb1=%d cb2=%d GCPtrSrc=%VGv\n", cb, cb1, cb2, GCPtrSrc));
1725 void *pvSrc1;
1726 rc = PGM_GCPHYS_2_PTR(pVM, GCPhys1, &pvSrc1);
1727 switch (rc)
1728 {
1729 case VINF_SUCCESS:
1730 memcpy(pvDst, (uint8_t *)pvSrc1 + (GCPtrSrc & PAGE_OFFSET_MASK), cb1);
1731 break;
1732 case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
1733 memset(pvDst, 0, cb1);
1734 break;
1735 default:
1736 return rc;
1737 }
1738
1739 void *pvSrc2;
1740 rc = PGM_GCPHYS_2_PTR(pVM, GCPhys2, &pvSrc2);
1741 switch (rc)
1742 {
1743 case VINF_SUCCESS:
1744 memcpy((uint8_t *)pvDst + cb2, pvSrc2, cb2);
1745 break;
1746 case VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS:
1747 memset((uint8_t *)pvDst + cb2, 0, cb2);
1748 break;
1749 default:
1750 return rc;
1751 }
1752
1753 if (!(fFlags1 & X86_PTE_A))
1754 {
1755 rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrSrc, 1, X86_PTE_A, ~(uint64_t)X86_PTE_A);
1756 AssertRC(rc);
1757 }
1758 if (!(fFlags2 & X86_PTE_A))
1759 {
1760 rc = PGM_GST_PFN(ModifyPage,pVM)(pVM, GCPtrSrc + cb1, 1, X86_PTE_A, ~(uint64_t)X86_PTE_A);
1761 AssertRC(rc);
1762 }
1763 return VINF_SUCCESS;
1764 }
1765 }
1766
1767 /*
1768 * Raise a #PF.
1769 */
1770 uint32_t uErr;
1771
1772 /* Get the current privilege level. */
1773 uint32_t cpl = CPUMGetGuestCPL(pVM, pCtxCore);
1774 switch (rc)
1775 {
1776 case VINF_SUCCESS:
1777 uErr = (cpl >= 2) ? X86_TRAP_PF_RSVD | X86_TRAP_PF_US : X86_TRAP_PF_RSVD;
1778 break;
1779
1780 case VERR_PAGE_NOT_PRESENT:
1781 case VERR_PAGE_TABLE_NOT_PRESENT:
1782 uErr = (cpl >= 2) ? X86_TRAP_PF_US : 0;
1783 break;
1784
1785 default:
1786 AssertMsgFailed(("rc=%Vrc GCPtrSrc=%VGv cb=%#x\n", rc, GCPtrSrc, cb));
1787 return rc;
1788 }
1789 Log(("PGMPhysInterpretedRead: GCPtrSrc=%VGv cb=%#x -> #PF(%#x)\n", GCPtrSrc, cb, uErr));
1790 return TRPMRaiseXcptErrCR2(pVM, pCtxCore, X86_XCPT_PF, uErr, GCPtrSrc);
1791}
1792
1793/// @todo PGMDECL(int) PGMPhysInterpretedWrite(PVM pVM, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
1794
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