Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpfnlist.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/mm/ARM3/pfnlist.c 00005 * PURPOSE: ARM Memory Manager PFN List Manipulation 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 #define MODULE_INVOLVED_IN_ARM3 00016 #include "../ARM3/miarm.h" 00017 00018 #if DBG 00019 #define ASSERT_LIST_INVARIANT(x) \ 00020 do { \ 00021 ASSERT(((x)->Total == 0 && \ 00022 (x)->Flink == LIST_HEAD && \ 00023 (x)->Blink == LIST_HEAD) || \ 00024 ((x)->Total != 0 && \ 00025 (x)->Flink != LIST_HEAD && \ 00026 (x)->Blink != LIST_HEAD)); \ 00027 } while (0) 00028 #else 00029 #define ASSERT_LIST_INVARIANT(x) 00030 #endif 00031 00032 /* GLOBALS ********************************************************************/ 00033 00034 BOOLEAN MmDynamicPfn; 00035 BOOLEAN MmMirroring; 00036 ULONG MmSystemPageColor; 00037 00038 ULONG MmTransitionSharedPages; 00039 ULONG MmTotalPagesForPagingFile; 00040 00041 MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD}; 00042 MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD}; 00043 MMPFNLIST MmStandbyPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD}; 00044 MMPFNLIST MmStandbyPageListByPriority[8]; 00045 MMPFNLIST MmModifiedPageListHead = {0, ModifiedPageList, LIST_HEAD, LIST_HEAD}; 00046 MMPFNLIST MmModifiedPageListByColor[1] = {{0, ModifiedPageList, LIST_HEAD, LIST_HEAD}}; 00047 MMPFNLIST MmModifiedNoWritePageListHead = {0, ModifiedNoWritePageList, LIST_HEAD, LIST_HEAD}; 00048 MMPFNLIST MmBadPageListHead = {0, BadPageList, LIST_HEAD, LIST_HEAD}; 00049 MMPFNLIST MmRomPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD}; 00050 00051 PMMPFNLIST MmPageLocationList[] = 00052 { 00053 &MmZeroedPageListHead, 00054 &MmFreePageListHead, 00055 &MmStandbyPageListHead, 00056 &MmModifiedPageListHead, 00057 &MmModifiedNoWritePageListHead, 00058 &MmBadPageListHead, 00059 NULL, 00060 NULL 00061 }; 00062 00063 ULONG MI_PFN_CURRENT_USAGE; 00064 CHAR MI_PFN_CURRENT_PROCESS_NAME[16] = "None yet"; 00065 00066 /* FUNCTIONS ******************************************************************/ 00067 00068 VOID 00069 NTAPI 00070 MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex) 00071 { 00072 KIRQL OldIrql; 00073 PVOID VirtualAddress; 00074 PEPROCESS Process = PsGetCurrentProcess(); 00075 00076 /* Map in hyperspace, then wipe it using XMMI or MEMSET */ 00077 VirtualAddress = MiMapPageInHyperSpace(Process, PageFrameIndex, &OldIrql); 00078 ASSERT(VirtualAddress); 00079 KeZeroPages(VirtualAddress, PAGE_SIZE); 00080 MiUnmapPageInHyperSpace(Process, VirtualAddress, OldIrql); 00081 } 00082 00083 VOID 00084 NTAPI 00085 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry) 00086 { 00087 PFN_NUMBER OldFlink, OldBlink; 00088 PMMPFNLIST ListHead; 00089 MMLISTS ListName; 00090 ULONG Color; 00091 PMMCOLOR_TABLES ColorTable; 00092 PMMPFN Pfn1; 00093 00094 /* Make sure the PFN lock is held */ 00095 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00096 00097 /* Make sure the PFN entry isn't in-use */ 00098 ASSERT(Entry->u3.e1.WriteInProgress == 0); 00099 ASSERT(Entry->u3.e1.ReadInProgress == 0); 00100 00101 /* Find the list for this entry, make sure it's the free or zero list */ 00102 ListHead = MmPageLocationList[Entry->u3.e1.PageLocation]; 00103 ListName = ListHead->ListName; 00104 ASSERT(ListHead != NULL); 00105 ASSERT(ListName <= FreePageList); 00106 ASSERT_LIST_INVARIANT(ListHead); 00107 00108 /* Remove one count */ 00109 ASSERT(ListHead->Total != 0); 00110 ListHead->Total--; 00111 00112 /* Get the forward and back pointers */ 00113 OldFlink = Entry->u1.Flink; 00114 OldBlink = Entry->u2.Blink; 00115 00116 /* Check if the next entry is the list head */ 00117 if (OldFlink != LIST_HEAD) 00118 { 00119 /* It is not, so set the backlink of the actual entry, to our backlink */ 00120 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink; 00121 } 00122 else 00123 { 00124 /* Set the list head's backlink instead */ 00125 ListHead->Blink = OldBlink; 00126 } 00127 00128 /* Check if the back entry is the list head */ 00129 if (OldBlink != LIST_HEAD) 00130 { 00131 /* It is not, so set the backlink of the actual entry, to our backlink */ 00132 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink; 00133 } 00134 else 00135 { 00136 /* Set the list head's backlink instead */ 00137 ListHead->Flink = OldFlink; 00138 } 00139 00140 /* Get the page color */ 00141 OldBlink = MiGetPfnEntryIndex(Entry); 00142 Color = OldBlink & MmSecondaryColorMask; 00143 00144 /* Get the first page on the color list */ 00145 ColorTable = &MmFreePagesByColor[ListName][Color]; 00146 00147 /* Check if this was was actually the head */ 00148 OldFlink = ColorTable->Flink; 00149 if (OldFlink == OldBlink) 00150 { 00151 /* Make the table point to the next page this page was linking to */ 00152 ColorTable->Flink = Entry->OriginalPte.u.Long; 00153 if (ColorTable->Flink != LIST_HEAD) 00154 { 00155 /* And make the previous link point to the head now */ 00156 MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD; 00157 } 00158 else 00159 { 00160 /* And if that page was the head, loop the list back around */ 00161 ColorTable->Blink = (PVOID)LIST_HEAD; 00162 } 00163 } 00164 else 00165 { 00166 /* This page shouldn't be pointing back to the head */ 00167 ASSERT(Entry->u4.PteFrame != COLORED_LIST_HEAD); 00168 00169 /* Make the back link point to whoever the next page is */ 00170 Pfn1 = MI_PFN_ELEMENT(Entry->u4.PteFrame); 00171 Pfn1->OriginalPte.u.Long = Entry->OriginalPte.u.Long; 00172 00173 /* Check if this page was pointing to the head */ 00174 if (Entry->OriginalPte.u.Long != LIST_HEAD) 00175 { 00176 /* Make the back link point to the head */ 00177 Pfn1 = MI_PFN_ELEMENT(Entry->OriginalPte.u.Long); 00178 Pfn1->u4.PteFrame = Entry->u4.PteFrame; 00179 } 00180 else 00181 { 00182 /* Then the table is directly back pointing to this page now */ 00183 ColorTable->Blink = Pfn1; 00184 } 00185 } 00186 00187 /* One less colored page */ 00188 ASSERT(ColorTable->Count >= 1); 00189 ColorTable->Count--; 00190 00191 /* ReactOS Hack */ 00192 Entry->OriginalPte.u.Long = 0; 00193 00194 /* We are not on a list anymore */ 00195 Entry->u1.Flink = Entry->u2.Blink = 0; 00196 ASSERT_LIST_INVARIANT(ListHead); 00197 00198 /* See if we hit any thresholds */ 00199 if (MmAvailablePages == MmHighMemoryThreshold) 00200 { 00201 /* Clear the high memory event */ 00202 KeClearEvent(MiHighMemoryEvent); 00203 } 00204 else if (MmAvailablePages == MmLowMemoryThreshold) 00205 { 00206 /* Signal the low memory event */ 00207 KeSetEvent(MiLowMemoryEvent, 0, FALSE); 00208 } 00209 00210 /* One less page */ 00211 if (--MmAvailablePages < MmMinimumFreePages) 00212 { 00213 /* FIXME: Should wake up the MPW and working set manager, if we had one */ 00214 00215 DPRINT1("Running low on pages: %d remaining\n", MmAvailablePages); 00216 00217 /* Call RosMm and see if it can release any pages for us */ 00218 MmRebalanceMemoryConsumers(); 00219 } 00220 00221 #if MI_TRACE_PFNS 00222 ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET); 00223 Entry->PfnUsage = MI_PFN_CURRENT_USAGE; 00224 memcpy(Entry->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16); 00225 // MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET; 00226 // memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16); 00227 #endif 00228 } 00229 00230 VOID 00231 NTAPI 00232 MiUnlinkPageFromList(IN PMMPFN Pfn) 00233 { 00234 PMMPFNLIST ListHead; 00235 PFN_NUMBER OldFlink, OldBlink; 00236 00237 /* Make sure the PFN lock is held */ 00238 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00239 00240 /* ARM3 should only call this for dead pages */ 00241 ASSERT(Pfn->u3.e2.ReferenceCount == 0); 00242 00243 /* Transition pages are supposed to be standby/modified/nowrite */ 00244 ListHead = MmPageLocationList[Pfn->u3.e1.PageLocation]; 00245 ASSERT(ListHead->ListName >= StandbyPageList); 00246 00247 /* Check if this was standby, or modified */ 00248 if (ListHead == &MmStandbyPageListHead) 00249 { 00250 /* Should not be a ROM page */ 00251 ASSERT(Pfn->u3.e1.Rom == 0); 00252 00253 /* Get the exact list */ 00254 ListHead = &MmStandbyPageListByPriority[Pfn->u4.Priority]; 00255 00256 /* See if we hit any thresholds */ 00257 if (MmAvailablePages == MmHighMemoryThreshold) 00258 { 00259 /* Clear the high memory event */ 00260 KeClearEvent(MiHighMemoryEvent); 00261 } 00262 else if (MmAvailablePages == MmLowMemoryThreshold) 00263 { 00264 /* Signal the low memory event */ 00265 KeSetEvent(MiLowMemoryEvent, 0, FALSE); 00266 } 00267 00268 /* Decrease transition page counter */ 00269 ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */ 00270 MmTransitionSharedPages--; 00271 00272 /* One less page */ 00273 if (--MmAvailablePages < MmMinimumFreePages) 00274 { 00275 /* FIXME: Should wake up the MPW and working set manager, if we had one */ 00276 DPRINT1("Running low on pages: %d remaining\n", MmAvailablePages); 00277 00278 /* Call RosMm and see if it can release any pages for us */ 00279 MmRebalanceMemoryConsumers(); 00280 } 00281 } 00282 else if (ListHead == &MmModifiedPageListHead) 00283 { 00284 /* Only shared memory (page-file backed) modified pages are supported */ 00285 ASSERT(Pfn->OriginalPte.u.Soft.Prototype == 0); 00286 00287 /* Decrement the counters */ 00288 ListHead->Total--; 00289 MmTotalPagesForPagingFile--; 00290 00291 /* Pick the correct colored list */ 00292 ListHead = &MmModifiedPageListByColor[0]; 00293 00294 /* Decrease transition page counter */ 00295 ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */ 00296 MmTransitionSharedPages--; 00297 } 00298 else if (ListHead == &MmModifiedNoWritePageListHead) 00299 { 00300 /* List not yet supported */ 00301 ASSERT(FALSE); 00302 } 00303 00304 /* Nothing should be in progress and the list should not be empty */ 00305 ASSERT(Pfn->u3.e1.WriteInProgress == 0); 00306 ASSERT(Pfn->u3.e1.ReadInProgress == 0); 00307 ASSERT(ListHead->Total != 0); 00308 00309 /* Get the forward and back pointers */ 00310 OldFlink = Pfn->u1.Flink; 00311 OldBlink = Pfn->u2.Blink; 00312 00313 /* Check if the next entry is the list head */ 00314 if (OldFlink != LIST_HEAD) 00315 { 00316 /* It is not, so set the backlink of the actual entry, to our backlink */ 00317 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink; 00318 } 00319 else 00320 { 00321 /* Set the list head's backlink instead */ 00322 ListHead->Blink = OldBlink; 00323 } 00324 00325 /* Check if the back entry is the list head */ 00326 if (OldBlink != LIST_HEAD) 00327 { 00328 /* It is not, so set the backlink of the actual entry, to our backlink */ 00329 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink; 00330 } 00331 else 00332 { 00333 /* Set the list head's backlink instead */ 00334 ListHead->Flink = OldFlink; 00335 } 00336 00337 /* ReactOS Hack */ 00338 Pfn->OriginalPte.u.Long = 0; 00339 00340 /* We are not on a list anymore */ 00341 Pfn->u1.Flink = Pfn->u2.Blink = 0; 00342 ASSERT_LIST_INVARIANT(ListHead); 00343 00344 /* Remove one entry from the list */ 00345 ListHead->Total--; 00346 } 00347 00348 PFN_NUMBER 00349 NTAPI 00350 MiRemovePageByColor(IN PFN_NUMBER PageIndex, 00351 IN ULONG Color) 00352 { 00353 PMMPFN Pfn1; 00354 PMMPFNLIST ListHead; 00355 MMLISTS ListName; 00356 PFN_NUMBER OldFlink, OldBlink; 00357 USHORT OldColor, OldCache; 00358 PMMCOLOR_TABLES ColorTable; 00359 00360 /* Make sure PFN lock is held */ 00361 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00362 ASSERT(Color < MmSecondaryColors); 00363 00364 /* Get the PFN entry */ 00365 Pfn1 = MI_PFN_ELEMENT(PageIndex); 00366 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 00367 ASSERT(Pfn1->u3.e1.Rom == 0); 00368 00369 /* Capture data for later */ 00370 OldColor = Pfn1->u3.e1.PageColor; 00371 OldCache = Pfn1->u3.e1.CacheAttribute; 00372 00373 /* Could be either on free or zero list */ 00374 ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation]; 00375 ASSERT_LIST_INVARIANT(ListHead); 00376 ListName = ListHead->ListName; 00377 ASSERT(ListName <= FreePageList); 00378 00379 /* Remove a page */ 00380 ListHead->Total--; 00381 00382 /* Get the forward and back pointers */ 00383 OldFlink = Pfn1->u1.Flink; 00384 OldBlink = Pfn1->u2.Blink; 00385 00386 /* Check if the next entry is the list head */ 00387 if (OldFlink != LIST_HEAD) 00388 { 00389 /* It is not, so set the backlink of the actual entry, to our backlink */ 00390 MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink; 00391 } 00392 else 00393 { 00394 /* Set the list head's backlink instead */ 00395 ListHead->Blink = OldBlink; 00396 } 00397 00398 /* Check if the back entry is the list head */ 00399 if (OldBlink != LIST_HEAD) 00400 { 00401 /* It is not, so set the backlink of the actual entry, to our backlink */ 00402 MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink; 00403 } 00404 else 00405 { 00406 /* Set the list head's backlink instead */ 00407 ListHead->Flink = OldFlink; 00408 } 00409 00410 /* We are not on a list anymore */ 00411 ASSERT_LIST_INVARIANT(ListHead); 00412 Pfn1->u1.Flink = Pfn1->u2.Blink = 0; 00413 00414 /* Zero flags but restore color and cache */ 00415 Pfn1->u3.e2.ShortFlags = 0; 00416 Pfn1->u3.e1.PageColor = OldColor; 00417 Pfn1->u3.e1.CacheAttribute = OldCache; 00418 00419 /* Get the first page on the color list */ 00420 ASSERT(Color < MmSecondaryColors); 00421 ColorTable = &MmFreePagesByColor[ListName][Color]; 00422 ASSERT(ColorTable->Count >= 1); 00423 00424 /* Set the forward link to whoever we were pointing to */ 00425 ColorTable->Flink = Pfn1->OriginalPte.u.Long; 00426 00427 /* Get the first page on the color list */ 00428 if (ColorTable->Flink == LIST_HEAD) 00429 { 00430 /* This is the beginning of the list, so set the sentinel value */ 00431 ColorTable->Blink = (PVOID)LIST_HEAD; 00432 } 00433 else 00434 { 00435 /* The list is empty, so we are the first page */ 00436 MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD; 00437 } 00438 00439 /* One less page */ 00440 ColorTable->Count--; 00441 00442 /* ReactOS Hack */ 00443 Pfn1->OriginalPte.u.Long = 0; 00444 00445 /* See if we hit any thresholds */ 00446 if (MmAvailablePages == MmHighMemoryThreshold) 00447 { 00448 /* Clear the high memory event */ 00449 KeClearEvent(MiHighMemoryEvent); 00450 } 00451 else if (MmAvailablePages == MmLowMemoryThreshold) 00452 { 00453 /* Signal the low memory event */ 00454 KeSetEvent(MiLowMemoryEvent, 0, FALSE); 00455 } 00456 00457 /* One less page */ 00458 if (--MmAvailablePages < MmMinimumFreePages) 00459 { 00460 /* FIXME: Should wake up the MPW and working set manager, if we had one */ 00461 00462 DPRINT1("Running low on pages: %d remaining\n", MmAvailablePages); 00463 00464 /* Call RosMm and see if it can release any pages for us */ 00465 MmRebalanceMemoryConsumers(); 00466 } 00467 00468 #if MI_TRACE_PFNS 00469 //ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET); 00470 Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE; 00471 memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16); 00472 //MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET; 00473 //memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16); 00474 #endif 00475 00476 /* Return the page */ 00477 return PageIndex; 00478 } 00479 00480 PFN_NUMBER 00481 NTAPI 00482 MiRemoveAnyPage(IN ULONG Color) 00483 { 00484 PFN_NUMBER PageIndex; 00485 PMMPFN Pfn1; 00486 00487 /* Make sure PFN lock is held and we have pages */ 00488 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00489 ASSERT(MmAvailablePages != 0); 00490 ASSERT(Color < MmSecondaryColors); 00491 00492 /* Check the colored free list */ 00493 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink; 00494 if (PageIndex == LIST_HEAD) 00495 { 00496 /* Check the colored zero list */ 00497 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink; 00498 if (PageIndex == LIST_HEAD) 00499 { 00500 /* Check the free list */ 00501 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 00502 PageIndex = MmFreePageListHead.Flink; 00503 Color = PageIndex & MmSecondaryColorMask; 00504 if (PageIndex == LIST_HEAD) 00505 { 00506 /* Check the zero list */ 00507 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 00508 PageIndex = MmZeroedPageListHead.Flink; 00509 Color = PageIndex & MmSecondaryColorMask; 00510 ASSERT(PageIndex != LIST_HEAD); 00511 if (PageIndex == LIST_HEAD) 00512 { 00513 /* FIXME: Should check the standby list */ 00514 ASSERT(MmZeroedPageListHead.Total == 0); 00515 } 00516 } 00517 } 00518 } 00519 00520 /* Remove the page from its list */ 00521 PageIndex = MiRemovePageByColor(PageIndex, Color); 00522 00523 /* Sanity checks */ 00524 Pfn1 = MI_PFN_ELEMENT(PageIndex); 00525 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) || 00526 (Pfn1->u3.e1.PageLocation == ZeroedPageList)); 00527 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 00528 ASSERT(Pfn1->u2.ShareCount == 0); 00529 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 00530 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 00531 00532 /* Return the page */ 00533 return PageIndex; 00534 } 00535 00536 PFN_NUMBER 00537 NTAPI 00538 MiRemoveZeroPage(IN ULONG Color) 00539 { 00540 PFN_NUMBER PageIndex; 00541 PMMPFN Pfn1; 00542 BOOLEAN Zero = FALSE; 00543 00544 /* Make sure PFN lock is held and we have pages */ 00545 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00546 ASSERT(MmAvailablePages != 0); 00547 ASSERT(Color < MmSecondaryColors); 00548 00549 /* Check the colored zero list */ 00550 PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink; 00551 if (PageIndex == LIST_HEAD) 00552 { 00553 /* Check the zero list */ 00554 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 00555 PageIndex = MmZeroedPageListHead.Flink; 00556 if (PageIndex == LIST_HEAD) 00557 { 00558 /* This means there's no zero pages, we have to look for free ones */ 00559 ASSERT(MmZeroedPageListHead.Total == 0); 00560 Zero = TRUE; 00561 00562 /* Check the colored free list */ 00563 PageIndex = MmFreePagesByColor[FreePageList][Color].Flink; 00564 if (PageIndex == LIST_HEAD) 00565 { 00566 /* Check the free list */ 00567 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 00568 PageIndex = MmFreePageListHead.Flink; 00569 Color = PageIndex & MmSecondaryColorMask; 00570 ASSERT(PageIndex != LIST_HEAD); 00571 if (PageIndex == LIST_HEAD) 00572 { 00573 /* FIXME: Should check the standby list */ 00574 ASSERT(MmZeroedPageListHead.Total == 0); 00575 } 00576 } 00577 } 00578 else 00579 { 00580 Color = PageIndex & MmSecondaryColorMask; 00581 } 00582 } 00583 00584 /* Sanity checks */ 00585 Pfn1 = MI_PFN_ELEMENT(PageIndex); 00586 ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) || 00587 (Pfn1->u3.e1.PageLocation == ZeroedPageList)); 00588 00589 /* Remove the page from its list */ 00590 PageIndex = MiRemovePageByColor(PageIndex, Color); 00591 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex)); 00592 00593 /* Zero it, if needed */ 00594 if (Zero) MiZeroPhysicalPage(PageIndex); 00595 00596 /* Sanity checks */ 00597 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 00598 ASSERT(Pfn1->u2.ShareCount == 0); 00599 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 00600 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 00601 00602 /* Return the page */ 00603 return PageIndex; 00604 } 00605 00606 VOID 00607 NTAPI 00608 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex) 00609 { 00610 PMMPFNLIST ListHead; 00611 PFN_NUMBER LastPage; 00612 PMMPFN Pfn1; 00613 ULONG Color; 00614 PMMPFN Blink; 00615 PMMCOLOR_TABLES ColorTable; 00616 00617 /* Make sure the page index is valid */ 00618 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); 00619 ASSERT((PageFrameIndex != 0) && 00620 (PageFrameIndex <= MmHighestPhysicalPage) && 00621 (PageFrameIndex >= MmLowestPhysicalPage)); 00622 00623 /* Get the PFN entry */ 00624 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 00625 00626 /* Sanity checks that a right kind of page is being inserted here */ 00627 ASSERT(Pfn1->u4.MustBeCached == 0); 00628 ASSERT(Pfn1->u3.e1.Rom != 1); 00629 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 00630 ASSERT(Pfn1->u4.VerifierAllocation == 0); 00631 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 00632 00633 /* Get the free page list and increment its count */ 00634 ListHead = &MmFreePageListHead; 00635 ASSERT_LIST_INVARIANT(ListHead); 00636 ListHead->Total++; 00637 00638 /* Get the last page on the list */ 00639 LastPage = ListHead->Blink; 00640 if (LastPage != LIST_HEAD) 00641 { 00642 /* Link us with the previous page, so we're at the end now */ 00643 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex; 00644 } 00645 else 00646 { 00647 /* The list is empty, so we are the first page */ 00648 ListHead->Flink = PageFrameIndex; 00649 } 00650 00651 /* Now make the list head point back to us (since we go at the end) */ 00652 ListHead->Blink = PageFrameIndex; 00653 ASSERT_LIST_INVARIANT(ListHead); 00654 00655 /* And initialize our own list pointers */ 00656 Pfn1->u1.Flink = LIST_HEAD; 00657 Pfn1->u2.Blink = LastPage; 00658 00659 /* Set the list name and default priority */ 00660 Pfn1->u3.e1.PageLocation = FreePageList; 00661 Pfn1->u4.Priority = 3; 00662 00663 /* Clear some status fields */ 00664 Pfn1->u4.InPageError = 0; 00665 Pfn1->u4.AweAllocation = 0; 00666 00667 /* Increase available pages */ 00668 MmAvailablePages++; 00669 00670 /* Check if we've reached the configured low memory threshold */ 00671 if (MmAvailablePages == MmLowMemoryThreshold) 00672 { 00673 /* Clear the event, because now we're ABOVE the threshold */ 00674 KeClearEvent(MiLowMemoryEvent); 00675 } 00676 else if (MmAvailablePages == MmHighMemoryThreshold) 00677 { 00678 /* Otherwise check if we reached the high threshold and signal the event */ 00679 KeSetEvent(MiHighMemoryEvent, 0, FALSE); 00680 } 00681 00682 /* Get the page color */ 00683 Color = PageFrameIndex & MmSecondaryColorMask; 00684 00685 /* Get the first page on the color list */ 00686 ColorTable = &MmFreePagesByColor[FreePageList][Color]; 00687 if (ColorTable->Flink == LIST_HEAD) 00688 { 00689 /* The list is empty, so we are the first page */ 00690 Pfn1->u4.PteFrame = COLORED_LIST_HEAD; 00691 ColorTable->Flink = PageFrameIndex; 00692 } 00693 else 00694 { 00695 /* Get the previous page */ 00696 Blink = (PMMPFN)ColorTable->Blink; 00697 00698 /* Make it link to us, and link back to it */ 00699 Blink->OriginalPte.u.Long = PageFrameIndex; 00700 Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink); 00701 } 00702 00703 /* Now initialize our own list pointers */ 00704 ColorTable->Blink = Pfn1; 00705 00706 /* This page is now the last */ 00707 Pfn1->OriginalPte.u.Long = LIST_HEAD; 00708 00709 /* And increase the count in the colored list */ 00710 ColorTable->Count++; 00711 00712 /* Notify zero page thread if enough pages are on the free list now */ 00713 if ((ListHead->Total >= 8) && !(MmZeroingPageThreadActive)) 00714 { 00715 /* Set the event */ 00716 MmZeroingPageThreadActive = TRUE; 00717 KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE); 00718 } 00719 00720 #if MI_TRACE_PFNS 00721 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE; 00722 RtlZeroMemory(Pfn1->ProcessName, 16); 00723 #endif 00724 } 00725 00726 VOID 00727 FASTCALL 00728 MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex) 00729 { 00730 PMMPFNLIST ListHead; 00731 PFN_NUMBER Flink; 00732 PMMPFN Pfn1, Pfn2; 00733 00734 /* Make sure the lock is held */ 00735 DPRINT1("Inserting page: %lx into standby list !\n", PageFrameIndex); 00736 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00737 00738 /* Make sure the PFN is valid */ 00739 ASSERT((PageFrameIndex != 0) && 00740 (PageFrameIndex <= MmHighestPhysicalPage) && 00741 (PageFrameIndex >= MmLowestPhysicalPage)); 00742 00743 /* Grab the PFN and validate it is the right kind of PFN being inserted */ 00744 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 00745 ASSERT(Pfn1->u4.MustBeCached == 0); 00746 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 00747 ASSERT(Pfn1->u3.e1.PrototypePte == 1); 00748 ASSERT(Pfn1->u3.e1.Rom != 1); 00749 00750 /* One more transition page on a list */ 00751 MmTransitionSharedPages++; 00752 00753 /* Get the standby page list and increment its count */ 00754 ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority]; 00755 ASSERT_LIST_INVARIANT(ListHead); 00756 ListHead->Total++; 00757 00758 /* Make the head of the list point to this page now */ 00759 Flink = ListHead->Flink; 00760 ListHead->Flink = PageFrameIndex; 00761 00762 /* Make the page point to the previous head, and back to the list */ 00763 Pfn1->u1.Flink = Flink; 00764 Pfn1->u2.Blink = LIST_HEAD; 00765 00766 /* Was the list empty? */ 00767 if (Flink != LIST_HEAD) 00768 { 00769 /* It wasn't, so update the backlink of the previous head page */ 00770 Pfn2 = MI_PFN_ELEMENT(Flink); 00771 Pfn2->u2.Blink = PageFrameIndex; 00772 } 00773 else 00774 { 00775 /* It was empty, so have it loop back around to this new page */ 00776 ListHead->Blink = PageFrameIndex; 00777 } 00778 00779 /* Move the page onto its new location */ 00780 Pfn1->u3.e1.PageLocation = StandbyPageList; 00781 00782 /* One more page on the system */ 00783 MmAvailablePages++; 00784 00785 /* Check if we've reached the configured low memory threshold */ 00786 if (MmAvailablePages == MmLowMemoryThreshold) 00787 { 00788 /* Clear the event, because now we're ABOVE the threshold */ 00789 KeClearEvent(MiLowMemoryEvent); 00790 } 00791 else if (MmAvailablePages == MmHighMemoryThreshold) 00792 { 00793 /* Otherwise check if we reached the high threshold and signal the event */ 00794 KeSetEvent(MiHighMemoryEvent, 0, FALSE); 00795 } 00796 } 00797 00798 VOID 00799 NTAPI 00800 MiInsertPageInList(IN PMMPFNLIST ListHead, 00801 IN PFN_NUMBER PageFrameIndex) 00802 { 00803 PFN_NUMBER Flink, LastPage; 00804 PMMPFN Pfn1, Pfn2; 00805 MMLISTS ListName; 00806 PMMCOLOR_TABLES ColorHead; 00807 ULONG Color; 00808 00809 /* For free pages, use MiInsertPageInFreeList */ 00810 ASSERT(ListHead != &MmFreePageListHead); 00811 00812 /* Make sure the lock is held */ 00813 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00814 00815 /* Make sure the PFN is valid */ 00816 ASSERT((PageFrameIndex) && 00817 (PageFrameIndex <= MmHighestPhysicalPage) && 00818 (PageFrameIndex >= MmLowestPhysicalPage)); 00819 00820 /* Page should be unused */ 00821 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 00822 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 00823 ASSERT(Pfn1->u3.e1.Rom != 1); 00824 00825 /* Is a standby or modified page being inserted? */ 00826 ListName = ListHead->ListName; 00827 if ((ListName == StandbyPageList) || (ListName == ModifiedPageList)) 00828 { 00829 /* If the page is in transition, it must also be a prototype page */ 00830 if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) && 00831 (Pfn1->OriginalPte.u.Soft.Transition == 1)) 00832 { 00833 /* Crash the system on inconsistency */ 00834 KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0); 00835 } 00836 } 00837 00838 /* Standby pages are prioritized, so we need to get the real head */ 00839 if (ListHead == &MmStandbyPageListHead) 00840 { 00841 /* Obviously the prioritized list should still have the same name */ 00842 ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority]; 00843 ASSERT(ListHead->ListName == ListName); 00844 } 00845 00846 /* Increment the list count */ 00847 ListHead->Total++; 00848 00849 /* Is a modified page being inserted? */ 00850 if (ListHead == &MmModifiedPageListHead) 00851 { 00852 /* For now, only single-prototype pages should end up in this path */ 00853 DPRINT1("Modified page being added: %lx\n", PageFrameIndex); 00854 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 00855 00856 /* Modified pages are colored when they are selected for page file */ 00857 ListHead = &MmModifiedPageListByColor[0]; 00858 ASSERT (ListHead->ListName == ListName); 00859 ListHead->Total++; 00860 00861 /* Increment the number of paging file modified pages */ 00862 MmTotalPagesForPagingFile++; 00863 } 00864 00865 /* Don't handle bad pages yet yet */ 00866 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 00867 00868 /* Zero pages go to the head, all other pages go to the end */ 00869 if (ListName == ZeroedPageList) 00870 { 00871 /* Make the head of the list point to this page now */ 00872 Flink = ListHead->Flink; 00873 ListHead->Flink = PageFrameIndex; 00874 00875 /* Make the page point to the previous head, and back to the list */ 00876 Pfn1->u1.Flink = Flink; 00877 Pfn1->u2.Blink = LIST_HEAD; 00878 00879 /* Was the list empty? */ 00880 if (Flink != LIST_HEAD) 00881 { 00882 /* It wasn't, so update the backlink of the previous head page */ 00883 Pfn2 = MI_PFN_ELEMENT(Flink); 00884 Pfn2->u2.Blink = PageFrameIndex; 00885 } 00886 else 00887 { 00888 /* It was empty, so have it loop back around to this new page */ 00889 ListHead->Blink = PageFrameIndex; 00890 } 00891 } 00892 else 00893 { 00894 /* Get the last page on the list */ 00895 LastPage = ListHead->Blink; 00896 if (LastPage != LIST_HEAD) 00897 { 00898 /* Link us with the previous page, so we're at the end now */ 00899 MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex; 00900 } 00901 else 00902 { 00903 /* The list is empty, so we are the first page */ 00904 ListHead->Flink = PageFrameIndex; 00905 } 00906 00907 /* Now make the list head point back to us (since we go at the end) */ 00908 ListHead->Blink = PageFrameIndex; 00909 ASSERT_LIST_INVARIANT(ListHead); 00910 00911 /* And initialize our own list pointers */ 00912 Pfn1->u1.Flink = LIST_HEAD; 00913 Pfn1->u2.Blink = LastPage; 00914 } 00915 00916 /* Move the page onto its new location */ 00917 Pfn1->u3.e1.PageLocation = ListName; 00918 00919 /* For zero/free pages, we also have to handle the colored lists */ 00920 if (ListName <= StandbyPageList) 00921 { 00922 /* One more page on the system */ 00923 MmAvailablePages++; 00924 00925 /* Check if we've reached the configured low memory threshold */ 00926 if (MmAvailablePages == MmLowMemoryThreshold) 00927 { 00928 /* Clear the event, because now we're ABOVE the threshold */ 00929 KeClearEvent(MiLowMemoryEvent); 00930 } 00931 else if (MmAvailablePages == MmHighMemoryThreshold) 00932 { 00933 /* Otherwise check if we reached the high threshold and signal the event */ 00934 KeSetEvent(MiHighMemoryEvent, 0, FALSE); 00935 } 00936 00937 /* Sanity checks */ 00938 ASSERT(ListName == ZeroedPageList); 00939 ASSERT(Pfn1->u4.InPageError == 0); 00940 00941 /* Get the page color */ 00942 Color = PageFrameIndex & MmSecondaryColorMask; 00943 00944 /* Get the list for this color */ 00945 ColorHead = &MmFreePagesByColor[ZeroedPageList][Color]; 00946 00947 /* Get the old head */ 00948 Flink = ColorHead->Flink; 00949 00950 /* Make this page point back to the list, and point forwards to the old head */ 00951 Pfn1->OriginalPte.u.Long = Flink; 00952 Pfn1->u4.PteFrame = COLORED_LIST_HEAD; 00953 00954 /* Set the new head */ 00955 ColorHead->Flink = PageFrameIndex; 00956 00957 /* Was the head empty? */ 00958 if (Flink != LIST_HEAD) 00959 { 00960 /* No, so make the old head point to this page */ 00961 Pfn2 = MI_PFN_ELEMENT(Flink); 00962 Pfn2->u4.PteFrame = PageFrameIndex; 00963 } 00964 else 00965 { 00966 /* Yes, make it loop back to this page */ 00967 ColorHead->Blink = (PVOID)Pfn1; 00968 } 00969 00970 /* One more paged on the colored list */ 00971 ColorHead->Count++; 00972 00973 #if MI_TRACE_PFNS 00974 //ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET); 00975 Pfn1->PfnUsage = MI_USAGE_FREE_PAGE; 00976 MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET; 00977 RtlZeroMemory(Pfn1->ProcessName, 16); 00978 #endif 00979 } 00980 else if (ListName == ModifiedPageList) 00981 { 00982 /* In ARM3, page must be destined for page file, and not yet written out */ 00983 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 00984 ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0); 00985 00986 /* One more transition page */ 00987 ASSERT(Pfn1->u3.e1.PrototypePte == 1); 00988 MmTransitionSharedPages++; 00989 00990 /* Increment the number of per-process modified pages */ 00991 PsGetCurrentProcess()->ModifiedPageCount++; 00992 00993 /* FIXME: Wake up modified page writer if there are not enough free pages */ 00994 } 00995 else if (ListName == ModifiedNoWritePageList) 00996 { 00997 /* This list is not yet implemented */ 00998 ASSERT(FALSE); 00999 } 01000 } 01001 01002 VOID 01003 NTAPI 01004 MiInitializePfn(IN PFN_NUMBER PageFrameIndex, 01005 IN PMMPTE PointerPte, 01006 IN BOOLEAN Modified) 01007 { 01008 PMMPFN Pfn1; 01009 NTSTATUS Status; 01010 PMMPTE PointerPtePte; 01011 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 01012 01013 /* Setup the PTE */ 01014 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 01015 Pfn1->PteAddress = PointerPte; 01016 01017 /* Check if this PFN is part of a valid address space */ 01018 if (PointerPte->u.Hard.Valid == 1) 01019 { 01020 /* Only valid from MmCreateProcessAddressSpace path */ 01021 ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0); 01022 01023 /* Make this a demand zero PTE */ 01024 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE); 01025 } 01026 else 01027 { 01028 /* Copy the PTE data */ 01029 Pfn1->OriginalPte = *PointerPte; 01030 ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) && 01031 (Pfn1->OriginalPte.u.Soft.Transition == 1))); 01032 } 01033 01034 /* Otherwise this is a fresh page -- set it up */ 01035 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 01036 Pfn1->u3.e2.ReferenceCount = 1; 01037 Pfn1->u2.ShareCount = 1; 01038 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01039 ASSERT(Pfn1->u3.e1.Rom == 0); 01040 Pfn1->u3.e1.Modified = Modified; 01041 01042 /* Get the page table for the PTE */ 01043 PointerPtePte = MiAddressToPte(PointerPte); 01044 if (PointerPtePte->u.Hard.Valid == 0) 01045 { 01046 /* Make sure the PDE gets paged in properly */ 01047 Status = MiCheckPdeForPagedPool(PointerPte); 01048 if (!NT_SUCCESS(Status)) 01049 { 01050 /* Crash */ 01051 KeBugCheckEx(MEMORY_MANAGEMENT, 01052 0x61940, 01053 (ULONG_PTR)PointerPte, 01054 (ULONG_PTR)PointerPtePte->u.Long, 01055 (ULONG_PTR)MiPteToAddress(PointerPte)); 01056 } 01057 } 01058 01059 /* Get the PFN for the page table */ 01060 PageFrameIndex = PFN_FROM_PTE(PointerPtePte); 01061 ASSERT(PageFrameIndex != 0); 01062 Pfn1->u4.PteFrame = PageFrameIndex; 01063 01064 /* Increase its share count so we don't get rid of it */ 01065 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 01066 Pfn1->u2.ShareCount++; 01067 } 01068 01069 VOID 01070 NTAPI 01071 MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex, 01072 IN PMMPTE PointerPte, 01073 IN MMPTE TempPte) 01074 { 01075 PMMPFN Pfn1; 01076 NTSTATUS Status; 01077 PMMPTE PointerPtePte; 01078 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 01079 01080 /* PTE must be invalid */ 01081 ASSERT(PointerPte->u.Hard.Valid == 0); 01082 01083 /* Setup the PTE */ 01084 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 01085 Pfn1->PteAddress = PointerPte; 01086 Pfn1->OriginalPte = DemandZeroPte; 01087 01088 /* Otherwise this is a fresh page -- set it up */ 01089 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 01090 Pfn1->u3.e2.ReferenceCount++; 01091 Pfn1->u2.ShareCount++; 01092 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01093 ASSERT(Pfn1->u3.e1.Rom == 0); 01094 Pfn1->u3.e1.Modified = 1; 01095 01096 /* Get the page table for the PTE */ 01097 PointerPtePte = MiAddressToPte(PointerPte); 01098 if (PointerPtePte->u.Hard.Valid == 0) 01099 { 01100 /* Make sure the PDE gets paged in properly */ 01101 Status = MiCheckPdeForPagedPool(PointerPte); 01102 if (!NT_SUCCESS(Status)) 01103 { 01104 /* Crash */ 01105 KeBugCheckEx(MEMORY_MANAGEMENT, 01106 0x61940, 01107 (ULONG_PTR)PointerPte, 01108 (ULONG_PTR)PointerPtePte->u.Long, 01109 (ULONG_PTR)MiPteToAddress(PointerPte)); 01110 } 01111 } 01112 01113 /* Get the PFN for the page table */ 01114 PageFrameIndex = PFN_FROM_PTE(PointerPtePte); 01115 ASSERT(PageFrameIndex != 0); 01116 Pfn1->u4.PteFrame = PageFrameIndex; 01117 01118 /* Increase its share count so we don't get rid of it */ 01119 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 01120 Pfn1->u2.ShareCount++; 01121 01122 /* Write valid PTE */ 01123 MI_WRITE_VALID_PTE(PointerPte, TempPte); 01124 } 01125 01126 01127 PFN_NUMBER 01128 NTAPI 01129 MiAllocatePfn(IN PMMPTE PointerPte, 01130 IN ULONG Protection) 01131 { 01132 KIRQL OldIrql; 01133 PFN_NUMBER PageFrameIndex; 01134 MMPTE TempPte; 01135 01136 /* Sanity check that we aren't passed a valid PTE */ 01137 ASSERT(PointerPte->u.Hard.Valid == 0); 01138 01139 /* Make an empty software PTE */ 01140 MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE); 01141 01142 /* Lock the PFN database */ 01143 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 01144 01145 /* Check if we're running low on pages */ 01146 if (MmAvailablePages < 128) 01147 { 01148 DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages); 01149 01150 //MiEnsureAvailablePageOrWait(NULL, OldIrql); 01151 01152 /* Call RosMm and see if it can release any pages for us */ 01153 MmRebalanceMemoryConsumers(); 01154 } 01155 01156 /* Grab a page */ 01157 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 01158 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 01159 PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); 01160 01161 /* Write the software PTE */ 01162 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 01163 PointerPte->u.Soft.Protection |= Protection; 01164 01165 /* Initialize its PFN entry */ 01166 MiInitializePfn(PageFrameIndex, PointerPte, TRUE); 01167 01168 /* Release the PFN lock and return the page */ 01169 ASSERT_LIST_INVARIANT(&MmFreePageListHead); 01170 ASSERT_LIST_INVARIANT(&MmZeroedPageListHead); 01171 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01172 return PageFrameIndex; 01173 } 01174 01175 VOID 01176 NTAPI 01177 MiDecrementShareCount(IN PMMPFN Pfn1, 01178 IN PFN_NUMBER PageFrameIndex) 01179 { 01180 PMMPTE PointerPte; 01181 MMPTE TempPte; 01182 01183 ASSERT(PageFrameIndex > 0); 01184 ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL); 01185 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex)); 01186 ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE); 01187 01188 /* Page must be in-use */ 01189 if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) && 01190 (Pfn1->u3.e1.PageLocation != StandbyPageList)) 01191 { 01192 /* Otherwise we have PFN corruption */ 01193 KeBugCheckEx(PFN_LIST_CORRUPT, 01194 0x99, 01195 PageFrameIndex, 01196 Pfn1->u3.e1.PageLocation, 01197 0); 01198 } 01199 01200 /* Check if the share count is now 0 */ 01201 ASSERT(Pfn1->u2.ShareCount < 0xF000000); 01202 if (!--Pfn1->u2.ShareCount) 01203 { 01204 /* Was this a prototype PTE? */ 01205 if (Pfn1->u3.e1.PrototypePte) 01206 { 01207 /* Grab the PTE address and make sure it's in prototype pool */ 01208 PointerPte = Pfn1->PteAddress; 01209 ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd)); 01210 01211 /* The PTE that backs it should also be valdi */ 01212 PointerPte = MiAddressToPte(PointerPte); 01213 ASSERT(PointerPte->u.Hard.Valid == 1); 01214 01215 /* Get the original prototype PTE and turn it into a transition PTE */ 01216 PointerPte = Pfn1->PteAddress; 01217 TempPte = *PointerPte; 01218 TempPte.u.Soft.Transition = 1; 01219 TempPte.u.Soft.Valid = 0; 01220 TempPte.u.Soft.Prototype = 0; 01221 TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection; 01222 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 01223 DPRINT1("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1)); 01224 } 01225 01226 /* Put the page in transition */ 01227 Pfn1->u3.e1.PageLocation = TransitionPage; 01228 01229 /* PFN lock must be held */ 01230 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 01231 01232 /* Page should at least have one reference */ 01233 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 01234 if (Pfn1->u3.e2.ReferenceCount == 1) 01235 { 01236 /* Is there still a PFN for this page? */ 01237 if (MI_IS_PFN_DELETED(Pfn1) == TRUE) 01238 { 01239 /* Clear the last reference */ 01240 Pfn1->u3.e2.ReferenceCount = 0; 01241 ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0); 01242 01243 /* Mark the page temporarily as valid, we're going to make it free soon */ 01244 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01245 01246 /* Bring it back into the free list */ 01247 MiInsertPageInFreeList(PageFrameIndex); 01248 } 01249 else 01250 { 01251 /* PFN not yet deleted, drop a ref count */ 01252 MiDecrementReferenceCount(Pfn1, PageFrameIndex); 01253 } 01254 } 01255 else 01256 { 01257 /* Otherwise, just drop the reference count */ 01258 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 01259 } 01260 } 01261 } 01262 01263 VOID 01264 NTAPI 01265 MiDecrementReferenceCount(IN PMMPFN Pfn1, 01266 IN PFN_NUMBER PageFrameIndex) 01267 { 01268 /* PFN lock must be held */ 01269 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 01270 01271 /* Sanity checks on the page */ 01272 ASSERT(PageFrameIndex < MmHighestPhysicalPage); 01273 ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex)); 01274 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 01275 01276 /* Dereference the page, bail out if it's still alive */ 01277 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 01278 if (Pfn1->u3.e2.ReferenceCount) return; 01279 01280 /* Nobody should still have reference to this page */ 01281 if (Pfn1->u2.ShareCount != 0) 01282 { 01283 /* Otherwise something's really wrong */ 01284 KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0); 01285 } 01286 01287 /* And it should be lying on some page list */ 01288 ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid); 01289 01290 /* Did someone set the delete flag? */ 01291 if (MI_IS_PFN_DELETED(Pfn1)) 01292 { 01293 /* Insert it into the free list, there's nothing left to do */ 01294 MiInsertPageInFreeList(PageFrameIndex); 01295 return; 01296 } 01297 01298 /* Check to see which list this page should go into */ 01299 ASSERT(FALSE); 01300 if (Pfn1->u3.e1.Modified == 1) 01301 { 01302 /* Push it into the modified page list */ 01303 MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex); 01304 } 01305 else 01306 { 01307 /* Otherwise, insert this page into the standby list */ 01308 ASSERT(Pfn1->u3.e1.RemovalRequested == 0); 01309 MiInsertStandbyListAtFront(PageFrameIndex); 01310 } 01311 } 01312 01313 VOID 01314 NTAPI 01315 MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex, 01316 IN PMMPTE PointerPte, 01317 IN PFN_NUMBER PteFrame) 01318 { 01319 PMMPFN Pfn1; 01320 01321 /* Setup the PTE */ 01322 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 01323 Pfn1->PteAddress = PointerPte; 01324 01325 /* Make this a software PTE */ 01326 MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE); 01327 01328 /* Setup the page */ 01329 ASSERT(Pfn1->u3.e2.ReferenceCount == 0); 01330 Pfn1->u3.e2.ReferenceCount = 1; 01331 Pfn1->u2.ShareCount = 1; 01332 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01333 Pfn1->u3.e1.Modified = TRUE; 01334 Pfn1->u4.InPageError = FALSE; 01335 01336 /* Did we get a PFN for the page table */ 01337 if (PteFrame) 01338 { 01339 /* Store it */ 01340 Pfn1->u4.PteFrame = PteFrame; 01341 01342 /* Increase its share count so we don't get rid of it */ 01343 Pfn1 = MI_PFN_ELEMENT(PteFrame); 01344 Pfn1->u2.ShareCount++; 01345 } 01346 } 01347 01348 /* EOF */ Generated on Sun May 27 2012 04:37:34 for ReactOS by
1.7.6.1
|