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)
11 /* INCLUDES *****************************************************************/
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>
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>
25 #include <internal/mmhal.h>
28 #include <internal/debug.h>
30 /* GLOBALS *****************************************************************/
33 * Size of extended memory (kb) (fixed for now)
35 #define EXTENDED_MEMORY_SIZE (3*1024*1024)
38 * Compiler defined symbol
40 extern unsigned int stext
;
41 extern unsigned int etext
;
42 extern unsigned int end
;
44 static BOOLEAN IsThisAnNtAsSystem
= FALSE
;
45 static MM_SYSTEM_SIZE MmSystemSize
= MmSmallSystem
;
47 extern unsigned int etext
;
48 extern unsigned int _bss_end__
;
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
;
56 * All pagefaults are synchronized on this
58 static KSPIN_LOCK MiPageFaultLock
;
60 /* FUNCTIONS ****************************************************************/
62 VOID
MiShutdownMemoryManager(VOID
)
66 VOID
MmInitVirtualMemory(boot_param
* bp
)
68 * FUNCTION: Intialize the memory areas list
70 * bp = Pointer to the boot parameters
71 * kernel_len = Length of the kernel
74 unsigned int kernel_len
= bp
->end_mem
- bp
->start_mem
;
77 ULONG ParamLength
= kernel_len
;
79 DPRINT("MmInitVirtualMemory(%x)\n",bp
);
82 ExInitNonPagedPool(KERNEL_BASE
+ PAGE_ROUND_UP(kernel_len
) + PAGESIZE
);
86 * Setup the system area descriptor list
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
);
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
,
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
);
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
);
118 // MmDumpMemoryAreas();
121 // while (inb_p(0x60)!=0x1); inb_p(0x60);
123 MmInitSectionImplementation();
127 NTSTATUS
MmCommitedSectionHandleFault(MEMORY_AREA
* MemoryArea
, PVOID Address
)
131 KeAcquireSpinLock(&MiPageFaultLock
, &oldIrql
);
133 if (MmIsPagePresent(NULL
, Address
))
135 KeReleaseSpinLock(&MiPageFaultLock
, oldIrql
);
136 return(STATUS_SUCCESS
);
139 MmSetPage(PsGetCurrentProcess(),
141 MemoryArea
->Attributes
,
142 (ULONG
)MmAllocPage());
144 KeReleaseSpinLock(&MiPageFaultLock
, oldIrql
);
146 return(STATUS_SUCCESS
);
149 NTSTATUS
MmSectionHandleFault(MEMORY_AREA
* MemoryArea
,
152 LARGE_INTEGER Offset
;
153 IO_STATUS_BLOCK IoStatus
;
159 DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
162 KeAcquireSpinLock(&MiPageFaultLock
, &oldIrql
);
164 if (MmIsPagePresent(NULL
, Address
))
166 KeReleaseSpinLock(&MiPageFaultLock
, oldIrql
);
167 return(STATUS_SUCCESS
);
170 Offset
.QuadPart
= (Address
- MemoryArea
->BaseAddress
) +
171 MemoryArea
->Data
.SectionData
.ViewOffset
;
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
);
180 if (MemoryArea
->Data
.SectionData
.Section
->FileObject
== NULL
)
184 Page
= (ULONG
)MiTryToSharePageInSection(
185 MemoryArea
->Data
.SectionData
.Section
,
186 (ULONG
)Offset
.QuadPart
);
190 Page
= (ULONG
)MmAllocPage();
193 MmSetPage(PsGetCurrentProcess(),
195 MemoryArea
->Attributes
,
197 return(STATUS_SUCCESS
);
200 Mdl
= MmCreateMdl(NULL
, NULL
, PAGESIZE
);
201 MmBuildMdlFromPages(Mdl
);
203 Page
= MmGetMdlPageAddress(Mdl
, 0);
205 KeReleaseSpinLock(&MiPageFaultLock
, oldIrql
);
207 Status
= IoPageRead(MemoryArea
->Data
.SectionData
.Section
->FileObject
,
212 if (!NT_SUCCESS(Status
))
217 KeAcquireSpinLock(&MiPageFaultLock
, &oldIrql
);
219 if (MmIsPagePresent(NULL
, Address
))
221 KeReleaseSpinLock(&MiPageFaultLock
, oldIrql
);
222 return(STATUS_SUCCESS
);
227 MemoryArea
->Attributes
,
230 KeReleaseSpinLock(&MiPageFaultLock
, oldIrql
);
232 DPRINT("Returning from MmSectionHandleFault()\n");
234 return(STATUS_SUCCESS
);
237 ULONG
MmPageFault(ULONG cs
, ULONG eip
, ULONG error_code
)
239 * FUNCTION: Handle a page fault
242 KPROCESSOR_MODE FaultMode
;
243 MEMORY_AREA
* MemoryArea
;
248 * Get the address for the page fault
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);
254 cr2
= PAGE_ROUND_DOWN(cr2
);
256 if (error_code
& 0x1)
258 DPRINT1("Page protection fault at %x with eip %x\n", cr2
, eip
);
264 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
)
266 DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
270 if (PsGetCurrentProcess() == NULL
)
272 DbgPrint("No current process\n");
277 * Find the memory area for the faulting address
279 if (cr2
>= KERNEL_BASE
)
286 DbgPrint("%s:%d\n",__FILE__
,__LINE__
);
289 FaultMode
= UserMode
;
293 FaultMode
= KernelMode
;
296 MemoryArea
= MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID
)cr2
);
297 if (MemoryArea
== NULL
)
299 DbgPrint("%s:%d\n",__FILE__
,__LINE__
);
303 switch (MemoryArea
->Type
)
305 case MEMORY_AREA_SYSTEM
:
306 Status
= STATUS_UNSUCCESSFUL
;
309 case MEMORY_AREA_SECTION_VIEW_COMMIT
:
310 Status
= MmSectionHandleFault(MemoryArea
, (PVOID
)cr2
);
313 case MEMORY_AREA_COMMIT
:
314 Status
= MmCommitedSectionHandleFault(MemoryArea
,(PVOID
)cr2
);
318 Status
= STATUS_UNSUCCESSFUL
;
321 DPRINT("Completed page fault handling\n");
322 return(NT_SUCCESS(Status
));
325 BOOLEAN
MmIsThisAnNtAsSystem(VOID
)
327 return(IsThisAnNtAsSystem
);
330 MM_SYSTEM_SIZE
MmQuerySystemSize(VOID
)
332 return(MmSystemSize
);
335 void MmInitialize(boot_param
* bp
, ULONG LastKernelAddress
)
337 * FUNCTION: Initalize memory managment
340 unsigned int first_krnl_phys_addr
;
341 unsigned int last_krnl_phys_addr
;
343 unsigned int kernel_len
;
345 DPRINT("MmInitialize(bp %x, LastKernelAddress %x)\n", bp
,
351 MmDeletePageTable(NULL
, 0);
354 * Free all pages not used for kernel memory
355 * (we assume the kernel occupies a continuous range of physical
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
);
364 * Free physical memory not used by the kernel
366 LastKernelAddress
= (ULONG
)MmInitializePageList(
367 (PVOID
)first_krnl_phys_addr
,
368 (PVOID
)last_krnl_phys_addr
,
370 PAGE_ROUND_UP(LastKernelAddress
));
371 kernel_len
= last_krnl_phys_addr
- first_krnl_phys_addr
;
374 * Create a trap for null pointer references and protect text
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
)
382 MmSetPageProtect(NULL
,
387 DPRINT("Invalidating between %x and %x\n",
389 KERNEL_BASE
+ PAGE_TABLE_SIZE
);
390 for (i
=(LastKernelAddress
);
391 i
<(KERNEL_BASE
+ PAGE_TABLE_SIZE
);
394 MmSetPage(NULL
, (PVOID
)(i
), PAGE_NOACCESS
, 0);
396 DPRINT("Almost done MmInit()\n");
399 * Intialize memory areas
401 MmInitVirtualMemory(bp
);