9a8ae3c9edacfd7ad652830ea4dfd441600645b3
[reactos.git] / reactos / boot / environ / lib / mm / mm.c
1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/mm/mm.c
5 * PURPOSE: Boot Library Memory Manager Core
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12 #include "bcd.h"
13
14 /* DATA VARIABLES ************************************************************/
15
16 BL_TRANSLATION_TYPE MmTranslationType, MmOriginalTranslationType;
17 ULONG MmDescriptorCallTreeCount;
18
19 /* FUNCTIONS *****************************************************************/
20
21 NTSTATUS
22 MmTrInitialize (
23 VOID
24 )
25 {
26 /* Nothing to track if we're using physical memory */
27 if (MmTranslationType == BlNone)
28 {
29 return STATUS_SUCCESS;
30 }
31
32 /* TODO */
33 EfiPrintf(L"Required for protected mode\r\n");
34 return STATUS_NOT_IMPLEMENTED;
35 }
36
37 NTSTATUS
38 BlMmRemoveBadMemory (
39 VOID
40 )
41 {
42 BOOLEAN AllowBad;
43 NTSTATUS Status;
44 PULONGLONG BadPages;
45 ULONGLONG BadPageCount;
46
47 /* First check if bad memory access is allowed */
48 AllowBad = FALSE;
49 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
50 BcdLibraryBoolean_AllowBadMemoryAccess,
51 &AllowBad);
52 if ((NT_SUCCESS(Status)) && (AllowBad))
53 {
54 /* No point checking the list if it is */
55 return STATUS_SUCCESS;
56 }
57
58 /* Otherwise, check if there's a persisted bad page list */
59 Status = BlpGetBootOptionIntegerList(BlpApplicationEntry.BcdData,
60 BcdLibraryIntegerList_BadMemoryList,
61 &BadPages,
62 &BadPageCount,
63 TRUE);
64 if (NT_SUCCESS(Status))
65 {
66 EfiPrintf(L"Persistent bad page list not supported\r\n");
67 return STATUS_NOT_IMPLEMENTED;
68 }
69
70 /* All done here */
71 return STATUS_SUCCESS;
72 }
73
74 NTSTATUS
75 MmSelectMappingAddress (
76 _Out_ PVOID* MappingAddress,
77 _In_ ULONGLONG Size,
78 _In_ ULONG AllocationAttributes,
79 _In_ ULONG Flags,
80 _In_ PHYSICAL_ADDRESS PhysicalAddress
81 )
82 {
83 /* Are we in physical mode? */
84 if (MmTranslationType == BlNone)
85 {
86 /* Just return the physical address as the mapping address */
87 *MappingAddress = (PVOID)PhysicalAddress.LowPart;
88 return STATUS_SUCCESS;
89 }
90
91 /* Have to allocate physical pages */
92 EfiPrintf(L"VM Todo\r\n");
93 return STATUS_NOT_IMPLEMENTED;
94 }
95
96 NTSTATUS
97 MmMapPhysicalAddress (
98 _Inout_ PPHYSICAL_ADDRESS PhysicalAddress,
99 _Out_ PVOID VirtualAddress,
100 _Inout_ PULONGLONG Size,
101 _In_ ULONG CacheAttributes
102 )
103 {
104 ULONGLONG MappingSize;
105
106 /* Fail if any parameters are missing */
107 if (!(PhysicalAddress) || !(VirtualAddress) || !(Size))
108 {
109 return STATUS_INVALID_PARAMETER;
110 }
111
112 /* Fail if the size is over 32-bits */
113 MappingSize = *Size;
114 if (MappingSize > 0xFFFFFFFF)
115 {
116 return STATUS_INVALID_PARAMETER;
117 }
118
119 /* Nothing to do if we're in physical mode */
120 if (MmTranslationType == BlNone)
121 {
122 return STATUS_SUCCESS;
123 }
124
125 /* Can't use virtual memory in real mode */
126 if (CurrentExecutionContext->Mode == BlRealMode)
127 {
128 return STATUS_UNSUCCESSFUL;
129 }
130
131 EfiPrintf(L"VM todo\r\n");
132 return STATUS_NOT_IMPLEMENTED;
133 }
134
135 NTSTATUS
136 BlMmMapPhysicalAddressEx (
137 _In_ PVOID* VirtualAddress,
138 _In_ ULONG Flags,
139 _In_ ULONGLONG Size,
140 _In_ PHYSICAL_ADDRESS PhysicalAddress
141 )
142 {
143 NTSTATUS Status;
144 PVOID MappingAddress;
145 PHYSICAL_ADDRESS MappedAddress;
146 PVOID MappedBase;
147 ULONGLONG MapSize;
148 UCHAR CacheAttributes;
149
150 /* Increase call depth */
151 ++MmDescriptorCallTreeCount;
152
153 /* Check if any parameters are missing */
154 if (!(VirtualAddress) || !(Size))
155 {
156 Status = STATUS_INVALID_PARAMETER;
157 goto Quickie;
158 }
159
160 /* Check for fixed allocation without an actual address */
161 if ((Flags & BlMemoryFixed) &&
162 (PhysicalAddress.QuadPart == -1) &&
163 !(*VirtualAddress))
164 {
165 Status = STATUS_INVALID_PARAMETER;
166 goto Quickie;
167 }
168
169 /* Check for invalid requirement flag, if one is present */
170 if (((Flags & BlMemoryValidAllocationAttributes) != BlMemoryFixed) &&
171 ((Flags & BlMemoryValidAllocationAttributes) != BlMemoryNonFixed) &&
172 (Flags & BlMemoryValidAllocationAttributes))
173 {
174 Status = STATUS_INVALID_PARAMETER;
175 goto Quickie;
176 }
177
178 /* Check for invalid cache attribute flags */
179 if (((Flags & BlMemoryValidCacheAttributeMask) - 1) &
180 (Flags & BlMemoryValidCacheAttributeMask))
181 {
182 Status = STATUS_INVALID_PARAMETER;
183 goto Quickie;
184 }
185
186 /* Select an address to map this at */
187 Status = MmSelectMappingAddress(&MappingAddress,
188 Size,
189 Flags & BlMemoryValidAllocationAttributes,
190 Flags,
191 PhysicalAddress);
192 if (!NT_SUCCESS(Status))
193 {
194 goto Quickie;
195 }
196
197 /* Map the selected address, using the appropriate caching attributes */
198 MappedAddress = PhysicalAddress;
199 MapSize = Size;
200 CacheAttributes = ((Flags & BlMemoryValidCacheAttributeMask) != 0x20) ?
201 (Flags & BlMemoryValidCacheAttributeMask) : 0;
202 Status = MmMapPhysicalAddress(&MappedAddress,
203 &MappingAddress,
204 &MapSize,
205 CacheAttributes);
206 if (!NT_SUCCESS(Status))
207 {
208 goto Quickie;
209 }
210
211 /* Compute the final address where the mapping was made */
212 MappedBase = (PVOID)((ULONG_PTR)MappingAddress +
213 PhysicalAddress.LowPart -
214 MappedAddress.LowPart);
215
216 /* Check if we're in physical or virtual mode */
217 if (MmTranslationType != BlNone)
218 {
219 /* For virtual memory, there's more to do */
220 EfiPrintf(L"VM not supported for mapping\r\n");
221 Status = STATUS_NOT_IMPLEMENTED;
222 goto Quickie;
223 }
224
225 /* Return the mapped virtual address */
226 Status = STATUS_SUCCESS;
227 *VirtualAddress = MappedBase;
228
229 Quickie:
230 /* Cleanup descriptors and reduce depth */
231 MmMdFreeGlobalDescriptors();
232 --MmDescriptorCallTreeCount;
233 return Status;
234 }
235
236 NTSTATUS
237 MmUnmapVirtualAddress (
238 _Inout_ PVOID* VirtualAddress,
239 _Inout_ PULONGLONG Size
240 )
241 {
242 NTSTATUS Status;
243
244 /* Make sure parameters were passed in and are valid */
245 if ((VirtualAddress) && (Size) && (*Size <= 0xFFFFFFFF))
246 {
247 /* Nothing to do if translation isn't active */
248 if (MmTranslationType == BlNone)
249 {
250 Status = STATUS_SUCCESS;
251 }
252
253 /* TODO */
254 Status = STATUS_NOT_IMPLEMENTED;
255 }
256 else
257 {
258 /* Fail */
259 Status = STATUS_INVALID_PARAMETER;
260 }
261
262 /* All done */
263 return Status;
264 }
265
266 NTSTATUS
267 BlMmUnmapVirtualAddressEx (
268 _In_ PVOID VirtualAddress,
269 _In_ ULONGLONG Size
270 )
271 {
272 NTSTATUS Status;
273
274 /* Increment call depth */
275 ++MmDescriptorCallTreeCount;
276
277 /* Make sure all parameters are there */
278 if ((VirtualAddress) && (Size))
279 {
280 /* Unmap the virtual address */
281 Status = MmUnmapVirtualAddress(&VirtualAddress, &Size);
282
283 /* Check if we actually had a virtual mapping active */
284 if ((NT_SUCCESS(Status)) && (MmTranslationType != BlNone))
285 {
286 /* TODO */
287 Status = STATUS_NOT_IMPLEMENTED;
288 }
289 }
290 else
291 {
292 /* Fail */
293 Status = STATUS_INVALID_PARAMETER;
294 }
295
296 /* Cleanup descriptors and reduce depth */
297 MmMdFreeGlobalDescriptors();
298 --MmDescriptorCallTreeCount;
299 return Status;
300 }
301
302 NTSTATUS
303 BlpMmInitialize (
304 _In_ PBL_MEMORY_DATA MemoryData,
305 _In_ BL_TRANSLATION_TYPE TranslationType,
306 _In_ PBL_LIBRARY_PARAMETERS LibraryParameters
307 )
308 {
309 NTSTATUS Status;
310
311 /* Take a reference */
312 MmDescriptorCallTreeCount = 1;
313
314 /* Only support valid translation types */
315 if ((TranslationType > BlPae) || (LibraryParameters->TranslationType > BlPae))
316 {
317 /* Bail out */
318 EfiPrintf(L"Invalid translation types present\r\n");
319 Status = STATUS_INVALID_PARAMETER;
320 goto Quickie;
321 }
322
323 /* Initialize memory descriptors */
324 MmMdInitialize(0, LibraryParameters);
325
326 /* Remember the page type we came in with */
327 MmOriginalTranslationType = TranslationType;
328
329 /* Initialize the physical page allocator */
330 Status = MmPaInitialize(MemoryData,
331 LibraryParameters->MinimumAllocationCount);
332 if (!NT_SUCCESS(Status))
333 {
334 goto Quickie;
335 }
336
337 /* Initialize the memory tracker */
338 Status = MmTrInitialize();
339 if (!NT_SUCCESS(Status))
340 {
341 //MmArchDestroy();
342 //MmPaDestroy(1);
343 goto Quickie;
344 }
345
346 /* Initialize paging, large pages, self-mapping, PAE, if needed */
347 Status = MmArchInitialize(1,
348 MemoryData,
349 TranslationType,
350 LibraryParameters->TranslationType);
351 if (NT_SUCCESS(Status))
352 {
353 /* Save the newly active transation type */
354 MmTranslationType = LibraryParameters->TranslationType;
355
356 /* Initialize the heap allocator now */
357 Status = MmHaInitialize(LibraryParameters->MinimumHeapSize,
358 LibraryParameters->HeapAllocationAttributes);
359 }
360
361 /* If Phase 1 init failed, bail out */
362 if (!NT_SUCCESS(Status))
363 {
364 /* Kill everything set setup so far */
365 //MmPaDestroy(0);
366 //MmTrDestroy();
367 //MmArchDestroy();
368 //MmPaDestroy(1);
369 goto Quickie;
370 }
371
372 /* Do we have too many descriptors? */
373 if (LibraryParameters->DescriptorCount > 512)
374 {
375 /* Switch to using a dynamic buffer instead */
376 EfiPrintf(L"Warning: too many descriptors\r\n");
377 Status = STATUS_NOT_IMPLEMENTED;
378 goto Quickie;
379 //MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
380 }
381
382 /* Remove memory that the BCD says is bad */
383 BlMmRemoveBadMemory();
384
385 /* Now map all the memory regions as needed */
386 Status = MmArchInitialize(2,
387 MemoryData,
388 TranslationType,
389 LibraryParameters->TranslationType);
390 if (NT_SUCCESS(Status))
391 {
392 /* Initialize the block allocator */
393 Status = MmBaInitialize();
394 }
395
396 /* Check if anything in phase 2 failed */
397 if (!NT_SUCCESS(Status))
398 {
399 /* Go back to static descriptors and kill the heap */
400 //MmMdpSwitchToStaticDescriptors();
401 //HapInitializationStatus = 0;
402 //++MmDescriptorCallTreeCount;
403
404 /* Destroy the Phase 1 initialization */
405 //MmPaDestroy(0);
406 //MmTrDestroy();
407 //MmArchDestroy();
408 //MmPaDestroy(1);
409 }
410
411 Quickie:
412 /* Free the memory descriptors and return the initialization state */
413 MmMdFreeGlobalDescriptors();
414 --MmDescriptorCallTreeCount;
415 return Status;
416 }