VirtualBox

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

Last change on this file was 103359, checked in by vboxsync, 3 months ago

VMM/DBGF,PDMLdr,PGM: Addressed parfait's complaints about uninitialized variables. bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 151.7 KB
Line 
1/* $Id: PGMDbg.cpp 103359 2024-02-14 14:39:26Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - Debugger & Debugging APIs.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_PGM
33/** @todo define VBOX_WITHOUT_PAGING_BIT_FIELDS - not so important here, should only be reading for debugging purposes. */
34#include <VBox/vmm/pgm.h>
35#include <VBox/vmm/stam.h>
36#include "PGMInternal.h"
37#include <VBox/vmm/vmcc.h>
38#include <VBox/vmm/uvm.h>
39#include "PGMInline.h"
40#include <iprt/assert.h>
41#include <iprt/asm.h>
42#include <iprt/string.h>
43#include <VBox/log.h>
44#include <VBox/param.h>
45#include <VBox/err.h>
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51/** The max needle size that we will bother searching for
52 * This must not be more than half a page! */
53#define MAX_NEEDLE_SIZE 256
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59/**
60 * State structure for the paging hierarchy dumpers.
61 */
62typedef struct PGMR3DUMPHIERARCHYSTATE
63{
64 /** Pointer to the VM. */
65 PVM pVM;
66 /** Output helpers. */
67 PCDBGFINFOHLP pHlp;
68 /** Set if PSE, PAE or long mode is enabled. */
69 bool fPse;
70 /** Set if PAE or long mode is enabled. */
71 bool fPae;
72 /** Set if long mode is enabled. */
73 bool fLme;
74 /** Set if nested paging. */
75 bool fNp;
76 /** Set if EPT. */
77 bool fEpt;
78 /** Set if NXE is enabled. */
79 bool fNxe;
80 /** The number or chars the address needs. */
81 uint8_t cchAddress;
82 /** The last reserved bit. */
83 uint8_t uLastRsvdBit;
84 /** Dump the page info as well (shadow page summary / guest physical
85 * page summary). */
86 bool fDumpPageInfo;
87 /** Whether or not to print the header. */
88 bool fPrintHeader;
89 /** Whether to print the CR3 value */
90 bool fPrintCr3;
91 /** Padding*/
92 bool afReserved[5];
93 /** The current address. */
94 uint64_t u64Address;
95 /** The last address to dump structures for. */
96 uint64_t u64FirstAddress;
97 /** The last address to dump structures for. */
98 uint64_t u64LastAddress;
99 /** Mask with the high reserved bits set. */
100 uint64_t u64HighReservedBits;
101 /** The number of leaf entries that we've printed. */
102 uint64_t cLeaves;
103} PGMR3DUMPHIERARCHYSTATE;
104/** Pointer to the paging hierarchy dumper state. */
105typedef PGMR3DUMPHIERARCHYSTATE *PPGMR3DUMPHIERARCHYSTATE;
106
107
108/**
109 * Assembly scanning function.
110 *
111 * @returns Pointer to possible match or NULL.
112 * @param pbHaystack Pointer to what we search in.
113 * @param cbHaystack Number of bytes to search.
114 * @param pbNeedle Pointer to what we search for.
115 * @param cbNeedle Size of what we're searching for.
116 */
117
118typedef DECLCALLBACKTYPE(uint8_t const *, FNPGMR3DBGFIXEDMEMSCAN,(uint8_t const *pbHaystack, uint32_t cbHaystack,
119 uint8_t const *pbNeedle, size_t cbNeedle));
120/** Pointer to an fixed size and step assembly scanner function. */
121typedef FNPGMR3DBGFIXEDMEMSCAN *PFNPGMR3DBGFIXEDMEMSCAN;
122
123
124/*********************************************************************************************************************************
125* Internal Functions *
126*********************************************************************************************************************************/
127#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
128DECLASM(uint8_t const *) pgmR3DbgFixedMemScan8Wide8Step(uint8_t const *, uint32_t, uint8_t const *, size_t);
129DECLASM(uint8_t const *) pgmR3DbgFixedMemScan4Wide4Step(uint8_t const *, uint32_t, uint8_t const *, size_t);
130DECLASM(uint8_t const *) pgmR3DbgFixedMemScan2Wide2Step(uint8_t const *, uint32_t, uint8_t const *, size_t);
131DECLASM(uint8_t const *) pgmR3DbgFixedMemScan1Wide1Step(uint8_t const *, uint32_t, uint8_t const *, size_t);
132DECLASM(uint8_t const *) pgmR3DbgFixedMemScan4Wide1Step(uint8_t const *, uint32_t, uint8_t const *, size_t);
133DECLASM(uint8_t const *) pgmR3DbgFixedMemScan8Wide1Step(uint8_t const *, uint32_t, uint8_t const *, size_t);
134#endif
135
136
137/*********************************************************************************************************************************
138* Global Variables *
139*********************************************************************************************************************************/
140static char const g_aaszEptMemType[2][8][3] =
141{
142 { "--", "!1", "!2", "!3", "!4", "!5", "!6", "!7" }, /* non-leaf */
143 { "UC", "WC", "2!", "3!", "WT", "WP", "WB", "7!" } /* leaf */
144};
145
146
147/**
148 * Converts a R3 pointer to a GC physical address.
149 *
150 * Only for the debugger.
151 *
152 * @returns VBox status code.
153 * @retval VINF_SUCCESS on success, *pGCPhys is set.
154 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
155 *
156 * @param pUVM The user mode VM handle.
157 * @param R3Ptr The R3 pointer to convert.
158 * @param pGCPhys Where to store the GC physical address on success.
159 */
160VMMR3DECL(int) PGMR3DbgR3Ptr2GCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTGCPHYS pGCPhys)
161{
162 NOREF(pUVM); NOREF(R3Ptr);
163 *pGCPhys = NIL_RTGCPHYS;
164 return VERR_NOT_IMPLEMENTED;
165}
166
167
168/**
169 * Converts a R3 pointer to a HC physical address.
170 *
171 * Only for the debugger.
172 *
173 * @returns VBox status code.
174 * @retval VINF_SUCCESS on success, *pHCPhys is set.
175 * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical page but has no physical backing.
176 * @retval VERR_INVALID_POINTER if the pointer is not within the GC physical memory.
177 *
178 * @param pUVM The user mode VM handle.
179 * @param R3Ptr The R3 pointer to convert.
180 * @param pHCPhys Where to store the HC physical address on success.
181 */
182VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys)
183{
184 NOREF(pUVM); NOREF(R3Ptr);
185 *pHCPhys = NIL_RTHCPHYS;
186 return VERR_NOT_IMPLEMENTED;
187}
188
189
190/**
191 * Converts a HC physical address to a GC physical address.
192 *
193 * Only for the debugger.
194 *
195 * @returns VBox status code
196 * @retval VINF_SUCCESS on success, *pGCPhys is set.
197 * @retval VERR_INVALID_POINTER if the HC physical address is not within the GC physical memory.
198 *
199 * @param pUVM The user mode VM handle.
200 * @param HCPhys The HC physical address to convert.
201 * @param pGCPhys Where to store the GC physical address on success.
202 */
203VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PUVM pUVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys)
204{
205 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
206 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
207
208 /*
209 * Validate and adjust the input a bit.
210 */
211 if (HCPhys == NIL_RTHCPHYS)
212 return VERR_INVALID_POINTER;
213 unsigned off = HCPhys & GUEST_PAGE_OFFSET_MASK;
214 HCPhys &= X86_PTE_PAE_PG_MASK;
215 if (HCPhys == 0)
216 return VERR_INVALID_POINTER;
217
218 for (PPGMRAMRANGE pRam = pUVM->pVM->pgm.s.CTX_SUFF(pRamRangesX);
219 pRam;
220 pRam = pRam->CTX_SUFF(pNext))
221 {
222 uint32_t iPage = pRam->cb >> GUEST_PAGE_SHIFT;
223 while (iPage-- > 0)
224 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
225 {
226 *pGCPhys = pRam->GCPhys + (iPage << GUEST_PAGE_SHIFT) + off;
227 return VINF_SUCCESS;
228 }
229 }
230 return VERR_INVALID_POINTER;
231}
232
233
234/**
235 * Read physical memory API for the debugger, similar to
236 * PGMPhysSimpleReadGCPhys.
237 *
238 * @returns VBox status code.
239 *
240 * @param pVM The cross context VM structure.
241 * @param pvDst Where to store what's read.
242 * @param GCPhysSrc Where to start reading from.
243 * @param cb The number of bytes to attempt reading.
244 * @param fFlags Flags, MBZ.
245 * @param pcbRead For store the actual number of bytes read, pass NULL if
246 * partial reads are unwanted.
247 * @todo Unused?
248 */
249VMMR3_INT_DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
250{
251 /* validate */
252 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
253 AssertReturn(pVM, VERR_INVALID_PARAMETER);
254
255 /* try simple first. */
256 int rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cb);
257 if (RT_SUCCESS(rc) || !pcbRead)
258 return rc;
259
260 /* partial read that failed, chop it up in pages. */
261 *pcbRead = 0;
262 rc = VINF_SUCCESS;
263 while (cb > 0)
264 {
265 size_t cbChunk = GUEST_PAGE_SIZE;
266 cbChunk -= GCPhysSrc & GUEST_PAGE_OFFSET_MASK;
267 if (cbChunk > cb)
268 cbChunk = cb;
269
270 rc = PGMPhysSimpleReadGCPhys(pVM, pvDst, GCPhysSrc, cbChunk);
271
272 /* advance */
273 if (RT_FAILURE(rc))
274 break;
275 *pcbRead += cbChunk;
276 cb -= cbChunk;
277 GCPhysSrc += cbChunk;
278 pvDst = (uint8_t *)pvDst + cbChunk;
279 }
280
281 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
282}
283
284
285/**
286 * Write physical memory API for the debugger, similar to
287 * PGMPhysSimpleWriteGCPhys.
288 *
289 * @returns VBox status code.
290 *
291 * @param pVM The cross context VM structure.
292 * @param GCPhysDst Where to start writing.
293 * @param pvSrc What to write.
294 * @param cb The number of bytes to attempt writing.
295 * @param fFlags Flags, MBZ.
296 * @param pcbWritten For store the actual number of bytes written, pass NULL
297 * if partial writes are unwanted.
298 * @todo Unused?
299 */
300VMMR3_INT_DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
301{
302 /* validate */
303 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
304 AssertReturn(pVM, VERR_INVALID_PARAMETER);
305
306 /* try simple first. */
307 int rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cb);
308 if (RT_SUCCESS(rc) || !pcbWritten)
309 return rc;
310
311 /* partial write that failed, chop it up in pages. */
312 *pcbWritten = 0;
313 rc = VINF_SUCCESS;
314 while (cb > 0)
315 {
316 size_t cbChunk = GUEST_PAGE_SIZE;
317 cbChunk -= GCPhysDst & GUEST_PAGE_OFFSET_MASK;
318 if (cbChunk > cb)
319 cbChunk = cb;
320
321 rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysDst, pvSrc, cbChunk);
322
323 /* advance */
324 if (RT_FAILURE(rc))
325 break;
326 *pcbWritten += cbChunk;
327 cb -= cbChunk;
328 GCPhysDst += cbChunk;
329 pvSrc = (uint8_t const *)pvSrc + cbChunk;
330 }
331
332 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
333
334}
335
336
337/**
338 * Read virtual memory API for the debugger, similar to PGMPhysSimpleReadGCPtr.
339 *
340 * @returns VBox status code.
341 *
342 * @param pVM The cross context VM structure.
343 * @param pvDst Where to store what's read.
344 * @param GCPtrSrc Where to start reading from.
345 * @param cb The number of bytes to attempt reading.
346 * @param fFlags Flags, MBZ.
347 * @param pcbRead For store the actual number of bytes read, pass NULL if
348 * partial reads are unwanted.
349 * @todo Unused?
350 */
351VMMR3_INT_DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead)
352{
353 /* validate */
354 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
355 AssertReturn(pVM, VERR_INVALID_PARAMETER);
356
357 /** @todo SMP support! */
358 PVMCPU pVCpu = pVM->apCpusR3[0];
359
360/** @todo deal with HMA */
361 /* try simple first. */
362 int rc = PGMPhysSimpleReadGCPtr(pVCpu, pvDst, GCPtrSrc, cb);
363 if (RT_SUCCESS(rc) || !pcbRead)
364 return rc;
365
366 /* partial read that failed, chop it up in pages. */
367 *pcbRead = 0;
368 rc = VINF_SUCCESS;
369 while (cb > 0)
370 {
371 size_t cbChunk = GUEST_PAGE_SIZE;
372 cbChunk -= GCPtrSrc & GUEST_PAGE_OFFSET_MASK;
373 if (cbChunk > cb)
374 cbChunk = cb;
375
376 rc = PGMPhysSimpleReadGCPtr(pVCpu, pvDst, GCPtrSrc, cbChunk);
377
378 /* advance */
379 if (RT_FAILURE(rc))
380 break;
381 *pcbRead += cbChunk;
382 cb -= cbChunk;
383 GCPtrSrc += cbChunk;
384 pvDst = (uint8_t *)pvDst + cbChunk;
385 }
386
387 return *pcbRead && RT_FAILURE(rc) ? -rc : rc;
388
389}
390
391
392/**
393 * Write virtual memory API for the debugger, similar to
394 * PGMPhysSimpleWriteGCPtr.
395 *
396 * @returns VBox status code.
397 *
398 * @param pVM The cross context VM structure.
399 * @param GCPtrDst Where to start writing.
400 * @param pvSrc What to write.
401 * @param cb The number of bytes to attempt writing.
402 * @param fFlags Flags, MBZ.
403 * @param pcbWritten For store the actual number of bytes written, pass NULL
404 * if partial writes are unwanted.
405 * @todo Unused?
406 */
407VMMR3_INT_DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten)
408{
409 /* validate */
410 AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
411 AssertReturn(pVM, VERR_INVALID_PARAMETER);
412
413 /** @todo SMP support! */
414 PVMCPU pVCpu = pVM->apCpusR3[0];
415
416/** @todo deal with HMA */
417 /* try simple first. */
418 int rc = PGMPhysSimpleWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cb);
419 if (RT_SUCCESS(rc) || !pcbWritten)
420 return rc;
421
422 /* partial write that failed, chop it up in pages. */
423 *pcbWritten = 0;
424 rc = VINF_SUCCESS;
425 while (cb > 0)
426 {
427 size_t cbChunk = GUEST_PAGE_SIZE;
428 cbChunk -= GCPtrDst & GUEST_PAGE_OFFSET_MASK;
429 if (cbChunk > cb)
430 cbChunk = cb;
431
432 rc = PGMPhysSimpleWriteGCPtr(pVCpu, GCPtrDst, pvSrc, cbChunk);
433
434 /* advance */
435 if (RT_FAILURE(rc))
436 break;
437 *pcbWritten += cbChunk;
438 cb -= cbChunk;
439 GCPtrDst += cbChunk;
440 pvSrc = (uint8_t const *)pvSrc + cbChunk;
441 }
442
443 return *pcbWritten && RT_FAILURE(rc) ? -rc : rc;
444
445}
446
447
448#if !defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86)
449/*
450 * For AMD64 and x86 we've got optimized assembly code for these search functions.
451 */
452
453static DECLCALLBACK(uint8_t const *) pgmR3DbgFixedMemScan8Wide8Step(uint8_t const *pbHaystack, uint32_t cbHaystack,
454 uint8_t const *pbNeedle, size_t cbNeedle)
455{
456 Assert(cbNeedle >= 8); RT_NOREF(cbNeedle);
457 const uint64_t uNeedle = *(const uint64_t *)pbNeedle;
458 uint64_t const *puHaystack = (uint64_t const *)pbHaystack;
459 cbHaystack /= sizeof(uint64_t);
460 while (cbHaystack-- > 0)
461 if (*puHaystack != uNeedle)
462 puHaystack++;
463 else
464 return (uint8_t const *)puHaystack;
465 return NULL;
466}
467
468
469static DECLCALLBACK(uint8_t const *) pgmR3DbgFixedMemScan4Wide4Step(uint8_t const *pbHaystack, uint32_t cbHaystack,
470 uint8_t const *pbNeedle, size_t cbNeedle)
471{
472 Assert(cbNeedle >= 4); RT_NOREF(cbNeedle);
473 const uint32_t uNeedle = *(const uint32_t *)pbNeedle;
474 uint32_t const *puHaystack = (uint32_t const *)pbHaystack;
475 cbHaystack /= sizeof(uint32_t);
476 while (cbHaystack-- > 0)
477 if (*puHaystack != uNeedle)
478 puHaystack++;
479 else
480 return (uint8_t const *)puHaystack;
481 return NULL;
482}
483
484
485static DECLCALLBACK(uint8_t const *) pgmR3DbgFixedMemScan2Wide2Step(uint8_t const *pbHaystack, uint32_t cbHaystack,
486 uint8_t const *pbNeedle, size_t cbNeedle)
487{
488 Assert(cbNeedle >= 2); RT_NOREF(cbNeedle);
489 const uint16_t uNeedle = *(const uint16_t *)pbNeedle;
490 uint16_t const *puHaystack = (uint16_t const *)pbHaystack;
491 cbHaystack /= sizeof(uint16_t);
492 while (cbHaystack-- > 0)
493 if (*puHaystack != uNeedle)
494 puHaystack++;
495 else
496 return (uint8_t const *)puHaystack;
497 return NULL;
498}
499
500static DECLCALLBACK(uint8_t const *) pgmR3DbgFixedMemScan1Wide1Step(uint8_t const *pbHaystack, uint32_t cbHaystack,
501 uint8_t const *pbNeedle, size_t cbNeedle)
502{
503 Assert(cbNeedle >= 1); RT_NOREF(cbNeedle);
504 const uint8_t bNeedle = *pbNeedle;
505 while (cbHaystack-- > 0)
506 if (*pbHaystack != bNeedle)
507 pbHaystack++;
508 else
509 return pbHaystack;
510 return NULL;
511}
512
513
514static DECLCALLBACK(uint8_t const *) pgmR3DbgFixedMemScan4Wide1Step(uint8_t const *pbHaystack, uint32_t cbHaystack,
515 uint8_t const *pbNeedle, size_t cbNeedle)
516{
517 Assert(cbNeedle >= 4); RT_NOREF(cbNeedle);
518 uint32_t const uNeedle = *(uint32_t const *)pbNeedle;
519 while (cbHaystack >= sizeof(uint32_t))
520 {
521 uint8_t const *pbHit = (uint8_t const *)memchr(pbHaystack, (uint8_t)uNeedle, cbHaystack - sizeof(uint32_t) + 1);
522 if (pbHit)
523 {
524 uint32_t const uFound = !((uintptr_t)pbHit & 3) ? *(const uint32_t *)pbHit
525 : RT_MAKE_U32_FROM_U8(pbHit[0], pbHit[1], pbHit[2], pbHit[3]);
526 if (uFound == uNeedle)
527 return pbHit;
528 cbHaystack -= (uintptr_t)pbHit - (uintptr_t)pbHaystack + 1;
529 pbHaystack = pbHit + 1;
530 }
531 else
532 break;
533 }
534 return NULL;
535}
536
537
538static DECLCALLBACK(uint8_t const *) pgmR3DbgFixedMemScan8Wide1Step(uint8_t const *pbHaystack, uint32_t cbHaystack,
539 uint8_t const *pbNeedle, size_t cbNeedle)
540{
541 Assert(cbNeedle >= 8); RT_NOREF(cbNeedle);
542 uint64_t const uNeedle = *(uint64_t const *)pbNeedle;
543 while (cbHaystack >= sizeof(uint64_t))
544 {
545 uint8_t const *pbHit = (uint8_t const *)memchr(pbHaystack, (uint8_t)uNeedle, cbHaystack - sizeof(uint64_t) + 1);
546 if (pbHit)
547 {
548 uint32_t const uFound = !((uintptr_t)pbHit & 7) ? *(const uint32_t *)pbHit
549 : RT_MAKE_U64_FROM_U8(pbHit[0], pbHit[1], pbHit[2], pbHit[3],
550 pbHit[4], pbHit[5], pbHit[6], pbHit[7]);
551 if (uFound == uNeedle)
552 return pbHit;
553 cbHaystack -= (uintptr_t)pbHit - (uintptr_t)pbHaystack + 1;
554 pbHaystack = pbHit + 1;
555 }
556 else
557 break;
558 }
559 return NULL;
560}
561
562#endif /* !defined(RT_ARCH_AMD64) && !defined(RT_ARCH_X86) */
563
564
565/**
566 * memchr() with alignment considerations.
567 *
568 * @returns Pointer to matching byte, NULL if none found.
569 * @param pb Where to search. Aligned.
570 * @param b What to search for.
571 * @param cb How much to search .
572 * @param uAlign The alignment restriction of the result.
573 */
574static const uint8_t *pgmR3DbgAlignedMemChr(const uint8_t *pb, uint8_t b, size_t cb, uint32_t uAlign)
575{
576 const uint8_t *pbRet;
577 if (uAlign <= 32)
578 {
579 pbRet = (const uint8_t *)memchr(pb, b, cb);
580 if ((uintptr_t)pbRet & (uAlign - 1))
581 {
582 do
583 {
584 pbRet++;
585 size_t cbLeft = cb - (pbRet - pb);
586 if (!cbLeft)
587 {
588 pbRet = NULL;
589 break;
590 }
591 pbRet = (const uint8_t *)memchr(pbRet, b, cbLeft);
592 } while ((uintptr_t)pbRet & (uAlign - 1));
593 }
594 }
595 else
596 {
597 pbRet = NULL;
598 if (cb)
599 {
600 for (;;)
601 {
602 if (*pb == b)
603 {
604 pbRet = pb;
605 break;
606 }
607 if (cb <= uAlign)
608 break;
609 cb -= uAlign;
610 pb += uAlign;
611 }
612 }
613 }
614 return pbRet;
615}
616
617
618/**
619 * Scans a page for a byte string, keeping track of potential
620 * cross page matches.
621 *
622 * @returns true and *poff on match.
623 * false on mismatch.
624 * @param pbPage Pointer to the current page.
625 * @param poff Input: The offset into the page (aligned).
626 * Output: The page offset of the match on success.
627 * @param cb The number of bytes to search, starting of *poff.
628 * @param uAlign The needle alignment. This is of course less than a page.
629 * @param pabNeedle The byte string to search for.
630 * @param cbNeedle The length of the byte string.
631 * @param pfnFixedMemScan Pointer to assembly scan function, if available for
632 * the given needle and alignment combination.
633 * @param pabPrev The buffer that keeps track of a partial match that we
634 * bring over from the previous page. This buffer must be
635 * at least cbNeedle - 1 big.
636 * @param pcbPrev Input: The number of partial matching bytes from the previous page.
637 * Output: The number of partial matching bytes from this page.
638 * Initialize to 0 before the first call to this function.
639 */
640static bool pgmR3DbgScanPage(const uint8_t *pbPage, int32_t *poff, uint32_t cb, uint32_t uAlign,
641 const uint8_t *pabNeedle, size_t cbNeedle, PFNPGMR3DBGFIXEDMEMSCAN pfnFixedMemScan,
642 uint8_t *pabPrev, size_t *pcbPrev)
643{
644 /*
645 * Try complete any partial match from the previous page.
646 */
647 if (*pcbPrev > 0)
648 {
649 size_t cbPrev = *pcbPrev;
650 Assert(!*poff);
651 Assert(cbPrev < cbNeedle);
652 if (!memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
653 {
654 if (cbNeedle - cbPrev > cb)
655 return false;
656 *poff = -(int32_t)cbPrev;
657 return true;
658 }
659
660 /* check out the remainder of the previous page. */
661 const uint8_t *pb = pabPrev;
662 for (;;)
663 {
664 if (cbPrev <= uAlign)
665 break;
666 cbPrev -= uAlign;
667 pb = pgmR3DbgAlignedMemChr(pb + uAlign, *pabNeedle, cbPrev, uAlign);
668 if (!pb)
669 break;
670 cbPrev = *pcbPrev - (pb - pabPrev);
671 if ( !memcmp(pb + 1, &pabNeedle[1], cbPrev - 1)
672 && !memcmp(pbPage, pabNeedle + cbPrev, cbNeedle - cbPrev))
673 {
674 if (cbNeedle - cbPrev > cb)
675 return false;
676 *poff = -(int32_t)cbPrev;
677 return true;
678 }
679 }
680
681 *pcbPrev = 0;
682 }
683
684 /*
685 * Match the body of the page.
686 */
687 const uint8_t *pb = pbPage + *poff;
688 const uint8_t * const pbEnd = pb + cb;
689 for (;;)
690 {
691 AssertMsg(((uintptr_t)pb & (uAlign - 1)) == 0, ("%#p %#x\n", pb, uAlign));
692 if (pfnFixedMemScan)
693 pb = pfnFixedMemScan(pb, cb, pabNeedle, cbNeedle);
694 else
695 pb = pgmR3DbgAlignedMemChr(pb, *pabNeedle, cb, uAlign);
696 if (!pb)
697 break;
698 cb = pbEnd - pb;
699 if (cb >= cbNeedle)
700 {
701 /* match? */
702 if (!memcmp(pb + 1, &pabNeedle[1], cbNeedle - 1))
703 {
704 *poff = pb - pbPage;
705 return true;
706 }
707 }
708 else
709 {
710 /* partial match at the end of the page? */
711 if (!memcmp(pb + 1, &pabNeedle[1], cb - 1))
712 {
713 /* We're copying one byte more that we really need here, but wtf. */
714 memcpy(pabPrev, pb, cb);
715 *pcbPrev = cb;
716 return false;
717 }
718 }
719
720 /* no match, skip ahead. */
721 if (cb <= uAlign)
722 break;
723 pb += uAlign;
724 cb -= uAlign;
725 }
726
727 return false;
728}
729
730
731static PFNPGMR3DBGFIXEDMEMSCAN pgmR3DbgSelectMemScanFunction(uint32_t GCPhysAlign, size_t cbNeedle)
732{
733 switch (GCPhysAlign)
734 {
735 case 1:
736 if (cbNeedle >= 8)
737 return pgmR3DbgFixedMemScan8Wide1Step;
738 if (cbNeedle >= 4)
739 return pgmR3DbgFixedMemScan4Wide1Step;
740 return pgmR3DbgFixedMemScan1Wide1Step;
741 case 2:
742 if (cbNeedle >= 2)
743 return pgmR3DbgFixedMemScan2Wide2Step;
744 break;
745 case 4:
746 if (cbNeedle >= 4)
747 return pgmR3DbgFixedMemScan4Wide4Step;
748 break;
749 case 8:
750 if (cbNeedle >= 8)
751 return pgmR3DbgFixedMemScan8Wide8Step;
752 break;
753 }
754 return NULL;
755}
756
757
758
759/**
760 * Scans guest physical memory for a byte string.
761 *
762 * @returns VBox status codes:
763 * @retval VINF_SUCCESS and *pGCPtrHit on success.
764 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
765 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
766 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
767 *
768 * @param pVM The cross context VM structure.
769 * @param GCPhys Where to start searching.
770 * @param cbRange The number of bytes to search.
771 * @param GCPhysAlign The alignment of the needle. Must be a power of two
772 * and less or equal to 4GB.
773 * @param pabNeedle The byte string to search for.
774 * @param cbNeedle The length of the byte string. Max 256 bytes.
775 * @param pGCPhysHit Where to store the address of the first occurrence on success.
776 */
777VMMR3_INT_DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign,
778 const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit)
779{
780 /*
781 * Validate and adjust the input a bit.
782 */
783 if (!RT_VALID_PTR(pGCPhysHit))
784 return VERR_INVALID_POINTER;
785 *pGCPhysHit = NIL_RTGCPHYS;
786
787 if ( !RT_VALID_PTR(pabNeedle)
788 || GCPhys == NIL_RTGCPHYS)
789 return VERR_INVALID_POINTER;
790 if (!cbNeedle)
791 return VERR_INVALID_PARAMETER;
792 if (cbNeedle > MAX_NEEDLE_SIZE)
793 return VERR_INVALID_PARAMETER;
794
795 if (!cbRange)
796 return VERR_DBGF_MEM_NOT_FOUND;
797 if (GCPhys + cbNeedle - 1 < GCPhys)
798 return VERR_DBGF_MEM_NOT_FOUND;
799
800 if (!GCPhysAlign)
801 return VERR_INVALID_PARAMETER;
802 if (GCPhysAlign > UINT32_MAX)
803 return VERR_NOT_POWER_OF_TWO;
804 if (GCPhysAlign & (GCPhysAlign - 1))
805 return VERR_INVALID_PARAMETER;
806
807 if (GCPhys & (GCPhysAlign - 1))
808 {
809 RTGCPHYS Adj = GCPhysAlign - (GCPhys & (GCPhysAlign - 1));
810 if ( cbRange <= Adj
811 || GCPhys + Adj < GCPhys)
812 return VERR_DBGF_MEM_NOT_FOUND;
813 GCPhys += Adj;
814 cbRange -= Adj;
815 }
816
817 const bool fAllZero = ASMMemIsZero(pabNeedle, cbNeedle);
818 const uint32_t cIncPages = GCPhysAlign <= GUEST_PAGE_SIZE
819 ? 1
820 : GCPhysAlign >> GUEST_PAGE_SHIFT;
821 const RTGCPHYS GCPhysLast = GCPhys + cbRange - 1 >= GCPhys
822 ? GCPhys + cbRange - 1
823 : ~(RTGCPHYS)0;
824
825 PFNPGMR3DBGFIXEDMEMSCAN pfnMemScan = pgmR3DbgSelectMemScanFunction((uint32_t)GCPhysAlign, cbNeedle);
826
827 /*
828 * Search the memory - ignore MMIO and zero pages, also don't
829 * bother to match across ranges.
830 */
831 PGM_LOCK_VOID(pVM);
832 for (PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRangesX);
833 pRam;
834 pRam = pRam->CTX_SUFF(pNext))
835 {
836 /*
837 * If the search range starts prior to the current ram range record,
838 * adjust the search range and possibly conclude the search.
839 */
840 RTGCPHYS off;
841 if (GCPhys < pRam->GCPhys)
842 {
843 if (GCPhysLast < pRam->GCPhys)
844 break;
845 GCPhys = pRam->GCPhys;
846 off = 0;
847 }
848 else
849 off = GCPhys - pRam->GCPhys;
850 if (off < pRam->cb)
851 {
852 /*
853 * Iterate the relevant pages.
854 */
855 uint8_t abPrev[MAX_NEEDLE_SIZE];
856 size_t cbPrev = 0;
857 const uint32_t cPages = pRam->cb >> GUEST_PAGE_SHIFT;
858 uint32_t iPage = off >> GUEST_PAGE_SHIFT;
859 uint32_t offPage = GCPhys & GUEST_PAGE_OFFSET_MASK;
860 GCPhys &= ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK;
861 for (;; offPage = 0)
862 {
863 PPGMPAGE pPage = &pRam->aPages[iPage];
864 if ( ( !PGM_PAGE_IS_ZERO(pPage)
865 || fAllZero)
866 && !PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)
867 && !PGM_PAGE_IS_BALLOONED(pPage))
868 {
869 void const *pvPage;
870 PGMPAGEMAPLOCK Lock;
871 int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, &pvPage, &Lock);
872 if (RT_SUCCESS(rc))
873 {
874 int32_t offHit = offPage;
875 bool fRc;
876 if (GCPhysAlign < GUEST_PAGE_SIZE)
877 {
878 uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK
879 ? GUEST_PAGE_SIZE - (uint32_t)offPage
880 : (GCPhysLast & GUEST_PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
881 fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPhysAlign,
882 pabNeedle, cbNeedle, pfnMemScan, &abPrev[0], &cbPrev);
883 }
884 else
885 fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
886 && (GCPhysLast - GCPhys) >= cbNeedle;
887 PGMPhysReleasePageMappingLock(pVM, &Lock);
888 if (fRc)
889 {
890 *pGCPhysHit = GCPhys + offHit;
891 PGM_UNLOCK(pVM);
892 return VINF_SUCCESS;
893 }
894 }
895 else
896 cbPrev = 0; /* ignore error. */
897 }
898 else
899 cbPrev = 0;
900
901 /* advance to the next page. */
902 GCPhys += (RTGCPHYS)cIncPages << GUEST_PAGE_SHIFT;
903 if (GCPhys >= GCPhysLast) /* (may not always hit, but we're run out of ranges.) */
904 {
905 PGM_UNLOCK(pVM);
906 return VERR_DBGF_MEM_NOT_FOUND;
907 }
908 iPage += cIncPages;
909 if ( iPage < cIncPages
910 || iPage >= cPages)
911 break;
912 }
913 }
914 }
915 PGM_UNLOCK(pVM);
916 return VERR_DBGF_MEM_NOT_FOUND;
917}
918
919
920/**
921 * Scans (guest) virtual memory for a byte string.
922 *
923 * @returns VBox status codes:
924 * @retval VINF_SUCCESS and *pGCPtrHit on success.
925 * @retval VERR_DBGF_MEM_NOT_FOUND if not found.
926 * @retval VERR_INVALID_POINTER if any of the pointer arguments are invalid.
927 * @retval VERR_INVALID_ARGUMENT if any other arguments are invalid.
928 *
929 * @param pVM The cross context VM structure.
930 * @param pVCpu The cross context virtual CPU structure of the CPU
931 * context to search from.
932 * @param GCPtr Where to start searching.
933 * @param GCPtrAlign The alignment of the needle. Must be a power of two
934 * and less or equal to 4GB.
935 * @param cbRange The number of bytes to search. Max 256 bytes.
936 * @param pabNeedle The byte string to search for.
937 * @param cbNeedle The length of the byte string.
938 * @param pGCPtrHit Where to store the address of the first occurrence on success.
939 */
940VMMR3_INT_DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign,
941 const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPtrHit)
942{
943 VMCPU_ASSERT_EMT(pVCpu);
944
945 /*
946 * Validate and adjust the input a bit.
947 */
948 if (!RT_VALID_PTR(pGCPtrHit))
949 return VERR_INVALID_POINTER;
950 *pGCPtrHit = 0;
951
952 if (!RT_VALID_PTR(pabNeedle))
953 return VERR_INVALID_POINTER;
954 if (!cbNeedle)
955 return VERR_INVALID_PARAMETER;
956 if (cbNeedle > MAX_NEEDLE_SIZE)
957 return VERR_INVALID_PARAMETER;
958
959 if (!cbRange)
960 return VERR_DBGF_MEM_NOT_FOUND;
961 if (GCPtr + cbNeedle - 1 < GCPtr)
962 return VERR_DBGF_MEM_NOT_FOUND;
963
964 if (!GCPtrAlign)
965 return VERR_INVALID_PARAMETER;
966 if (GCPtrAlign > UINT32_MAX)
967 return VERR_NOT_POWER_OF_TWO;
968 if (GCPtrAlign & (GCPtrAlign - 1))
969 return VERR_INVALID_PARAMETER;
970
971 if (GCPtr & (GCPtrAlign - 1))
972 {
973 RTGCPTR Adj = GCPtrAlign - (GCPtr & (GCPtrAlign - 1));
974 if ( cbRange <= Adj
975 || GCPtr + Adj < GCPtr)
976 return VERR_DBGF_MEM_NOT_FOUND;
977 GCPtr += Adj;
978 cbRange -= Adj;
979 }
980
981 /* Only paged protected mode or long mode here, use the physical scan for
982 the other modes. */
983 PGMMODE enmMode = PGMGetGuestMode(pVCpu);
984 AssertReturn(PGMMODE_WITH_PAGING(enmMode), VERR_PGM_NOT_USED_IN_MODE);
985
986 /*
987 * Search the memory - ignore MMIO, zero and not-present pages.
988 */
989 const bool fAllZero = ASMMemIsZero(pabNeedle, cbNeedle);
990 RTGCPTR GCPtrMask = PGMMODE_IS_LONG_MODE(enmMode) ? UINT64_MAX : UINT32_MAX;
991 uint8_t abPrev[MAX_NEEDLE_SIZE];
992 size_t cbPrev = 0;
993 const uint32_t cIncPages = GCPtrAlign <= GUEST_PAGE_SIZE
994 ? 1
995 : GCPtrAlign >> GUEST_PAGE_SHIFT;
996 const RTGCPTR GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
997 ? (GCPtr + cbRange - 1) & GCPtrMask
998 : GCPtrMask;
999 RTGCPTR cPages = (((GCPtrLast - GCPtr) + (GCPtr & GUEST_PAGE_OFFSET_MASK)) >> GUEST_PAGE_SHIFT) + 1;
1000 uint32_t offPage = GCPtr & GUEST_PAGE_OFFSET_MASK;
1001 GCPtr &= ~(RTGCPTR)GUEST_PAGE_OFFSET_MASK;
1002
1003 PFNPGMR3DBGFIXEDMEMSCAN pfnMemScan = pgmR3DbgSelectMemScanFunction((uint32_t)GCPtrAlign, cbNeedle);
1004
1005 VMSTATE enmVMState = pVM->enmVMState;
1006 uint32_t const cYieldCountDownReload = VMSTATE_IS_RUNNING(enmVMState) ? 4096 : 65536;
1007 uint32_t cYieldCountDown = cYieldCountDownReload;
1008 RTGCPHYS GCPhysPrev = NIL_RTGCPHYS;
1009 PGMPTWALK Walk = { NIL_RTGCPTR, NIL_RTGCPHYS, NIL_RTGCPHYS, false };
1010 PGMPTWALKGST WalkGst = { {}, PGMPTWALKGSTTYPE_INVALID };
1011 bool fFullWalk = true;
1012
1013 PGM_LOCK_VOID(pVM);
1014 for (;; offPage = 0)
1015 {
1016 int rc;
1017 if (fFullWalk)
1018 rc = pgmGstPtWalk(pVCpu, GCPtr, &Walk, &WalkGst);
1019 else
1020 rc = pgmGstPtWalkNext(pVCpu, GCPtr, &Walk, &WalkGst);
1021 if (RT_SUCCESS(rc) && Walk.fSucceeded)
1022 {
1023 fFullWalk = false;
1024
1025 /* Skip if same page as previous one (W10 optimization). */
1026 if ( Walk.GCPhys != GCPhysPrev
1027 || cbPrev != 0)
1028 {
1029 PPGMPAGE pPage = pgmPhysGetPage(pVM, Walk.GCPhys);
1030 if ( pPage
1031 && ( !PGM_PAGE_IS_ZERO(pPage)
1032 || fAllZero)
1033 && !PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)
1034 && !PGM_PAGE_IS_BALLOONED(pPage))
1035 {
1036 GCPhysPrev = Walk.GCPhys;
1037 void const *pvPage;
1038 PGMPAGEMAPLOCK Lock;
1039 rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, Walk.GCPhys, &pvPage, &Lock);
1040 if (RT_SUCCESS(rc))
1041 {
1042 int32_t offHit = offPage;
1043 bool fRc;
1044 if (GCPtrAlign < GUEST_PAGE_SIZE)
1045 {
1046 uint32_t cbSearch = cPages > 0
1047 ? GUEST_PAGE_SIZE - (uint32_t)offPage
1048 : (GCPtrLast & GUEST_PAGE_OFFSET_MASK) + 1 - (uint32_t)offPage;
1049 fRc = pgmR3DbgScanPage((uint8_t const *)pvPage, &offHit, cbSearch, (uint32_t)GCPtrAlign,
1050 pabNeedle, cbNeedle, pfnMemScan, &abPrev[0], &cbPrev);
1051 }
1052 else
1053 fRc = memcmp(pvPage, pabNeedle, cbNeedle) == 0
1054 && (GCPtrLast - GCPtr) >= cbNeedle;
1055 PGMPhysReleasePageMappingLock(pVM, &Lock);
1056 if (fRc)
1057 {
1058 *pGCPtrHit = GCPtr + offHit;
1059 PGM_UNLOCK(pVM);
1060 return VINF_SUCCESS;
1061 }
1062 }
1063 else
1064 cbPrev = 0; /* ignore error. */
1065 }
1066 else
1067 cbPrev = 0;
1068 }
1069 else
1070 cbPrev = 0;
1071 }
1072 else
1073 {
1074 Assert(WalkGst.enmType != PGMPTWALKGSTTYPE_INVALID);
1075 Assert(!Walk.fSucceeded);
1076 cbPrev = 0; /* ignore error. */
1077
1078 /*
1079 * Try skip as much as possible. No need to figure out that a PDE
1080 * is not present 512 times!
1081 */
1082 uint64_t cPagesCanSkip;
1083 switch (Walk.uLevel)
1084 {
1085 case 1:
1086 /* page level, use cIncPages */
1087 cPagesCanSkip = 1;
1088 break;
1089 case 2:
1090 if (WalkGst.enmType == PGMPTWALKGSTTYPE_32BIT)
1091 {
1092 cPagesCanSkip = X86_PG_ENTRIES - ((GCPtr >> X86_PT_SHIFT) & X86_PT_MASK);
1093 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PD_SHIFT) - 1)));
1094 }
1095 else
1096 {
1097 cPagesCanSkip = X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
1098 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PD_PAE_SHIFT) - 1)));
1099 }
1100 break;
1101 case 3:
1102 cPagesCanSkip = (X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK)) * X86_PG_PAE_ENTRIES
1103 - ((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
1104 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PDPT_SHIFT) - 1)));
1105 break;
1106 case 4:
1107 cPagesCanSkip = (X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64))
1108 * X86_PG_PAE_ENTRIES * X86_PG_PAE_ENTRIES
1109 - ((((GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK)) * X86_PG_PAE_ENTRIES)
1110 - (( GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
1111 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PML4_SHIFT) - 1)));
1112 break;
1113 case 8:
1114 /* The CR3 value is bad, forget the whole search. */
1115 cPagesCanSkip = cPages;
1116 break;
1117 default:
1118 AssertMsgFailed(("%d\n", Walk.uLevel));
1119 cPagesCanSkip = 0;
1120 break;
1121 }
1122 if (cPages <= cPagesCanSkip)
1123 break;
1124 fFullWalk = true;
1125 if (cPagesCanSkip >= cIncPages)
1126 {
1127 cPages -= cPagesCanSkip;
1128 GCPtr += (RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT;
1129 continue;
1130 }
1131 }
1132
1133 /* advance to the next page. */
1134 if (cPages <= cIncPages)
1135 break;
1136 cPages -= cIncPages;
1137 GCPtr += (RTGCPTR)cIncPages << X86_PT_PAE_SHIFT;
1138
1139 /* Yield the PGM lock every now and then. */
1140 if (!--cYieldCountDown)
1141 {
1142 fFullWalk = PDMR3CritSectYield(pVM, &pVM->pgm.s.CritSectX);
1143 cYieldCountDown = cYieldCountDownReload;
1144 }
1145 }
1146 PGM_UNLOCK(pVM);
1147 return VERR_DBGF_MEM_NOT_FOUND;
1148}
1149
1150
1151/**
1152 * Initializes the dumper state.
1153 *
1154 * @param pState The state to initialize.
1155 * @param pVM The cross context VM structure.
1156 * @param fFlags The flags.
1157 * @param u64FirstAddr The first address.
1158 * @param u64LastAddr The last address.
1159 * @param pHlp The output helpers.
1160 */
1161static void pgmR3DumpHierarchyInitState(PPGMR3DUMPHIERARCHYSTATE pState, PVM pVM, uint32_t fFlags,
1162 uint64_t u64FirstAddr, uint64_t u64LastAddr, PCDBGFINFOHLP pHlp)
1163{
1164 pState->pVM = pVM;
1165 pState->pHlp = pHlp ? pHlp : DBGFR3InfoLogHlp();
1166 pState->fPse = !!(fFlags & (DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
1167 pState->fPae = !!(fFlags & (DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
1168 pState->fLme = !!(fFlags & DBGFPGDMP_FLAGS_LME);
1169 pState->fNp = !!(fFlags & DBGFPGDMP_FLAGS_NP);
1170 pState->fEpt = !!(fFlags & DBGFPGDMP_FLAGS_EPT);
1171 pState->fNxe = !!(fFlags & DBGFPGDMP_FLAGS_NXE);
1172 pState->cchAddress = pState->fLme || pState->fEpt ? 16 : 8;
1173 pState->uLastRsvdBit = pState->fNxe ? 62 : 63;
1174 pState->fDumpPageInfo = !!(fFlags & DBGFPGDMP_FLAGS_PAGE_INFO);
1175 pState->fPrintHeader = !!(fFlags & DBGFPGDMP_FLAGS_HEADER);
1176 pState->fPrintCr3 = !!(fFlags & DBGFPGDMP_FLAGS_PRINT_CR3);
1177 pState->afReserved[0] = false;
1178 pState->afReserved[1] = false;
1179 pState->afReserved[2] = false;
1180 pState->afReserved[3] = false;
1181 pState->afReserved[4] = false;
1182 pState->u64Address = u64FirstAddr;
1183 pState->u64FirstAddress = u64FirstAddr;
1184 pState->u64LastAddress = u64LastAddr;
1185 pState->u64HighReservedBits = pState->uLastRsvdBit == 62 ? UINT64_C(0x7ff) << 52 : UINT64_C(0xfff) << 52;
1186 pState->cLeaves = 0;
1187}
1188
1189
1190/**
1191 * The simple way out, too tired to think of a more elegant solution.
1192 *
1193 * @returns The base address of this page table/directory/whatever.
1194 * @param pState The state where we get the current address.
1195 * @param cShift The shift count for the table entries.
1196 * @param cEntries The number of table entries.
1197 * @param piFirst Where to return the table index of the first
1198 * entry to dump.
1199 * @param piLast Where to return the table index of the last
1200 * entry.
1201 */
1202static uint64_t pgmR3DumpHierarchyCalcRange(PPGMR3DUMPHIERARCHYSTATE pState, uint32_t cShift, uint32_t cEntries,
1203 uint32_t *piFirst, uint32_t *piLast)
1204{
1205 const uint64_t iBase = (pState->u64Address >> cShift) & ~(uint64_t)(cEntries - 1);
1206 const uint64_t iFirst = pState->u64FirstAddress >> cShift;
1207 const uint64_t iLast = pState->u64LastAddress >> cShift;
1208
1209 if ( iBase >= iFirst
1210 && iBase + cEntries - 1 <= iLast)
1211 {
1212 /* full range. */
1213 *piFirst = 0;
1214 *piLast = cEntries - 1;
1215 }
1216 else if ( iBase + cEntries - 1 < iFirst
1217 || iBase > iLast)
1218 {
1219 /* no match */
1220 *piFirst = cEntries;
1221 *piLast = 0;
1222 }
1223 else
1224 {
1225 /* partial overlap */
1226 *piFirst = iBase <= iFirst
1227 ? iFirst - iBase
1228 : 0;
1229 *piLast = iBase + cEntries - 1 <= iLast
1230 ? cEntries - 1
1231 : iLast - iBase;
1232 }
1233
1234 return iBase << cShift;
1235}
1236
1237
1238/**
1239 * Maps/finds the shadow page.
1240 *
1241 * @returns VBox status code.
1242 * @param pState The dumper state.
1243 * @param HCPhys The physical address of the shadow page.
1244 * @param pszDesc The description.
1245 * @param ppv Where to return the pointer.
1246 */
1247static int pgmR3DumpHierarchyShwMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, const char *pszDesc, void const **ppv)
1248{
1249 PPGMPOOLPAGE pPoolPage = pgmPoolQueryPageForDbg(pState->pVM->pgm.s.pPoolR3, HCPhys);
1250 if (pPoolPage)
1251 {
1252 *ppv = (uint8_t *)pPoolPage->pvPageR3 + (HCPhys & GUEST_PAGE_OFFSET_MASK);
1253 return VINF_SUCCESS;
1254 }
1255 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! %s at HCPhys=%RHp was not found in the page pool!\n",
1256 pState->cchAddress, pState->u64Address, pszDesc, HCPhys);
1257 return VERR_PGM_POOL_GET_PAGE_FAILED;
1258}
1259
1260
1261/**
1262 * Dumps the a shadow page summary or smth.
1263 *
1264 * @param pState The dumper state.
1265 * @param HCPhys The page address.
1266 */
1267static void pgmR3DumpHierarchyShwTablePageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1268{
1269 PGM_LOCK_VOID(pState->pVM);
1270 char szPage[80];
1271 PPGMPOOLPAGE pPage = pgmPoolQueryPageForDbg(pState->pVM->pgm.s.CTX_SUFF(pPool), HCPhys);
1272 if (pPage)
1273 RTStrPrintf(szPage, sizeof(szPage), " idx=0i%u", pPage->idx);
1274 else
1275 strcpy(szPage, " not found");
1276 PGM_UNLOCK(pState->pVM);
1277 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
1278}
1279
1280
1281/**
1282 * Figures out which guest page this is and dumps a summary.
1283 *
1284 * @param pState The dumper state.
1285 * @param HCPhys The page address.
1286 * @param cbPage The page size.
1287 */
1288static void pgmR3DumpHierarchyShwGuestPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, uint32_t cbPage)
1289{
1290 char szPage[80];
1291 RTGCPHYS GCPhys;
1292 int rc = PGMR3DbgHCPhys2GCPhys(pState->pVM->pUVM, HCPhys, &GCPhys);
1293 if (RT_SUCCESS(rc))
1294 {
1295 PGM_LOCK_VOID(pState->pVM);
1296 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
1297 if (pPage)
1298 RTStrPrintf(szPage, sizeof(szPage), "%R[pgmpage]", pPage);
1299 else
1300 strcpy(szPage, "not found");
1301 PGM_UNLOCK(pState->pVM);
1302 pState->pHlp->pfnPrintf(pState->pHlp, " -> %RGp %s", GCPhys, szPage);
1303 }
1304 else
1305 pState->pHlp->pfnPrintf(pState->pHlp, " not found");
1306 NOREF(cbPage);
1307}
1308
1309
1310/**
1311 * Dumps an EPT shadow page table.
1312 *
1313 * @returns VBox status code (VINF_SUCCESS).
1314 * @param pState The dumper state.
1315 * @param HCPhys The page table address.
1316 */
1317static int pgmR3DumpHierarchyShwEptPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1318{
1319 PCEPTPT pPT = NULL;
1320 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "EPT level 1", (void const **)&pPT);
1321 if (RT_FAILURE(rc))
1322 return rc;
1323
1324 PVM const pVM = pState->pVM;
1325 uint32_t iFirst, iLast;
1326 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PT_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
1327 for (uint32_t i = iFirst; i <= iLast; i++)
1328 {
1329 uint64_t const u = pPT->a[i].u;
1330 if (u & EPT_PRESENT_MASK)
1331 {
1332 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PT_SHIFT);
1333 if ( (u & (EPT_E_WRITE | EPT_E_MEMTYPE_MASK | EPT_E_READ | EPT_E_EXECUTE))
1334 != (EPT_E_WRITE | EPT_E_MEMTYPE_INVALID_3)
1335 || (u & EPT_E_PG_MASK) != pVM->pgm.s.HCPhysInvMmioPg)
1336 {
1337 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1338 "%016llx 1 | %c%c%c %s %c L %c %c %c %c %c %c %c 4K %016llx",
1339 pState->u64Address,
1340 u & EPT_E_READ ? 'R' : '-',
1341 u & EPT_E_WRITE ? 'W' : '-',
1342 u & EPT_E_EXECUTE ? 'X' : '-',
1343 g_aaszEptMemType[1][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1344 u & EPT_E_IGNORE_PAT ? 'I' : '-',
1345 u & EPT_E_ACCESSED ? 'A' : '-',
1346 u & EPT_E_DIRTY ? 'D' : '-',
1347 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1348 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1349 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1350 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1351 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1352 u & EPT_E_PG_MASK);
1353 if (pState->fDumpPageInfo)
1354 pgmR3DumpHierarchyShwGuestPageInfo(pState, u & EPT_E_PG_MASK, _4K);
1355 //if ((u >> 52) & 0x7ff)
1356 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1357 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1358 }
1359 else
1360 {
1361 const char *pszDesc = "???";
1362 PGM_LOCK_VOID(pVM);
1363 PPGMPHYSHANDLER pHandler;
1364 int rc3 = pgmHandlerPhysicalLookup(pVM, u64BaseAddress, &pHandler);
1365 if (RT_SUCCESS(rc3))
1366 pszDesc = pHandler->pszDesc;
1367 PGM_UNLOCK(pVM);
1368
1369 pState->pHlp->pfnPrintf(pState->pHlp, "%016llx 1 | invalid / MMIO optimization (%s)\n",
1370 pState->u64Address, pszDesc);
1371 }
1372 pState->cLeaves++;
1373 }
1374 }
1375 return VINF_SUCCESS;
1376}
1377
1378
1379/**
1380 * Dumps an EPT shadow page directory table.
1381 *
1382 * @returns VBox status code (VINF_SUCCESS).
1383 * @param pState The dumper state.
1384 * @param HCPhys The physical address of the page directory table.
1385 * @param cMaxDepth The maximum depth.
1386 */
1387static int pgmR3DumpHierarchyShwEptPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1388{
1389 PCEPTPD pPD = NULL;
1390 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "EPT level 2", (void const **)&pPD);
1391 if (RT_FAILURE(rc))
1392 return rc;
1393
1394 Assert(cMaxDepth > 0);
1395 cMaxDepth--;
1396
1397 uint32_t iFirst, iLast;
1398 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PD_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
1399 for (uint32_t i = iFirst; i <= iLast; i++)
1400 {
1401 uint64_t const u = pPD->a[i].u;
1402 if (u & EPT_PRESENT_MASK)
1403 {
1404 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PD_SHIFT);
1405 if (u & EPT_E_LEAF)
1406 {
1407 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1408 "%016llx 2 | %c%c%c %s %c L %c %c %c %c %c %c %c 2M %016llx",
1409 pState->u64Address,
1410 u & EPT_E_READ ? 'R' : '-',
1411 u & EPT_E_WRITE ? 'W' : '-',
1412 u & EPT_E_EXECUTE ? 'X' : '-',
1413 g_aaszEptMemType[1][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1414 u & EPT_E_IGNORE_PAT ? 'I' : '-',
1415 u & EPT_E_ACCESSED ? 'A' : '-',
1416 u & EPT_E_DIRTY ? 'D' : '-',
1417 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1418 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1419 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1420 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1421 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1422 u & EPT_E_PG_MASK);
1423 if (pState->fDumpPageInfo)
1424 pgmR3DumpHierarchyShwGuestPageInfo(pState, u & EPT_PDE2M_PG_MASK, _2M);
1425 //if ((u >> 52) & 0x7ff)
1426 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1427 if (u & EPT_PDE2M_MBZ_MASK)
1428 pState->pHlp->pfnPrintf(pState->pHlp, " 20:12=%02llx!", (u >> 12) & 0x1ff);
1429 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1430
1431 pState->cLeaves++;
1432 }
1433 else
1434 {
1435 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1436 "%016llx 2 | %c%c%c %s %c - %c %c %c %c %c %c %c %016llx",
1437 pState->u64Address,
1438 u & EPT_E_READ ? 'R' : '-',
1439 u & EPT_E_WRITE ? 'W' : '-',
1440 u & EPT_E_EXECUTE ? 'X' : '-',
1441 g_aaszEptMemType[0][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1442 u & EPT_E_IGNORE_PAT ? '!' : '-',
1443 u & EPT_E_ACCESSED ? 'A' : '-',
1444 u & EPT_E_DIRTY ? 'D' : '-',
1445 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1446 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1447 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1448 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1449 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1450 u & EPT_E_PG_MASK);
1451 if (pState->fDumpPageInfo)
1452 pgmR3DumpHierarchyShwTablePageInfo(pState, u & EPT_E_PG_MASK);
1453 //if ((u >> 52) & 0x7ff)
1454 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (u >> 52) & 0x7ff);
1455 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1456
1457 if (cMaxDepth)
1458 {
1459 int rc2 = pgmR3DumpHierarchyShwEptPT(pState, u & EPT_E_PG_MASK);
1460 if (rc2 < rc && RT_SUCCESS(rc))
1461 rc = rc2;
1462 }
1463 else
1464 pState->cLeaves++;
1465 }
1466 }
1467 }
1468 return rc;
1469}
1470
1471
1472/**
1473 * Dumps an EPT shadow page directory pointer table.
1474 *
1475 * @returns VBox status code (VINF_SUCCESS).
1476 * @param pState The dumper state.
1477 * @param HCPhys The physical address of the page directory pointer table.
1478 * @param cMaxDepth The maximum depth.
1479 */
1480static int pgmR3DumpHierarchyShwEptPDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1481{
1482 PCEPTPDPT pPDPT = NULL;
1483 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "EPT level 3", (void const **)&pPDPT);
1484 if (RT_FAILURE(rc))
1485 return rc;
1486
1487 Assert(cMaxDepth > 0);
1488 cMaxDepth--;
1489
1490 uint32_t iFirst, iLast;
1491 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PDPT_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
1492 for (uint32_t i = iFirst; i <= iLast; i++)
1493 {
1494 uint64_t const u = pPDPT->a[i].u;
1495 if (u & EPT_PRESENT_MASK)
1496 {
1497 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PDPT_SHIFT);
1498 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1499 "%016llx 3 | %c%c%c %s %c %c %c %c %c %c %c %c %c %016llx",
1500 pState->u64Address,
1501 u & EPT_E_READ ? 'R' : '-',
1502 u & EPT_E_WRITE ? 'W' : '-',
1503 u & EPT_E_EXECUTE ? 'X' : '-',
1504 g_aaszEptMemType[!!(u & EPT_E_LEAF)][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1505 u & EPT_E_IGNORE_PAT ? '!' : '-',
1506 u & EPT_E_LEAF ? '!' : '-',
1507 u & EPT_E_ACCESSED ? 'A' : '-',
1508 u & EPT_E_DIRTY ? 'D' : '-',
1509 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1510 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1511 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1512 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1513 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1514 u & EPT_E_PG_MASK);
1515 if (pState->fDumpPageInfo)
1516 pgmR3DumpHierarchyShwTablePageInfo(pState, u & EPT_E_PG_MASK);
1517 //if ((u >> 52) & 0x7ff)
1518 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx", (u >> 52) & 0x7ff);
1519 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1520
1521 if (cMaxDepth)
1522 {
1523 int rc2 = pgmR3DumpHierarchyShwEptPD(pState, u & EPT_E_PG_MASK, cMaxDepth);
1524 if (rc2 < rc && RT_SUCCESS(rc))
1525 rc = rc2;
1526 }
1527 else
1528 pState->cLeaves++;
1529 }
1530 }
1531 return rc;
1532}
1533
1534
1535/**
1536 * Dumps an EPT shadow PML4 table.
1537 *
1538 * @returns VBox status code (VINF_SUCCESS).
1539 * @param pState The dumper state.
1540 * @param HCPhys The physical address of the table.
1541 * @param cMaxDepth The maximum depth.
1542 */
1543static int pgmR3DumpHierarchyShwEptPML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1544{
1545 PCEPTPML4 pPML4 = NULL;
1546 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "EPT level 4", (void const **)&pPML4);
1547 if (RT_FAILURE(rc))
1548 return rc;
1549
1550 Assert(cMaxDepth);
1551 cMaxDepth--;
1552
1553 uint32_t iFirst = (pState->u64FirstAddress >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
1554 uint32_t iLast = (pState->u64LastAddress >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
1555 for (uint32_t i = iFirst; i <= iLast; i++)
1556 {
1557 uint64_t const u = pPML4->a[i].u;
1558 if (u & EPT_PRESENT_MASK)
1559 {
1560 pState->u64Address = (uint64_t)i << X86_PML4_SHIFT;
1561 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1562 "%016llx 4 | %c%c%c %s %c %c %c %c %c %c %c %c %c %016llx",
1563 pState->u64Address,
1564 u & EPT_E_READ ? 'R' : '-',
1565 u & EPT_E_WRITE ? 'W' : '-',
1566 u & EPT_E_EXECUTE ? 'X' : '-',
1567 g_aaszEptMemType[!!(u & EPT_E_LEAF)][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1568 u & EPT_E_IGNORE_PAT ? '!' : '-',
1569 u & EPT_E_LEAF ? '!' : '-',
1570 u & EPT_E_ACCESSED ? 'A' : '-',
1571 u & EPT_E_DIRTY ? 'D' : '-',
1572 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1573 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1574 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1575 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1576 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1577 u & EPT_E_PG_MASK);
1578
1579 if (pState->fDumpPageInfo)
1580 pgmR3DumpHierarchyShwTablePageInfo(pState, u & EPT_E_PG_MASK);
1581 //if ((u >> 52) & 0x7ff)
1582 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (u >> 52) & 0x7ff);
1583 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1584
1585 if (cMaxDepth)
1586 {
1587 int rc2 = pgmR3DumpHierarchyShwEptPDPT(pState, u & EPT_E_PG_MASK, cMaxDepth);
1588 if (rc2 < rc && RT_SUCCESS(rc))
1589 rc = rc2;
1590 }
1591 else
1592 pState->cLeaves++;
1593 }
1594 }
1595 return rc;
1596}
1597
1598
1599/**
1600 * Dumps a PAE shadow page table.
1601 *
1602 * @returns VBox status code (VINF_SUCCESS).
1603 * @param pState The dumper state.
1604 * @param HCPhys The page table address.
1605 */
1606static int pgmR3DumpHierarchyShwPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1607{
1608 PCPGMSHWPTPAE pPT = NULL;
1609 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", (void const **)&pPT);
1610 if (RT_FAILURE(rc))
1611 return rc;
1612
1613 uint32_t iFirst, iLast;
1614 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1615 for (uint32_t i = iFirst; i <= iLast; i++)
1616 if (PGMSHWPTEPAE_GET_U(pPT->a[i]) & X86_PTE_P)
1617 {
1618 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
1619 if (PGMSHWPTEPAE_IS_P(pPT->a[i]))
1620 {
1621 X86PTEPAE Pte;
1622 Pte.u = PGMSHWPTEPAE_GET_U(pPT->a[i]);
1623 pState->pHlp->pfnPrintf(pState->pHlp,
1624 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
1625 ? "%016llx 1 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
1626 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
1627 pState->u64Address,
1628 Pte.n.u1Write ? 'W' : 'R',
1629 Pte.n.u1User ? 'U' : 'S',
1630 Pte.n.u1Accessed ? 'A' : '-',
1631 Pte.n.u1Dirty ? 'D' : '-',
1632 Pte.n.u1Global ? 'G' : '-',
1633 Pte.n.u1WriteThru ? "WT" : "--",
1634 Pte.n.u1CacheDisable? "CD" : "--",
1635 Pte.n.u1PAT ? "AT" : "--",
1636 Pte.n.u1NoExecute ? "NX" : "--",
1637 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1638 Pte.u & RT_BIT(10) ? '1' : '-',
1639 Pte.u & RT_BIT(11) ? '1' : '-',
1640 Pte.u & X86_PTE_PAE_PG_MASK);
1641 if (pState->fDumpPageInfo)
1642 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
1643 if ((Pte.u >> 52) & 0x7ff)
1644 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pte.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1645 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1646 }
1647 else if ( (PGMSHWPTEPAE_GET_U(pPT->a[i]) & (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1648 == (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1649 pState->pHlp->pfnPrintf(pState->pHlp,
1650 pState->fLme
1651 ? "%016llx 1 | invalid / MMIO optimization\n"
1652 : "%08llx 1 | invalid / MMIO optimization\n",
1653 pState->u64Address);
1654 else
1655 pState->pHlp->pfnPrintf(pState->pHlp,
1656 pState->fLme
1657 ? "%016llx 1 | invalid: %RX64\n"
1658 : "%08llx 1 | invalid: %RX64\n",
1659 pState->u64Address, PGMSHWPTEPAE_GET_U(pPT->a[i]));
1660 pState->cLeaves++;
1661 }
1662 return VINF_SUCCESS;
1663}
1664
1665
1666/**
1667 * Dumps a PAE shadow page directory table.
1668 *
1669 * @returns VBox status code (VINF_SUCCESS).
1670 * @param pState The dumper state.
1671 * @param HCPhys The physical address of the page directory table.
1672 * @param cMaxDepth The maximum depth.
1673 */
1674static int pgmR3DumpHierarchyShwPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1675{
1676 PCX86PDPAE pPD = NULL;
1677 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", (void const **)&pPD);
1678 if (RT_FAILURE(rc))
1679 return rc;
1680
1681 Assert(cMaxDepth > 0);
1682 cMaxDepth--;
1683
1684 uint32_t iFirst, iLast;
1685 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1686 for (uint32_t i = iFirst; i <= iLast; i++)
1687 {
1688 X86PDEPAE Pde = pPD->a[i];
1689 if (Pde.n.u1Present)
1690 {
1691 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
1692 if (Pde.b.u1Size)
1693 {
1694 pState->pHlp->pfnPrintf(pState->pHlp,
1695 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
1696 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
1697 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
1698 pState->u64Address,
1699 Pde.b.u1Write ? 'W' : 'R',
1700 Pde.b.u1User ? 'U' : 'S',
1701 Pde.b.u1Accessed ? 'A' : '-',
1702 Pde.b.u1Dirty ? 'D' : '-',
1703 Pde.b.u1Global ? 'G' : '-',
1704 Pde.b.u1WriteThru ? "WT" : "--",
1705 Pde.b.u1CacheDisable? "CD" : "--",
1706 Pde.b.u1PAT ? "AT" : "--",
1707 Pde.b.u1NoExecute ? "NX" : "--",
1708 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
1709 '-',
1710 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1711 Pde.u & X86_PDE2M_PAE_PG_MASK);
1712 if (pState->fDumpPageInfo)
1713 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
1714 if ((Pde.u >> 52) & 0x7ff)
1715 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pde.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1716 if ((Pde.u >> 13) & 0xff)
1717 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
1718 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1719
1720 pState->cLeaves++;
1721 }
1722 else
1723 {
1724 pState->pHlp->pfnPrintf(pState->pHlp,
1725 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
1726 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
1727 : "%08llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
1728 pState->u64Address,
1729 Pde.n.u1Write ? 'W' : 'R',
1730 Pde.n.u1User ? 'U' : 'S',
1731 Pde.n.u1Accessed ? 'A' : '-',
1732 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1733 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1734 Pde.n.u1WriteThru ? "WT" : "--",
1735 Pde.n.u1CacheDisable? "CD" : "--",
1736 Pde.n.u1NoExecute ? "NX" : "--",
1737 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
1738 '-',
1739 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1740 Pde.u & X86_PDE_PAE_PG_MASK);
1741 if (pState->fDumpPageInfo)
1742 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1743 if ((Pde.u >> 52) & 0x7ff)
1744 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pde.u >> 52) & 0x7ff);
1745 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1746
1747 if (cMaxDepth)
1748 {
1749 int rc2 = pgmR3DumpHierarchyShwPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1750 if (rc2 < rc && RT_SUCCESS(rc))
1751 rc = rc2;
1752 }
1753 else
1754 pState->cLeaves++;
1755 }
1756 }
1757 }
1758 return rc;
1759}
1760
1761
1762/**
1763 * Dumps a PAE shadow page directory pointer table.
1764 *
1765 * @returns VBox status code (VINF_SUCCESS).
1766 * @param pState The dumper state.
1767 * @param HCPhys The physical address of the page directory pointer table.
1768 * @param cMaxDepth The maximum depth.
1769 */
1770static int pgmR3DumpHierarchyShwPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1771{
1772 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
1773 if (!pState->fLme && pState->u64Address >= _4G)
1774 return VINF_SUCCESS;
1775
1776 PCX86PDPT pPDPT = NULL;
1777 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory pointer table", (void const **)&pPDPT);
1778 if (RT_FAILURE(rc))
1779 return rc;
1780
1781 Assert(cMaxDepth > 0);
1782 cMaxDepth--;
1783
1784 uint32_t iFirst, iLast;
1785 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
1786 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
1787 &iFirst, &iLast);
1788 for (uint32_t i = iFirst; i <= iLast; i++)
1789 {
1790 X86PDPE Pdpe = pPDPT->a[i];
1791 if (Pdpe.n.u1Present)
1792 {
1793 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
1794 if (pState->fLme)
1795 {
1796 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
1797 "%016llx 3 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1798 pState->u64Address,
1799 Pdpe.lm.u1Write ? 'W' : 'R',
1800 Pdpe.lm.u1User ? 'U' : 'S',
1801 Pdpe.lm.u1Accessed ? 'A' : '-',
1802 Pdpe.lm.u3Reserved & 1? '?' : '.', /* ignored */
1803 Pdpe.lm.u3Reserved & 4? '!' : '.', /* mbz */
1804 Pdpe.lm.u1WriteThru ? "WT" : "--",
1805 Pdpe.lm.u1CacheDisable? "CD" : "--",
1806 Pdpe.lm.u3Reserved & 2? "!" : "..",/* mbz */
1807 Pdpe.lm.u1NoExecute ? "NX" : "--",
1808 Pdpe.u & RT_BIT(9) ? '1' : '0',
1809 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1810 Pdpe.u & RT_BIT(11) ? '1' : '0',
1811 Pdpe.u & X86_PDPE_PG_MASK);
1812 if (pState->fDumpPageInfo)
1813 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1814 if ((Pdpe.u >> 52) & 0x7ff)
1815 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx", (Pdpe.u >> 52) & 0x7ff);
1816 }
1817 else
1818 {
1819 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
1820 "%08llx 3 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1821 pState->u64Address,
1822 Pdpe.n.u2Reserved & 1? '!' : '.', /* mbz */
1823 Pdpe.n.u2Reserved & 2? '!' : '.', /* mbz */
1824 Pdpe.n.u4Reserved & 1? '!' : '.', /* mbz */
1825 Pdpe.n.u4Reserved & 2? '!' : '.', /* mbz */
1826 Pdpe.n.u4Reserved & 8? '!' : '.', /* mbz */
1827 Pdpe.n.u1WriteThru ? "WT" : "--",
1828 Pdpe.n.u1CacheDisable? "CD" : "--",
1829 Pdpe.n.u4Reserved & 2? "!" : "..",/* mbz */
1830 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
1831 Pdpe.u & RT_BIT(9) ? '1' : '0',
1832 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1833 Pdpe.u & RT_BIT(11) ? '1' : '0',
1834 Pdpe.u & X86_PDPE_PG_MASK);
1835 if (pState->fDumpPageInfo)
1836 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1837 if ((Pdpe.u >> 52) & 0xfff)
1838 pState->pHlp->pfnPrintf(pState->pHlp, " 63:52=%03llx!", (Pdpe.u >> 52) & 0xfff);
1839 }
1840 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1841
1842 if (cMaxDepth)
1843 {
1844 int rc2 = pgmR3DumpHierarchyShwPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
1845 if (rc2 < rc && RT_SUCCESS(rc))
1846 rc = rc2;
1847 }
1848 else
1849 pState->cLeaves++;
1850 }
1851 }
1852 return rc;
1853}
1854
1855
1856/**
1857 * Dumps a 64-bit shadow PML4 table.
1858 *
1859 * @returns VBox status code (VINF_SUCCESS).
1860 * @param pState The dumper state.
1861 * @param HCPhys The physical address of the table.
1862 * @param cMaxDepth The maximum depth.
1863 */
1864static int pgmR3DumpHierarchyShwPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1865{
1866 PCX86PML4 pPML4 = NULL;
1867 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page map level 4", (void const **)&pPML4);
1868 if (RT_FAILURE(rc))
1869 return rc;
1870
1871 Assert(cMaxDepth);
1872 cMaxDepth--;
1873
1874 /*
1875 * This is a bit tricky as we're working on unsigned addresses while the
1876 * AMD64 spec uses signed tricks.
1877 */
1878 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1879 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1880 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
1881 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
1882 { /* Simple, nothing to adjust */ }
1883 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
1884 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
1885 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
1886 iFirst = X86_PG_AMD64_ENTRIES / 2;
1887 else
1888 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
1889
1890 for (uint32_t i = iFirst; i <= iLast; i++)
1891 {
1892 X86PML4E Pml4e = pPML4->a[i];
1893 if (Pml4e.n.u1Present)
1894 {
1895 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
1896 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
1897 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
1898 "%016llx 4 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1899 pState->u64Address,
1900 Pml4e.n.u1Write ? 'W' : 'R',
1901 Pml4e.n.u1User ? 'U' : 'S',
1902 Pml4e.n.u1Accessed ? 'A' : '-',
1903 Pml4e.n.u3Reserved & 1? '?' : '.', /* ignored */
1904 Pml4e.n.u3Reserved & 4? '!' : '.', /* mbz */
1905 Pml4e.n.u1WriteThru ? "WT" : "--",
1906 Pml4e.n.u1CacheDisable? "CD" : "--",
1907 Pml4e.n.u3Reserved & 2? "!" : "..",/* mbz */
1908 Pml4e.n.u1NoExecute ? "NX" : "--",
1909 Pml4e.u & RT_BIT(9) ? '1' : '0',
1910 Pml4e.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1911 Pml4e.u & RT_BIT(11) ? '1' : '0',
1912 Pml4e.u & X86_PML4E_PG_MASK);
1913 if (pState->fDumpPageInfo)
1914 pgmR3DumpHierarchyShwTablePageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK);
1915 if ((Pml4e.u >> 52) & 0x7ff)
1916 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pml4e.u >> 52) & 0x7ff);
1917 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1918
1919 if (cMaxDepth)
1920 {
1921 int rc2 = pgmR3DumpHierarchyShwPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
1922 if (rc2 < rc && RT_SUCCESS(rc))
1923 rc = rc2;
1924 }
1925 else
1926 pState->cLeaves++;
1927 }
1928 }
1929 return rc;
1930}
1931
1932
1933/**
1934 * Dumps a 32-bit shadow page table.
1935 *
1936 * @returns VBox status code (VINF_SUCCESS).
1937 * @param pState The dumper state.
1938 * @param HCPhys The physical address of the table.
1939 */
1940static int pgmR3DumpHierarchyShw32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1941{
1942 PCX86PT pPT = NULL;
1943 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", (void const **)&pPT);
1944 if (RT_FAILURE(rc))
1945 return rc;
1946
1947 uint32_t iFirst, iLast;
1948 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
1949 for (uint32_t i = iFirst; i <= iLast; i++)
1950 {
1951 X86PTE Pte = pPT->a[i];
1952 if (Pte.n.u1Present)
1953 {
1954 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
1955 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
1956 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
1957 pState->u64Address,
1958 Pte.n.u1Write ? 'W' : 'R',
1959 Pte.n.u1User ? 'U' : 'S',
1960 Pte.n.u1Accessed ? 'A' : '-',
1961 Pte.n.u1Dirty ? 'D' : '-',
1962 Pte.n.u1Global ? 'G' : '-',
1963 Pte.n.u1WriteThru ? "WT" : "--",
1964 Pte.n.u1CacheDisable? "CD" : "--",
1965 Pte.n.u1PAT ? "AT" : "--",
1966 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1967 Pte.u & RT_BIT(10) ? '1' : '-',
1968 Pte.u & RT_BIT(11) ? '1' : '-',
1969 Pte.u & X86_PDE_PG_MASK);
1970 if (pState->fDumpPageInfo)
1971 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
1972 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1973 }
1974 }
1975 return VINF_SUCCESS;
1976}
1977
1978
1979/**
1980 * Dumps a 32-bit shadow page directory and page tables.
1981 *
1982 * @returns VBox status code (VINF_SUCCESS).
1983 * @param pState The dumper state.
1984 * @param HCPhys The physical address of the table.
1985 * @param cMaxDepth The maximum depth.
1986 */
1987static int pgmR3DumpHierarchyShw32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1988{
1989 if (pState->u64Address >= _4G)
1990 return VINF_SUCCESS;
1991
1992 PCX86PD pPD = NULL;
1993 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", (void const **)&pPD);
1994 if (RT_FAILURE(rc))
1995 return rc;
1996
1997 Assert(cMaxDepth > 0);
1998 cMaxDepth--;
1999
2000 uint32_t iFirst, iLast;
2001 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2002 for (uint32_t i = iFirst; i <= iLast; i++)
2003 {
2004 X86PDE Pde = pPD->a[i];
2005 if (Pde.n.u1Present)
2006 {
2007 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
2008 if (Pde.b.u1Size && pState->fPse)
2009 {
2010 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
2011 | (Pde.u & X86_PDE4M_PG_MASK);
2012 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2013 "%08llx 2 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
2014 pState->u64Address,
2015 Pde.b.u1Write ? 'W' : 'R',
2016 Pde.b.u1User ? 'U' : 'S',
2017 Pde.b.u1Accessed ? 'A' : '-',
2018 Pde.b.u1Dirty ? 'D' : '-',
2019 Pde.b.u1Global ? 'G' : '-',
2020 Pde.b.u1WriteThru ? "WT" : "--",
2021 Pde.b.u1CacheDisable? "CD" : "--",
2022 Pde.b.u1PAT ? "AT" : "--",
2023 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
2024 '-',
2025 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
2026 u64Phys);
2027 if (pState->fDumpPageInfo)
2028 pgmR3DumpHierarchyShwGuestPageInfo(pState, u64Phys, _4M);
2029 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2030 pState->cLeaves++;
2031 }
2032 else
2033 {
2034 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2035 "%08llx 2 | P %c %c %c %c %c %s %s .. .. 4K %c%c%c %08x",
2036 pState->u64Address,
2037 Pde.n.u1Write ? 'W' : 'R',
2038 Pde.n.u1User ? 'U' : 'S',
2039 Pde.n.u1Accessed ? 'A' : '-',
2040 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2041 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2042 Pde.n.u1WriteThru ? "WT" : "--",
2043 Pde.n.u1CacheDisable? "CD" : "--",
2044 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
2045 '-',
2046 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
2047 Pde.u & X86_PDE_PG_MASK);
2048 if (pState->fDumpPageInfo)
2049 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PG_MASK);
2050 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2051
2052 if (cMaxDepth)
2053 {
2054 int rc2 = pgmR3DumpHierarchyShw32BitPT(pState, Pde.u & X86_PDE_PG_MASK);
2055 if (rc2 < rc && RT_SUCCESS(rc))
2056 rc = rc2;
2057 }
2058 else
2059 pState->cLeaves++;
2060 }
2061 }
2062 }
2063
2064 return rc;
2065}
2066
2067
2068/**
2069 * Internal worker that initiates the actual dump.
2070 *
2071 * @returns VBox status code.
2072 * @param pState The dumper state.
2073 * @param cr3 The CR3 value.
2074 * @param cMaxDepth The max depth.
2075 */
2076static int pgmR3DumpHierarchyShwDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
2077{
2078 int rc;
2079 unsigned const cch = pState->cchAddress;
2080 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK /** @todo this should be X86_CR3_EPT_PAGE_MASK */
2081 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
2082 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
2083 : X86_CR3_PAGE_MASK;
2084 if (pState->fPrintCr3)
2085 {
2086 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
2087 : pState->fLme ? "Long Mode"
2088 : pState->fPae ? "PAE Mode"
2089 : pState->fPse ? "32-bit w/ PSE"
2090 : "32-bit";
2091 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
2092 if (pState->fDumpPageInfo)
2093 pgmR3DumpHierarchyShwTablePageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK);
2094 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
2095 pszMode,
2096 pState->fNp ? " + Nested Paging" : "",
2097 pState->fNxe ? " + NX" : "");
2098 }
2099
2100
2101 if (pState->fEpt)
2102 {
2103 if (pState->fPrintHeader)
2104 pState->pHlp->pfnPrintf(pState->pHlp,
2105 "%-*s R - Readable\n"
2106 "%-*s |W - Writeable\n"
2107 "%-*s ||X - Executable\n"
2108 "%-*s ||| EMT - EPT memory type\n"
2109 "%-*s ||| | I - Ignored PAT?\n"
2110 "%-*s ||| | | L - leaf\n"
2111 "%-*s ||| | | | A - accessed\n"
2112 "%-*s ||| | | | | D - dirty\n"
2113 "%-*s ||| | | | | | U - user execute\n"
2114 "%-*s ||| | | | | | | w - Paging writable\n"
2115 "%-*s ||| | | | | | | | k - Supervisor shadow stack writable\n"
2116 "%-*s ||| | | | | | | | | v - Suppress #VE\n"
2117 "%-*s Level ||| | | | | | | | | | page\n"
2118 /* xxxx n **** RWX MT I L A D U w k v 4K xxxxxxxxxxxxx
2119 RWX 7 - - - - - - - - 0123456701234567 */
2120 ,
2121 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
2122 cch, "", cch, "", cch, "", cch, "", cch, "Address");
2123 /** @todo assumes 4-level EPT tables for now. */
2124 rc = pgmR3DumpHierarchyShwEptPML4(pState, cr3 & cr3Mask, cMaxDepth);
2125 }
2126 else
2127 {
2128 if (pState->fPrintHeader)
2129 pState->pHlp->pfnPrintf(pState->pHlp,
2130 "%-*s P - Present\n"
2131 "%-*s | R/W - Read (0) / Write (1)\n"
2132 "%-*s | | U/S - User (1) / Supervisor (0)\n"
2133 "%-*s | | | A - Accessed\n"
2134 "%-*s | | | | D - Dirty\n"
2135 "%-*s | | | | | G - Global\n"
2136 "%-*s | | | | | | WT - Write thru\n"
2137 "%-*s | | | | | | | CD - Cache disable\n"
2138 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
2139 "%-*s | | | | | | | | | NX - No execute (K8)\n"
2140 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
2141 "%-*s | | | | | | | | | | | AVL - a=allocated; m=mapping; d=track dirty;\n"
2142 "%-*s | | | | | | | | | | | | p=permanent; v=validated;\n"
2143 "%-*s Level | | | | | | | | | | | | Page\n"
2144 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
2145 - W U - - - -- -- -- -- -- 010 */
2146 ,
2147 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
2148 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
2149 if (pState->fLme)
2150 rc = pgmR3DumpHierarchyShwPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
2151 else if (pState->fPae)
2152 rc = pgmR3DumpHierarchyShwPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
2153 else
2154 rc = pgmR3DumpHierarchyShw32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
2155 }
2156
2157 if (!pState->cLeaves)
2158 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
2159 return rc;
2160}
2161
2162
2163/**
2164 * dbgfR3PagingDumpEx worker.
2165 *
2166 * @returns VBox status code.
2167 * @param pVM The cross context VM structure.
2168 * @param cr3 The CR3 register value.
2169 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
2170 * @param u64FirstAddr The start address.
2171 * @param u64LastAddr The address to stop after.
2172 * @param cMaxDepth The max depth.
2173 * @param pHlp The output callbacks. Defaults to log if NULL.
2174 *
2175 * @internal
2176 */
2177VMMR3_INT_DECL(int) PGMR3DumpHierarchyShw(PVM pVM, uint64_t cr3, uint32_t fFlags, uint64_t u64FirstAddr, uint64_t u64LastAddr,
2178 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
2179{
2180 /* Minimal validation as we're only supposed to service DBGF. */
2181 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2182 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
2183 AssertReturn(fFlags & DBGFPGDMP_FLAGS_SHADOW, VERR_INVALID_PARAMETER);
2184
2185 PGMR3DUMPHIERARCHYSTATE State;
2186 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, u64FirstAddr, u64LastAddr, pHlp);
2187 PGM_LOCK_VOID(pVM);
2188 int rc = pgmR3DumpHierarchyShwDoIt(&State, cr3, cMaxDepth);
2189 PGM_UNLOCK(pVM);
2190 return rc;
2191}
2192
2193
2194/**
2195 * Dumps a page table hierarchy use only physical addresses and cr4/lm flags.
2196 *
2197 * @returns VBox status code (VINF_SUCCESS).
2198 * @param pVM The cross context VM structure.
2199 * @param cr3 The root of the hierarchy.
2200 * @param cr4 The cr4, only PAE and PSE is currently used.
2201 * @param fLongMode Set if long mode, false if not long mode.
2202 * @param cMaxDepth Number of levels to dump.
2203 * @param pHlp Pointer to the output functions.
2204 *
2205 * @deprecated Use DBGFR3PagingDumpEx.
2206 */
2207VMMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint64_t cr3, uint64_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
2208{
2209 if (!cMaxDepth)
2210 return VINF_SUCCESS;
2211
2212 PVMCPU pVCpu = VMMGetCpu(pVM);
2213 if (!pVCpu)
2214 pVCpu = pVM->apCpusR3[0];
2215
2216 uint32_t fFlags = DBGFPGDMP_FLAGS_HEADER | DBGFPGDMP_FLAGS_PRINT_CR3 | DBGFPGDMP_FLAGS_PAGE_INFO | DBGFPGDMP_FLAGS_SHADOW;
2217 fFlags |= cr4 & (X86_CR4_PAE | X86_CR4_PSE);
2218 if (fLongMode)
2219 fFlags |= DBGFPGDMP_FLAGS_LME;
2220
2221 return DBGFR3PagingDumpEx(pVM->pUVM, pVCpu->idCpu, fFlags, cr3, 0, fLongMode ? UINT64_MAX : UINT32_MAX, cMaxDepth, pHlp);
2222}
2223
2224
2225/**
2226 * Maps the guest page.
2227 *
2228 * @returns VBox status code.
2229 * @param pState The dumper state.
2230 * @param GCPhys The physical address of the guest page.
2231 * @param pszDesc The description.
2232 * @param ppv Where to return the pointer.
2233 * @param pLock Where to return the mapping lock. Hand this to
2234 * PGMPhysReleasePageMappingLock when done.
2235 */
2236static int pgmR3DumpHierarchyGstMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, const char *pszDesc,
2237 void const **ppv, PPGMPAGEMAPLOCK pLock)
2238{
2239 int rc = PGMPhysGCPhys2CCPtrReadOnly(pState->pVM, GCPhys, ppv, pLock);
2240 if (RT_FAILURE(rc))
2241 {
2242 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! Failed to map %s at GCPhys=%RGp: %Rrc!\n",
2243 pState->cchAddress, pState->u64Address, pszDesc, GCPhys, rc);
2244 return rc;
2245 }
2246 return VINF_SUCCESS;
2247}
2248
2249
2250/**
2251 * Figures out which guest page this is and dumps a summary.
2252 *
2253 * @param pState The dumper state.
2254 * @param GCPhys The page address.
2255 * @param cbPage The page size.
2256 */
2257static void pgmR3DumpHierarchyGstPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, uint32_t cbPage)
2258{
2259 char szPage[80];
2260 PGM_LOCK_VOID(pState->pVM);
2261 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
2262 if (pPage)
2263 RTStrPrintf(szPage, sizeof(szPage), " %R[pgmpage]", pPage);
2264 else
2265 strcpy(szPage, " not found");
2266 PGM_UNLOCK(pState->pVM);
2267 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
2268 NOREF(cbPage);
2269}
2270
2271
2272/**
2273 * Checks the entry for reserved bits.
2274 *
2275 * @param pState The dumper state.
2276 * @param u64Entry The entry to check.
2277 */
2278static void pgmR3DumpHierarchyGstCheckReservedHighBits(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t u64Entry)
2279{
2280 uint32_t uRsvd = (u64Entry & pState->u64HighReservedBits) >> 52;
2281 if (uRsvd)
2282 pState->pHlp->pfnPrintf(pState->pHlp, " %u:52=%03x%s",
2283 pState->uLastRsvdBit, uRsvd, pState->fLme ? "" : "!");
2284 /** @todo check the valid physical bits as well. */
2285}
2286
2287
2288/**
2289 * Dumps an EPT guest page table.
2290 *
2291 * @returns VBox status code (VINF_SUCCESS).
2292 * @param pState The dumper state.
2293 * @param HCPhys The page table address.
2294 */
2295static int pgmR3DumpHierarchyGstEptPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
2296{
2297 PCEPTPT pPT = NULL;
2298 PGMPAGEMAPLOCK Lock;
2299 int rc = pgmR3DumpHierarchyGstMapPage(pState, HCPhys, "Guest EPT level 1", (void const **)&pPT, &Lock);
2300 if (RT_FAILURE(rc))
2301 return rc;
2302
2303 uint32_t iFirst, iLast;
2304 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PT_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
2305 for (uint32_t i = iFirst; i <= iLast; i++)
2306 {
2307 uint64_t const u = pPT->a[i].u;
2308 if (u & EPT_PRESENT_MASK)
2309 {
2310 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PT_SHIFT);
2311 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2312 "%016llx 1 | %c%c%c %s %c L %c %c %c %c %c %c %c 4K %016llx",
2313 pState->u64Address,
2314 u & EPT_E_READ ? 'R' : '-',
2315 u & EPT_E_WRITE ? 'W' : '-',
2316 u & EPT_E_EXECUTE ? 'X' : '-',
2317 g_aaszEptMemType[1][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2318 u & EPT_E_IGNORE_PAT ? 'I' : '-',
2319 u & EPT_E_ACCESSED ? 'A' : '-',
2320 u & EPT_E_DIRTY ? 'D' : '-',
2321 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2322 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2323 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2324 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2325 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2326 u & EPT_E_PG_MASK);
2327 if (pState->fDumpPageInfo)
2328 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_E_PG_MASK, _4K);
2329 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2330 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2331 pState->cLeaves++;
2332 }
2333 }
2334
2335 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2336 return VINF_SUCCESS;
2337}
2338
2339
2340/**
2341 * Dumps an EPT guest page directory table.
2342 *
2343 * @returns VBox status code (VINF_SUCCESS).
2344 * @param pState The dumper state.
2345 * @param HCPhys The physical address of the page directory table.
2346 * @param cMaxDepth The maximum depth.
2347 */
2348static int pgmR3DumpHierarchyGstEptPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
2349{
2350 PCEPTPD pPD = NULL;
2351 PGMPAGEMAPLOCK Lock;
2352 int rc = pgmR3DumpHierarchyGstMapPage(pState, HCPhys, "Guest EPT level 2", (void const **)&pPD, &Lock);
2353 if (RT_FAILURE(rc))
2354 return rc;
2355
2356 Assert(cMaxDepth > 0);
2357 cMaxDepth--;
2358
2359 uint32_t iFirst, iLast;
2360 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PD_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
2361 for (uint32_t i = iFirst; i <= iLast; i++)
2362 {
2363 uint64_t const u = pPD->a[i].u;
2364 if (u & EPT_PRESENT_MASK)
2365 {
2366 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PD_SHIFT);
2367 if (u & EPT_E_LEAF)
2368 {
2369 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2370 "%016llx 2 | %c%c%c %s %c L %c %c %c %c %c %c %c 2M %016llx",
2371 pState->u64Address,
2372 u & EPT_E_READ ? 'R' : '-',
2373 u & EPT_E_WRITE ? 'W' : '-',
2374 u & EPT_E_EXECUTE ? 'X' : '-',
2375 g_aaszEptMemType[1][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2376 u & EPT_E_IGNORE_PAT ? 'I' : '-',
2377 u & EPT_E_ACCESSED ? 'A' : '-',
2378 u & EPT_E_DIRTY ? 'D' : '-',
2379 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2380 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2381 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2382 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2383 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2384 u & EPT_E_PG_MASK);
2385 if (pState->fDumpPageInfo)
2386 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_PDE2M_PG_MASK, _2M);
2387 if (u & EPT_PDE2M_MBZ_MASK)
2388 pState->pHlp->pfnPrintf(pState->pHlp, " 20:12=%02llx!", (u >> 12) & 0x1ff);
2389 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2390 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2391
2392 pState->cLeaves++;
2393 }
2394 else
2395 {
2396 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2397 "%016llx 2 | %c%c%c %s %c - %c %c %c %c %c %c %c %016llx",
2398 pState->u64Address,
2399 u & EPT_E_READ ? 'R' : '-',
2400 u & EPT_E_WRITE ? 'W' : '-',
2401 u & EPT_E_EXECUTE ? 'X' : '-',
2402 g_aaszEptMemType[0][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2403 u & EPT_E_IGNORE_PAT ? '!' : '-',
2404 u & EPT_E_ACCESSED ? 'A' : '-',
2405 u & EPT_E_DIRTY ? 'D' : '-',
2406 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2407 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2408 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2409 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2410 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2411 u & EPT_E_PG_MASK);
2412 if (pState->fDumpPageInfo)
2413 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_E_PG_MASK, _4K);
2414 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2415 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2416
2417 if (cMaxDepth)
2418 {
2419 int rc2 = pgmR3DumpHierarchyGstEptPT(pState, u & EPT_E_PG_MASK);
2420 if (rc2 < rc && RT_SUCCESS(rc))
2421 rc = rc2;
2422 }
2423 else
2424 pState->cLeaves++;
2425 }
2426 }
2427 }
2428
2429 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2430 return rc;
2431}
2432
2433
2434/**
2435 * Dumps an EPT guest page directory pointer table.
2436 *
2437 * @returns VBox status code (VINF_SUCCESS).
2438 * @param pState The dumper state.
2439 * @param HCPhys The physical address of the page directory pointer table.
2440 * @param cMaxDepth The maximum depth.
2441 */
2442static int pgmR3DumpHierarchyGstEptPDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
2443{
2444 PCEPTPDPT pPDPT = NULL;
2445 PGMPAGEMAPLOCK Lock;
2446 int rc = pgmR3DumpHierarchyGstMapPage(pState, HCPhys, "Guest EPT level 3", (void const **)&pPDPT, &Lock);
2447 if (RT_FAILURE(rc))
2448 return rc;
2449
2450 Assert(cMaxDepth > 0);
2451 cMaxDepth--;
2452
2453 uint32_t iFirst, iLast;
2454 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PDPT_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
2455 for (uint32_t i = iFirst; i <= iLast; i++)
2456 {
2457 uint64_t const u = pPDPT->a[i].u;
2458 if (u & EPT_PRESENT_MASK)
2459 {
2460 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PDPT_SHIFT);
2461 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2462 "%016llx 3 | %c%c%c %s %c %c %c %c %c %c %c %c %c %016llx",
2463 pState->u64Address,
2464 u & EPT_E_READ ? 'R' : '-',
2465 u & EPT_E_WRITE ? 'W' : '-',
2466 u & EPT_E_EXECUTE ? 'X' : '-',
2467 g_aaszEptMemType[!!(u & EPT_E_LEAF)][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2468 u & EPT_E_IGNORE_PAT ? '!' : '-',
2469 u & EPT_E_LEAF ? '!' : '-',
2470 u & EPT_E_ACCESSED ? 'A' : '-',
2471 u & EPT_E_DIRTY ? 'D' : '-',
2472 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2473 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2474 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2475 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2476 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2477 u & EPT_E_PG_MASK);
2478 if (pState->fDumpPageInfo)
2479 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_E_PG_MASK, _4K);
2480 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2481 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2482
2483 if (cMaxDepth)
2484 {
2485 int rc2 = pgmR3DumpHierarchyGstEptPD(pState, u & EPT_E_PG_MASK, cMaxDepth);
2486 if (rc2 < rc && RT_SUCCESS(rc))
2487 rc = rc2;
2488 }
2489 else
2490 pState->cLeaves++;
2491 }
2492 }
2493
2494 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2495 return rc;
2496}
2497
2498
2499/**
2500 * Dumps an EPT guest PML4 table.
2501 *
2502 * @returns VBox status code (VINF_SUCCESS).
2503 * @param pState The dumper state.
2504 * @param HCPhys The physical address of the table.
2505 * @param cMaxDepth The maximum depth.
2506 */
2507static int pgmR3DumpHierarchyGstEptPML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
2508{
2509 PCEPTPML4 pPML4 = NULL;
2510 PGMPAGEMAPLOCK Lock;
2511 int rc = pgmR3DumpHierarchyGstMapPage(pState, HCPhys, "Guest EPT level 4", (void const **)&pPML4, &Lock);
2512 if (RT_FAILURE(rc))
2513 return rc;
2514
2515 Assert(cMaxDepth);
2516 cMaxDepth--;
2517
2518 uint32_t iFirst = (pState->u64FirstAddress >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
2519 uint32_t iLast = (pState->u64LastAddress >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
2520 for (uint32_t i = iFirst; i <= iLast; i++)
2521 {
2522 uint64_t const u = pPML4->a[i].u;
2523 if (u & EPT_PRESENT_MASK)
2524 {
2525 pState->u64Address = (uint64_t)i << X86_PML4_SHIFT;
2526 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2527 "%016llx 4 | %c%c%c %s %c %c %c %c %c %c %c %c %c %016llx",
2528 pState->u64Address,
2529 u & EPT_E_READ ? 'R' : '-',
2530 u & EPT_E_WRITE ? 'W' : '-',
2531 u & EPT_E_EXECUTE ? 'X' : '-',
2532 g_aaszEptMemType[!!(u & EPT_E_LEAF)][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2533 u & EPT_E_IGNORE_PAT ? '!' : '-',
2534 u & EPT_E_LEAF ? '!' : '-',
2535 u & EPT_E_ACCESSED ? 'A' : '-',
2536 u & EPT_E_DIRTY ? 'D' : '-',
2537 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2538 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2539 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2540 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2541 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2542 u & EPT_E_PG_MASK);
2543 if (pState->fDumpPageInfo)
2544 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_E_PG_MASK, _4K);
2545 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2546 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2547
2548 if (cMaxDepth)
2549 {
2550 int rc2 = pgmR3DumpHierarchyGstEptPDPT(pState, u & EPT_E_PG_MASK, cMaxDepth);
2551 if (rc2 < rc && RT_SUCCESS(rc))
2552 rc = rc2;
2553 }
2554 else
2555 pState->cLeaves++;
2556 }
2557 }
2558
2559 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2560 return rc;
2561}
2562
2563
2564/**
2565 * Dumps a PAE guest page table.
2566 *
2567 * @returns VBox status code (VINF_SUCCESS).
2568 * @param pState The dumper state.
2569 * @param GCPhys The page table address.
2570 */
2571static int pgmR3DumpHierarchyGstPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys)
2572{
2573 PCX86PTPAE pPT;
2574 PGMPAGEMAPLOCK Lock;
2575 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
2576 if (RT_FAILURE(rc))
2577 return rc;
2578
2579 uint32_t iFirst, iLast;
2580 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
2581 for (uint32_t i = iFirst; i <= iLast; i++)
2582 {
2583 X86PTEPAE Pte = pPT->a[i];
2584 if (Pte.n.u1Present)
2585 {
2586 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
2587 pState->pHlp->pfnPrintf(pState->pHlp,
2588 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
2589 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
2590 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
2591 pState->u64Address,
2592 Pte.n.u1Write ? 'W' : 'R',
2593 Pte.n.u1User ? 'U' : 'S',
2594 Pte.n.u1Accessed ? 'A' : '-',
2595 Pte.n.u1Dirty ? 'D' : '-',
2596 Pte.n.u1Global ? 'G' : '-',
2597 Pte.n.u1WriteThru ? "WT" : "--",
2598 Pte.n.u1CacheDisable? "CD" : "--",
2599 Pte.n.u1PAT ? "AT" : "--",
2600 Pte.n.u1NoExecute ? "NX" : "--",
2601 Pte.u & RT_BIT(9) ? '1' : '0',
2602 Pte.u & RT_BIT(10) ? '1' : '0',
2603 Pte.u & RT_BIT(11) ? '1' : '0',
2604 Pte.u & X86_PTE_PAE_PG_MASK);
2605 if (pState->fDumpPageInfo)
2606 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
2607 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pte.u);
2608 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2609 pState->cLeaves++;
2610 }
2611 }
2612
2613 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2614 return VINF_SUCCESS;
2615}
2616
2617
2618/**
2619 * Dumps a PAE guest page directory table.
2620 *
2621 * @returns VBox status code (VINF_SUCCESS).
2622 * @param pState The dumper state.
2623 * @param GCPhys The physical address of the table.
2624 * @param cMaxDepth The maximum depth.
2625 */
2626static int pgmR3DumpHierarchyGstPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
2627{
2628 PCX86PDPAE pPD;
2629 PGMPAGEMAPLOCK Lock;
2630 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
2631 if (RT_FAILURE(rc))
2632 return rc;
2633
2634 Assert(cMaxDepth > 0);
2635 cMaxDepth--;
2636
2637 uint32_t iFirst, iLast;
2638 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
2639 for (uint32_t i = iFirst; i <= iLast; i++)
2640 {
2641 X86PDEPAE Pde = pPD->a[i];
2642 if (Pde.n.u1Present)
2643 {
2644 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
2645 if (Pde.b.u1Size)
2646 {
2647 pState->pHlp->pfnPrintf(pState->pHlp,
2648 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
2649 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
2650 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
2651 pState->u64Address,
2652 Pde.b.u1Write ? 'W' : 'R',
2653 Pde.b.u1User ? 'U' : 'S',
2654 Pde.b.u1Accessed ? 'A' : '-',
2655 Pde.b.u1Dirty ? 'D' : '-',
2656 Pde.b.u1Global ? 'G' : '-',
2657 Pde.b.u1WriteThru ? "WT" : "--",
2658 Pde.b.u1CacheDisable ? "CD" : "--",
2659 Pde.b.u1PAT ? "AT" : "--",
2660 Pde.b.u1NoExecute ? "NX" : "--",
2661 Pde.u & RT_BIT_64(9) ? '1' : '0',
2662 Pde.u & RT_BIT_64(10) ? '1' : '0',
2663 Pde.u & RT_BIT_64(11) ? '1' : '0',
2664 Pde.u & X86_PDE2M_PAE_PG_MASK);
2665 if (pState->fDumpPageInfo)
2666 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
2667 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
2668 if ((Pde.u >> 13) & 0xff)
2669 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
2670 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2671
2672 pState->cLeaves++;
2673 }
2674 else
2675 {
2676 pState->pHlp->pfnPrintf(pState->pHlp,
2677 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
2678 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
2679 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
2680 pState->u64Address,
2681 Pde.n.u1Write ? 'W' : 'R',
2682 Pde.n.u1User ? 'U' : 'S',
2683 Pde.n.u1Accessed ? 'A' : '-',
2684 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2685 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2686 Pde.n.u1WriteThru ? "WT" : "--",
2687 Pde.n.u1CacheDisable ? "CD" : "--",
2688 Pde.n.u1NoExecute ? "NX" : "--",
2689 Pde.u & RT_BIT_64(9) ? '1' : '0',
2690 Pde.u & RT_BIT_64(10) ? '1' : '0',
2691 Pde.u & RT_BIT_64(11) ? '1' : '0',
2692 Pde.u & X86_PDE_PAE_PG_MASK);
2693 if (pState->fDumpPageInfo)
2694 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK, _4K);
2695 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
2696 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2697
2698 if (cMaxDepth)
2699 {
2700 int rc2 = pgmR3DumpHierarchyGstPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK);
2701 if (rc2 < rc && RT_SUCCESS(rc))
2702 rc = rc2;
2703 }
2704 else
2705 pState->cLeaves++;
2706 }
2707 }
2708 }
2709
2710 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2711 return rc;
2712}
2713
2714
2715/**
2716 * Dumps a PAE guest page directory pointer table.
2717 *
2718 * @returns VBox status code (VINF_SUCCESS).
2719 * @param pState The dumper state.
2720 * @param GCPhys The physical address of the table.
2721 * @param cMaxDepth The maximum depth.
2722 */
2723static int pgmR3DumpHierarchyGstPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
2724{
2725 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
2726 if (!pState->fLme && pState->u64Address >= _4G)
2727 return VINF_SUCCESS;
2728
2729 PCX86PDPT pPDPT;
2730 PGMPAGEMAPLOCK Lock;
2731 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory pointer table", (void const **)&pPDPT, &Lock);
2732 if (RT_FAILURE(rc))
2733 return rc;
2734
2735 Assert(cMaxDepth > 0);
2736 cMaxDepth--;
2737
2738 uint32_t iFirst, iLast;
2739 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
2740 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
2741 &iFirst, &iLast);
2742 for (uint32_t i = iFirst; i <= iLast; i++)
2743 {
2744 X86PDPE Pdpe = pPDPT->a[i];
2745 if (Pdpe.n.u1Present)
2746 {
2747 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
2748 if (pState->fLme)
2749 {
2750 /** @todo Do 1G pages. */
2751 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
2752 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2753 pState->u64Address,
2754 Pdpe.lm.u1Write ? 'W' : 'R',
2755 Pdpe.lm.u1User ? 'U' : 'S',
2756 Pdpe.lm.u1Accessed ? 'A' : '-',
2757 Pdpe.lm.u3Reserved & 1 ? '?' : '.', /* ignored */
2758 Pdpe.lm.u3Reserved & 4 ? '!' : '.', /* mbz */
2759 Pdpe.lm.u1WriteThru ? "WT" : "--",
2760 Pdpe.lm.u1CacheDisable ? "CD" : "--",
2761 Pdpe.lm.u3Reserved & 2 ? "!" : "..",/* mbz */
2762 Pdpe.lm.u1NoExecute ? "NX" : "--",
2763 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
2764 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
2765 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
2766 Pdpe.u & X86_PDPE_PG_MASK);
2767 if (pState->fDumpPageInfo)
2768 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
2769 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
2770 }
2771 else
2772 {
2773 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
2774 "%08llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2775 pState->u64Address,
2776 Pdpe.n.u2Reserved & 1 ? '!' : '.', /* mbz */
2777 Pdpe.n.u2Reserved & 2 ? '!' : '.', /* mbz */
2778 Pdpe.n.u4Reserved & 1 ? '!' : '.', /* mbz */
2779 Pdpe.n.u4Reserved & 2 ? '!' : '.', /* mbz */
2780 Pdpe.n.u4Reserved & 8 ? '!' : '.', /* mbz */
2781 Pdpe.n.u1WriteThru ? "WT" : "--",
2782 Pdpe.n.u1CacheDisable ? "CD" : "--",
2783 Pdpe.n.u4Reserved & 2 ? "!" : "..", /* mbz */
2784 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
2785 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
2786 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
2787 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
2788 Pdpe.u & X86_PDPE_PG_MASK);
2789 if (pState->fDumpPageInfo)
2790 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
2791 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
2792 }
2793 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2794
2795 if (cMaxDepth)
2796 {
2797 int rc2 = pgmR3DumpHierarchyGstPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
2798 if (rc2 < rc && RT_SUCCESS(rc))
2799 rc = rc2;
2800 }
2801 else
2802 pState->cLeaves++;
2803 }
2804 }
2805
2806 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2807 return rc;
2808}
2809
2810
2811/**
2812 * Dumps a 32-bit guest page table.
2813 *
2814 * @returns VBox status code (VINF_SUCCESS).
2815 * @param pState The dumper state.
2816 * @param GCPhys The physical address of the table.
2817 * @param cMaxDepth The maximum depth.
2818 */
2819static int pgmR3DumpHierarchyGstPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2820{
2821 PCX86PML4 pPML4;
2822 PGMPAGEMAPLOCK Lock;
2823 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page map level 4", (void const **)&pPML4, &Lock);
2824 if (RT_FAILURE(rc))
2825 return rc;
2826
2827 Assert(cMaxDepth);
2828 cMaxDepth--;
2829
2830 /*
2831 * This is a bit tricky as we're working on unsigned addresses while the
2832 * AMD64 spec uses signed tricks.
2833 */
2834 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2835 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2836 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
2837 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
2838 { /* Simple, nothing to adjust */ }
2839 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
2840 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
2841 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
2842 iFirst = X86_PG_AMD64_ENTRIES / 2;
2843 else
2844 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
2845
2846 for (uint32_t i = iFirst; i <= iLast; i++)
2847 {
2848 X86PML4E Pml4e = pPML4->a[i];
2849 if (Pml4e.n.u1Present)
2850 {
2851 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
2852 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
2853 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
2854 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2855 pState->u64Address,
2856 Pml4e.n.u1Write ? 'W' : 'R',
2857 Pml4e.n.u1User ? 'U' : 'S',
2858 Pml4e.n.u1Accessed ? 'A' : '-',
2859 Pml4e.n.u3Reserved & 1 ? '?' : '.', /* ignored */
2860 Pml4e.n.u3Reserved & 4 ? '!' : '.', /* mbz */
2861 Pml4e.n.u1WriteThru ? "WT" : "--",
2862 Pml4e.n.u1CacheDisable ? "CD" : "--",
2863 Pml4e.n.u3Reserved & 2 ? "!" : "..",/* mbz */
2864 Pml4e.n.u1NoExecute ? "NX" : "--",
2865 Pml4e.u & RT_BIT_64(9) ? '1' : '0',
2866 Pml4e.u & RT_BIT_64(10) ? '1' : '0',
2867 Pml4e.u & RT_BIT_64(11) ? '1' : '0',
2868 Pml4e.u & X86_PML4E_PG_MASK);
2869 if (pState->fDumpPageInfo)
2870 pgmR3DumpHierarchyGstPageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK, _4K);
2871 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pml4e.u);
2872 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2873
2874 if (cMaxDepth)
2875 {
2876 int rc2 = pgmR3DumpHierarchyGstPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
2877 if (rc2 < rc && RT_SUCCESS(rc))
2878 rc = rc2;
2879 }
2880 else
2881 pState->cLeaves++;
2882 }
2883 }
2884
2885 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2886 return rc;
2887}
2888
2889
2890/**
2891 * Dumps a 32-bit guest page table.
2892 *
2893 * @returns VBox status code (VINF_SUCCESS).
2894 * @param pState The dumper state.
2895 * @param GCPhys The physical address of the table.
2896 */
2897static int pgmR3DumpHierarchyGst32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys)
2898{
2899 PCX86PT pPT;
2900 PGMPAGEMAPLOCK Lock;
2901 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
2902 if (RT_FAILURE(rc))
2903 return rc;
2904
2905 uint32_t iFirst, iLast;
2906 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2907 for (uint32_t i = iFirst; i <= iLast; i++)
2908 {
2909 X86PTE Pte = pPT->a[i];
2910 if (Pte.n.u1Present)
2911 {
2912 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
2913 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
2914 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
2915 pState->u64Address,
2916 Pte.n.u1Write ? 'W' : 'R',
2917 Pte.n.u1User ? 'U' : 'S',
2918 Pte.n.u1Accessed ? 'A' : '-',
2919 Pte.n.u1Dirty ? 'D' : '-',
2920 Pte.n.u1Global ? 'G' : '-',
2921 Pte.n.u1WriteThru ? "WT" : "--",
2922 Pte.n.u1CacheDisable ? "CD" : "--",
2923 Pte.n.u1PAT ? "AT" : "--",
2924 Pte.u & RT_BIT_32(9) ? '1' : '0',
2925 Pte.u & RT_BIT_32(10) ? '1' : '0',
2926 Pte.u & RT_BIT_32(11) ? '1' : '0',
2927 Pte.u & X86_PDE_PG_MASK);
2928 if (pState->fDumpPageInfo)
2929 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
2930 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2931 }
2932 }
2933
2934 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2935 return VINF_SUCCESS;
2936}
2937
2938
2939/**
2940 * Dumps a 32-bit guest page directory and page tables.
2941 *
2942 * @returns VBox status code (VINF_SUCCESS).
2943 * @param pState The dumper state.
2944 * @param GCPhys The physical address of the table.
2945 * @param cMaxDepth The maximum depth.
2946 */
2947static int pgmR3DumpHierarchyGst32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2948{
2949 if (pState->u64Address >= _4G)
2950 return VINF_SUCCESS;
2951
2952 PCX86PD pPD;
2953 PGMPAGEMAPLOCK Lock;
2954 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
2955 if (RT_FAILURE(rc))
2956 return rc;
2957
2958 Assert(cMaxDepth > 0);
2959 cMaxDepth--;
2960
2961 uint32_t iFirst, iLast;
2962 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2963 for (uint32_t i = iFirst; i <= iLast; i++)
2964 {
2965 X86PDE Pde = pPD->a[i];
2966 if (Pde.n.u1Present)
2967 {
2968 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
2969 if (Pde.b.u1Size && pState->fPse)
2970 {
2971 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
2972 | (Pde.u & X86_PDE4M_PG_MASK);
2973 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2974 "%08llx 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
2975 pState->u64Address,
2976 Pde.b.u1Write ? 'W' : 'R',
2977 Pde.b.u1User ? 'U' : 'S',
2978 Pde.b.u1Accessed ? 'A' : '-',
2979 Pde.b.u1Dirty ? 'D' : '-',
2980 Pde.b.u1Global ? 'G' : '-',
2981 Pde.b.u1WriteThru ? "WT" : "--",
2982 Pde.b.u1CacheDisable ? "CD" : "--",
2983 Pde.b.u1PAT ? "AT" : "--",
2984 Pde.u & RT_BIT_32(9) ? '1' : '0',
2985 Pde.u & RT_BIT_32(10) ? '1' : '0',
2986 Pde.u & RT_BIT_32(11) ? '1' : '0',
2987 u64Phys);
2988 if (pState->fDumpPageInfo)
2989 pgmR3DumpHierarchyGstPageInfo(pState, u64Phys, _4M);
2990 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2991 pState->cLeaves++;
2992 }
2993 else
2994 {
2995 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2996 "%08llx 0 | P %c %c %c %c %c %s %s .. .. .. %c%c%c %08x",
2997 pState->u64Address,
2998 Pde.n.u1Write ? 'W' : 'R',
2999 Pde.n.u1User ? 'U' : 'S',
3000 Pde.n.u1Accessed ? 'A' : '-',
3001 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
3002 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
3003 Pde.n.u1WriteThru ? "WT" : "--",
3004 Pde.n.u1CacheDisable ? "CD" : "--",
3005 Pde.u & RT_BIT_32(9) ? '1' : '0',
3006 Pde.u & RT_BIT_32(10) ? '1' : '0',
3007 Pde.u & RT_BIT_32(11) ? '1' : '0',
3008 Pde.u & X86_PDE_PG_MASK);
3009 if (pState->fDumpPageInfo)
3010 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PG_MASK, _4K);
3011 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
3012
3013 if (cMaxDepth)
3014 {
3015 int rc2 = pgmR3DumpHierarchyGst32BitPT(pState, Pde.u & X86_PDE_PG_MASK);
3016 if (rc2 < rc && RT_SUCCESS(rc))
3017 rc = rc2;
3018 }
3019 else
3020 pState->cLeaves++;
3021 }
3022 }
3023 }
3024
3025 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
3026 return rc;
3027}
3028
3029
3030/**
3031 * Internal worker that initiates the actual dump.
3032 *
3033 * @returns VBox status code.
3034 * @param pState The dumper state.
3035 * @param cr3 The CR3 value.
3036 * @param cMaxDepth The max depth.
3037 */
3038static int pgmR3DumpHierarchyGstDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
3039{
3040 int rc;
3041 unsigned const cch = pState->cchAddress;
3042 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK /** @todo this should be X86_CR3_EPT_PAGE_MASK, but it is wrong */
3043 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
3044 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
3045 : X86_CR3_PAGE_MASK;
3046 if (pState->fPrintCr3)
3047 {
3048 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
3049 : pState->fLme ? "Long Mode"
3050 : pState->fPae ? "PAE Mode"
3051 : pState->fPse ? "32-bit w/ PSE"
3052 : "32-bit";
3053 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
3054 if (pState->fDumpPageInfo)
3055 pgmR3DumpHierarchyGstPageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK, _4K);
3056 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
3057 pszMode,
3058 pState->fNp ? " + Nested Paging" : "",
3059 pState->fNxe ? " + NX" : "");
3060 }
3061
3062
3063 if (pState->fEpt)
3064 {
3065 if (pState->fPrintHeader)
3066 pState->pHlp->pfnPrintf(pState->pHlp,
3067 "%-*s R - Readable\n"
3068 "%-*s |W - Writeable\n"
3069 "%-*s ||X - Executable\n"
3070 "%-*s ||| EMT - EPT memory type\n"
3071 "%-*s ||| | I - Ignored PAT?\n"
3072 "%-*s ||| | | L - leaf\n"
3073 "%-*s ||| | | | A - accessed\n"
3074 "%-*s ||| | | | | D - dirty\n"
3075 "%-*s ||| | | | | | U - user execute\n"
3076 "%-*s ||| | | | | | | w - Paging writable\n"
3077 "%-*s ||| | | | | | | | k - Supervisor shadow stack writable\n"
3078 "%-*s ||| | | | | | | | | v - Suppress #VE\n"
3079 "%-*s Level ||| | | | | | | | | | page\n"
3080 /* xxxx n **** RWX MT I L A D U w k v 4K xxxxxxxxxxxxx
3081 RWX 7 - - - - - - - - 0123456701234567 */
3082 ,
3083 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
3084 cch, "", cch, "", cch, "", cch, "", cch, "Address");
3085 /** @todo assumes 4-level EPT tables for now. */
3086 rc = pgmR3DumpHierarchyGstEptPML4(pState, cr3 & cr3Mask, cMaxDepth);
3087 }
3088 else
3089 {
3090 if (pState->fPrintHeader)
3091 pState->pHlp->pfnPrintf(pState->pHlp,
3092 "%-*s P - Present\n"
3093 "%-*s | R/W - Read (0) / Write (1)\n"
3094 "%-*s | | U/S - User (1) / Supervisor (0)\n"
3095 "%-*s | | | A - Accessed\n"
3096 "%-*s | | | | D - Dirty\n"
3097 "%-*s | | | | | G - Global\n"
3098 "%-*s | | | | | | WT - Write thru\n"
3099 "%-*s | | | | | | | CD - Cache disable\n"
3100 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
3101 "%-*s | | | | | | | | | NX - No execute (K8)\n"
3102 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
3103 "%-*s | | | | | | | | | | | AVL - 3 available bits.\n"
3104 "%-*s Level | | | | | | | | | | | | Page\n"
3105 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
3106 - W U - - - -- -- -- -- -- 010 */
3107 ,
3108 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
3109 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
3110 if (pState->fLme)
3111 rc = pgmR3DumpHierarchyGstPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
3112 else if (pState->fPae)
3113 rc = pgmR3DumpHierarchyGstPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
3114 else
3115 rc = pgmR3DumpHierarchyGst32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
3116 }
3117
3118 if (!pState->cLeaves)
3119 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
3120 return rc;
3121}
3122
3123
3124/**
3125 * dbgfR3PagingDumpEx worker.
3126 *
3127 * @returns VBox status code.
3128 * @param pVM The cross context VM structure.
3129 * @param cr3 The CR3 register value.
3130 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
3131 * @param FirstAddr The start address.
3132 * @param LastAddr The address to stop after.
3133 * @param cMaxDepth The max depth.
3134 * @param pHlp The output callbacks. Defaults to log if NULL.
3135 *
3136 * @internal
3137 */
3138VMMR3_INT_DECL(int) PGMR3DumpHierarchyGst(PVM pVM, uint64_t cr3, uint32_t fFlags, RTGCPTR FirstAddr, RTGCPTR LastAddr,
3139 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
3140{
3141 /* Minimal validation as we're only supposed to service DBGF. */
3142 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
3143 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
3144 AssertReturn(fFlags & DBGFPGDMP_FLAGS_GUEST, VERR_INVALID_PARAMETER);
3145
3146 PGMR3DUMPHIERARCHYSTATE State;
3147 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, FirstAddr, LastAddr, pHlp);
3148 return pgmR3DumpHierarchyGstDoIt(&State, cr3, cMaxDepth);
3149}
3150
3151
3152/**
3153 * For aiding with reset problems and similar.
3154 *
3155 * @param pVM The cross context VM handle.
3156 */
3157void pgmLogState(PVM pVM)
3158{
3159#if 0
3160 RTLogRelPrintf("\npgmLogState pgmLogState pgmLogState pgmLogState pgmLogState\n");
3161
3162 /*
3163 * Per CPU stuff.
3164 */
3165 for (VMCPUID iCpu = 0; iCpu < pVM->cCpus; iCpu++)
3166 {
3167 PPGMCPU pPgmCpu = &pVM->aCpus[iCpu].pgm.s;
3168 RTLogRelPrintf("pgmLogState: CPU #%u\n", iCpu);
3169# define LOG_PGMCPU_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPgmCpu->aMember)
3170 LOG_PGMCPU_MEMBER("#RX32", offVM);
3171 LOG_PGMCPU_MEMBER("#RX32", offVCpu);
3172 LOG_PGMCPU_MEMBER("#RX32", offPGM);
3173 LOG_PGMCPU_MEMBER("RGp", GCPhysA20Mask);
3174 LOG_PGMCPU_MEMBER("RTbool", fA20Enabled);
3175 LOG_PGMCPU_MEMBER("RTbool", fNoExecuteEnabled);
3176 LOG_PGMCPU_MEMBER("#RX32", fSyncFlags);
3177 LOG_PGMCPU_MEMBER("d", enmShadowMode);
3178 LOG_PGMCPU_MEMBER("d", enmGuestMode);
3179 LOG_PGMCPU_MEMBER("RGp", GCPhysCR3);
3180
3181 LOG_PGMCPU_MEMBER("p", pGst32BitPdR3);
3182 LOG_PGMCPU_MEMBER("p", pGst32BitPdR0);
3183 LOG_PGMCPU_MEMBER("RRv", pGst32BitPdRC);
3184 LOG_PGMCPU_MEMBER("#RX32", fGst32BitMbzBigPdeMask);
3185 LOG_PGMCPU_MEMBER("RTbool", fGst32BitPageSizeExtension);
3186
3187 LOG_PGMCPU_MEMBER("p", pGstPaePdptR3);
3188 LOG_PGMCPU_MEMBER("p", pGstPaePdptR0);
3189 LOG_PGMCPU_MEMBER("RRv", pGstPaePdptRC);
3190 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[0]);
3191 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[1]);
3192 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[2]);
3193 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[3]);
3194 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[0]);
3195 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[1]);
3196 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[2]);
3197 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[3]);
3198 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[0]);
3199 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[1]);
3200 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[2]);
3201 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[3]);
3202 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[0]);
3203 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[1]);
3204 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[2]);
3205 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[3]);
3206 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[0].u);
3207 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[1].u);
3208 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[2].u);
3209 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[3].u);
3210 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPteMask);
3211 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPdeMask);
3212 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzBigPdeMask);
3213 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzBigPdeMask);
3214 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPdpeMask);
3215
3216 LOG_PGMCPU_MEMBER("p", pGstAmd64Pml4R3);
3217 LOG_PGMCPU_MEMBER("p", pGstAmd64Pml4R0);
3218 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPteMask);
3219 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPdeMask);
3220 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzBigPdeMask);
3221 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPdpeMask);
3222 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzBigPdpeMask);
3223 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPml4eMask);
3224 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64ShadowedPdpeMask);
3225 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64ShadowedPml4eMask);
3226 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedPteMask);
3227 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedPdeMask);
3228 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedBigPdeMask);
3229 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedBigPde4PteMask);
3230
3231 LOG_PGMCPU_MEMBER("p", pShwPageCR3R3);
3232 LOG_PGMCPU_MEMBER("p", pShwPageCR3R0);
3233 LOG_PGMCPU_MEMBER("RRv", pShwPageCR3RC);
3234
3235 LOG_PGMCPU_MEMBER("p", pfnR3ShwRelocate);
3236 LOG_PGMCPU_MEMBER("p", pfnR3ShwExit);
3237 LOG_PGMCPU_MEMBER("p", pfnR3ShwGetPage);
3238 LOG_PGMCPU_MEMBER("p", pfnR3ShwModifyPage);
3239 LOG_PGMCPU_MEMBER("p", pfnR0ShwGetPage);
3240 LOG_PGMCPU_MEMBER("p", pfnR0ShwModifyPage);
3241 LOG_PGMCPU_MEMBER("p", pfnR3GstRelocate);
3242 LOG_PGMCPU_MEMBER("p", pfnR3GstExit);
3243 LOG_PGMCPU_MEMBER("p", pfnR3GstGetPage);
3244 LOG_PGMCPU_MEMBER("p", pfnR3GstModifyPage);
3245 LOG_PGMCPU_MEMBER("p", pfnR0GstGetPage);
3246 LOG_PGMCPU_MEMBER("p", pfnR0GstModifyPage);
3247 LOG_PGMCPU_MEMBER("p", pfnR3BthRelocate);
3248 LOG_PGMCPU_MEMBER("p", pfnR3BthInvalidatePage);
3249 LOG_PGMCPU_MEMBER("p", pfnR3BthSyncCR3);
3250 LOG_PGMCPU_MEMBER("p", pfnR3BthPrefetchPage);
3251 LOG_PGMCPU_MEMBER("p", pfnR3BthMapCR3);
3252 LOG_PGMCPU_MEMBER("p", pfnR3BthUnmapCR3);
3253 LOG_PGMCPU_MEMBER("p", pfnR0BthMapCR3);
3254 LOG_PGMCPU_MEMBER("p", pfnR0BthUnmapCR3);
3255 LOG_PGMCPU_MEMBER("#RX64", cNetwareWp0Hacks);
3256 LOG_PGMCPU_MEMBER("#RX64", cPoolAccessHandler);
3257
3258 }
3259
3260 /*
3261 * PGM globals.
3262 */
3263 RTLogRelPrintf("PGM globals\n");
3264 PPGM pPgm = &pVM->pgm.s;
3265# define LOG_PGM_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPgm->aMember)
3266 LOG_PGM_MEMBER("#RX32", offVM);
3267 LOG_PGM_MEMBER("#RX32", offVCpuPGM);
3268 LOG_PGM_MEMBER("RTbool", fRamPreAlloc);
3269 LOG_PGM_MEMBER("RTbool", fPhysWriteMonitoringEngaged);
3270 LOG_PGM_MEMBER("RTbool", fLessThan52PhysicalAddressBits);
3271 LOG_PGM_MEMBER("RTbool", fNestedPaging);
3272 LOG_PGM_MEMBER("d", enmHostMode);
3273 LOG_PGM_MEMBER("RTbool", fNoMorePhysWrites);
3274 LOG_PGM_MEMBER("RTbool", fPageFusionAllowed);
3275 LOG_PGM_MEMBER("RTbool", fPciPassthrough);
3276 LOG_PGM_MEMBER("#x", cMmio2Regions);
3277 LOG_PGM_MEMBER("RTbool", fRestoreRomPagesOnReset);
3278 LOG_PGM_MEMBER("RTbool", fZeroRamPagesOnReset);
3279 LOG_PGM_MEMBER("RTbool", fFinalizedMappings);
3280 LOG_PGM_MEMBER("RTbool", fMappingsFixed);
3281 LOG_PGM_MEMBER("RTbool", fMappingsFixedRestored);
3282 LOG_PGM_MEMBER("%#x", cbMappingFixed);
3283 LOG_PGM_MEMBER("%#x", idRamRangesGen);
3284 LOG_PGM_MEMBER("#RGv", GCPtrMappingFixed);
3285 LOG_PGM_MEMBER("#RGv", GCPtrPrevRamRangeMapping);
3286 LOG_PGM_MEMBER("%#x", hRomPhysHandlerType);
3287 LOG_PGM_MEMBER("#RGp", GCPhys4MBPSEMask);
3288 LOG_PGM_MEMBER("#RGp", GCPhysInvAddrMask);
3289 LOG_PGM_MEMBER("p", apRamRangesTlbR3[0]);
3290 LOG_PGM_MEMBER("p", apRamRangesTlbR3[1]);
3291 LOG_PGM_MEMBER("p", apRamRangesTlbR3[2]);
3292 LOG_PGM_MEMBER("p", apRamRangesTlbR3[3]);
3293 LOG_PGM_MEMBER("p", apRamRangesTlbR3[4]);
3294 LOG_PGM_MEMBER("p", apRamRangesTlbR3[5]);
3295 LOG_PGM_MEMBER("p", apRamRangesTlbR3[6]);
3296 LOG_PGM_MEMBER("p", apRamRangesTlbR3[7]);
3297 LOG_PGM_MEMBER("p", pRamRangesXR3);
3298 LOG_PGM_MEMBER("p", pRamRangeTreeR3);
3299 LOG_PGM_MEMBER("p", pTreesR3);
3300 LOG_PGM_MEMBER("p", pLastPhysHandlerR3);
3301 LOG_PGM_MEMBER("p", pPoolR3);
3302 LOG_PGM_MEMBER("p", pMappingsR3);
3303 LOG_PGM_MEMBER("p", pRomRangesR3);
3304 LOG_PGM_MEMBER("p", pRegMmioRangesR3);
3305 LOG_PGM_MEMBER("p", paModeData);
3306 LOG_PGM_MEMBER("p", apMmio2RangesR3[0]);
3307 LOG_PGM_MEMBER("p", apMmio2RangesR3[1]);
3308 LOG_PGM_MEMBER("p", apMmio2RangesR3[2]);
3309 LOG_PGM_MEMBER("p", apMmio2RangesR3[3]);
3310 LOG_PGM_MEMBER("p", apMmio2RangesR3[4]);
3311 LOG_PGM_MEMBER("p", apMmio2RangesR3[5]);
3312 LOG_PGM_MEMBER("p", apRamRangesTlbR0[0]);
3313 LOG_PGM_MEMBER("p", apRamRangesTlbR0[1]);
3314 LOG_PGM_MEMBER("p", apRamRangesTlbR0[2]);
3315 LOG_PGM_MEMBER("p", apRamRangesTlbR0[3]);
3316 LOG_PGM_MEMBER("p", apRamRangesTlbR0[4]);
3317 LOG_PGM_MEMBER("p", apRamRangesTlbR0[5]);
3318 LOG_PGM_MEMBER("p", apRamRangesTlbR0[6]);
3319 LOG_PGM_MEMBER("p", apRamRangesTlbR0[7]);
3320 LOG_PGM_MEMBER("p", pRamRangesXR0);
3321 LOG_PGM_MEMBER("p", pRamRangeTreeR0);
3322 LOG_PGM_MEMBER("p", pTreesR0);
3323 LOG_PGM_MEMBER("p", pLastPhysHandlerR0);
3324 LOG_PGM_MEMBER("p", pPoolR0);
3325 LOG_PGM_MEMBER("p", pMappingsR0);
3326 LOG_PGM_MEMBER("p", pRomRangesR0);
3327 LOG_PGM_MEMBER("p", apMmio2RangesR0[0]);
3328 LOG_PGM_MEMBER("p", apMmio2RangesR0[1]);
3329 LOG_PGM_MEMBER("p", apMmio2RangesR0[2]);
3330 LOG_PGM_MEMBER("p", apMmio2RangesR0[3]);
3331 LOG_PGM_MEMBER("p", apMmio2RangesR0[4]);
3332 LOG_PGM_MEMBER("p", apMmio2RangesR0[5]);
3333 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[0]);
3334 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[1]);
3335 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[2]);
3336 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[3]);
3337 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[4]);
3338 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[5]);
3339 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[6]);
3340 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[7]);
3341 LOG_PGM_MEMBER("RRv", pRamRangesXRC);
3342 LOG_PGM_MEMBER("RRv", pRamRangeTreeRC);
3343 LOG_PGM_MEMBER("RRv", pTreesRC);
3344 LOG_PGM_MEMBER("RRv", pLastPhysHandlerRC);
3345 LOG_PGM_MEMBER("RRv", pPoolRC);
3346 LOG_PGM_MEMBER("RRv", pMappingsRC);
3347 LOG_PGM_MEMBER("RRv", pRomRangesRC);
3348 LOG_PGM_MEMBER("RRv", paDynPageMap32BitPTEsGC);
3349 LOG_PGM_MEMBER("RRv", paDynPageMapPaePTEsGC);
3350
3351 LOG_PGM_MEMBER("#RGv", GCPtrCR3Mapping);
3352 LOG_PGM_MEMBER("p", pInterPD);
3353 LOG_PGM_MEMBER("p", apInterPTs[0]);
3354 LOG_PGM_MEMBER("p", apInterPTs[1]);
3355 LOG_PGM_MEMBER("p", apInterPaePTs[0]);
3356 LOG_PGM_MEMBER("p", apInterPaePTs[1]);
3357 LOG_PGM_MEMBER("p", apInterPaePDs[0]);
3358 LOG_PGM_MEMBER("p", apInterPaePDs[1]);
3359 LOG_PGM_MEMBER("p", apInterPaePDs[2]);
3360 LOG_PGM_MEMBER("p", apInterPaePDs[3]);
3361 LOG_PGM_MEMBER("p", pInterPaePDPT);
3362 LOG_PGM_MEMBER("p", pInterPaePML4);
3363 LOG_PGM_MEMBER("p", pInterPaePDPT64);
3364 LOG_PGM_MEMBER("#RHp", HCPhysInterPD);
3365 LOG_PGM_MEMBER("#RHp", HCPhysInterPaePDPT);
3366 LOG_PGM_MEMBER("#RHp", HCPhysInterPaePML4);
3367 LOG_PGM_MEMBER("RRv", pbDynPageMapBaseGC);
3368 LOG_PGM_MEMBER("RRv", pRCDynMap);
3369 LOG_PGM_MEMBER("p", pvR0DynMapUsed);
3370 LOG_PGM_MEMBER("%#x", cDeprecatedPageLocks);
3371
3372 /**
3373 * Data associated with managing the ring-3 mappings of the allocation chunks.
3374 */
3375 LOG_PGM_MEMBER("p", ChunkR3Map.pTree);
3376 //LOG_PGM_MEMBER(PGMCHUNKR3MAPTLB ChunkR3Map.Tlb);
3377 LOG_PGM_MEMBER("%#x", ChunkR3Map.c);
3378 LOG_PGM_MEMBER("%#x", ChunkR3Map.cMax);
3379 LOG_PGM_MEMBER("%#x", ChunkR3Map.iNow);
3380 //LOG_PGM_MEMBER(PGMPAGER3MAPTLB PhysTlbHC);
3381
3382 LOG_PGM_MEMBER("#RHp", HCPhysZeroPg);
3383 LOG_PGM_MEMBER("p", pvZeroPgR3);
3384 LOG_PGM_MEMBER("p", pvZeroPgR0);
3385 LOG_PGM_MEMBER("RRv", pvZeroPgRC);
3386 LOG_PGM_MEMBER("#RHp", HCPhysMmioPg);
3387 LOG_PGM_MEMBER("#RHp", HCPhysInvMmioPg);
3388 LOG_PGM_MEMBER("p", pvMmioPgR3);
3389 LOG_PGM_MEMBER("RTbool", fErrInjHandyPages);
3390
3391 /*
3392 * PGM page pool.
3393 */
3394 PPGMPOOL pPool = pVM->pgm.s.pPoolR3;
3395 RTLogRelPrintf("PGM Page Pool\n");
3396# define LOG_PGMPOOL_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPool->aMember)
3397 LOG_PGMPOOL_MEMBER("p", pVMR3);
3398 LOG_PGMPOOL_MEMBER("p", pVMR0);
3399 LOG_PGMPOOL_MEMBER("RRv", pVMRC);
3400 LOG_PGMPOOL_MEMBER("#x", cMaxPages);
3401 LOG_PGMPOOL_MEMBER("#x", cCurPages);
3402 LOG_PGMPOOL_MEMBER("#x", iFreeHead);
3403 LOG_PGMPOOL_MEMBER("#x", u16Padding);
3404 LOG_PGMPOOL_MEMBER("#x", iUserFreeHead);
3405 LOG_PGMPOOL_MEMBER("#x", cMaxUsers);
3406 LOG_PGMPOOL_MEMBER("#x", cPresent);
3407 LOG_PGMPOOL_MEMBER("RRv", paUsersRC);
3408 LOG_PGMPOOL_MEMBER("p", paUsersR3);
3409 LOG_PGMPOOL_MEMBER("p", paUsersR0);
3410 LOG_PGMPOOL_MEMBER("#x", iPhysExtFreeHead);
3411 LOG_PGMPOOL_MEMBER("#x", cMaxPhysExts);
3412 LOG_PGMPOOL_MEMBER("RRv", paPhysExtsRC);
3413 LOG_PGMPOOL_MEMBER("p", paPhysExtsR3);
3414 LOG_PGMPOOL_MEMBER("p", paPhysExtsR0);
3415 for (uint32_t i = 0; i < RT_ELEMENTS(pPool->aiHash); i++)
3416 RTLogRelPrintf(" aiHash[%u]: %#x\n", i, pPool->aiHash[i]);
3417 LOG_PGMPOOL_MEMBER("#x", iAgeHead);
3418 LOG_PGMPOOL_MEMBER("#x", iAgeTail);
3419 LOG_PGMPOOL_MEMBER("RTbool", fCacheEnabled);
3420 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[0]);
3421 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[1]);
3422 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[2]);
3423 LOG_PGMPOOL_MEMBER("#x", iModifiedHead);
3424 LOG_PGMPOOL_MEMBER("#x", cModifiedPages);
3425 LOG_PGMPOOL_MEMBER("#x", hAccessHandlerType);
3426 LOG_PGMPOOL_MEMBER("#x", idxFreeDirtyPage);
3427 LOG_PGMPOOL_MEMBER("#x", cDirtyPages);
3428 for (uint32_t i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
3429 RTLogRelPrintf(" aDirtyPages[%u].uIdx: %#x\n", i, pPool->aDirtyPages[i].uIdx);
3430 LOG_PGMPOOL_MEMBER("#x", cUsedPages);
3431 LOG_PGMPOOL_MEMBER("#x", HCPhysTree);
3432 for (uint32_t i = 0; i < pPool->cCurPages; i++)
3433 {
3434 PPGMPOOLPAGE pPage = &pPool->aPages[i];
3435# define LOG_PAGE_MEMBER(aFmt, aMember) RTLogRelPrintf(" %3u:%-32s: %" aFmt "\n", i, #aMember, pPage->aMember)
3436 RTLogRelPrintf("%3u:%-32s: %p\n", i, "", pPage);
3437 LOG_PAGE_MEMBER("RHp", Core.Key);
3438 LOG_PAGE_MEMBER("p", pvPageR3);
3439 LOG_PAGE_MEMBER("RGp", GCPhys);
3440 LOG_PAGE_MEMBER("d", enmKind);
3441 LOG_PAGE_MEMBER("d", enmAccess);
3442 LOG_PAGE_MEMBER("RTbool", fA20Enabled);
3443 LOG_PAGE_MEMBER("RTbool", fZeroed);
3444 LOG_PAGE_MEMBER("RTbool", fSeenNonGlobal);
3445 LOG_PAGE_MEMBER("RTbool", fMonitored);
3446 LOG_PAGE_MEMBER("RTbool", fCached);
3447 LOG_PAGE_MEMBER("RTbool", fReusedFlushPending);
3448 LOG_PAGE_MEMBER("RTbool", fDirty);
3449 LOG_PAGE_MEMBER("RTbool", fPadding1);
3450 LOG_PAGE_MEMBER("RTbool", fPadding2);
3451 LOG_PAGE_MEMBER("#x", idx);
3452 LOG_PAGE_MEMBER("#x", iNext);
3453 LOG_PAGE_MEMBER("#x", iUserHead);
3454 LOG_PAGE_MEMBER("#x", cPresent);
3455 LOG_PAGE_MEMBER("#x", iFirstPresent);
3456 LOG_PAGE_MEMBER("#x", cModifications);
3457 LOG_PAGE_MEMBER("#x", iModifiedNext);
3458 LOG_PAGE_MEMBER("#x", iModifiedPrev);
3459 LOG_PAGE_MEMBER("#x", iMonitoredNext);
3460 LOG_PAGE_MEMBER("#x", iMonitoredPrev);
3461 LOG_PAGE_MEMBER("#x", iAgeNext);
3462 LOG_PAGE_MEMBER("#x", iAgePrev);
3463 LOG_PAGE_MEMBER("#x", idxDirtyEntry);
3464 LOG_PAGE_MEMBER("RGv", GCPtrLastAccessHandlerRip);
3465 LOG_PAGE_MEMBER("RGv", GCPtrLastAccessHandlerFault);
3466 LOG_PAGE_MEMBER("#RX64", cLastAccessHandler);
3467 LOG_PAGE_MEMBER("#RX32", cLocked);
3468# ifdef VBOX_STRICT
3469 LOG_PAGE_MEMBER("RGv", GCPtrDirtyFault);
3470# endif
3471 if ( pPage->enmKind == PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT
3472 || pPage->enmKind == PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB
3473 || pPage->enmKind == PGMPOOLKIND_32BIT_PD
3474 || pPage->enmKind == PGMPOOLKIND_32BIT_PD_PHYS)
3475 {
3476 uint32_t const *pu32Page = (uint32_t const *)pPage->pvPageR3;
3477 for (uint32_t i = 0; i < 1024/2; i += 4)
3478 RTLogRelPrintf(" %#05x: %RX32 %RX32 %RX32 %RX32\n", i, pu32Page[i], pu32Page[i+1], pu32Page[i+2], pu32Page[i+3]);
3479 }
3480 else if ( pPage->enmKind != PGMPOOLKIND_FREE
3481 && pPage->enmKind != PGMPOOLKIND_INVALID)
3482 {
3483 uint64_t const *pu64Page = (uint64_t const *)pPage->pvPageR3;
3484 for (uint32_t i = 0; i < 512/2; i += 2)
3485 RTLogRelPrintf(" %#05x: %RX64 %RX64\n", i, pu64Page[i], pu64Page[i+1]);
3486 }
3487 }
3488
3489 RTLogRelPrintf("pgmLogState pgmLogState pgmLogState pgmLogState pgmLogState\n\n");
3490#else
3491 RT_NOREF(pVM);
3492#endif
3493}
3494
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use