VirtualBox

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

Last change on this file since 4295 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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