VirtualBox

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

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

grumble

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