VirtualBox

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

Last change on this file since 96335 was 93951, checked in by vboxsync, 3 years ago

VMM/PGMDbg: GCC 11.2.1 build tweaks.

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

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