VirtualBox

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

Last change on this file since 56296 was 56287, checked in by vboxsync, 9 years ago

VMM: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 100.2 KB
Line 
1/* $Id: PGMDbg.cpp 56287 2015-06-09 11:15:22Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - Debugger & Debugging APIs.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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