VirtualBox

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

Last change on this file since 51574 was 47786, checked in by vboxsync, 11 years ago

PGM: Added a new page type for the VT-x APIC access page MMIO alias instead of abusing the MMIO2 aliasing. There are important differences, we can safely access the MMIO2 page when aliased and save time doing so, while the alias created by IOMMMIOMapMMIOHCPage must not be accessed outside the VT-x execution AFAIK.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 100.2 KB
Line 
1/* $Id: PGMDbg.cpp 47786 2013-08-16 08:59:32Z 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_OR_ALIAS(pPage)
664 && !PGM_PAGE_IS_BALLOONED(pPage))
665 {
666 void const *pvPage;
667 PGMPAGEMAPLOCK Lock;
668 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, &pvPage, &Lock);
669 if (RT_SUCCESS(rc))
670 {
671 int32_t offHit = offPage;
672 bool fRc;
673 if (GCPhysAlign < PAGE_SIZE)
674 {
675 uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)PAGE_OFFSET_MASK
676 ? PAGE_SIZE - (uint32_t)offPage
677 : (GCPhysLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
678 fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPhysAlign,
679 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
680 }
681 else
682 fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
683 && (GCPhysLast - GCPhys) >= cbNeedle;
684 PGMPhysReleasePageMappingLock(pVM, &Lock);
685 if (fRc)
686 {
687 *pGCPhysHit = GCPhys + offHit;
688 pgmUnlock(pVM);
689 return VINF_SUCCESS;
690 }
691 }
692 else
693 cbPrev = 0; /* ignore error. */
694 }
695 else
696 cbPrev = 0;
697
698 /* advance to the next page. */
699 GCPhys += (RTGCPHYS)cIncPages << PAGE_SHIFT;
700 if (GCPhys >= GCPhysLast) /* (may not always hit, but we're run out of ranges.) */
701 {
702 pgmUnlock(pVM);
703 return VERR_DBGF_MEM_NOT_FOUND;
704 }
705 iPage += cIncPages;
706 if ( iPage < cIncPages
707 || iPage >= cPages)
708 break;
709 }
710 }
711 }
712 pgmUnlock(pVM);
713 return VERR_DBGF_MEM_NOT_FOUND;
714}
715
716
717/**
718 * Scans (guest) virtual memory for a byte string.
719 *
720 * @returns VBox status codes:
721 * @retval VINF_SUCCESS and *pGCPtrHit on success.
722 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
723 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
724 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
725 *
726 * @param pVM Pointer to the VM.
727 * @param pVCpu The CPU context to search in.
728 * @param GCPtr Where to start searching.
729 * @param GCPtrAlign The alignment of the needle. Must be a power of two
730 * and less or equal to 4GB.
731 * @param cbRange The number of bytes to search. Max 256 bytes.
732 * @param pabNeedle The byte string to search for.
733 * @param cbNeedle The length of the byte string.
734 * @param pGCPtrHit Where to store the address of the first occurrence on success.
735 */
736VMMR3_INT_DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign,
737 const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
738{
739 VMCPU_ASSERT_EMT(pVCpu);
740
741 /*
742 * Validate and adjust the input a bit.
743 */
744 if (!VALID_PTR(pGCPtrHit))
745 return VERR_INVALID_POINTER;
746 *pGCPtrHit = 0;
747
748 if (!VALID_PTR(pabNeedle))
749 return VERR_INVALID_POINTER;
750 if (!cbNeedle)
751 return VERR_INVALID_PARAMETER;
752 if (cbNeedle > MAX_NEEDLE_SIZE)
753 return VERR_INVALID_PARAMETER;
754
755 if (!cbRange)
756 return VERR_DBGF_MEM_NOT_FOUND;
757 if (GCPtr + cbNeedle - 1 < GCPtr)
758 return VERR_DBGF_MEM_NOT_FOUND;
759
760 if (!GCPtrAlign)
761 return VERR_INVALID_PARAMETER;
762 if (GCPtrAlign > UINT32_MAX)
763 return VERR_NOT_POWER_OF_TWO;
764 if (GCPtrAlign & (GCPtrAlign - 1))
765 return VERR_INVALID_PARAMETER;
766
767 if (GCPtr & (GCPtrAlign - 1))
768 {
769 RTGCPTR Adj = GCPtrAlign - (GCPtr & (GCPtrAlign - 1));
770 if ( cbRange <= Adj
771 || GCPtr + Adj < GCPtr)
772 return VERR_DBGF_MEM_NOT_FOUND;
773 GCPtr += Adj;
774 cbRange -= Adj;
775 }
776
777 /* Only paged protected mode or long mode here, use the physical scan for
778 the other modes. */
779 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
780 AssertReturn(PGMMODE_WITH_PAGING(enmMode), VERR_PGM_NOT_USED_IN_MODE);
781
782 /*
783 * Search the memory - ignore MMIO, zero and not-present pages.
784 */
785 const bool fAllZero = ASMMemIsAll8(pabNeedle, cbNeedle, 0) == NULL;
786 RTGCPTR GCPtrMask = PGMMODE_IS_LONG_MODE(enmMode) ? UINT64_MAX : UINT32_MAX;
787 uint8_t abPrev[MAX_NEEDLE_SIZE];
788 size_t cbPrev = 0;
789 const uint32_t cIncPages = GCPtrAlign <= PAGE_SIZE
790 ? 1
791 : GCPtrAlign >> PAGE_SHIFT;
792 const RTGCPTR GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
793 ? (GCPtr + cbRange - 1) & GCPtrMask
794 : GCPtrMask;
795 RTGCPTR cPages = (((GCPtrLast - GCPtr) + (GCPtr & PAGE_OFFSET_MASK)) >> PAGE_SHIFT) + 1;
796 uint32_t offPage = GCPtr & PAGE_OFFSET_MASK;
797 GCPtr &= ~(RTGCPTR)PAGE_OFFSET_MASK;
798 for (;; offPage = 0)
799 {
800 PGMPTWALKGST Walk;
801 int rc = pgmGstPtWalk(pVCpu, GCPtr, &Walk);
802 if (RT_SUCCESS(rc) && Walk.u.Core.fSucceeded)
803 {
804 PPGMPAGE pPage = pgmPhysGetPage(pVM, Walk.u.Core.GCPhys);
805 if ( pPage
806 && ( !PGM_PAGE_IS_ZERO(pPage)
807 || fAllZero)
808 && !PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)
809 && !PGM_PAGE_IS_BALLOONED(pPage))
810 {
811 void const *pvPage;
812 PGMPAGEMAPLOCK Lock;
813 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, Walk.u.Core.GCPhys, &pvPage, &Lock);
814 if (RT_SUCCESS(rc))
815 {
816 int32_t offHit = offPage;
817 bool fRc;
818 if (GCPtrAlign < PAGE_SIZE)
819 {
820 uint32_t cbSearch = cPages > 0
821 ? PAGE_SIZE - (uint32_t)offPage
822 : (GCPtrLast & PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
823 fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPtrAlign,
824 pabNeedle, cbNeedle, &abPrev[0], &cbPrev);
825 }
826 else
827 fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
828 && (GCPtrLast - GCPtr) >= cbNeedle;
829 PGMPhysReleasePageMappingLock(pVM, &Lock);
830 if (fRc)
831 {
832 *pGCPtrHit = GCPtr + offHit;
833 return VINF_SUCCESS;
834 }
835 }
836 else
837 cbPrev = 0; /* ignore error. */
838 }
839 else
840 cbPrev = 0;
841 }
842 else
843 {
844 Assert(Walk.enmType != PGMPTWALKGSTTYPE_INVALID);
845 Assert(!Walk.u.Core.fSucceeded);
846 cbPrev = 0; /* ignore error. */
847
848 /*
849 * Try skip as much as possible. No need to figure out that a PDE
850 * is not present 512 times!
851 */
852 uint64_t cPagesCanSkip;
853 switch (Walk.u.Core.uLevel)
854 {
855 case 1:
856 /* page level, use cIncPages */
857 cPagesCanSkip = 1;
858 break;
859 case 2:
860 if (Walk.enmType == PGMPTWALKGSTTYPE_32BIT)
861 {
862 cPagesCanSkip = X86_PG_ENTRIES - ((GCPtr >> X86_PT_SHIFT) & X86_PT_MASK);
863 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PD_SHIFT) - 1)));
864 }
865 else
866 {
867 cPagesCanSkip = X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
868 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PD_PAE_SHIFT) - 1)));
869 }
870 break;
871 case 3:
872 cPagesCanSkip = (X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK)) * X86_PG_PAE_ENTRIES
873 - ((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
874 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PDPT_SHIFT) - 1)));
875 break;
876 case 4:
877 cPagesCanSkip = (X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64))
878 * X86_PG_PAE_ENTRIES * X86_PG_PAE_ENTRIES
879 - ((((GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK)) * X86_PG_PAE_ENTRIES)
880 - (( GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
881 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PML4_SHIFT) - 1)));
882 break;
883 case 8:
884 /* The CR3 value is bad, forget the whole search. */
885 cPagesCanSkip = cPages;
886 break;
887 default:
888 AssertMsgFailed(("%d\n", Walk.u.Core.uLevel));
889 cPagesCanSkip = 0;
890 break;
891 }
892 if (cPages <= cPagesCanSkip)
893 break;
894 if (cPagesCanSkip >= cIncPages)
895 {
896 cPages -= cPagesCanSkip;
897 GCPtr += (RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT;
898 continue;
899 }
900 }
901
902 /* advance to the next page. */
903 if (cPages <= cIncPages)
904 break;
905 cPages -= cIncPages;
906 GCPtr += (RTGCPTR)cIncPages << X86_PT_PAE_SHIFT;
907 }
908 return VERR_DBGF_MEM_NOT_FOUND;
909}
910
911
912/**
913 * Initializes the dumper state.
914 *
915 * @param pState The state to initialize.
916 * @param pVM Pointer to the VM.
917 * @param fFlags The flags.
918 * @param u64FirstAddr The first address.
919 * @param u64LastAddr The last address.
920 * @param pHlp The output helpers.
921 */
922static void pgmR3DumpHierarchyInitState(PPGMR3DUMPHIERARCHYSTATE pState, PVM pVM, uint32_t fFlags,
923 uint64_t u64FirstAddr, uint64_t u64LastAddr, PCDBGFINFOHLP pHlp)
924{
925 pState->pVM = pVM;
926 pState->pHlp = pHlp ? pHlp : DBGFR3InfoLogHlp();
927 pState->fPse = !!(fFlags & (DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
928 pState->fPae = !!(fFlags & (DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
929 pState->fLme = !!(fFlags & DBGFPGDMP_FLAGS_LME);
930 pState->fNp = !!(fFlags & DBGFPGDMP_FLAGS_NP);
931 pState->fEpt = !!(fFlags & DBGFPGDMP_FLAGS_EPT);
932 pState->fNxe = !!(fFlags & DBGFPGDMP_FLAGS_NXE);
933 pState->cchAddress = pState->fLme ? 16 : 8;
934 pState->uLastRsvdBit = pState->fNxe ? 62 : 63;
935 pState->fDumpPageInfo = !!(fFlags & DBGFPGDMP_FLAGS_PAGE_INFO);
936 pState->fPrintHeader = !!(fFlags & DBGFPGDMP_FLAGS_HEADER);
937 pState->fPrintCr3 = !!(fFlags & DBGFPGDMP_FLAGS_PRINT_CR3);
938 pState->afReserved[0] = false;
939 pState->afReserved[1] = false;
940 pState->afReserved[2] = false;
941 pState->afReserved[3] = false;
942 pState->afReserved[4] = false;
943 pState->u64Address = u64FirstAddr;
944 pState->u64FirstAddress = u64FirstAddr;
945 pState->u64LastAddress = u64LastAddr;
946 pState->u64HighReservedBits = pState->uLastRsvdBit == 62 ? UINT64_C(0x7ff) << 52 : UINT64_C(0xfff) << 52;
947 pState->cLeaves = 0;
948}
949
950
951/**
952 * The simple way out, too tired to think of a more elegant solution.
953 *
954 * @returns The base address of this page table/directory/whatever.
955 * @param pState The state where we get the current address.
956 * @param cShift The shift count for the table entries.
957 * @param cEntries The number of table entries.
958 * @param piFirst Where to return the table index of the first
959 * entry to dump.
960 * @param piLast Where to return the table index of the last
961 * entry.
962 */
963static uint64_t pgmR3DumpHierarchyCalcRange(PPGMR3DUMPHIERARCHYSTATE pState, uint32_t cShift, uint32_t cEntries,
964 uint32_t *piFirst, uint32_t *piLast)
965{
966 const uint64_t iBase = (pState->u64Address >> cShift) & ~(uint64_t)(cEntries - 1);
967 const uint64_t iFirst = pState->u64FirstAddress >> cShift;
968 const uint64_t iLast = pState->u64LastAddress >> cShift;
969
970 if ( iBase >= iFirst
971 && iBase + cEntries - 1 <= iLast)
972 {
973 /* full range. */
974 *piFirst = 0;
975 *piLast = cEntries - 1;
976 }
977 else if ( iBase + cEntries - 1 < iFirst
978 || iBase > iLast)
979 {
980 /* no match */
981 *piFirst = cEntries;
982 *piLast = 0;
983 }
984 else
985 {
986 /* partial overlap */
987 *piFirst = iBase <= iFirst
988 ? iFirst - iBase
989 : 0;
990 *piLast = iBase + cEntries - 1 <= iLast
991 ? cEntries - 1
992 : iLast - iBase;
993 }
994
995 return iBase << cShift;
996}
997
998
999/**
1000 * Maps/finds the shadow page.
1001 *
1002 * @returns VBox status code.
1003 * @param pState The dumper state.
1004 * @param HCPhys The physical address of the shadow page.
1005 * @param pszDesc The description.
1006 * @param fIsMapping Set if it's a mapping.
1007 * @param ppv Where to return the pointer.
1008 */
1009static int pgmR3DumpHierarchyShwMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, const char *pszDesc,
1010 bool fIsMapping, void const **ppv)
1011{
1012 void *pvPage;
1013 if (!fIsMapping)
1014 {
1015 int rc = MMPagePhys2PageTry(pState->pVM, HCPhys, &pvPage);
1016 if (RT_FAILURE(rc))
1017 {
1018 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! %s at HCPhys=%RHp was not found in the page pool!\n",
1019 pState->cchAddress, pState->u64Address, pszDesc, HCPhys);
1020 return rc;
1021 }
1022 }
1023 else
1024 {
1025 pvPage = NULL;
1026 for (PPGMMAPPING pMap = pState->pVM->pgm.s.pMappingsR3; pMap; pMap = pMap->pNextR3)
1027 {
1028 uint64_t off = pState->u64Address - pMap->GCPtr;
1029 if (off < pMap->cb)
1030 {
1031 const int iPDE = (uint32_t)(off >> X86_PD_SHIFT);
1032 const int iSub = (int)((off >> X86_PD_PAE_SHIFT) & 1); /* MSC is a pain sometimes */
1033 if ((iSub ? pMap->aPTs[iPDE].HCPhysPaePT1 : pMap->aPTs[iPDE].HCPhysPaePT0) != HCPhys)
1034 pState->pHlp->pfnPrintf(pState->pHlp,
1035 "%0*llx error! Mapping error! PT %d has HCPhysPT=%RHp not %RHp is in the PD.\n",
1036 pState->cchAddress, pState->u64Address, iPDE,
1037 iSub ? pMap->aPTs[iPDE].HCPhysPaePT1 : pMap->aPTs[iPDE].HCPhysPaePT0, HCPhys);
1038 pvPage = &pMap->aPTs[iPDE].paPaePTsR3[iSub];
1039 break;
1040 }
1041 }
1042 if (!pvPage)
1043 {
1044 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! PT mapping %s at HCPhys=%RHp was not found in the page pool!\n",
1045 pState->cchAddress, pState->u64Address, HCPhys);
1046 return VERR_INVALID_PARAMETER;
1047 }
1048 }
1049 *ppv = pvPage;
1050 return VINF_SUCCESS;
1051}
1052
1053
1054/**
1055 * Dumps the a shadow page summary or smth.
1056 *
1057 * @param pState The dumper state.
1058 * @param HCPhys The page address.
1059 */
1060static void pgmR3DumpHierarchyShwTablePageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1061{
1062 pgmLock(pState->pVM);
1063 char szPage[80];
1064 PPGMPOOLPAGE pPage = pgmPoolQueryPageForDbg(pState->pVM->pgm.s.CTX_SUFF(pPool), HCPhys);
1065 if (pPage)
1066 RTStrPrintf(szPage, sizeof(szPage), " idx=0i%u", pPage->idx);
1067 else
1068 {
1069 /* probably a mapping */
1070 strcpy(szPage, " not found");
1071 for (PPGMMAPPING pMap = pState->pVM->pgm.s.pMappingsR3; pMap; pMap = pMap->pNextR3)
1072 {
1073 uint64_t off = pState->u64Address - pMap->GCPtr;
1074 if (off < pMap->cb)
1075 {
1076 const int iPDE = (uint32_t)(off >> X86_PD_SHIFT);
1077 if (pMap->aPTs[iPDE].HCPhysPT == HCPhys)
1078 RTStrPrintf(szPage, sizeof(szPage), " #%u: %s", iPDE, pMap->pszDesc);
1079 else if (pMap->aPTs[iPDE].HCPhysPaePT0 == HCPhys)
1080 RTStrPrintf(szPage, sizeof(szPage), " #%u/0: %s", iPDE, pMap->pszDesc);
1081 else if (pMap->aPTs[iPDE].HCPhysPaePT1 == HCPhys)
1082 RTStrPrintf(szPage, sizeof(szPage), " #%u/1: %s", iPDE, pMap->pszDesc);
1083 else
1084 continue;
1085 break;
1086 }
1087 }
1088 }
1089 pgmUnlock(pState->pVM);
1090 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
1091}
1092
1093
1094/**
1095 * Figures out which guest page this is and dumps a summary.
1096 *
1097 * @param pState The dumper state.
1098 * @param HCPhys The page address.
1099 * @param cbPage The page size.
1100 */
1101static void pgmR3DumpHierarchyShwGuestPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, uint32_t cbPage)
1102{
1103 char szPage[80];
1104 RTGCPHYS GCPhys;
1105 int rc = PGMR3DbgHCPhys2GCPhys(pState->pVM->pUVM, HCPhys, &GCPhys);
1106 if (RT_SUCCESS(rc))
1107 {
1108 pgmLock(pState->pVM);
1109 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
1110 if (pPage)
1111 RTStrPrintf(szPage, sizeof(szPage), "%R[pgmpage]", pPage);
1112 else
1113 strcpy(szPage, "not found");
1114 pgmUnlock(pState->pVM);
1115 pState->pHlp->pfnPrintf(pState->pHlp, " -> %RGp %s", GCPhys, szPage);
1116 }
1117 else
1118 {
1119 /* check the heap */
1120 uint32_t cbAlloc;
1121 rc = MMR3HyperQueryInfoFromHCPhys(pState->pVM, HCPhys, szPage, sizeof(szPage), &cbAlloc);
1122 if (RT_SUCCESS(rc))
1123 pState->pHlp->pfnPrintf(pState->pHlp, " %s %#x bytes", szPage, cbAlloc);
1124 else
1125 pState->pHlp->pfnPrintf(pState->pHlp, " not found");
1126 }
1127 NOREF(cbPage);
1128}
1129
1130
1131/**
1132 * Dumps a PAE shadow page table.
1133 *
1134 * @returns VBox status code (VINF_SUCCESS).
1135 * @param pState The dumper state.
1136 * @param HCPhys The page table address.
1137 * @param fIsMapping Whether it is a mapping.
1138 */
1139static int pgmR3DumpHierarchyShwPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, bool fIsMapping)
1140{
1141 PCPGMSHWPTPAE pPT;
1142 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", fIsMapping, (void const **)&pPT);
1143 if (RT_FAILURE(rc))
1144 return rc;
1145
1146 uint32_t iFirst, iLast;
1147 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1148 for (uint32_t i = iFirst; i <= iLast; i++)
1149 if (PGMSHWPTEPAE_GET_U(pPT->a[i]) & X86_PTE_P)
1150 {
1151 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
1152 if (PGMSHWPTEPAE_IS_P(pPT->a[i]))
1153 {
1154 X86PTEPAE Pte;
1155 Pte.u = PGMSHWPTEPAE_GET_U(pPT->a[i]);
1156 pState->pHlp->pfnPrintf(pState->pHlp,
1157 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
1158 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
1159 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
1160 pState->u64Address,
1161 Pte.n.u1Write ? 'W' : 'R',
1162 Pte.n.u1User ? 'U' : 'S',
1163 Pte.n.u1Accessed ? 'A' : '-',
1164 Pte.n.u1Dirty ? 'D' : '-',
1165 Pte.n.u1Global ? 'G' : '-',
1166 Pte.n.u1WriteThru ? "WT" : "--",
1167 Pte.n.u1CacheDisable? "CD" : "--",
1168 Pte.n.u1PAT ? "AT" : "--",
1169 Pte.n.u1NoExecute ? "NX" : "--",
1170 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1171 Pte.u & RT_BIT(10) ? '1' : '0',
1172 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED? 'v' : '-',
1173 Pte.u & X86_PTE_PAE_PG_MASK);
1174 if (pState->fDumpPageInfo)
1175 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
1176 if ((Pte.u >> 52) & 0x7ff)
1177 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pte.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1178 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1179 }
1180 else if ( (PGMSHWPTEPAE_GET_U(pPT->a[i]) & (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1181 == (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1182 pState->pHlp->pfnPrintf(pState->pHlp,
1183 pState->fLme
1184 ? "%016llx 3 | invalid / MMIO optimization\n"
1185 : "%08llx 2 | invalid / MMIO optimization\n",
1186 pState->u64Address);
1187 else
1188 pState->pHlp->pfnPrintf(pState->pHlp,
1189 pState->fLme
1190 ? "%016llx 3 | invalid: %RX64\n"
1191 : "%08llx 2 | invalid: %RX64\n",
1192 pState->u64Address, PGMSHWPTEPAE_GET_U(pPT->a[i]));
1193 pState->cLeaves++;
1194 }
1195 return VINF_SUCCESS;
1196}
1197
1198
1199/**
1200 * Dumps a PAE shadow page directory table.
1201 *
1202 * @returns VBox status code (VINF_SUCCESS).
1203 * @param pState The dumper state.
1204 * @param HCPhys The physical address of the page directory table.
1205 * @param cMaxDepth The maximum depth.
1206 */
1207static int pgmR3DumpHierarchyShwPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1208{
1209 PCX86PDPAE pPD;
1210 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", false, (void const **)&pPD);
1211 if (RT_FAILURE(rc))
1212 return rc;
1213
1214 Assert(cMaxDepth > 0);
1215 cMaxDepth--;
1216
1217 uint32_t iFirst, iLast;
1218 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1219 for (uint32_t i = iFirst; i <= iLast; i++)
1220 {
1221 X86PDEPAE Pde = pPD->a[i];
1222 if (Pde.n.u1Present)
1223 {
1224 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
1225 if (Pde.b.u1Size)
1226 {
1227 pState->pHlp->pfnPrintf(pState->pHlp,
1228 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
1229 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
1230 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
1231 pState->u64Address,
1232 Pde.b.u1Write ? 'W' : 'R',
1233 Pde.b.u1User ? 'U' : 'S',
1234 Pde.b.u1Accessed ? 'A' : '-',
1235 Pde.b.u1Dirty ? 'D' : '-',
1236 Pde.b.u1Global ? 'G' : '-',
1237 Pde.b.u1WriteThru ? "WT" : "--",
1238 Pde.b.u1CacheDisable? "CD" : "--",
1239 Pde.b.u1PAT ? "AT" : "--",
1240 Pde.b.u1NoExecute ? "NX" : "--",
1241 Pde.u & RT_BIT_64(9) ? '1' : '0',
1242 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1243 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1244 Pde.u & X86_PDE2M_PAE_PG_MASK);
1245 if (pState->fDumpPageInfo)
1246 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
1247 if ((Pde.u >> 52) & 0x7ff)
1248 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pde.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1249 if ((Pde.u >> 13) & 0xff)
1250 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
1251 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1252
1253 pState->cLeaves++;
1254 }
1255 else
1256 {
1257 pState->pHlp->pfnPrintf(pState->pHlp,
1258 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
1259 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
1260 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
1261 pState->u64Address,
1262 Pde.n.u1Write ? 'W' : 'R',
1263 Pde.n.u1User ? 'U' : 'S',
1264 Pde.n.u1Accessed ? 'A' : '-',
1265 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1266 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1267 Pde.n.u1WriteThru ? "WT" : "--",
1268 Pde.n.u1CacheDisable? "CD" : "--",
1269 Pde.n.u1NoExecute ? "NX" : "--",
1270 Pde.u & RT_BIT_64(9) ? '1' : '0',
1271 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1272 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1273 Pde.u & X86_PDE_PAE_PG_MASK);
1274 if (pState->fDumpPageInfo)
1275 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1276 if ((Pde.u >> 52) & 0x7ff)
1277 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pde.u >> 52) & 0x7ff);
1278 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1279
1280 if (cMaxDepth)
1281 {
1282 int rc2 = pgmR3DumpHierarchyShwPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK, !!(Pde.u & PGM_PDFLAGS_MAPPING));
1283 if (rc2 < rc && RT_SUCCESS(rc))
1284 rc = rc2;
1285 }
1286 else
1287 pState->cLeaves++;
1288 }
1289 }
1290 }
1291 return rc;
1292}
1293
1294
1295/**
1296 * Dumps a PAE shadow page directory pointer table.
1297 *
1298 * @returns VBox status code (VINF_SUCCESS).
1299 * @param pState The dumper state.
1300 * @param HCPhys The physical address of the page directory pointer table.
1301 * @param cMaxDepth The maximum depth.
1302 */
1303static int pgmR3DumpHierarchyShwPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1304{
1305 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
1306 if (!pState->fLme && pState->u64Address >= _4G)
1307 return VINF_SUCCESS;
1308
1309 PCX86PDPT pPDPT;
1310 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory pointer table", false, (void const **)&pPDPT);
1311 if (RT_FAILURE(rc))
1312 return rc;
1313
1314 Assert(cMaxDepth > 0);
1315 cMaxDepth--;
1316
1317 uint32_t iFirst, iLast;
1318 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
1319 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
1320 &iFirst, &iLast);
1321 for (uint32_t i = iFirst; i <= iLast; i++)
1322 {
1323 X86PDPE Pdpe = pPDPT->a[i];
1324 if (Pdpe.n.u1Present)
1325 {
1326 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
1327 if (pState->fLme)
1328 {
1329 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
1330 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1331 pState->u64Address,
1332 Pdpe.lm.u1Write ? 'W' : 'R',
1333 Pdpe.lm.u1User ? 'U' : 'S',
1334 Pdpe.lm.u1Accessed ? 'A' : '-',
1335 Pdpe.lm.u3Reserved & 1? '?' : '.', /* ignored */
1336 Pdpe.lm.u3Reserved & 4? '!' : '.', /* mbz */
1337 Pdpe.lm.u1WriteThru ? "WT" : "--",
1338 Pdpe.lm.u1CacheDisable? "CD" : "--",
1339 Pdpe.lm.u3Reserved & 2? "!" : "..",/* mbz */
1340 Pdpe.lm.u1NoExecute ? "NX" : "--",
1341 Pdpe.u & RT_BIT(9) ? '1' : '0',
1342 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1343 Pdpe.u & RT_BIT(11) ? '1' : '0',
1344 Pdpe.u & X86_PDPE_PG_MASK);
1345 if (pState->fDumpPageInfo)
1346 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1347 if ((Pdpe.u >> 52) & 0x7ff)
1348 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx", (Pdpe.u >> 52) & 0x7ff);
1349 }
1350 else
1351 {
1352 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
1353 "%08llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1354 pState->u64Address,
1355 Pdpe.n.u2Reserved & 1? '!' : '.', /* mbz */
1356 Pdpe.n.u2Reserved & 2? '!' : '.', /* mbz */
1357 Pdpe.n.u4Reserved & 1? '!' : '.', /* mbz */
1358 Pdpe.n.u4Reserved & 2? '!' : '.', /* mbz */
1359 Pdpe.n.u4Reserved & 8? '!' : '.', /* mbz */
1360 Pdpe.n.u1WriteThru ? "WT" : "--",
1361 Pdpe.n.u1CacheDisable? "CD" : "--",
1362 Pdpe.n.u4Reserved & 2? "!" : "..",/* mbz */
1363 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
1364 Pdpe.u & RT_BIT(9) ? '1' : '0',
1365 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1366 Pdpe.u & RT_BIT(11) ? '1' : '0',
1367 Pdpe.u & X86_PDPE_PG_MASK);
1368 if (pState->fDumpPageInfo)
1369 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1370 if ((Pdpe.u >> 52) & 0xfff)
1371 pState->pHlp->pfnPrintf(pState->pHlp, " 63:52=%03llx!", (Pdpe.u >> 52) & 0xfff);
1372 }
1373 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1374
1375 if (cMaxDepth)
1376 {
1377 int rc2 = pgmR3DumpHierarchyShwPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
1378 if (rc2 < rc && RT_SUCCESS(rc))
1379 rc = rc2;
1380 }
1381 else
1382 pState->cLeaves++;
1383 }
1384 }
1385 return rc;
1386}
1387
1388
1389/**
1390 * Dumps a 32-bit shadow page table.
1391 *
1392 * @returns VBox status code (VINF_SUCCESS).
1393 * @param pVM Pointer to the VM.
1394 * @param HCPhys The physical address of the table.
1395 * @param cMaxDepth The maximum depth.
1396 */
1397static int pgmR3DumpHierarchyShwPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1398{
1399 PCX86PML4 pPML4;
1400 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page map level 4", false, (void const **)&pPML4);
1401 if (RT_FAILURE(rc))
1402 return rc;
1403
1404 Assert(cMaxDepth);
1405 cMaxDepth--;
1406
1407 /*
1408 * This is a bit tricky as we're working on unsigned addresses while the
1409 * AMD64 spec uses signed tricks.
1410 */
1411 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1412 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1413 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
1414 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
1415 { /* Simple, nothing to adjust */ }
1416 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
1417 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
1418 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
1419 iFirst = X86_PG_AMD64_ENTRIES / 2;
1420 else
1421 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
1422
1423 for (uint32_t i = iFirst; i <= iLast; i++)
1424 {
1425 X86PML4E Pml4e = pPML4->a[i];
1426 if (Pml4e.n.u1Present)
1427 {
1428 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
1429 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
1430 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
1431 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1432 pState->u64Address,
1433 Pml4e.n.u1Write ? 'W' : 'R',
1434 Pml4e.n.u1User ? 'U' : 'S',
1435 Pml4e.n.u1Accessed ? 'A' : '-',
1436 Pml4e.n.u3Reserved & 1? '?' : '.', /* ignored */
1437 Pml4e.n.u3Reserved & 4? '!' : '.', /* mbz */
1438 Pml4e.n.u1WriteThru ? "WT" : "--",
1439 Pml4e.n.u1CacheDisable? "CD" : "--",
1440 Pml4e.n.u3Reserved & 2? "!" : "..",/* mbz */
1441 Pml4e.n.u1NoExecute ? "NX" : "--",
1442 Pml4e.u & RT_BIT(9) ? '1' : '0',
1443 Pml4e.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1444 Pml4e.u & RT_BIT(11) ? '1' : '0',
1445 Pml4e.u & X86_PML4E_PG_MASK);
1446 if (pState->fDumpPageInfo)
1447 pgmR3DumpHierarchyShwTablePageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK);
1448 if ((Pml4e.u >> 52) & 0x7ff)
1449 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pml4e.u >> 52) & 0x7ff);
1450 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1451
1452 if (cMaxDepth)
1453 {
1454 int rc2 = pgmR3DumpHierarchyShwPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
1455 if (rc2 < rc && RT_SUCCESS(rc))
1456 rc = rc2;
1457 }
1458 else
1459 pState->cLeaves++;
1460 }
1461 }
1462 return rc;
1463}
1464
1465
1466/**
1467 * Dumps a 32-bit shadow page table.
1468 *
1469 * @returns VBox status code (VINF_SUCCESS).
1470 * @param pVM Pointer to the VM.
1471 * @param pPT Pointer to the page table.
1472 * @param fMapping Set if it's a guest mapping.
1473 */
1474static int pgmR3DumpHierarchyShw32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, bool fMapping)
1475{
1476 PCX86PT pPT;
1477 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", fMapping, (void const **)&pPT);
1478 if (RT_FAILURE(rc))
1479 return rc;
1480
1481 uint32_t iFirst, iLast;
1482 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
1483 for (uint32_t i = iFirst; i <= iLast; i++)
1484 {
1485 X86PTE Pte = pPT->a[i];
1486 if (Pte.n.u1Present)
1487 {
1488 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
1489 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
1490 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
1491 pState->u64Address,
1492 Pte.n.u1Write ? 'W' : 'R',
1493 Pte.n.u1User ? 'U' : 'S',
1494 Pte.n.u1Accessed ? 'A' : '-',
1495 Pte.n.u1Dirty ? 'D' : '-',
1496 Pte.n.u1Global ? 'G' : '-',
1497 Pte.n.u1WriteThru ? "WT" : "--",
1498 Pte.n.u1CacheDisable? "CD" : "--",
1499 Pte.n.u1PAT ? "AT" : "--",
1500 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1501 Pte.u & RT_BIT(10) ? '1' : '0',
1502 Pte.u & PGM_PTFLAGS_CSAM_VALIDATED ? 'v' : '-',
1503 Pte.u & X86_PDE_PG_MASK);
1504 if (pState->fDumpPageInfo)
1505 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
1506 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1507 }
1508 }
1509 return VINF_SUCCESS;
1510}
1511
1512
1513/**
1514 * Dumps a 32-bit shadow page directory and page tables.
1515 *
1516 * @returns VBox status code (VINF_SUCCESS).
1517 * @param pState The dumper state.
1518 * @param HCPhys The physical address of the table.
1519 * @param cMaxDepth The maximum depth.
1520 */
1521static int pgmR3DumpHierarchyShw32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1522{
1523 if (pState->u64Address >= _4G)
1524 return VINF_SUCCESS;
1525
1526 PCX86PD pPD;
1527 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", false, (void const **)&pPD);
1528 if (RT_FAILURE(rc))
1529 return rc;
1530
1531 Assert(cMaxDepth > 0);
1532 cMaxDepth--;
1533
1534 uint32_t iFirst, iLast;
1535 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
1536 for (uint32_t i = iFirst; i <= iLast; i++)
1537 {
1538 X86PDE Pde = pPD->a[i];
1539 if (Pde.n.u1Present)
1540 {
1541 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
1542 if (Pde.b.u1Size && pState->fPse)
1543 {
1544 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
1545 | (Pde.u & X86_PDE4M_PG_MASK);
1546 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
1547 "%08llx 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
1548 pState->u64Address,
1549 Pde.b.u1Write ? 'W' : 'R',
1550 Pde.b.u1User ? 'U' : 'S',
1551 Pde.b.u1Accessed ? 'A' : '-',
1552 Pde.b.u1Dirty ? 'D' : '-',
1553 Pde.b.u1Global ? 'G' : '-',
1554 Pde.b.u1WriteThru ? "WT" : "--",
1555 Pde.b.u1CacheDisable? "CD" : "--",
1556 Pde.b.u1PAT ? "AT" : "--",
1557 Pde.u & RT_BIT_32(9) ? '1' : '0',
1558 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1559 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1560 u64Phys);
1561 if (pState->fDumpPageInfo)
1562 pgmR3DumpHierarchyShwGuestPageInfo(pState, u64Phys, _4M);
1563 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1564 pState->cLeaves++;
1565 }
1566 else
1567 {
1568 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
1569 "%08llx 0 | P %c %c %c %c %c %s %s .. .. 4K %c%c%c %08x",
1570 pState->u64Address,
1571 Pde.n.u1Write ? 'W' : 'R',
1572 Pde.n.u1User ? 'U' : 'S',
1573 Pde.n.u1Accessed ? 'A' : '-',
1574 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1575 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1576 Pde.n.u1WriteThru ? "WT" : "--",
1577 Pde.n.u1CacheDisable? "CD" : "--",
1578 Pde.u & RT_BIT_32(9) ? '1' : '0',
1579 Pde.u & PGM_PDFLAGS_MAPPING ? 'm' : '-',
1580 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1581 Pde.u & X86_PDE_PG_MASK);
1582 if (pState->fDumpPageInfo)
1583 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PG_MASK);
1584 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1585
1586 if (cMaxDepth)
1587 {
1588 int rc2 = pgmR3DumpHierarchyShw32BitPT(pState, Pde.u & X86_PDE_PG_MASK, !!(Pde.u & PGM_PDFLAGS_MAPPING));
1589 if (rc2 < rc && RT_SUCCESS(rc))
1590 rc = rc2;
1591 }
1592 else
1593 pState->cLeaves++;
1594 }
1595 }
1596 }
1597
1598 return rc;
1599}
1600
1601
1602/**
1603 * Internal worker that initiates the actual dump.
1604 *
1605 * @returns VBox status code.
1606 * @param pState The dumper state.
1607 * @param cr3 The CR3 value.
1608 * @param cMaxDepth The max depth.
1609 */
1610static int pgmR3DumpHierarchyShwDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
1611{
1612 int rc;
1613 unsigned const cch = pState->cchAddress;
1614 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK
1615 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
1616 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
1617 : X86_CR3_PAGE_MASK;
1618 if (pState->fPrintCr3)
1619 {
1620 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
1621 : pState->fLme ? "Long Mode"
1622 : pState->fPae ? "PAE Mode"
1623 : pState->fPse ? "32-bit w/ PSE"
1624 : "32-bit";
1625 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
1626 if (pState->fDumpPageInfo)
1627 pgmR3DumpHierarchyShwTablePageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK);
1628 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
1629 pszMode,
1630 pState->fNp ? " + Nested Paging" : "",
1631 pState->fNxe ? " + NX" : "");
1632 }
1633
1634
1635 if (pState->fEpt)
1636 {
1637 if (pState->fPrintHeader)
1638 pState->pHlp->pfnPrintf(pState->pHlp,
1639 "%-*s R - Readable\n"
1640 "%-*s | W - Writeable\n"
1641 "%-*s | | X - Executable\n"
1642 "%-*s | | | EMT - EPT memory type\n"
1643 "%-*s | | | | PAT - Ignored PAT?\n"
1644 "%-*s | | | | | AVL1 - 4 available bits\n"
1645 "%-*s | | | | | | AVL2 - 12 available bits\n"
1646 "%-*s Level | | | | | | | page \n"
1647 /* xxxx n **** R W X EMT PAT AVL1 AVL2 xxxxxxxxxxxxx
1648 R W X 7 0 f fff 0123456701234567 */
1649 ,
1650 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
1651
1652 pState->pHlp->pfnPrintf(pState->pHlp, "EPT dumping is not yet implemented, sorry.\n");
1653 /** @todo implemented EPT dumping. */
1654 rc = VERR_NOT_IMPLEMENTED;
1655 }
1656 else
1657 {
1658 if (pState->fPrintHeader)
1659 pState->pHlp->pfnPrintf(pState->pHlp,
1660 "%-*s P - Present\n"
1661 "%-*s | R/W - Read (0) / Write (1)\n"
1662 "%-*s | | U/S - User (1) / Supervisor (0)\n"
1663 "%-*s | | | A - Accessed\n"
1664 "%-*s | | | | D - Dirty\n"
1665 "%-*s | | | | | G - Global\n"
1666 "%-*s | | | | | | WT - Write thru\n"
1667 "%-*s | | | | | | | CD - Cache disable\n"
1668 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
1669 "%-*s | | | | | | | | | NX - No execute (K8)\n"
1670 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
1671 "%-*s | | | | | | | | | | | AVL - a=allocated; m=mapping; d=track dirty;\n"
1672 "%-*s | | | | | | | | | | | | p=permanent; v=validated;\n"
1673 "%-*s Level | | | | | | | | | | | | Page\n"
1674 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
1675 - W U - - - -- -- -- -- -- 010 */
1676 ,
1677 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
1678 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
1679 if (pState->fLme)
1680 rc = pgmR3DumpHierarchyShwPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
1681 else if (pState->fPae)
1682 rc = pgmR3DumpHierarchyShwPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
1683 else
1684 rc = pgmR3DumpHierarchyShw32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
1685 }
1686
1687 if (!pState->cLeaves)
1688 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
1689 return rc;
1690}
1691
1692
1693/**
1694 * dbgfR3PagingDumpEx worker.
1695 *
1696 * @returns VBox status code.
1697 * @param pVM Pointer to the VM.
1698 * @param cr3 The CR3 register value.
1699 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
1700 * @param u64FirstAddr The start address.
1701 * @param u64LastAddr The address to stop after.
1702 * @param cMaxDepth The max depth.
1703 * @param pHlp The output callbacks. Defaults to log if NULL.
1704 *
1705 * @internal
1706 */
1707VMMR3_INT_DECL(int) PGMR3DumpHierarchyShw(PVM pVM, uint64_t cr3, uint32_t fFlags, uint64_t u64FirstAddr, uint64_t u64LastAddr,
1708 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
1709{
1710 /* Minimal validation as we're only supposed to service DBGF. */
1711 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
1712 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
1713 AssertReturn(fFlags & DBGFPGDMP_FLAGS_SHADOW, VERR_INVALID_PARAMETER);
1714
1715 PGMR3DUMPHIERARCHYSTATE State;
1716 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, u64FirstAddr, u64LastAddr, pHlp);
1717 return pgmR3DumpHierarchyShwDoIt(&State, cr3, cMaxDepth);
1718}
1719
1720
1721/**
1722 * Dumps a page table hierarchy use only physical addresses and cr4/lm flags.
1723 *
1724 * @returns VBox status code (VINF_SUCCESS).
1725 * @param pVM Pointer to the VM.
1726 * @param cr3 The root of the hierarchy.
1727 * @param cr4 The cr4, only PAE and PSE is currently used.
1728 * @param fLongMode Set if long mode, false if not long mode.
1729 * @param cMaxDepth Number of levels to dump.
1730 * @param pHlp Pointer to the output functions.
1731 *
1732 * @deprecated Use DBGFR3PagingDumpEx.
1733 */
1734VMMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint64_t cr3, uint64_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
1735{
1736 if (!cMaxDepth)
1737 return VINF_SUCCESS;
1738
1739 PVMCPU pVCpu = VMMGetCpu(pVM);
1740 if (!pVCpu)
1741 pVCpu = &pVM->aCpus[0];
1742
1743 uint32_t fFlags = DBGFPGDMP_FLAGS_HEADER | DBGFPGDMP_FLAGS_PRINT_CR3 | DBGFPGDMP_FLAGS_PAGE_INFO | DBGFPGDMP_FLAGS_SHADOW;
1744 fFlags |= cr4 & (X86_CR4_PAE | X86_CR4_PSE);
1745 if (fLongMode)
1746 fFlags |= DBGFPGDMP_FLAGS_LME;
1747
1748 return DBGFR3PagingDumpEx(pVM->pUVM, pVCpu->idCpu, fFlags, cr3, 0, fLongMode ? UINT64_MAX : UINT32_MAX, cMaxDepth, pHlp);
1749}
1750
1751
1752/**
1753 * Maps the guest page.
1754 *
1755 * @returns VBox status code.
1756 * @param pState The dumper state.
1757 * @param GCPhys The physical address of the guest page.
1758 * @param pszDesc The description.
1759 * @param ppv Where to return the pointer.
1760 * @param pLock Where to return the mapping lock. Hand this to
1761 * PGMPhysReleasePageMappingLock when done.
1762 */
1763static int pgmR3DumpHierarchyGstMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, const char *pszDesc,
1764 void const **ppv, PPGMPAGEMAPLOCK pLock)
1765{
1766 int rc = PGMPhysGCPhys2CCPtrReadOnly(pState->pVM, GCPhys, ppv, pLock);
1767 if (RT_FAILURE(rc))
1768 {
1769 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! Failed to map %s at GCPhys=%RGp: %Rrc!\n",
1770 pState->cchAddress, pState->u64Address, pszDesc, GCPhys, rc);
1771 return rc;
1772 }
1773 return VINF_SUCCESS;
1774}
1775
1776
1777/**
1778 * Figures out which guest page this is and dumps a summary.
1779 *
1780 * @param pState The dumper state.
1781 * @param GCPhys The page address.
1782 * @param cbPage The page size.
1783 */
1784static void pgmR3DumpHierarchyGstPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, uint32_t cbPage)
1785{
1786 char szPage[80];
1787 pgmLock(pState->pVM);
1788 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
1789 if (pPage)
1790 RTStrPrintf(szPage, sizeof(szPage), " %R[pgmpage]", pPage);
1791 else
1792 strcpy(szPage, " not found");
1793 pgmUnlock(pState->pVM);
1794 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
1795 NOREF(cbPage);
1796}
1797
1798
1799/**
1800 * Checks the entry for reserved bits.
1801 *
1802 * @param pState The dumper state.
1803 * @param u64Entry The entry to check.
1804 */
1805static void pgmR3DumpHierarchyGstCheckReservedHighBits(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t u64Entry)
1806{
1807 uint32_t uRsvd = (u64Entry & pState->u64HighReservedBits) >> 52;
1808 if (uRsvd)
1809 pState->pHlp->pfnPrintf(pState->pHlp, " %u:52=%03x%s",
1810 pState->uLastRsvdBit, uRsvd, pState->fLme ? "" : "!");
1811 /** @todo check the valid physical bits as well. */
1812}
1813
1814
1815/**
1816 * Dumps a PAE shadow page table.
1817 *
1818 * @returns VBox status code (VINF_SUCCESS).
1819 * @param pState The dumper state.
1820 * @param GCPhys The page table address.
1821 */
1822static int pgmR3DumpHierarchyGstPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys)
1823{
1824 PCX86PTPAE pPT;
1825 PGMPAGEMAPLOCK Lock;
1826 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
1827 if (RT_FAILURE(rc))
1828 return rc;
1829
1830 uint32_t iFirst, iLast;
1831 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1832 for (uint32_t i = iFirst; i <= iLast; i++)
1833 {
1834 X86PTEPAE Pte = pPT->a[i];
1835 if (Pte.n.u1Present)
1836 {
1837 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
1838 pState->pHlp->pfnPrintf(pState->pHlp,
1839 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
1840 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
1841 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
1842 pState->u64Address,
1843 Pte.n.u1Write ? 'W' : 'R',
1844 Pte.n.u1User ? 'U' : 'S',
1845 Pte.n.u1Accessed ? 'A' : '-',
1846 Pte.n.u1Dirty ? 'D' : '-',
1847 Pte.n.u1Global ? 'G' : '-',
1848 Pte.n.u1WriteThru ? "WT" : "--",
1849 Pte.n.u1CacheDisable? "CD" : "--",
1850 Pte.n.u1PAT ? "AT" : "--",
1851 Pte.n.u1NoExecute ? "NX" : "--",
1852 Pte.u & RT_BIT(9) ? '1' : '0',
1853 Pte.u & RT_BIT(10) ? '1' : '0',
1854 Pte.u & RT_BIT(11) ? '1' : '0',
1855 Pte.u & X86_PTE_PAE_PG_MASK);
1856 if (pState->fDumpPageInfo)
1857 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
1858 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pte.u);
1859 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1860 pState->cLeaves++;
1861 }
1862 }
1863
1864 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
1865 return VINF_SUCCESS;
1866}
1867
1868
1869/**
1870 * Dumps a PAE shadow page directory table.
1871 *
1872 * @returns VBox status code (VINF_SUCCESS).
1873 * @param pState The dumper state.
1874 * @param GCPhys The physical address of the table.
1875 * @param cMaxDepth The maximum depth.
1876 */
1877static int pgmR3DumpHierarchyGstPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
1878{
1879 PCX86PDPAE pPD;
1880 PGMPAGEMAPLOCK Lock;
1881 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
1882 if (RT_FAILURE(rc))
1883 return rc;
1884
1885 Assert(cMaxDepth > 0);
1886 cMaxDepth--;
1887
1888 uint32_t iFirst, iLast;
1889 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1890 for (uint32_t i = iFirst; i <= iLast; i++)
1891 {
1892 X86PDEPAE Pde = pPD->a[i];
1893 if (Pde.n.u1Present)
1894 {
1895 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
1896 if (Pde.b.u1Size)
1897 {
1898 pState->pHlp->pfnPrintf(pState->pHlp,
1899 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
1900 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
1901 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
1902 pState->u64Address,
1903 Pde.b.u1Write ? 'W' : 'R',
1904 Pde.b.u1User ? 'U' : 'S',
1905 Pde.b.u1Accessed ? 'A' : '-',
1906 Pde.b.u1Dirty ? 'D' : '-',
1907 Pde.b.u1Global ? 'G' : '-',
1908 Pde.b.u1WriteThru ? "WT" : "--",
1909 Pde.b.u1CacheDisable ? "CD" : "--",
1910 Pde.b.u1PAT ? "AT" : "--",
1911 Pde.b.u1NoExecute ? "NX" : "--",
1912 Pde.u & RT_BIT_64(9) ? '1' : '0',
1913 Pde.u & RT_BIT_64(10) ? '1' : '0',
1914 Pde.u & RT_BIT_64(11) ? '1' : '0',
1915 Pde.u & X86_PDE2M_PAE_PG_MASK);
1916 if (pState->fDumpPageInfo)
1917 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
1918 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
1919 if ((Pde.u >> 13) & 0xff)
1920 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
1921 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1922
1923 pState->cLeaves++;
1924 }
1925 else
1926 {
1927 pState->pHlp->pfnPrintf(pState->pHlp,
1928 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
1929 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
1930 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
1931 pState->u64Address,
1932 Pde.n.u1Write ? 'W' : 'R',
1933 Pde.n.u1User ? 'U' : 'S',
1934 Pde.n.u1Accessed ? 'A' : '-',
1935 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1936 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1937 Pde.n.u1WriteThru ? "WT" : "--",
1938 Pde.n.u1CacheDisable ? "CD" : "--",
1939 Pde.n.u1NoExecute ? "NX" : "--",
1940 Pde.u & RT_BIT_64(9) ? '1' : '0',
1941 Pde.u & RT_BIT_64(10) ? '1' : '0',
1942 Pde.u & RT_BIT_64(11) ? '1' : '0',
1943 Pde.u & X86_PDE_PAE_PG_MASK);
1944 if (pState->fDumpPageInfo)
1945 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK, _4K);
1946 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
1947 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1948
1949 if (cMaxDepth)
1950 {
1951 int rc2 = pgmR3DumpHierarchyGstPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1952 if (rc2 < rc && RT_SUCCESS(rc))
1953 rc = rc2;
1954 }
1955 else
1956 pState->cLeaves++;
1957 }
1958 }
1959 }
1960
1961 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
1962 return rc;
1963}
1964
1965
1966/**
1967 * Dumps a PAE shadow page directory pointer table.
1968 *
1969 * @returns VBox status code (VINF_SUCCESS).
1970 * @param pState The dumper state.
1971 * @param GCPhys The physical address of the table.
1972 * @param cMaxDepth The maximum depth.
1973 */
1974static int pgmR3DumpHierarchyGstPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
1975{
1976 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
1977 if (!pState->fLme && pState->u64Address >= _4G)
1978 return VINF_SUCCESS;
1979
1980 PCX86PDPT pPDPT;
1981 PGMPAGEMAPLOCK Lock;
1982 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory pointer table", (void const **)&pPDPT, &Lock);
1983 if (RT_FAILURE(rc))
1984 return rc;
1985
1986 Assert(cMaxDepth > 0);
1987 cMaxDepth--;
1988
1989 uint32_t iFirst, iLast;
1990 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
1991 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
1992 &iFirst, &iLast);
1993 for (uint32_t i = iFirst; i <= iLast; i++)
1994 {
1995 X86PDPE Pdpe = pPDPT->a[i];
1996 if (Pdpe.n.u1Present)
1997 {
1998 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
1999 if (pState->fLme)
2000 {
2001 /** @todo Do 1G pages. */
2002 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
2003 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2004 pState->u64Address,
2005 Pdpe.lm.u1Write ? 'W' : 'R',
2006 Pdpe.lm.u1User ? 'U' : 'S',
2007 Pdpe.lm.u1Accessed ? 'A' : '-',
2008 Pdpe.lm.u3Reserved & 1 ? '?' : '.', /* ignored */
2009 Pdpe.lm.u3Reserved & 4 ? '!' : '.', /* mbz */
2010 Pdpe.lm.u1WriteThru ? "WT" : "--",
2011 Pdpe.lm.u1CacheDisable ? "CD" : "--",
2012 Pdpe.lm.u3Reserved & 2 ? "!" : "..",/* mbz */
2013 Pdpe.lm.u1NoExecute ? "NX" : "--",
2014 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
2015 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
2016 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
2017 Pdpe.u & X86_PDPE_PG_MASK);
2018 if (pState->fDumpPageInfo)
2019 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
2020 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
2021 }
2022 else
2023 {
2024 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
2025 "%08llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2026 pState->u64Address,
2027 Pdpe.n.u2Reserved & 1 ? '!' : '.', /* mbz */
2028 Pdpe.n.u2Reserved & 2 ? '!' : '.', /* mbz */
2029 Pdpe.n.u4Reserved & 1 ? '!' : '.', /* mbz */
2030 Pdpe.n.u4Reserved & 2 ? '!' : '.', /* mbz */
2031 Pdpe.n.u4Reserved & 8 ? '!' : '.', /* mbz */
2032 Pdpe.n.u1WriteThru ? "WT" : "--",
2033 Pdpe.n.u1CacheDisable ? "CD" : "--",
2034 Pdpe.n.u4Reserved & 2 ? "!" : "..", /* mbz */
2035 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
2036 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
2037 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
2038 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
2039 Pdpe.u & X86_PDPE_PG_MASK);
2040 if (pState->fDumpPageInfo)
2041 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
2042 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
2043 }
2044 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2045
2046 if (cMaxDepth)
2047 {
2048 int rc2 = pgmR3DumpHierarchyGstPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
2049 if (rc2 < rc && RT_SUCCESS(rc))
2050 rc = rc2;
2051 }
2052 else
2053 pState->cLeaves++;
2054 }
2055 }
2056
2057 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2058 return rc;
2059}
2060
2061
2062/**
2063 * Dumps a 32-bit shadow page table.
2064 *
2065 * @returns VBox status code (VINF_SUCCESS).
2066 * @param pVM Pointer to the VM.
2067 * @param GCPhys The physical address of the table.
2068 * @param cMaxDepth The maximum depth.
2069 */
2070static int pgmR3DumpHierarchyGstPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2071{
2072 PCX86PML4 pPML4;
2073 PGMPAGEMAPLOCK Lock;
2074 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page map level 4", (void const **)&pPML4, &Lock);
2075 if (RT_FAILURE(rc))
2076 return rc;
2077
2078 Assert(cMaxDepth);
2079 cMaxDepth--;
2080
2081 /*
2082 * This is a bit tricky as we're working on unsigned addresses while the
2083 * AMD64 spec uses signed tricks.
2084 */
2085 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2086 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2087 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
2088 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
2089 { /* Simple, nothing to adjust */ }
2090 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
2091 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
2092 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
2093 iFirst = X86_PG_AMD64_ENTRIES / 2;
2094 else
2095 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
2096
2097 for (uint32_t i = iFirst; i <= iLast; i++)
2098 {
2099 X86PML4E Pml4e = pPML4->a[i];
2100 if (Pml4e.n.u1Present)
2101 {
2102 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
2103 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
2104 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
2105 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2106 pState->u64Address,
2107 Pml4e.n.u1Write ? 'W' : 'R',
2108 Pml4e.n.u1User ? 'U' : 'S',
2109 Pml4e.n.u1Accessed ? 'A' : '-',
2110 Pml4e.n.u3Reserved & 1 ? '?' : '.', /* ignored */
2111 Pml4e.n.u3Reserved & 4 ? '!' : '.', /* mbz */
2112 Pml4e.n.u1WriteThru ? "WT" : "--",
2113 Pml4e.n.u1CacheDisable ? "CD" : "--",
2114 Pml4e.n.u3Reserved & 2 ? "!" : "..",/* mbz */
2115 Pml4e.n.u1NoExecute ? "NX" : "--",
2116 Pml4e.u & RT_BIT_64(9) ? '1' : '0',
2117 Pml4e.u & RT_BIT_64(10) ? '1' : '0',
2118 Pml4e.u & RT_BIT_64(11) ? '1' : '0',
2119 Pml4e.u & X86_PML4E_PG_MASK);
2120 if (pState->fDumpPageInfo)
2121 pgmR3DumpHierarchyGstPageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK, _4K);
2122 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pml4e.u);
2123 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2124
2125 if (cMaxDepth)
2126 {
2127 int rc2 = pgmR3DumpHierarchyGstPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
2128 if (rc2 < rc && RT_SUCCESS(rc))
2129 rc = rc2;
2130 }
2131 else
2132 pState->cLeaves++;
2133 }
2134 }
2135
2136 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2137 return rc;
2138}
2139
2140
2141/**
2142 * Dumps a 32-bit shadow page table.
2143 *
2144 * @returns VBox status code (VINF_SUCCESS).
2145 * @param pState The dumper state.
2146 * @param GCPhys The physical address of the table.
2147 */
2148static int pgmR3DumpHierarchyGst32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys)
2149{
2150 PCX86PT pPT;
2151 PGMPAGEMAPLOCK Lock;
2152 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
2153 if (RT_FAILURE(rc))
2154 return rc;
2155
2156 uint32_t iFirst, iLast;
2157 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2158 for (uint32_t i = iFirst; i <= iLast; i++)
2159 {
2160 X86PTE Pte = pPT->a[i];
2161 if (Pte.n.u1Present)
2162 {
2163 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
2164 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
2165 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
2166 pState->u64Address,
2167 Pte.n.u1Write ? 'W' : 'R',
2168 Pte.n.u1User ? 'U' : 'S',
2169 Pte.n.u1Accessed ? 'A' : '-',
2170 Pte.n.u1Dirty ? 'D' : '-',
2171 Pte.n.u1Global ? 'G' : '-',
2172 Pte.n.u1WriteThru ? "WT" : "--",
2173 Pte.n.u1CacheDisable ? "CD" : "--",
2174 Pte.n.u1PAT ? "AT" : "--",
2175 Pte.u & RT_BIT_32(9) ? '1' : '0',
2176 Pte.u & RT_BIT_32(10) ? '1' : '0',
2177 Pte.u & RT_BIT_32(11) ? '1' : '0',
2178 Pte.u & X86_PDE_PG_MASK);
2179 if (pState->fDumpPageInfo)
2180 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
2181 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2182 }
2183 }
2184
2185 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2186 return VINF_SUCCESS;
2187}
2188
2189
2190/**
2191 * Dumps a 32-bit shadow page directory and page tables.
2192 *
2193 * @returns VBox status code (VINF_SUCCESS).
2194 * @param pState The dumper state.
2195 * @param GCPhys The physical address of the table.
2196 * @param cMaxDepth The maximum depth.
2197 */
2198static int pgmR3DumpHierarchyGst32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2199{
2200 if (pState->u64Address >= _4G)
2201 return VINF_SUCCESS;
2202
2203 PCX86PD pPD;
2204 PGMPAGEMAPLOCK Lock;
2205 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
2206 if (RT_FAILURE(rc))
2207 return rc;
2208
2209 Assert(cMaxDepth > 0);
2210 cMaxDepth--;
2211
2212 uint32_t iFirst, iLast;
2213 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2214 for (uint32_t i = iFirst; i <= iLast; i++)
2215 {
2216 X86PDE Pde = pPD->a[i];
2217 if (Pde.n.u1Present)
2218 {
2219 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
2220 if (Pde.b.u1Size && pState->fPse)
2221 {
2222 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
2223 | (Pde.u & X86_PDE4M_PG_MASK);
2224 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2225 "%08llx 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
2226 pState->u64Address,
2227 Pde.b.u1Write ? 'W' : 'R',
2228 Pde.b.u1User ? 'U' : 'S',
2229 Pde.b.u1Accessed ? 'A' : '-',
2230 Pde.b.u1Dirty ? 'D' : '-',
2231 Pde.b.u1Global ? 'G' : '-',
2232 Pde.b.u1WriteThru ? "WT" : "--",
2233 Pde.b.u1CacheDisable ? "CD" : "--",
2234 Pde.b.u1PAT ? "AT" : "--",
2235 Pde.u & RT_BIT_32(9) ? '1' : '0',
2236 Pde.u & RT_BIT_32(10) ? '1' : '0',
2237 Pde.u & RT_BIT_32(11) ? '1' : '0',
2238 u64Phys);
2239 if (pState->fDumpPageInfo)
2240 pgmR3DumpHierarchyGstPageInfo(pState, u64Phys, _4M);
2241 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2242 pState->cLeaves++;
2243 }
2244 else
2245 {
2246 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2247 "%08llx 0 | P %c %c %c %c %c %s %s .. .. .. %c%c%c %08x",
2248 pState->u64Address,
2249 Pde.n.u1Write ? 'W' : 'R',
2250 Pde.n.u1User ? 'U' : 'S',
2251 Pde.n.u1Accessed ? 'A' : '-',
2252 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2253 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2254 Pde.n.u1WriteThru ? "WT" : "--",
2255 Pde.n.u1CacheDisable ? "CD" : "--",
2256 Pde.u & RT_BIT_32(9) ? '1' : '0',
2257 Pde.u & RT_BIT_32(10) ? '1' : '0',
2258 Pde.u & RT_BIT_32(11) ? '1' : '0',
2259 Pde.u & X86_PDE_PG_MASK);
2260 if (pState->fDumpPageInfo)
2261 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PG_MASK, _4K);
2262 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2263
2264 if (cMaxDepth)
2265 {
2266 int rc2 = pgmR3DumpHierarchyGst32BitPT(pState, Pde.u & X86_PDE_PG_MASK);
2267 if (rc2 < rc && RT_SUCCESS(rc))
2268 rc = rc2;
2269 }
2270 else
2271 pState->cLeaves++;
2272 }
2273 }
2274 }
2275
2276 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2277 return rc;
2278}
2279
2280
2281/**
2282 * Internal worker that initiates the actual dump.
2283 *
2284 * @returns VBox status code.
2285 * @param pState The dumper state.
2286 * @param cr3 The CR3 value.
2287 * @param cMaxDepth The max depth.
2288 */
2289static int pgmR3DumpHierarchyGstDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
2290{
2291 int rc;
2292 unsigned const cch = pState->cchAddress;
2293 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK
2294 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
2295 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
2296 : X86_CR3_PAGE_MASK;
2297 if (pState->fPrintCr3)
2298 {
2299 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
2300 : pState->fLme ? "Long Mode"
2301 : pState->fPae ? "PAE Mode"
2302 : pState->fPse ? "32-bit w/ PSE"
2303 : "32-bit";
2304 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
2305 if (pState->fDumpPageInfo)
2306 pgmR3DumpHierarchyGstPageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK, _4K);
2307 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
2308 pszMode,
2309 pState->fNp ? " + Nested Paging" : "",
2310 pState->fNxe ? " + NX" : "");
2311 }
2312
2313
2314 if (pState->fEpt)
2315 {
2316 if (pState->fPrintHeader)
2317 pState->pHlp->pfnPrintf(pState->pHlp,
2318 "%-*s R - Readable\n"
2319 "%-*s | W - Writeable\n"
2320 "%-*s | | X - Executable\n"
2321 "%-*s | | | EMT - EPT memory type\n"
2322 "%-*s | | | | PAT - Ignored PAT?\n"
2323 "%-*s | | | | | AVL1 - 4 available bits\n"
2324 "%-*s | | | | | | AVL2 - 12 available bits\n"
2325 "%-*s Level | | | | | | | page \n"
2326 /* xxxx n **** R W X EMT PAT AVL1 AVL2 xxxxxxxxxxxxx
2327 R W X 7 0 f fff 0123456701234567 */
2328 ,
2329 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
2330
2331 pState->pHlp->pfnPrintf(pState->pHlp, "EPT dumping is not yet implemented, sorry.\n");
2332 /** @todo implemented EPT dumping. */
2333 rc = VERR_NOT_IMPLEMENTED;
2334 }
2335 else
2336 {
2337 if (pState->fPrintHeader)
2338 pState->pHlp->pfnPrintf(pState->pHlp,
2339 "%-*s P - Present\n"
2340 "%-*s | R/W - Read (0) / Write (1)\n"
2341 "%-*s | | U/S - User (1) / Supervisor (0)\n"
2342 "%-*s | | | A - Accessed\n"
2343 "%-*s | | | | D - Dirty\n"
2344 "%-*s | | | | | G - Global\n"
2345 "%-*s | | | | | | WT - Write thru\n"
2346 "%-*s | | | | | | | CD - Cache disable\n"
2347 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
2348 "%-*s | | | | | | | | | NX - No execute (K8)\n"
2349 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
2350 "%-*s | | | | | | | | | | | AVL - 3 available bits.\n"
2351 "%-*s Level | | | | | | | | | | | | Page\n"
2352 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
2353 - W U - - - -- -- -- -- -- 010 */
2354 ,
2355 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
2356 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
2357 if (pState->fLme)
2358 rc = pgmR3DumpHierarchyGstPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
2359 else if (pState->fPae)
2360 rc = pgmR3DumpHierarchyGstPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
2361 else
2362 rc = pgmR3DumpHierarchyGst32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
2363 }
2364
2365 if (!pState->cLeaves)
2366 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
2367 return rc;
2368}
2369
2370
2371/**
2372 * dbgfR3PagingDumpEx worker.
2373 *
2374 * @returns VBox status code.
2375 * @param pVM Pointer to the VM.
2376 * @param cr3 The CR3 register value.
2377 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
2378 * @param FirstAddr The start address.
2379 * @param LastAddr The address to stop after.
2380 * @param cMaxDepth The max depth.
2381 * @param pHlp The output callbacks. Defaults to log if NULL.
2382 *
2383 * @internal
2384 */
2385VMMR3_INT_DECL(int) PGMR3DumpHierarchyGst(PVM pVM, uint64_t cr3, uint32_t fFlags, RTGCPTR FirstAddr, RTGCPTR LastAddr,
2386 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
2387{
2388 /* Minimal validation as we're only supposed to service DBGF. */
2389 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2390 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
2391 AssertReturn(fFlags & DBGFPGDMP_FLAGS_GUEST, VERR_INVALID_PARAMETER);
2392
2393 PGMR3DUMPHIERARCHYSTATE State;
2394 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, FirstAddr, LastAddr, pHlp);
2395 return pgmR3DumpHierarchyGstDoIt(&State, cr3, cMaxDepth);
2396}
2397
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