VirtualBox

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

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

VMM: Kicking out raw-mode and 32-bit hosts - MM, PGM, ++. bugref:9517 bugref:9511

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

© 2023 Oracle
ContactPrivacy policyTerms of Use