VirtualBox

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

Last change on this file since 32767 was 32036, checked in by vboxsync, 14 years ago

Removed X86_PTE_PAE_PG_MASK, renamed X86_PTE_PAE_PG_MASK_FULL to X86_PTE_PAE_PG_MASK.

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