VirtualBox

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

Last change on this file since 107171 was 107171, checked in by vboxsync, 7 weeks ago

VMM/PGM: Introducing VBOX_WITH_ONLY_PGM_NEM_MODE to disable lots unused code on *.arm64 and darwin. jiraref:VBP-1466

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