PDRIVER_REINITIALIZE: Force stdcall for captive as it is callbacked
[reactos.git] / ntoskrnl / mm / mm.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * COPYRIGHT:   See COPYING in the top directory
22  * PROJECT:     ReactOS kernel 
23  * FILE:        ntoskrnl/mm/mm.c
24  * PURPOSE:     kernel memory managment functions
25  * PROGRAMMER:  David Welch (welch@cwcom.net)
26  * UPDATE HISTORY:
27  *              Created 9/4/98
28  */
29
30 /* INCLUDES *****************************************************************/
31
32 #include <ddk/ntddk.h>
33 #include <internal/i386/segment.h>
34 #include <internal/mm.h>
35 #include <internal/ntoskrnl.h>
36 #include <internal/io.h>
37 #include <internal/ps.h>
38
39 #define NDEBUG
40 #include <internal/debug.h>
41
42 /* GLOBALS *****************************************************************/
43
44 PVOID EXPORTED MmUserProbeAddress = NULL; 
45 PVOID EXPORTED MmHighestUserAddress = NULL;
46 MM_STATS MmStats; 
47
48 /* FUNCTIONS ****************************************************************/
49
50 NTSTATUS MmReleaseMemoryArea(PEPROCESS Process, PMEMORY_AREA Marea)
51 {
52    NTSTATUS Status;
53    
54    DPRINT("MmReleaseMemoryArea(Process %x, Marea %x)\n",Process,Marea);
55    
56    DPRINT("Releasing %x between %x %x (type %d)\n",
57            Marea, Marea->BaseAddress, Marea->BaseAddress + Marea->Length,
58            Marea->Type);
59    
60    switch (Marea->Type)
61      {
62      case MEMORY_AREA_SECTION_VIEW:
63         Status = MmUnmapViewOfSection(Process, Marea->BaseAddress);
64         assert(Status == STATUS_SUCCESS);
65         return(STATUS_SUCCESS);
66
67      case MEMORY_AREA_VIRTUAL_MEMORY:
68        MmFreeVirtualMemory(Process, Marea);
69        break;   
70
71      case MEMORY_AREA_SHARED_DATA:
72        Status = MmFreeMemoryArea(&Process->AddressSpace,
73                                  Marea->BaseAddress,
74                                  0,
75                                  NULL,
76                                  NULL);
77        break;
78
79      default:
80        KeBugCheck(0);
81      }
82    
83    return(STATUS_SUCCESS);
84 }
85
86 NTSTATUS MmReleaseMmInfo(PEPROCESS Process)
87 {
88    PLIST_ENTRY CurrentEntry;
89    PMEMORY_AREA Current;
90    
91    DPRINT("MmReleaseMmInfo(Process %x (%s))\n", Process,
92            Process->ImageFileName);
93    
94    MmLockAddressSpace(&Process->AddressSpace);
95
96    CurrentEntry = Process->AddressSpace.MAreaListHead.Flink;
97    while (CurrentEntry != &Process->AddressSpace.MAreaListHead)
98      {
99         Current = CONTAINING_RECORD(CurrentEntry, MEMORY_AREA, Entry);
100         CurrentEntry = CurrentEntry->Flink;
101         
102         MmReleaseMemoryArea(Process, Current);
103      }
104    
105    Mmi386ReleaseMmInfo(Process);
106    
107    MmUnlockAddressSpace(&Process->AddressSpace);
108    MmDestroyAddressSpace(&Process->AddressSpace);
109    
110    DPRINT("Finished MmReleaseMmInfo()\n");
111    return(STATUS_SUCCESS);
112 }
113
114 BOOLEAN STDCALL MmIsNonPagedSystemAddressValid(PVOID VirtualAddress)
115 {
116    UNIMPLEMENTED;
117 }
118
119 BOOLEAN STDCALL MmIsAddressValid(PVOID VirtualAddress)
120 /*
121  * FUNCTION: Checks whether the given address is valid for a read or write
122  * ARGUMENTS:
123  *          VirtualAddress = address to check
124  * RETURNS: True if the access would be valid
125  *          False if the access would cause a page fault
126  * NOTES: This function checks whether a byte access to the page would
127  *        succeed. Is this realistic for RISC processors which don't
128  *        allow byte granular access?
129  */
130 {
131    MEMORY_AREA* MemoryArea;
132    PMADDRESS_SPACE AddressSpace;
133    
134    AddressSpace = &PsGetCurrentProcess()->AddressSpace;
135    
136    MmLockAddressSpace(AddressSpace);
137    MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
138                                           VirtualAddress);
139
140    if (MemoryArea == NULL)
141      {
142         MmUnlockAddressSpace(AddressSpace);
143         return(FALSE);
144      }
145    MmUnlockAddressSpace(AddressSpace);
146    return(TRUE);
147 }
148
149 NTSTATUS MmAccessFault(KPROCESSOR_MODE Mode,
150                        ULONG Address,
151                        BOOLEAN FromMdl)
152 {
153    PMADDRESS_SPACE AddressSpace;
154    MEMORY_AREA* MemoryArea;
155    NTSTATUS Status;
156    BOOLEAN Locked = FromMdl;
157    
158    DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
159    
160    if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
161      {
162         DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
163         return(STATUS_UNSUCCESSFUL);
164      }
165    if (PsGetCurrentProcess() == NULL)
166      {
167         DbgPrint("No current process\n");
168         return(STATUS_UNSUCCESSFUL);
169      }
170    
171    /*
172     * Find the memory area for the faulting address
173     */
174    if (Address >= KERNEL_BASE)
175      {
176         /*
177          * Check permissions
178          */
179         if (Mode != KernelMode)
180           {
181              DbgPrint("%s:%d\n",__FILE__,__LINE__);
182              return(STATUS_UNSUCCESSFUL);
183           }
184         AddressSpace = MmGetKernelAddressSpace();
185      }
186    else
187      {
188         AddressSpace = &PsGetCurrentProcess()->AddressSpace;
189      }
190    
191    if (!FromMdl)
192      {
193        MmLockAddressSpace(AddressSpace);
194      }
195    MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, (PVOID)Address);
196    if (MemoryArea == NULL)
197      {
198         DbgPrint("%s:%d\n",__FILE__,__LINE__);
199         if (!FromMdl)
200           {
201             MmUnlockAddressSpace(AddressSpace);
202           }
203         return(STATUS_UNSUCCESSFUL);
204      }
205    
206    switch (MemoryArea->Type)
207      {
208       case MEMORY_AREA_SYSTEM:
209         Status = STATUS_UNSUCCESSFUL;
210         break;
211
212      case MEMORY_AREA_PAGED_POOL:
213        Status = STATUS_SUCCESS;
214        break;
215         
216       case MEMORY_AREA_SECTION_VIEW:
217         Status = MmAccessFaultSectionView(AddressSpace,
218                                           MemoryArea, 
219                                           (PVOID)Address,
220                                           Locked);
221         break;
222         
223       case MEMORY_AREA_VIRTUAL_MEMORY:
224         Status = STATUS_UNSUCCESSFUL;
225         break;
226         
227       case MEMORY_AREA_SHARED_DATA:
228         Status = STATUS_UNSUCCESSFUL;
229         break;
230         
231       default:
232         Status = STATUS_UNSUCCESSFUL;
233         break;
234      }
235    DPRINT("Completed page fault handling\n");
236    if (!FromMdl)
237      {
238        MmUnlockAddressSpace(AddressSpace);
239      }
240    return(Status);
241 }
242
243 NTSTATUS MmCommitPagedPoolAddress(PVOID Address)
244 {
245   NTSTATUS Status;
246   PHYSICAL_ADDRESS AllocatedPage;
247   Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage);
248   if (!NT_SUCCESS(Status))
249     {
250       MmUnlockAddressSpace(MmGetKernelAddressSpace());
251       Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage);
252       MmLockAddressSpace(MmGetKernelAddressSpace());
253     }
254   Status = 
255     MmCreateVirtualMapping(NULL,
256                            (PVOID)PAGE_ROUND_DOWN(Address),
257                            PAGE_READWRITE,
258                            AllocatedPage,
259                            FALSE);
260   if (!NT_SUCCESS(Status))
261     {
262       MmUnlockAddressSpace(MmGetKernelAddressSpace());
263       Status = 
264         MmCreateVirtualMapping(NULL,
265                                (PVOID)PAGE_ROUND_DOWN(Address),
266                                PAGE_READWRITE,
267                                AllocatedPage,
268                                FALSE);
269       MmLockAddressSpace(MmGetKernelAddressSpace());
270     }
271   return(Status);
272 }
273
274 NTSTATUS MmNotPresentFault(KPROCESSOR_MODE Mode,
275                            ULONG Address, 
276                            BOOLEAN FromMdl)
277 {
278    PMADDRESS_SPACE AddressSpace;
279    MEMORY_AREA* MemoryArea;
280    NTSTATUS Status;
281    BOOLEAN Locked = FromMdl;
282    
283    DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
284    
285    if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
286      {
287         DbgPrint("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
288         return(STATUS_UNSUCCESSFUL);
289      }
290    if (PsGetCurrentProcess() == NULL)
291      {
292         DbgPrint("No current process\n");
293         return(STATUS_UNSUCCESSFUL);
294      }
295    
296    /*
297     * Find the memory area for the faulting address
298     */
299    if (Address >= KERNEL_BASE)
300      {
301         /*
302          * Check permissions
303          */
304         if (Mode != KernelMode)
305           {
306              DbgPrint("%s:%d\n",__FILE__,__LINE__);
307              return(STATUS_UNSUCCESSFUL);
308           }
309         AddressSpace = MmGetKernelAddressSpace();
310      }
311    else
312      {
313         AddressSpace = &PsGetCurrentProcess()->AddressSpace;
314      }
315    
316    if (!FromMdl)
317      {
318        MmLockAddressSpace(AddressSpace);
319      }
320
321    /*
322     * Call the memory area specific fault handler
323     */
324    do
325      {
326        MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, (PVOID)Address);
327        if (MemoryArea == NULL)
328          {
329            if (!FromMdl)
330              {
331                MmUnlockAddressSpace(AddressSpace);
332              }
333            return (STATUS_UNSUCCESSFUL);
334          }
335
336        switch (MemoryArea->Type)
337          {
338          case MEMORY_AREA_PAGED_POOL:
339            {
340              Status = MmCommitPagedPoolAddress((PVOID)Address);
341              break;
342            }
343
344          case MEMORY_AREA_SYSTEM:
345            Status = STATUS_UNSUCCESSFUL;
346            break;
347            
348          case MEMORY_AREA_SECTION_VIEW:
349            Status = MmNotPresentFaultSectionView(AddressSpace,
350                                                  MemoryArea, 
351                                                  (PVOID)Address,
352                                                  Locked);
353            break;
354            
355          case MEMORY_AREA_VIRTUAL_MEMORY:
356            Status = MmNotPresentFaultVirtualMemory(AddressSpace,
357                                                    MemoryArea,
358                                                    (PVOID)Address,
359                                                    Locked);
360                break;
361                
362          case MEMORY_AREA_SHARED_DATA:
363            Status = 
364              MmCreateVirtualMapping(PsGetCurrentProcess(),
365                                     (PVOID)PAGE_ROUND_DOWN(Address),
366                                     PAGE_READONLY,
367                                     MmSharedDataPagePhysicalAddress,
368                                     FALSE);
369            if (!NT_SUCCESS(Status))
370              {
371                MmUnlockAddressSpace(&PsGetCurrentProcess()->AddressSpace);
372                Status = 
373                  MmCreateVirtualMapping(PsGetCurrentProcess(),
374                                         (PVOID)PAGE_ROUND_DOWN(Address),
375                                         PAGE_READONLY,
376                                         MmSharedDataPagePhysicalAddress,
377                                         TRUE);
378                MmLockAddressSpace(&PsGetCurrentProcess()->AddressSpace);
379              }
380            break;
381            
382          default:
383            Status = STATUS_UNSUCCESSFUL;
384            break;
385          }
386      }
387    while (Status == STATUS_MM_RESTART_OPERATION);
388
389    DPRINT("Completed page fault handling\n");
390    if (!FromMdl)
391      {
392        MmUnlockAddressSpace(AddressSpace);
393      }
394    return(Status);
395 }
396
397 /* Miscellanea functions: they may fit somewhere else */
398
399 DWORD STDCALL
400 MmAdjustWorkingSetSize (DWORD   Unknown0,
401                         DWORD   Unknown1,
402                         DWORD   Unknown2)
403 {
404         UNIMPLEMENTED;
405         return (0);
406 }
407
408
409 DWORD
410 STDCALL
411 MmDbgTranslatePhysicalAddress (
412         DWORD   Unknown0,
413         DWORD   Unknown1
414         )
415 {
416         UNIMPLEMENTED;
417         return (0);
418 }
419
420
421 NTSTATUS
422 STDCALL
423 MmGrowKernelStack (
424         DWORD   Unknown0
425         )
426 {
427         UNIMPLEMENTED;
428         return (STATUS_NOT_IMPLEMENTED);
429 }
430
431
432 BOOLEAN
433 STDCALL
434 MmSetAddressRangeModified (
435         DWORD   Unknown0,
436         DWORD   Unknown1
437         )
438 {
439         UNIMPLEMENTED;
440         return (FALSE);
441 }
442
443 /* EOF */