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.

1095 lines
30 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. nolowmem.c
  5. Abstract:
  6. This module contains routines which remove physical memory below 4GB
  7. to make testing for driver addressing errors easier.
  8. Author:
  9. Landy Wang (landyw) 30-Nov-1998
  10. Revision History:
  11. --*/
  12. #include "mi.h"
  13. //
  14. // If /NOLOWMEM is used, this is set to the boundary PFN (pages below this
  15. // value are not used whenever possible).
  16. //
  17. PFN_NUMBER MiNoLowMemory;
  18. #if defined (_MI_MORE_THAN_4GB_)
  19. VOID
  20. MiFillRemovedPages (
  21. IN ULONG StartPage,
  22. IN ULONG NumberOfPages
  23. );
  24. ULONG
  25. MiRemoveModuloPages (
  26. IN ULONG StartPage,
  27. IN ULONG LastPage
  28. );
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(INIT,MiRemoveLowPages)
  31. #pragma alloc_text(INIT,MiFillRemovedPages)
  32. #pragma alloc_text(INIT,MiRemoveModuloPages)
  33. #endif
  34. PRTL_BITMAP MiLowMemoryBitMap;
  35. LOGICAL MiFillModuloPages = FALSE;
  36. VOID
  37. MiFillRemovedPages (
  38. IN ULONG StartPage,
  39. IN ULONG NumberOfPages
  40. )
  41. /*++
  42. Routine Description:
  43. This routine fills low pages with a recognizable pattern. Thus, if the
  44. page is ever mistakenly used by a broken component, it will be easy to
  45. see exactly which bytes were corrupted.
  46. Arguments:
  47. StartPage - Supplies the low page to fill.
  48. NumberOfPages - Supplies the number of pages to fill.
  49. Return Value:
  50. None.
  51. Environment:
  52. Phase 0 initialization.
  53. --*/
  54. {
  55. ULONG Page;
  56. ULONG LastPage;
  57. PVOID LastChunkVa;
  58. ULONG MaxPageChunk;
  59. ULONG ThisPageChunk;
  60. PVOID TempVa;
  61. PVOID BaseVa;
  62. SIZE_T NumberOfBytes;
  63. PHYSICAL_ADDRESS PhysicalAddress;
  64. //
  65. // Do 256MB at a time when possible (don't want to overflow unit
  66. // conversions or fail to allocate system PTEs needlessly).
  67. //
  68. MaxPageChunk = (256 * 1024 * 1024) / PAGE_SIZE;
  69. LastPage = StartPage + NumberOfPages;
  70. PhysicalAddress.QuadPart = StartPage;
  71. PhysicalAddress.QuadPart = PhysicalAddress.QuadPart << PAGE_SHIFT;
  72. Page = StartPage;
  73. while (Page < LastPage) {
  74. if (NumberOfPages > MaxPageChunk) {
  75. ThisPageChunk = MaxPageChunk;
  76. }
  77. else {
  78. ThisPageChunk = NumberOfPages;
  79. }
  80. NumberOfBytes = ThisPageChunk << PAGE_SHIFT;
  81. BaseVa = MmMapIoSpace (PhysicalAddress, NumberOfBytes, MmCached);
  82. if (BaseVa != NULL) {
  83. //
  84. // Fill the actual page with a recognizable data pattern. No
  85. // one should write to these pages unless they are allocated for
  86. // a contiguous memory request.
  87. //
  88. TempVa = BaseVa;
  89. LastChunkVa = (PVOID)((ULONG_PTR)BaseVa + NumberOfBytes);
  90. while (TempVa < LastChunkVa) {
  91. RtlFillMemoryUlong (TempVa,
  92. PAGE_SIZE,
  93. (ULONG)Page | MI_LOWMEM_MAGIC_BIT);
  94. TempVa = (PVOID)((ULONG_PTR)TempVa + PAGE_SIZE);
  95. Page += 1;
  96. }
  97. MmUnmapIoSpace (BaseVa, NumberOfBytes);
  98. }
  99. else {
  100. MaxPageChunk /= 2;
  101. if (MaxPageChunk == 0) {
  102. #if DBG
  103. DbgPrint ("Not even one PTE available for filling lowmem pages\n");
  104. DbgBreakPoint ();
  105. #endif
  106. break;
  107. }
  108. }
  109. }
  110. }
  111. ULONG
  112. MiRemoveModuloPages (
  113. IN ULONG StartPage,
  114. IN ULONG LastPage
  115. )
  116. /*++
  117. Routine Description:
  118. This routine removes pages above 4GB.
  119. For every page below 4GB that could not be reclaimed, don't use the
  120. high modulo-4GB equivalent page. The motivation is to prevent
  121. code bugs that drop the high bits from destroying critical
  122. system data in the unclaimed pages (like the GDT, IDT, kernel code
  123. and data, etc).
  124. Arguments:
  125. StartPage - Supplies the low page to modulo-ize and remove.
  126. LastPage - Supplies the final low page to modulo-ize and remove.
  127. Return Value:
  128. None.
  129. Environment:
  130. Phase 0 initialization.
  131. --*/
  132. {
  133. PEPROCESS Process;
  134. ULONG Page;
  135. ULONG PagesRemoved;
  136. PVOID TempVa;
  137. KIRQL OldIrql;
  138. PFN_NUMBER HighPage;
  139. PMMPFN Pfn1;
  140. //
  141. // Removing modulo pages can take a long (on the order of 30 minutes!) on
  142. // large memory systems because the various PFN lists generally need to
  143. // linearly walked in order to find and cross-remove from the colored chains
  144. // the requested pages. Since actually putting these pages out of
  145. // circulation is of dubious benefit, default this behavior to disabled
  146. // but leave the data variable so a questionable machine can have this
  147. // enabled without needing a new kernel.
  148. //
  149. if (MiFillModuloPages == FALSE) {
  150. return 0;
  151. }
  152. Process = PsGetCurrentProcess ();
  153. PagesRemoved = 0;
  154. #if DBG
  155. DbgPrint ("Removing modulo pages %x %x\n", StartPage, LastPage);
  156. #endif
  157. for (Page = StartPage; Page < LastPage; Page += 1) {
  158. //
  159. // Search for any high modulo pages and remove them.
  160. //
  161. HighPage = Page + MiNoLowMemory;
  162. LOCK_PFN (OldIrql);
  163. while (HighPage <= MmHighestPhysicalPage) {
  164. Pfn1 = MI_PFN_ELEMENT (HighPage);
  165. if ((MmIsAddressValid(Pfn1)) &&
  166. (MmIsAddressValid((PCHAR)Pfn1 + sizeof(MMPFN) - 1)) &&
  167. ((ULONG)Pfn1->u3.e1.PageLocation <= (ULONG)StandbyPageList) &&
  168. (Pfn1->u1.Flink != 0) &&
  169. (Pfn1->u2.Blink != 0) &&
  170. (Pfn1->u3.e2.ReferenceCount == 0) &&
  171. (MmAvailablePages > 0)) {
  172. //
  173. // Systems utilizing memory compression may have more
  174. // pages on the zero, free and standby lists than we
  175. // want to give out. Explicitly check MmAvailablePages
  176. // above instead (and recheck whenever the PFN lock is
  177. // released and reacquired).
  178. //
  179. //
  180. // This page can be taken.
  181. //
  182. if (Pfn1->u3.e1.PageLocation == StandbyPageList) {
  183. MiUnlinkPageFromList (Pfn1);
  184. MiRestoreTransitionPte (HighPage);
  185. }
  186. else {
  187. MiUnlinkFreeOrZeroedPage (HighPage);
  188. }
  189. Pfn1->u3.e2.ShortFlags = 0;
  190. Pfn1->u3.e2.ReferenceCount = 1;
  191. Pfn1->u2.ShareCount = 1;
  192. Pfn1->PteAddress = (PMMPTE)(ULONG_PTR)0xFFFFFFF8;
  193. Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE;
  194. Pfn1->u4.PteFrame = MI_MAGIC_4GB_RECLAIM;
  195. Pfn1->u3.e1.PageLocation = ActiveAndValid;
  196. Pfn1->u3.e1.CacheAttribute = MiNotMapped;
  197. Pfn1->u4.VerifierAllocation = 0;
  198. Pfn1->u3.e1.LargeSessionAllocation = 0;
  199. Pfn1->u3.e1.StartOfAllocation = 1;
  200. Pfn1->u3.e1.EndOfAllocation = 1;
  201. //
  202. // Fill the actual page with a recognizable data
  203. // pattern. No one else should write to these
  204. // pages unless they are allocated for
  205. // a contiguous memory request.
  206. //
  207. MmNumberOfPhysicalPages -= 1;
  208. UNLOCK_PFN (OldIrql);
  209. TempVa = (PULONG)MiMapPageInHyperSpace (Process,
  210. HighPage,
  211. &OldIrql);
  212. RtlFillMemoryUlong (TempVa,
  213. PAGE_SIZE,
  214. (ULONG)HighPage | MI_LOWMEM_MAGIC_BIT);
  215. MiUnmapPageInHyperSpace (Process, TempVa, OldIrql);
  216. PagesRemoved += 1;
  217. LOCK_PFN (OldIrql);
  218. }
  219. HighPage += MiNoLowMemory;
  220. }
  221. UNLOCK_PFN (OldIrql);
  222. }
  223. #if DBG
  224. DbgPrint ("Done removing modulo pages %x %x\n", StartPage, LastPage);
  225. #endif
  226. return PagesRemoved;
  227. }
  228. VOID
  229. MiRemoveLowPages (
  230. ULONG RemovePhase
  231. )
  232. /*++
  233. Routine Description:
  234. This routine removes all pages below physical 4GB in the system. This lets
  235. us find problems with device drivers by putting all accesses high.
  236. Arguments:
  237. RemovePhase - Supplies the current phase of page removal.
  238. Return Value:
  239. None.
  240. Environment:
  241. Kernel mode.
  242. --*/
  243. {
  244. KIRQL OldIrql;
  245. ULONG i;
  246. ULONG BitMapIndex;
  247. ULONG BitMapHint;
  248. ULONG LengthOfClearRun;
  249. ULONG LengthOfSetRun;
  250. ULONG StartingRunIndex;
  251. ULONG ModuloRemoved;
  252. ULONG PagesRemoved;
  253. PFN_COUNT PageCount;
  254. PMMPFN PfnNextColored;
  255. PMMPFN PfnNextFlink;
  256. PMMPFN PfnLastColored;
  257. PFN_NUMBER PageNextColored;
  258. PFN_NUMBER PageNextFlink;
  259. PFN_NUMBER PageLastColored;
  260. PFN_NUMBER Page;
  261. PMMPFN Pfn1;
  262. PMMPFNLIST ListHead;
  263. ULONG Color;
  264. PMMCOLOR_TABLES ColorHead;
  265. PFN_NUMBER MovedPage;
  266. if (RemovePhase == 0) {
  267. MiCreateBitMap (&MiLowMemoryBitMap, (ULONG)MiNoLowMemory, NonPagedPool);
  268. if (MiLowMemoryBitMap != NULL) {
  269. RtlClearAllBits (MiLowMemoryBitMap);
  270. MmMakeLowMemory = TRUE;
  271. }
  272. }
  273. if (MiLowMemoryBitMap == NULL) {
  274. return;
  275. }
  276. ListHead = &MmFreePageListHead;
  277. PageCount = 0;
  278. LOCK_PFN (OldIrql);
  279. for (Color = 0; Color < MmSecondaryColors; Color += 1) {
  280. ColorHead = &MmFreePagesByColor[FreePageList][Color];
  281. MovedPage = MM_EMPTY_LIST;
  282. while (ColorHead->Flink != MM_EMPTY_LIST) {
  283. Page = ColorHead->Flink;
  284. Pfn1 = MI_PFN_ELEMENT(Page);
  285. ASSERT ((MMLISTS)Pfn1->u3.e1.PageLocation == FreePageList);
  286. //
  287. // The Flink and Blink must be nonzero here for the page
  288. // to be on the listhead. Only code that scans the
  289. // MmPhysicalMemoryBlock has to check for the zero case.
  290. //
  291. ASSERT (Pfn1->u1.Flink != 0);
  292. ASSERT (Pfn1->u2.Blink != 0);
  293. //
  294. // See if the page is below 4GB - if not, skip it.
  295. //
  296. if (Page >= MiNoLowMemory) {
  297. //
  298. // Put page on end of list and if first time, save pfn.
  299. //
  300. if (MovedPage == MM_EMPTY_LIST) {
  301. MovedPage = Page;
  302. }
  303. else if (Page == MovedPage) {
  304. //
  305. // No more pages available in this colored chain.
  306. //
  307. break;
  308. }
  309. //
  310. // If the colored chain has more than one entry then
  311. // put this page on the end.
  312. //
  313. PageNextColored = (PFN_NUMBER)Pfn1->OriginalPte.u.Long;
  314. if (PageNextColored == MM_EMPTY_LIST) {
  315. //
  316. // No more pages available in this colored chain.
  317. //
  318. break;
  319. }
  320. ASSERT (Pfn1->u1.Flink != 0);
  321. ASSERT (Pfn1->u1.Flink != MM_EMPTY_LIST);
  322. ASSERT (Pfn1->u4.PteFrame != MI_MAGIC_4GB_RECLAIM);
  323. PfnNextColored = MI_PFN_ELEMENT(PageNextColored);
  324. ASSERT ((MMLISTS)PfnNextColored->u3.e1.PageLocation == FreePageList);
  325. ASSERT (PfnNextColored->u4.PteFrame != MI_MAGIC_4GB_RECLAIM);
  326. //
  327. // Adjust the free page list so Page
  328. // follows PageNextFlink.
  329. //
  330. PageNextFlink = Pfn1->u1.Flink;
  331. PfnNextFlink = MI_PFN_ELEMENT(PageNextFlink);
  332. ASSERT ((MMLISTS)PfnNextFlink->u3.e1.PageLocation == FreePageList);
  333. ASSERT (PfnNextFlink->u4.PteFrame != MI_MAGIC_4GB_RECLAIM);
  334. PfnLastColored = ColorHead->Blink;
  335. ASSERT (PfnLastColored != (PMMPFN)MM_EMPTY_LIST);
  336. ASSERT (PfnLastColored->OriginalPte.u.Long == MM_EMPTY_LIST);
  337. ASSERT (PfnLastColored->u4.PteFrame != MI_MAGIC_4GB_RECLAIM);
  338. ASSERT (PfnLastColored->u2.Blink != MM_EMPTY_LIST);
  339. ASSERT ((MMLISTS)PfnLastColored->u3.e1.PageLocation == FreePageList);
  340. PageLastColored = PfnLastColored - MmPfnDatabase;
  341. if (ListHead->Flink == Page) {
  342. ASSERT (Pfn1->u2.Blink == MM_EMPTY_LIST);
  343. ASSERT (ListHead->Blink != Page);
  344. ListHead->Flink = PageNextFlink;
  345. PfnNextFlink->u2.Blink = MM_EMPTY_LIST;
  346. }
  347. else {
  348. ASSERT (Pfn1->u2.Blink != MM_EMPTY_LIST);
  349. ASSERT ((MMLISTS)(MI_PFN_ELEMENT((MI_PFN_ELEMENT(Pfn1->u2.Blink)->u1.Flink)))->u4.PteFrame != MI_MAGIC_4GB_RECLAIM);
  350. ASSERT ((MMLISTS)(MI_PFN_ELEMENT((MI_PFN_ELEMENT(Pfn1->u2.Blink)->u1.Flink)))->u3.e1.PageLocation == FreePageList);
  351. MI_PFN_ELEMENT(Pfn1->u2.Blink)->u1.Flink = PageNextFlink;
  352. PfnNextFlink->u2.Blink = Pfn1->u2.Blink;
  353. }
  354. #if DBG
  355. if (PfnLastColored->u1.Flink == MM_EMPTY_LIST) {
  356. ASSERT (ListHead->Blink == PageLastColored);
  357. }
  358. #endif
  359. Pfn1->u1.Flink = PfnLastColored->u1.Flink;
  360. Pfn1->u2.Blink = PageLastColored;
  361. if (ListHead->Blink == PageLastColored) {
  362. ListHead->Blink = Page;
  363. }
  364. //
  365. // Adjust the colored chains.
  366. //
  367. if (PfnLastColored->u1.Flink != MM_EMPTY_LIST) {
  368. ASSERT (MI_PFN_ELEMENT(PfnLastColored->u1.Flink)->u4.PteFrame != MI_MAGIC_4GB_RECLAIM);
  369. ASSERT ((MMLISTS)(MI_PFN_ELEMENT(PfnLastColored->u1.Flink)->u3.e1.PageLocation) == FreePageList);
  370. MI_PFN_ELEMENT(PfnLastColored->u1.Flink)->u2.Blink = Page;
  371. }
  372. PfnLastColored->u1.Flink = Page;
  373. ColorHead->Flink = PageNextColored;
  374. Pfn1->OriginalPte.u.Long = MM_EMPTY_LIST;
  375. ASSERT (PfnLastColored->OriginalPte.u.Long == MM_EMPTY_LIST);
  376. PfnLastColored->OriginalPte.u.Long = Page;
  377. ColorHead->Blink = Pfn1;
  378. continue;
  379. }
  380. //
  381. // Page is below 4GB so reclaim it.
  382. //
  383. ASSERT (Pfn1->u3.e1.ReadInProgress == 0);
  384. MiUnlinkFreeOrZeroedPage (Page);
  385. Pfn1->u3.e2.ReferenceCount = 1;
  386. Pfn1->u2.ShareCount = 1;
  387. MI_SET_PFN_DELETED(Pfn1);
  388. Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE;
  389. Pfn1->u4.PteFrame = MI_MAGIC_4GB_RECLAIM;
  390. Pfn1->u3.e1.PageLocation = ActiveAndValid;
  391. Pfn1->u3.e1.CacheAttribute = MiNotMapped;
  392. Pfn1->u3.e1.StartOfAllocation = 1;
  393. Pfn1->u3.e1.EndOfAllocation = 1;
  394. Pfn1->u4.VerifierAllocation = 0;
  395. Pfn1->u3.e1.LargeSessionAllocation = 0;
  396. ASSERT (Page < MiLowMemoryBitMap->SizeOfBitMap);
  397. ASSERT (RtlCheckBit (MiLowMemoryBitMap, Page) == 0);
  398. RtlSetBit (MiLowMemoryBitMap, (ULONG)Page);
  399. PageCount += 1;
  400. }
  401. }
  402. MmNumberOfPhysicalPages -= PageCount;
  403. UNLOCK_PFN (OldIrql);
  404. #if DBG
  405. DbgPrint ("Removed 0x%x pages from low memory for LOW MEMORY testing\n", PageCount);
  406. #endif
  407. ModuloRemoved = 0;
  408. if (RemovePhase == 1) {
  409. //
  410. // For every page below 4GB that could not be reclaimed, don't use the
  411. // high modulo-4GB equivalent page. The motivation is to prevent
  412. // code bugs that drop the high bits from destroying critical
  413. // system data in the unclaimed pages (like the GDT, IDT, kernel code
  414. // and data, etc).
  415. //
  416. BitMapHint = 0;
  417. PagesRemoved = 0;
  418. StartingRunIndex = 0;
  419. LengthOfClearRun = 0;
  420. #if DBG
  421. DbgPrint ("%x Unclaimable Pages below 4GB are:\n\n",
  422. MiLowMemoryBitMap->SizeOfBitMap - RtlNumberOfSetBits (MiLowMemoryBitMap));
  423. DbgPrint ("StartPage EndPage Length\n");
  424. #endif
  425. do {
  426. BitMapIndex = RtlFindSetBits (MiLowMemoryBitMap, 1, BitMapHint);
  427. if (BitMapIndex < BitMapHint) {
  428. break;
  429. }
  430. if (BitMapIndex == NO_BITS_FOUND) {
  431. break;
  432. }
  433. //
  434. // Print the page run that was clear as we didn't get those pages.
  435. //
  436. if (BitMapIndex != 0) {
  437. #if DBG
  438. DbgPrint ("%08lx %08lx %08lx\n",
  439. StartingRunIndex,
  440. BitMapIndex - 1,
  441. BitMapIndex - StartingRunIndex);
  442. #endif
  443. //
  444. // Also remove high modulo pages corresponding to the low ones
  445. // we couldn't get.
  446. //
  447. ModuloRemoved += MiRemoveModuloPages (StartingRunIndex,
  448. BitMapIndex);
  449. }
  450. //
  451. // Found at least one page to copy - try for a cluster.
  452. //
  453. LengthOfClearRun = RtlFindNextForwardRunClear (MiLowMemoryBitMap,
  454. BitMapIndex,
  455. &StartingRunIndex);
  456. if (LengthOfClearRun != 0) {
  457. LengthOfSetRun = StartingRunIndex - BitMapIndex;
  458. }
  459. else {
  460. LengthOfSetRun = MiLowMemoryBitMap->SizeOfBitMap - BitMapIndex;
  461. }
  462. PagesRemoved += LengthOfSetRun;
  463. //
  464. // Fill the page run with unique patterns.
  465. //
  466. MiFillRemovedPages (BitMapIndex, LengthOfSetRun);
  467. //
  468. // Clear the cache attribute bit in each page as MmMapIoSpace
  469. // will have set it, but no one else has cleared it.
  470. //
  471. Pfn1 = MI_PFN_ELEMENT(BitMapIndex);
  472. i = LengthOfSetRun;
  473. LOCK_PFN (OldIrql);
  474. do {
  475. Pfn1->u3.e1.CacheAttribute = MiNotMapped;
  476. Pfn1 += 1;
  477. i -= 1;
  478. } while (i != 0);
  479. UNLOCK_PFN (OldIrql);
  480. BitMapHint = BitMapIndex + LengthOfSetRun + LengthOfClearRun;
  481. } while (BitMapHint < MiLowMemoryBitMap->SizeOfBitMap);
  482. if (LengthOfClearRun != 0) {
  483. #if DBG
  484. DbgPrint ("%08lx %08lx %08lx\n",
  485. StartingRunIndex,
  486. StartingRunIndex + LengthOfClearRun - 1,
  487. LengthOfClearRun);
  488. #endif
  489. ModuloRemoved += MiRemoveModuloPages (StartingRunIndex,
  490. StartingRunIndex + LengthOfClearRun);
  491. }
  492. ASSERT (RtlNumberOfSetBits(MiLowMemoryBitMap) == PagesRemoved);
  493. }
  494. #if DBG
  495. if (ModuloRemoved != 0) {
  496. DbgPrint ("Total 0x%x Above-4GB Alias Pages also reclaimed\n\n",
  497. ModuloRemoved);
  498. }
  499. #endif
  500. }
  501. PVOID
  502. MiAllocateLowMemory (
  503. IN SIZE_T NumberOfBytes,
  504. IN PFN_NUMBER LowestAcceptablePfn,
  505. IN PFN_NUMBER HighestAcceptablePfn,
  506. IN PFN_NUMBER BoundaryPfn,
  507. IN PVOID CallingAddress,
  508. IN MEMORY_CACHING_TYPE CacheType,
  509. IN ULONG Tag
  510. )
  511. /*++
  512. Routine Description:
  513. This is a special routine for allocating contiguous physical memory below
  514. 4GB on a system that has been booted in test mode where all this memory
  515. has been made generally unavailable to all components. This lets us find
  516. problems with device drivers.
  517. Arguments:
  518. NumberOfBytes - Supplies the number of bytes to allocate.
  519. LowestAcceptablePfn - Supplies the lowest page frame number
  520. which is valid for the allocation.
  521. HighestAcceptablePfn - Supplies the highest page frame number
  522. which is valid for the allocation.
  523. BoundaryPfn - Supplies the page frame number multiple the allocation must
  524. not cross. 0 indicates it can cross any boundary.
  525. CallingAddress - Supplies the calling address of the allocator.
  526. CacheType - Supplies the type of cache mapping that will be used for the
  527. memory.
  528. Tag - Supplies the tag to tie to this allocation.
  529. Return Value:
  530. NULL - a contiguous range could not be found to satisfy the request.
  531. NON-NULL - Returns a pointer (virtual address in the system PTEs portion
  532. of the system) to the allocated physically contiguous
  533. memory.
  534. Environment:
  535. Kernel mode, IRQL of APC_LEVEL or below.
  536. --*/
  537. {
  538. PFN_NUMBER Page;
  539. PFN_NUMBER BoundaryMask;
  540. PVOID BaseAddress;
  541. KIRQL OldIrql;
  542. PMMPFN Pfn1;
  543. PMMPFN StartPfn;
  544. ULONG BitMapHint;
  545. PFN_NUMBER SizeInPages;
  546. PFN_NUMBER PageFrameIndex;
  547. PFN_NUMBER StartPage;
  548. PFN_NUMBER LastPage;
  549. PMMPTE PointerPte;
  550. PMMPTE DummyPte;
  551. PHYSICAL_ADDRESS PhysicalAddress;
  552. MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
  553. PAGED_CODE();
  554. UNREFERENCED_PARAMETER (Tag);
  555. UNREFERENCED_PARAMETER (CallingAddress);
  556. //
  557. // This cast is ok because the callers check the PFNs first.
  558. //
  559. ASSERT64 (LowestAcceptablePfn < _4gb);
  560. BitMapHint = (ULONG)LowestAcceptablePfn;
  561. SizeInPages = BYTES_TO_PAGES (NumberOfBytes);
  562. BoundaryMask = ~(BoundaryPfn - 1);
  563. CacheAttribute = MI_TRANSLATE_CACHETYPE (CacheType, 0);
  564. LOCK_PFN (OldIrql);
  565. do {
  566. Page = RtlFindSetBits (MiLowMemoryBitMap, (ULONG)SizeInPages, BitMapHint);
  567. if (Page == (ULONG)-1) {
  568. UNLOCK_PFN (OldIrql);
  569. return NULL;
  570. }
  571. if (BoundaryPfn == 0) {
  572. break;
  573. }
  574. //
  575. // If a noncachable mapping is requested, none of the pages in the
  576. // requested MDL can reside in a large page. Otherwise we would be
  577. // creating an incoherent overlapping TB entry as the same physical
  578. // page would be mapped by 2 different TB entries with different
  579. // cache attributes.
  580. //
  581. if (CacheAttribute != MiCached) {
  582. for (PageFrameIndex = Page; PageFrameIndex < Page + SizeInPages; PageFrameIndex += 1) {
  583. if (MI_PAGE_FRAME_INDEX_MUST_BE_CACHED (PageFrameIndex)) {
  584. MiNonCachedCollisions += 1;
  585. //
  586. // Keep it simple and just march one page at a time.
  587. //
  588. BitMapHint += 1;
  589. goto FindNext;
  590. }
  591. }
  592. }
  593. if (((Page ^ (Page + SizeInPages - 1)) & BoundaryMask) == 0) {
  594. //
  595. // This portion of the range meets the alignment requirements.
  596. //
  597. break;
  598. }
  599. BitMapHint = (ULONG)((Page & BoundaryMask) + BoundaryPfn);
  600. FindNext:
  601. if ((BitMapHint >= MiLowMemoryBitMap->SizeOfBitMap) ||
  602. (BitMapHint + SizeInPages > HighestAcceptablePfn)) {
  603. UNLOCK_PFN (OldIrql);
  604. return NULL;
  605. }
  606. } while (TRUE);
  607. if (Page + SizeInPages > HighestAcceptablePfn) {
  608. UNLOCK_PFN (OldIrql);
  609. return NULL;
  610. }
  611. RtlClearBits (MiLowMemoryBitMap, (ULONG)Page, (ULONG)SizeInPages);
  612. //
  613. // No need to update ResidentAvailable or commit as these pages were
  614. // never added to either.
  615. //
  616. Pfn1 = MI_PFN_ELEMENT (Page);
  617. StartPfn = Pfn1;
  618. StartPage = Page;
  619. LastPage = Page + SizeInPages;
  620. DummyPte = MiGetPteAddress (MmNonPagedPoolExpansionStart);
  621. do {
  622. ASSERT (Pfn1->u3.e1.PageLocation == ActiveAndValid);
  623. ASSERT (Pfn1->u3.e1.CacheAttribute == MiNotMapped);
  624. ASSERT (Pfn1->u3.e2.ReferenceCount == 1);
  625. ASSERT (Pfn1->u2.ShareCount == 1);
  626. ASSERT (Pfn1->OriginalPte.u.Long == MM_DEMAND_ZERO_WRITE_PTE);
  627. ASSERT (Pfn1->u4.VerifierAllocation == 0);
  628. ASSERT (Pfn1->u3.e1.LargeSessionAllocation == 0);
  629. MiDetermineNode (Page, Pfn1);
  630. Pfn1->u3.e1.CacheAttribute = CacheAttribute;
  631. Pfn1->u3.e1.EndOfAllocation = 0;
  632. //
  633. // Initialize PteAddress so an MiIdentifyPfn scan
  634. // won't crash. The real value is put in after the loop.
  635. //
  636. Pfn1->PteAddress = DummyPte;
  637. Pfn1 += 1;
  638. Page += 1;
  639. } while (Page < LastPage);
  640. Pfn1 -= 1;
  641. Pfn1->u3.e1.EndOfAllocation = 1;
  642. StartPfn->u3.e1.StartOfAllocation = 1;
  643. UNLOCK_PFN (OldIrql);
  644. PhysicalAddress.QuadPart = StartPage;
  645. PhysicalAddress.QuadPart = PhysicalAddress.QuadPart << PAGE_SHIFT;
  646. BaseAddress = MmMapIoSpace (PhysicalAddress,
  647. SizeInPages << PAGE_SHIFT,
  648. CacheType);
  649. if (BaseAddress == NULL) {
  650. //
  651. // Release the actual pages.
  652. //
  653. LOCK_PFN (OldIrql);
  654. ASSERT (Pfn1->u3.e1.EndOfAllocation == 1);
  655. Pfn1->u3.e1.EndOfAllocation = 0;
  656. Pfn1->u3.e1.CacheAttribute = MiNotMapped;
  657. RtlSetBits (MiLowMemoryBitMap, (ULONG)StartPage, (ULONG)SizeInPages);
  658. UNLOCK_PFN (OldIrql);
  659. return NULL;
  660. }
  661. PointerPte = MiGetPteAddress (BaseAddress);
  662. do {
  663. StartPfn->PteAddress = PointerPte;
  664. StartPfn->u4.PteFrame = MI_GET_PAGE_FRAME_FROM_PTE (MiGetPteAddress(PointerPte));
  665. StartPfn += 1;
  666. PointerPte += 1;
  667. } while (StartPfn <= Pfn1);
  668. #if 0
  669. MiInsertContiguousTag (BaseAddress,
  670. SizeInPages << PAGE_SHIFT,
  671. CallingAddress);
  672. #endif
  673. return BaseAddress;
  674. }
  675. LOGICAL
  676. MiFreeLowMemory (
  677. IN PVOID BaseAddress,
  678. IN ULONG Tag
  679. )
  680. /*++
  681. Routine Description:
  682. This is a special routine which returns allocated contiguous physical
  683. memory below 4GB on a system that has been booted in test mode where
  684. all this memory has been made generally unavailable to all components.
  685. This lets us find problems with device drivers.
  686. Arguments:
  687. BaseAddress - Supplies the base virtual address where the physical
  688. address was previously mapped.
  689. Tag - Supplies the tag for this address.
  690. Return Value:
  691. TRUE if the allocation was freed by this routine, FALSE if not.
  692. Environment:
  693. Kernel mode, IRQL of APC_LEVEL or below.
  694. --*/
  695. {
  696. PFN_NUMBER Page;
  697. PFN_NUMBER StartPage;
  698. KIRQL OldIrql;
  699. KIRQL OldIrqlHyper;
  700. PMMPFN Pfn1;
  701. PMMPFN Pfn2;
  702. PFN_NUMBER SizeInPages;
  703. PMMPTE PointerPte;
  704. PMMPTE StartPte;
  705. PULONG TempVa;
  706. PEPROCESS Process;
  707. PAGED_CODE();
  708. UNREFERENCED_PARAMETER (Tag);
  709. //
  710. // If the address is superpage mapped then it must be a regular pool
  711. // address.
  712. //
  713. if (MI_IS_PHYSICAL_ADDRESS(BaseAddress)) {
  714. return FALSE;
  715. }
  716. Process = PsGetCurrentProcess ();
  717. PointerPte = MiGetPteAddress (BaseAddress);
  718. StartPte = PointerPte;
  719. ASSERT (PointerPte->u.Hard.Valid == 1);
  720. Page = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
  721. //
  722. // Only free allocations here that really were obtained from the low pool.
  723. //
  724. if (Page >= MiNoLowMemory) {
  725. return FALSE;
  726. }
  727. StartPage = Page;
  728. Pfn1 = MI_PFN_ELEMENT (Page);
  729. ASSERT (Pfn1->u3.e1.StartOfAllocation == 1);
  730. //
  731. // The PFNs can be walked without the PFN lock as no one can be changing
  732. // the allocation bits while this allocation is being freed.
  733. //
  734. Pfn2 = Pfn1;
  735. while (Pfn2->u3.e1.EndOfAllocation == 0) {
  736. Pfn2 += 1;
  737. }
  738. SizeInPages = Pfn2 - Pfn1 + 1;
  739. MmUnmapIoSpace (BaseAddress, SizeInPages << PAGE_SHIFT);
  740. LOCK_PFN (OldIrql);
  741. Pfn1->u3.e1.StartOfAllocation = 0;
  742. do {
  743. ASSERT (Pfn1->u3.e1.PageLocation == ActiveAndValid);
  744. ASSERT (Pfn1->u2.ShareCount == 1);
  745. ASSERT (Pfn1->OriginalPte.u.Long == MM_DEMAND_ZERO_WRITE_PTE);
  746. ASSERT (Pfn1->u4.VerifierAllocation == 0);
  747. ASSERT (Pfn1->u3.e1.LargeSessionAllocation == 0);
  748. while (Pfn1->u3.e2.ReferenceCount != 1) {
  749. //
  750. // A driver is still transferring data even though the caller
  751. // is freeing the memory. Wait a bit before filling this page.
  752. //
  753. UNLOCK_PFN (OldIrql);
  754. //
  755. // Drain the deferred lists as these pages may be
  756. // sitting in there right now.
  757. //
  758. MiDeferredUnlockPages (0);
  759. KeDelayExecutionThread (KernelMode, FALSE, (PLARGE_INTEGER)&MmShortTime);
  760. LOCK_PFN (OldIrql);
  761. ASSERT (Pfn1->u3.e1.StartOfAllocation == 0);
  762. continue;
  763. }
  764. Pfn1->u4.PteFrame = MI_MAGIC_4GB_RECLAIM;
  765. Pfn1->u3.e1.CacheAttribute = MiNotMapped;
  766. //
  767. // Fill the actual page with a recognizable data
  768. // pattern. No one else should write to these
  769. // pages unless they are allocated for
  770. // a contiguous memory request.
  771. //
  772. TempVa = (PULONG)MiMapPageInHyperSpace (Process, Page, &OldIrqlHyper);
  773. RtlFillMemoryUlong (TempVa, PAGE_SIZE, (ULONG)Page | MI_LOWMEM_MAGIC_BIT);
  774. MiUnmapPageInHyperSpace (Process, TempVa, OldIrqlHyper);
  775. if (Pfn1 == Pfn2) {
  776. break;
  777. }
  778. Pfn1 += 1;
  779. Page += 1;
  780. } while (TRUE);
  781. Pfn1->u3.e1.EndOfAllocation = 0;
  782. //
  783. // Note the clearing of the bitmap range cannot be done until all the
  784. // PFNs above are finished.
  785. //
  786. ASSERT (RtlAreBitsClear (MiLowMemoryBitMap, (ULONG)StartPage, (ULONG)SizeInPages) == TRUE);
  787. RtlSetBits (MiLowMemoryBitMap, (ULONG)StartPage, (ULONG)SizeInPages);
  788. //
  789. // No need to update ResidentAvailable or commit as these pages were
  790. // never added to either.
  791. //
  792. UNLOCK_PFN (OldIrql);
  793. return TRUE;
  794. }
  795. #endif