Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

947 lines
25 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. debugsup.c
  5. Abstract:
  6. This module contains routines which provide support for the
  7. kernel debugger.
  8. Author:
  9. Lou Perazzoli (loup) 02-Aug-1990
  10. Landy Wang (landyw) 02-June-1997
  11. Revision History:
  12. --*/
  13. #include "mi.h"
  14. #include <kdp.h>
  15. ULONG MmPoisonedTb;
  16. PVOID
  17. MiDbgWriteCheck (
  18. IN PVOID VirtualAddress,
  19. IN PHARDWARE_PTE Opaque,
  20. IN LOGICAL ForceWritableIfPossible
  21. )
  22. /*++
  23. Routine Description:
  24. This routine checks the specified virtual address and if it is
  25. valid and writable, it returns that virtual address, otherwise
  26. it returns NULL.
  27. Arguments:
  28. VirtualAddress - Supplies the virtual address to check.
  29. Opaque - Supplies an opaque pointer.
  30. Return Value:
  31. Returns NULL if the address is not valid or writable, otherwise
  32. returns the virtual address.
  33. Environment:
  34. Kernel mode IRQL at DISPATCH_LEVEL or greater.
  35. --*/
  36. {
  37. MMPTE PteContents;
  38. PMMPTE InputPte;
  39. PMMPTE PointerPte;
  40. ULONG_PTR IsPhysical;
  41. InputPte = (PMMPTE)Opaque;
  42. InputPte->u.Long = 0;
  43. if (!MmIsAddressValid (VirtualAddress)) {
  44. return NULL;
  45. }
  46. #if defined(_IA64_)
  47. //
  48. // There are regions mapped by TRs (PALcode, PCR, etc) that are
  49. // not part of the MI_IS_PHYSICAL_ADDRESS macro.
  50. //
  51. IsPhysical = MiIsVirtualAddressMappedByTr (VirtualAddress);
  52. if (IsPhysical == FALSE) {
  53. IsPhysical = MI_IS_PHYSICAL_ADDRESS (VirtualAddress);
  54. }
  55. #else
  56. IsPhysical = MI_IS_PHYSICAL_ADDRESS (VirtualAddress);
  57. #endif
  58. if (IsPhysical) {
  59. //
  60. // All superpage mappings must be read-write and never generate
  61. // faults so nothing needs to be done for this case.
  62. //
  63. return VirtualAddress;
  64. }
  65. PointerPte = MiGetPteAddress (VirtualAddress);
  66. PteContents = *PointerPte;
  67. #if defined(NT_UP) || defined(_IA64_)
  68. if (PteContents.u.Hard.Write == 0)
  69. #else
  70. if (PteContents.u.Hard.Writable == 0)
  71. #endif
  72. {
  73. if (ForceWritableIfPossible == FALSE) {
  74. return NULL;
  75. }
  76. //
  77. // PTE is not writable, make it so.
  78. //
  79. *InputPte = PteContents;
  80. //
  81. // Carefully modify the PTE to ensure write permissions,
  82. // preserving the page's cache attributes to keep the TB
  83. // coherent.
  84. //
  85. #if defined(NT_UP) || defined(_IA64_)
  86. PteContents.u.Hard.Write = 1;
  87. #else
  88. PteContents.u.Hard.Writable = 1;
  89. #endif
  90. MI_SET_PTE_DIRTY (PteContents);
  91. MI_SET_ACCESSED_IN_PTE (&PteContents, 1);
  92. *PointerPte = PteContents;
  93. //
  94. // Note KeFillEntryTb does not IPI the other processors. This is
  95. // required as the other processors are frozen in the debugger
  96. // and we will deadlock if we try and IPI them.
  97. // Just flush the current processor instead.
  98. //
  99. KeFillEntryTb ((PHARDWARE_PTE)PointerPte, VirtualAddress, TRUE);
  100. }
  101. return VirtualAddress;
  102. }
  103. VOID
  104. MiDbgReleaseAddress (
  105. IN PVOID VirtualAddress,
  106. IN PHARDWARE_PTE Opaque
  107. )
  108. /*++
  109. Routine Description:
  110. This routine resets the specified virtual address access permissions
  111. to its original state.
  112. Arguments:
  113. VirtualAddress - Supplies the virtual address to check.
  114. Opaque - Supplies an opaque pointer.
  115. Return Value:
  116. None.
  117. Environment:
  118. Kernel mode IRQL at DISPATCH_LEVEL or greater.
  119. --*/
  120. {
  121. MMPTE TempPte;
  122. PMMPTE PointerPte;
  123. PMMPTE InputPte;
  124. InputPte = (PMMPTE)Opaque;
  125. ASSERT (MmIsAddressValid (VirtualAddress));
  126. if (InputPte->u.Long != 0) {
  127. PointerPte = MiGetPteAddress (VirtualAddress);
  128. TempPte = *InputPte;
  129. TempPte.u.Hard.Dirty = 1;
  130. *PointerPte = TempPte;
  131. KeFillEntryTb ((PHARDWARE_PTE)PointerPte, VirtualAddress, TRUE);
  132. }
  133. return;
  134. }
  135. PVOID64
  136. MiDbgTranslatePhysicalAddress (
  137. IN PHYSICAL_ADDRESS PhysicalAddress,
  138. IN ULONG Flags
  139. )
  140. /*++
  141. Routine Description:
  142. This routine maps the specified physical address and returns
  143. the virtual address which maps the physical address.
  144. The next call to MiDbgTranslatePhysicalAddress removes the
  145. previous physical address translation, hence only a single
  146. physical address can be examined at a time (can't cross page
  147. boundaries).
  148. Arguments:
  149. PhysicalAddress - Supplies the physical address to map and translate.
  150. Flags -
  151. MMDBG_COPY_WRITE - Ignored.
  152. MMDBG_COPY_PHYSICAL - Ignored.
  153. MMDBG_COPY_UNSAFE - Ignored.
  154. MMDBG_COPY_CACHED - Use a PTE with the cached attribute for the
  155. mapping to ensure TB coherence.
  156. MMDBG_COPY_UNCACHED - Use a PTE with the uncached attribute for the
  157. mapping to ensure TB coherence.
  158. MMDBG_COPY_WRITE_COMBINED - Use a PTE with the writecombined attribute
  159. for the mapping to ensure TB coherence.
  160. Note the cached/uncached/write combined attribute requested by the
  161. caller is ignored if Mm can internally determine the proper attribute.
  162. Return Value:
  163. The virtual address which corresponds to the physical address.
  164. Environment:
  165. Kernel mode IRQL at DISPATCH_LEVEL or greater.
  166. --*/
  167. {
  168. ULONG Hint;
  169. MMPTE TempPte;
  170. PVOID BaseAddress;
  171. PFN_NUMBER PageFrameIndex;
  172. PMMPFN Pfn1;
  173. MMPTE OriginalPte;
  174. //
  175. // The debugger can call this before Mm has even initialized in Phase 0 !
  176. // MmDebugPte cannot be referenced before Mm has initialized without
  177. // causing an infinite loop wedging the machine.
  178. //
  179. if (MmPhysicalMemoryBlock == NULL) {
  180. return NULL;
  181. }
  182. Hint = 0;
  183. BaseAddress = MiGetVirtualAddressMappedByPte (MmDebugPte);
  184. TempPte = ValidKernelPte;
  185. PageFrameIndex = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT);
  186. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  187. if (MiIsPhysicalMemoryAddress (PageFrameIndex, &Hint, FALSE) == TRUE) {
  188. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  189. switch (Pfn1->u3.e1.CacheAttribute) {
  190. case MiCached:
  191. case MiNotMapped:
  192. default:
  193. break;
  194. case MiNonCached:
  195. MI_DISABLE_CACHING (TempPte);
  196. break;
  197. case MiWriteCombined:
  198. MI_SET_PTE_WRITE_COMBINE (TempPte);
  199. break;
  200. }
  201. }
  202. else {
  203. if (Flags & MMDBG_COPY_CACHED) {
  204. NOTHING;
  205. }
  206. else if (Flags & MMDBG_COPY_UNCACHED) {
  207. //
  208. // Just flush the entire TB on this processor but not the others
  209. // as an IPI may not be safe depending on when/why we broke into
  210. // the debugger.
  211. //
  212. // If IPIs were safe, we would have used
  213. // MI_PREPARE_FOR_NONCACHED (MiNonCached) instead.
  214. //
  215. KeFlushCurrentTb ();
  216. MI_DISABLE_CACHING (TempPte);
  217. }
  218. else if (Flags & MMDBG_COPY_WRITE_COMBINED) {
  219. //
  220. // Just flush the entire TB on this processor but not the others
  221. // as an IPI may not be safe depending on when/why we broke into
  222. // the debugger.
  223. //
  224. // If IPIs were safe, we would have used
  225. // MI_PREPARE_FOR_NONCACHED (MiWriteCombined) instead.
  226. //
  227. KeFlushCurrentTb ();
  228. MI_SET_PTE_WRITE_COMBINE (TempPte);
  229. }
  230. else {
  231. //
  232. // This is an access to I/O space and we don't know the correct
  233. // attribute type. Only proceed if the caller explicitly specified
  234. // an attribute and hope he didn't get it wrong. If no attribute
  235. // is specified then just return failure.
  236. //
  237. return NULL;
  238. }
  239. //
  240. // Since we really don't know if the caller got the attribute right,
  241. // set the flag below so (assuming the machine doesn't hard hang) we
  242. // can at least tell in the crash that he may have whacked the TB.
  243. //
  244. MmPoisonedTb += 1;
  245. }
  246. MI_SET_ACCESSED_IN_PTE (&TempPte, 1);
  247. OriginalPte.u.Long = 0;
  248. OriginalPte.u.Long = InterlockedCompareExchangePte (MmDebugPte,
  249. TempPte.u.Long,
  250. OriginalPte.u.Long);
  251. if (OriginalPte.u.Long != 0) {
  252. //
  253. // Someone else is using the debug PTE. Inform our caller it is not
  254. // available.
  255. //
  256. return NULL;
  257. }
  258. //
  259. // Just flush (no sweep) the TB entry on this processor as an IPI
  260. // may not be safe depending on when/why we broke into the debugger.
  261. // Note that if we are in kd, then all the processors are frozen and
  262. // this thread can't migrate so the local TB flush is enough. For
  263. // the localkd case, our caller has raised to DISPATCH_LEVEL thereby
  264. // ensuring this thread can't migrate even though the other processors
  265. // are not frozen.
  266. //
  267. KiFlushSingleTb (TRUE, BaseAddress);
  268. return (PVOID64)((ULONG_PTR)BaseAddress + BYTE_OFFSET(PhysicalAddress.LowPart));
  269. }
  270. VOID
  271. MiDbgUnTranslatePhysicalAddress (
  272. VOID
  273. )
  274. /*++
  275. Routine Description:
  276. This routine unmaps the virtual address currently mapped by the debug PTE.
  277. This is needed so that stale PTE mappings are not left in the debug PTE
  278. as if the page attribute subsequently changes, a stale mapping would
  279. cause TB incoherency.
  280. This can only be called if the previous MiDbgTranslatePhysicalAddress
  281. succeeded.
  282. Arguments:
  283. None.
  284. Return Value:
  285. None.
  286. Environment:
  287. Kernel mode IRQL at DISPATCH_LEVEL or greater.
  288. --*/
  289. {
  290. PVOID BaseAddress;
  291. BaseAddress = MiGetVirtualAddressMappedByPte (MmDebugPte);
  292. ASSERT (MmIsAddressValid (BaseAddress));
  293. #if defined (_WIN64)
  294. InterlockedExchange64 ((PLONG64)MmDebugPte, ZeroPte.u.Long);
  295. #elif defined(_X86PAE_)
  296. KeInterlockedSwapPte ((PHARDWARE_PTE)MmDebugPte,
  297. (PHARDWARE_PTE)&ZeroPte.u.Long);
  298. #else
  299. InterlockedExchange ((PLONG)MmDebugPte, ZeroPte.u.Long);
  300. #endif
  301. KiFlushSingleTb (TRUE, BaseAddress);
  302. return;
  303. }
  304. NTSTATUS
  305. MmDbgCopyMemory (
  306. IN ULONG64 UntrustedAddress,
  307. IN PVOID Buffer,
  308. IN ULONG Size,
  309. IN ULONG Flags
  310. )
  311. /*++
  312. Routine Description:
  313. Transfers a single chunk of memory between a buffer and a system
  314. address. The transfer can be a read or write with a virtual or
  315. physical address.
  316. The chunk size must be 1, 2, 4 or 8 bytes and the address
  317. must be appropriately aligned for the size.
  318. Arguments:
  319. UntrustedAddress - Supplies the system address being read from or written
  320. into. The address is translated appropriately and
  321. validated before being used. This address must not
  322. cross a page boundary.
  323. Buffer - Supplies the buffer to read into or write from. It is the caller's
  324. responsibility to ensure this buffer address is nonpaged and valid
  325. (ie: will not generate any faults including access bit faults)
  326. throughout the duration of this call. This routine (not the
  327. caller) will handle copying into this buffer as the buffer
  328. address may not be aligned properly for the requested transfer.
  329. Typically this buffer points to a kd circular buffer or an
  330. ExLockUserBuffer'd address. Note this buffer can cross page
  331. boundaries.
  332. Size - Supplies the size of the transfer. This may be 1, 2, 4 or 8 bytes.
  333. Flags -
  334. MMDBG_COPY_WRITE - Write from the buffer to the address.
  335. If this is not set a read is done.
  336. MMDBG_COPY_PHYSICAL - The address is a physical address and by default
  337. a PTE with a cached attribute will be used to
  338. map it to retrieve (or set) the specified data.
  339. If this is not set the address is virtual.
  340. MMDBG_COPY_UNSAFE - No locks are taken during operation. It
  341. is the caller's responsibility to ensure
  342. stability of the system during the call.
  343. MMDBG_COPY_CACHED - If MMDBG_COPY_PHYSICAL is specified, then use
  344. a PTE with the cached attribute for the mapping
  345. to ensure TB coherence.
  346. MMDBG_COPY_UNCACHED - If MMDBG_COPY_PHYSICAL is specified, then use
  347. a PTE with the uncached attribute for the mapping
  348. to ensure TB coherence.
  349. MMDBG_COPY_WRITE_COMBINED - If MMDBG_COPY_PHYSICAL is specified, then
  350. use a PTE with the writecombined attribute
  351. for the mapping to ensure TB coherence.
  352. Return Value:
  353. NTSTATUS.
  354. --*/
  355. {
  356. LOGICAL ForceWritableIfPossible;
  357. ULONG i;
  358. KIRQL PfnIrql;
  359. KIRQL OldIrql;
  360. PVOID VirtualAddress;
  361. HARDWARE_PTE Opaque;
  362. CHAR TempBuffer[8];
  363. PCHAR SourceBuffer;
  364. PCHAR TargetBuffer;
  365. PHYSICAL_ADDRESS PhysicalAddress;
  366. PETHREAD Thread;
  367. LOGICAL PfnHeld;
  368. ULONG WsHeld;
  369. switch (Size) {
  370. case 1:
  371. break;
  372. case 2:
  373. break;
  374. case 4:
  375. break;
  376. case 8:
  377. break;
  378. default:
  379. return STATUS_INVALID_PARAMETER_3;
  380. }
  381. if (UntrustedAddress & (Size - 1)) {
  382. //
  383. // The untrusted address is not properly aligned with the requested
  384. // transfer size. This is a caller error.
  385. //
  386. return STATUS_INVALID_PARAMETER_3;
  387. }
  388. if (((ULONG)UntrustedAddress & ~(Size - 1)) !=
  389. (((ULONG)UntrustedAddress + Size - 1) & ~(Size - 1))) {
  390. //
  391. // The range spanned by the untrusted address crosses a page boundary.
  392. // Straddling pages is not allowed. This is a caller error.
  393. //
  394. return STATUS_INVALID_PARAMETER_3;
  395. }
  396. PfnHeld = FALSE;
  397. WsHeld = 0;
  398. //
  399. // Initializing OldIrql and PhysicalAddress are not needed for
  400. // correctness but without it the compiler cannot compile this code
  401. // W4 to check for use of uninitialized variables.
  402. //
  403. PfnIrql = PASSIVE_LEVEL;
  404. OldIrql = PASSIVE_LEVEL;
  405. PhysicalAddress.LowPart = 0;
  406. ForceWritableIfPossible = TRUE;
  407. if ((Flags & MMDBG_COPY_PHYSICAL) == 0) {
  408. //
  409. // If the caller has not frozen the machine (ie: this is localkd or the
  410. // equivalent), then acquire the PFN lock. This keeps the address
  411. // valid even after the return from the MmIsAddressValid call. Note
  412. // that for system (or session) addresses, the relevant working set
  413. // mutex is acquired to prevent the page from getting trimmed or the
  414. // PTE access bit from getting cleared. For user space addresses,
  415. // no mutex is needed because the access is performed using the user
  416. // virtual address inside an exception handler.
  417. //
  418. if ((Flags & MMDBG_COPY_UNSAFE) == 0) {
  419. if (KeGetCurrentIrql () > APC_LEVEL) {
  420. return STATUS_INVALID_PARAMETER_4;
  421. }
  422. //
  423. // Note that for safe copy mode (ie: the system is live), the
  424. // address must not be made writable if it is not already because
  425. // other threads might concurrently access it this way and losing
  426. // copy-on-write semantics, etc would be very bad.
  427. //
  428. ForceWritableIfPossible = FALSE;
  429. if ((PVOID) (ULONG_PTR) UntrustedAddress >= MmSystemRangeStart) {
  430. Thread = PsGetCurrentThread ();
  431. if (MmIsSessionAddress ((PVOID)(ULONG_PTR)UntrustedAddress)) {
  432. if (MmGetSessionId (PsGetCurrentProcess ()) == 0) {
  433. return STATUS_INVALID_PARAMETER_1;
  434. }
  435. WsHeld = 1;
  436. LOCK_SESSION_SPACE_WS (OldIrql, Thread);
  437. }
  438. else {
  439. WsHeld = 2;
  440. LOCK_SYSTEM_WS (OldIrql, Thread);
  441. }
  442. PfnHeld = TRUE;
  443. LOCK_PFN (PfnIrql);
  444. }
  445. else {
  446. //
  447. // The caller specified a user address. Probe and access
  448. // the address carefully inside an exception handler.
  449. //
  450. try {
  451. if (Flags & MMDBG_COPY_WRITE) {
  452. ProbeForWrite ((PVOID)(ULONG_PTR)UntrustedAddress, Size, Size);
  453. }
  454. else {
  455. ProbeForRead ((PVOID)(ULONG_PTR)UntrustedAddress, Size, Size);
  456. }
  457. } except(EXCEPTION_EXECUTE_HANDLER) {
  458. return GetExceptionCode();
  459. }
  460. VirtualAddress = (PVOID) (ULONG_PTR) UntrustedAddress;
  461. if (Flags & MMDBG_COPY_WRITE) {
  462. goto WriteData;
  463. }
  464. else {
  465. goto ReadData;
  466. }
  467. }
  468. }
  469. if (MmIsAddressValid ((PVOID) (ULONG_PTR) UntrustedAddress) == FALSE) {
  470. if (PfnHeld == TRUE) {
  471. UNLOCK_PFN (PfnIrql);
  472. }
  473. if (WsHeld == 1) {
  474. UNLOCK_SESSION_SPACE_WS (OldIrql);
  475. }
  476. else if (WsHeld == 2) {
  477. UNLOCK_SYSTEM_WS (OldIrql);
  478. }
  479. return STATUS_INVALID_PARAMETER_1;
  480. }
  481. VirtualAddress = (PVOID) (ULONG_PTR) UntrustedAddress;
  482. }
  483. else {
  484. PhysicalAddress.QuadPart = UntrustedAddress;
  485. //
  486. // If the caller has not frozen the machine (ie: this is localkd or the
  487. // equivalent), then acquire the PFN lock. This prevents
  488. // MmPhysicalMemoryBlock from changing inside the debug PTE routines
  489. // and also blocks APCs so malicious callers cannot suspend us
  490. // while we hold the debug PTE.
  491. //
  492. if ((Flags & MMDBG_COPY_UNSAFE) == 0) {
  493. if (KeGetCurrentIrql () > APC_LEVEL) {
  494. return STATUS_INVALID_PARAMETER_4;
  495. }
  496. PfnHeld = TRUE;
  497. LOCK_PFN (PfnIrql);
  498. }
  499. VirtualAddress = (PVOID) (ULONG_PTR) MiDbgTranslatePhysicalAddress (PhysicalAddress, Flags);
  500. if (VirtualAddress == NULL) {
  501. if (PfnHeld == TRUE) {
  502. UNLOCK_PFN (PfnIrql);
  503. }
  504. return STATUS_UNSUCCESSFUL;
  505. }
  506. }
  507. if (Flags & MMDBG_COPY_WRITE) {
  508. VirtualAddress = MiDbgWriteCheck (VirtualAddress, &Opaque, ForceWritableIfPossible);
  509. if (VirtualAddress == NULL) {
  510. if (PfnHeld == TRUE) {
  511. UNLOCK_PFN (PfnIrql);
  512. }
  513. if (WsHeld == 1) {
  514. UNLOCK_SESSION_SPACE_WS (OldIrql);
  515. }
  516. else if (WsHeld == 2) {
  517. UNLOCK_SYSTEM_WS (OldIrql);
  518. }
  519. return STATUS_INVALID_PARAMETER_1;
  520. }
  521. WriteData:
  522. //
  523. // Carefully capture the source buffer into a local *aligned* buffer
  524. // as the write to the target must be done using the desired operation
  525. // size specified by the caller. This is because the target may be
  526. // a memory mapped device which requires specific transfer sizes.
  527. //
  528. SourceBuffer = (PCHAR) Buffer;
  529. try {
  530. for (i = 0; i < Size; i += 1) {
  531. TempBuffer[i] = *SourceBuffer;
  532. SourceBuffer += 1;
  533. }
  534. } except(EXCEPTION_EXECUTE_HANDLER) {
  535. ASSERT (WsHeld == 0);
  536. ASSERT (PfnHeld == FALSE);
  537. return GetExceptionCode();
  538. }
  539. switch (Size) {
  540. case 1:
  541. *(PCHAR) VirtualAddress = *(PCHAR) TempBuffer;
  542. break;
  543. case 2:
  544. *(PSHORT) VirtualAddress = *(PSHORT) TempBuffer;
  545. break;
  546. case 4:
  547. *(PULONG) VirtualAddress = *(PULONG) TempBuffer;
  548. break;
  549. case 8:
  550. *(PULONGLONG) VirtualAddress = *(PULONGLONG) TempBuffer;
  551. break;
  552. default:
  553. break;
  554. }
  555. if ((PVOID) (ULONG_PTR) UntrustedAddress >= MmSystemRangeStart) {
  556. MiDbgReleaseAddress (VirtualAddress, &Opaque);
  557. }
  558. }
  559. else {
  560. ReadData:
  561. try {
  562. switch (Size) {
  563. case 1:
  564. *(PCHAR) TempBuffer = *(PCHAR) VirtualAddress;
  565. break;
  566. case 2:
  567. *(PSHORT) TempBuffer = *(PSHORT) VirtualAddress;
  568. break;
  569. case 4:
  570. *(PULONG) TempBuffer = *(PULONG) VirtualAddress;
  571. break;
  572. case 8:
  573. *(PULONGLONG) TempBuffer = *(PULONGLONG) VirtualAddress;
  574. break;
  575. default:
  576. break;
  577. }
  578. } except(EXCEPTION_EXECUTE_HANDLER) {
  579. ASSERT (WsHeld == 0);
  580. ASSERT (PfnHeld == FALSE);
  581. return GetExceptionCode();
  582. }
  583. //
  584. // The buffer to fill may not be aligned so do it one character at
  585. // a time.
  586. //
  587. TargetBuffer = (PCHAR) Buffer;
  588. for (i = 0; i < Size; i += 1) {
  589. *TargetBuffer = TempBuffer[i];
  590. TargetBuffer += 1;
  591. }
  592. }
  593. if (Flags & MMDBG_COPY_PHYSICAL) {
  594. MiDbgUnTranslatePhysicalAddress ();
  595. }
  596. if (PfnHeld == TRUE) {
  597. UNLOCK_PFN (PfnIrql);
  598. }
  599. if (WsHeld == 1) {
  600. UNLOCK_SESSION_SPACE_WS (OldIrql);
  601. }
  602. else if (WsHeld == 2) {
  603. UNLOCK_SYSTEM_WS (OldIrql);
  604. }
  605. return STATUS_SUCCESS;
  606. }
  607. LOGICAL
  608. MmDbgIsLowMemOk (
  609. IN PFN_NUMBER PageFrameIndex,
  610. OUT PPFN_NUMBER NextPageFrameIndex,
  611. IN OUT PULONG CorruptionOffset
  612. )
  613. /*++
  614. Routine Description:
  615. This is a special function called only from the kernel debugger
  616. to check that the physical memory below 4Gb removed with /NOLOWMEM
  617. contains the expected fill patterns. If not, there is a high
  618. probability that a driver which cannot handle physical addresses greater
  619. than 32 bits corrupted the memory.
  620. Arguments:
  621. PageFrameIndex - Supplies the physical page number to check.
  622. NextPageFrameIndex - Supplies the next physical page number the caller
  623. should check or 0 if the search is complete.
  624. CorruptionOffset - If corruption is found, the byte offset
  625. of the corruption start is returned here.
  626. Return Value:
  627. TRUE if the page was removed and the fill pattern is correct, or
  628. if the page was never removed. FALSE if corruption was detected
  629. in the page.
  630. Environment:
  631. This routine is for use of the kernel debugger ONLY, specifically
  632. the !chklowmem command.
  633. The debugger's PTE will be repointed.
  634. --*/
  635. {
  636. #if defined (_MI_MORE_THAN_4GB_)
  637. PULONG Va;
  638. ULONG Index;
  639. PHYSICAL_ADDRESS Pa;
  640. #if DBG
  641. PMMPFN Pfn;
  642. #endif
  643. if (MiNoLowMemory == 0) {
  644. *NextPageFrameIndex = 0;
  645. return TRUE;
  646. }
  647. if (MiLowMemoryBitMap == NULL) {
  648. *NextPageFrameIndex = 0;
  649. return TRUE;
  650. }
  651. if (PageFrameIndex >= MiNoLowMemory - 1) {
  652. *NextPageFrameIndex = 0;
  653. }
  654. else {
  655. *NextPageFrameIndex = PageFrameIndex + 1;
  656. }
  657. //
  658. // Verify that the page to be verified is one of the reclaimed
  659. // pages.
  660. //
  661. if ((PageFrameIndex >= MiLowMemoryBitMap->SizeOfBitMap) ||
  662. (RtlCheckBit (MiLowMemoryBitMap, PageFrameIndex) == 0)) {
  663. return TRUE;
  664. }
  665. //
  666. // At this point we have a low page that is not in active use.
  667. // The fill pattern must match.
  668. //
  669. #if DBG
  670. Pfn = MI_PFN_ELEMENT (PageFrameIndex);
  671. ASSERT (Pfn->u4.PteFrame == MI_MAGIC_4GB_RECLAIM);
  672. ASSERT (Pfn->u3.e1.PageLocation == ActiveAndValid);
  673. #endif
  674. //
  675. // Map the physical page using the debug PTE so the
  676. // fill pattern can be validated.
  677. //
  678. // The debugger cannot be using this virtual address on entry or exit.
  679. //
  680. Pa.QuadPart = ((ULONGLONG)PageFrameIndex) << PAGE_SHIFT;
  681. Va = (PULONG) MiDbgTranslatePhysicalAddress (Pa, 0);
  682. if (Va == NULL) {
  683. return TRUE;
  684. }
  685. for (Index = 0; Index < PAGE_SIZE / sizeof(ULONG); Index += 1) {
  686. if (*Va != (PageFrameIndex | MI_LOWMEM_MAGIC_BIT)) {
  687. if (CorruptionOffset != NULL) {
  688. *CorruptionOffset = Index * sizeof(ULONG);
  689. }
  690. MiDbgUnTranslatePhysicalAddress ();
  691. return FALSE;
  692. }
  693. Va += 1;
  694. }
  695. MiDbgUnTranslatePhysicalAddress ();
  696. #else
  697. UNREFERENCED_PARAMETER (PageFrameIndex);
  698. UNREFERENCED_PARAMETER (CorruptionOffset);
  699. *NextPageFrameIndex = 0;
  700. #endif
  701. return TRUE;
  702. }