VirtualBox

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

Last change on this file since 41783 was 41783, checked in by vboxsync, 12 years ago

Doxygen, comment typos.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 97.0 KB
Line 
1/* $Id: PGMDbg.cpp 41783 2012-06-16 19:24:15Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - Debugger & Debugging APIs.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_PGM
22#include <VBox/vmm/pgm.h>
23#include <VBox/vmm/stam.h>
24#include "PGMInternal.h"
25#include <VBox/vmm/vm.h>
26#include "PGMInline.h"
27#include <iprt/assert.h>
28#include <iprt/asm.h>
29#include <iprt/string.h>
30#include <VBox/log.h>
31#include <VBox/param.h>
32#include <VBox/err.h>
33
34
35/*******************************************************************************
36* Defined Constants And Macros *
37*******************************************************************************/
38/** The max needle size that we will bother searching for
39 * This must not be more than half a page! */
40#define MAX_NEEDLE_SIZE 256
41
42
43/*******************************************************************************
44* Structures and Typedefs *
45*******************************************************************************/
46/**
47 * State structure for the paging hierarchy dumpers.
48 */
49typedef struct PGMR3DUMPHIERARCHYSTATE
50{
51 /** Pointer to the VM. */
52 PVM pVM;
53 /** Output helpers. */
54 PCDBGFINFOHLP pHlp;
55 /** Set if PSE, PAE or long mode is enabled. */
56 bool fPse;
57 /** Set if PAE or long mode is enabled. */
58 bool fPae;
59 /** Set if long mode is enabled. */
60 bool fLme;
61 /** Set if nested paging. */
62 bool fNp;
63 /** Set if EPT. */
64 bool fEpt;
65 /** Set if NXE is enabled. */
66 bool fNxe;
67 /** The number or chars the address needs. */
68 uint8_t cchAddress;
69 /** The last reserved bit. */
70 uint8_t uLastRsvdBit;
71 /** Dump the page info as well (shadow page summary / guest physical
72 * page summary). */
73 bool fDumpPageInfo;
74 /** Whether or not to print the header. */
75 bool fPrintHeader;
76 /** Whether to print the CR3 value */
77 bool fPrintCr3;
78 /** Padding*/
79 bool afReserved[5];
80 /** The current address. */
81 uint64_t u64Address;
82 /** The last address to dump structures for. */
83 uint64_t u64FirstAddress;
84 /** The last address to dump structures for. */
85 uint64_t u64LastAddress;
86 /** Mask with the high reserved bits set. */
87 uint64_t u64HighReservedBits;
88 /** The number of leaf entries that we've printed. */
89 uint64_t cLeaves;
90} PGMR3DUMPHIERARCHYSTATE;
91/** Pointer to the paging hierarchy dumper state. */
92typedef PGMR3DUMPHIERARCHYSTATE *PPGMR3DUMPHIERARCHYSTATE;
93
94
95
96/**
97 * Converts a R3 pointer to a GC physical address.
98 *
99 * Only for the debugger.
100 *
101 * @returns VBox status code.
102 * @retval VINF_SUCCESS on success, *pGCPhys is set.
103 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
104 *
105 * @param pVM Pointer to the VM.
106 * @param R3Ptr The R3 pointer to convert.
107 * @param pGCPhys Where to store the GC physical address on success.
108 */
109VMMR3DECL(int) PGMR3DbgR3Ptr2GCPhys(PVM pVM, RTR3PTR R3Ptr, PRTGCPHYS pGCPhys)
110{
111 NOREF(pVM); NOREF(R3Ptr);
112 *pGCPhys = NIL_RTGCPHYS;
113 return VERR_NOT_IMPLEMENTED;
114}
115
116
117/**
118 * Converts a R3 pointer to a HC physical address.
119 *
120 * Only for the debugger.
121 *
122 * @returns VBox status code.
123 * @retval VINF_SUCCESS on success, *pHCPhys is set.
124 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical page but has no physical backing.
125 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
126 *
127 * @param pVM Pointer to the VM.
128 * @param R3Ptr The R3 pointer to convert.
129 * @param pHCPhys Where to store the HC physical address on success.
130 */
131VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PVM pVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys)
132{
133 NOREF(pVM); NOREF(R3Ptr);
134 *pHCPhys = NIL_RTHCPHYS;
135 return VERR_NOT_IMPLEMENTED;
136}
137
138
139/**
140 * Converts a HC physical address to a GC physical address.
141 *
142 * Only for the debugger.
143 *
144 * @returns VBox status code
145 * @retval VINF_SUCCESS on success, *pGCPhys is set.
146 * @retval VERR_INVALID_POINTER if the HC physical address is not within the GC physical memory.
147 *
148 * @param pVM Pointer to the VM.
149 * @param HCPhys The HC physical address to convert.
150 * @param pGCPhys Where to store the GC physical address on success.
151 */
152VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PVM pVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys)
153{
154 /*
155 * Validate and adjust the input a bit.
156 */
157 if (HCPhys == NIL_RTHCPHYS)
158 return VERR_INVALID_POINTER;
159 unsigned off = HCPhys & PAGE_OFFSET_MASK;
160 HCPhys &= X86_PTE_PAE_PG_MASK;
161 if (HCPhys == 0)
162 return VERR_INVALID_POINTER;
163
164 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX);
165 pRam;
166 pRam = pRam->CTX_SUFF(pNext))
167 {
168 uint32_t iPage = pRam->cb >> PAGE_SHIFT;
169 while (iPage-- > 0)
170 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
171 {
172 *pGCPhys = pRam->GCPhys + (iPage << PAGE_SHIFT) + off;
173 return VINF_SUCCESS;
174 }
175 }
176 return VERR_INVALID_POINTER;
177}
178
179
180/**
181 * Read physical memory API for the debugger, similar to
182 * PGMPhysSimpleReadGCPhys.
183 *
184 * @returns VBox status code.
185 *
186 * @param pVM Pointer to the VM.
187 * @param pvDst Where to store what's read.
188 * @param GCPhysDst Where to start reading from.
189 * @param cb The number of bytes to attempt reading.
190 * @param fFlags Flags, MBZ.
191 * @param pcbRead For store the actual number of bytes read, pass NULL if
192 * partial reads are unwanted.
193 * @todo Unused?
194 */
195VMMR3DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
196{
197 /* validate */
198 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
199 AssertReturn(pVM, VERR_INVALID_PARAMETER);
200
201 /* try simple first. */
202 int rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cb);
203 if (RT_SUCCESS(rc) || !pcbRead)
204 return rc;
205
206 /* partial read that failed, chop it up in pages. */
207 *pcbRead = 0;
208 rc = VINF_SUCCESS;
209 while (cb > 0)
210 {
211 size_t cbChunk = PAGE_SIZE;
212 cbChunk -= GCPhysSrc & PAGE_OFFSET_MASK;
213 if (cbChunk > cb)
214 cbChunk = cb;
215
216 rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cbChunk);
217
218 /* advance */
219 if (RT_FAILURE(rc))
220 break;
221 *pcbRead += cbChunk;
222 cb -= cbChunk;
223 GCPhysSrc += cbChunk;
224 pvDst = (uint8_t *)pvDst + cbChunk;
225 }
226
227 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
228}
229
230
231/**
232 * Write physical memory API for the debugger, similar to
233 * PGMPhysSimpleWriteGCPhys.
234 *
235 * @returns VBox status code.
236 *
237 * @param pVM Pointer to the VM.
238 * @param GCPhysDst Where to start writing.
239 * @param pvSrc What to write.
240 * @param cb The number of bytes to attempt writing.
241 * @param fFlags Flags, MBZ.
242 * @param pcbWritten For store the actual number of bytes written, pass NULL
243 * if partial writes are unwanted.
244 * @todo Unused?
245 */
246VMMR3DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
247{
248 /* validate */
249 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
250 AssertReturn(pVM, VERR_INVALID_PARAMETER);
251
252 /* try simple first. */
253 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cb);
254 if (RT_SUCCESS(rc) || !pcbWritten)
255 return rc;
256
257 /* partial write that failed, chop it up in pages. */
258 *pcbWritten = 0;
259 rc = VINF_SUCCESS;
260 while (cb > 0)
261 {
262 size_t cbChunk = PAGE_SIZE;
263 cbChunk -= GCPhysDst & PAGE_OFFSET_MASK;
264 if (cbChunk > cb)
265 cbChunk = cb;
266
267 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cbChunk);
268
269 /* advance */
270 if (RT_FAILURE(rc))
271 break;
272 *pcbWritten += cbChunk;
273 cb -= cbChunk;
274 GCPhysDst += cbChunk;
275 pvSrc = (uint8_t const *)pvSrc + cbChunk;
276 }
277
278 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
279
280}
281
282
283/**
284 * Read virtual memory API for the debugger, similar to PGMPhysSimpleReadGCPtr.
285 *
286 * @returns VBox status code.
287 *
288 * @param pVM Pointer to the VM.
289 * @param pvDst Where to store what's read.
290 * @param GCPtrDst Where to start reading from.
291 * @param cb The number of bytes to attempt reading.
292 * @param fFlags Flags, MBZ.
293 * @param pcbRead For store the actual number of bytes read, pass NULL if
294 * partial reads are unwanted.
295 * @todo Unused?
296 */
297VMMR3DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
298{
299 /* validate */
300 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
301 AssertReturn(pVM, VERR_INVALID_PARAMETER);
302
303 /* @todo SMP support! */
304 PVMCPU pVCpu = &pVM->aCpus[0];
305
306/** @todo deal with HMA */
307 /* try simple first. */
308 int rc = PGMPhysSimpleReadGCPtr(pVCpu, pvDst, GCPtrSrc, cb);
309 if (RT_SUCCESS(rc) || !pcbRead)
310 return rc;
311
312 /* partial read that failed, chop it up in pages. */
313 *pcbRead = 0;
314 rc = VINF_SUCCESS;
315 while (cb > 0)
316 {
317 size_t cbChunk = PAGE_SIZE;
318 cbChunk -= GCPtrSrc & PAGE_OFFSET_MASK;
319 if (cbChunk > cb)
320 cbChunk = cb;
321
322 rc = PGMPhysSimpleReadGCPtr(pVCpu, pvDst, GCPtrSrc, cbChunk);
323
324 /* advance */
325 if (RT_FAILURE(rc))
326 break;
327 *pcbRead += cbChunk;
328 cb -= cbChunk;
329 GCPtrSrc += cbChunk;
330 pvDst = (uint8_t *)pvDst + cbChunk;
331 }
332
333 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
334
335}
336
337
338/**
339 * Write virtual memory API for the debugger, similar to
340 * PGMPhysSimpleWriteGCPtr.
341 *
342 * @returns VBox status code.
343 *
344 * @param pVM Pointer to the VM.
345 * @param GCPtrDst Where to start writing.
346 * @param pvSrc What to write.
347 * @param cb The number of bytes to attempt writing.
348 * @param fFlags Flags, MBZ.
349 * @param pcbWritten For store the actual number of bytes written, pass NULL
350 * if partial writes are unwanted.
351 * @todo Unused?
352 */
353VMMR3DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
354{
355 /* validate */
356 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
357 AssertReturn(pVM, VERR_INVALID_PARAMETER);
358
359 /* @todo SMP support! */
360 PVMCPU pVCpu = &pVM->aCpus[0];
361
362/** @todo deal with HMA */
363 /* try simple first. */
364 int rc = PGMPhysSimpleWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cb);
365 if (RT_SUCCESS(rc) || !pcbWritten)
366 return rc;
367
368 /* partial write that failed, chop it up in pages. */
369 *pcbWritten = 0;
370 rc = VINF_SUCCESS;
371 while (cb > 0)
372 {
373 size_t cbChunk = PAGE_SIZE;
374 cbChunk -= GCPtrDst & PAGE_OFFSET_MASK;
375 if (cbChunk > cb)
376 cbChunk = cb;
377
378 rc = PGMPhysSimpleWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cbChunk);
379
380 /* advance */
381 if (RT_FAILURE(rc))
382 break;
383 *pcbWritten += cbChunk;
384 cb -= cbChunk;
385 GCPtrDst += cbChunk;
386 pvSrc = (uint8_t const *)pvSrc + cbChunk;
387 }
388
389 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
390
391}
392
393
394/**
395 * memchr() with alignment considerations.
396 *
397 * @returns Pointer to matching byte, NULL if none found.
398 * @param pb Where to search. Aligned.
399 * @param b What to search for.
400 * @param cb How much to search .
401 * @param uAlign The alignment restriction of the result.
402 */
403static const uint8_t *pgmR3DbgAlignedMemChr(const uint8_t *pb, uint8_t b, size_t cb, uint32_t uAlign)
404{
405 const uint8_t *pbRet;
406 if (uAlign <= 32)
407 {
408 pbRet = (const uint8_t *)memchr(pb, b, cb);
409 if ((uintptr_t)pbRet & (uAlign - 1))
410 {
411 do
412 {
413 pbRet++;
414 size_t cbLeft = cb - (pbRet - pb);
415 if (!cbLeft)
416 {
417 pbRet = NULL;
418 break;
419 }
420 pbRet = (const uint8_t *)memchr(pbRet, b, cbLeft);
421 } while ((uintptr_t)pbRet & (uAlign - 1));
422 }
423 }
424 else
425 {
426 pbRet = NULL;
427 if (cb)
428 {
429 for (;;)
430 {
431 if (*pb == b)
432 {
433 pbRet = pb;
434 break;
435 }
436 if (cb <= uAlign)
437 break;
438 cb -= uAlign;
439 pb += uAlign;
440 }
441 }
442 }
443 return pbRet;
444}
445
446
447/**
448 * Scans a page for a byte string, keeping track of potential
449 * cross page matches.
450 *
451 * @returns true and *poff on match.
452 * false on mismatch.
453 * @param pbPage Pointer to the current page.
454 * @param poff Input: The offset into the page (aligned).
455 * Output: The page offset of the match on success.
456 * @param cb The number of bytes to search, starting of *poff.
457 * @param uAlign The needle alignment. This is of course less than a page.
458 * @param pabNeedle The byte string to search for.
459 * @param cbNeedle The length of the byte string.
460 * @param pabPrev The buffer that keeps track of a partial match that we
461 * bring over from the previous page. This buffer must be
462 * at least cbNeedle - 1 big.
463 * @param pcbPrev Input: The number of partial matching bytes from the previous page.
464 * Output: The number of partial matching bytes from this page.
465 * Initialize to 0 before the first call to this function.
466 */
467static bool pgmR3DbgScanPage(const uint8_t *pbPage, int32_t *poff, uint32_t cb, uint32_t uAlign,
468 const uint8_t *pabNeedle, size_t cbNeedle,
469 uint8_t *pabPrev, size_t *pcbPrev)
470{
471 /*
472 * Try complete any partial match from the previous page.
473 */
474 if (*pcbPrev > 0)
475 {
476 size_t cbPrev = *pcbPrev;
477 Assert(!*poff);
478 Assert(cbPrev < cbNeedle);
479 if (!memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
480 {
481 if (cbNeedle - cbPrev > cb)
482 return false;
483 *poff = -(int32_t)cbPrev;
484 return true;
485 }
486
487 /* check out the remainder of the previous page. */
488 const uint8_t *pb = pabPrev;
489 for (;;)
490 {
491 if (cbPrev <= uAlign)
492 break;
493 cbPrev -= uAlign;
494 pb = pgmR3DbgAlignedMemChr(pb + uAlign, *pabNeedle, cbPrev, uAlign);
495 if (!pb)
496 break;
497 cbPrev = *pcbPrev - (pb - pabPrev);
498 if ( !memcmp(pb + 1, &pabNeedle[1], cbPrev - 1)
499 && !memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
500 {
501 if (cbNeedle - cbPrev > cb)
502 return false;
503 *poff = -(int32_t)cbPrev;
504 return true;
505 }
506 }
507
508 *pcbPrev = 0;
509 }
510
511 /*
512 * Match the body of the page.
513 */
514 const uint8_t *pb = pbPage + *poff;
515 const uint8_t *pbEnd = pb + cb;
516 for (;;)
517 {
518 pb = pgmR3DbgAlignedMemChr(pb, *pabNeedle, cb, uAlign);
519 if (!pb)
520 break;
521 cb = pbEnd - pb;
522 if (cb >= cbNeedle)
523 {
524 /* match? */
525 if (!memcmp(pb + 1, &pabNeedle[1], cbNeedle - 1))
526 {
527 *poff = pb - pbPage;
528 return true;
529 }
530 }
531 else
532 {
533 /* partial match at the end of the page? */
534 if (!memcmp(pb + 1, &pabNeedle[1], cb - 1))
535 {
536 /* We're copying one byte more that we really need here, but wtf. */
537 memcpy(pabPrev, pb, cb);
538 *pcbPrev = cb;
539 return false;
540 }
541 }
542
543 /* no match, skip ahead. */
544 if (cb <= uAlign)
545 break;
546 pb += uAlign;
547 cb -= uAlign;
548 }
549
550 return false;
551}
552
553
554/**
555 * Scans guest physical memory for a byte string.
556 *
557 * @returns VBox status codes:
558 * @retval VINF_SUCCESS and *pGCPtrHit on success.
559 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
560 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
561 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
562 *
563 * @param pVM Pointer to the VM.
564 * @param GCPhys Where to start searching.
565 * @param cbRange The number of bytes to search.
566 * @param GCPhysAlign The alignment of the needle. Must be a power of two
567 * and less or equal to 4GB.
568 * @param pabNeedle The byte string to search for.
569 * @param cbNeedle The length of the byte string. Max 256 bytes.
570 * @param pGCPhysHit Where to store the address of the first occurrence on success.
571 */
572VMMR3DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign,
573 const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit)
574{
575 /*
576 * Validate and adjust the input a bit.
577 */
578 if (!VALID_PTR(pGCPhysHit))
579 return VERR_INVALID_POINTER;
580 *pGCPhysHit = NIL_RTGCPHYS;
581
582 if ( !VALID_PTR(pabNeedle)
583 || GCPhys == NIL_RTGCPHYS)
584 return VERR_INVALID_POINTER;
585 if (!cbNeedle)
586 return VERR_INVALID_PARAMETER;
587 if (cbNeedle > MAX_NEEDLE_SIZE)
588 return VERR_INVALID_PARAMETER;
589
590 if (!cbRange)
591 return VERR_DBGF_MEM_NOT_FOUND;
592 if (GCPhys + cbNeedle - 1 < GCPhys)
593 return VERR_DBGF_MEM_NOT_FOUND;
594
595 if (!GCPhysAlign)
596 return VERR_INVALID_PARAMETER;
597 if (GCPhysAlign > UINT32_MAX)
598 return VERR_NOT_POWER_OF_TWO;
599 if (GCPhysAlign & (GCPhysAlign - 1))
600 return VERR_INVALID_PARAMETER;
601
602 if (GCPhys & (GCPhysAlign - 1))
603 {
604 RTGCPHYS Adj = GCPhysAlign - (GCPhys & (GCPhysAlign - 1));
605 if ( cbRange <= Adj
606 || GCPhys + Adj < GCPhys)
607 return VERR_DBGF_MEM_NOT_FOUND;
608 GCPhys += Adj;
609 cbRange -= Adj;
610 }
611
612 const bool fAllZero = ASMMemIsAll8(pabNeedle, cbNeedle, 0) == NULL;
613 const uint32_t cIncPages = GCPhysAlign <= PAGE_SIZE
614 ? 1
615 : GCPhysAlign >> PAGE_SHIFT;
616 const RTGCPHYS GCPhysLast = GCPhys + cbRange - 1 >= GCPhys
617 ? GCPhys + cbRange - 1
618 : ~(RTGCPHYS)0;
619
620 /*
621 * Search the memory - ignore MMIO and zero pages, also don't
622 * bother to match across ranges.
623 */
624 pgmLock(pVM);
625 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX);
626 pRam;
627 pRam = pRam->CTX_SUFF(pNext))
628 {
629 /*
630 * If the search range starts prior to the current ram range record,
631 * adjust the search range and possibly conclude the search.
632 */
633 RTGCPHYS off;
634 if (GCPhys < pRam->GCPhys)
635 {
636 if (GCPhysLast < pRam->GCPhys)
637 break;
638 GCPhys = pRam->GCPhys;
639 off = 0;
640 }
641 else
642 off = GCPhys - pRam->GCPhys;
643 if (off < pRam->cb)
644 {
645 /*
646 * Iterate the relevant pages.
647 */
648 uint8_t abPrev[MAX_NEEDLE_SIZE];
649 size_t cbPrev = 0;
650 const uint32_t cPages = pRam->cb >> PAGE_SHIFT;
651 uint32_t iPage = off >> PAGE_SHIFT;
652 uint32_t offPage = GCPhys & PAGE_OFFSET_MASK;
653 GCPhys &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
654 for (;; offPage = 0)
655 {
656 PPGMPAGE pPage = &pRam->aPages[iPage];
657 if ( ( !PGM_PAGE_IS_ZERO(pPage)
658 || fAllZero)
659 && !PGM_PAGE_IS_BALLOONED(pPage)
660 && !PGM_PAGE_IS_MMIO(pPage))
661 {
662 void const *pvPage;
663 PGMPAGEMAPLOCK Lock;
664 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, &pvPage, &Lock);
665 if (RT_SUCCESS(rc))
666 {
667 int32_t offHit = offPage;
668 bool fRc;
669 if (GCPhysAlign < PAGE_SIZE)
670 {
671 uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)PAGE_OFFSET_MASK
672 ? PAGE_SIZE - (uint32_t)offPage
673 : (GCPhysLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
674 fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPhysAlign,
675 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
676 }
677 else
678 fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
679 && (GCPhysLast - GCPhys) >= cbNeedle;
680 PGMPhysReleasePageMappingLock(pVM, &Lock);
681 if (fRc)
682 {
683 *pGCPhysHit = GCPhys + offHit;
684 pgmUnlock(pVM);
685 return VINF_SUCCESS;
686 }
687 }
688 else
689 cbPrev = 0; /* ignore error. */
690 }
691 else
692 cbPrev = 0;
693
694 /* advance to the next page. */
695 GCPhys += (RTGCPHYS)cIncPages << PAGE_SHIFT;
696 if (GCPhys >= GCPhysLast) /* (may not always hit, but we're run out of ranges.) */
697 {
698 pgmUnlock(pVM);
699 return VERR_DBGF_MEM_NOT_FOUND;
700 }
701 iPage += cIncPages;
702 if ( iPage < cIncPages
703 || iPage >= cPages)
704 break;
705 }
706 }
707 }
708 pgmUnlock(pVM);
709 return VERR_DBGF_MEM_NOT_FOUND;
710}
711
712
713/**
714 * Scans (guest) virtual memory for a byte string.
715 *
716 * @returns VBox status codes:
717 * @retval VINF_SUCCESS and *pGCPtrHit on success.
718 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
719 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
720 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
721 *
722 * @param pVM Pointer to the VM.
723 * @param pVCpu The CPU context to search in.
724 * @param GCPtr Where to start searching.
725 * @param GCPtrAlign The alignment of the needle. Must be a power of two
726 * and less or equal to 4GB.
727 * @param cbRange The number of bytes to search. Max 256 bytes.
728 * @param pabNeedle The byte string to search for.
729 * @param cbNeedle The length of the byte string.
730 * @param pGCPtrHit Where to store the address of the first occurrence on success.
731 */
732VMMR3DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign,
733 const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
734{
735 VMCPU_ASSERT_EMT(pVCpu);
736
737 /*
738 * Validate and adjust the input a bit.
739 */
740 if (!VALID_PTR(pGCPtrHit))
741 return VERR_INVALID_POINTER;
742 *pGCPtrHit = 0;
743
744 if (!VALID_PTR(pabNeedle))
745 return VERR_INVALID_POINTER;
746 if (!cbNeedle)
747 return VERR_INVALID_PARAMETER;
748 if (cbNeedle > MAX_NEEDLE_SIZE)
749 return VERR_INVALID_PARAMETER;
750
751 if (!cbRange)
752 return VERR_DBGF_MEM_NOT_FOUND;
753 if (GCPtr + cbNeedle - 1 < GCPtr)
754 return VERR_DBGF_MEM_NOT_FOUND;
755
756 if (!GCPtrAlign)
757 return VERR_INVALID_PARAMETER;
758 if (GCPtrAlign > UINT32_MAX)
759 return VERR_NOT_POWER_OF_TWO;
760 if (GCPtrAlign & (GCPtrAlign - 1))
761 return VERR_INVALID_PARAMETER;
762
763 if (GCPtr & (GCPtrAlign - 1))
764 {
765 RTGCPTR Adj = GCPtrAlign - (GCPtr & (GCPtrAlign - 1));
766 if ( cbRange <= Adj
767 || GCPtr + Adj < GCPtr)
768 return VERR_DBGF_MEM_NOT_FOUND;
769 GCPtr += Adj;
770 cbRange -= Adj;
771 }
772
773 /*
774 * Search the memory - ignore MMIO, zero and not-present pages.
775 */
776 const bool fAllZero = ASMMemIsAll8(pabNeedle, cbNeedle, 0) == NULL;
777 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
778 RTGCPTR GCPtrMask = PGMMODE_IS_LONG_MODE(enmMode) ? UINT64_MAX : UINT32_MAX;
779 uint8_t abPrev[MAX_NEEDLE_SIZE];
780 size_t cbPrev = 0;
781 const uint32_t cIncPages = GCPtrAlign <= PAGE_SIZE
782 ? 1
783 : GCPtrAlign >> PAGE_SHIFT;
784 const RTGCPTR GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
785 ? (GCPtr + cbRange - 1) & GCPtrMask
786 : GCPtrMask;
787 RTGCPTR cPages = (((GCPtrLast - GCPtr) + (GCPtr & PAGE_OFFSET_MASK)) >> PAGE_SHIFT) + 1;
788 uint32_t offPage = GCPtr & PAGE_OFFSET_MASK;
789 GCPtr &= ~(RTGCPTR)PAGE_OFFSET_MASK;
790 for (;; offPage = 0)
791 {
792 RTGCPHYS GCPhys;
793 int rc = PGMPhysGCPtr2GCPhys(pVCpu, GCPtr, &GCPhys);
794 if (RT_SUCCESS(rc))
795 {
796 PPGMPAGE pPage = pgmPhysGetPage(pVM, GCPhys);
797 if ( pPage
798 && ( !PGM_PAGE_IS_ZERO(pPage)
799 || fAllZero)
800 && !PGM_PAGE_IS_BALLOONED(pPage)
801 && !PGM_PAGE_IS_MMIO(pPage))
802 {
803 void const *pvPage;
804 PGMPAGEMAPLOCK Lock;
805 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, &pvPage, &Lock);
806 if (RT_SUCCESS(rc))
807 {
808 int32_t offHit = offPage;
809 bool fRc;
810 if (GCPtrAlign < PAGE_SIZE)
811 {
812 uint32_t cbSearch = cPages > 0
813 ? PAGE_SIZE - (uint32_t)offPage
814 : (GCPtrLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
815 fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPtrAlign,
816 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
817 }
818 else
819 fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
820 && (GCPtrLast - GCPtr) >= cbNeedle;
821 PGMPhysReleasePageMappingLock(pVM, &Lock);
822 if (fRc)
823 {
824 *pGCPtrHit = GCPtr + offHit;
825 return VINF_SUCCESS;
826 }
827 }
828 else
829 cbPrev = 0; /* ignore error. */
830 }
831 else
832 cbPrev = 0;
833 }
834 else
835 cbPrev = 0; /* ignore error. */
836
837 /* advance to the next page. */
838 if (cPages <= cIncPages)
839 break;
840 cPages -= cIncPages;
841 GCPtr += (RTGCPTR)cIncPages << PAGE_SHIFT;
842 }
843 return VERR_DBGF_MEM_NOT_FOUND;
844}
845
846
847/**
848 * Initializes the dumper state.
849 *
850 * @param pState The state to initialize.
851 * @param pVM Pointer to the VM.
852 * @param fFlags The flags.
853 * @param u64FirstAddr The first address.
854 * @param u64LastAddr The last address.
855 * @param pHlp The output helpers.
856 */
857static void pgmR3DumpHierarchyInitState(PPGMR3DUMPHIERARCHYSTATE pState, PVM pVM, uint32_t fFlags,
858 uint64_t u64FirstAddr, uint64_t u64LastAddr, PCDBGFINFOHLP pHlp)
859{
860 pState->pVM = pVM;
861 pState->pHlp = pHlp ? pHlp : DBGFR3InfoLogHlp();
862 pState->fPse = !!(fFlags & (DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
863 pState->fPae = !!(fFlags & (DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
864 pState->fLme = !!(fFlags & DBGFPGDMP_FLAGS_LME);
865 pState->fNp = !!(fFlags & DBGFPGDMP_FLAGS_NP);
866 pState->fEpt = !!(fFlags & DBGFPGDMP_FLAGS_EPT);
867 pState->fNxe = !!(fFlags & DBGFPGDMP_FLAGS_NXE);
868 pState->cchAddress = pState->fLme ? 16 : 8;
869 pState->uLastRsvdBit = pState->fNxe ? 62 : 63;
870 pState->fDumpPageInfo = !!(fFlags & DBGFPGDMP_FLAGS_PAGE_INFO);
871 pState->fPrintHeader = !!(fFlags & DBGFPGDMP_FLAGS_HEADER);
872 pState->fPrintCr3 = !!(fFlags & DBGFPGDMP_FLAGS_PRINT_CR3);
873 pState->afReserved[0] = false;
874 pState->afReserved[1] = false;
875 pState->afReserved[2] = false;
876 pState->afReserved[3] = false;
877 pState->afReserved[4] = false;
878 pState->u64Address = u64FirstAddr;
879 pState->u64FirstAddress = u64FirstAddr;
880 pState->u64LastAddress = u64LastAddr;
881 pState->u64HighReservedBits = pState->uLastRsvdBit == 62 ? UINT64_C(0x7ff) << 52 : UINT64_C(0xfff) << 52;
882 pState->cLeaves = 0;
883}
884
885
886/**
887 * The simple way out, too tired to think of a more elegant solution.
888 *
889 * @returns The base address of this page table/directory/whatever.
890 * @param pState The state where we get the current address.
891 * @param cShift The shift count for the table entries.
892 * @param cEntries The number of table entries.
893 * @param piFirst Where to return the table index of the first
894 * entry to dump.
895 * @param piLast Where to return the table index of the last
896 * entry.
897 */
898static uint64_t pgmR3DumpHierarchyCalcRange(PPGMR3DUMPHIERARCHYSTATE pState, uint32_t cShift, uint32_t cEntries,
899 uint32_t *piFirst, uint32_t *piLast)
900{
901 const uint64_t iBase = (pState->u64Address >> cShift) & ~(uint64_t)(cEntries - 1);
902 const uint64_t iFirst = pState->u64FirstAddress >> cShift;
903 const uint64_t iLast = pState->u64LastAddress >> cShift;
904
905 if ( iBase >= iFirst
906 && iBase + cEntries - 1 <= iLast)
907 {
908 /* full range. */
909 *piFirst = 0;
910 *piLast = cEntries - 1;
911 }
912 else if ( iBase + cEntries - 1 < iFirst
913 || iBase > iLast)
914 {
915 /* no match */
916 *piFirst = cEntries;
917 *piLast = 0;
918 }
919 else
920 {
921 /* partial overlap */
922 *piFirst = iBase <= iFirst
923 ? iFirst - iBase
924 : 0;
925 *piLast = iBase + cEntries - 1 <= iLast
926 ? cEntries - 1
927 : iLast - iBase;
928 }
929
930 return iBase << cShift;
931}
932
933
934/**
935 * Maps/finds the shadow page.
936 *
937 * @returns VBox status code.
938 * @param pState The dumper state.
939 * @param HCPhys The physical address of the shadow page.
940 * @param pszDesc The description.
941 * @param fIsMapping Set if it's a mapping.
942 * @param ppv Where to return the pointer.
943 */
944static int pgmR3DumpHierarchyShwMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, const char *pszDesc,
945 bool fIsMapping, void const **ppv)
946{
947 void *pvPage;
948 if (!fIsMapping)
949 {
950 int rc = MMPagePhys2PageTry(pState->pVM, HCPhys, &pvPage);
951 if (RT_FAILURE(rc))
952 {
953 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! %s at HCPhys=%RHp was not found in the page pool!\n",
954 pState->cchAddress, pState->u64Address, pszDesc, HCPhys);
955 return rc;
956 }
957 }
958 else
959 {
960 pvPage = NULL;
961 for (PPGMMAPPING pMap = pState->pVM->pgm.s.pMappingsR3; pMap; pMap = pMap->pNextR3)
962 {
963 uint64_t off = pState->u64Address - pMap->GCPtr;
964 if (off < pMap->cb)
965 {
966 const int iPDE = (uint32_t)(off >> X86_PD_SHIFT);
967 const int iSub = (int)((off >> X86_PD_PAE_SHIFT) & 1); /* MSC is a pain sometimes */
968 if ((iSub ? pMap->aPTs[iPDE].HCPhysPaePT1 : pMap->aPTs[iPDE].HCPhysPaePT0) != HCPhys)
969 pState->pHlp->pfnPrintf(pState->pHlp,
970 "%0*llx error! Mapping error! PT %d has HCPhysPT=%RHp not %RHp is in the PD.\n",
971 pState->cchAddress, pState->u64Address, iPDE,
972 iSub ? pMap->aPTs[iPDE].HCPhysPaePT1 : pMap->aPTs[iPDE].HCPhysPaePT0, HCPhys);
973 pvPage = &pMap->aPTs[iPDE].paPaePTsR3[iSub];
974 break;
975 }
976 }
977 if (!pvPage)
978 {
979 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! PT mapping %s at HCPhys=%RHp was not found in the page pool!\n",
980 pState->cchAddress, pState->u64Address, HCPhys);
981 return VERR_INVALID_PARAMETER;
982 }
983 }
984 *ppv = pvPage;
985 return VINF_SUCCESS;
986}
987
988
989/**
990 * Dumps the a shadow page summary or smth.
991 *
992 * @param pState The dumper state.
993 * @param HCPhys The page address.
994 */
995static void pgmR3DumpHierarchyShwTablePageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
996{
997 pgmLock(pState->pVM);
998 char szPage[80];
999 PPGMPOOLPAGE pPage = pgmPoolQueryPageForDbg(pState->pVM->pgm.s.CTX_SUFF(pPool), HCPhys);
1000 if (pPage)
1001 RTStrPrintf(szPage, sizeof(szPage), " idx=0i%u", pPage->idx);
1002 else
1003 {
1004 /* probably a mapping */
1005 strcpy(szPage, " not found");
1006 for (PPGMMAPPING pMap = pState->pVM->pgm.s.pMappingsR3; pMap; pMap = pMap->pNextR3)
1007 {
1008 uint64_t off = pState->u64Address - pMap->GCPtr;
1009 if (off < pMap->cb)
1010 {
1011 const int iPDE = (uint32_t)(off >> X86_PD_SHIFT);
1012 if (pMap->aPTs[iPDE].HCPhysPT == HCPhys)
1013 RTStrPrintf(szPage, sizeof(szPage), " #%u: %s", iPDE, pMap->pszDesc);
1014 else if (pMap->aPTs[iPDE].HCPhysPaePT0 == HCPhys)
1015 RTStrPrintf(szPage, sizeof(szPage), " #%u/0: %s", iPDE, pMap->pszDesc);
1016 else if (pMap->aPTs[iPDE].HCPhysPaePT1 == HCPhys)
1017 RTStrPrintf(szPage, sizeof(szPage), " #%u/1: %s", iPDE, pMap->pszDesc);
1018 else
1019 continue;
1020 break;
1021 }
1022 }
1023 }
1024 pgmUnlock(pState->pVM);
1025 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
1026}
1027
1028
1029/**
1030 * Figures out which guest page this is and dumps a summary.
1031 *
1032 * @param pState The dumper state.
1033 * @param HCPhys The page address.
1034 * @param cbPage The page size.
1035 */
1036static void pgmR3DumpHierarchyShwGuestPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, uint32_t cbPage)
1037{
1038 char szPage[80];
1039 RTGCPHYS GCPhys;
1040 int rc = PGMR3DbgHCPhys2GCPhys(pState->pVM, HCPhys, &GCPhys);
1041 if (RT_SUCCESS(rc))
1042 {
1043 pgmLock(pState->pVM);
1044 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
1045 if (pPage)
1046 RTStrPrintf(szPage, sizeof(szPage), "%R[pgmpage]", pPage);
1047 else
1048 strcpy(szPage, "not found");
1049 pgmUnlock(pState->pVM);
1050 pState->pHlp->pfnPrintf(pState->pHlp, " -> %RGp %s", GCPhys, szPage);
1051 }
1052 else
1053 {
1054 /* check the heap */
1055 uint32_t cbAlloc;
1056 rc = MMR3HyperQueryInfoFromHCPhys(pState->pVM, HCPhys, szPage, sizeof(szPage), &cbAlloc);
1057 if (RT_SUCCESS(rc))
1058 pState->pHlp->pfnPrintf(pState->pHlp, " %s %#x bytes", szPage, cbAlloc);
1059 else
1060 pState->pHlp->pfnPrintf(pState->pHlp, " not found");
1061 }
1062 NOREF(cbPage);
1063}
1064
1065
1066/**
1067 * Dumps a PAE shadow page table.
1068 *
1069 * @returns VBox status code (VINF_SUCCESS).
1070 * @param pState The dumper state.
1071 * @param HCPhys The page table address.
1072 * @param fIsMapping Whether it is a mapping.
1073 */
1074static int pgmR3DumpHierarchyShwPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, bool fIsMapping)
1075{
1076 PCPGMSHWPTPAE pPT;
1077 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", fIsMapping, (void const **)&pPT);
1078 if (RT_FAILURE(rc))
1079 return rc;
1080
1081 uint32_t iFirst, iLast;
1082 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1083 for (uint32_t i = iFirst; i <= iLast; i++)
1084 if (PGMSHWPTEPAE_GET_U(pPT->a[i]) & X86_PTE_P)
1085 {
1086 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
1087 if (PGMSHWPTEPAE_IS_P(pPT->a[i]))
1088 {
1089 X86PTEPAE Pte;
1090 Pte.u = PGMSHWPTEPAE_GET_U(pPT->a[i]);
1091 pState->pHlp->pfnPrintf(pState->pHlp,
1092 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
1093 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
1094 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
1095 pState->u64Address,
1096 Pte.n.u1Write ? 'W' : 'R',
1097 Pte.n.u1User ? 'U' : 'S',
1098 Pte.n.u1Accessed ? 'A' : '-',
1099 Pte.n.u1Dirty ? 'D' : '-',
1100 Pte.n.u1Global ? 'G' : '-',
1101 Pte.n.u1WriteThru ? "WT" : "--",
1102 Pte.n.u1CacheDisable? "CD" : "--",
1103 Pte.n.u1PAT ? "AT" : "--",
1104 Pte.n.u1NoExecute ? "NX" : "--",
1105 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1106 Pte.u & RT_BIT(10) ? '1' : '0',
1107 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED? 'v' : '-',
1108 Pte.u & X86_PTE_PAE_PG_MASK);
1109 if (pState->fDumpPageInfo)
1110 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
1111 if ((Pte.u >> 52) & 0x7ff)
1112 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pte.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1113 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1114 }
1115 else if ( (PGMSHWPTEPAE_GET_U(pPT->a[i]) & (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1116 == (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1117 pState->pHlp->pfnPrintf(pState->pHlp,
1118 pState->fLme
1119 ? "%016llx 3 | invalid / MMIO optimization\n"
1120 : "%08llx 2 | invalid / MMIO optimization\n",
1121 pState->u64Address);
1122 else
1123 pState->pHlp->pfnPrintf(pState->pHlp,
1124 pState->fLme
1125 ? "%016llx 3 | invalid: %RX64\n"
1126 : "%08llx 2 | invalid: %RX64\n",
1127 pState->u64Address, PGMSHWPTEPAE_GET_U(pPT->a[i]));
1128 pState->cLeaves++;
1129 }
1130 return VINF_SUCCESS;
1131}
1132
1133
1134/**
1135 * Dumps a PAE shadow page directory table.
1136 *
1137 * @returns VBox status code (VINF_SUCCESS).
1138 * @param pState The dumper state.
1139 * @param HCPhys The physical address of the page directory table.
1140 * @param cMaxDepth The maximum depth.
1141 */
1142static int pgmR3DumpHierarchyShwPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1143{
1144 PCX86PDPAE pPD;
1145 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", false, (void const **)&pPD);
1146 if (RT_FAILURE(rc))
1147 return rc;
1148
1149 Assert(cMaxDepth > 0);
1150 cMaxDepth--;
1151
1152 uint32_t iFirst, iLast;
1153 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1154 for (uint32_t i = iFirst; i <= iLast; i++)
1155 {
1156 X86PDEPAE Pde = pPD->a[i];
1157 if (Pde.n.u1Present)
1158 {
1159 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
1160 if (Pde.b.u1Size)
1161 {
1162 pState->pHlp->pfnPrintf(pState->pHlp,
1163 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
1164 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
1165 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
1166 pState->u64Address,
1167 Pde.b.u1Write ? 'W' : 'R',
1168 Pde.b.u1User ? 'U' : 'S',
1169 Pde.b.u1Accessed ? 'A' : '-',
1170 Pde.b.u1Dirty ? 'D' : '-',
1171 Pde.b.u1Global ? 'G' : '-',
1172 Pde.b.u1WriteThru ? "WT" : "--",
1173 Pde.b.u1CacheDisable? "CD" : "--",
1174 Pde.b.u1PAT ? "AT" : "--",
1175 Pde.b.u1NoExecute ? "NX" : "--",
1176 Pde.u & RT_BIT_64(9) ? '1' : '0',
1177 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1178 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1179 Pde.u & X86_PDE2M_PAE_PG_MASK);
1180 if (pState->fDumpPageInfo)
1181 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
1182 if ((Pde.u >> 52) & 0x7ff)
1183 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pde.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1184 if ((Pde.u >> 13) & 0xff)
1185 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
1186 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1187
1188 pState->cLeaves++;
1189 }
1190 else
1191 {
1192 pState->pHlp->pfnPrintf(pState->pHlp,
1193 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
1194 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
1195 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
1196 pState->u64Address,
1197 Pde.n.u1Write ? 'W' : 'R',
1198 Pde.n.u1User ? 'U' : 'S',
1199 Pde.n.u1Accessed ? 'A' : '-',
1200 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1201 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1202 Pde.n.u1WriteThru ? "WT" : "--",
1203 Pde.n.u1CacheDisable? "CD" : "--",
1204 Pde.n.u1NoExecute ? "NX" : "--",
1205 Pde.u & RT_BIT_64(9) ? '1' : '0',
1206 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1207 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1208 Pde.u & X86_PDE_PAE_PG_MASK);
1209 if (pState->fDumpPageInfo)
1210 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1211 if ((Pde.u >> 52) & 0x7ff)
1212 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pde.u >> 52) & 0x7ff);
1213 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1214
1215 if (cMaxDepth)
1216 {
1217 int rc2 = pgmR3DumpHierarchyShwPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK, !!(Pde.u & PGM_PDFLAGS_MAPPING));
1218 if (rc2 < rc && RT_SUCCESS(rc))
1219 rc = rc2;
1220 }
1221 else
1222 pState->cLeaves++;
1223 }
1224 }
1225 }
1226 return rc;
1227}
1228
1229
1230/**
1231 * Dumps a PAE shadow page directory pointer table.
1232 *
1233 * @returns VBox status code (VINF_SUCCESS).
1234 * @param pState The dumper state.
1235 * @param HCPhys The physical address of the page directory pointer table.
1236 * @param cMaxDepth The maximum depth.
1237 */
1238static int pgmR3DumpHierarchyShwPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1239{
1240 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
1241 if (!pState->fLme && pState->u64Address >= _4G)
1242 return VINF_SUCCESS;
1243
1244 PCX86PDPT pPDPT;
1245 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory pointer table", false, (void const **)&pPDPT);
1246 if (RT_FAILURE(rc))
1247 return rc;
1248
1249 Assert(cMaxDepth > 0);
1250 cMaxDepth--;
1251
1252 uint32_t iFirst, iLast;
1253 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
1254 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
1255 &iFirst, &iLast);
1256 for (uint32_t i = iFirst; i <= iLast; i++)
1257 {
1258 X86PDPE Pdpe = pPDPT->a[i];
1259 if (Pdpe.n.u1Present)
1260 {
1261 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
1262 if (pState->fLme)
1263 {
1264 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
1265 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1266 pState->u64Address,
1267 Pdpe.lm.u1Write ? 'W' : 'R',
1268 Pdpe.lm.u1User ? 'U' : 'S',
1269 Pdpe.lm.u1Accessed ? 'A' : '-',
1270 Pdpe.lm.u3Reserved & 1? '?' : '.', /* ignored */
1271 Pdpe.lm.u3Reserved & 4? '!' : '.', /* mbz */
1272 Pdpe.lm.u1WriteThru ? "WT" : "--",
1273 Pdpe.lm.u1CacheDisable? "CD" : "--",
1274 Pdpe.lm.u3Reserved & 2? "!" : "..",/* mbz */
1275 Pdpe.lm.u1NoExecute ? "NX" : "--",
1276 Pdpe.u & RT_BIT(9) ? '1' : '0',
1277 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1278 Pdpe.u & RT_BIT(11) ? '1' : '0',
1279 Pdpe.u & X86_PDPE_PG_MASK);
1280 if (pState->fDumpPageInfo)
1281 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1282 if ((Pdpe.u >> 52) & 0x7ff)
1283 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx", (Pdpe.u >> 52) & 0x7ff);
1284 }
1285 else
1286 {
1287 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
1288 "%08llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1289 pState->u64Address,
1290 Pdpe.n.u2Reserved & 1? '!' : '.', /* mbz */
1291 Pdpe.n.u2Reserved & 2? '!' : '.', /* mbz */
1292 Pdpe.n.u4Reserved & 1? '!' : '.', /* mbz */
1293 Pdpe.n.u4Reserved & 2? '!' : '.', /* mbz */
1294 Pdpe.n.u4Reserved & 8? '!' : '.', /* mbz */
1295 Pdpe.n.u1WriteThru ? "WT" : "--",
1296 Pdpe.n.u1CacheDisable? "CD" : "--",
1297 Pdpe.n.u4Reserved & 2? "!" : "..",/* mbz */
1298 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
1299 Pdpe.u & RT_BIT(9) ? '1' : '0',
1300 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1301 Pdpe.u & RT_BIT(11) ? '1' : '0',
1302 Pdpe.u & X86_PDPE_PG_MASK);
1303 if (pState->fDumpPageInfo)
1304 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1305 if ((Pdpe.u >> 52) & 0xfff)
1306 pState->pHlp->pfnPrintf(pState->pHlp, " 63:52=%03llx!", (Pdpe.u >> 52) & 0xfff);
1307 }
1308 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1309
1310 if (cMaxDepth)
1311 {
1312 int rc2 = pgmR3DumpHierarchyShwPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
1313 if (rc2 < rc && RT_SUCCESS(rc))
1314 rc = rc2;
1315 }
1316 else
1317 pState->cLeaves++;
1318 }
1319 }
1320 return rc;
1321}
1322
1323
1324/**
1325 * Dumps a 32-bit shadow page table.
1326 *
1327 * @returns VBox status code (VINF_SUCCESS).
1328 * @param pVM Pointer to the VM.
1329 * @param HCPhys The physical address of the table.
1330 * @param cMaxDepth The maximum depth.
1331 */
1332static int pgmR3DumpHierarchyShwPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1333{
1334 PCX86PML4 pPML4;
1335 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page map level 4", false, (void const **)&pPML4);
1336 if (RT_FAILURE(rc))
1337 return rc;
1338
1339 Assert(cMaxDepth);
1340 cMaxDepth--;
1341
1342 /*
1343 * This is a bit tricky as we're working on unsigned addresses while the
1344 * AMD64 spec uses signed tricks.
1345 */
1346 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1347 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1348 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
1349 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
1350 { /* Simple, nothing to adjust */ }
1351 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
1352 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
1353 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
1354 iFirst = X86_PG_AMD64_ENTRIES / 2;
1355 else
1356 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
1357
1358 for (uint32_t i = iFirst; i <= iLast; i++)
1359 {
1360 X86PML4E Pml4e = pPML4->a[i];
1361 if (Pml4e.n.u1Present)
1362 {
1363 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
1364 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
1365 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
1366 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1367 pState->u64Address,
1368 Pml4e.n.u1Write ? 'W' : 'R',
1369 Pml4e.n.u1User ? 'U' : 'S',
1370 Pml4e.n.u1Accessed ? 'A' : '-',
1371 Pml4e.n.u3Reserved & 1? '?' : '.', /* ignored */
1372 Pml4e.n.u3Reserved & 4? '!' : '.', /* mbz */
1373 Pml4e.n.u1WriteThru ? "WT" : "--",
1374 Pml4e.n.u1CacheDisable? "CD" : "--",
1375 Pml4e.n.u3Reserved & 2? "!" : "..",/* mbz */
1376 Pml4e.n.u1NoExecute ? "NX" : "--",
1377 Pml4e.u & RT_BIT(9) ? '1' : '0',
1378 Pml4e.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1379 Pml4e.u & RT_BIT(11) ? '1' : '0',
1380 Pml4e.u & X86_PML4E_PG_MASK);
1381 if (pState->fDumpPageInfo)
1382 pgmR3DumpHierarchyShwTablePageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK);
1383 if ((Pml4e.u >> 52) & 0x7ff)
1384 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pml4e.u >> 52) & 0x7ff);
1385 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1386
1387 if (cMaxDepth)
1388 {
1389 int rc2 = pgmR3DumpHierarchyShwPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
1390 if (rc2 < rc && RT_SUCCESS(rc))
1391 rc = rc2;
1392 }
1393 else
1394 pState->cLeaves++;
1395 }
1396 }
1397 return rc;
1398}
1399
1400
1401/**
1402 * Dumps a 32-bit shadow page table.
1403 *
1404 * @returns VBox status code (VINF_SUCCESS).
1405 * @param pVM Pointer to the VM.
1406 * @param pPT Pointer to the page table.
1407 * @param fMapping Set if it's a guest mapping.
1408 */
1409static int pgmR3DumpHierarchyShw32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, bool fMapping)
1410{
1411 PCX86PT pPT;
1412 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", fMapping, (void const **)&pPT);
1413 if (RT_FAILURE(rc))
1414 return rc;
1415
1416 uint32_t iFirst, iLast;
1417 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
1418 for (uint32_t i = iFirst; i <= iLast; i++)
1419 {
1420 X86PTE Pte = pPT->a[i];
1421 if (Pte.n.u1Present)
1422 {
1423 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
1424 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
1425 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
1426 pState->u64Address,
1427 Pte.n.u1Write ? 'W' : 'R',
1428 Pte.n.u1User ? 'U' : 'S',
1429 Pte.n.u1Accessed ? 'A' : '-',
1430 Pte.n.u1Dirty ? 'D' : '-',
1431 Pte.n.u1Global ? 'G' : '-',
1432 Pte.n.u1WriteThru ? "WT" : "--",
1433 Pte.n.u1CacheDisable? "CD" : "--",
1434 Pte.n.u1PAT ? "AT" : "--",
1435 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1436 Pte.u & RT_BIT(10) ? '1' : '0',
1437 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED ? 'v' : '-',
1438 Pte.u & X86_PDE_PG_MASK);
1439 if (pState->fDumpPageInfo)
1440 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
1441 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1442 }
1443 }
1444 return VINF_SUCCESS;
1445}
1446
1447
1448/**
1449 * Dumps a 32-bit shadow page directory and page tables.
1450 *
1451 * @returns VBox status code (VINF_SUCCESS).
1452 * @param pState The dumper state.
1453 * @param HCPhys The physical address of the table.
1454 * @param cMaxDepth The maximum depth.
1455 */
1456static int pgmR3DumpHierarchyShw32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1457{
1458 if (pState->u64Address >= _4G)
1459 return VINF_SUCCESS;
1460
1461 PCX86PD pPD;
1462 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", false, (void const **)&pPD);
1463 if (RT_FAILURE(rc))
1464 return rc;
1465
1466 Assert(cMaxDepth > 0);
1467 cMaxDepth--;
1468
1469 uint32_t iFirst, iLast;
1470 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
1471 for (uint32_t i = iFirst; i <= iLast; i++)
1472 {
1473 X86PDE Pde = pPD->a[i];
1474 if (Pde.n.u1Present)
1475 {
1476 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
1477 if (Pde.b.u1Size && pState->fPse)
1478 {
1479 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
1480 | (Pde.u & X86_PDE4M_PG_MASK);
1481 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
1482 "%08llx 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
1483 pState->u64Address,
1484 Pde.b.u1Write ? 'W' : 'R',
1485 Pde.b.u1User ? 'U' : 'S',
1486 Pde.b.u1Accessed ? 'A' : '-',
1487 Pde.b.u1Dirty ? 'D' : '-',
1488 Pde.b.u1Global ? 'G' : '-',
1489 Pde.b.u1WriteThru ? "WT" : "--",
1490 Pde.b.u1CacheDisable? "CD" : "--",
1491 Pde.b.u1PAT ? "AT" : "--",
1492 Pde.u & RT_BIT_32(9) ? '1' : '0',
1493 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1494 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1495 u64Phys);
1496 if (pState->fDumpPageInfo)
1497 pgmR3DumpHierarchyShwGuestPageInfo(pState, u64Phys, _4M);
1498 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1499 pState->cLeaves++;
1500 }
1501 else
1502 {
1503 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
1504 "%08llx 0 | P %c %c %c %c %c %s %s .. .. 4K %c%c%c %08x",
1505 pState->u64Address,
1506 Pde.n.u1Write ? 'W' : 'R',
1507 Pde.n.u1User ? 'U' : 'S',
1508 Pde.n.u1Accessed ? 'A' : '-',
1509 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1510 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1511 Pde.n.u1WriteThru ? "WT" : "--",
1512 Pde.n.u1CacheDisable? "CD" : "--",
1513 Pde.u & RT_BIT_32(9) ? '1' : '0',
1514 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1515 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1516 Pde.u & X86_PDE_PG_MASK);
1517 if (pState->fDumpPageInfo)
1518 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PG_MASK);
1519 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1520
1521 if (cMaxDepth)
1522 {
1523 int rc2 = pgmR3DumpHierarchyShw32BitPT(pState, Pde.u & X86_PDE_PG_MASK, !!(Pde.u & PGM_PDFLAGS_MAPPING));
1524 if (rc2 < rc && RT_SUCCESS(rc))
1525 rc = rc2;
1526 }
1527 else
1528 pState->cLeaves++;
1529 }
1530 }
1531 }
1532
1533 return rc;
1534}
1535
1536
1537/**
1538 * Internal worker that initiates the actual dump.
1539 *
1540 * @returns VBox status code.
1541 * @param pState The dumper state.
1542 * @param cr3 The CR3 value.
1543 * @param cMaxDepth The max depth.
1544 */
1545static int pgmR3DumpHierarchyShwDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
1546{
1547 int rc;
1548 unsigned const cch = pState->cchAddress;
1549 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK
1550 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
1551 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
1552 : X86_CR3_PAGE_MASK;
1553 if (pState->fPrintCr3)
1554 {
1555 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
1556 : pState->fLme ? "Long Mode"
1557 : pState->fPae ? "PAE Mode"
1558 : pState->fPse ? "32-bit w/ PSE"
1559 : "32-bit";
1560 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
1561 if (pState->fDumpPageInfo)
1562 pgmR3DumpHierarchyShwTablePageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK);
1563 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
1564 pszMode,
1565 pState->fNp ? " + Nested Paging" : "",
1566 pState->fNxe ? " + NX" : "");
1567 }
1568
1569
1570 if (pState->fEpt)
1571 {
1572 if (pState->fPrintHeader)
1573 pState->pHlp->pfnPrintf(pState->pHlp,
1574 "%-*s R - Readable\n"
1575 "%-*s | W - Writeable\n"
1576 "%-*s | | X - Executable\n"
1577 "%-*s | | | EMT - EPT memory type\n"
1578 "%-*s | | | | PAT - Ignored PAT?\n"
1579 "%-*s | | | | | AVL1 - 4 available bits\n"
1580 "%-*s | | | | | | AVL2 - 12 available bits\n"
1581 "%-*s Level | | | | | | | page \n"
1582 /* xxxx n **** R W X EMT PAT AVL1 AVL2 xxxxxxxxxxxxx
1583 R W X 7 0 f fff 0123456701234567 */
1584 ,
1585 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
1586
1587 pState->pHlp->pfnPrintf(pState->pHlp, "EPT dumping is not yet implemented, sorry.\n");
1588 /** @todo implemented EPT dumping. */
1589 rc = VERR_NOT_IMPLEMENTED;
1590 }
1591 else
1592 {
1593 if (pState->fPrintHeader)
1594 pState->pHlp->pfnPrintf(pState->pHlp,
1595 "%-*s P - Present\n"
1596 "%-*s | R/W - Read (0) / Write (1)\n"
1597 "%-*s | | U/S - User (1) / Supervisor (0)\n"
1598 "%-*s | | | A - Accessed\n"
1599 "%-*s | | | | D - Dirty\n"
1600 "%-*s | | | | | G - Global\n"
1601 "%-*s | | | | | | WT - Write thru\n"
1602 "%-*s | | | | | | | CD - Cache disable\n"
1603 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
1604 "%-*s | | | | | | | | | NX - No execute (K8)\n"
1605 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
1606 "%-*s | | | | | | | | | | | AVL - a=allocated; m=mapping; d=track dirty;\n"
1607 "%-*s | | | | | | | | | | | | p=permanent; v=validated;\n"
1608 "%-*s Level | | | | | | | | | | | | Page\n"
1609 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
1610 - W U - - - -- -- -- -- -- 010 */
1611 ,
1612 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
1613 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
1614 if (pState->fLme)
1615 rc = pgmR3DumpHierarchyShwPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
1616 else if (pState->fPae)
1617 rc = pgmR3DumpHierarchyShwPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
1618 else
1619 rc = pgmR3DumpHierarchyShw32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
1620 }
1621
1622 if (!pState->cLeaves)
1623 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
1624 return rc;
1625}
1626
1627
1628/**
1629 * dbgfR3PagingDumpEx worker.
1630 *
1631 * @returns VBox status code.
1632 * @param pVM Pointer to the VM.
1633 * @param cr3 The CR3 register value.
1634 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
1635 * @param u64FirstAddr The start address.
1636 * @param u64LastAddr The address to stop after.
1637 * @param cMaxDepth The max depth.
1638 * @param pHlp The output callbacks. Defaults to log if NULL.
1639 *
1640 * @internal
1641 */
1642VMMR3_INT_DECL(int) PGMR3DumpHierarchyShw(PVM pVM, uint64_t cr3, uint32_t fFlags, uint64_t u64FirstAddr, uint64_t u64LastAddr,
1643 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
1644{
1645 /* Minimal validation as we're only supposed to service DBGF. */
1646 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1647 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
1648 AssertReturn(fFlags & DBGFPGDMP_FLAGS_SHADOW, VERR_INVALID_PARAMETER);
1649
1650 PGMR3DUMPHIERARCHYSTATE State;
1651 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, u64FirstAddr, u64LastAddr, pHlp);
1652 return pgmR3DumpHierarchyShwDoIt(&State, cr3, cMaxDepth);
1653}
1654
1655
1656/**
1657 * Dumps a page table hierarchy use only physical addresses and cr4/lm flags.
1658 *
1659 * @returns VBox status code (VINF_SUCCESS).
1660 * @param pVM Pointer to the VM.
1661 * @param cr3 The root of the hierarchy.
1662 * @param cr4 The cr4, only PAE and PSE is currently used.
1663 * @param fLongMode Set if long mode, false if not long mode.
1664 * @param cMaxDepth Number of levels to dump.
1665 * @param pHlp Pointer to the output functions.
1666 *
1667 * @deprecated Use DBGFR3PagingDumpEx.
1668 */
1669VMMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint64_t cr3, uint64_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
1670{
1671 if (!cMaxDepth)
1672 return VINF_SUCCESS;
1673
1674 PVMCPU pVCpu = VMMGetCpu(pVM);
1675 if (!pVCpu)
1676 pVCpu = &pVM->aCpus[0];
1677
1678 uint32_t fFlags = DBGFPGDMP_FLAGS_HEADER | DBGFPGDMP_FLAGS_PRINT_CR3 | DBGFPGDMP_FLAGS_PAGE_INFO | DBGFPGDMP_FLAGS_SHADOW;
1679 fFlags |= cr4 & (X86_CR4_PAE | X86_CR4_PSE);
1680 if (fLongMode)
1681 fFlags |= DBGFPGDMP_FLAGS_LME;
1682
1683 return DBGFR3PagingDumpEx(pVM, pVCpu->idCpu, fFlags, cr3, 0, fLongMode ? UINT64_MAX : UINT32_MAX, cMaxDepth, pHlp);
1684}
1685
1686
1687/**
1688 * Maps the guest page.
1689 *
1690 * @returns VBox status code.
1691 * @param pState The dumper state.
1692 * @param GCPhys The physical address of the guest page.
1693 * @param pszDesc The description.
1694 * @param ppv Where to return the pointer.
1695 * @param pLock Where to return the mapping lock. Hand this to
1696 * PGMPhysReleasePageMappingLock when done.
1697 */
1698static int pgmR3DumpHierarchyGstMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, const char *pszDesc,
1699 void const **ppv, PPGMPAGEMAPLOCK pLock)
1700{
1701 int rc = PGMPhysGCPhys2CCPtrReadOnly(pState->pVM, GCPhys, ppv, pLock);
1702 if (RT_FAILURE(rc))
1703 {
1704 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! Failed to map %s at GCPhys=%RGp: %Rrc!\n",
1705 pState->cchAddress, pState->u64Address, pszDesc, GCPhys, rc);
1706 return rc;
1707 }
1708 return VINF_SUCCESS;
1709}
1710
1711
1712/**
1713 * Figures out which guest page this is and dumps a summary.
1714 *
1715 * @param pState The dumper state.
1716 * @param GCPhys The page address.
1717 * @param cbPage The page size.
1718 */
1719static void pgmR3DumpHierarchyGstPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, uint32_t cbPage)
1720{
1721 char szPage[80];
1722 pgmLock(pState->pVM);
1723 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
1724 if (pPage)
1725 RTStrPrintf(szPage, sizeof(szPage), " %R[pgmpage]", pPage);
1726 else
1727 strcpy(szPage, " not found");
1728 pgmUnlock(pState->pVM);
1729 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
1730 NOREF(cbPage);
1731}
1732
1733
1734/**
1735 * Checks the entry for reserved bits.
1736 *
1737 * @param pState The dumper state.
1738 * @param u64Entry The entry to check.
1739 */
1740static void pgmR3DumpHierarchyGstCheckReservedHighBits(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t u64Entry)
1741{
1742 uint32_t uRsvd = (u64Entry & pState->u64HighReservedBits) >> 52;
1743 if (uRsvd)
1744 pState->pHlp->pfnPrintf(pState->pHlp, " %u:52=%03x%s",
1745 pState->uLastRsvdBit, uRsvd, pState->fLme ? "" : "!");
1746 /** @todo check the valid physical bits as well. */
1747}
1748
1749
1750/**
1751 * Dumps a PAE shadow page table.
1752 *
1753 * @returns VBox status code (VINF_SUCCESS).
1754 * @param pState The dumper state.
1755 * @param GCPhys The page table address.
1756 */
1757static int pgmR3DumpHierarchyGstPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys)
1758{
1759 PCX86PTPAE pPT;
1760 PGMPAGEMAPLOCK Lock;
1761 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
1762 if (RT_FAILURE(rc))
1763 return rc;
1764
1765 uint32_t iFirst, iLast;
1766 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1767 for (uint32_t i = iFirst; i <= iLast; i++)
1768 {
1769 X86PTEPAE Pte = pPT->a[i];
1770 if (Pte.n.u1Present)
1771 {
1772 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
1773 pState->pHlp->pfnPrintf(pState->pHlp,
1774 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
1775 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
1776 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
1777 pState->u64Address,
1778 Pte.n.u1Write ? 'W' : 'R',
1779 Pte.n.u1User ? 'U' : 'S',
1780 Pte.n.u1Accessed ? 'A' : '-',
1781 Pte.n.u1Dirty ? 'D' : '-',
1782 Pte.n.u1Global ? 'G' : '-',
1783 Pte.n.u1WriteThru ? "WT" : "--",
1784 Pte.n.u1CacheDisable? "CD" : "--",
1785 Pte.n.u1PAT ? "AT" : "--",
1786 Pte.n.u1NoExecute ? "NX" : "--",
1787 Pte.u & RT_BIT(9) ? '1' : '0',
1788 Pte.u & RT_BIT(10) ? '1' : '0',
1789 Pte.u & RT_BIT(11) ? '1' : '0',
1790 Pte.u & X86_PTE_PAE_PG_MASK);
1791 if (pState->fDumpPageInfo)
1792 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
1793 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pte.u);
1794 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1795 pState->cLeaves++;
1796 }
1797 }
1798
1799 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
1800 return VINF_SUCCESS;
1801}
1802
1803
1804/**
1805 * Dumps a PAE shadow page directory table.
1806 *
1807 * @returns VBox status code (VINF_SUCCESS).
1808 * @param pState The dumper state.
1809 * @param GCPhys The physical address of the table.
1810 * @param cMaxDepth The maximum depth.
1811 */
1812static int pgmR3DumpHierarchyGstPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
1813{
1814 PCX86PDPAE pPD;
1815 PGMPAGEMAPLOCK Lock;
1816 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
1817 if (RT_FAILURE(rc))
1818 return rc;
1819
1820 Assert(cMaxDepth > 0);
1821 cMaxDepth--;
1822
1823 uint32_t iFirst, iLast;
1824 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1825 for (uint32_t i = iFirst; i <= iLast; i++)
1826 {
1827 X86PDEPAE Pde = pPD->a[i];
1828 if (Pde.n.u1Present)
1829 {
1830 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
1831 if (Pde.b.u1Size)
1832 {
1833 pState->pHlp->pfnPrintf(pState->pHlp,
1834 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
1835 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
1836 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
1837 pState->u64Address,
1838 Pde.b.u1Write ? 'W' : 'R',
1839 Pde.b.u1User ? 'U' : 'S',
1840 Pde.b.u1Accessed ? 'A' : '-',
1841 Pde.b.u1Dirty ? 'D' : '-',
1842 Pde.b.u1Global ? 'G' : '-',
1843 Pde.b.u1WriteThru ? "WT" : "--",
1844 Pde.b.u1CacheDisable ? "CD" : "--",
1845 Pde.b.u1PAT ? "AT" : "--",
1846 Pde.b.u1NoExecute ? "NX" : "--",
1847 Pde.u & RT_BIT_64(9) ? '1' : '0',
1848 Pde.u & RT_BIT_64(10) ? '1' : '0',
1849 Pde.u & RT_BIT_64(11) ? '1' : '0',
1850 Pde.u & X86_PDE2M_PAE_PG_MASK);
1851 if (pState->fDumpPageInfo)
1852 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
1853 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
1854 if ((Pde.u >> 13) & 0xff)
1855 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
1856 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1857
1858 pState->cLeaves++;
1859 }
1860 else
1861 {
1862 pState->pHlp->pfnPrintf(pState->pHlp,
1863 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
1864 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
1865 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
1866 pState->u64Address,
1867 Pde.n.u1Write ? 'W' : 'R',
1868 Pde.n.u1User ? 'U' : 'S',
1869 Pde.n.u1Accessed ? 'A' : '-',
1870 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1871 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1872 Pde.n.u1WriteThru ? "WT" : "--",
1873 Pde.n.u1CacheDisable ? "CD" : "--",
1874 Pde.n.u1NoExecute ? "NX" : "--",
1875 Pde.u & RT_BIT_64(9) ? '1' : '0',
1876 Pde.u & RT_BIT_64(10) ? '1' : '0',
1877 Pde.u & RT_BIT_64(11) ? '1' : '0',
1878 Pde.u & X86_PDE_PAE_PG_MASK);
1879 if (pState->fDumpPageInfo)
1880 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK, _4K);
1881 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
1882 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1883
1884 if (cMaxDepth)
1885 {
1886 int rc2 = pgmR3DumpHierarchyGstPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1887 if (rc2 < rc && RT_SUCCESS(rc))
1888 rc = rc2;
1889 }
1890 else
1891 pState->cLeaves++;
1892 }
1893 }
1894 }
1895
1896 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
1897 return rc;
1898}
1899
1900
1901/**
1902 * Dumps a PAE shadow page directory pointer table.
1903 *
1904 * @returns VBox status code (VINF_SUCCESS).
1905 * @param pState The dumper state.
1906 * @param GCPhys The physical address of the table.
1907 * @param cMaxDepth The maximum depth.
1908 */
1909static int pgmR3DumpHierarchyGstPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
1910{
1911 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
1912 if (!pState->fLme && pState->u64Address >= _4G)
1913 return VINF_SUCCESS;
1914
1915 PCX86PDPT pPDPT;
1916 PGMPAGEMAPLOCK Lock;
1917 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory pointer table", (void const **)&pPDPT, &Lock);
1918 if (RT_FAILURE(rc))
1919 return rc;
1920
1921 Assert(cMaxDepth > 0);
1922 cMaxDepth--;
1923
1924 uint32_t iFirst, iLast;
1925 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
1926 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
1927 &iFirst, &iLast);
1928 for (uint32_t i = iFirst; i <= iLast; i++)
1929 {
1930 X86PDPE Pdpe = pPDPT->a[i];
1931 if (Pdpe.n.u1Present)
1932 {
1933 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
1934 if (pState->fLme)
1935 {
1936 /** @todo Do 1G pages. */
1937 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
1938 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1939 pState->u64Address,
1940 Pdpe.lm.u1Write ? 'W' : 'R',
1941 Pdpe.lm.u1User ? 'U' : 'S',
1942 Pdpe.lm.u1Accessed ? 'A' : '-',
1943 Pdpe.lm.u3Reserved & 1 ? '?' : '.', /* ignored */
1944 Pdpe.lm.u3Reserved & 4 ? '!' : '.', /* mbz */
1945 Pdpe.lm.u1WriteThru ? "WT" : "--",
1946 Pdpe.lm.u1CacheDisable ? "CD" : "--",
1947 Pdpe.lm.u3Reserved & 2 ? "!" : "..",/* mbz */
1948 Pdpe.lm.u1NoExecute ? "NX" : "--",
1949 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
1950 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
1951 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
1952 Pdpe.u & X86_PDPE_PG_MASK);
1953 if (pState->fDumpPageInfo)
1954 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
1955 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
1956 }
1957 else
1958 {
1959 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
1960 "%08llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1961 pState->u64Address,
1962 Pdpe.n.u2Reserved & 1 ? '!' : '.', /* mbz */
1963 Pdpe.n.u2Reserved & 2 ? '!' : '.', /* mbz */
1964 Pdpe.n.u4Reserved & 1 ? '!' : '.', /* mbz */
1965 Pdpe.n.u4Reserved & 2 ? '!' : '.', /* mbz */
1966 Pdpe.n.u4Reserved & 8 ? '!' : '.', /* mbz */
1967 Pdpe.n.u1WriteThru ? "WT" : "--",
1968 Pdpe.n.u1CacheDisable ? "CD" : "--",
1969 Pdpe.n.u4Reserved & 2 ? "!" : "..", /* mbz */
1970 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
1971 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
1972 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
1973 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
1974 Pdpe.u & X86_PDPE_PG_MASK);
1975 if (pState->fDumpPageInfo)
1976 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
1977 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
1978 }
1979 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1980
1981 if (cMaxDepth)
1982 {
1983 int rc2 = pgmR3DumpHierarchyGstPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
1984 if (rc2 < rc && RT_SUCCESS(rc))
1985 rc = rc2;
1986 }
1987 else
1988 pState->cLeaves++;
1989 }
1990 }
1991
1992 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
1993 return rc;
1994}
1995
1996
1997/**
1998 * Dumps a 32-bit shadow page table.
1999 *
2000 * @returns VBox status code (VINF_SUCCESS).
2001 * @param pVM Pointer to the VM.
2002 * @param GCPhys The physical address of the table.
2003 * @param cMaxDepth The maximum depth.
2004 */
2005static int pgmR3DumpHierarchyGstPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2006{
2007 PCX86PML4 pPML4;
2008 PGMPAGEMAPLOCK Lock;
2009 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page map level 4", (void const **)&pPML4, &Lock);
2010 if (RT_FAILURE(rc))
2011 return rc;
2012
2013 Assert(cMaxDepth);
2014 cMaxDepth--;
2015
2016 /*
2017 * This is a bit tricky as we're working on unsigned addresses while the
2018 * AMD64 spec uses signed tricks.
2019 */
2020 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2021 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2022 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
2023 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
2024 { /* Simple, nothing to adjust */ }
2025 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
2026 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
2027 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
2028 iFirst = X86_PG_AMD64_ENTRIES / 2;
2029 else
2030 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
2031
2032 for (uint32_t i = iFirst; i <= iLast; i++)
2033 {
2034 X86PML4E Pml4e = pPML4->a[i];
2035 if (Pml4e.n.u1Present)
2036 {
2037 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
2038 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
2039 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
2040 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2041 pState->u64Address,
2042 Pml4e.n.u1Write ? 'W' : 'R',
2043 Pml4e.n.u1User ? 'U' : 'S',
2044 Pml4e.n.u1Accessed ? 'A' : '-',
2045 Pml4e.n.u3Reserved & 1 ? '?' : '.', /* ignored */
2046 Pml4e.n.u3Reserved & 4 ? '!' : '.', /* mbz */
2047 Pml4e.n.u1WriteThru ? "WT" : "--",
2048 Pml4e.n.u1CacheDisable ? "CD" : "--",
2049 Pml4e.n.u3Reserved & 2 ? "!" : "..",/* mbz */
2050 Pml4e.n.u1NoExecute ? "NX" : "--",
2051 Pml4e.u & RT_BIT_64(9) ? '1' : '0',
2052 Pml4e.u & RT_BIT_64(10) ? '1' : '0',
2053 Pml4e.u & RT_BIT_64(11) ? '1' : '0',
2054 Pml4e.u & X86_PML4E_PG_MASK);
2055 if (pState->fDumpPageInfo)
2056 pgmR3DumpHierarchyGstPageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK, _4K);
2057 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pml4e.u);
2058 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2059
2060 if (cMaxDepth)
2061 {
2062 int rc2 = pgmR3DumpHierarchyGstPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
2063 if (rc2 < rc && RT_SUCCESS(rc))
2064 rc = rc2;
2065 }
2066 else
2067 pState->cLeaves++;
2068 }
2069 }
2070
2071 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2072 return rc;
2073}
2074
2075
2076/**
2077 * Dumps a 32-bit shadow page table.
2078 *
2079 * @returns VBox status code (VINF_SUCCESS).
2080 * @param pState The dumper state.
2081 * @param GCPhys The physical address of the table.
2082 */
2083static int pgmR3DumpHierarchyGst32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys)
2084{
2085 PCX86PT pPT;
2086 PGMPAGEMAPLOCK Lock;
2087 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
2088 if (RT_FAILURE(rc))
2089 return rc;
2090
2091 uint32_t iFirst, iLast;
2092 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2093 for (uint32_t i = iFirst; i <= iLast; i++)
2094 {
2095 X86PTE Pte = pPT->a[i];
2096 if (Pte.n.u1Present)
2097 {
2098 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
2099 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
2100 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
2101 pState->u64Address,
2102 Pte.n.u1Write ? 'W' : 'R',
2103 Pte.n.u1User ? 'U' : 'S',
2104 Pte.n.u1Accessed ? 'A' : '-',
2105 Pte.n.u1Dirty ? 'D' : '-',
2106 Pte.n.u1Global ? 'G' : '-',
2107 Pte.n.u1WriteThru ? "WT" : "--",
2108 Pte.n.u1CacheDisable ? "CD" : "--",
2109 Pte.n.u1PAT ? "AT" : "--",
2110 Pte.u & RT_BIT_32(9) ? '1' : '0',
2111 Pte.u & RT_BIT_32(10) ? '1' : '0',
2112 Pte.u & RT_BIT_32(11) ? '1' : '0',
2113 Pte.u & X86_PDE_PG_MASK);
2114 if (pState->fDumpPageInfo)
2115 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
2116 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2117 }
2118 }
2119
2120 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2121 return VINF_SUCCESS;
2122}
2123
2124
2125/**
2126 * Dumps a 32-bit shadow page directory and page tables.
2127 *
2128 * @returns VBox status code (VINF_SUCCESS).
2129 * @param pState The dumper state.
2130 * @param GCPhys The physical address of the table.
2131 * @param cMaxDepth The maximum depth.
2132 */
2133static int pgmR3DumpHierarchyGst32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2134{
2135 if (pState->u64Address >= _4G)
2136 return VINF_SUCCESS;
2137
2138 PCX86PD pPD;
2139 PGMPAGEMAPLOCK Lock;
2140 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
2141 if (RT_FAILURE(rc))
2142 return rc;
2143
2144 Assert(cMaxDepth > 0);
2145 cMaxDepth--;
2146
2147 uint32_t iFirst, iLast;
2148 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2149 for (uint32_t i = iFirst; i <= iLast; i++)
2150 {
2151 X86PDE Pde = pPD->a[i];
2152 if (Pde.n.u1Present)
2153 {
2154 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
2155 if (Pde.b.u1Size && pState->fPse)
2156 {
2157 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
2158 | (Pde.u & X86_PDE4M_PG_MASK);
2159 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2160 "%08llx 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
2161 pState->u64Address,
2162 Pde.b.u1Write ? 'W' : 'R',
2163 Pde.b.u1User ? 'U' : 'S',
2164 Pde.b.u1Accessed ? 'A' : '-',
2165 Pde.b.u1Dirty ? 'D' : '-',
2166 Pde.b.u1Global ? 'G' : '-',
2167 Pde.b.u1WriteThru ? "WT" : "--",
2168 Pde.b.u1CacheDisable ? "CD" : "--",
2169 Pde.b.u1PAT ? "AT" : "--",
2170 Pde.u & RT_BIT_32(9) ? '1' : '0',
2171 Pde.u & RT_BIT_32(10) ? '1' : '0',
2172 Pde.u & RT_BIT_32(11) ? '1' : '0',
2173 u64Phys);
2174 if (pState->fDumpPageInfo)
2175 pgmR3DumpHierarchyGstPageInfo(pState, u64Phys, _4M);
2176 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2177 pState->cLeaves++;
2178 }
2179 else
2180 {
2181 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2182 "%08llx 0 | P %c %c %c %c %c %s %s .. .. .. %c%c%c %08x",
2183 pState->u64Address,
2184 Pde.n.u1Write ? 'W' : 'R',
2185 Pde.n.u1User ? 'U' : 'S',
2186 Pde.n.u1Accessed ? 'A' : '-',
2187 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2188 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2189 Pde.n.u1WriteThru ? "WT" : "--",
2190 Pde.n.u1CacheDisable ? "CD" : "--",
2191 Pde.u & RT_BIT_32(9) ? '1' : '0',
2192 Pde.u & RT_BIT_32(10) ? '1' : '0',
2193 Pde.u & RT_BIT_32(11) ? '1' : '0',
2194 Pde.u & X86_PDE_PG_MASK);
2195 if (pState->fDumpPageInfo)
2196 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PG_MASK, _4K);
2197 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2198
2199 if (cMaxDepth)
2200 {
2201 int rc2 = pgmR3DumpHierarchyGst32BitPT(pState, Pde.u & X86_PDE_PG_MASK);
2202 if (rc2 < rc && RT_SUCCESS(rc))
2203 rc = rc2;
2204 }
2205 else
2206 pState->cLeaves++;
2207 }
2208 }
2209 }
2210
2211 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2212 return rc;
2213}
2214
2215
2216/**
2217 * Internal worker that initiates the actual dump.
2218 *
2219 * @returns VBox status code.
2220 * @param pState The dumper state.
2221 * @param cr3 The CR3 value.
2222 * @param cMaxDepth The max depth.
2223 */
2224static int pgmR3DumpHierarchyGstDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
2225{
2226 int rc;
2227 unsigned const cch = pState->cchAddress;
2228 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK
2229 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
2230 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
2231 : X86_CR3_PAGE_MASK;
2232 if (pState->fPrintCr3)
2233 {
2234 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
2235 : pState->fLme ? "Long Mode"
2236 : pState->fPae ? "PAE Mode"
2237 : pState->fPse ? "32-bit w/ PSE"
2238 : "32-bit";
2239 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
2240 if (pState->fDumpPageInfo)
2241 pgmR3DumpHierarchyGstPageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK, _4K);
2242 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
2243 pszMode,
2244 pState->fNp ? " + Nested Paging" : "",
2245 pState->fNxe ? " + NX" : "");
2246 }
2247
2248
2249 if (pState->fEpt)
2250 {
2251 if (pState->fPrintHeader)
2252 pState->pHlp->pfnPrintf(pState->pHlp,
2253 "%-*s R - Readable\n"
2254 "%-*s | W - Writeable\n"
2255 "%-*s | | X - Executable\n"
2256 "%-*s | | | EMT - EPT memory type\n"
2257 "%-*s | | | | PAT - Ignored PAT?\n"
2258 "%-*s | | | | | AVL1 - 4 available bits\n"
2259 "%-*s | | | | | | AVL2 - 12 available bits\n"
2260 "%-*s Level | | | | | | | page \n"
2261 /* xxxx n **** R W X EMT PAT AVL1 AVL2 xxxxxxxxxxxxx
2262 R W X 7 0 f fff 0123456701234567 */
2263 ,
2264 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
2265
2266 pState->pHlp->pfnPrintf(pState->pHlp, "EPT dumping is not yet implemented, sorry.\n");
2267 /** @todo implemented EPT dumping. */
2268 rc = VERR_NOT_IMPLEMENTED;
2269 }
2270 else
2271 {
2272 if (pState->fPrintHeader)
2273 pState->pHlp->pfnPrintf(pState->pHlp,
2274 "%-*s P - Present\n"
2275 "%-*s | R/W - Read (0) / Write (1)\n"
2276 "%-*s | | U/S - User (1) / Supervisor (0)\n"
2277 "%-*s | | | A - Accessed\n"
2278 "%-*s | | | | D - Dirty\n"
2279 "%-*s | | | | | G - Global\n"
2280 "%-*s | | | | | | WT - Write thru\n"
2281 "%-*s | | | | | | | CD - Cache disable\n"
2282 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
2283 "%-*s | | | | | | | | | NX - No execute (K8)\n"
2284 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
2285 "%-*s | | | | | | | | | | | AVL - 3 available bits.\n"
2286 "%-*s Level | | | | | | | | | | | | Page\n"
2287 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
2288 - W U - - - -- -- -- -- -- 010 */
2289 ,
2290 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
2291 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
2292 if (pState->fLme)
2293 rc = pgmR3DumpHierarchyGstPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
2294 else if (pState->fPae)
2295 rc = pgmR3DumpHierarchyGstPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
2296 else
2297 rc = pgmR3DumpHierarchyGst32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
2298 }
2299
2300 if (!pState->cLeaves)
2301 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
2302 return rc;
2303}
2304
2305
2306/**
2307 * dbgfR3PagingDumpEx worker.
2308 *
2309 * @returns VBox status code.
2310 * @param pVM Pointer to the VM.
2311 * @param cr3 The CR3 register value.
2312 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
2313 * @param FirstAddr The start address.
2314 * @param LastAddr The address to stop after.
2315 * @param cMaxDepth The max depth.
2316 * @param pHlp The output callbacks. Defaults to log if NULL.
2317 *
2318 * @internal
2319 */
2320VMMR3_INT_DECL(int) PGMR3DumpHierarchyGst(PVM pVM, uint64_t cr3, uint32_t fFlags, RTGCPTR FirstAddr, RTGCPTR LastAddr,
2321 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
2322{
2323 /* Minimal validation as we're only supposed to service DBGF. */
2324 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2325 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
2326 AssertReturn(fFlags & DBGFPGDMP_FLAGS_GUEST, VERR_INVALID_PARAMETER);
2327
2328 PGMR3DUMPHIERARCHYSTATE State;
2329 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, FirstAddr, LastAddr, pHlp);
2330 return pgmR3DumpHierarchyGstDoIt(&State, cr3, cMaxDepth);
2331}
2332
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