VirtualBox

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

Last change on this file since 107307 was 107227, checked in by vboxsync, 2 months ago

VMM: Cleaning up ARMv8 / x86 split. jiraref:VBP-1470

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 154.4 KB
Line 
1/* $Id: PGMDbg.cpp 107227 2024-12-04 15:20:14Z vboxsync $ */
2/** @file
3 * PGM - Page Manager and Monitor - Debugger & Debugging APIs.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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_64BIT_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#ifdef VBOX_VMM_TARGET_X86
1087 Assert(WalkGst.enmType != PGMPTWALKGSTTYPE_INVALID);
1088#endif
1089 Assert(!Walk.fSucceeded);
1090 cbPrev = 0; /* ignore error. */
1091
1092 /*
1093 * Try skip as much as possible. No need to figure out that a PDE
1094 * is not present 512 times!
1095 */
1096 uint64_t cPagesCanSkip;
1097#ifdef VBOX_VMM_TARGET_X86
1098 switch (Walk.uLevel)
1099 {
1100 case 1:
1101 /* page level, use cIncPages */
1102 cPagesCanSkip = 1;
1103 break;
1104 case 2:
1105 if (WalkGst.enmType == PGMPTWALKGSTTYPE_32BIT)
1106 {
1107 cPagesCanSkip = X86_PG_ENTRIES - ((GCPtr >> X86_PT_SHIFT) & X86_PT_MASK);
1108 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PD_SHIFT) - 1)));
1109 }
1110 else
1111 {
1112 cPagesCanSkip = X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
1113 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PD_PAE_SHIFT) - 1)));
1114 }
1115 break;
1116 case 3:
1117 cPagesCanSkip = (X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK)) * X86_PG_PAE_ENTRIES
1118 - ((GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
1119 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PDPT_SHIFT) - 1)));
1120 break;
1121 case 4:
1122 cPagesCanSkip = (X86_PG_PAE_ENTRIES - ((GCPtr >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64))
1123 * X86_PG_PAE_ENTRIES * X86_PG_PAE_ENTRIES
1124 - ((((GCPtr >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK)) * X86_PG_PAE_ENTRIES)
1125 - (( GCPtr >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK);
1126 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT)) & (RT_BIT_64(X86_PML4_SHIFT) - 1)));
1127 break;
1128 case 8:
1129 /* The CR3 value is bad, forget the whole search. */
1130 cPagesCanSkip = cPages;
1131 break;
1132 default:
1133 AssertMsgFailed(("%d\n", Walk.uLevel));
1134 cPagesCanSkip = 0;
1135 break;
1136 }
1137 if (cPages <= cPagesCanSkip)
1138 break;
1139 fFullWalk = true;
1140 if (cPagesCanSkip >= cIncPages)
1141 {
1142 cPages -= cPagesCanSkip;
1143 GCPtr += (RTGCPTR)cPagesCanSkip << X86_PT_PAE_SHIFT;
1144 continue;
1145 }
1146
1147#elif defined(VBOX_VMM_TARGET_ARMV8)
1148
1149 /** @todo Sketch, needs creating proper defines for constants in armv8.h and using these
1150 * instead of hardcoding these here. */
1151 switch (Walk.uLevel)
1152 {
1153 case 0:
1154 case 1:
1155 cPagesCanSkip = (512 - ((GCPtr >> 21) & 0x1ff)) * 512
1156 - ((GCPtr >> 12) & 0x1ff);
1157 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << 12)) & (RT_BIT_64(21) - 1)));
1158 break;
1159 case 2:
1160 cPagesCanSkip = 512 - ((GCPtr >> 12) & 0x1ff);
1161 Assert(!((GCPtr + ((RTGCPTR)cPagesCanSkip << 12)) & (RT_BIT_64(12) - 1)));
1162 break;
1163 case 3:
1164 /* page level, use cIncPages */
1165 cPagesCanSkip = 1;
1166 break;
1167 default:
1168 AssertMsgFailed(("%d\n", Walk.uLevel));
1169 cPagesCanSkip = 0;
1170 break;
1171 }
1172
1173 if (cPages <= cPagesCanSkip)
1174 break;
1175 fFullWalk = true;
1176 if (cPagesCanSkip >= cIncPages)
1177 {
1178 cPages -= cPagesCanSkip;
1179 GCPtr += (RTGCPTR)cPagesCanSkip << 12;
1180 continue;
1181 }
1182#else
1183# error "port me"
1184#endif
1185 }
1186
1187 /* advance to the next page. */
1188 if (cPages <= cIncPages)
1189 break;
1190 cPages -= cIncPages;
1191#ifdef VBOX_VMM_TARGET_X86
1192 GCPtr += (RTGCPTR)cIncPages << X86_PT_PAE_SHIFT;
1193#elif defined(VBOX_VMM_TARGET_ARMV8)
1194 GCPtr += (RTGCPTR)cIncPages << 12;
1195#else
1196# error "port me"
1197#endif
1198
1199 /* Yield the PGM lock every now and then. */
1200 if (!--cYieldCountDown)
1201 {
1202 fFullWalk = PDMR3CritSectYield(pVM, &pVM->pgm.s.CritSectX);
1203 cYieldCountDown = cYieldCountDownReload;
1204 }
1205 }
1206 PGM_UNLOCK(pVM);
1207 return VERR_DBGF_MEM_NOT_FOUND;
1208}
1209
1210
1211/**
1212 * Initializes the dumper state.
1213 *
1214 * @param pState The state to initialize.
1215 * @param pVM The cross context VM structure.
1216 * @param fFlags The flags.
1217 * @param u64FirstAddr The first address.
1218 * @param u64LastAddr The last address.
1219 * @param pHlp The output helpers.
1220 */
1221static void pgmR3DumpHierarchyInitState(PPGMR3DUMPHIERARCHYSTATE pState, PVM pVM, uint32_t fFlags,
1222 uint64_t u64FirstAddr, uint64_t u64LastAddr, PCDBGFINFOHLP pHlp)
1223{
1224 pState->pVM = pVM;
1225 pState->pHlp = pHlp ? pHlp : DBGFR3InfoLogHlp();
1226 pState->fPse = !!(fFlags & (DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
1227 pState->fPae = !!(fFlags & (DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME));
1228 pState->fLme = !!(fFlags & DBGFPGDMP_FLAGS_LME);
1229 pState->fNp = !!(fFlags & DBGFPGDMP_FLAGS_NP);
1230 pState->fEpt = !!(fFlags & DBGFPGDMP_FLAGS_EPT);
1231 pState->fNxe = !!(fFlags & DBGFPGDMP_FLAGS_NXE);
1232 pState->cchAddress = pState->fLme || pState->fEpt ? 16 : 8;
1233 pState->uLastRsvdBit = pState->fNxe ? 62 : 63;
1234 pState->fDumpPageInfo = !!(fFlags & DBGFPGDMP_FLAGS_PAGE_INFO);
1235 pState->fPrintHeader = !!(fFlags & DBGFPGDMP_FLAGS_HEADER);
1236 pState->fPrintCr3 = !!(fFlags & DBGFPGDMP_FLAGS_PRINT_CR3);
1237 pState->afReserved[0] = false;
1238 pState->afReserved[1] = false;
1239 pState->afReserved[2] = false;
1240 pState->afReserved[3] = false;
1241 pState->afReserved[4] = false;
1242 pState->u64Address = u64FirstAddr;
1243 pState->u64FirstAddress = u64FirstAddr;
1244 pState->u64LastAddress = u64LastAddr;
1245 pState->u64HighReservedBits = pState->uLastRsvdBit == 62 ? UINT64_C(0x7ff) << 52 : UINT64_C(0xfff) << 52;
1246 pState->cLeaves = 0;
1247}
1248
1249
1250/**
1251 * The simple way out, too tired to think of a more elegant solution.
1252 *
1253 * @returns The base address of this page table/directory/whatever.
1254 * @param pState The state where we get the current address.
1255 * @param cShift The shift count for the table entries.
1256 * @param cEntries The number of table entries.
1257 * @param piFirst Where to return the table index of the first
1258 * entry to dump.
1259 * @param piLast Where to return the table index of the last
1260 * entry.
1261 */
1262static uint64_t pgmR3DumpHierarchyCalcRange(PPGMR3DUMPHIERARCHYSTATE pState, uint32_t cShift, uint32_t cEntries,
1263 uint32_t *piFirst, uint32_t *piLast)
1264{
1265 const uint64_t iBase = (pState->u64Address >> cShift) & ~(uint64_t)(cEntries - 1);
1266 const uint64_t iFirst = pState->u64FirstAddress >> cShift;
1267 const uint64_t iLast = pState->u64LastAddress >> cShift;
1268
1269 if ( iBase >= iFirst
1270 && iBase + cEntries - 1 <= iLast)
1271 {
1272 /* full range. */
1273 *piFirst = 0;
1274 *piLast = cEntries - 1;
1275 }
1276 else if ( iBase + cEntries - 1 < iFirst
1277 || iBase > iLast)
1278 {
1279 /* no match */
1280 *piFirst = cEntries;
1281 *piLast = 0;
1282 }
1283 else
1284 {
1285 /* partial overlap */
1286 *piFirst = iBase <= iFirst
1287 ? iFirst - iBase
1288 : 0;
1289 *piLast = iBase + cEntries - 1 <= iLast
1290 ? cEntries - 1
1291 : iLast - iBase;
1292 }
1293
1294 return iBase << cShift;
1295}
1296
1297#ifndef VBOX_WITH_ONLY_PGM_NEM_MODE
1298
1299/**
1300 * Maps/finds the shadow page.
1301 *
1302 * @returns VBox status code.
1303 * @param pState The dumper state.
1304 * @param HCPhys The physical address of the shadow page.
1305 * @param pszDesc The description.
1306 * @param ppv Where to return the pointer.
1307 */
1308static int pgmR3DumpHierarchyShwMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, const char *pszDesc, void const **ppv)
1309{
1310 PPGMPOOLPAGE pPoolPage = pgmPoolQueryPageForDbg(pState->pVM->pgm.s.pPoolR3, HCPhys);
1311 if (pPoolPage)
1312 {
1313 *ppv = (uint8_t *)pPoolPage->pvPageR3 + (HCPhys & GUEST_PAGE_OFFSET_MASK);
1314 return VINF_SUCCESS;
1315 }
1316 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! %s at HCPhys=%RHp was not found in the page pool!\n",
1317 pState->cchAddress, pState->u64Address, pszDesc, HCPhys);
1318 return VERR_PGM_POOL_GET_PAGE_FAILED;
1319}
1320
1321
1322/**
1323 * Dumps the a shadow page summary or smth.
1324 *
1325 * @param pState The dumper state.
1326 * @param HCPhys The page address.
1327 */
1328static void pgmR3DumpHierarchyShwTablePageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1329{
1330 PGM_LOCK_VOID(pState->pVM);
1331 char szPage[80];
1332 PPGMPOOLPAGE pPage = pgmPoolQueryPageForDbg(pState->pVM->pgm.s.CTX_SUFF(pPool), HCPhys);
1333 if (pPage)
1334 RTStrPrintf(szPage, sizeof(szPage), " idx=0i%u", pPage->idx);
1335 else
1336 strcpy(szPage, " not found");
1337 PGM_UNLOCK(pState->pVM);
1338 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
1339}
1340
1341
1342/**
1343 * Figures out which guest page this is and dumps a summary.
1344 *
1345 * @param pState The dumper state.
1346 * @param HCPhys The page address.
1347 * @param cbPage The page size.
1348 */
1349static void pgmR3DumpHierarchyShwGuestPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, uint32_t cbPage)
1350{
1351 char szPage[80];
1352 RTGCPHYS GCPhys;
1353 int rc = PGMR3DbgHCPhys2GCPhys(pState->pVM->pUVM, HCPhys, &GCPhys);
1354 if (RT_SUCCESS(rc))
1355 {
1356 PGM_LOCK_VOID(pState->pVM);
1357 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
1358 if (pPage)
1359 RTStrPrintf(szPage, sizeof(szPage), "%R[pgmpage]", pPage);
1360 else
1361 strcpy(szPage, "not found");
1362 PGM_UNLOCK(pState->pVM);
1363 pState->pHlp->pfnPrintf(pState->pHlp, " -> %RGp %s", GCPhys, szPage);
1364 }
1365 else
1366 pState->pHlp->pfnPrintf(pState->pHlp, " not found");
1367 NOREF(cbPage);
1368}
1369
1370
1371/**
1372 * Dumps an EPT shadow page table.
1373 *
1374 * @returns VBox status code (VINF_SUCCESS).
1375 * @param pState The dumper state.
1376 * @param HCPhys The page table address.
1377 */
1378static int pgmR3DumpHierarchyShwEptPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1379{
1380 PCEPTPT pPT = NULL;
1381 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "EPT level 1", (void const **)&pPT);
1382 if (RT_FAILURE(rc))
1383 return rc;
1384
1385 PVM const pVM = pState->pVM;
1386 uint32_t iFirst, iLast;
1387 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PT_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
1388 for (uint32_t i = iFirst; i <= iLast; i++)
1389 {
1390 uint64_t const u = pPT->a[i].u;
1391 if (u & EPT_PRESENT_MASK)
1392 {
1393 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PT_SHIFT);
1394 if ( (u & (EPT_E_WRITE | EPT_E_MEMTYPE_MASK | EPT_E_READ | EPT_E_EXECUTE))
1395 != (EPT_E_WRITE | EPT_E_MEMTYPE_INVALID_3)
1396 || (u & EPT_E_PG_MASK) != pVM->pgm.s.HCPhysInvMmioPg)
1397 {
1398 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1399 "%016llx 1 | %c%c%c %s %c L %c %c %c %c %c %c %c 4K %016llx",
1400 pState->u64Address,
1401 u & EPT_E_READ ? 'R' : '-',
1402 u & EPT_E_WRITE ? 'W' : '-',
1403 u & EPT_E_EXECUTE ? 'X' : '-',
1404 g_aaszEptMemType[1][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1405 u & EPT_E_IGNORE_PAT ? 'I' : '-',
1406 u & EPT_E_ACCESSED ? 'A' : '-',
1407 u & EPT_E_DIRTY ? 'D' : '-',
1408 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1409 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1410 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1411 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1412 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1413 u & EPT_E_PG_MASK);
1414 if (pState->fDumpPageInfo)
1415 pgmR3DumpHierarchyShwGuestPageInfo(pState, u & EPT_E_PG_MASK, _4K);
1416 //if ((u >> 52) & 0x7ff)
1417 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1418 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1419 }
1420 else
1421 {
1422 const char *pszDesc = "???";
1423 PGM_LOCK_VOID(pVM);
1424 PPGMPHYSHANDLER pHandler;
1425 int rc3 = pgmHandlerPhysicalLookup(pVM, u64BaseAddress, &pHandler);
1426 if (RT_SUCCESS(rc3))
1427 pszDesc = pHandler->pszDesc;
1428 PGM_UNLOCK(pVM);
1429
1430 pState->pHlp->pfnPrintf(pState->pHlp, "%016llx 1 | invalid / MMIO optimization (%s)\n",
1431 pState->u64Address, pszDesc);
1432 }
1433 pState->cLeaves++;
1434 }
1435 }
1436 return VINF_SUCCESS;
1437}
1438
1439
1440/**
1441 * Dumps an EPT shadow page directory table.
1442 *
1443 * @returns VBox status code (VINF_SUCCESS).
1444 * @param pState The dumper state.
1445 * @param HCPhys The physical address of the page directory table.
1446 * @param cMaxDepth The maximum depth.
1447 */
1448static int pgmR3DumpHierarchyShwEptPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1449{
1450 PCEPTPD pPD = NULL;
1451 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "EPT level 2", (void const **)&pPD);
1452 if (RT_FAILURE(rc))
1453 return rc;
1454
1455 Assert(cMaxDepth > 0);
1456 cMaxDepth--;
1457
1458 uint32_t iFirst, iLast;
1459 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PD_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
1460 for (uint32_t i = iFirst; i <= iLast; i++)
1461 {
1462 uint64_t const u = pPD->a[i].u;
1463 if (u & EPT_PRESENT_MASK)
1464 {
1465 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PD_SHIFT);
1466 if (u & EPT_E_LEAF)
1467 {
1468 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1469 "%016llx 2 | %c%c%c %s %c L %c %c %c %c %c %c %c 2M %016llx",
1470 pState->u64Address,
1471 u & EPT_E_READ ? 'R' : '-',
1472 u & EPT_E_WRITE ? 'W' : '-',
1473 u & EPT_E_EXECUTE ? 'X' : '-',
1474 g_aaszEptMemType[1][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1475 u & EPT_E_IGNORE_PAT ? 'I' : '-',
1476 u & EPT_E_ACCESSED ? 'A' : '-',
1477 u & EPT_E_DIRTY ? 'D' : '-',
1478 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1479 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1480 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1481 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1482 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1483 u & EPT_E_PG_MASK);
1484 if (pState->fDumpPageInfo)
1485 pgmR3DumpHierarchyShwGuestPageInfo(pState, u & EPT_PDE2M_PG_MASK, _2M);
1486 //if ((u >> 52) & 0x7ff)
1487 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1488 if (u & EPT_PDE2M_MBZ_MASK)
1489 pState->pHlp->pfnPrintf(pState->pHlp, " 20:12=%02llx!", (u >> 12) & 0x1ff);
1490 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1491
1492 pState->cLeaves++;
1493 }
1494 else
1495 {
1496 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1497 "%016llx 2 | %c%c%c %s %c - %c %c %c %c %c %c %c %016llx",
1498 pState->u64Address,
1499 u & EPT_E_READ ? 'R' : '-',
1500 u & EPT_E_WRITE ? 'W' : '-',
1501 u & EPT_E_EXECUTE ? 'X' : '-',
1502 g_aaszEptMemType[0][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1503 u & EPT_E_IGNORE_PAT ? '!' : '-',
1504 u & EPT_E_ACCESSED ? 'A' : '-',
1505 u & EPT_E_DIRTY ? 'D' : '-',
1506 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1507 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1508 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1509 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1510 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1511 u & EPT_E_PG_MASK);
1512 if (pState->fDumpPageInfo)
1513 pgmR3DumpHierarchyShwTablePageInfo(pState, u & EPT_E_PG_MASK);
1514 //if ((u >> 52) & 0x7ff)
1515 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (u >> 52) & 0x7ff);
1516 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1517
1518 if (cMaxDepth)
1519 {
1520 int rc2 = pgmR3DumpHierarchyShwEptPT(pState, u & EPT_E_PG_MASK);
1521 if (rc2 < rc && RT_SUCCESS(rc))
1522 rc = rc2;
1523 }
1524 else
1525 pState->cLeaves++;
1526 }
1527 }
1528 }
1529 return rc;
1530}
1531
1532
1533/**
1534 * Dumps an EPT shadow page directory pointer table.
1535 *
1536 * @returns VBox status code (VINF_SUCCESS).
1537 * @param pState The dumper state.
1538 * @param HCPhys The physical address of the page directory pointer table.
1539 * @param cMaxDepth The maximum depth.
1540 */
1541static int pgmR3DumpHierarchyShwEptPDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1542{
1543 PCEPTPDPT pPDPT = NULL;
1544 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "EPT level 3", (void const **)&pPDPT);
1545 if (RT_FAILURE(rc))
1546 return rc;
1547
1548 Assert(cMaxDepth > 0);
1549 cMaxDepth--;
1550
1551 uint32_t iFirst, iLast;
1552 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PDPT_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
1553 for (uint32_t i = iFirst; i <= iLast; i++)
1554 {
1555 uint64_t const u = pPDPT->a[i].u;
1556 if (u & EPT_PRESENT_MASK)
1557 {
1558 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PDPT_SHIFT);
1559 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1560 "%016llx 3 | %c%c%c %s %c %c %c %c %c %c %c %c %c %016llx",
1561 pState->u64Address,
1562 u & EPT_E_READ ? 'R' : '-',
1563 u & EPT_E_WRITE ? 'W' : '-',
1564 u & EPT_E_EXECUTE ? 'X' : '-',
1565 g_aaszEptMemType[!!(u & EPT_E_LEAF)][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1566 u & EPT_E_IGNORE_PAT ? '!' : '-',
1567 u & EPT_E_LEAF ? '!' : '-',
1568 u & EPT_E_ACCESSED ? 'A' : '-',
1569 u & EPT_E_DIRTY ? 'D' : '-',
1570 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1571 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1572 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1573 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1574 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1575 u & EPT_E_PG_MASK);
1576 if (pState->fDumpPageInfo)
1577 pgmR3DumpHierarchyShwTablePageInfo(pState, u & EPT_E_PG_MASK);
1578 //if ((u >> 52) & 0x7ff)
1579 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx", (u >> 52) & 0x7ff);
1580 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1581
1582 if (cMaxDepth)
1583 {
1584 int rc2 = pgmR3DumpHierarchyShwEptPD(pState, u & EPT_E_PG_MASK, cMaxDepth);
1585 if (rc2 < rc && RT_SUCCESS(rc))
1586 rc = rc2;
1587 }
1588 else
1589 pState->cLeaves++;
1590 }
1591 }
1592 return rc;
1593}
1594
1595
1596/**
1597 * Dumps an EPT shadow PML4 table.
1598 *
1599 * @returns VBox status code (VINF_SUCCESS).
1600 * @param pState The dumper state.
1601 * @param HCPhys The physical address of the table.
1602 * @param cMaxDepth The maximum depth.
1603 */
1604static int pgmR3DumpHierarchyShwEptPML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1605{
1606 PCEPTPML4 pPML4 = NULL;
1607 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "EPT level 4", (void const **)&pPML4);
1608 if (RT_FAILURE(rc))
1609 return rc;
1610
1611 Assert(cMaxDepth);
1612 cMaxDepth--;
1613
1614 uint32_t iFirst = (pState->u64FirstAddress >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
1615 uint32_t iLast = (pState->u64LastAddress >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
1616 for (uint32_t i = iFirst; i <= iLast; i++)
1617 {
1618 uint64_t const u = pPML4->a[i].u;
1619 if (u & EPT_PRESENT_MASK)
1620 {
1621 pState->u64Address = (uint64_t)i << X86_PML4_SHIFT;
1622 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
1623 "%016llx 4 | %c%c%c %s %c %c %c %c %c %c %c %c %c %016llx",
1624 pState->u64Address,
1625 u & EPT_E_READ ? 'R' : '-',
1626 u & EPT_E_WRITE ? 'W' : '-',
1627 u & EPT_E_EXECUTE ? 'X' : '-',
1628 g_aaszEptMemType[!!(u & EPT_E_LEAF)][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
1629 u & EPT_E_IGNORE_PAT ? '!' : '-',
1630 u & EPT_E_LEAF ? '!' : '-',
1631 u & EPT_E_ACCESSED ? 'A' : '-',
1632 u & EPT_E_DIRTY ? 'D' : '-',
1633 u & EPT_E_USER_EXECUTE ? 'U' : '-',
1634 u & EPT_E_PAGING_WRITE ? 'w' : '-',
1635 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
1636 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
1637 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
1638 u & EPT_E_PG_MASK);
1639
1640 if (pState->fDumpPageInfo)
1641 pgmR3DumpHierarchyShwTablePageInfo(pState, u & EPT_E_PG_MASK);
1642 //if ((u >> 52) & 0x7ff)
1643 // pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (u >> 52) & 0x7ff);
1644 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1645
1646 if (cMaxDepth)
1647 {
1648 int rc2 = pgmR3DumpHierarchyShwEptPDPT(pState, u & EPT_E_PG_MASK, cMaxDepth);
1649 if (rc2 < rc && RT_SUCCESS(rc))
1650 rc = rc2;
1651 }
1652 else
1653 pState->cLeaves++;
1654 }
1655 }
1656 return rc;
1657}
1658
1659
1660/**
1661 * Dumps a PAE shadow page table.
1662 *
1663 * @returns VBox status code (VINF_SUCCESS).
1664 * @param pState The dumper state.
1665 * @param HCPhys The page table address.
1666 */
1667static int pgmR3DumpHierarchyShwPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
1668{
1669 PCPGMSHWPTPAE pPT = NULL;
1670 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", (void const **)&pPT);
1671 if (RT_FAILURE(rc))
1672 return rc;
1673
1674 uint32_t iFirst, iLast;
1675 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1676 for (uint32_t i = iFirst; i <= iLast; i++)
1677 if (PGMSHWPTEPAE_GET_U(pPT->a[i]) & X86_PTE_P)
1678 {
1679 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
1680 if (PGMSHWPTEPAE_IS_P(pPT->a[i]))
1681 {
1682 X86PTEPAE Pte;
1683 Pte.u = PGMSHWPTEPAE_GET_U(pPT->a[i]);
1684 pState->pHlp->pfnPrintf(pState->pHlp,
1685 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
1686 ? "%016llx 1 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
1687 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
1688 pState->u64Address,
1689 Pte.n.u1Write ? 'W' : 'R',
1690 Pte.n.u1User ? 'U' : 'S',
1691 Pte.n.u1Accessed ? 'A' : '-',
1692 Pte.n.u1Dirty ? 'D' : '-',
1693 Pte.n.u1Global ? 'G' : '-',
1694 Pte.n.u1WriteThru ? "WT" : "--",
1695 Pte.n.u1CacheDisable? "CD" : "--",
1696 Pte.n.u1PAT ? "AT" : "--",
1697 Pte.n.u1NoExecute ? "NX" : "--",
1698 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
1699 Pte.u & RT_BIT(10) ? '1' : '-',
1700 Pte.u & RT_BIT(11) ? '1' : '-',
1701 Pte.u & X86_PTE_PAE_PG_MASK);
1702 if (pState->fDumpPageInfo)
1703 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
1704 if ((Pte.u >> 52) & 0x7ff)
1705 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pte.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1706 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1707 }
1708 else if ( (PGMSHWPTEPAE_GET_U(pPT->a[i]) & (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1709 == (pState->pVM->pgm.s.HCPhysInvMmioPg | X86_PTE_PAE_MBZ_MASK_NO_NX))
1710 pState->pHlp->pfnPrintf(pState->pHlp,
1711 pState->fLme
1712 ? "%016llx 1 | invalid / MMIO optimization\n"
1713 : "%08llx 1 | invalid / MMIO optimization\n",
1714 pState->u64Address);
1715 else
1716 pState->pHlp->pfnPrintf(pState->pHlp,
1717 pState->fLme
1718 ? "%016llx 1 | invalid: %RX64\n"
1719 : "%08llx 1 | invalid: %RX64\n",
1720 pState->u64Address, PGMSHWPTEPAE_GET_U(pPT->a[i]));
1721 pState->cLeaves++;
1722 }
1723 return VINF_SUCCESS;
1724}
1725
1726
1727/**
1728 * Dumps a PAE shadow page directory table.
1729 *
1730 * @returns VBox status code (VINF_SUCCESS).
1731 * @param pState The dumper state.
1732 * @param HCPhys The physical address of the page directory table.
1733 * @param cMaxDepth The maximum depth.
1734 */
1735static int pgmR3DumpHierarchyShwPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1736{
1737 PCX86PDPAE pPD = NULL;
1738 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", (void const **)&pPD);
1739 if (RT_FAILURE(rc))
1740 return rc;
1741
1742 Assert(cMaxDepth > 0);
1743 cMaxDepth--;
1744
1745 uint32_t iFirst, iLast;
1746 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
1747 for (uint32_t i = iFirst; i <= iLast; i++)
1748 {
1749 X86PDEPAE Pde = pPD->a[i];
1750 if (Pde.n.u1Present)
1751 {
1752 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
1753 if (Pde.b.u1Size)
1754 {
1755 pState->pHlp->pfnPrintf(pState->pHlp,
1756 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
1757 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
1758 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
1759 pState->u64Address,
1760 Pde.b.u1Write ? 'W' : 'R',
1761 Pde.b.u1User ? 'U' : 'S',
1762 Pde.b.u1Accessed ? 'A' : '-',
1763 Pde.b.u1Dirty ? 'D' : '-',
1764 Pde.b.u1Global ? 'G' : '-',
1765 Pde.b.u1WriteThru ? "WT" : "--",
1766 Pde.b.u1CacheDisable? "CD" : "--",
1767 Pde.b.u1PAT ? "AT" : "--",
1768 Pde.b.u1NoExecute ? "NX" : "--",
1769 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
1770 '-',
1771 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1772 Pde.u & X86_PDE2M_PAE_PG_MASK);
1773 if (pState->fDumpPageInfo)
1774 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
1775 if ((Pde.u >> 52) & 0x7ff)
1776 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx%s", (Pde.u >> 52) & 0x7ff, pState->fLme ? "" : "!");
1777 if ((Pde.u >> 13) & 0xff)
1778 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
1779 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1780
1781 pState->cLeaves++;
1782 }
1783 else
1784 {
1785 pState->pHlp->pfnPrintf(pState->pHlp,
1786 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
1787 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
1788 : "%08llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
1789 pState->u64Address,
1790 Pde.n.u1Write ? 'W' : 'R',
1791 Pde.n.u1User ? 'U' : 'S',
1792 Pde.n.u1Accessed ? 'A' : '-',
1793 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
1794 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
1795 Pde.n.u1WriteThru ? "WT" : "--",
1796 Pde.n.u1CacheDisable? "CD" : "--",
1797 Pde.n.u1NoExecute ? "NX" : "--",
1798 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
1799 '-',
1800 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
1801 Pde.u & X86_PDE_PAE_PG_MASK);
1802 if (pState->fDumpPageInfo)
1803 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1804 if ((Pde.u >> 52) & 0x7ff)
1805 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pde.u >> 52) & 0x7ff);
1806 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1807
1808 if (cMaxDepth)
1809 {
1810 int rc2 = pgmR3DumpHierarchyShwPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK);
1811 if (rc2 < rc && RT_SUCCESS(rc))
1812 rc = rc2;
1813 }
1814 else
1815 pState->cLeaves++;
1816 }
1817 }
1818 }
1819 return rc;
1820}
1821
1822
1823/**
1824 * Dumps a PAE shadow page directory pointer table.
1825 *
1826 * @returns VBox status code (VINF_SUCCESS).
1827 * @param pState The dumper state.
1828 * @param HCPhys The physical address of the page directory pointer table.
1829 * @param cMaxDepth The maximum depth.
1830 */
1831static int pgmR3DumpHierarchyShwPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1832{
1833 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
1834 if (!pState->fLme && pState->u64Address >= _4G)
1835 return VINF_SUCCESS;
1836
1837 PCX86PDPT pPDPT = NULL;
1838 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory pointer table", (void const **)&pPDPT);
1839 if (RT_FAILURE(rc))
1840 return rc;
1841
1842 Assert(cMaxDepth > 0);
1843 cMaxDepth--;
1844
1845 uint32_t iFirst, iLast;
1846 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
1847 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
1848 &iFirst, &iLast);
1849 for (uint32_t i = iFirst; i <= iLast; i++)
1850 {
1851 X86PDPE Pdpe = pPDPT->a[i];
1852 if (Pdpe.n.u1Present)
1853 {
1854 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
1855 if (pState->fLme)
1856 {
1857 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
1858 "%016llx 3 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1859 pState->u64Address,
1860 Pdpe.lm.u1Write ? 'W' : 'R',
1861 Pdpe.lm.u1User ? 'U' : 'S',
1862 Pdpe.lm.u1Accessed ? 'A' : '-',
1863 Pdpe.lm.u3Reserved & 1? '?' : '.', /* ignored */
1864 Pdpe.lm.u3Reserved & 4? '!' : '.', /* mbz */
1865 Pdpe.lm.u1WriteThru ? "WT" : "--",
1866 Pdpe.lm.u1CacheDisable? "CD" : "--",
1867 Pdpe.lm.u3Reserved & 2? "!" : "..",/* mbz */
1868 Pdpe.lm.u1NoExecute ? "NX" : "--",
1869 Pdpe.u & RT_BIT(9) ? '1' : '0',
1870 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1871 Pdpe.u & RT_BIT(11) ? '1' : '0',
1872 Pdpe.u & X86_PDPE_PG_MASK);
1873 if (pState->fDumpPageInfo)
1874 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1875 if ((Pdpe.u >> 52) & 0x7ff)
1876 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx", (Pdpe.u >> 52) & 0x7ff);
1877 }
1878 else
1879 {
1880 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
1881 "%08llx 3 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1882 pState->u64Address,
1883 Pdpe.n.u2Reserved & 1? '!' : '.', /* mbz */
1884 Pdpe.n.u2Reserved & 2? '!' : '.', /* mbz */
1885 Pdpe.n.u4Reserved & 1? '!' : '.', /* mbz */
1886 Pdpe.n.u4Reserved & 2? '!' : '.', /* mbz */
1887 Pdpe.n.u4Reserved & 8? '!' : '.', /* mbz */
1888 Pdpe.n.u1WriteThru ? "WT" : "--",
1889 Pdpe.n.u1CacheDisable? "CD" : "--",
1890 Pdpe.n.u4Reserved & 2? "!" : "..",/* mbz */
1891 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
1892 Pdpe.u & RT_BIT(9) ? '1' : '0',
1893 Pdpe.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1894 Pdpe.u & RT_BIT(11) ? '1' : '0',
1895 Pdpe.u & X86_PDPE_PG_MASK);
1896 if (pState->fDumpPageInfo)
1897 pgmR3DumpHierarchyShwTablePageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK);
1898 if ((Pdpe.u >> 52) & 0xfff)
1899 pState->pHlp->pfnPrintf(pState->pHlp, " 63:52=%03llx!", (Pdpe.u >> 52) & 0xfff);
1900 }
1901 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1902
1903 if (cMaxDepth)
1904 {
1905 int rc2 = pgmR3DumpHierarchyShwPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
1906 if (rc2 < rc && RT_SUCCESS(rc))
1907 rc = rc2;
1908 }
1909 else
1910 pState->cLeaves++;
1911 }
1912 }
1913 return rc;
1914}
1915
1916
1917/**
1918 * Dumps a 64-bit shadow PML4 table.
1919 *
1920 * @returns VBox status code (VINF_SUCCESS).
1921 * @param pState The dumper state.
1922 * @param HCPhys The physical address of the table.
1923 * @param cMaxDepth The maximum depth.
1924 */
1925static int pgmR3DumpHierarchyShwPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
1926{
1927 PCX86PML4 pPML4 = NULL;
1928 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page map level 4", (void const **)&pPML4);
1929 if (RT_FAILURE(rc))
1930 return rc;
1931
1932 Assert(cMaxDepth);
1933 cMaxDepth--;
1934
1935 /*
1936 * This is a bit tricky as we're working on unsigned addresses while the
1937 * AMD64 spec uses signed tricks.
1938 */
1939 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1940 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
1941 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
1942 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
1943 { /* Simple, nothing to adjust */ }
1944 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
1945 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
1946 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
1947 iFirst = X86_PG_AMD64_ENTRIES / 2;
1948 else
1949 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
1950
1951 for (uint32_t i = iFirst; i <= iLast; i++)
1952 {
1953 X86PML4E Pml4e = pPML4->a[i];
1954 if (Pml4e.n.u1Present)
1955 {
1956 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
1957 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
1958 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
1959 "%016llx 4 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
1960 pState->u64Address,
1961 Pml4e.n.u1Write ? 'W' : 'R',
1962 Pml4e.n.u1User ? 'U' : 'S',
1963 Pml4e.n.u1Accessed ? 'A' : '-',
1964 Pml4e.n.u3Reserved & 1? '?' : '.', /* ignored */
1965 Pml4e.n.u3Reserved & 4? '!' : '.', /* mbz */
1966 Pml4e.n.u1WriteThru ? "WT" : "--",
1967 Pml4e.n.u1CacheDisable? "CD" : "--",
1968 Pml4e.n.u3Reserved & 2? "!" : "..",/* mbz */
1969 Pml4e.n.u1NoExecute ? "NX" : "--",
1970 Pml4e.u & RT_BIT(9) ? '1' : '0',
1971 Pml4e.u & PGM_PLXFLAGS_PERMANENT ? 'p' : '-',
1972 Pml4e.u & RT_BIT(11) ? '1' : '0',
1973 Pml4e.u & X86_PML4E_PG_MASK);
1974 if (pState->fDumpPageInfo)
1975 pgmR3DumpHierarchyShwTablePageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK);
1976 if ((Pml4e.u >> 52) & 0x7ff)
1977 pState->pHlp->pfnPrintf(pState->pHlp, " 62:52=%03llx!", (Pml4e.u >> 52) & 0x7ff);
1978 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
1979
1980 if (cMaxDepth)
1981 {
1982 int rc2 = pgmR3DumpHierarchyShwPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
1983 if (rc2 < rc && RT_SUCCESS(rc))
1984 rc = rc2;
1985 }
1986 else
1987 pState->cLeaves++;
1988 }
1989 }
1990 return rc;
1991}
1992
1993
1994/**
1995 * Dumps a 32-bit shadow page table.
1996 *
1997 * @returns VBox status code (VINF_SUCCESS).
1998 * @param pState The dumper state.
1999 * @param HCPhys The physical address of the table.
2000 */
2001static int pgmR3DumpHierarchyShw32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
2002{
2003 PCX86PT pPT = NULL;
2004 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page table", (void const **)&pPT);
2005 if (RT_FAILURE(rc))
2006 return rc;
2007
2008 uint32_t iFirst, iLast;
2009 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2010 for (uint32_t i = iFirst; i <= iLast; i++)
2011 {
2012 X86PTE Pte = pPT->a[i];
2013 if (Pte.n.u1Present)
2014 {
2015 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
2016 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
2017 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
2018 pState->u64Address,
2019 Pte.n.u1Write ? 'W' : 'R',
2020 Pte.n.u1User ? 'U' : 'S',
2021 Pte.n.u1Accessed ? 'A' : '-',
2022 Pte.n.u1Dirty ? 'D' : '-',
2023 Pte.n.u1Global ? 'G' : '-',
2024 Pte.n.u1WriteThru ? "WT" : "--",
2025 Pte.n.u1CacheDisable? "CD" : "--",
2026 Pte.n.u1PAT ? "AT" : "--",
2027 Pte.u & PGM_PTFLAGS_TRACK_DIRTY ? 'd' : '-',
2028 Pte.u & RT_BIT(10) ? '1' : '-',
2029 Pte.u & RT_BIT(11) ? '1' : '-',
2030 Pte.u & X86_PDE_PG_MASK);
2031 if (pState->fDumpPageInfo)
2032 pgmR3DumpHierarchyShwGuestPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
2033 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2034 }
2035 }
2036 return VINF_SUCCESS;
2037}
2038
2039
2040/**
2041 * Dumps a 32-bit shadow page directory and page tables.
2042 *
2043 * @returns VBox status code (VINF_SUCCESS).
2044 * @param pState The dumper state.
2045 * @param HCPhys The physical address of the table.
2046 * @param cMaxDepth The maximum depth.
2047 */
2048static int pgmR3DumpHierarchyShw32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
2049{
2050 if (pState->u64Address >= _4G)
2051 return VINF_SUCCESS;
2052
2053 PCX86PD pPD = NULL;
2054 int rc = pgmR3DumpHierarchyShwMapPage(pState, HCPhys, "Page directory", (void const **)&pPD);
2055 if (RT_FAILURE(rc))
2056 return rc;
2057
2058 Assert(cMaxDepth > 0);
2059 cMaxDepth--;
2060
2061 uint32_t iFirst, iLast;
2062 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2063 for (uint32_t i = iFirst; i <= iLast; i++)
2064 {
2065 X86PDE Pde = pPD->a[i];
2066 if (Pde.n.u1Present)
2067 {
2068 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
2069 if (Pde.b.u1Size && pState->fPse)
2070 {
2071 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
2072 | (Pde.u & X86_PDE4M_PG_MASK);
2073 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2074 "%08llx 2 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
2075 pState->u64Address,
2076 Pde.b.u1Write ? 'W' : 'R',
2077 Pde.b.u1User ? 'U' : 'S',
2078 Pde.b.u1Accessed ? 'A' : '-',
2079 Pde.b.u1Dirty ? 'D' : '-',
2080 Pde.b.u1Global ? 'G' : '-',
2081 Pde.b.u1WriteThru ? "WT" : "--",
2082 Pde.b.u1CacheDisable? "CD" : "--",
2083 Pde.b.u1PAT ? "AT" : "--",
2084 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
2085 '-',
2086 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
2087 u64Phys);
2088 if (pState->fDumpPageInfo)
2089 pgmR3DumpHierarchyShwGuestPageInfo(pState, u64Phys, _4M);
2090 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2091 pState->cLeaves++;
2092 }
2093 else
2094 {
2095 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
2096 "%08llx 2 | P %c %c %c %c %c %s %s .. .. 4K %c%c%c %08x",
2097 pState->u64Address,
2098 Pde.n.u1Write ? 'W' : 'R',
2099 Pde.n.u1User ? 'U' : 'S',
2100 Pde.n.u1Accessed ? 'A' : '-',
2101 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2102 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2103 Pde.n.u1WriteThru ? "WT" : "--",
2104 Pde.n.u1CacheDisable? "CD" : "--",
2105 Pde.u & PGM_PDFLAGS_BIG_PAGE ? 'b' : '-',
2106 '-',
2107 Pde.u & PGM_PDFLAGS_TRACK_DIRTY ? 'd' : '-',
2108 Pde.u & X86_PDE_PG_MASK);
2109 if (pState->fDumpPageInfo)
2110 pgmR3DumpHierarchyShwTablePageInfo(pState, Pde.u & X86_PDE_PG_MASK);
2111 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2112
2113 if (cMaxDepth)
2114 {
2115 int rc2 = pgmR3DumpHierarchyShw32BitPT(pState, Pde.u & X86_PDE_PG_MASK);
2116 if (rc2 < rc && RT_SUCCESS(rc))
2117 rc = rc2;
2118 }
2119 else
2120 pState->cLeaves++;
2121 }
2122 }
2123 }
2124
2125 return rc;
2126}
2127
2128
2129/**
2130 * Internal worker that initiates the actual dump.
2131 *
2132 * @returns VBox status code.
2133 * @param pState The dumper state.
2134 * @param cr3 The CR3 value.
2135 * @param cMaxDepth The max depth.
2136 */
2137static int pgmR3DumpHierarchyShwDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
2138{
2139 int rc;
2140 unsigned const cch = pState->cchAddress;
2141 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK /** @todo this should be X86_CR3_EPT_PAGE_MASK */
2142 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
2143 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
2144 : X86_CR3_PAGE_MASK;
2145 if (pState->fPrintCr3)
2146 {
2147 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
2148 : pState->fLme ? "Long Mode"
2149 : pState->fPae ? "PAE Mode"
2150 : pState->fPse ? "32-bit w/ PSE"
2151 : "32-bit";
2152 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
2153 if (pState->fDumpPageInfo)
2154 pgmR3DumpHierarchyShwTablePageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK);
2155 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
2156 pszMode,
2157 pState->fNp ? " + Nested Paging" : "",
2158 pState->fNxe ? " + NX" : "");
2159 }
2160
2161
2162 if (pState->fEpt)
2163 {
2164 if (pState->fPrintHeader)
2165 pState->pHlp->pfnPrintf(pState->pHlp,
2166 "%-*s R - Readable\n"
2167 "%-*s |W - Writeable\n"
2168 "%-*s ||X - Executable\n"
2169 "%-*s ||| EMT - EPT memory type\n"
2170 "%-*s ||| | I - Ignored PAT?\n"
2171 "%-*s ||| | | L - leaf\n"
2172 "%-*s ||| | | | A - accessed\n"
2173 "%-*s ||| | | | | D - dirty\n"
2174 "%-*s ||| | | | | | U - user execute\n"
2175 "%-*s ||| | | | | | | w - Paging writable\n"
2176 "%-*s ||| | | | | | | | k - Supervisor shadow stack writable\n"
2177 "%-*s ||| | | | | | | | | v - Suppress #VE\n"
2178 "%-*s Level ||| | | | | | | | | | page\n"
2179 /* xxxx n **** RWX MT I L A D U w k v 4K xxxxxxxxxxxxx
2180 RWX 7 - - - - - - - - 0123456701234567 */
2181 ,
2182 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
2183 cch, "", cch, "", cch, "", cch, "", cch, "Address");
2184 /** @todo assumes 4-level EPT tables for now. */
2185 rc = pgmR3DumpHierarchyShwEptPML4(pState, cr3 & cr3Mask, cMaxDepth);
2186 }
2187 else
2188 {
2189 if (pState->fPrintHeader)
2190 pState->pHlp->pfnPrintf(pState->pHlp,
2191 "%-*s P - Present\n"
2192 "%-*s | R/W - Read (0) / Write (1)\n"
2193 "%-*s | | U/S - User (1) / Supervisor (0)\n"
2194 "%-*s | | | A - Accessed\n"
2195 "%-*s | | | | D - Dirty\n"
2196 "%-*s | | | | | G - Global\n"
2197 "%-*s | | | | | | WT - Write thru\n"
2198 "%-*s | | | | | | | CD - Cache disable\n"
2199 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
2200 "%-*s | | | | | | | | | NX - No execute (K8)\n"
2201 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
2202 "%-*s | | | | | | | | | | | AVL - a=allocated; m=mapping; d=track dirty;\n"
2203 "%-*s | | | | | | | | | | | | p=permanent; v=validated;\n"
2204 "%-*s Level | | | | | | | | | | | | Page\n"
2205 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
2206 - W U - - - -- -- -- -- -- 010 */
2207 ,
2208 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
2209 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
2210 if (pState->fLme)
2211 rc = pgmR3DumpHierarchyShwPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
2212 else if (pState->fPae)
2213 rc = pgmR3DumpHierarchyShwPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
2214 else
2215 rc = pgmR3DumpHierarchyShw32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
2216 }
2217
2218 if (!pState->cLeaves)
2219 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
2220 return rc;
2221}
2222
2223#endif /* !VBOX_WITH_ONLY_PGM_NEM_MODE */
2224
2225
2226/**
2227 * dbgfR3PagingDumpEx worker.
2228 *
2229 * @returns VBox status code.
2230 * @param pVM The cross context VM structure.
2231 * @param cr3 The CR3 register value.
2232 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
2233 * @param u64FirstAddr The start address.
2234 * @param u64LastAddr The address to stop after.
2235 * @param cMaxDepth The max depth.
2236 * @param pHlp The output callbacks. Defaults to log if NULL.
2237 *
2238 * @internal
2239 */
2240VMMR3_INT_DECL(int) PGMR3DumpHierarchyShw(PVM pVM, uint64_t cr3, uint32_t fFlags, uint64_t u64FirstAddr, uint64_t u64LastAddr,
2241 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
2242{
2243 /* Minimal validation as we're only supposed to service DBGF. */
2244 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
2245 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
2246 AssertReturn(fFlags & DBGFPGDMP_FLAGS_SHADOW, VERR_INVALID_PARAMETER);
2247
2248#ifndef VBOX_WITH_ONLY_PGM_NEM_MODE
2249 PGMR3DUMPHIERARCHYSTATE State;
2250 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, u64FirstAddr, u64LastAddr, pHlp);
2251 PGM_LOCK_VOID(pVM);
2252 int rc = pgmR3DumpHierarchyShwDoIt(&State, cr3, cMaxDepth);
2253 PGM_UNLOCK(pVM);
2254 return rc;
2255#else
2256 RT_NOREF(pVM, cr3, fFlags, u64FirstAddr, u64LastAddr, cMaxDepth, pHlp);
2257 return VINF_SUCCESS;
2258#endif
2259}
2260
2261
2262/**
2263 * Dumps a page table hierarchy use only physical addresses and cr4/lm flags.
2264 *
2265 * @returns VBox status code (VINF_SUCCESS).
2266 * @param pVM The cross context VM structure.
2267 * @param cr3 The root of the hierarchy.
2268 * @param cr4 The cr4, only PAE and PSE is currently used.
2269 * @param fLongMode Set if long mode, false if not long mode.
2270 * @param cMaxDepth Number of levels to dump.
2271 * @param pHlp Pointer to the output functions.
2272 *
2273 * @deprecated Use DBGFR3PagingDumpEx.
2274 */
2275VMMR3DECL(int) PGMR3DumpHierarchyHC(PVM pVM, uint64_t cr3, uint64_t cr4, bool fLongMode, unsigned cMaxDepth, PCDBGFINFOHLP pHlp)
2276{
2277 if (!cMaxDepth)
2278 return VINF_SUCCESS;
2279
2280 PVMCPU pVCpu = VMMGetCpu(pVM);
2281 if (!pVCpu)
2282 pVCpu = pVM->apCpusR3[0];
2283
2284 uint32_t fFlags = DBGFPGDMP_FLAGS_HEADER | DBGFPGDMP_FLAGS_PRINT_CR3 | DBGFPGDMP_FLAGS_PAGE_INFO | DBGFPGDMP_FLAGS_SHADOW;
2285 fFlags |= cr4 & (X86_CR4_PAE | X86_CR4_PSE);
2286 if (fLongMode)
2287 fFlags |= DBGFPGDMP_FLAGS_LME;
2288
2289 return DBGFR3PagingDumpEx(pVM->pUVM, pVCpu->idCpu, fFlags, cr3, 0, fLongMode ? UINT64_MAX : UINT32_MAX, cMaxDepth, pHlp);
2290}
2291
2292
2293/**
2294 * Maps the guest page.
2295 *
2296 * @returns VBox status code.
2297 * @param pState The dumper state.
2298 * @param GCPhys The physical address of the guest page.
2299 * @param pszDesc The description.
2300 * @param ppv Where to return the pointer.
2301 * @param pLock Where to return the mapping lock. Hand this to
2302 * PGMPhysReleasePageMappingLock when done.
2303 */
2304static int pgmR3DumpHierarchyGstMapPage(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, const char *pszDesc,
2305 void const **ppv, PPGMPAGEMAPLOCK pLock)
2306{
2307 int rc = PGMPhysGCPhys2CCPtrReadOnly(pState->pVM, GCPhys, ppv, pLock);
2308 if (RT_FAILURE(rc))
2309 {
2310 pState->pHlp->pfnPrintf(pState->pHlp, "%0*llx error! Failed to map %s at GCPhys=%RGp: %Rrc!\n",
2311 pState->cchAddress, pState->u64Address, pszDesc, GCPhys, rc);
2312 return rc;
2313 }
2314 return VINF_SUCCESS;
2315}
2316
2317
2318/**
2319 * Figures out which guest page this is and dumps a summary.
2320 *
2321 * @param pState The dumper state.
2322 * @param GCPhys The page address.
2323 * @param cbPage The page size.
2324 */
2325static void pgmR3DumpHierarchyGstPageInfo(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, uint32_t cbPage)
2326{
2327 char szPage[80];
2328 PGM_LOCK_VOID(pState->pVM);
2329 PCPGMPAGE pPage = pgmPhysGetPage(pState->pVM, GCPhys);
2330 if (pPage)
2331 RTStrPrintf(szPage, sizeof(szPage), " %R[pgmpage]", pPage);
2332 else
2333 strcpy(szPage, " not found");
2334 PGM_UNLOCK(pState->pVM);
2335 pState->pHlp->pfnPrintf(pState->pHlp, "%s", szPage);
2336 NOREF(cbPage);
2337}
2338
2339
2340/**
2341 * Checks the entry for reserved bits.
2342 *
2343 * @param pState The dumper state.
2344 * @param u64Entry The entry to check.
2345 */
2346static void pgmR3DumpHierarchyGstCheckReservedHighBits(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t u64Entry)
2347{
2348 uint32_t uRsvd = (u64Entry & pState->u64HighReservedBits) >> 52;
2349 if (uRsvd)
2350 pState->pHlp->pfnPrintf(pState->pHlp, " %u:52=%03x%s",
2351 pState->uLastRsvdBit, uRsvd, pState->fLme ? "" : "!");
2352 /** @todo check the valid physical bits as well. */
2353}
2354
2355
2356/**
2357 * Dumps an EPT guest page table.
2358 *
2359 * @returns VBox status code (VINF_SUCCESS).
2360 * @param pState The dumper state.
2361 * @param HCPhys The page table address.
2362 */
2363static int pgmR3DumpHierarchyGstEptPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys)
2364{
2365 PCEPTPT pPT = NULL;
2366 PGMPAGEMAPLOCK Lock;
2367 int rc = pgmR3DumpHierarchyGstMapPage(pState, HCPhys, "Guest EPT level 1", (void const **)&pPT, &Lock);
2368 if (RT_FAILURE(rc))
2369 return rc;
2370
2371 uint32_t iFirst, iLast;
2372 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PT_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
2373 for (uint32_t i = iFirst; i <= iLast; i++)
2374 {
2375 uint64_t const u = pPT->a[i].u;
2376 if (u & EPT_PRESENT_MASK)
2377 {
2378 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PT_SHIFT);
2379 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2380 "%016llx 1 | %c%c%c %s %c L %c %c %c %c %c %c %c 4K %016llx",
2381 pState->u64Address,
2382 u & EPT_E_READ ? 'R' : '-',
2383 u & EPT_E_WRITE ? 'W' : '-',
2384 u & EPT_E_EXECUTE ? 'X' : '-',
2385 g_aaszEptMemType[1][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2386 u & EPT_E_IGNORE_PAT ? 'I' : '-',
2387 u & EPT_E_ACCESSED ? 'A' : '-',
2388 u & EPT_E_DIRTY ? 'D' : '-',
2389 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2390 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2391 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2392 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2393 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2394 u & EPT_E_PG_MASK);
2395 if (pState->fDumpPageInfo)
2396 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_E_PG_MASK, _4K);
2397 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2398 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2399 pState->cLeaves++;
2400 }
2401 }
2402
2403 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2404 return VINF_SUCCESS;
2405}
2406
2407
2408/**
2409 * Dumps an EPT guest page directory table.
2410 *
2411 * @returns VBox status code (VINF_SUCCESS).
2412 * @param pState The dumper state.
2413 * @param HCPhys The physical address of the page directory table.
2414 * @param cMaxDepth The maximum depth.
2415 */
2416static int pgmR3DumpHierarchyGstEptPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
2417{
2418 PCEPTPD pPD = NULL;
2419 PGMPAGEMAPLOCK Lock;
2420 int rc = pgmR3DumpHierarchyGstMapPage(pState, HCPhys, "Guest EPT level 2", (void const **)&pPD, &Lock);
2421 if (RT_FAILURE(rc))
2422 return rc;
2423
2424 Assert(cMaxDepth > 0);
2425 cMaxDepth--;
2426
2427 uint32_t iFirst, iLast;
2428 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PD_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
2429 for (uint32_t i = iFirst; i <= iLast; i++)
2430 {
2431 uint64_t const u = pPD->a[i].u;
2432 if (u & EPT_PRESENT_MASK)
2433 {
2434 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PD_SHIFT);
2435 if (u & EPT_E_LEAF)
2436 {
2437 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2438 "%016llx 2 | %c%c%c %s %c L %c %c %c %c %c %c %c 2M %016llx",
2439 pState->u64Address,
2440 u & EPT_E_READ ? 'R' : '-',
2441 u & EPT_E_WRITE ? 'W' : '-',
2442 u & EPT_E_EXECUTE ? 'X' : '-',
2443 g_aaszEptMemType[1][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2444 u & EPT_E_IGNORE_PAT ? 'I' : '-',
2445 u & EPT_E_ACCESSED ? 'A' : '-',
2446 u & EPT_E_DIRTY ? 'D' : '-',
2447 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2448 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2449 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2450 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2451 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2452 u & EPT_E_PG_MASK);
2453 if (pState->fDumpPageInfo)
2454 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_PDE2M_PG_MASK, _2M);
2455 if (u & EPT_PDE2M_MBZ_MASK)
2456 pState->pHlp->pfnPrintf(pState->pHlp, " 20:12=%02llx!", (u >> 12) & 0x1ff);
2457 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2458 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2459
2460 pState->cLeaves++;
2461 }
2462 else
2463 {
2464 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2465 "%016llx 2 | %c%c%c %s %c - %c %c %c %c %c %c %c %016llx",
2466 pState->u64Address,
2467 u & EPT_E_READ ? 'R' : '-',
2468 u & EPT_E_WRITE ? 'W' : '-',
2469 u & EPT_E_EXECUTE ? 'X' : '-',
2470 g_aaszEptMemType[0][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2471 u & EPT_E_IGNORE_PAT ? '!' : '-',
2472 u & EPT_E_ACCESSED ? 'A' : '-',
2473 u & EPT_E_DIRTY ? 'D' : '-',
2474 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2475 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2476 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2477 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2478 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2479 u & EPT_E_PG_MASK);
2480 if (pState->fDumpPageInfo)
2481 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_E_PG_MASK, _4K);
2482 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2483 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2484
2485 if (cMaxDepth)
2486 {
2487 int rc2 = pgmR3DumpHierarchyGstEptPT(pState, u & EPT_E_PG_MASK);
2488 if (rc2 < rc && RT_SUCCESS(rc))
2489 rc = rc2;
2490 }
2491 else
2492 pState->cLeaves++;
2493 }
2494 }
2495 }
2496
2497 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2498 return rc;
2499}
2500
2501
2502/**
2503 * Dumps an EPT guest page directory pointer table.
2504 *
2505 * @returns VBox status code (VINF_SUCCESS).
2506 * @param pState The dumper state.
2507 * @param HCPhys The physical address of the page directory pointer table.
2508 * @param cMaxDepth The maximum depth.
2509 */
2510static int pgmR3DumpHierarchyGstEptPDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
2511{
2512 PCEPTPDPT pPDPT = NULL;
2513 PGMPAGEMAPLOCK Lock;
2514 int rc = pgmR3DumpHierarchyGstMapPage(pState, HCPhys, "Guest EPT level 3", (void const **)&pPDPT, &Lock);
2515 if (RT_FAILURE(rc))
2516 return rc;
2517
2518 Assert(cMaxDepth > 0);
2519 cMaxDepth--;
2520
2521 uint32_t iFirst, iLast;
2522 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, EPT_PDPT_SHIFT, EPT_PG_ENTRIES, &iFirst, &iLast);
2523 for (uint32_t i = iFirst; i <= iLast; i++)
2524 {
2525 uint64_t const u = pPDPT->a[i].u;
2526 if (u & EPT_PRESENT_MASK)
2527 {
2528 pState->u64Address = u64BaseAddress + ((uint64_t)i << EPT_PDPT_SHIFT);
2529 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2530 "%016llx 3 | %c%c%c %s %c %c %c %c %c %c %c %c %c %016llx",
2531 pState->u64Address,
2532 u & EPT_E_READ ? 'R' : '-',
2533 u & EPT_E_WRITE ? 'W' : '-',
2534 u & EPT_E_EXECUTE ? 'X' : '-',
2535 g_aaszEptMemType[!!(u & EPT_E_LEAF)][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2536 u & EPT_E_IGNORE_PAT ? '!' : '-',
2537 u & EPT_E_LEAF ? '!' : '-',
2538 u & EPT_E_ACCESSED ? 'A' : '-',
2539 u & EPT_E_DIRTY ? 'D' : '-',
2540 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2541 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2542 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2543 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2544 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2545 u & EPT_E_PG_MASK);
2546 if (pState->fDumpPageInfo)
2547 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_E_PG_MASK, _4K);
2548 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2549 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2550
2551 if (cMaxDepth)
2552 {
2553 int rc2 = pgmR3DumpHierarchyGstEptPD(pState, u & EPT_E_PG_MASK, cMaxDepth);
2554 if (rc2 < rc && RT_SUCCESS(rc))
2555 rc = rc2;
2556 }
2557 else
2558 pState->cLeaves++;
2559 }
2560 }
2561
2562 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2563 return rc;
2564}
2565
2566
2567/**
2568 * Dumps an EPT guest PML4 table.
2569 *
2570 * @returns VBox status code (VINF_SUCCESS).
2571 * @param pState The dumper state.
2572 * @param HCPhys The physical address of the table.
2573 * @param cMaxDepth The maximum depth.
2574 */
2575static int pgmR3DumpHierarchyGstEptPML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS HCPhys, unsigned cMaxDepth)
2576{
2577 PCEPTPML4 pPML4 = NULL;
2578 PGMPAGEMAPLOCK Lock;
2579 int rc = pgmR3DumpHierarchyGstMapPage(pState, HCPhys, "Guest EPT level 4", (void const **)&pPML4, &Lock);
2580 if (RT_FAILURE(rc))
2581 return rc;
2582
2583 Assert(cMaxDepth);
2584 cMaxDepth--;
2585
2586 uint32_t iFirst = (pState->u64FirstAddress >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
2587 uint32_t iLast = (pState->u64LastAddress >> EPT_PML4_SHIFT) & EPT_PML4_MASK;
2588 for (uint32_t i = iFirst; i <= iLast; i++)
2589 {
2590 uint64_t const u = pPML4->a[i].u;
2591 if (u & EPT_PRESENT_MASK)
2592 {
2593 pState->u64Address = (uint64_t)i << X86_PML4_SHIFT;
2594 pState->pHlp->pfnPrintf(pState->pHlp, /* R W X MT I L A D U w k s v */
2595 "%016llx 4 | %c%c%c %s %c %c %c %c %c %c %c %c %c %016llx",
2596 pState->u64Address,
2597 u & EPT_E_READ ? 'R' : '-',
2598 u & EPT_E_WRITE ? 'W' : '-',
2599 u & EPT_E_EXECUTE ? 'X' : '-',
2600 g_aaszEptMemType[!!(u & EPT_E_LEAF)][(u >> EPT_E_MEMTYPE_SHIFT) & EPT_E_MEMTYPE_SMASK],
2601 u & EPT_E_IGNORE_PAT ? '!' : '-',
2602 u & EPT_E_LEAF ? '!' : '-',
2603 u & EPT_E_ACCESSED ? 'A' : '-',
2604 u & EPT_E_DIRTY ? 'D' : '-',
2605 u & EPT_E_USER_EXECUTE ? 'U' : '-',
2606 u & EPT_E_PAGING_WRITE ? 'w' : '-',
2607 u & EPT_E_SUPER_SHW_STACK ? 'k' : '-',
2608 u & EPT_E_SUBPAGE_WRITE_PERM ? 's' : '-',
2609 u & EPT_E_SUPPRESS_VE ? 'v' : '-',
2610 u & EPT_E_PG_MASK);
2611 if (pState->fDumpPageInfo)
2612 pgmR3DumpHierarchyGstPageInfo(pState, u & EPT_E_PG_MASK, _4K);
2613 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, u);
2614 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2615
2616 if (cMaxDepth)
2617 {
2618 int rc2 = pgmR3DumpHierarchyGstEptPDPT(pState, u & EPT_E_PG_MASK, cMaxDepth);
2619 if (rc2 < rc && RT_SUCCESS(rc))
2620 rc = rc2;
2621 }
2622 else
2623 pState->cLeaves++;
2624 }
2625 }
2626
2627 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2628 return rc;
2629}
2630
2631
2632/**
2633 * Dumps a PAE guest page table.
2634 *
2635 * @returns VBox status code (VINF_SUCCESS).
2636 * @param pState The dumper state.
2637 * @param GCPhys The page table address.
2638 */
2639static int pgmR3DumpHierarchyGstPaePT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys)
2640{
2641 PCX86PTPAE pPT;
2642 PGMPAGEMAPLOCK Lock;
2643 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
2644 if (RT_FAILURE(rc))
2645 return rc;
2646
2647 uint32_t iFirst, iLast;
2648 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
2649 for (uint32_t i = iFirst; i <= iLast; i++)
2650 {
2651 X86PTEPAE Pte = pPT->a[i];
2652 if (Pte.n.u1Present)
2653 {
2654 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PT_PAE_SHIFT);
2655 pState->pHlp->pfnPrintf(pState->pHlp,
2656 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? */
2657 ? "%016llx 3 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx"
2658 : "%08llx 2 | P %c %c %c %c %c %s %s %s %s 4K %c%c%c %016llx",
2659 pState->u64Address,
2660 Pte.n.u1Write ? 'W' : 'R',
2661 Pte.n.u1User ? 'U' : 'S',
2662 Pte.n.u1Accessed ? 'A' : '-',
2663 Pte.n.u1Dirty ? 'D' : '-',
2664 Pte.n.u1Global ? 'G' : '-',
2665 Pte.n.u1WriteThru ? "WT" : "--",
2666 Pte.n.u1CacheDisable? "CD" : "--",
2667 Pte.n.u1PAT ? "AT" : "--",
2668 Pte.n.u1NoExecute ? "NX" : "--",
2669 Pte.u & RT_BIT(9) ? '1' : '0',
2670 Pte.u & RT_BIT(10) ? '1' : '0',
2671 Pte.u & RT_BIT(11) ? '1' : '0',
2672 Pte.u & X86_PTE_PAE_PG_MASK);
2673 if (pState->fDumpPageInfo)
2674 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PTE_PAE_PG_MASK, _4K);
2675 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pte.u);
2676 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2677 pState->cLeaves++;
2678 }
2679 }
2680
2681 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2682 return VINF_SUCCESS;
2683}
2684
2685
2686/**
2687 * Dumps a PAE guest page directory table.
2688 *
2689 * @returns VBox status code (VINF_SUCCESS).
2690 * @param pState The dumper state.
2691 * @param GCPhys The physical address of the table.
2692 * @param cMaxDepth The maximum depth.
2693 */
2694static int pgmR3DumpHierarchyGstPaePD(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
2695{
2696 PCX86PDPAE pPD;
2697 PGMPAGEMAPLOCK Lock;
2698 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
2699 if (RT_FAILURE(rc))
2700 return rc;
2701
2702 Assert(cMaxDepth > 0);
2703 cMaxDepth--;
2704
2705 uint32_t iFirst, iLast;
2706 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PD_PAE_SHIFT, X86_PG_PAE_ENTRIES, &iFirst, &iLast);
2707 for (uint32_t i = iFirst; i <= iLast; i++)
2708 {
2709 X86PDEPAE Pde = pPD->a[i];
2710 if (Pde.n.u1Present)
2711 {
2712 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PD_PAE_SHIFT);
2713 if (Pde.b.u1Size)
2714 {
2715 pState->pHlp->pfnPrintf(pState->pHlp,
2716 pState->fLme /*P R S A D G WT CD AT NX 2M a p ? phys*/
2717 ? "%016llx 2 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx"
2718 : "%08llx 1 | P %c %c %c %c %c %s %s %s %s 2M %c%c%c %016llx",
2719 pState->u64Address,
2720 Pde.b.u1Write ? 'W' : 'R',
2721 Pde.b.u1User ? 'U' : 'S',
2722 Pde.b.u1Accessed ? 'A' : '-',
2723 Pde.b.u1Dirty ? 'D' : '-',
2724 Pde.b.u1Global ? 'G' : '-',
2725 Pde.b.u1WriteThru ? "WT" : "--",
2726 Pde.b.u1CacheDisable ? "CD" : "--",
2727 Pde.b.u1PAT ? "AT" : "--",
2728 Pde.b.u1NoExecute ? "NX" : "--",
2729 Pde.u & RT_BIT_64(9) ? '1' : '0',
2730 Pde.u & RT_BIT_64(10) ? '1' : '0',
2731 Pde.u & RT_BIT_64(11) ? '1' : '0',
2732 Pde.u & X86_PDE2M_PAE_PG_MASK);
2733 if (pState->fDumpPageInfo)
2734 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE2M_PAE_PG_MASK, _2M);
2735 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
2736 if ((Pde.u >> 13) & 0xff)
2737 pState->pHlp->pfnPrintf(pState->pHlp, " 20:13=%02llx%s", (Pde.u >> 13) & 0x0ff, pState->fLme ? "" : "!");
2738 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2739
2740 pState->cLeaves++;
2741 }
2742 else
2743 {
2744 pState->pHlp->pfnPrintf(pState->pHlp,
2745 pState->fLme /*P R S A D G WT CD AT NX 4M a p ? phys */
2746 ? "%016llx 2 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx"
2747 : "%08llx 1 | P %c %c %c %c %c %s %s .. %s .. %c%c%c %016llx",
2748 pState->u64Address,
2749 Pde.n.u1Write ? 'W' : 'R',
2750 Pde.n.u1User ? 'U' : 'S',
2751 Pde.n.u1Accessed ? 'A' : '-',
2752 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
2753 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
2754 Pde.n.u1WriteThru ? "WT" : "--",
2755 Pde.n.u1CacheDisable ? "CD" : "--",
2756 Pde.n.u1NoExecute ? "NX" : "--",
2757 Pde.u & RT_BIT_64(9) ? '1' : '0',
2758 Pde.u & RT_BIT_64(10) ? '1' : '0',
2759 Pde.u & RT_BIT_64(11) ? '1' : '0',
2760 Pde.u & X86_PDE_PAE_PG_MASK);
2761 if (pState->fDumpPageInfo)
2762 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PAE_PG_MASK, _4K);
2763 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pde.u);
2764 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2765
2766 if (cMaxDepth)
2767 {
2768 int rc2 = pgmR3DumpHierarchyGstPaePT(pState, Pde.u & X86_PDE_PAE_PG_MASK);
2769 if (rc2 < rc && RT_SUCCESS(rc))
2770 rc = rc2;
2771 }
2772 else
2773 pState->cLeaves++;
2774 }
2775 }
2776 }
2777
2778 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2779 return rc;
2780}
2781
2782
2783/**
2784 * Dumps a PAE guest page directory pointer table.
2785 *
2786 * @returns VBox status code (VINF_SUCCESS).
2787 * @param pState The dumper state.
2788 * @param GCPhys The physical address of the table.
2789 * @param cMaxDepth The maximum depth.
2790 */
2791static int pgmR3DumpHierarchyGstPaePDPT(PPGMR3DUMPHIERARCHYSTATE pState, RTGCPHYS GCPhys, unsigned cMaxDepth)
2792{
2793 /* Fend of addresses that are out of range in PAE mode - simplifies the code below. */
2794 if (!pState->fLme && pState->u64Address >= _4G)
2795 return VINF_SUCCESS;
2796
2797 PCX86PDPT pPDPT;
2798 PGMPAGEMAPLOCK Lock;
2799 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory pointer table", (void const **)&pPDPT, &Lock);
2800 if (RT_FAILURE(rc))
2801 return rc;
2802
2803 Assert(cMaxDepth > 0);
2804 cMaxDepth--;
2805
2806 uint32_t iFirst, iLast;
2807 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PDPT_SHIFT,
2808 pState->fLme ? X86_PG_AMD64_PDPE_ENTRIES : X86_PG_PAE_PDPE_ENTRIES,
2809 &iFirst, &iLast);
2810 for (uint32_t i = iFirst; i <= iLast; i++)
2811 {
2812 X86PDPE Pdpe = pPDPT->a[i];
2813 if (Pdpe.n.u1Present)
2814 {
2815 pState->u64Address = u64BaseAddress + ((uint64_t)i << X86_PDPT_SHIFT);
2816 if (pState->fLme)
2817 {
2818 /** @todo Do 1G pages. */
2819 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX .. a p ? */
2820 "%016llx 1 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2821 pState->u64Address,
2822 Pdpe.lm.u1Write ? 'W' : 'R',
2823 Pdpe.lm.u1User ? 'U' : 'S',
2824 Pdpe.lm.u1Accessed ? 'A' : '-',
2825 Pdpe.lm.u3Reserved & 1 ? '?' : '.', /* ignored */
2826 Pdpe.lm.u3Reserved & 4 ? '!' : '.', /* mbz */
2827 Pdpe.lm.u1WriteThru ? "WT" : "--",
2828 Pdpe.lm.u1CacheDisable ? "CD" : "--",
2829 Pdpe.lm.u3Reserved & 2 ? "!" : "..",/* mbz */
2830 Pdpe.lm.u1NoExecute ? "NX" : "--",
2831 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
2832 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
2833 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
2834 Pdpe.u & X86_PDPE_PG_MASK);
2835 if (pState->fDumpPageInfo)
2836 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
2837 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
2838 }
2839 else
2840 {
2841 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX .. a p ? */
2842 "%08llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2843 pState->u64Address,
2844 Pdpe.n.u2Reserved & 1 ? '!' : '.', /* mbz */
2845 Pdpe.n.u2Reserved & 2 ? '!' : '.', /* mbz */
2846 Pdpe.n.u4Reserved & 1 ? '!' : '.', /* mbz */
2847 Pdpe.n.u4Reserved & 2 ? '!' : '.', /* mbz */
2848 Pdpe.n.u4Reserved & 8 ? '!' : '.', /* mbz */
2849 Pdpe.n.u1WriteThru ? "WT" : "--",
2850 Pdpe.n.u1CacheDisable ? "CD" : "--",
2851 Pdpe.n.u4Reserved & 2 ? "!" : "..", /* mbz */
2852 Pdpe.lm.u1NoExecute ? "!!" : "..",/* mbz */
2853 Pdpe.u & RT_BIT_64(9) ? '1' : '0',
2854 Pdpe.u & RT_BIT_64(10) ? '1' : '0',
2855 Pdpe.u & RT_BIT_64(11) ? '1' : '0',
2856 Pdpe.u & X86_PDPE_PG_MASK);
2857 if (pState->fDumpPageInfo)
2858 pgmR3DumpHierarchyGstPageInfo(pState, Pdpe.u & X86_PDPE_PG_MASK, _4K);
2859 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pdpe.u);
2860 }
2861 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2862
2863 if (cMaxDepth)
2864 {
2865 int rc2 = pgmR3DumpHierarchyGstPaePD(pState, Pdpe.u & X86_PDPE_PG_MASK, cMaxDepth);
2866 if (rc2 < rc && RT_SUCCESS(rc))
2867 rc = rc2;
2868 }
2869 else
2870 pState->cLeaves++;
2871 }
2872 }
2873
2874 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2875 return rc;
2876}
2877
2878
2879/**
2880 * Dumps a 32-bit guest page table.
2881 *
2882 * @returns VBox status code (VINF_SUCCESS).
2883 * @param pState The dumper state.
2884 * @param GCPhys The physical address of the table.
2885 * @param cMaxDepth The maximum depth.
2886 */
2887static int pgmR3DumpHierarchyGstPaePML4(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
2888{
2889 PCX86PML4 pPML4;
2890 PGMPAGEMAPLOCK Lock;
2891 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page map level 4", (void const **)&pPML4, &Lock);
2892 if (RT_FAILURE(rc))
2893 return rc;
2894
2895 Assert(cMaxDepth);
2896 cMaxDepth--;
2897
2898 /*
2899 * This is a bit tricky as we're working on unsigned addresses while the
2900 * AMD64 spec uses signed tricks.
2901 */
2902 uint32_t iFirst = (pState->u64FirstAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2903 uint32_t iLast = (pState->u64LastAddress >> X86_PML4_SHIFT) & X86_PML4_MASK;
2904 if ( pState->u64LastAddress <= UINT64_C(0x00007fffffffffff)
2905 || pState->u64FirstAddress >= UINT64_C(0xffff800000000000))
2906 { /* Simple, nothing to adjust */ }
2907 else if (pState->u64FirstAddress <= UINT64_C(0x00007fffffffffff))
2908 iLast = X86_PG_AMD64_ENTRIES / 2 - 1;
2909 else if (pState->u64LastAddress >= UINT64_C(0xffff800000000000))
2910 iFirst = X86_PG_AMD64_ENTRIES / 2;
2911 else
2912 iFirst = X86_PG_AMD64_ENTRIES; /* neither address is canonical */
2913
2914 for (uint32_t i = iFirst; i <= iLast; i++)
2915 {
2916 X86PML4E Pml4e = pPML4->a[i];
2917 if (Pml4e.n.u1Present)
2918 {
2919 pState->u64Address = ((uint64_t)i << X86_PML4_SHIFT)
2920 | (i >= RT_ELEMENTS(pPML4->a) / 2 ? UINT64_C(0xffff000000000000) : 0);
2921 pState->pHlp->pfnPrintf(pState->pHlp, /*P R S A D G WT CD AT NX 4M a p ? */
2922 "%016llx 0 | P %c %c %c %c %c %s %s %s %s .. %c%c%c %016llx",
2923 pState->u64Address,
2924 Pml4e.n.u1Write ? 'W' : 'R',
2925 Pml4e.n.u1User ? 'U' : 'S',
2926 Pml4e.n.u1Accessed ? 'A' : '-',
2927 Pml4e.n.u3Reserved & 1 ? '?' : '.', /* ignored */
2928 Pml4e.n.u3Reserved & 4 ? '!' : '.', /* mbz */
2929 Pml4e.n.u1WriteThru ? "WT" : "--",
2930 Pml4e.n.u1CacheDisable ? "CD" : "--",
2931 Pml4e.n.u3Reserved & 2 ? "!" : "..",/* mbz */
2932 Pml4e.n.u1NoExecute ? "NX" : "--",
2933 Pml4e.u & RT_BIT_64(9) ? '1' : '0',
2934 Pml4e.u & RT_BIT_64(10) ? '1' : '0',
2935 Pml4e.u & RT_BIT_64(11) ? '1' : '0',
2936 Pml4e.u & X86_PML4E_PG_MASK);
2937 if (pState->fDumpPageInfo)
2938 pgmR3DumpHierarchyGstPageInfo(pState, Pml4e.u & X86_PML4E_PG_MASK, _4K);
2939 pgmR3DumpHierarchyGstCheckReservedHighBits(pState, Pml4e.u);
2940 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2941
2942 if (cMaxDepth)
2943 {
2944 int rc2 = pgmR3DumpHierarchyGstPaePDPT(pState, Pml4e.u & X86_PML4E_PG_MASK, cMaxDepth);
2945 if (rc2 < rc && RT_SUCCESS(rc))
2946 rc = rc2;
2947 }
2948 else
2949 pState->cLeaves++;
2950 }
2951 }
2952
2953 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
2954 return rc;
2955}
2956
2957
2958/**
2959 * Dumps a 32-bit guest page table.
2960 *
2961 * @returns VBox status code (VINF_SUCCESS).
2962 * @param pState The dumper state.
2963 * @param GCPhys The physical address of the table.
2964 */
2965static int pgmR3DumpHierarchyGst32BitPT(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys)
2966{
2967 PCX86PT pPT;
2968 PGMPAGEMAPLOCK Lock;
2969 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page table", (void const **)&pPT, &Lock);
2970 if (RT_FAILURE(rc))
2971 return rc;
2972
2973 uint32_t iFirst, iLast;
2974 uint64_t u64BaseAddress = pgmR3DumpHierarchyCalcRange(pState, X86_PT_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
2975 for (uint32_t i = iFirst; i <= iLast; i++)
2976 {
2977 X86PTE Pte = pPT->a[i];
2978 if (Pte.n.u1Present)
2979 {
2980 pState->u64Address = u64BaseAddress + (i << X86_PT_SHIFT);
2981 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d */
2982 "%08llx 1 | P %c %c %c %c %c %s %s %s .. 4K %c%c%c %08x",
2983 pState->u64Address,
2984 Pte.n.u1Write ? 'W' : 'R',
2985 Pte.n.u1User ? 'U' : 'S',
2986 Pte.n.u1Accessed ? 'A' : '-',
2987 Pte.n.u1Dirty ? 'D' : '-',
2988 Pte.n.u1Global ? 'G' : '-',
2989 Pte.n.u1WriteThru ? "WT" : "--",
2990 Pte.n.u1CacheDisable ? "CD" : "--",
2991 Pte.n.u1PAT ? "AT" : "--",
2992 Pte.u & RT_BIT_32(9) ? '1' : '0',
2993 Pte.u & RT_BIT_32(10) ? '1' : '0',
2994 Pte.u & RT_BIT_32(11) ? '1' : '0',
2995 Pte.u & X86_PDE_PG_MASK);
2996 if (pState->fDumpPageInfo)
2997 pgmR3DumpHierarchyGstPageInfo(pState, Pte.u & X86_PDE_PG_MASK, _4K);
2998 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
2999 }
3000 }
3001
3002 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
3003 return VINF_SUCCESS;
3004}
3005
3006
3007/**
3008 * Dumps a 32-bit guest page directory and page tables.
3009 *
3010 * @returns VBox status code (VINF_SUCCESS).
3011 * @param pState The dumper state.
3012 * @param GCPhys The physical address of the table.
3013 * @param cMaxDepth The maximum depth.
3014 */
3015static int pgmR3DumpHierarchyGst32BitPD(PPGMR3DUMPHIERARCHYSTATE pState, RTHCPHYS GCPhys, unsigned cMaxDepth)
3016{
3017 if (pState->u64Address >= _4G)
3018 return VINF_SUCCESS;
3019
3020 PCX86PD pPD;
3021 PGMPAGEMAPLOCK Lock;
3022 int rc = pgmR3DumpHierarchyGstMapPage(pState, GCPhys, "Page directory", (void const **)&pPD, &Lock);
3023 if (RT_FAILURE(rc))
3024 return rc;
3025
3026 Assert(cMaxDepth > 0);
3027 cMaxDepth--;
3028
3029 uint32_t iFirst, iLast;
3030 pgmR3DumpHierarchyCalcRange(pState, X86_PD_SHIFT, X86_PG_ENTRIES, &iFirst, &iLast);
3031 for (uint32_t i = iFirst; i <= iLast; i++)
3032 {
3033 X86PDE Pde = pPD->a[i];
3034 if (Pde.n.u1Present)
3035 {
3036 pState->u64Address = (uint32_t)i << X86_PD_SHIFT;
3037 if (Pde.b.u1Size && pState->fPse)
3038 {
3039 uint64_t u64Phys = ((uint64_t)(Pde.u & X86_PDE4M_PG_HIGH_MASK) << X86_PDE4M_PG_HIGH_SHIFT)
3040 | (Pde.u & X86_PDE4M_PG_MASK);
3041 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
3042 "%08llx 0 | P %c %c %c %c %c %s %s %s .. 4M %c%c%c %08llx",
3043 pState->u64Address,
3044 Pde.b.u1Write ? 'W' : 'R',
3045 Pde.b.u1User ? 'U' : 'S',
3046 Pde.b.u1Accessed ? 'A' : '-',
3047 Pde.b.u1Dirty ? 'D' : '-',
3048 Pde.b.u1Global ? 'G' : '-',
3049 Pde.b.u1WriteThru ? "WT" : "--",
3050 Pde.b.u1CacheDisable ? "CD" : "--",
3051 Pde.b.u1PAT ? "AT" : "--",
3052 Pde.u & RT_BIT_32(9) ? '1' : '0',
3053 Pde.u & RT_BIT_32(10) ? '1' : '0',
3054 Pde.u & RT_BIT_32(11) ? '1' : '0',
3055 u64Phys);
3056 if (pState->fDumpPageInfo)
3057 pgmR3DumpHierarchyGstPageInfo(pState, u64Phys, _4M);
3058 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
3059 pState->cLeaves++;
3060 }
3061 else
3062 {
3063 pState->pHlp->pfnPrintf(pState->pHlp,/*P R S A D G WT CD AT NX 4M a m d phys */
3064 "%08llx 0 | P %c %c %c %c %c %s %s .. .. .. %c%c%c %08x",
3065 pState->u64Address,
3066 Pde.n.u1Write ? 'W' : 'R',
3067 Pde.n.u1User ? 'U' : 'S',
3068 Pde.n.u1Accessed ? 'A' : '-',
3069 Pde.n.u1Reserved0 ? '?' : '.', /* ignored */
3070 Pde.n.u1Reserved1 ? '?' : '.', /* ignored */
3071 Pde.n.u1WriteThru ? "WT" : "--",
3072 Pde.n.u1CacheDisable ? "CD" : "--",
3073 Pde.u & RT_BIT_32(9) ? '1' : '0',
3074 Pde.u & RT_BIT_32(10) ? '1' : '0',
3075 Pde.u & RT_BIT_32(11) ? '1' : '0',
3076 Pde.u & X86_PDE_PG_MASK);
3077 if (pState->fDumpPageInfo)
3078 pgmR3DumpHierarchyGstPageInfo(pState, Pde.u & X86_PDE_PG_MASK, _4K);
3079 pState->pHlp->pfnPrintf(pState->pHlp, "\n");
3080
3081 if (cMaxDepth)
3082 {
3083 int rc2 = pgmR3DumpHierarchyGst32BitPT(pState, Pde.u & X86_PDE_PG_MASK);
3084 if (rc2 < rc && RT_SUCCESS(rc))
3085 rc = rc2;
3086 }
3087 else
3088 pState->cLeaves++;
3089 }
3090 }
3091 }
3092
3093 PGMPhysReleasePageMappingLock(pState->pVM, &Lock);
3094 return rc;
3095}
3096
3097
3098/**
3099 * Internal worker that initiates the actual dump.
3100 *
3101 * @returns VBox status code.
3102 * @param pState The dumper state.
3103 * @param cr3 The CR3 value.
3104 * @param cMaxDepth The max depth.
3105 */
3106static int pgmR3DumpHierarchyGstDoIt(PPGMR3DUMPHIERARCHYSTATE pState, uint64_t cr3, unsigned cMaxDepth)
3107{
3108 int rc;
3109 unsigned const cch = pState->cchAddress;
3110 uint64_t const cr3Mask = pState->fEpt ? X86_CR3_AMD64_PAGE_MASK /** @todo this should be X86_CR3_EPT_PAGE_MASK, but it is wrong */
3111 : pState->fLme ? X86_CR3_AMD64_PAGE_MASK
3112 : pState->fPae ? X86_CR3_PAE_PAGE_MASK
3113 : X86_CR3_PAGE_MASK;
3114 if (pState->fPrintCr3)
3115 {
3116 const char * const pszMode = pState->fEpt ? "Extended Page Tables"
3117 : pState->fLme ? "Long Mode"
3118 : pState->fPae ? "PAE Mode"
3119 : pState->fPse ? "32-bit w/ PSE"
3120 : "32-bit";
3121 pState->pHlp->pfnPrintf(pState->pHlp, "cr3=%0*llx", cch, cr3);
3122 if (pState->fDumpPageInfo)
3123 pgmR3DumpHierarchyGstPageInfo(pState, cr3 & X86_CR3_AMD64_PAGE_MASK, _4K);
3124 pState->pHlp->pfnPrintf(pState->pHlp, " %s%s%s\n",
3125 pszMode,
3126 pState->fNp ? " + Nested Paging" : "",
3127 pState->fNxe ? " + NX" : "");
3128 }
3129
3130
3131 if (pState->fEpt)
3132 {
3133 if (pState->fPrintHeader)
3134 pState->pHlp->pfnPrintf(pState->pHlp,
3135 "%-*s R - Readable\n"
3136 "%-*s |W - Writeable\n"
3137 "%-*s ||X - Executable\n"
3138 "%-*s ||| EMT - EPT memory type\n"
3139 "%-*s ||| | I - Ignored PAT?\n"
3140 "%-*s ||| | | L - leaf\n"
3141 "%-*s ||| | | | A - accessed\n"
3142 "%-*s ||| | | | | D - dirty\n"
3143 "%-*s ||| | | | | | U - user execute\n"
3144 "%-*s ||| | | | | | | w - Paging writable\n"
3145 "%-*s ||| | | | | | | | k - Supervisor shadow stack writable\n"
3146 "%-*s ||| | | | | | | | | v - Suppress #VE\n"
3147 "%-*s Level ||| | | | | | | | | | page\n"
3148 /* xxxx n **** RWX MT I L A D U w k v 4K xxxxxxxxxxxxx
3149 RWX 7 - - - - - - - - 0123456701234567 */
3150 ,
3151 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
3152 cch, "", cch, "", cch, "", cch, "", cch, "Address");
3153 /** @todo assumes 4-level EPT tables for now. */
3154 rc = pgmR3DumpHierarchyGstEptPML4(pState, cr3 & cr3Mask, cMaxDepth);
3155 }
3156 else
3157 {
3158 if (pState->fPrintHeader)
3159 pState->pHlp->pfnPrintf(pState->pHlp,
3160 "%-*s P - Present\n"
3161 "%-*s | R/W - Read (0) / Write (1)\n"
3162 "%-*s | | U/S - User (1) / Supervisor (0)\n"
3163 "%-*s | | | A - Accessed\n"
3164 "%-*s | | | | D - Dirty\n"
3165 "%-*s | | | | | G - Global\n"
3166 "%-*s | | | | | | WT - Write thru\n"
3167 "%-*s | | | | | | | CD - Cache disable\n"
3168 "%-*s | | | | | | | | AT - Attribute table (PAT)\n"
3169 "%-*s | | | | | | | | | NX - No execute (K8)\n"
3170 "%-*s | | | | | | | | | | 4K/4M/2M - Page size.\n"
3171 "%-*s | | | | | | | | | | | AVL - 3 available bits.\n"
3172 "%-*s Level | | | | | | | | | | | | Page\n"
3173 /* xxxx n **** P R S A D G WT CD AT NX 4M AVL xxxxxxxxxxxxx
3174 - W U - - - -- -- -- -- -- 010 */
3175 ,
3176 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "", cch, "",
3177 cch, "", cch, "", cch, "", cch, "", cch, "", cch, "Address");
3178 if (pState->fLme)
3179 rc = pgmR3DumpHierarchyGstPaePML4(pState, cr3 & cr3Mask, cMaxDepth);
3180 else if (pState->fPae)
3181 rc = pgmR3DumpHierarchyGstPaePDPT(pState, cr3 & cr3Mask, cMaxDepth);
3182 else
3183 rc = pgmR3DumpHierarchyGst32BitPD(pState, cr3 & cr3Mask, cMaxDepth);
3184 }
3185
3186 if (!pState->cLeaves)
3187 pState->pHlp->pfnPrintf(pState->pHlp, "not present\n");
3188 return rc;
3189}
3190
3191
3192/**
3193 * dbgfR3PagingDumpEx worker.
3194 *
3195 * @returns VBox status code.
3196 * @param pVM The cross context VM structure.
3197 * @param cr3 The CR3 register value.
3198 * @param fFlags The flags, DBGFPGDMP_FLAGS_XXX.
3199 * @param FirstAddr The start address.
3200 * @param LastAddr The address to stop after.
3201 * @param cMaxDepth The max depth.
3202 * @param pHlp The output callbacks. Defaults to log if NULL.
3203 *
3204 * @internal
3205 */
3206VMMR3_INT_DECL(int) PGMR3DumpHierarchyGst(PVM pVM, uint64_t cr3, uint32_t fFlags, RTGCPTR FirstAddr, RTGCPTR LastAddr,
3207 uint32_t cMaxDepth, PCDBGFINFOHLP pHlp)
3208{
3209 /* Minimal validation as we're only supposed to service DBGF. */
3210 AssertReturn(~(fFlags & ~DBGFPGDMP_FLAGS_VALID_MASK), VERR_INVALID_PARAMETER);
3211 AssertReturn(!(fFlags & (DBGFPGDMP_FLAGS_CURRENT_MODE | DBGFPGDMP_FLAGS_CURRENT_CR3)), VERR_INVALID_PARAMETER);
3212 AssertReturn(fFlags & DBGFPGDMP_FLAGS_GUEST, VERR_INVALID_PARAMETER);
3213
3214 PGMR3DUMPHIERARCHYSTATE State;
3215 pgmR3DumpHierarchyInitState(&State, pVM, fFlags, FirstAddr, LastAddr, pHlp);
3216 return pgmR3DumpHierarchyGstDoIt(&State, cr3, cMaxDepth);
3217}
3218
3219
3220/**
3221 * For aiding with reset problems and similar.
3222 *
3223 * @param pVM The cross context VM handle.
3224 */
3225void pgmLogState(PVM pVM)
3226{
3227#if 0
3228 RTLogRelPrintf("\npgmLogState pgmLogState pgmLogState pgmLogState pgmLogState\n");
3229
3230 /*
3231 * Per CPU stuff.
3232 */
3233 for (VMCPUID iCpu = 0; iCpu < pVM->cCpus; iCpu++)
3234 {
3235 PPGMCPU pPgmCpu = &pVM->aCpus[iCpu].pgm.s;
3236 RTLogRelPrintf("pgmLogState: CPU #%u\n", iCpu);
3237# define LOG_PGMCPU_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPgmCpu->aMember)
3238 LOG_PGMCPU_MEMBER("#RX32", offVM);
3239 LOG_PGMCPU_MEMBER("#RX32", offVCpu);
3240 LOG_PGMCPU_MEMBER("#RX32", offPGM);
3241 LOG_PGMCPU_MEMBER("RGp", GCPhysA20Mask);
3242 LOG_PGMCPU_MEMBER("RTbool", fA20Enabled);
3243 LOG_PGMCPU_MEMBER("RTbool", fNoExecuteEnabled);
3244 LOG_PGMCPU_MEMBER("#RX32", fSyncFlags);
3245 LOG_PGMCPU_MEMBER("d", enmShadowMode);
3246 LOG_PGMCPU_MEMBER("d", enmGuestMode);
3247 LOG_PGMCPU_MEMBER("RGp", GCPhysCR3);
3248
3249 LOG_PGMCPU_MEMBER("p", pGst32BitPdR3);
3250 LOG_PGMCPU_MEMBER("p", pGst32BitPdR0);
3251 LOG_PGMCPU_MEMBER("RRv", pGst32BitPdRC);
3252 LOG_PGMCPU_MEMBER("#RX32", fGst32BitMbzBigPdeMask);
3253 LOG_PGMCPU_MEMBER("RTbool", fGst32BitPageSizeExtension);
3254
3255 LOG_PGMCPU_MEMBER("p", pGstPaePdptR3);
3256 LOG_PGMCPU_MEMBER("p", pGstPaePdptR0);
3257 LOG_PGMCPU_MEMBER("RRv", pGstPaePdptRC);
3258 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[0]);
3259 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[1]);
3260 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[2]);
3261 LOG_PGMCPU_MEMBER("p", apGstPaePDsR3[3]);
3262 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[0]);
3263 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[1]);
3264 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[2]);
3265 LOG_PGMCPU_MEMBER("p", apGstPaePDsR0[3]);
3266 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[0]);
3267 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[1]);
3268 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[2]);
3269 LOG_PGMCPU_MEMBER("RRv", apGstPaePDsR0[3]);
3270 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[0]);
3271 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[1]);
3272 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[2]);
3273 LOG_PGMCPU_MEMBER("RGp", aGCPhysGstPaePDs[3]);
3274 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[0].u);
3275 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[1].u);
3276 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[2].u);
3277 LOG_PGMCPU_MEMBER("#RX64", aGstPaePdpeRegs[3].u);
3278 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPteMask);
3279 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPdeMask);
3280 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzBigPdeMask);
3281 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzBigPdeMask);
3282 LOG_PGMCPU_MEMBER("#RX64", fGstPaeMbzPdpeMask);
3283
3284 LOG_PGMCPU_MEMBER("p", pGstAmd64Pml4R3);
3285 LOG_PGMCPU_MEMBER("p", pGstAmd64Pml4R0);
3286 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPteMask);
3287 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPdeMask);
3288 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzBigPdeMask);
3289 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPdpeMask);
3290 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzBigPdpeMask);
3291 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64MbzPml4eMask);
3292 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64ShadowedPdpeMask);
3293 LOG_PGMCPU_MEMBER("#RX64", fGstAmd64ShadowedPml4eMask);
3294 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedPteMask);
3295 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedPdeMask);
3296 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedBigPdeMask);
3297 LOG_PGMCPU_MEMBER("#RX64", fGst64ShadowedBigPde4PteMask);
3298
3299 LOG_PGMCPU_MEMBER("p", pShwPageCR3R3);
3300 LOG_PGMCPU_MEMBER("p", pShwPageCR3R0);
3301 LOG_PGMCPU_MEMBER("RRv", pShwPageCR3RC);
3302
3303 LOG_PGMCPU_MEMBER("p", pfnR3ShwRelocate);
3304 LOG_PGMCPU_MEMBER("p", pfnR3ShwExit);
3305 LOG_PGMCPU_MEMBER("p", pfnR3ShwGetPage);
3306 LOG_PGMCPU_MEMBER("p", pfnR3ShwModifyPage);
3307 LOG_PGMCPU_MEMBER("p", pfnR0ShwGetPage);
3308 LOG_PGMCPU_MEMBER("p", pfnR0ShwModifyPage);
3309 LOG_PGMCPU_MEMBER("p", pfnR3GstRelocate);
3310 LOG_PGMCPU_MEMBER("p", pfnR3GstExit);
3311 LOG_PGMCPU_MEMBER("p", pfnR3GstGetPage);
3312 LOG_PGMCPU_MEMBER("p", pfnR3GstModifyPage);
3313 LOG_PGMCPU_MEMBER("p", pfnR0GstGetPage);
3314 LOG_PGMCPU_MEMBER("p", pfnR0GstModifyPage);
3315 LOG_PGMCPU_MEMBER("p", pfnR3BthRelocate);
3316 LOG_PGMCPU_MEMBER("p", pfnR3BthInvalidatePage);
3317 LOG_PGMCPU_MEMBER("p", pfnR3BthSyncCR3);
3318 LOG_PGMCPU_MEMBER("p", pfnR3BthPrefetchPage);
3319 LOG_PGMCPU_MEMBER("p", pfnR3BthMapCR3);
3320 LOG_PGMCPU_MEMBER("p", pfnR3BthUnmapCR3);
3321 LOG_PGMCPU_MEMBER("p", pfnR0BthMapCR3);
3322 LOG_PGMCPU_MEMBER("p", pfnR0BthUnmapCR3);
3323 LOG_PGMCPU_MEMBER("#RX64", cNetwareWp0Hacks);
3324 LOG_PGMCPU_MEMBER("#RX64", cPoolAccessHandler);
3325
3326 }
3327
3328 /*
3329 * PGM globals.
3330 */
3331 RTLogRelPrintf("PGM globals\n");
3332 PPGM pPgm = &pVM->pgm.s;
3333# define LOG_PGM_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPgm->aMember)
3334 LOG_PGM_MEMBER("#RX32", offVM);
3335 LOG_PGM_MEMBER("#RX32", offVCpuPGM);
3336 LOG_PGM_MEMBER("RTbool", fRamPreAlloc);
3337 LOG_PGM_MEMBER("RTbool", fPhysWriteMonitoringEngaged);
3338 LOG_PGM_MEMBER("RTbool", fLessThan52PhysicalAddressBits);
3339 LOG_PGM_MEMBER("RTbool", fNestedPaging);
3340 LOG_PGM_MEMBER("d", enmHostMode);
3341 LOG_PGM_MEMBER("RTbool", fNoMorePhysWrites);
3342 LOG_PGM_MEMBER("RTbool", fPageFusionAllowed);
3343 LOG_PGM_MEMBER("RTbool", fPciPassthrough);
3344 LOG_PGM_MEMBER("#x", cMmio2Ranges);
3345 LOG_PGM_MEMBER("RTbool", fRestoreRomPagesOnReset);
3346 LOG_PGM_MEMBER("RTbool", fZeroRamPagesOnReset);
3347 LOG_PGM_MEMBER("RTbool", fFinalizedMappings);
3348 LOG_PGM_MEMBER("RTbool", fMappingsFixed);
3349 LOG_PGM_MEMBER("RTbool", fMappingsFixedRestored);
3350 LOG_PGM_MEMBER("%#x", cbMappingFixed);
3351 LOG_PGM_MEMBER("%#x", idRamRangesGen);
3352 LOG_PGM_MEMBER("#RGv", GCPtrMappingFixed);
3353 LOG_PGM_MEMBER("#RGv", GCPtrPrevRamRangeMapping);
3354 LOG_PGM_MEMBER("%#x", hRomPhysHandlerType);
3355 LOG_PGM_MEMBER("#RGp", GCPhys4MBPSEMask);
3356 LOG_PGM_MEMBER("#RGp", GCPhysInvAddrMask);
3357 LOG_PGM_MEMBER("p", apRamRangesTlbR3[0]);
3358 LOG_PGM_MEMBER("p", apRamRangesTlbR3[1]);
3359 LOG_PGM_MEMBER("p", apRamRangesTlbR3[2]);
3360 LOG_PGM_MEMBER("p", apRamRangesTlbR3[3]);
3361 LOG_PGM_MEMBER("p", apRamRangesTlbR3[4]);
3362 LOG_PGM_MEMBER("p", apRamRangesTlbR3[5]);
3363 LOG_PGM_MEMBER("p", apRamRangesTlbR3[6]);
3364 LOG_PGM_MEMBER("p", apRamRangesTlbR3[7]);
3365 LOG_PGM_MEMBER("p", pRamRangesXR3);
3366 LOG_PGM_MEMBER("p", pRamRangeTreeR3);
3367 LOG_PGM_MEMBER("p", pTreesR3);
3368 LOG_PGM_MEMBER("p", pLastPhysHandlerR3);
3369 LOG_PGM_MEMBER("p", pPoolR3);
3370 LOG_PGM_MEMBER("p", pMappingsR3);
3371 LOG_PGM_MEMBER("p", pRomRangesR3);
3372 LOG_PGM_MEMBER("p", pRegMmioRangesR3);
3373 LOG_PGM_MEMBER("p", paModeData);
3374 LOG_PGM_MEMBER("p", apMmio2RangesR3[0]);
3375 LOG_PGM_MEMBER("p", apMmio2RangesR3[1]);
3376 LOG_PGM_MEMBER("p", apMmio2RangesR3[2]);
3377 LOG_PGM_MEMBER("p", apMmio2RangesR3[3]);
3378 LOG_PGM_MEMBER("p", apMmio2RangesR3[4]);
3379 LOG_PGM_MEMBER("p", apMmio2RangesR3[5]);
3380 LOG_PGM_MEMBER("p", apRamRangesTlbR0[0]);
3381 LOG_PGM_MEMBER("p", apRamRangesTlbR0[1]);
3382 LOG_PGM_MEMBER("p", apRamRangesTlbR0[2]);
3383 LOG_PGM_MEMBER("p", apRamRangesTlbR0[3]);
3384 LOG_PGM_MEMBER("p", apRamRangesTlbR0[4]);
3385 LOG_PGM_MEMBER("p", apRamRangesTlbR0[5]);
3386 LOG_PGM_MEMBER("p", apRamRangesTlbR0[6]);
3387 LOG_PGM_MEMBER("p", apRamRangesTlbR0[7]);
3388 LOG_PGM_MEMBER("p", pRamRangesXR0);
3389 LOG_PGM_MEMBER("p", pRamRangeTreeR0);
3390 LOG_PGM_MEMBER("p", pTreesR0);
3391 LOG_PGM_MEMBER("p", pLastPhysHandlerR0);
3392 LOG_PGM_MEMBER("p", pPoolR0);
3393 LOG_PGM_MEMBER("p", pMappingsR0);
3394 LOG_PGM_MEMBER("p", pRomRangesR0);
3395 LOG_PGM_MEMBER("p", apMmio2RangesR0[0]);
3396 LOG_PGM_MEMBER("p", apMmio2RangesR0[1]);
3397 LOG_PGM_MEMBER("p", apMmio2RangesR0[2]);
3398 LOG_PGM_MEMBER("p", apMmio2RangesR0[3]);
3399 LOG_PGM_MEMBER("p", apMmio2RangesR0[4]);
3400 LOG_PGM_MEMBER("p", apMmio2RangesR0[5]);
3401 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[0]);
3402 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[1]);
3403 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[2]);
3404 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[3]);
3405 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[4]);
3406 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[5]);
3407 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[6]);
3408 LOG_PGM_MEMBER("RRv", apRamRangesTlbRC[7]);
3409 LOG_PGM_MEMBER("RRv", pRamRangesXRC);
3410 LOG_PGM_MEMBER("RRv", pRamRangeTreeRC);
3411 LOG_PGM_MEMBER("RRv", pTreesRC);
3412 LOG_PGM_MEMBER("RRv", pLastPhysHandlerRC);
3413 LOG_PGM_MEMBER("RRv", pPoolRC);
3414 LOG_PGM_MEMBER("RRv", pMappingsRC);
3415 LOG_PGM_MEMBER("RRv", pRomRangesRC);
3416 LOG_PGM_MEMBER("RRv", paDynPageMap32BitPTEsGC);
3417 LOG_PGM_MEMBER("RRv", paDynPageMapPaePTEsGC);
3418
3419 LOG_PGM_MEMBER("#RGv", GCPtrCR3Mapping);
3420 LOG_PGM_MEMBER("p", pInterPD);
3421 LOG_PGM_MEMBER("p", apInterPTs[0]);
3422 LOG_PGM_MEMBER("p", apInterPTs[1]);
3423 LOG_PGM_MEMBER("p", apInterPaePTs[0]);
3424 LOG_PGM_MEMBER("p", apInterPaePTs[1]);
3425 LOG_PGM_MEMBER("p", apInterPaePDs[0]);
3426 LOG_PGM_MEMBER("p", apInterPaePDs[1]);
3427 LOG_PGM_MEMBER("p", apInterPaePDs[2]);
3428 LOG_PGM_MEMBER("p", apInterPaePDs[3]);
3429 LOG_PGM_MEMBER("p", pInterPaePDPT);
3430 LOG_PGM_MEMBER("p", pInterPaePML4);
3431 LOG_PGM_MEMBER("p", pInterPaePDPT64);
3432 LOG_PGM_MEMBER("#RHp", HCPhysInterPD);
3433 LOG_PGM_MEMBER("#RHp", HCPhysInterPaePDPT);
3434 LOG_PGM_MEMBER("#RHp", HCPhysInterPaePML4);
3435 LOG_PGM_MEMBER("RRv", pbDynPageMapBaseGC);
3436 LOG_PGM_MEMBER("RRv", pRCDynMap);
3437 LOG_PGM_MEMBER("p", pvR0DynMapUsed);
3438 LOG_PGM_MEMBER("%#x", cDeprecatedPageLocks);
3439
3440 /**
3441 * Data associated with managing the ring-3 mappings of the allocation chunks.
3442 */
3443 LOG_PGM_MEMBER("p", ChunkR3Map.pTree);
3444 //LOG_PGM_MEMBER(PGMCHUNKR3MAPTLB ChunkR3Map.Tlb);
3445 LOG_PGM_MEMBER("%#x", ChunkR3Map.c);
3446 LOG_PGM_MEMBER("%#x", ChunkR3Map.cMax);
3447 LOG_PGM_MEMBER("%#x", ChunkR3Map.iNow);
3448 //LOG_PGM_MEMBER(PGMPAGER3MAPTLB PhysTlbHC);
3449
3450 LOG_PGM_MEMBER("#RHp", HCPhysZeroPg);
3451 LOG_PGM_MEMBER("p", pvZeroPgR3);
3452 LOG_PGM_MEMBER("p", pvZeroPgR0);
3453 LOG_PGM_MEMBER("RRv", pvZeroPgRC);
3454 LOG_PGM_MEMBER("#RHp", HCPhysMmioPg);
3455 LOG_PGM_MEMBER("#RHp", HCPhysInvMmioPg);
3456 LOG_PGM_MEMBER("p", pvMmioPgR3);
3457 LOG_PGM_MEMBER("RTbool", fErrInjHandyPages);
3458
3459 /*
3460 * PGM page pool.
3461 */
3462 PPGMPOOL pPool = pVM->pgm.s.pPoolR3;
3463 RTLogRelPrintf("PGM Page Pool\n");
3464# define LOG_PGMPOOL_MEMBER(aFmt, aMember) RTLogRelPrintf(" %32s: %" aFmt "\n", #aMember, pPool->aMember)
3465 LOG_PGMPOOL_MEMBER("p", pVMR3);
3466 LOG_PGMPOOL_MEMBER("p", pVMR0);
3467 LOG_PGMPOOL_MEMBER("RRv", pVMRC);
3468 LOG_PGMPOOL_MEMBER("#x", cMaxPages);
3469 LOG_PGMPOOL_MEMBER("#x", cCurPages);
3470 LOG_PGMPOOL_MEMBER("#x", iFreeHead);
3471 LOG_PGMPOOL_MEMBER("#x", u16Padding);
3472 LOG_PGMPOOL_MEMBER("#x", iUserFreeHead);
3473 LOG_PGMPOOL_MEMBER("#x", cMaxUsers);
3474 LOG_PGMPOOL_MEMBER("#x", cPresent);
3475 LOG_PGMPOOL_MEMBER("RRv", paUsersRC);
3476 LOG_PGMPOOL_MEMBER("p", paUsersR3);
3477 LOG_PGMPOOL_MEMBER("p", paUsersR0);
3478 LOG_PGMPOOL_MEMBER("#x", iPhysExtFreeHead);
3479 LOG_PGMPOOL_MEMBER("#x", cMaxPhysExts);
3480 LOG_PGMPOOL_MEMBER("RRv", paPhysExtsRC);
3481 LOG_PGMPOOL_MEMBER("p", paPhysExtsR3);
3482 LOG_PGMPOOL_MEMBER("p", paPhysExtsR0);
3483 for (uint32_t i = 0; i < RT_ELEMENTS(pPool->aiHash); i++)
3484 RTLogRelPrintf(" aiHash[%u]: %#x\n", i, pPool->aiHash[i]);
3485 LOG_PGMPOOL_MEMBER("#x", iAgeHead);
3486 LOG_PGMPOOL_MEMBER("#x", iAgeTail);
3487 LOG_PGMPOOL_MEMBER("RTbool", fCacheEnabled);
3488 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[0]);
3489 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[1]);
3490 LOG_PGMPOOL_MEMBER("RTbool", afPadding1[2]);
3491 LOG_PGMPOOL_MEMBER("#x", iModifiedHead);
3492 LOG_PGMPOOL_MEMBER("#x", cModifiedPages);
3493 LOG_PGMPOOL_MEMBER("#x", hAccessHandlerType);
3494 LOG_PGMPOOL_MEMBER("#x", idxFreeDirtyPage);
3495 LOG_PGMPOOL_MEMBER("#x", cDirtyPages);
3496 for (uint32_t i = 0; i < RT_ELEMENTS(pPool->aDirtyPages); i++)
3497 RTLogRelPrintf(" aDirtyPages[%u].uIdx: %#x\n", i, pPool->aDirtyPages[i].uIdx);
3498 LOG_PGMPOOL_MEMBER("#x", cUsedPages);
3499 LOG_PGMPOOL_MEMBER("#x", HCPhysTree);
3500 for (uint32_t i = 0; i < pPool->cCurPages; i++)
3501 {
3502 PPGMPOOLPAGE pPage = &pPool->aPages[i];
3503# define LOG_PAGE_MEMBER(aFmt, aMember) RTLogRelPrintf(" %3u:%-32s: %" aFmt "\n", i, #aMember, pPage->aMember)
3504 RTLogRelPrintf("%3u:%-32s: %p\n", i, "", pPage);
3505 LOG_PAGE_MEMBER("RHp", Core.Key);
3506 LOG_PAGE_MEMBER("p", pvPageR3);
3507 LOG_PAGE_MEMBER("RGp", GCPhys);
3508 LOG_PAGE_MEMBER("d", enmKind);
3509 LOG_PAGE_MEMBER("d", enmAccess);
3510 LOG_PAGE_MEMBER("RTbool", fA20Enabled);
3511 LOG_PAGE_MEMBER("RTbool", fZeroed);
3512 LOG_PAGE_MEMBER("RTbool", fSeenNonGlobal);
3513 LOG_PAGE_MEMBER("RTbool", fMonitored);
3514 LOG_PAGE_MEMBER("RTbool", fCached);
3515 LOG_PAGE_MEMBER("RTbool", fReusedFlushPending);
3516 LOG_PAGE_MEMBER("RTbool", fDirty);
3517 LOG_PAGE_MEMBER("RTbool", fPadding1);
3518 LOG_PAGE_MEMBER("RTbool", fPadding2);
3519 LOG_PAGE_MEMBER("#x", idx);
3520 LOG_PAGE_MEMBER("#x", iNext);
3521 LOG_PAGE_MEMBER("#x", iUserHead);
3522 LOG_PAGE_MEMBER("#x", cPresent);
3523 LOG_PAGE_MEMBER("#x", iFirstPresent);
3524 LOG_PAGE_MEMBER("#x", cModifications);
3525 LOG_PAGE_MEMBER("#x", iModifiedNext);
3526 LOG_PAGE_MEMBER("#x", iModifiedPrev);
3527 LOG_PAGE_MEMBER("#x", iMonitoredNext);
3528 LOG_PAGE_MEMBER("#x", iMonitoredPrev);
3529 LOG_PAGE_MEMBER("#x", iAgeNext);
3530 LOG_PAGE_MEMBER("#x", iAgePrev);
3531 LOG_PAGE_MEMBER("#x", idxDirtyEntry);
3532 LOG_PAGE_MEMBER("RGv", GCPtrLastAccessHandlerRip);
3533 LOG_PAGE_MEMBER("RGv", GCPtrLastAccessHandlerFault);
3534 LOG_PAGE_MEMBER("#RX64", cLastAccessHandler);
3535 LOG_PAGE_MEMBER("#RX32", cLocked);
3536# ifdef VBOX_STRICT
3537 LOG_PAGE_MEMBER("RGv", GCPtrDirtyFault);
3538# endif
3539 if ( pPage->enmKind == PGMPOOLKIND_32BIT_PT_FOR_32BIT_PT
3540 || pPage->enmKind == PGMPOOLKIND_32BIT_PT_FOR_32BIT_4MB
3541 || pPage->enmKind == PGMPOOLKIND_32BIT_PD
3542 || pPage->enmKind == PGMPOOLKIND_32BIT_PD_PHYS)
3543 {
3544 uint32_t const *pu32Page = (uint32_t const *)pPage->pvPageR3;
3545 for (uint32_t i = 0; i < 1024/2; i += 4)
3546 RTLogRelPrintf(" %#05x: %RX32 %RX32 %RX32 %RX32\n", i, pu32Page[i], pu32Page[i+1], pu32Page[i+2], pu32Page[i+3]);
3547 }
3548 else if ( pPage->enmKind != PGMPOOLKIND_FREE
3549 && pPage->enmKind != PGMPOOLKIND_INVALID)
3550 {
3551 uint64_t const *pu64Page = (uint64_t const *)pPage->pvPageR3;
3552 for (uint32_t i = 0; i < 512/2; i += 2)
3553 RTLogRelPrintf(" %#05x: %RX64 %RX64\n", i, pu64Page[i], pu64Page[i+1]);
3554 }
3555 }
3556
3557 RTLogRelPrintf("pgmLogState pgmLogState pgmLogState pgmLogState pgmLogState\n\n");
3558#else
3559 RT_NOREF(pVM);
3560#endif
3561}
3562
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