VirtualBox

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

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

DBGF,DBGC,++: PVM -> PUVM. Some refactoring and cleanup as well.

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