Sync with trunk r58740.
[reactos.git] / drivers / sac / driver / memory.c
1 /*
2 * PROJECT: ReactOS Boot Loader
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/sac/driver/memory.c
5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "sacdrv.h"
12
13 /* GLOBALS ********************************************************************/
14
15 LONG TotalFrees, TotalBytesFreed, TotalAllocations, TotalBytesAllocated;
16 KSPIN_LOCK MemoryLock;
17 PSAC_MEMORY_LIST GlobalMemoryList;
18
19 /* FUNCTIONS ******************************************************************/
20
21 BOOLEAN
22 InitializeMemoryManagement(VOID)
23 {
24 PSAC_MEMORY_ENTRY Entry;
25
26 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
27
28 GlobalMemoryList = ExAllocatePoolWithTagPriority(
29 NonPagedPool,
30 SAC_MEMORY_LIST_SIZE,
31 INITIAL_BLOCK_TAG,
32 HighPoolPriority);
33 if (GlobalMemoryList)
34 {
35 KeInitializeSpinLock(&MemoryLock);
36
37 GlobalMemoryList->Signature = GLOBAL_MEMORY_SIGNATURE;
38 GlobalMemoryList->LocalDescriptor =
39 (PSAC_MEMORY_ENTRY)(GlobalMemoryList + 1);
40 GlobalMemoryList->Size = SAC_MEMORY_LIST_SIZE - sizeof(SAC_MEMORY_LIST);
41
42 Entry = GlobalMemoryList->LocalDescriptor;
43 Entry->Signature = LOCAL_MEMORY_SIGNATURE;
44 Entry->Tag = FREE_POOL_TAG;
45 Entry->Size = GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY);
46
47 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with TRUE.\n");
48 return TRUE;
49 }
50
51 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with FALSE. No pool.\n");
52 return FALSE;
53 }
54
55 VOID
56 FreeMemoryManagement(
57 VOID
58 )
59 {
60 PSAC_MEMORY_LIST Next;
61 KIRQL OldIrql;
62
63 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n");
64
65 KeAcquireSpinLock(&MemoryLock, &OldIrql);
66 while (GlobalMemoryList)
67 {
68 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE);
69
70 KeReleaseSpinLock(&MemoryLock, OldIrql);
71
72 Next = GlobalMemoryList->Next;
73
74 ExFreePoolWithTag(GlobalMemoryList, 0);
75
76 KeAcquireSpinLock(&MemoryLock, &OldIrql);
77 GlobalMemoryList = Next;
78 }
79
80 KeReleaseSpinLock(&MemoryLock, OldIrql);
81 SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting\n");
82 }
83
84 PVOID
85 MyAllocatePool(
86 IN SIZE_T PoolSize,
87 IN ULONG Tag,
88 IN PCHAR File,
89 IN ULONG Line
90 )
91 {
92 KIRQL OldIrql;
93 PSAC_MEMORY_LIST GlobalDescriptor, NewDescriptor;
94 PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor;
95 ULONG GlobalSize, ActualSize;
96 PVOID Buffer;
97
98 ASSERT("Tag != FREE_POOL_TAG");
99
100 SAC_DBG(SAC_DBG_MM, "Entering.\n");
101
102 OldIrql = KfAcquireSpinLock(&MemoryLock);
103 PoolSize = ALIGN_UP(PoolSize, ULONGLONG);
104
105 GlobalDescriptor = GlobalMemoryList;
106 KeAcquireSpinLock(&MemoryLock, &OldIrql);
107 while (GlobalDescriptor)
108 {
109 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE);
110
111 LocalDescriptor = GlobalDescriptor->LocalDescriptor;
112
113 GlobalSize = GlobalDescriptor->Size;
114 while (GlobalSize)
115 {
116 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
117
118 if ((LocalDescriptor->Tag == FREE_POOL_TAG) &&
119 (LocalDescriptor->Size >= PoolSize))
120 {
121 break;
122 }
123
124 GlobalSize -= (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY));
125
126 LocalDescriptor =
127 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor +
128 LocalDescriptor->Size +
129 sizeof(SAC_MEMORY_ENTRY));
130 }
131
132 GlobalDescriptor = GlobalDescriptor->Next;
133 }
134
135 if (!GlobalDescriptor)
136 {
137 KeReleaseSpinLock(&MemoryLock, OldIrql);
138
139 ActualSize = min(
140 PAGE_SIZE,
141 PoolSize + sizeof(SAC_MEMORY_ENTRY) + sizeof(SAC_MEMORY_LIST));
142
143 SAC_DBG(SAC_DBG_MM, "Allocating new space.\n");
144
145 NewDescriptor = ExAllocatePoolWithTagPriority(
146 0,
147 ActualSize,
148 ALLOC_BLOCK_TAG,
149 HighPoolPriority);
150 if (!NewDescriptor)
151 {
152 SAC_DBG(SAC_DBG_MM, "No more memory, returning NULL.\n");
153 return NULL;
154 }
155
156 KeAcquireSpinLock(&MemoryLock, &OldIrql);
157
158 NewDescriptor->Signature = GLOBAL_MEMORY_SIGNATURE;
159 NewDescriptor->LocalDescriptor = (PSAC_MEMORY_ENTRY)(NewDescriptor + 1);
160 NewDescriptor->Size = ActualSize - 16;
161 NewDescriptor->Next = GlobalMemoryList;
162
163 GlobalMemoryList = NewDescriptor;
164
165 LocalDescriptor = NewDescriptor->LocalDescriptor;
166 LocalDescriptor->Signature = LOCAL_MEMORY_SIGNATURE;
167 LocalDescriptor->Tag = FREE_POOL_TAG;
168 LocalDescriptor->Size =
169 GlobalMemoryList->Size - sizeof(SAC_MEMORY_ENTRY);
170 }
171
172 SAC_DBG(SAC_DBG_MM, "Found a good sized block.\n");
173 ASSERT(LocalDescriptor->Tag == FREE_POOL_TAG);
174 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
175
176 if (LocalDescriptor->Size > (PoolSize + sizeof(SAC_MEMORY_ENTRY)))
177 {
178 NextDescriptor =
179 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor +
180 PoolSize +
181 sizeof(SAC_MEMORY_ENTRY));
182 if (NextDescriptor->Tag == FREE_POOL_TAG)
183 {
184 NextDescriptor->Tag = FREE_POOL_TAG;
185 NextDescriptor->Signature = LOCAL_MEMORY_SIGNATURE;
186 NextDescriptor->Size =
187 (LocalDescriptor->Size - PoolSize - sizeof(SAC_MEMORY_ENTRY));
188
189 LocalDescriptor->Size = PoolSize;
190 }
191 }
192
193 LocalDescriptor->Tag = Tag;
194 KeReleaseSpinLock(&MemoryLock, OldIrql);
195
196 InterlockedIncrement(&TotalAllocations);
197 InterlockedExchangeAdd(&TotalBytesAllocated, LocalDescriptor->Size);
198 SAC_DBG(1, "Returning block 0x%X.\n", LocalDescriptor);
199
200 Buffer = LocalDescriptor + 1;
201 RtlZeroMemory(Buffer, PoolSize);
202 return Buffer;
203 }
204
205 VOID
206 MyFreePool(
207 IN PVOID *Block
208 )
209 {
210 PSAC_MEMORY_ENTRY LocalDescriptor, NextDescriptor;
211 PSAC_MEMORY_ENTRY ThisDescriptor, FoundDescriptor;
212 ULONG GlobalSize, LocalSize;
213 PSAC_MEMORY_LIST GlobalDescriptor;
214 KIRQL OldIrql;
215
216 LocalDescriptor = (PVOID)((ULONG_PTR)(*Block) - sizeof(SAC_MEMORY_ENTRY));
217
218 SAC_DBG(SAC_DBG_MM, "Entering with block 0x%X.\n", LocalDescriptor);
219
220 ASSERT(LocalDescriptor->Size > 0);
221 ASSERT(LocalDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
222
223 InterlockedIncrement(&TotalFrees);
224
225 InterlockedExchangeAdd(&TotalBytesFreed, LocalDescriptor->Size);
226
227 GlobalDescriptor = GlobalMemoryList;
228 KeAcquireSpinLock(&MemoryLock, &OldIrql);
229 while (GlobalDescriptor)
230 {
231 ASSERT(GlobalMemoryList->Signature == GLOBAL_MEMORY_SIGNATURE);
232
233 FoundDescriptor = NULL;
234
235 ThisDescriptor = GlobalDescriptor->LocalDescriptor;
236
237 GlobalSize = GlobalDescriptor->Size;
238 while (GlobalSize)
239 {
240 ASSERT(ThisDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
241
242 if (ThisDescriptor == LocalDescriptor) break;
243
244 GlobalSize -= (ThisDescriptor->Size + sizeof(SAC_MEMORY_ENTRY));
245
246 ThisDescriptor =
247 (PSAC_MEMORY_ENTRY)((ULONG_PTR)ThisDescriptor +
248 ThisDescriptor->Size +
249 sizeof(SAC_MEMORY_ENTRY));
250 }
251
252 if (ThisDescriptor == LocalDescriptor) break;
253
254 GlobalDescriptor = GlobalDescriptor->Next;
255 }
256
257 if (!GlobalDescriptor)
258 {
259 KeReleaseSpinLock(&MemoryLock, OldIrql);
260 SAC_DBG(SAC_DBG_MM, "Could not find block.\n");
261 return;
262 }
263
264 ASSERT(ThisDescriptor->Signature == LOCAL_MEMORY_SIGNATURE);
265
266 if (LocalDescriptor->Tag == FREE_POOL_TAG)
267 {
268 KeReleaseSpinLock(&MemoryLock, OldIrql);
269 SAC_DBG(SAC_DBG_MM, "Attempted to free something twice.\n");
270 return;
271 }
272
273 LocalSize = LocalDescriptor->Size;
274 LocalDescriptor->Tag = FREE_POOL_TAG;
275
276 if (GlobalSize > (LocalSize + sizeof(SAC_MEMORY_ENTRY)))
277 {
278 NextDescriptor =
279 (PSAC_MEMORY_ENTRY)((ULONG_PTR)LocalDescriptor +
280 LocalSize +
281 sizeof(SAC_MEMORY_ENTRY));
282 if (NextDescriptor->Tag == FREE_POOL_TAG)
283 {
284 NextDescriptor->Tag = 0;
285 NextDescriptor->Signature = 0;
286
287 LocalDescriptor->Size +=
288 (NextDescriptor->Size + sizeof(SAC_MEMORY_ENTRY));
289 }
290 }
291
292 if ((FoundDescriptor) && (FoundDescriptor->Tag == FREE_POOL_TAG))
293 {
294 LocalDescriptor->Signature = 0;
295 LocalDescriptor->Tag = 0;
296
297 FoundDescriptor->Size +=
298 (LocalDescriptor->Size + sizeof(SAC_MEMORY_ENTRY));
299 }
300
301 KeReleaseSpinLock(&MemoryLock, OldIrql);
302 *Block = NULL;
303
304 SAC_DBG(SAC_DBG_MM, "exiting.\n");
305 return;
306 }