VirtualBox

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

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

VMM: Changed PAGE_SIZE -> GUEST_PAGE_SIZE / HOST_PAGE_SIZE, PAGE_SHIFT -> GUEST_PAGE_SHIFT / HOST_PAGE_SHIFT, and PAGE_OFFSET_MASK -> GUEST_PAGE_OFFSET_MASK / HOST_PAGE_OFFSET_MASK. Also removed most usage of ASMMemIsZeroPage and ASMMemZeroPage since the host and guest page size doesn't need to be the same any more. Some work left to do in the page pool code. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 119.3 KB
Line 
1/* $Id: PGMDbg.cpp 93554 2022-02-02 22:57:02Z 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 & GUEST_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 >> GUEST_PAGE_SHIFT;
201 while (iPage-- > 0)
202 if (PGM_PAGE_GET_HCPHYS(&pRam->aPages[iPage]) == HCPhys)
203 {
204 *pGCPhys = pRam->GCPhys + (iPage << GUEST_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 = GUEST_PAGE_SIZE;
244 cbChunk -= GCPhysSrc & GUEST_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 = GUEST_PAGE_SIZE;
295 cbChunk -= GCPhysDst & GUEST_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 = GUEST_PAGE_SIZE;
350 cbChunk -= GCPtrSrc & GUEST_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 = GUEST_PAGE_SIZE;
406 cbChunk -= GCPtrDst & GUEST_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 <= GUEST_PAGE_SIZE
680 ? 1
681 : GCPhysAlign >> GUEST_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 >> GUEST_PAGE_SHIFT;
719 uint32_t iPage = off >> GUEST_PAGE_SHIFT;
720 uint32_t offPage = GCPhys & GUEST_PAGE_OFFSET_MASK;
721 GCPhys &= ~(RTGCPHYS)GUEST_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 < GUEST_PAGE_SIZE)
738 {
739 uint32_t cbSearch = (GCPhys ^ GCPhysLast) & ~(RTGCPHYS)GUEST_PAGE_OFFSET_MASK
740 ? GUEST_PAGE_SIZE - (uint32_t)offPage
741 : (GCPhysLast & GUEST_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 << GUEST_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 <= GUEST_PAGE_SIZE
855 ? 1
856 : GCPtrAlign >> GUEST_PAGE_SHIFT;
857 const RTGCPTR GCPtrLast = GCPtr + cbRange - 1 >= GCPtr
858 ? (GCPtr + cbRange - 1) & GCPtrMask
859 : GCPtrMask;
860 RTGCPTR cPages = (((GCPtrLast - GCPtr) + (GCPtr & GUEST_PAGE_OFFSET_MASK)) >> GUEST_PAGE_SHIFT) + 1;
861 uint32_t offPage = GCPtr & GUEST_PAGE_OFFSET_MASK;
862 GCPtr &= ~(RTGCPTR)GUEST_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 < GUEST_PAGE_SIZE)
906 {
907 uint32_t cbSearch = cPages > 0
908 ? GUEST_PAGE_SIZE - (uint32_t)offPage
909 : (GCPtrLast & GUEST_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 & GUEST_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