VirtualBox

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

Last change on this file since 4050 was 4013, checked in by vboxsync, 17 years ago

pdm.h = include pdm*.h; pdmapi.h = only the 'core' pdm APIs.

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