ae4ddce3f1e8e0683181b11ef93cfcf70312133c
[reactos.git] / reactos / ntoskrnl / mm / freelist.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/freelist.c
5 * PURPOSE: Handle the list of free physical pages
6 * PROGRAMMER: David Welch (welch@cwcom.net)
7 * UPDATE HISTORY:
8 * 27/05/98: Created
9 * 18/08/98: Added a fix from Robert Bergkvist
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <internal/stddef.h>
15 #include <ddk/ntddk.h>
16 #include <internal/mm.h>
17 #include <internal/mmhal.h>
18 #include <internal/ntoskrnl.h>
19 #include <internal/bitops.h>
20 #include <internal/i386/io.h>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 /* TYPES *******************************************************************/
26
27 #define PHYSICAL_PAGE_FREE (0x1)
28 #define PHYSICAL_PAGE_INUSE (0x2)
29 #define PHYSICAL_PAGE_BIOS (0x4)
30
31 typedef struct _PHYSICAL_PAGE
32 {
33 ULONG Flags;
34 LIST_ENTRY ListEntry;
35 } PHYSICAL_PAGE, *PPHYSICAL_PAGE;
36
37 /* GLOBALS ****************************************************************/
38
39 static PPHYSICAL_PAGE MmPageArray;
40
41 static LIST_ENTRY UsedPageListHead;
42 static KSPIN_LOCK UsedPageListLock;
43 static LIST_ENTRY FreePageListHead;
44 static KSPIN_LOCK FreePageListLock;
45 static LIST_ENTRY BiosPageListHead;
46 static KSPIN_LOCK BiosPageListLock;
47
48 ULONG MiNrFreePages;
49 ULONG MiNrUsedPages;
50
51 /* FUNCTIONS *************************************************************/
52
53 PVOID MmInitializePageList(PVOID FirstPhysKernelAddress,
54 PVOID LastPhysKernelAddress,
55 ULONG MemorySizeInPages,
56 ULONG LastKernelAddress)
57 /*
58 * FUNCTION: Initializes the page list with all pages free
59 * except those known to be reserved and those used by the kernel
60 * ARGUMENTS:
61 * PageBuffer = Page sized buffer
62 * FirstKernelAddress = First physical address used by the kernel
63 * LastKernelAddress = Last physical address used by the kernel
64 */
65 {
66 ULONG i;
67 ULONG Reserved;
68
69 DPRINT("MmInitializePageList(FirstPhysKernelAddress %x, "
70 "LastPhysKernelAddress %x, "
71 "MemorySizeInPages %x, LastKernelAddress %x)\n",
72 FirstPhysKernelAddress,
73 LastPhysKernelAddress,
74 MemorySizeInPages,
75 LastKernelAddress);
76
77 InitializeListHead(&UsedPageListHead);
78 KeInitializeSpinLock(&UsedPageListLock);
79 InitializeListHead(&FreePageListHead);
80 KeInitializeSpinLock(&FreePageListLock);
81 InitializeListHead(&BiosPageListHead);
82 KeInitializeSpinLock(&BiosPageListLock);
83
84 Reserved = (MemorySizeInPages * sizeof(PHYSICAL_PAGE)) / PAGESIZE;
85 MmPageArray = (PHYSICAL_PAGE *)LastKernelAddress;
86
87 DPRINT("Reserved %d\n", Reserved);
88
89 MiNrFreePages = 0;
90 MiNrUsedPages = 0;
91
92 i = 1;
93 if ((ULONG)FirstPhysKernelAddress < 0xa0000)
94 {
95 MiNrFreePages = MiNrFreePages +
96 ((ULONG)FirstPhysKernelAddress/PAGESIZE);
97 for (; i<((ULONG)FirstPhysKernelAddress/PAGESIZE); i++)
98 {
99 MmPageArray[i].Flags = PHYSICAL_PAGE_FREE;
100 InsertTailList(&FreePageListHead,
101 &MmPageArray[i].ListEntry);
102 }
103 MiNrUsedPages = MiNrUsedPages +
104 (((0xa0000) / PAGESIZE) - i);
105 for (; i<(0xa0000 / PAGESIZE); i++)
106 {
107 MmPageArray[i].Flags = PHYSICAL_PAGE_INUSE;
108 InsertTailList(&UsedPageListHead,
109 &MmPageArray[i].ListEntry);
110 }
111 for (; i<(0x100000 / PAGESIZE); i++)
112 {
113 MmPageArray[i].Flags = PHYSICAL_PAGE_BIOS;
114 InsertTailList(&BiosPageListHead,
115 &MmPageArray[i].ListEntry);
116 }
117 }
118 else
119 {
120 MiNrFreePages = MiNrFreePages + (0xa0000 / PAGESIZE);
121 for (; i<(0xa0000 / PAGESIZE); i++)
122 {
123 MmPageArray[i].Flags = PHYSICAL_PAGE_FREE;
124 InsertTailList(&FreePageListHead,
125 &MmPageArray[i].ListEntry);
126 }
127 for (; i<(0x100000 / PAGESIZE); i++)
128 {
129 MmPageArray[i].Flags = PHYSICAL_PAGE_BIOS;
130 InsertTailList(&BiosPageListHead,
131 &MmPageArray[i].ListEntry);
132 }
133 MiNrFreePages = MiNrFreePages +
134 (((ULONG)FirstPhysKernelAddress/PAGESIZE) - i);
135 for (; i<((ULONG)FirstPhysKernelAddress/PAGESIZE); i++)
136 {
137 MmPageArray[i].Flags = PHYSICAL_PAGE_FREE;
138 InsertTailList(&FreePageListHead,
139 &MmPageArray[i].ListEntry);
140 }
141 MiNrUsedPages = MiNrUsedPages +
142 (((ULONG)LastPhysKernelAddress/PAGESIZE) - i);
143 for (; i<((ULONG)LastPhysKernelAddress/PAGESIZE); i++)
144 {
145 MmPageArray[i].Flags = PHYSICAL_PAGE_INUSE;
146 InsertTailList(&UsedPageListHead,
147 &MmPageArray[i].ListEntry);
148 }
149 }
150
151 MiNrFreePages = MiNrFreePages + (MemorySizeInPages - i);
152 for (; i<MemorySizeInPages; i++)
153 {
154 MmPageArray[i].Flags = PHYSICAL_PAGE_FREE;
155 InsertTailList(&FreePageListHead,
156 &MmPageArray[i].ListEntry);
157 }
158 DPRINT("\nMmInitializePageList() = %x\n",
159 LastKernelAddress + Reserved * PAGESIZE);
160 return((PVOID)(LastKernelAddress + Reserved * PAGESIZE));
161 }
162
163 VOID MmFreePage(PVOID PhysicalAddress, ULONG Nr)
164 {
165 ULONG i;
166 ULONG Start = (ULONG)PhysicalAddress / PAGESIZE;
167 KIRQL oldIrql;
168
169 DPRINT("MmFreePage(PhysicalAddress %x, Nr %x)\n", PhysicalAddress, Nr);
170
171 if (((ULONG)PhysicalAddress) > 0x400000)
172 {
173 DbgPrint("MmFreePage() failed with %x\n", PhysicalAddress);
174 KeBugCheck(0);
175 }
176
177 MiNrFreePages = MiNrFreePages + Nr;
178 MiNrUsedPages = MiNrUsedPages - Nr;
179
180 for (i=0; i<Nr; i++)
181 {
182 KeAcquireSpinLock(&UsedPageListLock, &oldIrql);
183 RemoveEntryList(&MmPageArray[Start + i].ListEntry);
184 MmPageArray[Start + i].Flags = PHYSICAL_PAGE_FREE;
185 KeReleaseSpinLock(&UsedPageListLock, oldIrql);
186
187 ExInterlockedInsertTailList(&FreePageListHead,
188 &MmPageArray[Start + i].ListEntry,
189 &FreePageListLock);
190 }
191 }
192
193
194 PVOID MmAllocPage(VOID)
195 {
196 ULONG offset;
197 PLIST_ENTRY ListEntry;
198 PPHYSICAL_PAGE PageDescriptor;
199
200 DPRINT("MmAllocPage()\n");
201
202 ListEntry = ExInterlockedRemoveHeadList(&FreePageListHead,
203 &FreePageListLock);
204 DPRINT("ListEntry %x\n",ListEntry);
205 if (ListEntry == NULL)
206 {
207 DbgPrint("MmAllocPage(): Out of memory\n");
208 KeBugCheck(0);
209 }
210 PageDescriptor = CONTAINING_RECORD(ListEntry, PHYSICAL_PAGE, ListEntry);
211 DPRINT("PageDescriptor %x\n",PageDescriptor);
212 PageDescriptor->Flags = PHYSICAL_PAGE_INUSE;
213 ExInterlockedInsertTailList(&UsedPageListHead, ListEntry,
214 &UsedPageListLock);
215
216 DPRINT("PageDescriptor %x MmPageArray %x\n", PageDescriptor, MmPageArray);
217 offset = (ULONG)((ULONG)PageDescriptor - (ULONG)MmPageArray);
218 DPRINT("offset %x\n",offset);
219 offset = offset / sizeof(PHYSICAL_PAGE) * PAGESIZE;
220 DPRINT("offset %x\n",offset);
221
222 MiNrUsedPages = MiNrUsedPages + 1;
223 MiNrFreePages = MiNrFreePages - 1;
224
225 if (offset > 0x400000)
226 {
227 DbgPrint("Failed in MmAllocPage() with offset %x\n", offset);
228 KeBugCheck(0);
229 }
230
231 DPRINT("MmAllocPage() = %x\n",offset);
232 return((PVOID)offset);
233 }