Began seperation of machine-dependant/independant sections of memory
[reactos.git] / reactos / ntoskrnl / mm / marea.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/marea.c
5 * PURPOSE: Implements memory areas
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/mm.h>
15 #include <internal/mmhal.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* FUNCTIONS *****************************************************************/
21
22 VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
23 {
24 PLIST_ENTRY current_entry;
25 MEMORY_AREA* current;
26
27 DbgPrint("MmDumpMemoryAreas()\n");
28
29 current_entry = ListHead->Flink;
30 while (current_entry!=ListHead)
31 {
32 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
33 DbgPrint("Base %x Length %x End %x Attributes %x Flink %x\n",
34 current->BaseAddress,current->Length,
35 current->BaseAddress+current->Length,current->Attributes,
36 current->Entry.Flink);
37 current_entry = current_entry->Flink;
38 }
39 DbgPrint("Finished MmDumpMemoryAreas()\n");
40 }
41
42 MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
43 PVOID Address)
44 {
45 PLIST_ENTRY current_entry;
46 MEMORY_AREA* current;
47 PLIST_ENTRY previous_entry;
48
49 DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
50 AddressSpace, Address);
51
52 // MmDumpMemoryAreas(&AddressSpace->MAreaListHead);
53
54 previous_entry = &AddressSpace->MAreaListHead;
55 current_entry = AddressSpace->MAreaListHead.Flink;
56 while (current_entry != &AddressSpace->MAreaListHead)
57 {
58 current = CONTAINING_RECORD(current_entry,
59 MEMORY_AREA,
60 Entry);
61 DPRINT("Scanning %x BaseAddress %x Length %x\n",
62 current, current->BaseAddress, current->Length);
63 assert(current_entry->Blink->Flink == current_entry);
64 if (current_entry->Flink->Blink != current_entry)
65 {
66 DPRINT("BaseAddress %x\n", current->BaseAddress);
67 DPRINT("current_entry->Flink %x ", current_entry->Flink);
68 DPRINT("&current_entry->Flink %x\n",
69 &current_entry->Flink);
70 DPRINT("current_entry->Flink->Blink %x\n",
71 current_entry->Flink->Blink);
72 DPRINT("&current_entry->Flink->Blink %x\n",
73 &current_entry->Flink->Blink);
74 DPRINT("&current_entry->Flink %x\n",
75 &current_entry->Flink);
76 }
77 assert(current_entry->Flink->Blink == current_entry);
78 assert(previous_entry->Flink == current_entry);
79 if (current->BaseAddress <= Address &&
80 (current->BaseAddress + current->Length) > Address)
81 {
82 DPRINT("%s() = %x\n",__FUNCTION__,current);
83 return(current);
84 }
85 if (current->BaseAddress > Address)
86 {
87 DPRINT("%s() = NULL\n",__FUNCTION__);
88 return(NULL);
89 }
90 previous_entry = current_entry;
91 current_entry = current_entry->Flink;
92 }
93 DPRINT("%s() = NULL\n",__FUNCTION__);
94 return(NULL);
95 }
96
97 MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace,
98 PVOID Address,
99 ULONG Length)
100 {
101 MEMORY_AREA* Result;
102 PLIST_ENTRY current_entry;
103 MEMORY_AREA* current;
104 ULONG Extent;
105
106 DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
107 AddressSpace, Address, Length);
108
109 current_entry = AddressSpace->MAreaListHead.Flink;
110 while (current_entry != &AddressSpace->MAreaListHead)
111 {
112 current = CONTAINING_RECORD(current_entry,
113 MEMORY_AREA,
114 Entry);
115 DPRINT("current->BaseAddress %x current->Length %x\n",
116 current->BaseAddress,current->Length);
117 if (current->BaseAddress >= Address &&
118 current->BaseAddress < (Address+Length))
119 {
120 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
121 current);
122 return(current);
123 }
124 Extent = (ULONG)current->BaseAddress + current->Length;
125 if (Extent > (ULONG)Address &&
126 Extent < (ULONG)(Address+Length))
127 {
128 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
129 current);
130 return(current);
131 }
132 if (current->BaseAddress <= Address &&
133 Extent >= (ULONG)(Address+Length))
134 {
135 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
136 current);
137 return(current);
138 }
139 if (current->BaseAddress >= (Address+Length))
140 {
141 DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
142 return(NULL);
143 }
144 current_entry = current_entry->Flink;
145 }
146 DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
147 return(NULL);
148
149 return(Result);
150 }
151
152 static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
153 MEMORY_AREA* marea)
154 {
155 PLIST_ENTRY ListHead;
156 PLIST_ENTRY current_entry;
157 PLIST_ENTRY inserted_entry = &marea->Entry;
158 MEMORY_AREA* current;
159 MEMORY_AREA* next;
160
161 DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
162 DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
163 DPRINT("marea->Length %x\n", marea->Length);
164
165 ListHead = &AddressSpace->MAreaListHead;
166
167 current_entry = ListHead->Flink;
168 CHECKPOINT;
169 if (IsListEmpty(ListHead))
170 {
171 CHECKPOINT;
172 InsertHeadList(ListHead,&marea->Entry);
173 DPRINT("Inserting at list head\n");
174 CHECKPOINT;
175 return;
176 }
177 CHECKPOINT;
178 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
179 CHECKPOINT;
180 if (current->BaseAddress > marea->BaseAddress)
181 {
182 CHECKPOINT;
183 InsertHeadList(ListHead,&marea->Entry);
184 DPRINT("Inserting at list head\n");
185 CHECKPOINT;
186 return;
187 }
188 CHECKPOINT;
189 while (current_entry->Flink!=ListHead)
190 {
191 // CHECKPOINT;
192 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
193 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
194 // assert(current->BaseAddress != marea->BaseAddress);
195 // assert(next->BaseAddress != marea->BaseAddress);
196 if (current->BaseAddress < marea->BaseAddress &&
197 current->Entry.Flink==ListHead)
198 {
199 DPRINT("Insert after %x\n", current_entry);
200 current_entry->Flink = inserted_entry;
201 inserted_entry->Flink=ListHead;
202 inserted_entry->Blink=current_entry;
203 ListHead->Blink = inserted_entry;
204 return;
205 }
206 if (current->BaseAddress < marea->BaseAddress &&
207 next->BaseAddress > marea->BaseAddress)
208 {
209 DPRINT("Inserting before %x\n", current_entry);
210 inserted_entry->Flink = current_entry->Flink;
211 inserted_entry->Blink = current_entry;
212 inserted_entry->Flink->Blink = inserted_entry;
213 current_entry->Flink=inserted_entry;
214 return;
215 }
216 current_entry = current_entry->Flink;
217 }
218 CHECKPOINT;
219 DPRINT("Inserting at list tail\n");
220 InsertTailList(ListHead,inserted_entry);
221 }
222
223 static PVOID MmFindGap(PMADDRESS_SPACE AddressSpace,
224 ULONG Length)
225 {
226 PLIST_ENTRY ListHead;
227 PLIST_ENTRY current_entry;
228 MEMORY_AREA* current;
229 MEMORY_AREA* next;
230 ULONG Gap;
231
232 DPRINT("MmFindGap(Length %x)\n",Length);
233
234 ListHead = &AddressSpace->MAreaListHead;
235
236 current_entry = ListHead->Flink;
237 while (current_entry->Flink!=ListHead)
238 {
239 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
240 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
241 DPRINT("current %x current->BaseAddress %x ",current,
242 current->BaseAddress);
243 DPRINT("current->Length %x\n",current->Length);
244 DPRINT("next %x next->BaseAddress %x ",next,next->BaseAddress);
245 Gap = (next->BaseAddress ) -(current->BaseAddress + current->Length);
246 DPRINT("Base %x Gap %x\n",current->BaseAddress,Gap);
247 if (Gap >= Length)
248 {
249 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
250 }
251 current_entry = current_entry->Flink;
252 }
253
254 if (current_entry == ListHead)
255 {
256 return((PVOID)AddressSpace->LowestAddress);
257 }
258
259 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
260 //DbgPrint("current %x returning %x\n",current,current->BaseAddress+
261 // current->Length);
262 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
263 }
264
265 NTSTATUS MmInitMemoryAreas(VOID)
266 /*
267 * FUNCTION: Initialize the memory area list
268 */
269 {
270 DPRINT("MmInitMemoryAreas()\n",0);
271 return(STATUS_SUCCESS);
272 }
273
274 NTSTATUS MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
275 PVOID BaseAddress,
276 ULONG Length,
277 BOOLEAN FreePages)
278 {
279 MEMORY_AREA* MemoryArea;
280 ULONG i;
281 LARGE_INTEGER PhysicalAddr;
282
283 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
284 "FreePages %d)\n",AddressSpace,BaseAddress,Length,FreePages);
285
286 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
287 BaseAddress);
288 if (MemoryArea == NULL)
289 {
290 KeBugCheck(0);
291 return(STATUS_UNSUCCESSFUL);
292 }
293 if (FreePages)
294 {
295 for (i=0;i<=(MemoryArea->Length/PAGESIZE);i++)
296 {
297 PhysicalAddr = MmGetPhysicalAddress(MemoryArea->BaseAddress +
298 (i*PAGESIZE));
299 MmDereferencePage((PVOID)(ULONG)(PhysicalAddr.u.LowPart));
300 }
301 }
302 for (i=0; i<=(MemoryArea->Length/PAGESIZE); i++)
303 {
304 if (AddressSpace->Process != NULL)
305 {
306 DPRINT("Freeing %x in %d\n",
307 MemoryArea->BaseAddress + (i*PAGESIZE),
308 AddressSpace->Process->UniqueProcessId);
309 }
310 else
311 {
312 // DPRINT("Freeing %x in kernel address space\n");
313 }
314 MmSetPage(AddressSpace->Process,
315 MemoryArea->BaseAddress + (i*PAGESIZE),
316 0,
317 0);
318 }
319
320 RemoveEntryList(&(MemoryArea->Entry));
321 ExFreePool(MemoryArea);
322
323 DPRINT("MmFreeMemoryArea() succeeded\n");
324
325 return(STATUS_SUCCESS);
326 }
327
328 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
329 PMADDRESS_SPACE AddressSpace,
330 PMEMORY_AREA OriginalMemoryArea,
331 PVOID BaseAddress,
332 ULONG Length,
333 ULONG NewType,
334 ULONG NewAttributes)
335 {
336 PMEMORY_AREA Result;
337 PMEMORY_AREA Split;
338
339 Result = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
340 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
341 Result->Type = NewType;
342 Result->BaseAddress = BaseAddress;
343 Result->Length = Length;
344 Result->Attributes = NewAttributes;
345 Result->LockCount = 0;
346 Result->Process = Process;
347
348 if (BaseAddress == OriginalMemoryArea->BaseAddress)
349 {
350 OriginalMemoryArea->BaseAddress = BaseAddress + Length;
351 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
352 MmInsertMemoryArea(AddressSpace, Result);
353 return(Result);
354 }
355 if ((BaseAddress + Length) ==
356 (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
357 {
358 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
359 MmInsertMemoryArea(AddressSpace, Result);
360
361 return(Result);
362 }
363
364 Split = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
365 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
366 Split->BaseAddress = BaseAddress + Length;
367 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
368 + Length);
369
370 OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
371
372 return(Split);
373 }
374
375 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
376 PMADDRESS_SPACE AddressSpace,
377 ULONG Type,
378 PVOID* BaseAddress,
379 ULONG Length,
380 ULONG Attributes,
381 MEMORY_AREA** Result)
382 /*
383 * FUNCTION: Create a memory area
384 * ARGUMENTS:
385 * AddressSpace = Address space to create the area in
386 * Type = Type of the address space
387 * BaseAddress =
388 * Length = Length to allocate
389 * Attributes = Protection attributes for the memory area
390 * Result = Receives a pointer to the memory area on exit
391 * RETURNS: Status
392 * NOTES: Lock the address space before calling this function
393 */
394 {
395 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
396 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
397 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
398
399 if ((*BaseAddress)==0)
400 {
401 *BaseAddress = MmFindGap(AddressSpace,
402 PAGE_ROUND_UP(Length) +(PAGESIZE*2));
403 if ((*BaseAddress)==0)
404 {
405 DPRINT("No suitable gap\n");
406 return(STATUS_UNSUCCESSFUL);
407 }
408 (*BaseAddress)=(*BaseAddress)+PAGESIZE;
409 }
410 else
411 {
412 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
413 if (MmOpenMemoryAreaByRegion(AddressSpace,
414 *BaseAddress,
415 Length)!=NULL)
416 {
417 DPRINT("Memory area already occupied\n");
418 return(STATUS_UNSUCCESSFUL);
419 }
420 }
421
422 *Result = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
423 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
424 (*Result)->Type = Type;
425 (*Result)->BaseAddress = *BaseAddress;
426 (*Result)->Length = Length;
427 (*Result)->Attributes = Attributes;
428 (*Result)->LockCount = 0;
429 (*Result)->Process = Process;
430
431 MmInsertMemoryArea(AddressSpace, *Result);
432
433 DPRINT("MmCreateMemoryArea() succeeded\n");
434 return(STATUS_SUCCESS);
435 }