Fixed problem with handles not being released
[reactos.git] / reactos / ntoskrnl / mm / mm.c
1 /*
2 * COPYRIGHT: See COPYING in the top directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/mm.c
5 * PURPOSE: kernel memory managment functions
6 * PROGRAMMER: David Welch (welch@cwcom.net)
7 * UPDATE HISTORY:
8 * Created 9/4/98
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/hal/io.h>
15 #include <internal/i386/segment.h>
16 #include <internal/stddef.h>
17 #include <internal/mm.h>
18 #include <string.h>
19 #include <internal/string.h>
20 #include <internal/ntoskrnl.h>
21 #include <internal/bitops.h>
22 #include <internal/string.h>
23 #include <internal/io.h>
24
25 #include <internal/mmhal.h>
26
27 #define NDEBUG
28 #include <internal/debug.h>
29
30 /* GLOBALS *****************************************************************/
31
32 /*
33 * Size of extended memory (kb) (fixed for now)
34 */
35 #define EXTENDED_MEMORY_SIZE (3*1024*1024)
36
37 /*
38 * Compiler defined symbol
39 */
40 extern unsigned int stext;
41 extern unsigned int etext;
42 extern unsigned int end;
43
44 static BOOLEAN IsThisAnNtAsSystem = FALSE;
45 static MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
46
47 extern unsigned int etext;
48 extern unsigned int _bss_end__;
49
50 static MEMORY_AREA* kernel_text_desc = NULL;
51 static MEMORY_AREA* kernel_data_desc = NULL;
52 static MEMORY_AREA* kernel_param_desc = NULL;
53 static MEMORY_AREA* kernel_pool_desc = NULL;
54
55 /*
56 * All pagefaults are synchronized on this
57 */
58 static KSPIN_LOCK MiPageFaultLock;
59
60 /* FUNCTIONS ****************************************************************/
61
62 VOID MiShutdownMemoryManager(VOID)
63 {
64 }
65
66 VOID MmInitVirtualMemory(boot_param* bp)
67 /*
68 * FUNCTION: Intialize the memory areas list
69 * ARGUMENTS:
70 * bp = Pointer to the boot parameters
71 * kernel_len = Length of the kernel
72 */
73 {
74 unsigned int kernel_len = bp->end_mem - bp->start_mem;
75 PVOID BaseAddress;
76 ULONG Length;
77 ULONG ParamLength = kernel_len;
78
79 DPRINT("MmInitVirtualMemory(%x)\n",bp);
80
81 MmInitMemoryAreas();
82 ExInitNonPagedPool(KERNEL_BASE+ PAGE_ROUND_UP(kernel_len) + PAGESIZE);
83
84
85 /*
86 * Setup the system area descriptor list
87 */
88 BaseAddress = (PVOID)KERNEL_BASE;
89 Length = PAGE_ROUND_UP(((ULONG)&etext)) - KERNEL_BASE;
90 ParamLength = ParamLength - Length;
91 MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
92 Length,0,&kernel_text_desc);
93
94 Length = PAGE_ROUND_UP(((ULONG)&_bss_end__)) -
95 PAGE_ROUND_UP(((ULONG)&etext));
96 ParamLength = ParamLength - Length;
97 DPRINT("Length %x\n",Length);
98 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&etext));
99 DPRINT("BaseAddress %x\n",BaseAddress);
100 MmCreateMemoryArea(KernelMode,
101 NULL,
102 MEMORY_AREA_SYSTEM,
103 &BaseAddress,
104 Length,
105 0,
106 &kernel_data_desc);
107
108 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&end));
109 Length = ParamLength;
110 MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
111 Length,0,&kernel_param_desc);
112
113 BaseAddress = (PVOID)(KERNEL_BASE + PAGE_ROUND_UP(kernel_len) + PAGESIZE);
114 Length = NONPAGED_POOL_SIZE;
115 MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
116 Length,0,&kernel_pool_desc);
117
118 // MmDumpMemoryAreas();
119 CHECKPOINT;
120
121 // while (inb_p(0x60)!=0x1); inb_p(0x60);
122
123 MmInitSectionImplementation();
124 MmInitPagingFile();
125 }
126
127 NTSTATUS MmCommitedSectionHandleFault(MEMORY_AREA* MemoryArea, PVOID Address)
128 {
129 KIRQL oldIrql;
130
131 KeAcquireSpinLock(&MiPageFaultLock, &oldIrql);
132
133 if (MmIsPagePresent(NULL, Address))
134 {
135 KeReleaseSpinLock(&MiPageFaultLock, oldIrql);
136 return(STATUS_SUCCESS);
137 }
138
139 MmSetPage(PsGetCurrentProcess(),
140 Address,
141 MemoryArea->Attributes,
142 (ULONG)MmAllocPage());
143
144 KeReleaseSpinLock(&MiPageFaultLock, oldIrql);
145
146 return(STATUS_SUCCESS);
147 }
148
149 NTSTATUS MmSectionHandleFault(MEMORY_AREA* MemoryArea,
150 PVOID Address)
151 {
152 LARGE_INTEGER Offset;
153 IO_STATUS_BLOCK IoStatus;
154 PMDL Mdl;
155 PVOID Page;
156 NTSTATUS Status;
157 KIRQL oldIrql;
158
159 DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
160 MemoryArea,Address);
161
162 KeAcquireSpinLock(&MiPageFaultLock, &oldIrql);
163
164 if (MmIsPagePresent(NULL, Address))
165 {
166 KeReleaseSpinLock(&MiPageFaultLock, oldIrql);
167 return(STATUS_SUCCESS);
168 }
169
170 Offset.QuadPart = (Address - MemoryArea->BaseAddress) +
171 MemoryArea->Data.SectionData.ViewOffset;
172
173 DPRINT("MemoryArea->Data.SectionData.Section->FileObject %x\n",
174 MemoryArea->Data.SectionData.Section->FileObject);
175 DPRINT("MemoryArea->Data.SectionData.ViewOffset %x\n",
176 MemoryArea->Data.SectionData.ViewOffset);
177 DPRINT("Offset.QuadPart %x\n", (ULONG)Offset.QuadPart);
178 DPRINT("MemoryArea->BaseAddress %x\n", MemoryArea->BaseAddress);
179
180 if (MemoryArea->Data.SectionData.Section->FileObject == NULL)
181 {
182 ULONG Page;
183
184 Page = (ULONG)MiTryToSharePageInSection(
185 MemoryArea->Data.SectionData.Section,
186 (ULONG)Offset.QuadPart);
187
188 if (Page == 0)
189 {
190 Page = (ULONG)MmAllocPage();
191 }
192
193 MmSetPage(PsGetCurrentProcess(),
194 Address,
195 MemoryArea->Attributes,
196 Page);
197 return(STATUS_SUCCESS);
198 }
199
200 Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
201 MmBuildMdlFromPages(Mdl);
202
203 Page = MmGetMdlPageAddress(Mdl, 0);
204
205 KeReleaseSpinLock(&MiPageFaultLock, oldIrql);
206
207 Status = IoPageRead(MemoryArea->Data.SectionData.Section->FileObject,
208 Mdl,
209 &Offset,
210 &IoStatus);
211
212 if (!NT_SUCCESS(Status))
213 {
214 return(Status);
215 }
216
217 KeAcquireSpinLock(&MiPageFaultLock, &oldIrql);
218
219 if (MmIsPagePresent(NULL, Address))
220 {
221 KeReleaseSpinLock(&MiPageFaultLock, oldIrql);
222 return(STATUS_SUCCESS);
223 }
224
225 MmSetPage(NULL,
226 Address,
227 MemoryArea->Attributes,
228 (ULONG)Page);
229
230 KeReleaseSpinLock(&MiPageFaultLock, oldIrql);
231
232 DPRINT("Returning from MmSectionHandleFault()\n");
233
234 return(STATUS_SUCCESS);
235 }
236
237 ULONG MmPageFault(ULONG cs, ULONG eip, ULONG error_code)
238 /*
239 * FUNCTION: Handle a page fault
240 */
241 {
242 KPROCESSOR_MODE FaultMode;
243 MEMORY_AREA* MemoryArea;
244 NTSTATUS Status;
245 unsigned int cr2;
246
247 /*
248 * Get the address for the page fault
249 */
250 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
251 // DbgPrint("Page fault address %x eip %x process %x code %x\n",cr2,eip,
252 // PsGetCurrentProcess(), error_code);
253
254 cr2 = PAGE_ROUND_DOWN(cr2);
255
256 if (error_code & 0x1)
257 {
258 DPRINT1("Page protection fault at %x with eip %x\n", cr2, eip);
259 return(0);
260 }
261
262 // DbgPrint("(%%");
263
264 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
265 {
266 DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
267 return(0);
268 // KeBugCheck(0);
269 }
270 if (PsGetCurrentProcess() == NULL)
271 {
272 DbgPrint("No current process\n");
273 return(0);
274 }
275
276 /*
277 * Find the memory area for the faulting address
278 */
279 if (cr2 >= KERNEL_BASE)
280 {
281 /*
282 * Check permissions
283 */
284 if (cs != KERNEL_CS)
285 {
286 DbgPrint("%s:%d\n",__FILE__,__LINE__);
287 return(0);
288 }
289 FaultMode = UserMode;
290 }
291 else
292 {
293 FaultMode = KernelMode;
294 }
295
296 MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID)cr2);
297 if (MemoryArea == NULL)
298 {
299 DbgPrint("%s:%d\n",__FILE__,__LINE__);
300 return(0);
301 }
302
303 switch (MemoryArea->Type)
304 {
305 case MEMORY_AREA_SYSTEM:
306 Status = STATUS_UNSUCCESSFUL;
307 break;
308
309 case MEMORY_AREA_SECTION_VIEW_COMMIT:
310 Status = MmSectionHandleFault(MemoryArea, (PVOID)cr2);
311 break;
312
313 case MEMORY_AREA_COMMIT:
314 Status = MmCommitedSectionHandleFault(MemoryArea,(PVOID)cr2);
315 break;
316
317 default:
318 Status = STATUS_UNSUCCESSFUL;
319 break;
320 }
321 DPRINT("Completed page fault handling\n");
322 return(NT_SUCCESS(Status));
323 }
324
325 BOOLEAN MmIsThisAnNtAsSystem(VOID)
326 {
327 return(IsThisAnNtAsSystem);
328 }
329
330 MM_SYSTEM_SIZE MmQuerySystemSize(VOID)
331 {
332 return(MmSystemSize);
333 }
334
335 void MmInitialize(boot_param* bp, ULONG LastKernelAddress)
336 /*
337 * FUNCTION: Initalize memory managment
338 */
339 {
340 unsigned int first_krnl_phys_addr;
341 unsigned int last_krnl_phys_addr;
342 int i;
343 unsigned int kernel_len;
344
345 DPRINT("MmInitialize(bp %x, LastKernelAddress %x)\n", bp,
346 LastKernelAddress);
347
348 /*
349 * Unmap low memory
350 */
351 MmDeletePageTable(NULL, 0);
352
353 /*
354 * Free all pages not used for kernel memory
355 * (we assume the kernel occupies a continuous range of physical
356 * memory)
357 */
358 first_krnl_phys_addr = bp->start_mem;
359 last_krnl_phys_addr = bp->end_mem;
360 DPRINT("first krnl %x\nlast krnl %x\n",first_krnl_phys_addr,
361 last_krnl_phys_addr);
362
363 /*
364 * Free physical memory not used by the kernel
365 */
366 LastKernelAddress = (ULONG)MmInitializePageList(
367 (PVOID)first_krnl_phys_addr,
368 (PVOID)last_krnl_phys_addr,
369 1024,
370 PAGE_ROUND_UP(LastKernelAddress));
371 kernel_len = last_krnl_phys_addr - first_krnl_phys_addr;
372
373 /*
374 * Create a trap for null pointer references and protect text
375 * segment
376 */
377 CHECKPOINT;
378 DPRINT("stext %x etext %x\n",(int)&stext,(int)&etext);
379 for (i=PAGE_ROUND_UP(((int)&stext));
380 i<PAGE_ROUND_DOWN(((int)&etext));i=i+PAGESIZE)
381 {
382 MmSetPageProtect(NULL,
383 (PVOID)i,
384 PAGE_EXECUTE_READ);
385 }
386
387 DPRINT("Invalidating between %x and %x\n",
388 LastKernelAddress,
389 KERNEL_BASE + PAGE_TABLE_SIZE);
390 for (i=(LastKernelAddress);
391 i<(KERNEL_BASE + PAGE_TABLE_SIZE);
392 i=i+PAGESIZE)
393 {
394 MmSetPage(NULL, (PVOID)(i), PAGE_NOACCESS, 0);
395 }
396 DPRINT("Almost done MmInit()\n");
397
398 /*
399 * Intialize memory areas
400 */
401 MmInitVirtualMemory(bp);
402 }