Merge from amd64-branch:
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / pfnlist.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/pfnlist.c
5 * PURPOSE: ARM Memory Manager PFN List Manipulation
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #line 15 "ARMĀ³::PFNLIST"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 /* GLOBALS ********************************************************************/
20
21 MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD};
22 MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD};
23 MMPFNLIST MmStandbyPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
24 MMPFNLIST MmModifiedPageListHead = {0, ModifiedPageList, LIST_HEAD, LIST_HEAD};
25 MMPFNLIST MmModifiedNoWritePageListHead = {0, ModifiedNoWritePageList, LIST_HEAD, LIST_HEAD};
26 MMPFNLIST MmBadPageListHead = {0, BadPageList, LIST_HEAD, LIST_HEAD};
27 MMPFNLIST MmRomPageListHead = {0, StandbyPageList, LIST_HEAD, LIST_HEAD};
28
29 PMMPFNLIST MmPageLocationList[] =
30 {
31 &MmZeroedPageListHead,
32 &MmFreePageListHead,
33 &MmStandbyPageListHead,
34 &MmModifiedPageListHead,
35 &MmModifiedNoWritePageListHead,
36 &MmBadPageListHead,
37 NULL,
38 NULL
39 };
40 /* FUNCTIONS ******************************************************************/
41
42 VOID
43 NTAPI
44 MiInsertInListTail(IN PMMPFNLIST ListHead,
45 IN PMMPFN Entry)
46 {
47 PFN_NUMBER OldBlink, EntryIndex = MiGetPfnEntryIndex(Entry);
48
49 /* Get the back link */
50 OldBlink = ListHead->Blink;
51 if (OldBlink != LIST_HEAD)
52 {
53 /* Set the back pointer to point to us now */
54 MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
55 }
56 else
57 {
58 /* Set the list to point to us */
59 ListHead->Flink = EntryIndex;
60 }
61
62 /* Set the entry to point to the list head forwards, and the old page backwards */
63 Entry->u1.Flink = LIST_HEAD;
64 Entry->u2.Blink = OldBlink;
65
66 /* And now the head points back to us, since we are last */
67 ListHead->Blink = EntryIndex;
68 ListHead->Total++;
69 }
70
71 VOID
72 NTAPI
73 MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex)
74 {
75 PFN_NUMBER OldBlink;
76 PMMPFNLIST ListHead;
77 PMMPFN Pfn1;
78 #if 0
79 PMMPFN Blink;
80 ULONG Color;
81 PMMCOLOR_TABLES ColorHead;
82 #endif
83
84 /* Make sure the PFN lock is held */
85 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
86
87 /* Get the descriptor */
88 Pfn1 = MiGetPfnEntry(EntryIndex);
89 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
90 ASSERT(Pfn1->u4.MustBeCached == 0);
91 ASSERT(Pfn1->u3.e1.Rom == 0);
92 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
93 ASSERT(Pfn1->u4.InPageError == 0);
94
95 /* Use the zero list */
96 ListHead = &MmZeroedPageListHead;
97 ListHead->Total++;
98
99 /* Get the back link */
100 OldBlink = ListHead->Blink;
101 if (OldBlink != LIST_HEAD)
102 {
103 /* Set the back pointer to point to us now */
104 MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
105 }
106 else
107 {
108 /* Set the list to point to us */
109 ListHead->Flink = EntryIndex;
110 }
111
112 /* Set the entry to point to the list head forwards, and the old page backwards */
113 Pfn1->u1.Flink = LIST_HEAD;
114 Pfn1->u2.Blink = OldBlink;
115
116 /* And now the head points back to us, since we are last */
117 ListHead->Blink = EntryIndex;
118
119 /* Update the page location */
120 Pfn1->u3.e1.PageLocation = ZeroedPageList;
121
122 /* FIXME: NOT YET Due to caller semantics: Update the available page count */
123 //MmAvailablePages++;
124
125 /* Check if we've reached the configured low memory threshold */
126 if (MmAvailablePages == MmLowMemoryThreshold)
127 {
128 /* Clear the event, because now we're ABOVE the threshold */
129 KeClearEvent(MiLowMemoryEvent);
130 }
131 else if (MmAvailablePages == MmHighMemoryThreshold)
132 {
133 /* Otherwise check if we reached the high threshold and signal the event */
134 KeSetEvent(MiHighMemoryEvent, 0, FALSE);
135 }
136 #if 0
137 /* Get the page color */
138 Color = EntryIndex & MmSecondaryColorMask;
139
140 /* Get the first page on the color list */
141 ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
142 if (ColorHead->Flink == LIST_HEAD)
143 {
144 /* The list is empty, so we are the first page */
145 Pfn1->u4.PteFrame = -1;
146 ColorHead->Flink = EntryIndex;
147 }
148 else
149 {
150 /* Get the previous page */
151 Blink = (PMMPFN)ColorHead->Blink;
152
153 /* Make it link to us */
154 Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
155 Blink->OriginalPte.u.Long = EntryIndex;
156 }
157
158 /* Now initialize our own list pointers */
159 ColorHead->Blink = Pfn1;
160 Pfn1->OriginalPte.u.Long = LIST_HEAD;
161
162 /* And increase the count in the colored list */
163 ColorHead->Count++;
164 #endif
165 }
166
167 VOID
168 NTAPI
169 MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry)
170 {
171 PFN_NUMBER OldFlink, OldBlink;
172 PMMPFNLIST ListHead;
173 MMLISTS ListName;
174
175 /* Make sure the PFN lock is held */
176 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
177
178 /* Make sure the PFN entry isn't in-use */
179 ASSERT(Entry->u3.e1.WriteInProgress == 0);
180 ASSERT(Entry->u3.e1.ReadInProgress == 0);
181
182 /* Find the list for this entry, make sure it's the free or zero list */
183 ListHead = MmPageLocationList[Entry->u3.e1.PageLocation];
184 ListName = ListHead->ListName;
185 ASSERT(ListHead != NULL);
186 ASSERT(ListName <= FreePageList);
187
188 /* Remove one count */
189 ASSERT(ListHead->Total != 0);
190 ListHead->Total--;
191
192 /* Get the forward and back pointers */
193 OldFlink = Entry->u1.Flink;
194 OldBlink = Entry->u2.Blink;
195
196 /* Check if the next entry is the list head */
197 if (OldFlink != LIST_HEAD)
198 {
199 /* It is not, so set the backlink of the actual entry, to our backlink */
200 MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
201 }
202 else
203 {
204 /* Set the list head's backlink instead */
205 ListHead->Blink = OldFlink;
206 }
207
208 /* Check if the back entry is the list head */
209 if (OldBlink != LIST_HEAD)
210 {
211 /* It is not, so set the backlink of the actual entry, to our backlink */
212 MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
213 }
214 else
215 {
216 /* Set the list head's backlink instead */
217 ListHead->Flink = OldFlink;
218 }
219
220 /* We are not on a list anymore */
221 Entry->u1.Flink = Entry->u2.Blink = 0;
222
223 /* FIXME: Deal with color list */
224
225 /* See if we hit any thresholds */
226 if (MmAvailablePages == MmHighMemoryThreshold)
227 {
228 /* Clear the high memory event */
229 KeClearEvent(MiHighMemoryEvent);
230 }
231 else if (MmAvailablePages == MmLowMemoryThreshold)
232 {
233 /* Signal the low memory event */
234 KeSetEvent(MiLowMemoryEvent, 0, FALSE);
235 }
236
237 /* One less page */
238 if (--MmAvailablePages < MmMinimumFreePages)
239 {
240 /* FIXME: Should wake up the MPW and working set manager, if we had one */
241 }
242 }
243
244 PMMPFN
245 NTAPI
246 MiRemoveHeadList(IN PMMPFNLIST ListHead)
247 {
248 PFN_NUMBER Entry, Flink;
249 PMMPFN Pfn1;
250
251 /* Get the entry that's currently first on the list */
252 Entry = ListHead->Flink;
253 Pfn1 = MiGetPfnEntry(Entry);
254
255 /* Make the list point to the entry following the first one */
256 Flink = Pfn1->u1.Flink;
257 ListHead->Flink = Flink;
258
259 /* Check if the next entry is actually the list head */
260 if (ListHead->Flink != LIST_HEAD)
261 {
262 /* It isn't, so therefore whoever is coming next points back to the head */
263 MiGetPfnEntry(Flink)->u2.Blink = LIST_HEAD;
264 }
265 else
266 {
267 /* Then the list is empty, so the backlink should point back to us */
268 ListHead->Blink = LIST_HEAD;
269 }
270
271 /* We are not on a list anymore */
272 Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
273 ListHead->Total--;
274
275 /* Return the head element */
276 return Pfn1;
277 }
278
279 VOID
280 NTAPI
281 MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
282 {
283 PMMPFNLIST ListHead;
284 PFN_NUMBER LastPage;
285 PMMPFN Pfn1, Blink;
286 ULONG Color;
287 PMMCOLOR_TABLES ColorHead;
288
289 /* Make sure the page index is valid */
290 ASSERT((PageFrameIndex != 0) &&
291 (PageFrameIndex <= MmHighestPhysicalPage) &&
292 (PageFrameIndex >= MmLowestPhysicalPage));
293
294 /* Get the PFN entry */
295 Pfn1 = MI_PFN_TO_PFNENTRY(PageFrameIndex);
296
297 /* Sanity checks that a right kind of page is being inserted here */
298 ASSERT(Pfn1->u4.MustBeCached == 0);
299 ASSERT(Pfn1->u3.e1.Rom != 1);
300 ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
301 ASSERT(Pfn1->u4.VerifierAllocation == 0);
302 ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
303
304 /* Get the free page list and increment its count */
305 ListHead = &MmFreePageListHead;
306 ListHead->Total++;
307
308 /* Get the last page on the list */
309 LastPage = ListHead->Blink;
310 if (LastPage != LIST_HEAD)
311 {
312 /* Link us with the previous page, so we're at the end now */
313 MI_PFN_TO_PFNENTRY(LastPage)->u1.Flink = PageFrameIndex;
314 }
315 else
316 {
317 /* The list is empty, so we are the first page */
318 ListHead->Flink = PageFrameIndex;
319 }
320
321 /* Now make the list head point back to us (since we go at the end) */
322 ListHead->Blink = PageFrameIndex;
323
324 /* And initialize our own list pointers */
325 Pfn1->u1.Flink = LIST_HEAD;
326 Pfn1->u2.Blink = LastPage;
327
328 /* Set the list name and default priority */
329 Pfn1->u3.e1.PageLocation = FreePageList;
330 Pfn1->u4.Priority = 3;
331
332 /* Clear some status fields */
333 Pfn1->u4.InPageError = 0;
334 Pfn1->u4.AweAllocation = 0;
335
336 /* Not yet until we switch to this */
337 //MmAvailablePages++;
338
339 /* Check if we've reached the configured low memory threshold */
340 if (MmAvailablePages == MmLowMemoryThreshold)
341 {
342 /* Clear the event, because now we're ABOVE the threshold */
343 KeClearEvent(MiLowMemoryEvent);
344 }
345 else if (MmAvailablePages == MmHighMemoryThreshold)
346 {
347 /* Otherwise check if we reached the high threshold and signal the event */
348 KeSetEvent(MiHighMemoryEvent, 0, FALSE);
349 }
350
351 /* Get the page color */
352 Color = PageFrameIndex & MmSecondaryColorMask;
353
354 /* Get the first page on the color list */
355 ColorHead = &MmFreePagesByColor[FreePageList][Color];
356 if (ColorHead->Flink == LIST_HEAD)
357 {
358 /* The list is empty, so we are the first page */
359 Pfn1->u4.PteFrame = -1;
360 ColorHead->Flink = PageFrameIndex;
361 }
362 else
363 {
364 /* Get the previous page */
365 Blink = (PMMPFN)ColorHead->Blink;
366
367 /* Make it link to us */
368 Pfn1->u4.PteFrame = MI_PFNENTRY_TO_PFN(Blink);
369 Blink->OriginalPte.u.Long = PageFrameIndex;
370 }
371
372 /* Now initialize our own list pointers */
373 ColorHead->Blink = Pfn1;
374 Pfn1->OriginalPte.u.Long = LIST_HEAD;
375
376 /* And increase the count in the colored list */
377 ColorHead->Count++;
378
379 /* FIXME: Notify zero page thread if enough pages are on the free list now */
380 }
381
382 /* EOF */