VirtualBox

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

Last change on this file since 107044 was 106382, checked in by vboxsync, 5 weeks ago

VMM/PGM-armv8.cpp: Sketch some page table walking code for the debugger, nowhere near complete, bugref:10388 bugref:10393

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