VirtualBox

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

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

VMM/PGM: Check PGMCritSectEnter status code when we don't return it. bugref:6695

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