VirtualBox

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

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

style

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