VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PGMDbg.cpp@ 86462

Last change on this file since 86462 was 86461, checked in by vboxsync, 5 years ago

VMM/PGM: Don't check for, or even define, PGM_PDFLAGS_MAPPING when PGM_WITHOUT_MAPPINGS is active (the default now).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 123.1 KB
Line 
1/* $Id: PGMDbg.cpp 86461 2020-10-06 16:40:59Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - Debugger & Debugging APIs.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_PGM
23#include <VBox/vmm/pgm.h>
24#include <VBox/vmm/stam.h>
25#include "PGMInternal.h"
26#include <VBox/vmm/vm.h>
27#include <VBox/vmm/uvm.h>
28#include "PGMInline.h"
29#include <iprt/assert.h>
30#include <iprt/asm.h>
31#include <iprt/string.h>
32#include <VBox/log.h>
33#include <VBox/param.h>
34#include <VBox/err.h>
35
36
37/*********************************************************************************************************************************
38* Defined Constants And Macros *
39*********************************************************************************************************************************/
40/** The max needle size that we will bother searching for
41 * This must not be more than half a page! */
42#define MAX_NEEDLE_SIZE 256
43
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48/**
49 * State structure for the paging hierarchy dumpers.
50 */
51typedef struct PGMR3DUMPHIERARCHYSTATE
52{
53 /** Pointer to the VM. */
54 PVM pVM;
55 /** Output helpers. */
56 PCDBGFINFOHLP pHlp;
57 /** Set if PSE, PAE or long mode is enabled. */
58 bool fPse;
59 /** Set if PAE or long mode is enabled. */
60 bool fPae;
61 /** Set if long mode is enabled. */
62 bool fLme;
63 /** Set if nested paging. */
64 bool fNp;
65 /** Set if EPT. */
66 bool fEpt;
67 /** Set if NXE is enabled. */
68 bool fNxe;
69 /** The number or chars the address needs. */
70 uint8_t cchAddress;
71 /** The last reserved bit. */
72 uint8_t uLastRsvdBit;
73 /** Dump the page info as well (shadow page summary / guest physical
74 * page summary). */
75 bool fDumpPageInfo;
76 /** Whether or not to print the header. */
77 bool fPrintHeader;
78 /** Whether to print the CR3 value */
79 bool fPrintCr3;
80 /** Padding*/
81 bool afReserved[5];
82 /** The current address. */
83 uint64_t u64Address;
84 /** The last address to dump structures for. */
85 uint64_t u64FirstAddress;
86 /** The last address to dump structures for. */
87 uint64_t u64LastAddress;
88 /** Mask with the high reserved bits set. */
89 uint64_t u64HighReservedBits;
90 /** The number of leaf entries that we've printed. */
91 uint64_t cLeaves;
92} PGMR3DUMPHIERARCHYSTATE;
93/** Pointer to the paging hierarchy dumper state. */
94typedef PGMR3DUMPHIERARCHYSTATE *PPGMR3DUMPHIERARCHYSTATE;
95
96
97/**
98 * Assembly scanning function.
99 *
100 * @returns Pointer to possible match or NULL.
101 * @param pvHaystack Pointer to what we search in.
102 * @param cbHaystack Number of bytes to search.
103 * @param pvNeedle Pointer to what we search for.
104 * @param cbNeedle Size of what we're searching for.
105 */
106
107typedef DECLCALLBACKTYPE(uint8_t const *, FNPGMR3DBGFIXEDMEMSCAN,(void const *pvHaystack, uint32_t cbHaystack,
108 void const *pvNeedle, size_t cbNeedle));
109/** Pointer to an fixed size and step assembly scanner function. */
110typedef FNPGMR3DBGFIXEDMEMSCAN *PFNPGMR3DBGFIXEDMEMSCAN;
111
112
113/*********************************************************************************************************************************
114* Internal Functions *
115*********************************************************************************************************************************/
116DECLASM(uint8_t const *) pgmR3DbgFixedMemScan8Wide8Step(void const *, uint32_t, void const *, size_t cbNeedle);
117DECLASM(uint8_t const *) pgmR3DbgFixedMemScan4Wide4Step(void const *, uint32_t, void const *, size_t cbNeedle);
118DECLASM(uint8_t const *) pgmR3DbgFixedMemScan2Wide2Step(void const *, uint32_t, void const *, size_t cbNeedle);
119DECLASM(uint8_t const *) pgmR3DbgFixedMemScan1Wide1Step(void const *, uint32_t, void const *, size_t cbNeedle);
120DECLASM(uint8_t const *) pgmR3DbgFixedMemScan4Wide1Step(void const *, uint32_t, void const *, size_t cbNeedle);
121DECLASM(uint8_t const *) pgmR3DbgFixedMemScan8Wide1Step(void const *, uint32_t, void const *, size_t cbNeedle);
122
123
124/**
125 * Converts a R3 pointer to a GC physical address.
126 *
127 * Only for the debugger.
128 *
129 * @returns VBox status code.
130 * @retval VINF_SUCCESS on success, *pGCPhys is set.
131 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
132 *
133 * @param pUVM The user mode VM handle.
134 * @param R3Ptr The R3 pointer to convert.
135 * @param pGCPhys Where to store the GC physical address on success.
136 */
137VMMR3DECL(int) PGMR3DbgR3Ptr2GCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTGCPHYS pGCPhys)
138{
139 NOREF(pUVM); NOREF(R3Ptr);
140 *pGCPhys = NIL_RTGCPHYS;
141 return VERR_NOT_IMPLEMENTED;
142}
143
144
145/**
146 * Converts a R3 pointer to a HC physical address.
147 *
148 * Only for the debugger.
149 *
150 * @returns VBox status code.
151 * @retval VINF_SUCCESS on success, *pHCPhys is set.
152 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical page but has no physical backing.
153 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
154 *
155 * @param pUVM The user mode VM handle.
156 * @param R3Ptr The R3 pointer to convert.
157 * @param pHCPhys Where to store the HC physical address on success.
158 */
159VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys)
160{
161 NOREF(pUVM); NOREF(R3Ptr);
162 *pHCPhys = NIL_RTHCPHYS;
163 return VERR_NOT_IMPLEMENTED;
164}
165
166
167/**
168 * Converts a HC physical address to a GC physical address.
169 *
170 * Only for the debugger.
171 *
172 * @returns VBox status code
173 * @retval VINF_SUCCESS on success, *pGCPhys is set.
174 * @retval VERR_INVALID_POINTER if the HC physical address is not within the GC physical memory.
175 *
176 * @param pUVM The user mode VM handle.
177 * @param HCPhys The HC physical address to convert.
178 * @param pGCPhys Where to store the GC physical address on success.
179 */
180VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PUVM pUVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys)
181{
182 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
183 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
184
185 /*
186 * Validate and adjust the input a bit.
187 */
188 if (HCPhys == NIL_RTHCPHYS)
189 return VERR_INVALID_POINTER;
190 unsigned off = HCPhys & PAGE_OFFSET_MASK;
191 HCPhys &= X86_PTE_PAE_PG_MASK;
192 if (HCPhys == 0)
193 return VERR_INVALID_POINTER;
194
195 for (PPGMRAMRANGE pRam = pUVM->pVM->pgm.s.CTX_SUFF(pRamRangesX);
196 pRam;
197 pRam = pRam->CTX_SUFF(pNext))
198 {
199 uint32_t iPage = pRam->cb >> PAGE_SHIFT;
200 while (iPage-- > 0)
201 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
202 {
203 *pGCPhys = pRam->GCPhys + (iPage << PAGE_SHIFT) + off;
204 return VINF_SUCCESS;
205 }
206 }
207 return VERR_INVALID_POINTER;
208}
209
210
211/**
212 * Read physical memory API for the debugger, similar to
213 * PGMPhysSimpleReadGCPhys.
214 *
215 * @returns VBox status code.
216 *
217 * @param pVM The cross context VM structure.
218 * @param pvDst Where to store what's read.
219 * @param GCPhysSrc Where to start reading from.
220 * @param cb The number of bytes to attempt reading.
221 * @param fFlags Flags, MBZ.
222 * @param pcbRead For store the actual number of bytes read, pass NULL if
223 * partial reads are unwanted.
224 * @todo Unused?
225 */
226VMMR3_INT_DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
227{
228 /* validate */
229 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
230 AssertReturn(pVM, VERR_INVALID_PARAMETER);
231
232 /* try simple first. */
233 int rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cb);
234 if (RT_SUCCESS(rc) || !pcbRead)
235 return rc;
236
237 /* partial read that failed, chop it up in pages. */
238 *pcbRead = 0;
239 rc = VINF_SUCCESS;
240 while (cb > 0)
241 {
242 size_t cbChunk = PAGE_SIZE;
243 cbChunk -= GCPhysSrc & PAGE_OFFSET_MASK;
244 if (cbChunk > cb)
245 cbChunk = cb;
246
247 rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cbChunk);
248
249 /* advance */
250 if (RT_FAILURE(rc))
251 break;
252 *pcbRead += cbChunk;
253 cb -= cbChunk;
254 GCPhysSrc += cbChunk;
255 pvDst = (uint8_t *)pvDst + cbChunk;
256 }
257
258 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
259}
260
261
262/**
263 * Write physical memory API for the debugger, similar to
264 * PGMPhysSimpleWriteGCPhys.
265 *
266 * @returns VBox status code.
267 *
268 * @param pVM The cross context VM structure.
269 * @param GCPhysDst Where to start writing.
270 * @param pvSrc What to write.
271 * @param cb The number of bytes to attempt writing.
272 * @param fFlags Flags, MBZ.
273 * @param pcbWritten For store the actual number of bytes written, pass NULL
274 * if partial writes are unwanted.
275 * @todo Unused?
276 */
277VMMR3_INT_DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
278{
279 /* validate */
280 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
281 AssertReturn(pVM, VERR_INVALID_PARAMETER);
282
283 /* try simple first. */
284 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cb);
285 if (RT_SUCCESS(rc) || !pcbWritten)
286 return rc;
287
288 /* partial write that failed, chop it up in pages. */
289 *pcbWritten = 0;
290 rc = VINF_SUCCESS;
291 while (cb > 0)
292 {
293 size_t cbChunk = PAGE_SIZE;
294 cbChunk -= GCPhysDst & PAGE_OFFSET_MASK;
295 if (cbChunk > cb)
296 cbChunk = cb;
297
298 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cbChunk);
299
300 /* advance */
301 if (RT_FAILURE(rc))
302 break;
303 *pcbWritten += cbChunk;
304 cb -= cbChunk;
305 GCPhysDst += cbChunk;
306 pvSrc = (uint8_t const *)pvSrc + cbChunk;
307 }
308
309 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
310
311}
312
313
314/**
315 * Read virtual memory API for the debugger, similar to PGMPhysSimpleReadGCPtr.
316 *
317 * @returns VBox status code.
318 *
319 * @param pVM The cross context VM structure.
320 * @param pvDst Where to store what's read.
321 * @param GCPtrSrc Where to start reading from.
322 * @param cb The number of bytes to attempt reading.
323 * @param fFlags Flags, MBZ.
324 * @param pcbRead For store the actual number of bytes read, pass NULL if
325 * partial reads are unwanted.
326 * @todo Unused?
327 */
328VMMR3_INT_DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
329{
330 /* validate */
331 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
332 AssertReturn(pVM, VERR_INVALID_PARAMETER);
333
334 /** @todo SMP support! */
335 PVMCPU pVCpu = pVM->apCpusR3[0];
336
337/** @todo deal with HMA */
338 /* try simple first. */
339 int rc = PGMPhysSimpleReadGCPtr(pVCpu, pvDst, GCPtrSrc, cb);
340 if (RT_SUCCESS(rc) || !pcbRead)
341 return rc;
342
343 /* partial read that failed, chop it up in pages. */
344 *pcbRead = 0;
345 rc = VINF_SUCCESS;
346 while (cb > 0)
347 {
348 size_t cbChunk = PAGE_SIZE;
349 cbChunk -= GCPtrSrc & PAGE_OFFSET_MASK;
350 if (cbChunk > cb)
351 cbChunk = cb;
352
353 rc = PGMPhysSimpleReadGCPtr(pVCpu, pvDst, GCPtrSrc, cbChunk);
354
355 /* advance */
356 if (RT_FAILURE(rc))
357 break;
358 *pcbRead += cbChunk;
359 cb -= cbChunk;
360 GCPtrSrc += cbChunk;
361 pvDst = (uint8_t *)pvDst + cbChunk;
362 }
363
364 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
365
366}
367
368
369/**
370 * Write virtual memory API for the debugger, similar to
371 * PGMPhysSimpleWriteGCPtr.
372 *
373 * @returns VBox status code.
374 *
375 * @param pVM The cross context VM structure.
376 * @param GCPtrDst Where to start writing.
377 * @param pvSrc What to write.
378 * @param cb The number of bytes to attempt writing.
379 * @param fFlags Flags, MBZ.
380 * @param pcbWritten For store the actual number of bytes written, pass NULL
381 * if partial writes are unwanted.
382 * @todo Unused?
383 */
384VMMR3_INT_DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
385{
386 /* validate */
387 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
388 AssertReturn(pVM, VERR_INVALID_PARAMETER);
389
390 /** @todo SMP support! */
391 PVMCPU pVCpu = pVM->apCpusR3[0];
392
393/** @todo deal with HMA */
394 /* try simple first. */
395 int rc = PGMPhysSimpleWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cb);
396 if (RT_SUCCESS(rc) || !pcbWritten)
397 return rc;
398
399 /* partial write that failed, chop it up in pages. */
400 *pcbWritten = 0;
401 rc = VINF_SUCCESS;
402 while (cb > 0)
403 {
404 size_t cbChunk = PAGE_SIZE;
405 cbChunk -= GCPtrDst & PAGE_OFFSET_MASK;
406 if (cbChunk > cb)
407 cbChunk = cb;
408
409 rc = PGMPhysSimpleWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cbChunk);
410
411 /* advance */
412 if (RT_FAILURE(rc))
413 break;
414 *pcbWritten += cbChunk;
415 cb -= cbChunk;
416 GCPtrDst += cbChunk;
417 pvSrc = (uint8_t const *)pvSrc + cbChunk;
418 }
419
420 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
421
422}
423
424
425/**
426 * memchr() with alignment considerations.
427 *
428 * @returns Pointer to matching byte, NULL if none found.
429 * @param pb Where to search. Aligned.
430 * @param b What to search for.
431 * @param cb How much to search .
432 * @param uAlign The alignment restriction of the result.
433 */
434static const uint8_t *pgmR3DbgAlignedMemChr(const uint8_t *pb, uint8_t b, size_t cb, uint32_t uAlign)
435{
436 const uint8_t *pbRet;
437 if (uAlign <= 32)
438 {
439 pbRet = (const uint8_t *)memchr(pb, b, cb);
440 if ((uintptr_t)pbRet & (uAlign - 1))
441 {
442 do
443 {
444 pbRet++;
445 size_t cbLeft = cb - (pbRet - pb);
446 if (!cbLeft)
447 {
448 pbRet = NULL;
449 break;
450 }
451 pbRet = (const uint8_t *)memchr(pbRet, b, cbLeft);
452 } while ((uintptr_t)pbRet & (uAlign - 1));
453 }
454 }
455 else
456 {
457 pbRet = NULL;
458 if (cb)
459 {
460 for (;;)
461 {
462 if (*pb == b)
463 {
464 pbRet = pb;
465 break;
466 }
467 if (cb <= uAlign)
468 break;
469 cb -= uAlign;
470 pb += uAlign;
471 }
472 }
473 }
474 return pbRet;
475}
476
477
478/**
479 * Scans a page for a byte string, keeping track of potential
480 * cross page matches.
481 *
482 * @returns true and *poff on match.
483 * false on mismatch.
484 * @param pbPage Pointer to the current page.
485 * @param poff Input: The offset into the page (aligned).
486 * Output: The page offset of the match on success.
487 * @param cb The number of bytes to search, starting of *poff.
488 * @param uAlign The needle alignment. This is of course less than a page.
489 * @param pabNeedle The byte string to search for.
490 * @param cbNeedle The length of the byte string.
491 * @param pfnFixedMemScan Pointer to assembly scan function, if available for
492 * the given needle and alignment combination.
493 * @param pabPrev The buffer that keeps track of a partial match that we
494 * bring over from the previous page. This buffer must be
495 * at least cbNeedle - 1 big.
496 * @param pcbPrev Input: The number of partial matching bytes from the previous page.
497 * Output: The number of partial matching bytes from this page.
498 * Initialize to 0 before the first call to this function.
499 */
500static bool pgmR3DbgScanPage(const uint8_t *pbPage, int32_t *poff, uint32_t cb, uint32_t uAlign,
501 const uint8_t *pabNeedle, size_t cbNeedle, PFNPGMR3DBGFIXEDMEMSCAN pfnFixedMemScan,
502 uint8_t *pabPrev, size_t *pcbPrev)
503{
504 /*
505 * Try complete any partial match from the previous page.
506 */
507 if (*pcbPrev > 0)
508 {
509 size_t cbPrev = *pcbPrev;
510 Assert(!*poff);
511 Assert(cbPrev < cbNeedle);
512 if (!memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
513 {
514 if (cbNeedle - cbPrev > cb)
515 return false;
516 *poff = -(int32_t)cbPrev;
517 return true;
518 }
519
520 /* check out the remainder of the previous page. */
521 const uint8_t *pb = pabPrev;
522 for (;;)
523 {
524 if (cbPrev <= uAlign)
525 break;
526 cbPrev -= uAlign;
527 pb = pgmR3DbgAlignedMemChr(pb + uAlign, *pabNeedle, cbPrev, uAlign);
528 if (!pb)
529 break;
530 cbPrev = *pcbPrev - (pb - pabPrev);
531 if ( !memcmp(pb + 1, &pabNeedle[1], cbPrev - 1)
532 && !memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
533 {
534 if (cbNeedle - cbPrev > cb)
535 return false;
536 *poff = -(int32_t)cbPrev;
537 return true;
538 }
539 }
540
541 *pcbPrev = 0;
542 }
543
544 /*
545 * Match the body of the page.
546 */
547 const uint8_t *pb = pbPage + *poff;
548 const uint8_t * const pbEnd = pb + cb;
549 for (;;)
550 {
551 AssertMsg(((uintptr_t)pb & (uAlign - 1)) == 0, ("%#p %#x\n", pb, uAlign));
552 if (pfnFixedMemScan)
553 pb = pfnFixedMemScan(pb, cb, pabNeedle, cbNeedle);
554 else
555 pb = pgmR3DbgAlignedMemChr(pb, *pabNeedle, cb, uAlign);
556 if (!pb)
557 break;
558 cb = pbEnd - pb;
559 if (cb >= cbNeedle)
560 {
561 /* match? */
562 if (!memcmp(pb + 1, &pabNeedle[1], cbNeedle - 1))
563 {
564 *poff = pb - pbPage;
565 return true;
566 }
567 }
568 else
569 {
570 /* partial match at the end of the page? */
571 if (!memcmp(pb + 1, &pabNeedle[1], cb - 1))
572 {
573 /* We're copying one byte more that we really need here, but wtf. */
574 memcpy(pabPrev, pb, cb);
575 *pcbPrev = cb;
576 return false;
577 }
578 }
579
580 /* no match, skip ahead. */
581 if (cb <= uAlign)
582 break;
583 pb += uAlign;
584 cb -= uAlign;
585 }
586
587 return false;
588}
589
590
591static PFNPGMR3DBGFIXEDMEMSCAN pgmR3DbgSelectMemScanFunction(uint32_t GCPhysAlign, size_t cbNeedle)
592{
593 switch (GCPhysAlign)
594 {
595 case 1:
596 if (cbNeedle >= 8)
597 return pgmR3DbgFixedMemScan8Wide1Step;
598 if (cbNeedle >= 4)
599 return pgmR3DbgFixedMemScan4Wide1Step;
600 return pgmR3DbgFixedMemScan1Wide1Step;
601 case 2:
602 if (cbNeedle >= 2)
603 return pgmR3DbgFixedMemScan2Wide2Step;
604 break;
605 case 4:
606 if (cbNeedle >= 4)
607 return pgmR3DbgFixedMemScan4Wide4Step;
608 break;
609 case 8:
610 if (cbNeedle >= 8)
611 return pgmR3DbgFixedMemScan8Wide8Step;
612 break;
613 }
614 return NULL;
615}
616
617
618
619/**
620 * Scans guest physical memory for a byte string.
621 *
622 * @returns VBox status codes:
623 * @retval VINF_SUCCESS and *pGCPtrHit on success.
624 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
625 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
626 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
627 *
628 * @param pVM The cross context VM structure.
629 * @param GCPhys Where to start searching.
630 * @param cbRange The number of bytes to search.
631 * @param GCPhysAlign The alignment of the needle. Must be a power of two
632 * and less or equal to 4GB.
633 * @param pabNeedle The byte string to search for.
634 * @param cbNeedle The length of the byte string. Max 256 bytes.
635 * @param pGCPhysHit Where to store the address of the first occurrence on success.
636 */
637VMMR3_INT_DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign,
638 const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit)
639{
640 /*
641 * Validate and adjust the input a bit.
642 */
643 if (!VALID_PTR(pGCPhysHit))
644 return VERR_INVALID_POINTER;
645 *pGCPhysHit = NIL_RTGCPHYS;
646
647 if ( !VALID_PTR(pabNeedle)
648 || GCPhys == NIL_RTGCPHYS)
649 return VERR_INVALID_POINTER;
650 if (!cbNeedle)
651 return VERR_INVALID_PARAMETER;
652 if (cbNeedle > MAX_NEEDLE_SIZE)
653 return VERR_INVALID_PARAMETER;
654
655 if (!cbRange)
656 return VERR_DBGF_MEM_NOT_FOUND;
657 if (GCPhys + cbNeedle - 1 < GCPhys)
658 return VERR_DBGF_MEM_NOT_FOUND;
659
660 if (!GCPhysAlign)
661 return VERR_INVALID_PARAMETER;
662 if (GCPhysAlign > UINT32_MAX)
663 return VERR_NOT_POWER_OF_TWO;
664 if (GCPhysAlign & (GCPhysAlign - 1))
665 return VERR_INVALID_PARAMETER;
666
667 if (GCPhys & (GCPhysAlign - 1))
668 {
669 RTGCPHYS Adj = GCPhysAlign - (GCPhys & (GCPhysAlign - 1));
670 if ( cbRange <= Adj
671 || GCPhys + Adj < GCPhys)
672 return VERR_DBGF_MEM_NOT_FOUND;
673 GCPhys += Adj;
674 cbRange -= Adj;
675 }
676
677 const bool fAllZero = ASMMemIsZero(pabNeedle, cbNeedle);
678 const uint32_t cIncPages = GCPhysAlign <= PAGE_SIZE
679 ? 1
680 : GCPhysAlign >> PAGE_SHIFT;
681 const RTGCPHYS GCPhysLast = GCPhys + cbRange - 1 >= GCPhys
682 ? GCPhys + cbRange - 1
683 : ~(RTGCPHYS)0;
684
685 PFNPGMR3DBGFIXEDMEMSCAN pfnMemScan = pgmR3DbgSelectMemScanFunction((uint32_t)GCPhysAlign, cbNeedle);
686
687 /*
688 * Search the memory - ignore MMIO and zero pages, also don't
689 * bother to match across ranges.
690 */
691 pgmLock(pVM);
692 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX);
693 pRam;
694 pRam = pRam->CTX_SUFF(pNext))
695 {
696 /*
697 * If the search range starts prior to the current ram range record,
698 * adjust the search range and possibly conclude the search.
699 */
700 RTGCPHYS off;
701 if (GCPhys < pRam->GCPhys)
702 {
703 if (GCPhysLast < pRam->GCPhys)
704 break;
705 GCPhys = pRam->GCPhys;
706 off = 0;
707 }
708 else
709 off = GCPhys - pRam->GCPhys;
710 if (off < pRam->cb)
711 {
712 /*
713 * Iterate the relevant pages.
714 */
715 uint8_t abPrev[MAX_NEEDLE_SIZE];
716 size_t cbPrev = 0;
717 const uint32_t cPages = pRam->cb >> PAGE_SHIFT;
718 uint32_t iPage = off >> PAGE_SHIFT;
719 uint32_t offPage = GCPhys & PAGE_OFFSET_MASK;
720 GCPhys &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
721 for (;; offPage = 0)
722 {
723 PPGMPAGE pPage = &pRam->aPages[iPage];
724 if ( ( !PGM_PAGE_IS_ZERO(pPage)
725 || fAllZero)
726 && !PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)
727 && !PGM_PAGE_IS_BALLOONED(pPage))
728 {
729 void const *pvPage;
730 PGMPAGEMAPLOCK Lock;
731 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, &pvPage, &Lock);
732 if (RT_SUCCESS(rc))
733 {
734 int32_t offHit = offPage;
735 bool fRc;
736 if (GCPhysAlign < PAGE_SIZE)
737 {
738 uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)PAGE_OFFSET_MASK
739 ? PAGE_SIZE - (uint32_t)offPage
740 : (GCPhysLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
741 fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPhysAlign,
742 pabNeedle, cbNeedle, pfnMemScan, &abPrev[0], &cbPrev);
743 }
744 else
745 fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
746 && (GCPhysLast - GCPhys) >= cbNeedle;
747 PGMPhysReleasePageMappingLock(pVM, &Lock);
748 if (fRc)
749 {
750 *pGCPhysHit = GCPhys + offHit;
751 pgmUnlock(pVM);
752 return VINF_SUCCESS;
753 }
754 }
755 else
756 cbPrev = 0; /* ignore error. */
757 }
758 else
759 cbPrev = 0;
760
761 /* advance to the next page. */
762 GCPhys += (RTGCPHYS)cIncPages << PAGE_SHIFT;
763 if (GCPhys >= GCPhysLast) /* (may not always hit, but we're run out of ranges.) */
764 {
765 pgmUnlock(pVM);
766 return VERR_DBGF_MEM_NOT_FOUND;
767 }
768 iPage += cIncPages;
769 if ( iPage < cIncPages
770 || iPage >= cPages)
771 break;
772 }
773 }
774 }
775 pgmUnlock(pVM);
776 return VERR_DBGF_MEM_NOT_FOUND;
777}
778
779
780/**
781 * Scans (guest) virtual memory for a byte string.
782 *
783 * @returns VBox status codes:
784 * @retval VINF_SUCCESS and *pGCPtrHit on success.
785 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
786 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
787 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
788 *
789 * @param pVM The cross context VM structure.
790 * @param pVCpu The cross context virtual CPU structure of the CPU
791 * context to search from.
792 * @param GCPtr Where to start searching.
793 * @param GCPtrAlign The alignment of the needle. Must be a power of two
794 * and less or equal to 4GB.
795 * @param cbRange The number of bytes to search. Max 256 bytes.
796 * @param pabNeedle The byte string to search for.
797 * @param cbNeedle The length of the byte string.
798 * @param pGCPtrHit Where to store the address of the first occurrence on success.
799 */
800VMMR3_INT_DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign,
801 const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
802{
803 VMCPU_ASSERT_EMT(pVCpu);
804
805 /*
806 * Validate and adjust the input a bit.
807 */
808 if (!VALID_PTR(pGCPtrHit))
809 return VERR_INVALID_POINTER;
810 *pGCPtrHit = 0;
811
812 if (!VALID_PTR(pabNeedle))
813 return VERR_INVALID_POINTER;
814 if (!cbNeedle)
815 return VERR_INVALID_PARAMETER;
816 if (cbNeedle > MAX_NEEDLE_SIZE)
817 return VERR_INVALID_PARAMETER;
818
819 if (!cbRange)
820 return VERR_DBGF_MEM_NOT_FOUND;
821 if (GCPtr + cbNeedle - 1 < GCPtr)
822 return VERR_DBGF_MEM_NOT_FOUND;
823
824 if (!GCPtrAlign)
825 return VERR_INVALID_PARAMETER;
826 if (GCPtrAlign > UINT32_MAX)
827 return VERR_NOT_POWER_OF_TWO;
828 if (GCPtrAlign & (GCPtrAlign - 1))
829 return VERR_INVALID_PARAMETER;
830
831 if (GCPtr & (GCPtrAlign - 1))
832 {
833 RTGCPTR Adj = GCPtrAlign - (GCPtr & (GCPtrAlign - 1));
834 if ( cbRange <= Adj
835 || GCPtr + Adj < GCPtr)
836 return VERR_DBGF_MEM_NOT_FOUND;
837 GCPtr += Adj;
838 cbRange -= Adj;
839 }
840
841 /* Only paged protected mode or long mode here, use the physical scan for
842 the other modes. */
843 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
844 AssertReturn(PGMMODE_WITH_PAGING(enmMode), VERR_PGM_NOT_USED_IN_MODE);
845
846 /*
847 * Search the memory - ignore MMIO, zero and not-present pages.
848 */
849 const bool fAllZero = ASMMemIsZero(pabNeedle, cbNeedle);
850 RTGCPTR GCPtrMask = PGMMODE_IS_LONG_MODE(enmMode) ? UINT64_MAX : UINT32_MAX;
851 uint8_t abPrev[MAX_NEEDLE_SIZE];
852 size_t cbPrev = 0;
853 const uint32_t cIncPages = GCPtrAlign <= PAGE_SIZE
854 ? 1
855 : GCPtrAlign >> PAGE_SHIFT;
856 const RTGCPTR GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
857 ? (GCPtr + cbRange - 1) & GCPtrMask
858 : GCPtrMask;
859 RTGCPTR cPages = (((GCPtrLast - GCPtr) + (GCPtr & PAGE_OFFSET_MASK)) >> PAGE_SHIFT) + 1;
860 uint32_t offPage = GCPtr & PAGE_OFFSET_MASK;
861 GCPtr &= ~(RTGCPTR)PAGE_OFFSET_MASK;
862
863 PFNPGMR3DBGFIXEDMEMSCAN pfnMemScan = pgmR3DbgSelectMemScanFunction((uint32_t)GCPtrAlign, cbNeedle);
864
865 VMSTATE enmVMState = pVM->enmVMState;
866 uint32_t const cYieldCountDownReload = VMSTATE_IS_RUNNING(enmVMState) ? 4096 : 65536;
867 uint32_t cYieldCountDown = cYieldCountDownReload;
868 RTGCPHYS GCPhysPrev = NIL_RTGCPHYS;
869 bool fFullWalk = true;
870 PGMPTWALKGST Walk;
871 RT_ZERO(Walk);
872
873 pgmLock(pVM);
874 for (;; offPage = 0)
875 {
876 int rc;
877 if (fFullWalk)
878 rc = pgmGstPtWalk(pVCpu, GCPtr, &Walk);
879 else
880 rc = pgmGstPtWalkNext(pVCpu, GCPtr, &Walk);
881 if (RT_SUCCESS(rc) && Walk.u.Core.fSucceeded)
882 {
883 fFullWalk = false;
884
885 /* Skip if same page as previous one (W10 optimization). */
886 if ( Walk.u.Core.GCPhys != GCPhysPrev
887 || cbPrev != 0)
888 {
889 PPGMPAGE pPage = pgmPhysGetPage(pVM, Walk.u.Core.GCPhys);
890 if ( pPage
891 && ( !PGM_PAGE_IS_ZERO(pPage)
892 || fAllZero)
893 && !PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)
894 && !PGM_PAGE_IS_BALLOONED(pPage))
895 {
896 GCPhysPrev = Walk.u.Core.GCPhys;
897 void const *pvPage;
898 PGMPAGEMAPLOCK Lock;
899 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, Walk.u.Core.GCPhys, &pvPage, &Lock);
900 if (RT_SUCCESS(rc))
901 {
902 int32_t offHit = offPage;
903 bool fRc;
904 if (GCPtrAlign < PAGE_SIZE)
905 {
906 uint32_t cbSearch = cPages > 0
907 ? PAGE_SIZE - (uint32_t)offPage
908 : (GCPtrLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
909 fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPtrAlign,
910 pabNeedle, cbNeedle, pfnMemScan, &abPrev[0], &cbPrev);
911 }
912 else
913 fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
914 && (GCPtrLast - GCPtr) >= cbNeedle;
915 PGMPhysReleasePageMappingLock(pVM, &Lock);
916 if (fRc)
917 {
918 *pGCPtrHit = GCPtr + offHit;
919 pgmUnlock(pVM);
920 return VINF_SUCCESS;
921 }
922 }
923 else
924 cbPrev = 0; /* ignore error. */
925 }
926 else
927 cbPrev = 0;
928 }
929 else
930 cbPrev = 0;
931 }
932 else
933 {
934 Assert(Walk.enmType != PGMPTWALKGSTTYPE_INVALID);
935 Assert(!Walk.u.Core.fSucceeded);
936 cbPrev = 0; /* ignore error. */
937
938 /*
939 * Try skip as much as possible. No need to figure out that a PDE
940 * is not present 512 times!
941 */
942 uint64_t cPagesCanSkip;
943 switch (Walk.u.Core.uLevel)
944 {
945 case 1:
946 /* page level, use cIncPages */
947 cPagesCanSkip = 1;
948 break;
949 case 2:
950 if (Walk.enmType == PGMPTWALKGSTTYPE_32BIT)
951 {
952 cPagesCanSkip = X86_PG_ENTRIES - ((GCPtr >> X86_PT_SHIFT) & X86_PT_MASK);
953 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PD_SHIFT) - 1)));
954 }
955 else
956 {
957 cPagesCanSkip = X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
958 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PD_PAE_SHIFT) - 1)));
959 }
960 break;
961 case 3:
962 cPagesCanSkip = (X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK)) * X86_PG_PAE_ENTRIES
963 - ((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
964 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PDPT_SHIFT) - 1)));
965 break;
966 case 4:
967 cPagesCanSkip = (X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64))
968 * X86_PG_PAE_ENTRIES * X86_PG_PAE_ENTRIES
969 - ((((GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK)) * X86_PG_PAE_ENTRIES)
970 - (( GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
971 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PML4_SHIFT) - 1)));
972 break;
973 case 8:
974 /* The CR3 value is bad, forget the whole search. */
975 cPagesCanSkip = cPages;
976 break;
977 default:
978 AssertMsgFailed(("%d\n", Walk.u.Core.uLevel));
979 cPagesCanSkip = 0;
980 break;
981 }
982 if (cPages <= cPagesCanSkip)
983 break;
984 fFullWalk = true;
985 if (cPagesCanSkip >= cIncPages)
986 {
987 cPages -= cPagesCanSkip;
988 GCPtr += (RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT;
989 continue;
990 }
991 }
992
993 /* advance to the next page. */
994 if (cPages <= cIncPages)
995 break;
996 cPages -= cIncPages;
997 GCPtr += (RTGCPTR)cIncPages << X86_PT_PAE_SHIFT;
998
999 /* Yield the PGM lock every now and then. */
1000 if (!--cYieldCountDown)
1001 {
1002 fFullWalk = PDMR3CritSectYield(pVM, &pVM->pgm.s.CritSectX);
1003 cYieldCountDown = cYieldCountDownReload;
1004 }
1005 }
1006 pgmUnlock(pVM);
1007 return VERR_DBGF_MEM_NOT_FOUND;
1008}
1009
1010
1011/**
1012 * Initializes the dumper state.
1013 *
1014 * @param pState The state to initialize.
1015 * @param pVM The cross context VM structure.
1016 * @param fFlags The flags.
1017 * @param u64FirstAddr The first address.
1018 * @param u64LastAddr The last address.
1019 * @param pHlp The output helpers.
1020 */
1021static void pgmR3DumpHierarchyInitState(PPGMR3DUMPHIERARCHYSTATE pState, PVM pVM, uint32_t fFlags,
1022 uint64_t u64FirstAddr, uint64_t u64LastAddr, PCDBGFINFOHLP pHlp)
1023{
1024 pState->pVM = pVM;
1025 pState->pHlp = pHlp ? pHlp : DBGFR3InfoLogHlp();
1026 pState->fPse = !!(fFlags & (DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
1027 pState->fPae = !!(fFlags & (DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
1028 pState->fLme = !!(fFlags & DBGFPGDMP_FLAGS_LME);
1029 pState->fNp = !!(fFlags & DBGFPGDMP_FLAGS_NP);
1030 pState->fEpt = !!(fFlags & DBGFPGDMP_FLAGS_EPT);
1031 pState->fNxe = !!(fFlags & DBGFPGDMP_FLAGS_NXE);
1032 pState->cchAddress = pState->fLme ? 16 : 8;
1033 pState->uLastRsvdBit = pState->fNxe ? 62 : 63;
1034 pState->fDumpPageInfo = !!(fFlags & DBGFPGDMP_FLAGS_PAGE_INFO);
1035 pState->fPrintHeader = !!(fFlags & DBGFPGDMP_FLAGS_HEADER);
1036 pState->fPrintCr3 = !!(fFlags & DBGFPGDMP_FLAGS_PRINT_CR3);
1037 pState->afReserved[0] = false;
1038 pState->afReserved[1] = false;
1039 pState->afReserved[2] = false;
1040 pState->afReserved[3] = false;
1041 pState->afReserved[4] = false;
1042 pState->u64Address = u64FirstAddr;
1043 pState->u64FirstAddress = u64FirstAddr;
1044 pState->u64LastAddress = u64LastAddr;
1045 pState->u64HighReservedBits = pState->uLastRsvdBit == 62 ? UINT64_C(0x7ff) << 52 : UINT64_C(0xfff) << 52;
1046 pState->cLeaves = 0;
1047}
1048
1049
1050/**
1051 * The simple way out, too tired to think of a more elegant solution.
1052 *
1053 * @returns The base address of this page table/directory/whatever.
1054 * @param pState The state where we get the current address.
1055 * @param cShift The shift count for the table entries.
1056 * @param cEntries The number of table entries.
1057 * @param piFirst Where to return the table index of the first
1058 * entry to dump.
1059 * @param piLast Where to return the table index of the last
1060 * entry.
1061 */
1062static uint64_t pgmR3DumpHierarchyCalcRange(PPGMR3DUMPHIERARCHYSTATE pState, uint32_t cShift, uint32_t cEntries,
1063 uint32_t *piFirst, uint32_t *piLast)
1064{
1065 const uint64_t iBase = (pState->u64Address >> cShift) & ~(uint64_t)(cEntries - 1);
1066 const uint64_t iFirst = pState->u64FirstAddress >> cShift;
1067 const uint64_t iLast = pState->u64LastAddress >> cShift;
1068
1069 if ( iBase >= iFirst
1070 && iBase + cEntries - 1 <= iLast)
1071 {
1072 /* full range. */
1073 *piFirst = 0;
1074 *piLast = cEntries - 1;
1075 }
1076 else if ( iBase + cEntries - 1 < iFirst
1077 || iBase > iLast)
1078 {
1079 /* no match */
1080 *piFirst = cEntries;
1081 *piLast = 0;
1082 }
1083 else
1084 {
1085 /* partial overlap */
1086 *piFirst = iBase <= iFirst
1087 ? iFirst - iBase
1088 : 0;
1089 *piLast = iBase + cEntries - 1 <= iLast
1090 ? cEntries - 1
1091 : iLast - iBase;
1092 }
1093
1094 return iBase << cShift;
1095}
1096
1097
1098/**
1099 * Maps/finds the shadow page.
1100 *
1101 * @returns VBox status code.
1102 * @param pState The dumper state.
1103 * @param HCPhys The physical address of the shadow page.
1104 * @param pszDesc The description.
1105 * @param fIsMapping Set if it's a mapping.
1106 * @param ppv Where to return the pointer.
1107 */
1108static int pgmR3DumpHierarchyShwMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, const char *pszDesc,
1109 bool fIsMapping, void const **ppv)
1110{
1111 void *pvPage;
1112 if (!fIsMapping)
1113 {
1114 PPGMPOOLPAGE pPoolPage = pgmPoolQueryPageForDbg(pState->pVM->pgm.s.pPoolR3, HCPhys);
1115 if (pPoolPage)
1116 {
1117 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! %s at HCPhys=%RHp was not found in the page pool!\n",
1118 pState->cchAddress, pState->u64Address, pszDesc, HCPhys);
1119 return VERR_PGM_POOL_GET_PAGE_FAILED;
1120 }
1121 pvPage = (uint8_t *)pPoolPage->pvPageR3 + (HCPhys & PAGE_OFFSET_MASK);
1122 }
1123 else
1124 {
1125 pvPage = NULL;
1126#ifndef PGM_WITHOUT_MAPPINGS
1127 for (PPGMMAPPING pMap = pState->pVM->pgm.s.pMappingsR3; pMap; pMap = pMap->pNextR3)
1128 {
1129 uint64_t off = pState->u64Address - pMap->GCPtr;
1130 if (off < pMap->cb)
1131 {
1132 const int iPDE = (uint32_t)(off >> X86_PD_SHIFT);
1133 const int iSub = (int)((off >> X86_PD_PAE_SHIFT) & 1); /* MSC is a pain sometimes */
1134 if ((iSub ? pMap->aPTs[iPDE].HCPhysPaePT1 : pMap->aPTs[iPDE].HCPhysPaePT0) != HCPhys)
1135 pState->pHlp->pfnPrintf(pState->pHlp,
1136 "%0*llx error! Mapping error! PT %d has HCPhysPT=%RHp not %RHp is in the PD.\n",
1137 pState->cchAddress, pState->u64Address, iPDE,
1138 iSub ? pMap->aPTs[iPDE].HCPhysPaePT1 : pMap->aPTs[iPDE].HCPhysPaePT0, HCPhys);
1139 pvPage = &pMap->aPTs[iPDE].paPaePTsR3[iSub];
1140 break;
1141 }
1142 }
1143#endif /* !PGM_WITHOUT_MAPPINGS */
1144 if (!pvPage)
1145 {
1146 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! PT mapping %s at HCPhys=%RHp was not found in the page pool!\n",
1147 pState->cchAddress, pState->u64Address, pszDesc, HCPhys);
1148 return VERR_INVALID_PARAMETER;
1149 }
1150 }
1151 *ppv = pvPage;
1152 return VINF_SUCCESS;
1153}
1154
1155
1156/**
1157 * Dumps the a shadow page summary or smth.
1158 *
1159 * @param pState The dumper state.
1160 * @param HCPhys The page address.
1161 */
1162static void pgmR3DumpHierarchyShwTablePageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1163{
1164 pgmLock(pState->pVM);
1165 char szPage[80];
1166 PPGMPOOLPAGE pPage = pgmPoolQueryPageForDbg(pState->pVM->pgm.s.CTX_SUFF(pPool), HCPhys);
1167 if (pPage)
1168 RTStrPrintf(szPage, sizeof(szPage), " idx=0i%u", pPage->idx);
1169 else
1170 {
1171 /* probably a mapping */
1172 strcpy(szPage, " not found");
1173#ifndef PGM_WITHOUT_MAPPINGS
1174 for (PPGMMAPPING pMap = pState->pVM->pgm.s.pMappingsR3; pMap; pMap = pMap->pNextR3)
1175 {
1176 uint64_t off = pState->u64Address - pMap->GCPtr;
1177 if (off < pMap->cb)
1178 {
1179 const int iPDE = (uint32_t)(off >> X86_PD_SHIFT);
1180 if (pMap->aPTs[iPDE].HCPhysPT == HCPhys)
1181 RTStrPrintf(szPage, sizeof(szPage), " #%u: %s", iPDE, pMap->pszDesc);
1182 else if (pMap->aPTs[iPDE].HCPhysPaePT0 == HCPhys)
1183 RTStrPrintf(szPage, sizeof(szPage), " #%u/0: %s", iPDE, pMap->pszDesc);
1184 else if (pMap->aPTs[iPDE].HCPhysPaePT1 == HCPhys)
1185 RTStrPrintf(szPage, sizeof(szPage), " #%u/1: %s", iPDE, pMap->pszDesc);
1186 else
1187 continue;
1188 break;
1189 }
1190 }
1191#endif /* !PGM_WITHOUT_MAPPINGS */
1192 }
1193 pgmUnlock(pState->pVM);
1194 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
1195}
1196
1197
1198/**
1199 * Figures out which guest page this is and dumps a summary.
1200 *
1201 * @param pState The dumper state.
1202 * @param HCPhys The page address.
1203 * @param cbPage The page size.
1204 */
1205static void pgmR3DumpHierarchyShwGuestPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, uint32_t cbPage)
1206{
1207 char szPage[80];
1208 RTGCPHYS GCPhys;
1209 int rc = PGMR3DbgHCPhys2GCPhys(pState->pVM->pUVM, HCPhys, &GCPhys);
1210 if (RT_SUCCESS(rc))
1211 {
1212 pgmLock(pState->pVM);
1213 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
1214 if (pPage)
1215 RTStrPrintf(szPage, sizeof(szPage), "%R[pgmpage]", pPage);
1216 else
1217 strcpy(szPage, "not found");
1218 pgmUnlock(pState->pVM);
1219 pState->pHlp->pfnPrintf(pState->pHlp, " -> %RGp %s", GCPhys, szPage);
1220 }
1221 else
1222 {
1223#ifndef PGM_WITHOUT_MAPPINGS
1224 /* check the heap */
1225 uint32_t cbAlloc;
1226 rc = MMR3HyperQueryInfoFromHCPhys(pState->pVM, HCPhys, szPage, sizeof(szPage), &cbAlloc);
1227 if (RT_SUCCESS(rc))
1228 pState->pHlp->pfnPrintf(pState->pHlp, " %s %#x bytes", szPage, cbAlloc);
1229 else
1230#endif
1231 pState->pHlp->pfnPrintf(pState->pHlp, " not found");
1232 }
1233 NOREF(cbPage);
1234}
1235
1236
1237/**
1238 * Dumps a PAE shadow page table.
1239 *
1240 * @returns VBox status code (VINF_SUCCESS).
1241 * @param pState The dumper state.
1242 * @param HCPhys The page table address.
1243 * @param fIsMapping Whether it is a mapping.
1244 */
1245static int pgmR3DumpHierarchyShwPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, bool fIsMapping)
1246{
1247 PCPGMSHWPTPAE pPT;
1248 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", fIsMapping, (void const **)&pPT);
1249 if (RT_FAILURE(rc))
1250 return rc;
1251
1252 uint32_t iFirst, iLast;
1253 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1254 for (uint32_t i = iFirst; i <= iLast; i++)
1255 if (PGMSHWPTEPAE_GET_U(pPT->a[i]) & X86_PTE_P)
1256 {
1257 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
1258 if (PGMSHWPTEPAE_IS_P(pPT->a[i]))
1259 {
1260 X86PTEPAE Pte;
1261 Pte.u = PGMSHWPTEPAE_GET_U(pPT->a[i]);
1262 pState->pHlp->pfnPrintf(pState->pHlp,
1263 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
1264 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
1265 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
1266 pState->u64Address,
1267 Pte.n.u1Write ? 'W' : 'R',
1268 Pte.n.u1User ? 'U' : 'S',
1269 Pte.n.u1Accessed ? 'A' : '-',
1270 Pte.n.u1Dirty ? 'D' : '-',
1271 Pte.n.u1Global ? 'G' : '-',
1272 Pte.n.u1WriteThru ? "WT" : "--",
1273 Pte.n.u1CacheDisable? "CD" : "--",
1274 Pte.n.u1PAT ? "AT" : "--",
1275 Pte.n.u1NoExecute ? "NX" : "--",
1276 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1277 Pte.u & RT_BIT(10) ? '1' : '0',
1278 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED? 'v' : '-',
1279 Pte.u & X86_PTE_PAE_PG_MASK);
1280 if (pState->fDumpPageInfo)
1281 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
1282 if ((Pte.u >> 52) & 0x7ff)
1283 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pte.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1284 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1285 }
1286 else if ( (PGMSHWPTEPAE_GET_U(pPT->a[i]) & (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1287 == (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1288 pState->pHlp->pfnPrintf(pState->pHlp,
1289 pState->fLme
1290 ? "%016llx 3 | invalid / MMIO optimization\n"
1291 : "%08llx 2 | invalid / MMIO optimization\n",
1292 pState->u64Address);
1293 else
1294 pState->pHlp->pfnPrintf(pState->pHlp,
1295 pState->fLme
1296 ? "%016llx 3 | invalid: %RX64\n"
1297 : "%08llx 2 | invalid: %RX64\n",
1298 pState->u64Address, PGMSHWPTEPAE_GET_U(pPT->a[i]));
1299 pState->cLeaves++;
1300 }
1301 return VINF_SUCCESS;
1302}
1303
1304
1305/**
1306 * Dumps a PAE shadow page directory table.
1307 *
1308 * @returns VBox status code (VINF_SUCCESS).
1309 * @param pState The dumper state.
1310 * @param HCPhys The physical address of the page directory table.
1311 * @param cMaxDepth The maximum depth.
1312 */
1313static int pgmR3DumpHierarchyShwPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1314{
1315 PCX86PDPAE pPD;
1316 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", false, (void const **)&pPD);
1317 if (RT_FAILURE(rc))
1318 return rc;
1319
1320 Assert(cMaxDepth > 0);
1321 cMaxDepth--;
1322
1323 uint32_t iFirst, iLast;
1324 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1325 for (uint32_t i = iFirst; i <= iLast; i++)
1326 {
1327 X86PDEPAE Pde = pPD->a[i];
1328 if (Pde.n.u1Present)
1329 {
1330 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
1331 if (Pde.b.u1Size)
1332 {
1333 pState->pHlp->pfnPrintf(pState->pHlp,
1334 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
1335 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
1336 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
1337 pState->u64Address,
1338 Pde.b.u1Write ? 'W' : 'R',
1339 Pde.b.u1User ? 'U' : 'S',
1340 Pde.b.u1Accessed ? 'A' : '-',
1341 Pde.b.u1Dirty ? 'D' : '-',
1342 Pde.b.u1Global ? 'G' : '-',
1343 Pde.b.u1WriteThru ? "WT" : "--",
1344 Pde.b.u1CacheDisable? "CD" : "--",
1345 Pde.b.u1PAT ? "AT" : "--",
1346 Pde.b.u1NoExecute ? "NX" : "--",
1347 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
1348#ifndef PGM_WITHOUT_MAPPINGS
1349 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1350#else
1351 '-',
1352#endif
1353 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1354 Pde.u & X86_PDE2M_PAE_PG_MASK);
1355 if (pState->fDumpPageInfo)
1356 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
1357 if ((Pde.u >> 52) & 0x7ff)
1358 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pde.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1359 if ((Pde.u >> 13) & 0xff)
1360 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
1361 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1362
1363 pState->cLeaves++;
1364 }
1365 else
1366 {
1367 pState->pHlp->pfnPrintf(pState->pHlp,
1368 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
1369 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
1370 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
1371 pState->u64Address,
1372 Pde.n.u1Write ? 'W' : 'R',
1373 Pde.n.u1User ? 'U' : 'S',
1374 Pde.n.u1Accessed ? 'A' : '-',
1375 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1376 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1377 Pde.n.u1WriteThru ? "WT" : "--",
1378 Pde.n.u1CacheDisable? "CD" : "--",
1379 Pde.n.u1NoExecute ? "NX" : "--",
1380 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
1381#ifndef PGM_WITHOUT_MAPPINGS
1382 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1383#else
1384 '-',
1385#endif
1386 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1387 Pde.u & X86_PDE_PAE_PG_MASK);
1388 if (pState->fDumpPageInfo)
1389 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1390 if ((Pde.u >> 52) & 0x7ff)
1391 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pde.u >> 52) & 0x7ff);
1392 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1393
1394 if (cMaxDepth)
1395 {
1396 int rc2 = pgmR3DumpHierarchyShwPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK,
1397#ifndef PGM_WITHOUT_MAPPINGS
1398 RT_BOOL(Pde.u & PGM_PDFLAGS_MAPPING)
1399#else
1400 false /*fIsMapping*/
1401#endif
1402 );
1403 if (rc2 < rc && RT_SUCCESS(rc))
1404 rc = rc2;
1405 }
1406 else
1407 pState->cLeaves++;
1408 }
1409 }
1410 }
1411 return rc;
1412}
1413
1414
1415/**
1416 * Dumps a PAE shadow page directory pointer table.
1417 *
1418 * @returns VBox status code (VINF_SUCCESS).
1419 * @param pState The dumper state.
1420 * @param HCPhys The physical address of the page directory pointer table.
1421 * @param cMaxDepth The maximum depth.
1422 */
1423static int pgmR3DumpHierarchyShwPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1424{
1425 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
1426 if (!pState->fLme && pState->u64Address >= _4G)
1427 return VINF_SUCCESS;
1428
1429 PCX86PDPT pPDPT;
1430 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory pointer table", false, (void const **)&pPDPT);
1431 if (RT_FAILURE(rc))
1432 return rc;
1433
1434 Assert(cMaxDepth > 0);
1435 cMaxDepth--;
1436
1437 uint32_t iFirst, iLast;
1438 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
1439 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
1440 &iFirst, &iLast);
1441 for (uint32_t i = iFirst; i <= iLast; i++)
1442 {
1443 X86PDPE Pdpe = pPDPT->a[i];
1444 if (Pdpe.n.u1Present)
1445 {
1446 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
1447 if (pState->fLme)
1448 {
1449 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
1450 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1451 pState->u64Address,
1452 Pdpe.lm.u1Write ? 'W' : 'R',
1453 Pdpe.lm.u1User ? 'U' : 'S',
1454 Pdpe.lm.u1Accessed ? 'A' : '-',
1455 Pdpe.lm.u3Reserved & 1? '?' : '.', /* ignored */
1456 Pdpe.lm.u3Reserved & 4? '!' : '.', /* mbz */
1457 Pdpe.lm.u1WriteThru ? "WT" : "--",
1458 Pdpe.lm.u1CacheDisable? "CD" : "--",
1459 Pdpe.lm.u3Reserved & 2? "!" : "..",/* mbz */
1460 Pdpe.lm.u1NoExecute ? "NX" : "--",
1461 Pdpe.u & RT_BIT(9) ? '1' : '0',
1462 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1463 Pdpe.u & RT_BIT(11) ? '1' : '0',
1464 Pdpe.u & X86_PDPE_PG_MASK);
1465 if (pState->fDumpPageInfo)
1466 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1467 if ((Pdpe.u >> 52) & 0x7ff)
1468 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx", (Pdpe.u >> 52) & 0x7ff);
1469 }
1470 else
1471 {
1472 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
1473 "%08llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1474 pState->u64Address,
1475 Pdpe.n.u2Reserved & 1? '!' : '.', /* mbz */
1476 Pdpe.n.u2Reserved & 2? '!' : '.', /* mbz */
1477 Pdpe.n.u4Reserved & 1? '!' : '.', /* mbz */
1478 Pdpe.n.u4Reserved & 2? '!' : '.', /* mbz */
1479 Pdpe.n.u4Reserved & 8? '!' : '.', /* mbz */
1480 Pdpe.n.u1WriteThru ? "WT" : "--",
1481 Pdpe.n.u1CacheDisable? "CD" : "--",
1482 Pdpe.n.u4Reserved & 2? "!" : "..",/* mbz */
1483 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
1484 Pdpe.u & RT_BIT(9) ? '1' : '0',
1485 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1486 Pdpe.u & RT_BIT(11) ? '1' : '0',
1487 Pdpe.u & X86_PDPE_PG_MASK);
1488 if (pState->fDumpPageInfo)
1489 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1490 if ((Pdpe.u >> 52) & 0xfff)
1491 pState->pHlp->pfnPrintf(pState->pHlp, " 63:52=%03llx!", (Pdpe.u >> 52) & 0xfff);
1492 }
1493 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1494
1495 if (cMaxDepth)
1496 {
1497 int rc2 = pgmR3DumpHierarchyShwPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
1498 if (rc2 < rc && RT_SUCCESS(rc))
1499 rc = rc2;
1500 }
1501 else
1502 pState->cLeaves++;
1503 }
1504 }
1505 return rc;
1506}
1507
1508
1509/**
1510 * Dumps a 32-bit shadow page table.
1511 *
1512 * @returns VBox status code (VINF_SUCCESS).
1513 * @param pState The dumper state.
1514 * @param HCPhys The physical address of the table.
1515 * @param cMaxDepth The maximum depth.
1516 */
1517static int pgmR3DumpHierarchyShwPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1518{
1519 PCX86PML4 pPML4;
1520 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page map level 4", false, (void const **)&pPML4);
1521 if (RT_FAILURE(rc))
1522 return rc;
1523
1524 Assert(cMaxDepth);
1525 cMaxDepth--;
1526
1527 /*
1528 * This is a bit tricky as we're working on unsigned addresses while the
1529 * AMD64 spec uses signed tricks.
1530 */
1531 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1532 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1533 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
1534 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
1535 { /* Simple, nothing to adjust */ }
1536 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
1537 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
1538 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
1539 iFirst = X86_PG_AMD64_ENTRIES / 2;
1540 else
1541 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
1542
1543 for (uint32_t i = iFirst; i <= iLast; i++)
1544 {
1545 X86PML4E Pml4e = pPML4->a[i];
1546 if (Pml4e.n.u1Present)
1547 {
1548 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
1549 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
1550 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
1551 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1552 pState->u64Address,
1553 Pml4e.n.u1Write ? 'W' : 'R',
1554 Pml4e.n.u1User ? 'U' : 'S',
1555 Pml4e.n.u1Accessed ? 'A' : '-',
1556 Pml4e.n.u3Reserved & 1? '?' : '.', /* ignored */
1557 Pml4e.n.u3Reserved & 4? '!' : '.', /* mbz */
1558 Pml4e.n.u1WriteThru ? "WT" : "--",
1559 Pml4e.n.u1CacheDisable? "CD" : "--",
1560 Pml4e.n.u3Reserved & 2? "!" : "..",/* mbz */
1561 Pml4e.n.u1NoExecute ? "NX" : "--",
1562 Pml4e.u & RT_BIT(9) ? '1' : '0',
1563 Pml4e.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1564 Pml4e.u & RT_BIT(11) ? '1' : '0',
1565 Pml4e.u & X86_PML4E_PG_MASK);
1566 if (pState->fDumpPageInfo)
1567 pgmR3DumpHierarchyShwTablePageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK);
1568 if ((Pml4e.u >> 52) & 0x7ff)
1569 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pml4e.u >> 52) & 0x7ff);
1570 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1571
1572 if (cMaxDepth)
1573 {
1574 int rc2 = pgmR3DumpHierarchyShwPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
1575 if (rc2 < rc && RT_SUCCESS(rc))
1576 rc = rc2;
1577 }
1578 else
1579 pState->cLeaves++;
1580 }
1581 }
1582 return rc;
1583}
1584
1585
1586/**
1587 * Dumps a 32-bit shadow page table.
1588 *
1589 * @returns VBox status code (VINF_SUCCESS).
1590 * @param pState The dumper state.
1591 * @param HCPhys The physical address of the table.
1592 * @param fMapping Set if it's a guest mapping.
1593 */
1594static int pgmR3DumpHierarchyShw32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, bool fMapping)
1595{
1596 PCX86PT pPT;
1597 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", fMapping, (void const **)&pPT);
1598 if (RT_FAILURE(rc))
1599 return rc;
1600
1601 uint32_t iFirst, iLast;
1602 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
1603 for (uint32_t i = iFirst; i <= iLast; i++)
1604 {
1605 X86PTE Pte = pPT->a[i];
1606 if (Pte.n.u1Present)
1607 {
1608 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
1609 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
1610 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
1611 pState->u64Address,
1612 Pte.n.u1Write ? 'W' : 'R',
1613 Pte.n.u1User ? 'U' : 'S',
1614 Pte.n.u1Accessed ? 'A' : '-',
1615 Pte.n.u1Dirty ? 'D' : '-',
1616 Pte.n.u1Global ? 'G' : '-',
1617 Pte.n.u1WriteThru ? "WT" : "--",
1618 Pte.n.u1CacheDisable? "CD" : "--",
1619 Pte.n.u1PAT ? "AT" : "--",
1620 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1621 Pte.u & RT_BIT(10) ? '1' : '0',
1622 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED ? 'v' : '-',
1623 Pte.u & X86_PDE_PG_MASK);
1624 if (pState->fDumpPageInfo)
1625 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
1626 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1627 }
1628 }
1629 return VINF_SUCCESS;
1630}
1631
1632
1633/**
1634 * Dumps a 32-bit shadow page directory and page tables.
1635 *
1636 * @returns VBox status code (VINF_SUCCESS).
1637 * @param pState The dumper state.
1638 * @param HCPhys The physical address of the table.
1639 * @param cMaxDepth The maximum depth.
1640 */
1641static int pgmR3DumpHierarchyShw32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1642{
1643 if (pState->u64Address >= _4G)
1644 return VINF_SUCCESS;
1645
1646 PCX86PD pPD;
1647 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", false, (void const **)&pPD);
1648 if (RT_FAILURE(rc))
1649 return rc;
1650
1651 Assert(cMaxDepth > 0);
1652 cMaxDepth--;
1653
1654 uint32_t iFirst, iLast;
1655 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
1656 for (uint32_t i = iFirst; i <= iLast; i++)
1657 {
1658 X86PDE Pde = pPD->a[i];
1659 if (Pde.n.u1Present)
1660 {
1661 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
1662 if (Pde.b.u1Size && pState->fPse)
1663 {
1664 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
1665 | (Pde.u & X86_PDE4M_PG_MASK);
1666 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
1667 "%08llx 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
1668 pState->u64Address,
1669 Pde.b.u1Write ? 'W' : 'R',
1670 Pde.b.u1User ? 'U' : 'S',
1671 Pde.b.u1Accessed ? 'A' : '-',
1672 Pde.b.u1Dirty ? 'D' : '-',
1673 Pde.b.u1Global ? 'G' : '-',
1674 Pde.b.u1WriteThru ? "WT" : "--",
1675 Pde.b.u1CacheDisable? "CD" : "--",
1676 Pde.b.u1PAT ? "AT" : "--",
1677 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
1678#ifndef PGM_WITHOUT_MAPPINGS
1679 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1680#else
1681 '-',
1682#endif
1683 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1684 u64Phys);
1685 if (pState->fDumpPageInfo)
1686 pgmR3DumpHierarchyShwGuestPageInfo(pState, u64Phys, _4M);
1687 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1688 pState->cLeaves++;
1689 }
1690 else
1691 {
1692 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
1693 "%08llx 0 | P %c %c %c %c %c %s %s .. .. 4K %c%c%c %08x",
1694 pState->u64Address,
1695 Pde.n.u1Write ? 'W' : 'R',
1696 Pde.n.u1User ? 'U' : 'S',
1697 Pde.n.u1Accessed ? 'A' : '-',
1698 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1699 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1700 Pde.n.u1WriteThru ? "WT" : "--",
1701 Pde.n.u1CacheDisable? "CD" : "--",
1702 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
1703#ifndef PGM_WITHOUT_MAPPINGS
1704 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1705#else
1706 '-',
1707#endif
1708 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1709 Pde.u & X86_PDE_PG_MASK);
1710 if (pState->fDumpPageInfo)
1711 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PG_MASK);
1712 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1713
1714 if (cMaxDepth)
1715 {
1716 int rc2 = pgmR3DumpHierarchyShw32BitPT(pState, Pde.u & X86_PDE_PG_MASK,
1717#ifndef PGM_WITHOUT_MAPPINGS
1718 !!(Pde.u & PGM_PDFLAGS_MAPPING)
1719#else
1720 false /*fIsMapping*/
1721#endif
1722 );
1723 if (rc2 < rc && RT_SUCCESS(rc))
1724 rc = rc2;
1725 }
1726 else
1727 pState->cLeaves++;
1728 }
1729 }
1730 }
1731
1732 return rc;
1733}
1734
1735
1736/**
1737 * Internal worker that initiates the actual dump.
1738 *
1739 * @returns VBox status code.
1740 * @param pState The dumper state.
1741 * @param cr3 The CR3 value.
1742 * @param cMaxDepth The max depth.
1743 */
1744static int pgmR3DumpHierarchyShwDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
1745{
1746 int rc;
1747 unsigned const cch = pState->cchAddress;
1748 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK
1749 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
1750 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
1751 : X86_CR3_PAGE_MASK;
1752 if (pState->fPrintCr3)
1753 {
1754 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
1755 : pState->fLme ? "Long Mode"
1756 : pState->fPae ? "PAE Mode"
1757 : pState->fPse ? "32-bit w/ PSE"
1758 : "32-bit";
1759 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
1760 if (pState->fDumpPageInfo)
1761 pgmR3DumpHierarchyShwTablePageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK);
1762 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
1763 pszMode,
1764 pState->fNp ? " + Nested Paging" : "",
1765 pState->fNxe ? " + NX" : "");
1766 }
1767
1768
1769 if (pState->fEpt)
1770 {
1771 if (pState->fPrintHeader)
1772 pState->pHlp->pfnPrintf(pState->pHlp,
1773 "%-*s R - Readable\n"
1774 "%-*s | W - Writeable\n"
1775 "%-*s | | X - Executable\n"
1776 "%-*s | | | EMT - EPT memory type\n"
1777 "%-*s | | | | PAT - Ignored PAT?\n"
1778 "%-*s | | | | | AVL1 - 4 available bits\n"
1779 "%-*s | | | | | | AVL2 - 12 available bits\n"
1780 "%-*s Level | | | | | | | page \n"
1781 /* xxxx n **** R W X EMT PAT AVL1 AVL2 xxxxxxxxxxxxx
1782 R W X 7 0 f fff 0123456701234567 */
1783 ,
1784 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
1785
1786 pState->pHlp->pfnPrintf(pState->pHlp, "EPT dumping is not yet implemented, sorry.\n");
1787 /** @todo implemented EPT dumping. */
1788 rc = VERR_NOT_IMPLEMENTED;
1789 }
1790 else
1791 {
1792 if (pState->fPrintHeader)
1793 pState->pHlp->pfnPrintf(pState->pHlp,
1794 "%-*s P - Present\n"
1795 "%-*s | R/W - Read (0) / Write (1)\n"
1796 "%-*s | | U/S - User (1) / Supervisor (0)\n"
1797 "%-*s | | | A - Accessed\n"
1798 "%-*s | | | | D - Dirty\n"
1799 "%-*s | | | | | G - Global\n"
1800 "%-*s | | | | | | WT - Write thru\n"
1801 "%-*s | | | | | | | CD - Cache disable\n"
1802 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
1803 "%-*s | | | | | | | | | NX - No execute (K8)\n"
1804 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
1805 "%-*s | | | | | | | | | | | AVL - a=allocated; m=mapping; d=track dirty;\n"
1806 "%-*s | | | | | | | | | | | | p=permanent; v=validated;\n"
1807 "%-*s Level | | | | | | | | | | | | Page\n"
1808 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
1809 - W U - - - -- -- -- -- -- 010 */
1810 ,
1811 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
1812 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
1813 if (pState->fLme)
1814 rc = pgmR3DumpHierarchyShwPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
1815 else if (pState->fPae)
1816 rc = pgmR3DumpHierarchyShwPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
1817 else
1818 rc = pgmR3DumpHierarchyShw32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
1819 }
1820
1821 if (!pState->cLeaves)
1822 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
1823 return rc;
1824}
1825
1826
1827/**
1828 * dbgfR3PagingDumpEx worker.
1829 *
1830 * @returns VBox status code.
1831 * @param pVM The cross context VM structure.
1832 * @param cr3 The CR3 register value.
1833 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
1834 * @param u64FirstAddr The start address.
1835 * @param u64LastAddr The address to stop after.
1836 * @param cMaxDepth The max depth.
1837 * @param pHlp The output callbacks. Defaults to log if NULL.
1838 *
1839 * @internal
1840 */
1841VMMR3_INT_DECL(int) PGMR3DumpHierarchyShw(PVM pVM, uint64_t cr3, uint32_t fFlags, uint64_t u64FirstAddr, uint64_t u64LastAddr,
1842 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
1843{
1844 /* Minimal validation as we're only supposed to service DBGF. */
1845 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1846 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
1847 AssertReturn(fFlags & DBGFPGDMP_FLAGS_SHADOW, VERR_INVALID_PARAMETER);
1848
1849 PGMR3DUMPHIERARCHYSTATE State;
1850 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, u64FirstAddr, u64LastAddr, pHlp);
1851 return pgmR3DumpHierarchyShwDoIt(&State, cr3, cMaxDepth);
1852}
1853
1854
1855/**
1856 * Dumps a page table hierarchy use only physical addresses and cr4/lm flags.
1857 *
1858 * @returns VBox status code (VINF_SUCCESS).
1859 * @param pVM The cross context VM structure.
1860 * @param cr3 The root of the hierarchy.
1861 * @param cr4 The cr4, only PAE and PSE is currently used.
1862 * @param fLongMode Set if long mode, false if not long mode.
1863 * @param cMaxDepth Number of levels to dump.
1864 * @param pHlp Pointer to the output functions.
1865 *
1866 * @deprecated Use DBGFR3PagingDumpEx.
1867 */
1868VMMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint64_t cr3, uint64_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
1869{
1870 if (!cMaxDepth)
1871 return VINF_SUCCESS;
1872
1873 PVMCPU pVCpu = VMMGetCpu(pVM);
1874 if (!pVCpu)
1875 pVCpu = pVM->apCpusR3[0];
1876
1877 uint32_t fFlags = DBGFPGDMP_FLAGS_HEADER | DBGFPGDMP_FLAGS_PRINT_CR3 | DBGFPGDMP_FLAGS_PAGE_INFO | DBGFPGDMP_FLAGS_SHADOW;
1878 fFlags |= cr4 & (X86_CR4_PAE | X86_CR4_PSE);
1879 if (fLongMode)
1880 fFlags |= DBGFPGDMP_FLAGS_LME;
1881
1882 return DBGFR3PagingDumpEx(pVM->pUVM, pVCpu->idCpu, fFlags, cr3, 0, fLongMode ? UINT64_MAX : UINT32_MAX, cMaxDepth, pHlp);
1883}
1884
1885
1886/**
1887 * Maps the guest page.
1888 *
1889 * @returns VBox status code.
1890 * @param pState The dumper state.
1891 * @param GCPhys The physical address of the guest page.
1892 * @param pszDesc The description.
1893 * @param ppv Where to return the pointer.
1894 * @param pLock Where to return the mapping lock. Hand this to
1895 * PGMPhysReleasePageMappingLock when done.
1896 */
1897static int pgmR3DumpHierarchyGstMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, const char *pszDesc,
1898 void const **ppv, PPGMPAGEMAPLOCK pLock)
1899{
1900 int rc = PGMPhysGCPhys2CCPtrReadOnly(pState->pVM, GCPhys, ppv, pLock);
1901 if (RT_FAILURE(rc))
1902 {
1903 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! Failed to map %s at GCPhys=%RGp: %Rrc!\n",
1904 pState->cchAddress, pState->u64Address, pszDesc, GCPhys, rc);
1905 return rc;
1906 }
1907 return VINF_SUCCESS;
1908}
1909
1910
1911/**
1912 * Figures out which guest page this is and dumps a summary.
1913 *
1914 * @param pState The dumper state.
1915 * @param GCPhys The page address.
1916 * @param cbPage The page size.
1917 */
1918static void pgmR3DumpHierarchyGstPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, uint32_t cbPage)
1919{
1920 char szPage[80];
1921 pgmLock(pState->pVM);
1922 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
1923 if (pPage)
1924 RTStrPrintf(szPage, sizeof(szPage), " %R[pgmpage]", pPage);
1925 else
1926 strcpy(szPage, " not found");
1927 pgmUnlock(pState->pVM);
1928 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
1929 NOREF(cbPage);
1930}
1931
1932
1933/**
1934 * Checks the entry for reserved bits.
1935 *
1936 * @param pState The dumper state.
1937 * @param u64Entry The entry to check.
1938 */
1939static void pgmR3DumpHierarchyGstCheckReservedHighBits(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t u64Entry)
1940{
1941 uint32_t uRsvd = (u64Entry & pState->u64HighReservedBits) >> 52;
1942 if (uRsvd)
1943 pState->pHlp->pfnPrintf(pState->pHlp, " %u:52=%03x%s",
1944 pState->uLastRsvdBit, uRsvd, pState->fLme ? "" : "!");
1945 /** @todo check the valid physical bits as well. */
1946}
1947
1948
1949/**
1950 * Dumps a PAE shadow page table.
1951 *
1952 * @returns VBox status code (VINF_SUCCESS).
1953 * @param pState The dumper state.
1954 * @param GCPhys The page table address.
1955 */
1956static int pgmR3DumpHierarchyGstPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys)
1957{
1958 PCX86PTPAE pPT;
1959 PGMPAGEMAPLOCK Lock;
1960 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
1961 if (RT_FAILURE(rc))
1962 return rc;
1963
1964 uint32_t iFirst, iLast;
1965 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1966 for (uint32_t i = iFirst; i <= iLast; i++)
1967 {
1968 X86PTEPAE Pte = pPT->a[i];
1969 if (Pte.n.u1Present)
1970 {
1971 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
1972 pState->pHlp->pfnPrintf(pState->pHlp,
1973 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
1974 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
1975 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
1976 pState->u64Address,
1977 Pte.n.u1Write ? 'W' : 'R',
1978 Pte.n.u1User ? 'U' : 'S',
1979 Pte.n.u1Accessed ? 'A' : '-',
1980 Pte.n.u1Dirty ? 'D' : '-',
1981 Pte.n.u1Global ? 'G' : '-',
1982 Pte.n.u1WriteThru ? "WT" : "--",
1983 Pte.n.u1CacheDisable? "CD" : "--",
1984 Pte.n.u1PAT ? "AT" : "--",
1985 Pte.n.u1NoExecute ? "NX" : "--",
1986 Pte.u & RT_BIT(9) ? '1' : '0',
1987 Pte.u & RT_BIT(10) ? '1' : '0',
1988 Pte.u & RT_BIT(11) ? '1' : '0',
1989 Pte.u & X86_PTE_PAE_PG_MASK);
1990 if (pState->fDumpPageInfo)
1991 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
1992 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pte.u);
1993 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1994 pState->cLeaves++;
1995 }
1996 }
1997
1998 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
1999 return VINF_SUCCESS;
2000}
2001
2002
2003/**
2004 * Dumps a PAE shadow page directory table.
2005 *
2006 * @returns VBox status code (VINF_SUCCESS).
2007 * @param pState The dumper state.
2008 * @param GCPhys The physical address of the table.
2009 * @param cMaxDepth The maximum depth.
2010 */
2011static int pgmR3DumpHierarchyGstPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
2012{
2013 PCX86PDPAE pPD;
2014 PGMPAGEMAPLOCK Lock;
2015 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
2016 if (RT_FAILURE(rc))
2017 return rc;
2018
2019 Assert(cMaxDepth > 0);
2020 cMaxDepth--;
2021
2022 uint32_t iFirst, iLast;
2023 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
2024 for (uint32_t i = iFirst; i <= iLast; i++)
2025 {
2026 X86PDEPAE Pde = pPD->a[i];
2027 if (Pde.n.u1Present)
2028 {
2029 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
2030 if (Pde.b.u1Size)
2031 {
2032 pState->pHlp->pfnPrintf(pState->pHlp,
2033 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
2034 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
2035 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
2036 pState->u64Address,
2037 Pde.b.u1Write ? 'W' : 'R',
2038 Pde.b.u1User ? 'U' : 'S',
2039 Pde.b.u1Accessed ? 'A' : '-',
2040 Pde.b.u1Dirty ? 'D' : '-',
2041 Pde.b.u1Global ? 'G' : '-',
2042 Pde.b.u1WriteThru ? "WT" : "--",
2043 Pde.b.u1CacheDisable ? "CD" : "--",
2044 Pde.b.u1PAT ? "AT" : "--",
2045 Pde.b.u1NoExecute ? "NX" : "--",
2046 Pde.u & RT_BIT_64(9) ? '1' : '0',
2047 Pde.u & RT_BIT_64(10) ? '1' : '0',
2048 Pde.u & RT_BIT_64(11) ? '1' : '0',
2049 Pde.u & X86_PDE2M_PAE_PG_MASK);
2050 if (pState->fDumpPageInfo)
2051 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
2052 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
2053 if ((Pde.u >> 13) & 0xff)
2054 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
2055 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2056
2057 pState->cLeaves++;
2058 }
2059 else
2060 {
2061 pState->pHlp->pfnPrintf(pState->pHlp,
2062 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
2063 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
2064 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
2065 pState->u64Address,
2066 Pde.n.u1Write ? 'W' : 'R',
2067 Pde.n.u1User ? 'U' : 'S',
2068 Pde.n.u1Accessed ? 'A' : '-',
2069 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2070 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2071 Pde.n.u1WriteThru ? "WT" : "--",
2072 Pde.n.u1CacheDisable ? "CD" : "--",
2073 Pde.n.u1NoExecute ? "NX" : "--",
2074 Pde.u & RT_BIT_64(9) ? '1' : '0',
2075 Pde.u & RT_BIT_64(10) ? '1' : '0',
2076 Pde.u & RT_BIT_64(11) ? '1' : '0',
2077 Pde.u & X86_PDE_PAE_PG_MASK);
2078 if (pState->fDumpPageInfo)
2079 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK, _4K);
2080 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
2081 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2082
2083 if (cMaxDepth)
2084 {
2085 int rc2 = pgmR3DumpHierarchyGstPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK);
2086 if (rc2 < rc && RT_SUCCESS(rc))
2087 rc = rc2;
2088 }
2089 else
2090 pState->cLeaves++;
2091 }
2092 }
2093 }
2094
2095 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2096 return rc;
2097}
2098
2099
2100/**
2101 * Dumps a PAE shadow page directory pointer table.
2102 *
2103 * @returns VBox status code (VINF_SUCCESS).
2104 * @param pState The dumper state.
2105 * @param GCPhys The physical address of the table.
2106 * @param cMaxDepth The maximum depth.
2107 */
2108static int pgmR3DumpHierarchyGstPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
2109{
2110 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
2111 if (!pState->fLme && pState->u64Address >= _4G)
2112 return VINF_SUCCESS;
2113
2114 PCX86PDPT pPDPT;
2115 PGMPAGEMAPLOCK Lock;
2116 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory pointer table", (void const **)&pPDPT, &Lock);
2117 if (RT_FAILURE(rc))
2118 return rc;
2119
2120 Assert(cMaxDepth > 0);
2121 cMaxDepth--;
2122
2123 uint32_t iFirst, iLast;
2124 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
2125 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
2126 &iFirst, &iLast);
2127 for (uint32_t i = iFirst; i <= iLast; i++)
2128 {
2129 X86PDPE Pdpe = pPDPT->a[i];
2130 if (Pdpe.n.u1Present)
2131 {
2132 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
2133 if (pState->fLme)
2134 {
2135 /** @todo Do 1G pages. */
2136 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
2137 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2138 pState->u64Address,
2139 Pdpe.lm.u1Write ? 'W' : 'R',
2140 Pdpe.lm.u1User ? 'U' : 'S',
2141 Pdpe.lm.u1Accessed ? 'A' : '-',
2142 Pdpe.lm.u3Reserved & 1 ? '?' : '.', /* ignored */
2143 Pdpe.lm.u3Reserved & 4 ? '!' : '.', /* mbz */
2144 Pdpe.lm.u1WriteThru ? "WT" : "--",
2145 Pdpe.lm.u1CacheDisable ? "CD" : "--",
2146 Pdpe.lm.u3Reserved & 2 ? "!" : "..",/* mbz */
2147 Pdpe.lm.u1NoExecute ? "NX" : "--",
2148 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
2149 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
2150 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
2151 Pdpe.u & X86_PDPE_PG_MASK);
2152 if (pState->fDumpPageInfo)
2153 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
2154 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
2155 }
2156 else
2157 {
2158 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
2159 "%08llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2160 pState->u64Address,
2161 Pdpe.n.u2Reserved & 1 ? '!' : '.', /* mbz */
2162 Pdpe.n.u2Reserved & 2 ? '!' : '.', /* mbz */
2163 Pdpe.n.u4Reserved & 1 ? '!' : '.', /* mbz */
2164 Pdpe.n.u4Reserved & 2 ? '!' : '.', /* mbz */
2165 Pdpe.n.u4Reserved & 8 ? '!' : '.', /* mbz */
2166 Pdpe.n.u1WriteThru ? "WT" : "--",
2167 Pdpe.n.u1CacheDisable ? "CD" : "--",
2168 Pdpe.n.u4Reserved & 2 ? "!" : "..", /* mbz */
2169 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
2170 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
2171 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
2172 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
2173 Pdpe.u & X86_PDPE_PG_MASK);
2174 if (pState->fDumpPageInfo)
2175 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
2176 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
2177 }
2178 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2179
2180 if (cMaxDepth)
2181 {
2182 int rc2 = pgmR3DumpHierarchyGstPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
2183 if (rc2 < rc && RT_SUCCESS(rc))
2184 rc = rc2;
2185 }
2186 else
2187 pState->cLeaves++;
2188 }
2189 }
2190
2191 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2192 return rc;
2193}
2194
2195
2196/**
2197 * Dumps a 32-bit shadow page table.
2198 *
2199 * @returns VBox status code (VINF_SUCCESS).
2200 * @param pState The dumper state.
2201 * @param GCPhys The physical address of the table.
2202 * @param cMaxDepth The maximum depth.
2203 */
2204static int pgmR3DumpHierarchyGstPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2205{
2206 PCX86PML4 pPML4;
2207 PGMPAGEMAPLOCK Lock;
2208 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page map level 4", (void const **)&pPML4, &Lock);
2209 if (RT_FAILURE(rc))
2210 return rc;
2211
2212 Assert(cMaxDepth);
2213 cMaxDepth--;
2214
2215 /*
2216 * This is a bit tricky as we're working on unsigned addresses while the
2217 * AMD64 spec uses signed tricks.
2218 */
2219 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2220 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2221 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
2222 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
2223 { /* Simple, nothing to adjust */ }
2224 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
2225 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
2226 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
2227 iFirst = X86_PG_AMD64_ENTRIES / 2;
2228 else
2229 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
2230
2231 for (uint32_t i = iFirst; i <= iLast; i++)
2232 {
2233 X86PML4E Pml4e = pPML4->a[i];
2234 if (Pml4e.n.u1Present)
2235 {
2236 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
2237 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
2238 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
2239 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2240 pState->u64Address,
2241 Pml4e.n.u1Write ? 'W' : 'R',
2242 Pml4e.n.u1User ? 'U' : 'S',
2243 Pml4e.n.u1Accessed ? 'A' : '-',
2244 Pml4e.n.u3Reserved & 1 ? '?' : '.', /* ignored */
2245 Pml4e.n.u3Reserved & 4 ? '!' : '.', /* mbz */
2246 Pml4e.n.u1WriteThru ? "WT" : "--",
2247 Pml4e.n.u1CacheDisable ? "CD" : "--",
2248 Pml4e.n.u3Reserved & 2 ? "!" : "..",/* mbz */
2249 Pml4e.n.u1NoExecute ? "NX" : "--",
2250 Pml4e.u & RT_BIT_64(9) ? '1' : '0',
2251 Pml4e.u & RT_BIT_64(10) ? '1' : '0',
2252 Pml4e.u & RT_BIT_64(11) ? '1' : '0',
2253 Pml4e.u & X86_PML4E_PG_MASK);
2254 if (pState->fDumpPageInfo)
2255 pgmR3DumpHierarchyGstPageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK, _4K);
2256 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pml4e.u);
2257 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2258
2259 if (cMaxDepth)
2260 {
2261 int rc2 = pgmR3DumpHierarchyGstPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
2262 if (rc2 < rc && RT_SUCCESS(rc))
2263 rc = rc2;
2264 }
2265 else
2266 pState->cLeaves++;
2267 }
2268 }
2269
2270 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2271 return rc;
2272}
2273
2274
2275/**
2276 * Dumps a 32-bit shadow page table.
2277 *
2278 * @returns VBox status code (VINF_SUCCESS).
2279 * @param pState The dumper state.
2280 * @param GCPhys The physical address of the table.
2281 */
2282static int pgmR3DumpHierarchyGst32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys)
2283{
2284 PCX86PT pPT;
2285 PGMPAGEMAPLOCK Lock;
2286 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
2287 if (RT_FAILURE(rc))
2288 return rc;
2289
2290 uint32_t iFirst, iLast;
2291 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2292 for (uint32_t i = iFirst; i <= iLast; i++)
2293 {
2294 X86PTE Pte = pPT->a[i];
2295 if (Pte.n.u1Present)
2296 {
2297 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
2298 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
2299 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
2300 pState->u64Address,
2301 Pte.n.u1Write ? 'W' : 'R',
2302 Pte.n.u1User ? 'U' : 'S',
2303 Pte.n.u1Accessed ? 'A' : '-',
2304 Pte.n.u1Dirty ? 'D' : '-',
2305 Pte.n.u1Global ? 'G' : '-',
2306 Pte.n.u1WriteThru ? "WT" : "--",
2307 Pte.n.u1CacheDisable ? "CD" : "--",
2308 Pte.n.u1PAT ? "AT" : "--",
2309 Pte.u & RT_BIT_32(9) ? '1' : '0',
2310 Pte.u & RT_BIT_32(10) ? '1' : '0',
2311 Pte.u & RT_BIT_32(11) ? '1' : '0',
2312 Pte.u & X86_PDE_PG_MASK);
2313 if (pState->fDumpPageInfo)
2314 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
2315 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2316 }
2317 }
2318
2319 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2320 return VINF_SUCCESS;
2321}
2322
2323
2324/**
2325 * Dumps a 32-bit shadow page directory and page tables.
2326 *
2327 * @returns VBox status code (VINF_SUCCESS).
2328 * @param pState The dumper state.
2329 * @param GCPhys The physical address of the table.
2330 * @param cMaxDepth The maximum depth.
2331 */
2332static int pgmR3DumpHierarchyGst32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2333{
2334 if (pState->u64Address >= _4G)
2335 return VINF_SUCCESS;
2336
2337 PCX86PD pPD;
2338 PGMPAGEMAPLOCK Lock;
2339 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
2340 if (RT_FAILURE(rc))
2341 return rc;
2342
2343 Assert(cMaxDepth > 0);
2344 cMaxDepth--;
2345
2346 uint32_t iFirst, iLast;
2347 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2348 for (uint32_t i = iFirst; i <= iLast; i++)
2349 {
2350 X86PDE Pde = pPD->a[i];
2351 if (Pde.n.u1Present)
2352 {
2353 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
2354 if (Pde.b.u1Size && pState->fPse)
2355 {
2356 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
2357 | (Pde.u & X86_PDE4M_PG_MASK);
2358 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2359 "%08llx 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
2360 pState->u64Address,
2361 Pde.b.u1Write ? 'W' : 'R',
2362 Pde.b.u1User ? 'U' : 'S',
2363 Pde.b.u1Accessed ? 'A' : '-',
2364 Pde.b.u1Dirty ? 'D' : '-',
2365 Pde.b.u1Global ? 'G' : '-',
2366 Pde.b.u1WriteThru ? "WT" : "--",
2367 Pde.b.u1CacheDisable ? "CD" : "--",
2368 Pde.b.u1PAT ? "AT" : "--",
2369 Pde.u & RT_BIT_32(9) ? '1' : '0',
2370 Pde.u & RT_BIT_32(10) ? '1' : '0',
2371 Pde.u & RT_BIT_32(11) ? '1' : '0',
2372 u64Phys);
2373 if (pState->fDumpPageInfo)
2374 pgmR3DumpHierarchyGstPageInfo(pState, u64Phys, _4M);
2375 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2376 pState->cLeaves++;
2377 }
2378 else
2379 {
2380 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2381 "%08llx 0 | P %c %c %c %c %c %s %s .. .. .. %c%c%c %08x",
2382 pState->u64Address,
2383 Pde.n.u1Write ? 'W' : 'R',
2384 Pde.n.u1User ? 'U' : 'S',
2385 Pde.n.u1Accessed ? 'A' : '-',
2386 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2387 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2388 Pde.n.u1WriteThru ? "WT" : "--",
2389 Pde.n.u1CacheDisable ? "CD" : "--",
2390 Pde.u & RT_BIT_32(9) ? '1' : '0',
2391 Pde.u & RT_BIT_32(10) ? '1' : '0',
2392 Pde.u & RT_BIT_32(11) ? '1' : '0',
2393 Pde.u & X86_PDE_PG_MASK);
2394 if (pState->fDumpPageInfo)
2395 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PG_MASK, _4K);
2396 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2397
2398 if (cMaxDepth)
2399 {
2400 int rc2 = pgmR3DumpHierarchyGst32BitPT(pState, Pde.u & X86_PDE_PG_MASK);
2401 if (rc2 < rc && RT_SUCCESS(rc))
2402 rc = rc2;
2403 }
2404 else
2405 pState->cLeaves++;
2406 }
2407 }
2408 }
2409
2410 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2411 return rc;
2412}
2413
2414
2415/**
2416 * Internal worker that initiates the actual dump.
2417 *
2418 * @returns VBox status code.
2419 * @param pState The dumper state.
2420 * @param cr3 The CR3 value.
2421 * @param cMaxDepth The max depth.
2422 */
2423static int pgmR3DumpHierarchyGstDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
2424{
2425 int rc;
2426 unsigned const cch = pState->cchAddress;
2427 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK
2428 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
2429 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
2430 : X86_CR3_PAGE_MASK;
2431 if (pState->fPrintCr3)
2432 {
2433 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
2434 : pState->fLme ? "Long Mode"
2435 : pState->fPae ? "PAE Mode"
2436 : pState->fPse ? "32-bit w/ PSE"
2437 : "32-bit";
2438 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
2439 if (pState->fDumpPageInfo)
2440 pgmR3DumpHierarchyGstPageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK, _4K);
2441 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
2442 pszMode,
2443 pState->fNp ? " + Nested Paging" : "",
2444 pState->fNxe ? " + NX" : "");
2445 }
2446
2447
2448 if (pState->fEpt)
2449 {
2450 if (pState->fPrintHeader)
2451 pState->pHlp->pfnPrintf(pState->pHlp,
2452 "%-*s R - Readable\n"
2453 "%-*s | W - Writeable\n"
2454 "%-*s | | X - Executable\n"
2455 "%-*s | | | EMT - EPT memory type\n"
2456 "%-*s | | | | PAT - Ignored PAT?\n"
2457 "%-*s | | | | | AVL1 - 4 available bits\n"
2458 "%-*s | | | | | | AVL2 - 12 available bits\n"
2459 "%-*s Level | | | | | | | page \n"
2460 /* xxxx n **** R W X EMT PAT AVL1 AVL2 xxxxxxxxxxxxx
2461 R W X 7 0 f fff 0123456701234567 */
2462 ,
2463 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
2464
2465 pState->pHlp->pfnPrintf(pState->pHlp, "EPT dumping is not yet implemented, sorry.\n");
2466 /** @todo implemented EPT dumping. */
2467 rc = VERR_NOT_IMPLEMENTED;
2468 }
2469 else
2470 {
2471 if (pState->fPrintHeader)
2472 pState->pHlp->pfnPrintf(pState->pHlp,
2473 "%-*s P - Present\n"
2474 "%-*s | R/W - Read (0) / Write (1)\n"
2475 "%-*s | | U/S - User (1) / Supervisor (0)\n"
2476 "%-*s | | | A - Accessed\n"
2477 "%-*s | | | | D - Dirty\n"
2478 "%-*s | | | | | G - Global\n"
2479 "%-*s | | | | | | WT - Write thru\n"
2480 "%-*s | | | | | | | CD - Cache disable\n"
2481 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
2482 "%-*s | | | | | | | | | NX - No execute (K8)\n"
2483 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
2484 "%-*s | | | | | | | | | | | AVL - 3 available bits.\n"
2485 "%-*s Level | | | | | | | | | | | | Page\n"
2486 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
2487 - W U - - - -- -- -- -- -- 010 */
2488 ,
2489 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
2490 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
2491 if (pState->fLme)
2492 rc = pgmR3DumpHierarchyGstPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
2493 else if (pState->fPae)
2494 rc = pgmR3DumpHierarchyGstPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
2495 else
2496 rc = pgmR3DumpHierarchyGst32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
2497 }
2498
2499 if (!pState->cLeaves)
2500 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
2501 return rc;
2502}
2503
2504
2505/**
2506 * dbgfR3PagingDumpEx worker.
2507 *
2508 * @returns VBox status code.
2509 * @param pVM The cross context VM structure.
2510 * @param cr3 The CR3 register value.
2511 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
2512 * @param FirstAddr The start address.
2513 * @param LastAddr The address to stop after.
2514 * @param cMaxDepth The max depth.
2515 * @param pHlp The output callbacks. Defaults to log if NULL.
2516 *
2517 * @internal
2518 */
2519VMMR3_INT_DECL(int) PGMR3DumpHierarchyGst(PVM pVM, uint64_t cr3, uint32_t fFlags, RTGCPTR FirstAddr, RTGCPTR LastAddr,
2520 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
2521{
2522 /* Minimal validation as we're only supposed to service DBGF. */
2523 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2524 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
2525 AssertReturn(fFlags & DBGFPGDMP_FLAGS_GUEST, VERR_INVALID_PARAMETER);
2526
2527 PGMR3DUMPHIERARCHYSTATE State;
2528 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, FirstAddr, LastAddr, pHlp);
2529 return pgmR3DumpHierarchyGstDoIt(&State, cr3, cMaxDepth);
2530}
2531
2532
2533/**
2534 * For aiding with reset problems and similar.
2535 *
2536 * @param pVM The cross context VM handle.
2537 */
2538void pgmLogState(PVM pVM)
2539{
2540#if 0
2541 RTLogRelPrintf("\npgmLogState pgmLogState pgmLogState pgmLogState pgmLogState\n");
2542
2543 /*
2544 * Per CPU stuff.
2545 */
2546 for (VMCPUID iCpu = 0; iCpu < pVM->cCpus; iCpu++)
2547 {
2548 PPGMCPU pPgmCpu = &pVM->aCpus[iCpu].pgm.s;
2549 RTLogRelPrintf("pgmLogState: CPU #%u\n", iCpu);
2550# define LOG_PGMCPU_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPgmCpu->aMember)
2551 LOG_PGMCPU_MEMBER("#RX32", offVM);
2552 LOG_PGMCPU_MEMBER("#RX32", offVCpu);
2553 LOG_PGMCPU_MEMBER("#RX32", offPGM);
2554 LOG_PGMCPU_MEMBER("RGp", GCPhysA20Mask);
2555 LOG_PGMCPU_MEMBER("RTbool", fA20Enabled);
2556 LOG_PGMCPU_MEMBER("RTbool", fNoExecuteEnabled);
2557 LOG_PGMCPU_MEMBER("#RX32", fSyncFlags);
2558 LOG_PGMCPU_MEMBER("d", enmShadowMode);
2559 LOG_PGMCPU_MEMBER("d", enmGuestMode);
2560 LOG_PGMCPU_MEMBER("RGp", GCPhysCR3);
2561
2562 LOG_PGMCPU_MEMBER("p", pGst32BitPdR3);
2563# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2564 LOG_PGMCPU_MEMBER("p", pGst32BitPdR0);
2565# endif
2566 LOG_PGMCPU_MEMBER("RRv", pGst32BitPdRC);
2567 LOG_PGMCPU_MEMBER("#RX32", fGst32BitMbzBigPdeMask);
2568 LOG_PGMCPU_MEMBER("RTbool", fGst32BitPageSizeExtension);
2569
2570 LOG_PGMCPU_MEMBER("p", pGstPaePdptR3);
2571# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2572 LOG_PGMCPU_MEMBER("p", pGstPaePdptR0);
2573# endif
2574 LOG_PGMCPU_MEMBER("RRv", pGstPaePdptRC);
2575 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[0]);
2576 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[1]);
2577 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[2]);
2578 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[3]);
2579# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2580 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[0]);
2581 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[1]);
2582 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[2]);
2583 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[3]);
2584# endif
2585 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[0]);
2586 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[1]);
2587 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[2]);
2588 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[3]);
2589 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[0]);
2590 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[1]);
2591 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[2]);
2592 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[3]);
2593 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[0].u);
2594 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[1].u);
2595 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[2].u);
2596 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[3].u);
2597 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDsMonitored[0]);
2598 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDsMonitored[1]);
2599 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDsMonitored[2]);
2600 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDsMonitored[3]);
2601 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPteMask);
2602 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPdeMask);
2603 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzBigPdeMask);
2604 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzBigPdeMask);
2605 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPdpeMask);
2606
2607 LOG_PGMCPU_MEMBER("p", pGstAmd64Pml4R3);
2608# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE
2609 LOG_PGMCPU_MEMBER("p", pGstAmd64Pml4R0);
2610# endif
2611 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPteMask);
2612 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPdeMask);
2613 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzBigPdeMask);
2614 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPdpeMask);
2615 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzBigPdpeMask);
2616 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPml4eMask);
2617 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64ShadowedPdpeMask);
2618 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64ShadowedPml4eMask);
2619 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedPteMask);
2620 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedPdeMask);
2621 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedBigPdeMask);
2622 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedBigPde4PteMask);
2623
2624 LOG_PGMCPU_MEMBER("p", pShwPageCR3R3);
2625 LOG_PGMCPU_MEMBER("p", pShwPageCR3R0);
2626 LOG_PGMCPU_MEMBER("RRv", pShwPageCR3RC);
2627
2628 LOG_PGMCPU_MEMBER("p", pfnR3ShwRelocate);
2629 LOG_PGMCPU_MEMBER("p", pfnR3ShwExit);
2630 LOG_PGMCPU_MEMBER("p", pfnR3ShwGetPage);
2631 LOG_PGMCPU_MEMBER("p", pfnR3ShwModifyPage);
2632 LOG_PGMCPU_MEMBER("p", pfnR0ShwGetPage);
2633 LOG_PGMCPU_MEMBER("p", pfnR0ShwModifyPage);
2634 LOG_PGMCPU_MEMBER("p", pfnR3GstRelocate);
2635 LOG_PGMCPU_MEMBER("p", pfnR3GstExit);
2636 LOG_PGMCPU_MEMBER("p", pfnR3GstGetPage);
2637 LOG_PGMCPU_MEMBER("p", pfnR3GstModifyPage);
2638 LOG_PGMCPU_MEMBER("p", pfnR0GstGetPage);
2639 LOG_PGMCPU_MEMBER("p", pfnR0GstModifyPage);
2640 LOG_PGMCPU_MEMBER("p", pfnR3BthRelocate);
2641 LOG_PGMCPU_MEMBER("p", pfnR3BthInvalidatePage);
2642 LOG_PGMCPU_MEMBER("p", pfnR3BthSyncCR3);
2643 LOG_PGMCPU_MEMBER("p", pfnR3BthPrefetchPage);
2644 LOG_PGMCPU_MEMBER("p", pfnR3BthMapCR3);
2645 LOG_PGMCPU_MEMBER("p", pfnR3BthUnmapCR3);
2646 LOG_PGMCPU_MEMBER("p", pfnR0BthMapCR3);
2647 LOG_PGMCPU_MEMBER("p", pfnR0BthUnmapCR3);
2648 LOG_PGMCPU_MEMBER("#RX64", cNetwareWp0Hacks);
2649 LOG_PGMCPU_MEMBER("#RX64", cPoolAccessHandler);
2650
2651 }
2652
2653 /*
2654 * PGM globals.
2655 */
2656 RTLogRelPrintf("PGM globals\n");
2657 PPGM pPgm = &pVM->pgm.s;
2658# define LOG_PGM_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPgm->aMember)
2659 LOG_PGM_MEMBER("#RX32", offVM);
2660 LOG_PGM_MEMBER("#RX32", offVCpuPGM);
2661 LOG_PGM_MEMBER("RTbool", fRamPreAlloc);
2662 LOG_PGM_MEMBER("RTbool", fPhysWriteMonitoringEngaged);
2663 LOG_PGM_MEMBER("RTbool", fLessThan52PhysicalAddressBits);
2664 LOG_PGM_MEMBER("RTbool", fNestedPaging);
2665 LOG_PGM_MEMBER("d", enmHostMode);
2666 LOG_PGM_MEMBER("RTbool", fNoMorePhysWrites);
2667 LOG_PGM_MEMBER("RTbool", fPageFusionAllowed);
2668 LOG_PGM_MEMBER("RTbool", fPciPassthrough);
2669 LOG_PGM_MEMBER("#x", cMmio2Regions);
2670 LOG_PGM_MEMBER("RTbool", fRestoreRomPagesOnReset);
2671 LOG_PGM_MEMBER("RTbool", fZeroRamPagesOnReset);
2672 LOG_PGM_MEMBER("RTbool", fFinalizedMappings);
2673 LOG_PGM_MEMBER("RTbool", fMappingsFixed);
2674 LOG_PGM_MEMBER("RTbool", fMappingsFixedRestored);
2675 LOG_PGM_MEMBER("%#x", cbMappingFixed);
2676 LOG_PGM_MEMBER("%#x", idRamRangesGen);
2677 LOG_PGM_MEMBER("#RGv", GCPtrMappingFixed);
2678 LOG_PGM_MEMBER("#RGv", GCPtrPrevRamRangeMapping);
2679 LOG_PGM_MEMBER("%#x", hRomPhysHandlerType);
2680 LOG_PGM_MEMBER("#RGp", GCPhys4MBPSEMask);
2681 LOG_PGM_MEMBER("#RGp", GCPhysInvAddrMask);
2682 LOG_PGM_MEMBER("p", apRamRangesTlbR3[0]);
2683 LOG_PGM_MEMBER("p", apRamRangesTlbR3[1]);
2684 LOG_PGM_MEMBER("p", apRamRangesTlbR3[2]);
2685 LOG_PGM_MEMBER("p", apRamRangesTlbR3[3]);
2686 LOG_PGM_MEMBER("p", apRamRangesTlbR3[4]);
2687 LOG_PGM_MEMBER("p", apRamRangesTlbR3[5]);
2688 LOG_PGM_MEMBER("p", apRamRangesTlbR3[6]);
2689 LOG_PGM_MEMBER("p", apRamRangesTlbR3[7]);
2690 LOG_PGM_MEMBER("p", pRamRangesXR3);
2691 LOG_PGM_MEMBER("p", pRamRangeTreeR3);
2692 LOG_PGM_MEMBER("p", pTreesR3);
2693 LOG_PGM_MEMBER("p", pLastPhysHandlerR3);
2694 LOG_PGM_MEMBER("p", pPoolR3);
2695 LOG_PGM_MEMBER("p", pMappingsR3);
2696 LOG_PGM_MEMBER("p", pRomRangesR3);
2697 LOG_PGM_MEMBER("p", pRegMmioRangesR3);
2698 LOG_PGM_MEMBER("p", paModeData);
2699 LOG_PGM_MEMBER("p", apMmio2RangesR3[0]);
2700 LOG_PGM_MEMBER("p", apMmio2RangesR3[1]);
2701 LOG_PGM_MEMBER("p", apMmio2RangesR3[2]);
2702 LOG_PGM_MEMBER("p", apMmio2RangesR3[3]);
2703 LOG_PGM_MEMBER("p", apMmio2RangesR3[4]);
2704 LOG_PGM_MEMBER("p", apMmio2RangesR3[5]);
2705 LOG_PGM_MEMBER("p", apRamRangesTlbR0[0]);
2706 LOG_PGM_MEMBER("p", apRamRangesTlbR0[1]);
2707 LOG_PGM_MEMBER("p", apRamRangesTlbR0[2]);
2708 LOG_PGM_MEMBER("p", apRamRangesTlbR0[3]);
2709 LOG_PGM_MEMBER("p", apRamRangesTlbR0[4]);
2710 LOG_PGM_MEMBER("p", apRamRangesTlbR0[5]);
2711 LOG_PGM_MEMBER("p", apRamRangesTlbR0[6]);
2712 LOG_PGM_MEMBER("p", apRamRangesTlbR0[7]);
2713 LOG_PGM_MEMBER("p", pRamRangesXR0);
2714 LOG_PGM_MEMBER("p", pRamRangeTreeR0);
2715 LOG_PGM_MEMBER("p", pTreesR0);
2716 LOG_PGM_MEMBER("p", pLastPhysHandlerR0);
2717 LOG_PGM_MEMBER("p", pPoolR0);
2718 LOG_PGM_MEMBER("p", pMappingsR0);
2719 LOG_PGM_MEMBER("p", pRomRangesR0);
2720 LOG_PGM_MEMBER("p", apMmio2RangesR0[0]);
2721 LOG_PGM_MEMBER("p", apMmio2RangesR0[1]);
2722 LOG_PGM_MEMBER("p", apMmio2RangesR0[2]);
2723 LOG_PGM_MEMBER("p", apMmio2RangesR0[3]);
2724 LOG_PGM_MEMBER("p", apMmio2RangesR0[4]);
2725 LOG_PGM_MEMBER("p", apMmio2RangesR0[5]);
2726 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[0]);
2727 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[1]);
2728 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[2]);
2729 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[3]);
2730 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[4]);
2731 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[5]);
2732 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[6]);
2733 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[7]);
2734 LOG_PGM_MEMBER("RRv", pRamRangesXRC);
2735 LOG_PGM_MEMBER("RRv", pRamRangeTreeRC);
2736 LOG_PGM_MEMBER("RRv", pTreesRC);
2737 LOG_PGM_MEMBER("RRv", pLastPhysHandlerRC);
2738 LOG_PGM_MEMBER("RRv", pPoolRC);
2739 LOG_PGM_MEMBER("RRv", pMappingsRC);
2740 LOG_PGM_MEMBER("RRv", pRomRangesRC);
2741 LOG_PGM_MEMBER("RRv", paDynPageMap32BitPTEsGC);
2742 LOG_PGM_MEMBER("RRv", paDynPageMapPaePTEsGC);
2743
2744 LOG_PGM_MEMBER("#RGv", GCPtrCR3Mapping);
2745 LOG_PGM_MEMBER("p", pInterPD);
2746 LOG_PGM_MEMBER("p", apInterPTs[0]);
2747 LOG_PGM_MEMBER("p", apInterPTs[1]);
2748 LOG_PGM_MEMBER("p", apInterPaePTs[0]);
2749 LOG_PGM_MEMBER("p", apInterPaePTs[1]);
2750 LOG_PGM_MEMBER("p", apInterPaePDs[0]);
2751 LOG_PGM_MEMBER("p", apInterPaePDs[1]);
2752 LOG_PGM_MEMBER("p", apInterPaePDs[2]);
2753 LOG_PGM_MEMBER("p", apInterPaePDs[3]);
2754 LOG_PGM_MEMBER("p", pInterPaePDPT);
2755 LOG_PGM_MEMBER("p", pInterPaePML4);
2756 LOG_PGM_MEMBER("p", pInterPaePDPT64);
2757 LOG_PGM_MEMBER("#RHp", HCPhysInterPD);
2758 LOG_PGM_MEMBER("#RHp", HCPhysInterPaePDPT);
2759 LOG_PGM_MEMBER("#RHp", HCPhysInterPaePML4);
2760 LOG_PGM_MEMBER("RRv", pbDynPageMapBaseGC);
2761 LOG_PGM_MEMBER("RRv", pRCDynMap);
2762 LOG_PGM_MEMBER("p", pvR0DynMapUsed);
2763 LOG_PGM_MEMBER("%#x", cDeprecatedPageLocks);
2764
2765 /**
2766 * Data associated with managing the ring-3 mappings of the allocation chunks.
2767 */
2768 LOG_PGM_MEMBER("p", ChunkR3Map.pTree);
2769 //LOG_PGM_MEMBER(PGMCHUNKR3MAPTLB ChunkR3Map.Tlb);
2770 LOG_PGM_MEMBER("%#x", ChunkR3Map.c);
2771 LOG_PGM_MEMBER("%#x", ChunkR3Map.cMax);
2772 LOG_PGM_MEMBER("%#x", ChunkR3Map.iNow);
2773 //LOG_PGM_MEMBER(PGMPAGER3MAPTLB PhysTlbHC);
2774
2775 LOG_PGM_MEMBER("#RHp", HCPhysZeroPg);
2776 LOG_PGM_MEMBER("p", pvZeroPgR3);
2777 LOG_PGM_MEMBER("p", pvZeroPgR0);
2778 LOG_PGM_MEMBER("RRv", pvZeroPgRC);
2779 LOG_PGM_MEMBER("#RHp", HCPhysMmioPg);
2780 LOG_PGM_MEMBER("#RHp", HCPhysInvMmioPg);
2781 LOG_PGM_MEMBER("p", pvMmioPgR3);
2782 LOG_PGM_MEMBER("RTbool", fErrInjHandyPages);
2783
2784 /*
2785 * PGM page pool.
2786 */
2787 PPGMPOOL pPool = pVM->pgm.s.pPoolR3;
2788 RTLogRelPrintf("PGM Page Pool\n");
2789# define LOG_PGMPOOL_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPool->aMember)
2790 LOG_PGMPOOL_MEMBER("p", pVMR3);
2791 LOG_PGMPOOL_MEMBER("p", pVMR0);
2792 LOG_PGMPOOL_MEMBER("RRv", pVMRC);
2793 LOG_PGMPOOL_MEMBER("#x", cMaxPages);
2794 LOG_PGMPOOL_MEMBER("#x", cCurPages);
2795 LOG_PGMPOOL_MEMBER("#x", iFreeHead);
2796 LOG_PGMPOOL_MEMBER("#x", u16Padding);
2797 LOG_PGMPOOL_MEMBER("#x", iUserFreeHead);
2798 LOG_PGMPOOL_MEMBER("#x", cMaxUsers);
2799 LOG_PGMPOOL_MEMBER("#x", cPresent);
2800 LOG_PGMPOOL_MEMBER("RRv", paUsersRC);
2801 LOG_PGMPOOL_MEMBER("p", paUsersR3);
2802 LOG_PGMPOOL_MEMBER("p", paUsersR0);
2803 LOG_PGMPOOL_MEMBER("#x", iPhysExtFreeHead);
2804 LOG_PGMPOOL_MEMBER("#x", cMaxPhysExts);
2805 LOG_PGMPOOL_MEMBER("RRv", paPhysExtsRC);
2806 LOG_PGMPOOL_MEMBER("p", paPhysExtsR3);
2807 LOG_PGMPOOL_MEMBER("p", paPhysExtsR0);
2808 for (uint32_t i = 0; i < RT_ELEMENTS(pPool->aiHash); i++)
2809 RTLogRelPrintf(" aiHash[%u]: %#x\n", i, pPool->aiHash[i]);
2810 LOG_PGMPOOL_MEMBER("#x", iAgeHead);
2811 LOG_PGMPOOL_MEMBER("#x", iAgeTail);
2812 LOG_PGMPOOL_MEMBER("RTbool", fCacheEnabled);
2813 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[0]);
2814 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[1]);
2815 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[2]);
2816 LOG_PGMPOOL_MEMBER("#x", iModifiedHead);
2817 LOG_PGMPOOL_MEMBER("#x", cModifiedPages);
2818 LOG_PGMPOOL_MEMBER("#x", hAccessHandlerType);
2819 LOG_PGMPOOL_MEMBER("#x", idxFreeDirtyPage);
2820 LOG_PGMPOOL_MEMBER("#x", cDirtyPages);
2821 for (uint32_t i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
2822 RTLogRelPrintf(" aDirtyPages[%u].uIdx: %#x\n", i, pPool->aDirtyPages[i].uIdx);
2823 LOG_PGMPOOL_MEMBER("#x", cUsedPages);
2824 LOG_PGMPOOL_MEMBER("#x", HCPhysTree);
2825 for (uint32_t i = 0; i < pPool->cCurPages; i++)
2826 {
2827 PPGMPOOLPAGE pPage = &pPool->aPages[i];
2828# define LOG_PAGE_MEMBER(aFmt, aMember) RTLogRelPrintf(" %3u:%-32s: %" aFmt "\n", i, #aMember, pPage->aMember)
2829 RTLogRelPrintf("%3u:%-32s: %p\n", i, "", pPage);
2830 LOG_PAGE_MEMBER("RHp", Core.Key);
2831 LOG_PAGE_MEMBER("p", pvPageR3);
2832 LOG_PAGE_MEMBER("RGp", GCPhys);
2833 LOG_PAGE_MEMBER("d", enmKind);
2834 LOG_PAGE_MEMBER("d", enmAccess);
2835 LOG_PAGE_MEMBER("RTbool", fA20Enabled);
2836 LOG_PAGE_MEMBER("RTbool", fZeroed);
2837 LOG_PAGE_MEMBER("RTbool", fSeenNonGlobal);
2838 LOG_PAGE_MEMBER("RTbool", fMonitored);
2839 LOG_PAGE_MEMBER("RTbool", fCached);
2840 LOG_PAGE_MEMBER("RTbool", fReusedFlushPending);
2841 LOG_PAGE_MEMBER("RTbool", fDirty);
2842 LOG_PAGE_MEMBER("RTbool", fPadding1);
2843 LOG_PAGE_MEMBER("RTbool", fPadding2);
2844 LOG_PAGE_MEMBER("#x", idx);
2845 LOG_PAGE_MEMBER("#x", iNext);
2846 LOG_PAGE_MEMBER("#x", iUserHead);
2847 LOG_PAGE_MEMBER("#x", cPresent);
2848 LOG_PAGE_MEMBER("#x", iFirstPresent);
2849 LOG_PAGE_MEMBER("#x", cModifications);
2850 LOG_PAGE_MEMBER("#x", iModifiedNext);
2851 LOG_PAGE_MEMBER("#x", iModifiedPrev);
2852 LOG_PAGE_MEMBER("#x", iMonitoredNext);
2853 LOG_PAGE_MEMBER("#x", iMonitoredPrev);
2854 LOG_PAGE_MEMBER("#x", iAgeNext);
2855 LOG_PAGE_MEMBER("#x", iAgePrev);
2856 LOG_PAGE_MEMBER("#x", idxDirtyEntry);
2857 LOG_PAGE_MEMBER("RGv", GCPtrLastAccessHandlerRip);
2858 LOG_PAGE_MEMBER("RGv", GCPtrLastAccessHandlerFault);
2859 LOG_PAGE_MEMBER("#RX64", cLastAccessHandler);
2860 LOG_PAGE_MEMBER("#RX32", cLocked);
2861# ifdef VBOX_STRICT
2862 LOG_PAGE_MEMBER("RGv", GCPtrDirtyFault);
2863# endif
2864 if ( pPage->enmKind == PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT
2865 || pPage->enmKind == PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB
2866 || pPage->enmKind == PGMPOOLKIND_32BIT_PD
2867 || pPage->enmKind == PGMPOOLKIND_32BIT_PD_PHYS)
2868 {
2869 uint32_t const *pu32Page = (uint32_t const *)pPage->pvPageR3;
2870 for (uint32_t i = 0; i < 1024/2; i += 4)
2871 RTLogRelPrintf(" %#05x: %RX32 %RX32 %RX32 %RX32\n", i, pu32Page[i], pu32Page[i+1], pu32Page[i+2], pu32Page[i+3]);
2872 }
2873 else if ( pPage->enmKind != PGMPOOLKIND_FREE
2874 && pPage->enmKind != PGMPOOLKIND_INVALID)
2875 {
2876 uint64_t const *pu64Page = (uint64_t const *)pPage->pvPageR3;
2877 for (uint32_t i = 0; i < 512/2; i += 2)
2878 RTLogRelPrintf(" %#05x: %RX64 %RX64\n", i, pu64Page[i], pu64Page[i+1]);
2879 }
2880 }
2881
2882 RTLogRelPrintf("pgmLogState pgmLogState pgmLogState pgmLogState pgmLogState\n\n");
2883#else
2884 RT_NOREF(pVM);
2885#endif
2886}
2887
Note: See TracBrowser for help on using the repository browser.

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