VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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