VirtualBox

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

Last change on this file since 105266 was 104840, checked in by vboxsync, 5 months ago

VMM/PGM: Refactored RAM ranges, MMIO2 ranges and ROM ranges and added MMIO ranges (to PGM) so we can safely access RAM ranges at runtime w/o fear of them ever being freed up. It is now only possible to create these during VM creation and loading, and they will live till VM destruction (except for MMIO2 which could be destroyed during loading (PCNet fun)). The lookup handling is by table instead of pointer tree. No more ring-0 pointers in shared data. bugref:10687 bugref:10093

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette