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