Fixed header inclusion order.
[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 /* FUNCTIONS ****************************************************************/
56
57 VOID MmInitVirtualMemory(boot_param* bp)
58 /*
59 * FUNCTION: Intialize the memory areas list
60 * ARGUMENTS:
61 * bp = Pointer to the boot parameters
62 * kernel_len = Length of the kernel
63 */
64 {
65 unsigned int kernel_len = bp->end_mem - bp->start_mem;
66 PVOID BaseAddress;
67 ULONG Length;
68 ULONG ParamLength = kernel_len;
69
70 DPRINT("MmInitVirtualMemory(%x)\n",bp);
71
72 MmInitMemoryAreas();
73 ExInitNonPagedPool(KERNEL_BASE+ PAGE_ROUND_UP(kernel_len) + PAGESIZE);
74
75
76 /*
77 * Setup the system area descriptor list
78 */
79 BaseAddress = (PVOID)KERNEL_BASE;
80 Length = PAGE_ROUND_UP(((ULONG)&etext)) - KERNEL_BASE;
81 ParamLength = ParamLength - Length;
82 MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
83 Length,0,&kernel_text_desc);
84
85 Length = PAGE_ROUND_UP(((ULONG)&_bss_end__)) -
86 PAGE_ROUND_UP(((ULONG)&etext));
87 ParamLength = ParamLength - Length;
88 DPRINT("Length %x\n",Length);
89 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&etext));
90 DPRINT("BaseAddress %x\n",BaseAddress);
91 MmCreateMemoryArea(KernelMode,
92 NULL,
93 MEMORY_AREA_SYSTEM,
94 &BaseAddress,
95 Length,
96 0,
97 &kernel_data_desc);
98
99 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&end));
100 Length = ParamLength;
101 MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
102 Length,0,&kernel_param_desc);
103
104 BaseAddress = (PVOID)(KERNEL_BASE + PAGE_ROUND_UP(kernel_len) + PAGESIZE);
105 Length = NONPAGED_POOL_SIZE;
106 MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
107 Length,0,&kernel_pool_desc);
108
109 // MmDumpMemoryAreas();
110 CHECKPOINT;
111
112 // while (inb_p(0x60)!=0x1); inb_p(0x60);
113
114 MmInitSectionImplementation();
115 }
116
117 NTSTATUS MmCommitedSectionHandleFault(MEMORY_AREA* MemoryArea, PVOID Address)
118 {
119 MmSetPage(PsGetCurrentProcess(),
120 Address,
121 MemoryArea->Attributes,
122 (ULONG)MmAllocPage());
123 return(STATUS_SUCCESS);
124 }
125
126 NTSTATUS MmSectionHandleFault(MEMORY_AREA* MemoryArea, PVOID Address)
127 {
128 LARGE_INTEGER Offset;
129 IO_STATUS_BLOCK IoStatus;
130
131 DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
132 MemoryArea,Address);
133
134 MmSetPage(NULL,
135 Address,
136 MemoryArea->Attributes,
137 (ULONG)MmAllocPage());
138
139 Offset.QuadPart = (Address - MemoryArea->BaseAddress) +
140 MemoryArea->Data.SectionData.ViewOffset;
141
142 DPRINT("MemoryArea->Data.SectionData.Section->FileObject %x\n",
143 MemoryArea->Data.SectionData.Section->FileObject);
144
145 if (MemoryArea->Data.SectionData.Section->FileObject == NULL)
146 {
147 return(STATUS_UNSUCCESSFUL);
148 }
149
150 IoPageRead(MemoryArea->Data.SectionData.Section->FileObject,
151 (PVOID)Address,
152 &Offset,
153 &IoStatus);
154
155 DPRINT("Returning from MmSectionHandleFault()\n");
156
157 return(STATUS_SUCCESS);
158 }
159
160 asmlinkage int page_fault_handler(unsigned int cs,
161 unsigned int eip)
162 /*
163 * FUNCTION: Handle a page fault
164 */
165 {
166 KPROCESSOR_MODE FaultMode;
167 MEMORY_AREA* MemoryArea;
168 KIRQL oldlvl;
169 NTSTATUS Status;
170
171 /*
172 * Get the address for the page fault
173 */
174 unsigned int cr2;
175 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
176 DPRINT("Page fault at address %x with eip %x in process %x\n",cr2,eip,
177 PsGetCurrentProcess());
178
179 cr2 = PAGE_ROUND_DOWN(cr2);
180
181 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
182 {
183 DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
184 return(0);
185 // KeBugCheck(0);
186 }
187
188 KeRaiseIrql(DISPATCH_LEVEL, &oldlvl);
189
190 /*
191 * Find the memory area for the faulting address
192 */
193 if (cr2 >= KERNEL_BASE)
194 {
195 /*
196 * Check permissions
197 */
198 if (cs != KERNEL_CS)
199 {
200 printk("%s:%d\n",__FILE__,__LINE__);
201 return(0);
202 }
203 FaultMode = UserMode;
204 }
205 else
206 {
207 FaultMode = KernelMode;
208 }
209
210 MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID)cr2);
211 if (MemoryArea == NULL)
212 {
213 printk("%s:%d\n",__FILE__,__LINE__);
214 return(0);
215 }
216
217 switch (MemoryArea->Type)
218 {
219 case MEMORY_AREA_SYSTEM:
220 Status = STATUS_UNSUCCESSFUL;
221 break;
222
223 case MEMORY_AREA_SECTION_VIEW_COMMIT:
224 Status = MmSectionHandleFault(MemoryArea, (PVOID)cr2);
225 break;
226
227 case MEMORY_AREA_COMMIT:
228 Status = MmCommitedSectionHandleFault(MemoryArea,(PVOID)cr2);
229 break;
230
231 default:
232 Status = STATUS_UNSUCCESSFUL;
233 break;
234 }
235 DPRINT("Completed page fault handling\n");
236 if (NT_SUCCESS(Status))
237 {
238 KeLowerIrql(oldlvl);
239 }
240 return(NT_SUCCESS(Status));
241 }
242
243 BOOLEAN MmIsThisAnNtAsSystem(VOID)
244 {
245 return(IsThisAnNtAsSystem);
246 }
247
248 MM_SYSTEM_SIZE MmQuerySystemSize(VOID)
249 {
250 return(MmSystemSize);
251 }
252
253 void MmInitialize(boot_param* bp, ULONG LastKernelAddress)
254 /*
255 * FUNCTION: Initalize memory managment
256 */
257 {
258 unsigned int first_krnl_phys_addr;
259 unsigned int last_krnl_phys_addr;
260 int i;
261 unsigned int kernel_len;
262
263 DPRINT("MmInitialize(bp %x, LastKernelAddress %x)\n", bp,
264 LastKernelAddress);
265
266 /*
267 * Unmap low memory
268 */
269 MmDeletePageTable(NULL, 0);
270
271 /*
272 * Free all pages not used for kernel memory
273 * (we assume the kernel occupies a continuous range of physical
274 * memory)
275 */
276 first_krnl_phys_addr = bp->start_mem;
277 last_krnl_phys_addr = bp->end_mem;
278 DPRINT("first krnl %x\nlast krnl %x\n",first_krnl_phys_addr,
279 last_krnl_phys_addr);
280
281 /*
282 * Free physical memory not used by the kernel
283 */
284 LastKernelAddress = (ULONG)MmInitializePageList(
285 (PVOID)first_krnl_phys_addr,
286 (PVOID)last_krnl_phys_addr,
287 1024,
288 PAGE_ROUND_UP(LastKernelAddress));
289 kernel_len = last_krnl_phys_addr - first_krnl_phys_addr;
290
291 /*
292 * Create a trap for null pointer references and protect text
293 * segment
294 */
295 CHECKPOINT;
296 DPRINT("stext %x etext %x\n",(int)&stext,(int)&etext);
297 for (i=PAGE_ROUND_UP(((int)&stext));
298 i<PAGE_ROUND_DOWN(((int)&etext));i=i+PAGESIZE)
299 {
300 MmSetPageProtect(NULL,
301 (PVOID)i,
302 PAGE_EXECUTE_READ);
303 }
304
305 DPRINT("Invalidating between %x and %x\n",
306 LastKernelAddress,
307 KERNEL_BASE + PAGE_TABLE_SIZE);
308 for (i=(LastKernelAddress);
309 i<(KERNEL_BASE + PAGE_TABLE_SIZE);
310 i=i+PAGESIZE)
311 {
312 MmSetPage(NULL, (PVOID)(i), PAGE_NOACCESS, 0);
313 }
314 DPRINT("Almost done MmInit()\n");
315
316 /*
317 * Intialize memory areas
318 */
319 MmInitVirtualMemory(bp);
320 }