VirtualBox

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

Last change on this file since 96860 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

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

© 2023 Oracle
ContactPrivacy policyTerms of Use