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