Leaked source code of windows server 2003
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.

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