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.

1001 lines
24 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. compress.c
  5. Abstract:
  6. This module contains the routines to support allow hardware to
  7. transparently compress physical memory.
  8. Author:
  9. Landy Wang (landyw) 21-Oct-2000
  10. Revision History:
  11. --*/
  12. #include "mi.h"
  13. #if defined (_MI_COMPRESSION)
  14. Enable the #if 0 code in cmdat3.c to allow Ratio specification.
  15. //
  16. // Compression public interface.
  17. //
  18. #define MM_PHYSICAL_MEMORY_PRODUCED_VIA_COMPRESSION 0x1
  19. typedef
  20. NTSTATUS
  21. (*PMM_SET_COMPRESSION_THRESHOLD) (
  22. IN ULONGLONG CompressionByteThreshold
  23. );
  24. typedef struct _MM_COMPRESSION_CONTEXT {
  25. ULONG Version;
  26. ULONG SizeInBytes;
  27. ULONGLONG ReservedBytes;
  28. PMM_SET_COMPRESSION_THRESHOLD SetCompressionThreshold;
  29. } MM_COMPRESSION_CONTEXT, *PMM_COMPRESSION_CONTEXT;
  30. #define MM_COMPRESSION_VERSION_INITIAL 1
  31. #define MM_COMPRESSION_VERSION_CURRENT 1
  32. NTSTATUS
  33. MmRegisterCompressionDevice (
  34. IN PMM_COMPRESSION_CONTEXT Context
  35. );
  36. NTSTATUS
  37. MmDeregisterCompressionDevice (
  38. IN PMM_COMPRESSION_CONTEXT Context
  39. );
  40. //
  41. // This defaults to 75% but can be overridden in the registry. At this
  42. // percentage of *real* physical memory in use, an interrupt is generated so
  43. // that memory management can zero pages to make more memory available.
  44. //
  45. #define MI_DEFAULT_COMPRESSION_THRESHOLD 75
  46. ULONG MmCompressionThresholdRatio;
  47. PFN_NUMBER MiNumberOfCompressionPages;
  48. PMM_SET_COMPRESSION_THRESHOLD MiSetCompressionThreshold;
  49. #if DBG
  50. KIRQL MiCompressionIrql;
  51. #endif
  52. //
  53. // Note there is also code in dynmem.c that is dependent on this #define.
  54. //
  55. #if defined (_MI_COMPRESSION_SUPPORTED_)
  56. typedef struct _MI_COMPRESSION_INFO {
  57. ULONG IsrPageProcessed;
  58. ULONG DpcPageProcessed;
  59. ULONG IsrForcedDpc;
  60. ULONG IsrFailedDpc;
  61. ULONG IsrRan;
  62. ULONG DpcRan;
  63. ULONG DpcsFired;
  64. ULONG IsrSkippedZeroedPage;
  65. ULONG DpcSkippedZeroedPage;
  66. ULONG PfnForcedDpcInsert;
  67. ULONG PfnFailedDpcInsert;
  68. } MI_COMPRESSION_INFO, *PMI_COMPRESSION_INFO;
  69. MI_COMPRESSION_INFO MiCompressionInfo; // LWFIX - temp remove.
  70. PFN_NUMBER MiCompressionOverHeadInPages;
  71. PKDPC MiCompressionDpcArray;
  72. CCHAR MiCompressionProcessors;
  73. VOID
  74. MiCompressionDispatch (
  75. IN PKDPC Dpc,
  76. IN PVOID DeferredContext,
  77. IN PVOID SystemArgument1,
  78. IN PVOID SystemArgument2
  79. );
  80. PVOID
  81. MiMapCompressionInHyperSpace (
  82. IN PFN_NUMBER PageFrameIndex
  83. );
  84. VOID
  85. MiUnmapCompressionInHyperSpace (
  86. VOID
  87. );
  88. SIZE_T
  89. MiMakeCompressibleMemoryAtDispatch (
  90. IN SIZE_T NumberOfBytes OPTIONAL
  91. );
  92. NTSTATUS
  93. MmRegisterCompressionDevice (
  94. IN PMM_COMPRESSION_CONTEXT Context
  95. )
  96. /*++
  97. Routine Description:
  98. This routine notifies memory management that compression hardware exists
  99. in the system. Memory management responds by initializing compression
  100. support here.
  101. Arguments:
  102. Context - Supplies the compression context pointer.
  103. Return Value:
  104. NTSTATUS.
  105. Environment:
  106. Kernel mode, PASSIVE_LEVEL.
  107. --*/
  108. {
  109. KIRQL OldIrql;
  110. PFN_NUMBER OverHeadInPages;
  111. CCHAR Processor;
  112. CCHAR NumberProcessors;
  113. PKDPC CompressionDpcArray;
  114. ASSERT (KeGetCurrentIrql () == PASSIVE_LEVEL);
  115. if (Context->Version != MM_COMPRESSION_VERSION_CURRENT) {
  116. return STATUS_INVALID_PARAMETER_1;
  117. }
  118. if (Context->SizeInBytes < sizeof (MM_COMPRESSION_CONTEXT)) {
  119. return STATUS_INVALID_PARAMETER_1;
  120. }
  121. //
  122. // If the subsequent hot-add cannot succeed then fail this API now.
  123. //
  124. if (MmDynamicPfn == 0) {
  125. return STATUS_NOT_SUPPORTED;
  126. }
  127. //
  128. // Hardware that can't generate a configurable interrupt is not supported.
  129. //
  130. if (Context->SetCompressionThreshold == NULL) {
  131. return STATUS_INVALID_PARAMETER_1;
  132. }
  133. //
  134. // ReservedBytes indicates the number of reserved bytes required by the
  135. // underlying hardware. For example, some hardware might have:
  136. //
  137. // 1. translation tables which are 1/64 of the fictional RAM total.
  138. //
  139. // 2. the first MB of memory is never compressed.
  140. //
  141. // 3. an L3 which is never compressed.
  142. //
  143. // etc.
  144. //
  145. // ReservedBytes would be the sum of all of these types of ranges.
  146. //
  147. OverHeadInPages = (PFN_COUNT)(Context->ReservedBytes / PAGE_SIZE);
  148. if (MmResidentAvailablePages < (SPFN_NUMBER) OverHeadInPages) {
  149. return STATUS_INSUFFICIENT_RESOURCES;
  150. }
  151. if (MmAvailablePages < OverHeadInPages) {
  152. MmEmptyAllWorkingSets ();
  153. if (MmAvailablePages < OverHeadInPages) {
  154. return STATUS_INSUFFICIENT_RESOURCES;
  155. }
  156. }
  157. //
  158. // Create a DPC for every processor in the system as servicing the
  159. // compression interrupt is critical.
  160. //
  161. NumberProcessors = KeNumberProcessors;
  162. CompressionDpcArray = ExAllocatePoolWithTag (NonPagedPool,
  163. NumberProcessors * sizeof (KDPC),
  164. 'pDmM');
  165. if (CompressionDpcArray == NULL) {
  166. return STATUS_INSUFFICIENT_RESOURCES;
  167. }
  168. for (Processor = 0; Processor < NumberProcessors; Processor += 1) {
  169. KeInitializeDpc (CompressionDpcArray + Processor, MiCompressionDispatch, NULL);
  170. //
  171. // Set importance so this DPC always gets queued at the head.
  172. //
  173. KeSetImportanceDpc (CompressionDpcArray + Processor, HighImportance);
  174. KeSetTargetProcessorDpc (CompressionDpcArray + Processor, Processor);
  175. }
  176. LOCK_PFN (OldIrql);
  177. if (MmCompressionThresholdRatio == 0) {
  178. MmCompressionThresholdRatio = MI_DEFAULT_COMPRESSION_THRESHOLD;
  179. }
  180. else if (MmCompressionThresholdRatio > 100) {
  181. MmCompressionThresholdRatio = 100;
  182. }
  183. if ((MmResidentAvailablePages < (SPFN_NUMBER) OverHeadInPages) ||
  184. (MmAvailablePages < OverHeadInPages)) {
  185. UNLOCK_PFN (OldIrql);
  186. ExFreePool (CompressionDpcArray);
  187. return STATUS_INSUFFICIENT_RESOURCES;
  188. }
  189. MI_DECREMENT_RESIDENT_AVAILABLE (OverHeadInPages,
  190. MM_RESAVAIL_ALLOCATE_COMPRESSION);
  191. MmAvailablePages -= (PFN_COUNT) OverHeadInPages;
  192. //
  193. // Signal applications if allocating these pages caused a threshold cross.
  194. //
  195. MiNotifyMemoryEvents ();
  196. //
  197. // Snap our own copy to prevent busted drivers from causing overcommits
  198. // if they deregister improperly.
  199. //
  200. MiCompressionOverHeadInPages += OverHeadInPages;
  201. ASSERT (MiNumberOfCompressionPages == 0);
  202. ASSERT (MiSetCompressionThreshold == NULL);
  203. MiSetCompressionThreshold = Context->SetCompressionThreshold;
  204. if (MiCompressionDpcArray == NULL) {
  205. MiCompressionDpcArray = CompressionDpcArray;
  206. CompressionDpcArray = NULL;
  207. MiCompressionProcessors = NumberProcessors;
  208. }
  209. UNLOCK_PFN (OldIrql);
  210. if (CompressionDpcArray != NULL) {
  211. ExFreePool (CompressionDpcArray);
  212. }
  213. return STATUS_SUCCESS;
  214. }
  215. NTSTATUS
  216. MiArmCompressionInterrupt (
  217. VOID
  218. )
  219. /*++
  220. Routine Description:
  221. This routine arms the hardware-generated compression interrupt.
  222. Arguments:
  223. None.
  224. Return Value:
  225. NTSTATUS.
  226. Environment:
  227. Kernel mode, PFN lock held.
  228. --*/
  229. {
  230. NTSTATUS Status;
  231. PFN_NUMBER RealPages;
  232. ULONGLONG ByteThreshold;
  233. MM_PFN_LOCK_ASSERT();
  234. if (MiSetCompressionThreshold == NULL) {
  235. return STATUS_SUCCESS;
  236. }
  237. RealPages = MmNumberOfPhysicalPages - MiNumberOfCompressionPages - MiCompressionOverHeadInPages;
  238. ByteThreshold = (RealPages * MmCompressionThresholdRatio) / 100;
  239. ByteThreshold *= PAGE_SIZE;
  240. //
  241. // Note this callout is made with the PFN lock held !
  242. //
  243. Status = (*MiSetCompressionThreshold) (ByteThreshold);
  244. if (!NT_SUCCESS (Status)) {
  245. //
  246. // If the hardware fails, all is lost.
  247. //
  248. KeBugCheckEx (MEMORY_MANAGEMENT,
  249. 0x61941,
  250. MmNumberOfPhysicalPages,
  251. RealPages,
  252. MmCompressionThresholdRatio);
  253. }
  254. return Status;
  255. }
  256. NTSTATUS
  257. MmDeregisterCompressionDevice (
  258. IN PMM_COMPRESSION_CONTEXT Context
  259. )
  260. /*++
  261. Routine Description:
  262. This routine notifies memory management that compression hardware is
  263. being removed. Note the compression driver must have already SUCCESSFULLY
  264. called MmRemovePhysicalMemoryEx.
  265. Arguments:
  266. Context - Supplies the compression context pointer.
  267. Return Value:
  268. STATUS_SUCCESS if compression support is initialized properly.
  269. Environment:
  270. Kernel mode, PASSIVE_LEVEL.
  271. --*/
  272. {
  273. KIRQL OldIrql;
  274. PFN_COUNT OverHeadInPages;
  275. ASSERT (KeGetCurrentIrql () == PASSIVE_LEVEL);
  276. OverHeadInPages = (PFN_COUNT)(Context->ReservedBytes / PAGE_SIZE);
  277. LOCK_PFN (OldIrql);
  278. if (OverHeadInPages > MiCompressionOverHeadInPages) {
  279. UNLOCK_PFN (OldIrql);
  280. return STATUS_INVALID_PARAMETER;
  281. }
  282. MmAvailablePages += OverHeadInPages;
  283. //
  284. // Signal applications if allocating these pages caused a threshold cross.
  285. //
  286. MiNotifyMemoryEvents ();
  287. ASSERT (MiCompressionOverHeadInPages == OverHeadInPages);
  288. MiCompressionOverHeadInPages -= OverHeadInPages;
  289. MiSetCompressionThreshold = NULL;
  290. UNLOCK_PFN (OldIrql);
  291. MI_INCREMENT_RESIDENT_AVAILABLE (OverHeadInPages,
  292. MM_RESAVAIL_FREE_COMPRESSION);
  293. return STATUS_SUCCESS;
  294. }
  295. VOID
  296. MiCompressionDispatch (
  297. IN PKDPC Dpc,
  298. IN PVOID DeferredContext,
  299. IN PVOID SystemArgument1,
  300. IN PVOID SystemArgument2
  301. )
  302. /*++
  303. Routine Description:
  304. Called to make memory compressible if the PFN lock could not be
  305. acquired during the original device interrupt.
  306. Arguments:
  307. Dpc - Supplies a pointer to a control object of type DPC.
  308. SystemArgument1 - Supplies the number of bytes to make compressible.
  309. Return Value:
  310. None.
  311. Environment:
  312. Kernel mode. DISPATCH_LEVEL.
  313. --*/
  314. {
  315. SIZE_T NumberOfBytes;
  316. UNREFERENCED_PARAMETER (Dpc);
  317. UNREFERENCED_PARAMETER (DeferredContext);
  318. UNREFERENCED_PARAMETER (SystemArgument2);
  319. NumberOfBytes = (SIZE_T) SystemArgument1;
  320. MiCompressionInfo.DpcsFired += 1;
  321. MiMakeCompressibleMemoryAtDispatch (NumberOfBytes);
  322. }
  323. SIZE_T
  324. MmMakeCompressibleMemory (
  325. IN SIZE_T NumberOfBytes OPTIONAL
  326. )
  327. /*++
  328. Routine Description:
  329. This routine attempts to move pages from transition to zero so that
  330. hardware compression can reclaim the physical memory.
  331. Arguments:
  332. NumberOfBytes - Supplies the number of bytes to make compressible.
  333. Zero indicates as much as possible.
  334. Return Value:
  335. Returns the number of bytes made compressible.
  336. Environment:
  337. Kernel mode. Any IRQL as this is called from device interrupt service
  338. routines.
  339. --*/
  340. {
  341. KIRQL OldIrql;
  342. BOOLEAN Queued;
  343. #if !defined(NT_UP)
  344. PFN_NUMBER PageFrameIndex;
  345. MMLISTS MemoryList;
  346. PMMPFNLIST ListHead;
  347. PMMPFN Pfn1;
  348. CCHAR Processor;
  349. PFN_NUMBER Total;
  350. PVOID ZeroBase;
  351. PKPRCB Prcb;
  352. PFN_NUMBER RequestedPages;
  353. PFN_NUMBER ActualPages;
  354. PKSPIN_LOCK_QUEUE LockQueuePfn;
  355. #endif
  356. //
  357. // LWFIX: interlocked add in the request size above so overlapping
  358. // requests can be processed.
  359. //
  360. OldIrql = KeGetCurrentIrql();
  361. if (OldIrql <= DISPATCH_LEVEL) {
  362. return MiMakeCompressibleMemoryAtDispatch (NumberOfBytes);
  363. }
  364. #if defined(NT_UP)
  365. //
  366. // In uniprocessor configurations, there is no indication as to the PFN lock
  367. // is owned because the uniprocessor kernel macros these into merely IRQL
  368. // raises. Therefore this routine must be conservative when called above
  369. // DISPATCH_LEVEL and assume the lock is owned and just always queue
  370. // a DPC in these cases.
  371. //
  372. Queued = KeInsertQueueDpc (MiCompressionDpcArray,
  373. (PVOID) NumberOfBytes,
  374. NULL);
  375. if (Queued == TRUE) {
  376. MiCompressionInfo.PfnForcedDpcInsert += 1;
  377. }
  378. else {
  379. MiCompressionInfo.PfnFailedDpcInsert += 1;
  380. }
  381. return 0;
  382. #else
  383. #if DBG
  384. //
  385. // Make sure this interrupt always comes in at the same device IRQL.
  386. //
  387. ASSERT ((MiCompressionIrql == 0) || (OldIrql == MiCompressionIrql));
  388. MiCompressionIrql = OldIrql;
  389. #endif
  390. Prcb = KeGetCurrentPrcb();
  391. RequestedPages = NumberOfBytes >> PAGE_SHIFT;
  392. ActualPages = 0;
  393. MemoryList = FreePageList;
  394. ListHead = MmPageLocationList[MemoryList];
  395. LockQueuePfn = &Prcb->LockQueue[LockQueuePfnLock];
  396. if (KeTryToAcquireQueuedSpinLockAtRaisedIrql (LockQueuePfn) == FALSE) {
  397. //
  398. // Unable to acquire the spinlock, queue a DPC to pick it up instead.
  399. //
  400. for (Processor = 0; Processor < MiCompressionProcessors; Processor += 1) {
  401. Queued = KeInsertQueueDpc (MiCompressionDpcArray + Processor,
  402. (PVOID) NumberOfBytes,
  403. NULL);
  404. if (Queued == TRUE) {
  405. MiCompressionInfo.PfnForcedDpcInsert += 1;
  406. }
  407. else {
  408. MiCompressionInfo.PfnFailedDpcInsert += 1;
  409. }
  410. }
  411. return 0;
  412. }
  413. MiCompressionInfo.IsrRan += 1;
  414. //
  415. // Run the free and transition list and zero the pages.
  416. //
  417. while (MemoryList <= StandbyPageList) {
  418. Total = ListHead->Total;
  419. PageFrameIndex = ListHead->Flink;
  420. while (Total != 0) {
  421. //
  422. // Transition pages may need restoration which requires a
  423. // hyperspace mapping plus control area deletion actions all of
  424. // which occur at DISPATCH_LEVEL. So if we're at device IRQL,
  425. // only do the minimum and queue the rest.
  426. //
  427. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  428. if ((Pfn1->u3.e1.InPageError == 1) &&
  429. (Pfn1->u3.e1.ReadInProgress == 1)) {
  430. //
  431. // This page is already zeroed so skip it.
  432. //
  433. MiCompressionInfo.IsrSkippedZeroedPage += 1;
  434. }
  435. else {
  436. //
  437. // Zero the page directly now instead of waiting for the low
  438. // priority zeropage thread to get a slice. Note that the
  439. // slower mapping and zeroing routines are used here because
  440. // the faster ones are for the zeropage thread only.
  441. // Maybe we should change this someday.
  442. //
  443. ZeroBase = MiMapCompressionInHyperSpace (PageFrameIndex);
  444. KeZeroPages (ZeroBase, PAGE_SIZE);
  445. MiUnmapCompressionInHyperSpace ();
  446. ASSERT (Pfn1->u3.e2.ReferenceCount == 0);
  447. //
  448. // Overload ReadInProgress to signify that collided faults that
  449. // occur before the PTE is completely restored will know to
  450. // delay and retry until the page (and PTE) are updated.
  451. //
  452. Pfn1->u3.e1.InPageError = 1;
  453. ASSERT (Pfn1->u3.e1.ReadInProgress == 0);
  454. Pfn1->u3.e1.ReadInProgress = 1;
  455. ActualPages += 1;
  456. if (ActualPages == RequestedPages) {
  457. MemoryList = StandbyPageList;
  458. ListHead = MmPageLocationList[MemoryList];
  459. break;
  460. }
  461. }
  462. Total -= 1;
  463. PageFrameIndex = Pfn1->u1.Flink;
  464. }
  465. MemoryList += 1;
  466. ListHead += 1;
  467. }
  468. if (ActualPages != 0) {
  469. //
  470. // Rearm the interrupt as pages have now been zeroed.
  471. //
  472. MiArmCompressionInterrupt ();
  473. }
  474. KeReleaseQueuedSpinLockFromDpcLevel (LockQueuePfn);
  475. if (ActualPages != 0) {
  476. //
  477. // Pages were zeroed - queue a DPC to the current processor to
  478. // move them to the zero list. Note this is not critical path so
  479. // don't bother sending a DPC to every processor for this case.
  480. //
  481. MiCompressionInfo.IsrPageProcessed += (ULONG)ActualPages;
  482. Processor = (CCHAR) KeGetCurrentProcessorNumber ();
  483. //
  484. // Ensure a hot-added processor scenario just works.
  485. //
  486. if (Processor >= MiCompressionProcessors) {
  487. Processor = MiCompressionProcessors;
  488. }
  489. Queued = KeInsertQueueDpc (MiCompressionDpcArray + Processor,
  490. (PVOID) NumberOfBytes,
  491. NULL);
  492. if (Queued == TRUE) {
  493. MiCompressionInfo.IsrForcedDpc += 1;
  494. }
  495. else {
  496. MiCompressionInfo.IsrFailedDpc += 1;
  497. }
  498. }
  499. return (ActualPages << PAGE_SHIFT);
  500. #endif
  501. }
  502. SIZE_T
  503. MiMakeCompressibleMemoryAtDispatch (
  504. IN SIZE_T NumberOfBytes OPTIONAL
  505. )
  506. /*++
  507. Routine Description:
  508. This routine attempts to move pages from transition to zero so that
  509. hardware compression can reclaim the physical memory.
  510. Arguments:
  511. NumberOfBytes - Supplies the number of bytes to make compressible.
  512. Zero indicates as much as possible.
  513. Return Value:
  514. Returns the number of bytes made compressible.
  515. Environment:
  516. Kernel mode. DISPATCH_LEVEL.
  517. --*/
  518. {
  519. KIRQL OldIrql;
  520. PFN_NUMBER PageFrameIndex;
  521. PFN_NUMBER PageFrameIndex2;
  522. PVOID ZeroBase;
  523. PMMPFN Pfn1;
  524. MMLISTS MemoryList;
  525. PMMPFNLIST ListHead;
  526. PFN_NUMBER RequestedPages;
  527. PFN_NUMBER ActualPages;
  528. LOGICAL NeedToZero;
  529. ASSERT (KeGetCurrentIrql () == DISPATCH_LEVEL);
  530. RequestedPages = NumberOfBytes >> PAGE_SHIFT;
  531. ActualPages = 0;
  532. MemoryList = FreePageList;
  533. ListHead = MmPageLocationList[MemoryList];
  534. MiCompressionInfo.DpcRan += 1;
  535. LOCK_PFN2 (OldIrql);
  536. //
  537. // Run the free and transition list and zero the pages.
  538. //
  539. while (MemoryList <= StandbyPageList) {
  540. while (ListHead->Total != 0) {
  541. //
  542. // Before removing the page from the head of the list (which will
  543. // zero the flag bits), snap whether it's been zeroed by our ISR
  544. // or whether we need to zero it here.
  545. //
  546. PageFrameIndex = ListHead->Flink;
  547. Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
  548. NeedToZero = TRUE;
  549. if ((Pfn1->u3.e1.InPageError == 1) && (Pfn1->u3.e1.ReadInProgress == 1)) {
  550. MiCompressionInfo.DpcSkippedZeroedPage += 1;
  551. NeedToZero = FALSE;
  552. }
  553. //
  554. // Transition pages may need restoration which requires a
  555. // hyperspace mapping plus control area deletion actions all of
  556. // which occur at DISPATCH_LEVEL. Since we're at DISPATCH_LEVEL
  557. // now, go ahead and do it.
  558. //
  559. PageFrameIndex2 = MiRemovePageFromList (ListHead);
  560. ASSERT (PageFrameIndex == PageFrameIndex2);
  561. //
  562. // Zero the page directly now instead of waiting for the low
  563. // priority zeropage thread to get a slice. Note that the
  564. // slower mapping and zeroing routines are used here because
  565. // the faster ones are for the zeropage thread only.
  566. // Maybe we should change this someday.
  567. //
  568. if (NeedToZero == TRUE) {
  569. ZeroBase = MiMapCompressionInHyperSpace (PageFrameIndex);
  570. KeZeroPages (ZeroBase, PAGE_SIZE);
  571. MiUnmapCompressionInHyperSpace ();
  572. }
  573. ASSERT (Pfn1->u2.ShareCount == 0);
  574. ASSERT (Pfn1->u3.e2.ReferenceCount == 0);
  575. MiInsertPageInList (&MmZeroedPageListHead, PageFrameIndex);
  576. //
  577. // We have changed (zeroed) the contents of this page.
  578. // If memory mirroring is in progress, the bitmap must be updated.
  579. //
  580. if (MiMirroringActive == TRUE) {
  581. RtlSetBit (MiMirrorBitMap2, (ULONG)PageFrameIndex);
  582. }
  583. MiCompressionInfo.DpcPageProcessed += 1;
  584. ActualPages += 1;
  585. if (ActualPages == RequestedPages) {
  586. MemoryList = StandbyPageList;
  587. ListHead = MmPageLocationList[MemoryList];
  588. break;
  589. }
  590. }
  591. MemoryList += 1;
  592. ListHead += 1;
  593. }
  594. //
  595. // Rearm the interrupt as pages have now been zeroed.
  596. //
  597. MiArmCompressionInterrupt ();
  598. UNLOCK_PFN2 (OldIrql);
  599. return (ActualPages << PAGE_SHIFT);
  600. }
  601. PVOID
  602. MiMapCompressionInHyperSpace (
  603. IN PFN_NUMBER PageFrameIndex
  604. )
  605. /*++
  606. Routine Description:
  607. This procedure maps the specified physical page into the
  608. PTE within hyper space reserved explicitly for compression page
  609. mapping.
  610. The PTE is guaranteed to always be available since the PFN lock is held.
  611. Arguments:
  612. PageFrameIndex - Supplies the physical page number to map.
  613. Return Value:
  614. Returns the virtual address where the specified physical page was
  615. mapped.
  616. Environment:
  617. Kernel mode, PFN lock held, any IRQL.
  618. --*/
  619. {
  620. MMPTE TempPte;
  621. PMMPTE PointerPte;
  622. PVOID FlushVaPointer;
  623. ASSERT (PageFrameIndex != 0);
  624. TempPte = ValidPtePte;
  625. TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
  626. FlushVaPointer = (PVOID) (ULONG_PTR) COMPRESSION_MAPPING_PTE;
  627. //
  628. // Ensure both modified and accessed bits are set so the hardware doesn't
  629. // ever write this PTE.
  630. //
  631. ASSERT (TempPte.u.Hard.Dirty == 1);
  632. ASSERT (TempPte.u.Hard.Accessed == 1);
  633. PointerPte = MiGetPteAddress (COMPRESSION_MAPPING_PTE);
  634. ASSERT (PointerPte->u.Long == 0);
  635. //
  636. // Only flush the TB on the current processor as no context switch can
  637. // occur while using this mapping.
  638. //
  639. MI_WRITE_VALID_PTE (PointerPte, TempPte);
  640. KeFlushSingleTb (FlushVaPointer, FALSE);
  641. return (PVOID) MiGetVirtualAddressMappedByPte (PointerPte);
  642. }
  643. __forceinline
  644. VOID
  645. MiUnmapCompressionInHyperSpace (
  646. VOID
  647. )
  648. /*++
  649. Routine Description:
  650. This procedure unmaps the PTE reserved for mapping the compression page.
  651. Arguments:
  652. None.
  653. Return Value:
  654. None.
  655. Environment:
  656. Kernel mode, PFN lock held, any IRQL.
  657. --*/
  658. {
  659. PMMPTE PointerPte;
  660. PointerPte = MiGetPteAddress (COMPRESSION_MAPPING_PTE);
  661. //
  662. // Capture the number of waiters.
  663. //
  664. ASSERT (PointerPte->u.Long != 0);
  665. MI_WRITE_INVALID_PTE (PointerPte, ZeroPte);
  666. return;
  667. }
  668. #else
  669. NTSTATUS
  670. MmRegisterCompressionDevice (
  671. IN PMM_COMPRESSION_CONTEXT Context
  672. )
  673. {
  674. UNREFERENCED_PARAMETER (Context);
  675. return STATUS_NOT_SUPPORTED;
  676. }
  677. NTSTATUS
  678. MmDeregisterCompressionDevice (
  679. IN PMM_COMPRESSION_CONTEXT Context
  680. )
  681. {
  682. UNREFERENCED_PARAMETER (Context);
  683. return STATUS_NOT_SUPPORTED;
  684. }
  685. SIZE_T
  686. MmMakeCompressibleMemory (
  687. IN SIZE_T NumberOfBytes OPTIONAL
  688. )
  689. {
  690. UNREFERENCED_PARAMETER (NumberOfBytes);
  691. return 0;
  692. }
  693. NTSTATUS
  694. MiArmCompressionInterrupt (
  695. VOID
  696. )
  697. {
  698. return STATUS_NOT_SUPPORTED;
  699. }
  700. #endif
  701. #endif