xref: /reactos/ntoskrnl/mm/ARM3/mmsup.c (revision 9393fc32)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/mm/ARM3/mmsup.c
5  * PURPOSE:         ARM Memory Manager Support Routines
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define MODULE_INVOLVED_IN_ARM3
16 #include <mm/ARM3/miarm.h>
17 
18 /* GLOBALS ********************************************************************/
19 
20 SIZE_T MmMinimumWorkingSetSize;
21 SIZE_T MmMaximumWorkingSetSize;
22 SIZE_T MmPagesAboveWsMinimum;
23 
24 /* PUBLIC FUNCTIONS ***********************************************************/
25 
26 /*
27  * @unimplemented
28  */
29 NTSTATUS
30 NTAPI
31 MmMapUserAddressesToPage(IN PVOID BaseAddress,
32                          IN SIZE_T NumberOfBytes,
33                          IN PVOID PageAddress)
34 {
35     UNIMPLEMENTED;
36     return STATUS_NOT_IMPLEMENTED;
37 }
38 
39 /*
40  * @unimplemented
41  */
42 NTSTATUS
43 NTAPI
44 MmAdjustWorkingSetSize(IN SIZE_T WorkingSetMinimumInBytes,
45                        IN SIZE_T WorkingSetMaximumInBytes,
46                        IN ULONG SystemCache,
47                        IN BOOLEAN IncreaseOkay)
48 {
49     SIZE_T MinimumWorkingSetSize, MaximumWorkingSetSize;
50     SSIZE_T Delta;
51     PMMSUPPORT Ws;
52     NTSTATUS Status;
53 
54     /* Check for special case: empty the working set */
55     if ((WorkingSetMinimumInBytes == -1) &&
56         (WorkingSetMaximumInBytes == -1))
57     {
58         UNIMPLEMENTED;
59         return STATUS_NOT_IMPLEMENTED;
60     }
61 
62     /* Assume success */
63     Status = STATUS_SUCCESS;
64 
65     /* Get the working set and lock it */
66     Ws = &PsGetCurrentProcess()->Vm;
67     MiLockWorkingSet(PsGetCurrentThread(), Ws);
68 
69     /* Calculate the actual minimum and maximum working set size to set */
70     MinimumWorkingSetSize = (WorkingSetMinimumInBytes != 0) ?
71         (WorkingSetMinimumInBytes / PAGE_SIZE) : Ws->MinimumWorkingSetSize;
72     MaximumWorkingSetSize = (WorkingSetMaximumInBytes != 0) ?
73         (WorkingSetMaximumInBytes / PAGE_SIZE) : Ws->MaximumWorkingSetSize;
74 
75     /* Check if the new maximum exceeds the global maximum */
76     if (MaximumWorkingSetSize > MmMaximumWorkingSetSize)
77     {
78         MaximumWorkingSetSize = MmMaximumWorkingSetSize;
79         Status = STATUS_WORKING_SET_LIMIT_RANGE;
80     }
81 
82     /* Check if the new minimum is below the global minimum */
83     if (MinimumWorkingSetSize < MmMinimumWorkingSetSize)
84     {
85         MinimumWorkingSetSize = MmMinimumWorkingSetSize;
86         Status = STATUS_WORKING_SET_LIMIT_RANGE;
87     }
88 
89     /* Check if the new minimum exceeds the new maximum */
90     if (MinimumWorkingSetSize > MaximumWorkingSetSize)
91     {
92         DPRINT1("MinimumWorkingSetSize (%lu) > MaximumWorkingSetSize (%lu)\n",
93                 MinimumWorkingSetSize, MaximumWorkingSetSize);
94         Status = STATUS_BAD_WORKING_SET_LIMIT;
95         goto Cleanup;
96     }
97 
98     /* Calculate the minimum WS size adjustment and check if we increase */
99     Delta = MinimumWorkingSetSize - Ws->MinimumWorkingSetSize;
100     if (Delta > 0)
101     {
102         /* Is increasing ok? */
103         if (!IncreaseOkay)
104         {
105             DPRINT1("Privilege for WS size increase not held\n");
106             Status = STATUS_PRIVILEGE_NOT_HELD;
107             goto Cleanup;
108         }
109 
110         /* Check if the number of available pages is large enough */
111         if (((SIZE_T)Delta / 1024) > (MmAvailablePages - 128))
112         {
113             DPRINT1("Not enough available pages\n");
114             Status = STATUS_INSUFFICIENT_RESOURCES;
115             goto Cleanup;
116         }
117 
118         /* Check if there are enough resident available pages */
119         if ((SIZE_T)Delta >
120             (MmResidentAvailablePages - MmSystemLockPagesCount - 256))
121         {
122             DPRINT1("Not enough resident pages\n");
123             Status = STATUS_INSUFFICIENT_RESOURCES;
124             goto Cleanup;
125         }
126     }
127 
128     /* Update resident available pages */
129     if (Delta != 0)
130     {
131         InterlockedExchangeAddSizeT(&MmResidentAvailablePages, -Delta);
132     }
133 
134     /* Calculate new pages above minimum WS size */
135     Delta += max((SSIZE_T)Ws->WorkingSetSize - MinimumWorkingSetSize, 0);
136 
137     /* Subtract old pages above minimum WS size */
138     Delta -= max((SSIZE_T)Ws->WorkingSetSize - Ws->MinimumWorkingSetSize, 0);
139 
140     /* If it changed, add it to the global variable */
141     if (Delta != 0)
142     {
143         InterlockedExchangeAddSizeT(&MmPagesAboveWsMinimum, Delta);
144     }
145 
146     /* Set the new working set size */
147     Ws->MinimumWorkingSetSize = MinimumWorkingSetSize;
148     Ws->MaximumWorkingSetSize = MaximumWorkingSetSize;
149 
150 Cleanup:
151 
152     /* Unlock the working set and return the status */
153     MiUnlockWorkingSet(PsGetCurrentThread(), Ws);
154     return Status;
155 }
156 
157 /*
158  * @unimplemented
159  */
160 BOOLEAN
161 NTAPI
162 MmSetAddressRangeModified(IN PVOID Address,
163                           IN SIZE_T Length)
164 {
165    UNIMPLEMENTED;
166    return FALSE;
167 }
168 
169 /*
170  * @implemented
171  */
172 BOOLEAN
173 NTAPI
174 MmIsAddressValid(IN PVOID VirtualAddress)
175 {
176 #if _MI_PAGING_LEVELS >= 4
177     /* Check if the PXE is valid */
178     if (MiAddressToPxe(VirtualAddress)->u.Hard.Valid == 0) return FALSE;
179 #endif
180 
181 #if _MI_PAGING_LEVELS >= 3
182     /* Check if the PPE is valid */
183     if (MiAddressToPpe(VirtualAddress)->u.Hard.Valid == 0) return FALSE;
184 #endif
185 
186 #if _MI_PAGING_LEVELS >= 2
187     /* Check if the PDE is valid */
188     if (MiAddressToPde(VirtualAddress)->u.Hard.Valid == 0) return FALSE;
189 #endif
190 
191     /* Check if the PTE is valid */
192     if (MiAddressToPte(VirtualAddress)->u.Hard.Valid == 0) return FALSE;
193 
194     /* This address is valid now, but it will only stay so if the caller holds
195      * the PFN lock */
196     return TRUE;
197 }
198 
199 /*
200  * @unimplemented
201  */
202 BOOLEAN
203 NTAPI
204 MmIsNonPagedSystemAddressValid(IN PVOID VirtualAddress)
205 {
206     DPRINT1("WARNING: %s returns bogus result\n", __FUNCTION__);
207     return MmIsAddressValid(VirtualAddress);
208 }
209 
210 /*
211  * @unimplemented
212  */
213 NTSTATUS
214 NTAPI
215 MmSetBankedSection(IN HANDLE ProcessHandle,
216                    IN PVOID VirtualAddress,
217                    IN ULONG BankLength,
218                    IN BOOLEAN ReadWriteBank,
219                    IN PVOID BankRoutine,
220                    IN PVOID Context)
221 {
222     UNIMPLEMENTED;
223     return STATUS_NOT_IMPLEMENTED;
224 }
225 
226 /*
227  * @implemented
228  */
229 BOOLEAN
230 NTAPI
231 MmIsRecursiveIoFault(VOID)
232 {
233     PETHREAD Thread = PsGetCurrentThread();
234 
235     //
236     // If any of these is true, this is a recursive fault
237     //
238     return ((Thread->DisablePageFaultClustering) | (Thread->ForwardClusterOnly));
239 }
240 
241 /*
242  * @implemented
243  */
244 BOOLEAN
245 NTAPI
246 MmIsThisAnNtAsSystem(VOID)
247 {
248     /* Return if this is a server system */
249     return MmProductType & 0xFF;
250 }
251 
252 /*
253  * @implemented
254  */
255 MM_SYSTEMSIZE
256 NTAPI
257 MmQuerySystemSize(VOID)
258 {
259     /* Return the low, medium or high memory system type */
260     return MmSystemSize;
261 }
262 
263 NTSTATUS
264 NTAPI
265 MmCreateMirror(VOID)
266 {
267     UNIMPLEMENTED;
268     return STATUS_NOT_IMPLEMENTED;
269 }
270 
271 /* EOF */
272