VirtualBox

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

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

PGMDbg.cpp: Don't try scan PGMPAGETYPE_MMIO2_ALIAS_MMIO pages.

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