[BOOTLIB]: Clarify some attributes now that their meaning is clearer.
[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 /* This is a bug in Windows, but is required for MmTrInitialize to load */
17 BL_TRANSLATION_TYPE MmTranslationType = BlMax;
18 BL_TRANSLATION_TYPE MmOriginalTranslationType;
19 ULONG MmDescriptorCallTreeCount;
20
21 /* FUNCTIONS *****************************************************************/
22
23 NTSTATUS
24 MmTrInitialize (
25 VOID
26 )
27 {
28 PBL_MEMORY_DESCRIPTOR Descriptor;
29 NTSTATUS Status;
30 PLIST_ENTRY NextEntry;
31
32 /* Nothing to track if we're using physical memory */
33 if (MmTranslationType == BlNone)
34 {
35 return STATUS_SUCCESS;
36 }
37
38 /* Initialize all the virtual lists */
39 MmMdInitializeListHead(&MmMdlMappingTrackers);
40 MmMdlMappingTrackers.Type = BlMdTracker;
41 MmMdInitializeListHead(&MmMdlFreeVirtual);
42 MmMdlFreeVirtual.Type = BlMdVirtual;
43
44 /* Initialize a 4GB free descriptor */
45 Descriptor = MmMdInitByteGranularDescriptor(0,
46 BlConventionalMemory,
47 0,
48 0,
49 ((ULONGLONG)4 * 1024 * 1024 * 1024) >>
50 PAGE_SHIFT);
51 if (!Descriptor)
52 {
53 Status = STATUS_NO_MEMORY;
54 goto Quickie;
55 }
56
57 /* Add this 4GB region to the free virtual address space list */
58 Status = MmMdAddDescriptorToList(&MmMdlFreeVirtual,
59 Descriptor,
60 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG);
61 if (!NT_SUCCESS(Status))
62 {
63 RtlZeroMemory(Descriptor, sizeof(*Descriptor));
64 goto Quickie;
65 }
66
67 /* Remove any reserved regions of virtual address space */
68 NextEntry = MmMdlReservedAllocated.First->Flink;
69 while (NextEntry != MmMdlReservedAllocated.First)
70 {
71 /* Grab the descriptor and see if it's mapped */
72 Descriptor = CONTAINING_RECORD(NextEntry, BL_MEMORY_DESCRIPTOR, ListEntry);
73 if (Descriptor->VirtualPage)
74 {
75 EfiPrintf(L"Need to handle reserved allocation: %llx %llx\r\n",
76 Descriptor->VirtualPage, Descriptor->PageCount);
77 EfiStall(100000);
78 Status = STATUS_NOT_IMPLEMENTED;
79 goto Quickie;
80 }
81
82 /* Next entry */
83 NextEntry = NextEntry->Flink;
84 }
85
86 /* Set success if we made it */
87 Status = STATUS_SUCCESS;
88
89 Quickie:
90 /* Return back to caller */
91 return Status;
92 }
93
94 NTSTATUS
95 BlMmRemoveBadMemory (
96 VOID
97 )
98 {
99 BOOLEAN AllowBad;
100 NTSTATUS Status;
101 PULONGLONG BadPages;
102 ULONGLONG BadPageCount;
103
104 /* First check if bad memory access is allowed */
105 AllowBad = FALSE;
106 Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
107 BcdLibraryBoolean_AllowBadMemoryAccess,
108 &AllowBad);
109 if ((NT_SUCCESS(Status)) && (AllowBad))
110 {
111 /* No point checking the list if it is */
112 return STATUS_SUCCESS;
113 }
114
115 /* Otherwise, check if there's a persisted bad page list */
116 Status = BlpGetBootOptionIntegerList(BlpApplicationEntry.BcdData,
117 BcdLibraryIntegerList_BadMemoryList,
118 &BadPages,
119 &BadPageCount,
120 TRUE);
121 if (NT_SUCCESS(Status))
122 {
123 EfiPrintf(L"Persistent bad page list not supported\r\n");
124 return STATUS_NOT_IMPLEMENTED;
125 }
126
127 /* All done here */
128 return STATUS_SUCCESS;
129 }
130
131 NTSTATUS
132 BlMmMapPhysicalAddressEx (
133 _In_ PVOID* VirtualAddress,
134 _In_ ULONG Flags,
135 _In_ ULONGLONG Size,
136 _In_ PHYSICAL_ADDRESS PhysicalAddress
137 )
138 {
139 NTSTATUS Status;
140 PVOID MappingAddress;
141 PHYSICAL_ADDRESS MappedAddress;
142 PVOID MappedBase;
143 ULONGLONG MapSize;
144 UCHAR CacheAttributes;
145
146 /* Increase call depth */
147 ++MmDescriptorCallTreeCount;
148
149 /* Check if any parameters are missing */
150 if (!(VirtualAddress) || !(Size))
151 {
152 Status = STATUS_INVALID_PARAMETER;
153 goto Quickie;
154 }
155
156 /* Check for fixed allocation without an actual address */
157 if ((Flags & BlMemoryFixed) &&
158 (PhysicalAddress.QuadPart == -1) &&
159 !(*VirtualAddress))
160 {
161 Status = STATUS_INVALID_PARAMETER;
162 goto Quickie;
163 }
164
165 /* Check for invalid requirement flag, if one is present */
166 if (((Flags & BlMemoryValidAllocationAttributes) != BlMemoryFixed) &&
167 ((Flags & BlMemoryValidAllocationAttributes) != BlMemoryKernelRange) &&
168 (Flags & BlMemoryValidAllocationAttributes))
169 {
170 Status = STATUS_INVALID_PARAMETER;
171 goto Quickie;
172 }
173
174 /* Check for invalid cache attribute flags */
175 if (((Flags & BlMemoryValidCacheAttributeMask) - 1) &
176 (Flags & BlMemoryValidCacheAttributeMask))
177 {
178 Status = STATUS_INVALID_PARAMETER;
179 goto Quickie;
180 }
181
182 /* Select an address to map this at */
183 Status = MmSelectMappingAddress(&MappingAddress,
184 *VirtualAddress,
185 Size,
186 Flags & BlMemoryValidAllocationAttributes,
187 Flags,
188 PhysicalAddress);
189 if (!NT_SUCCESS(Status))
190 {
191 goto Quickie;
192 }
193
194 /* Map the selected address, using the appropriate caching attributes */
195 MappedAddress = PhysicalAddress;
196 MapSize = Size;
197 CacheAttributes = ((Flags & BlMemoryValidCacheAttributeMask) != 0x20) ?
198 (Flags & BlMemoryValidCacheAttributeMask) : 0;
199 EfiPrintf(L"Selected address: %p for %lx\r\n", MappingAddress, MappedAddress.LowPart);
200 Status = MmMapPhysicalAddress(&MappedAddress,
201 &MappingAddress,
202 &MapSize,
203 CacheAttributes);
204 if (!NT_SUCCESS(Status))
205 {
206 goto Quickie;
207 }
208
209 /* Compute the final address where the mapping was made */
210 MappedBase = (PVOID)((ULONG_PTR)MappingAddress +
211 PhysicalAddress.LowPart -
212 MappedAddress.LowPart);
213
214 /* Check if we're in physical or virtual mode */
215 if (MmTranslationType != BlNone)
216 {
217 /* We don't support virtual memory yet @TODO */
218 EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
219 EfiStall(1000000);
220 Status = STATUS_NOT_IMPLEMENTED;
221 goto Quickie;
222 }
223
224 /* Return the mapped virtual address */
225 Status = STATUS_SUCCESS;
226 *VirtualAddress = MappedBase;
227
228 Quickie:
229 /* Cleanup descriptors and reduce depth */
230 MmMdFreeGlobalDescriptors();
231 --MmDescriptorCallTreeCount;
232 return Status;
233 }
234
235 NTSTATUS
236 MmUnmapVirtualAddress (
237 _Inout_ PVOID* VirtualAddress,
238 _Inout_ PULONGLONG Size
239 )
240 {
241 NTSTATUS Status;
242
243 /* Make sure parameters were passed in and are valid */
244 if ((VirtualAddress) && (Size) && (*Size <= 0xFFFFFFFF))
245 {
246 /* Nothing to do if translation isn't active */
247 if (MmTranslationType == BlNone)
248 {
249 Status = STATUS_SUCCESS;
250 }
251 else
252 {
253 /* We don't support virtual memory yet @TODO */
254 EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
255 EfiStall(1000000);
256 Status = STATUS_NOT_IMPLEMENTED;
257 }
258 }
259 else
260 {
261 /* Fail */
262 Status = STATUS_INVALID_PARAMETER;
263 }
264
265 /* All done */
266 return Status;
267 }
268
269 NTSTATUS
270 BlMmUnmapVirtualAddressEx (
271 _In_ PVOID VirtualAddress,
272 _In_ ULONGLONG Size
273 )
274 {
275 NTSTATUS Status;
276
277 /* Increment call depth */
278 ++MmDescriptorCallTreeCount;
279
280 /* Make sure all parameters are there */
281 if ((VirtualAddress) && (Size))
282 {
283 /* Unmap the virtual address */
284 Status = MmUnmapVirtualAddress(&VirtualAddress, &Size);
285
286 /* Check if we actually had a virtual mapping active */
287 if ((NT_SUCCESS(Status)) && (MmTranslationType != BlNone))
288 {
289 /* We don't support virtual memory yet @TODO */
290 EfiPrintf(L"not yet implemented in %S\r\n", __FUNCTION__);
291 EfiStall(1000000);
292 Status = STATUS_NOT_IMPLEMENTED;
293 }
294 }
295 else
296 {
297 /* Fail */
298 Status = STATUS_INVALID_PARAMETER;
299 }
300
301 /* Cleanup descriptors and reduce depth */
302 MmMdFreeGlobalDescriptors();
303 --MmDescriptorCallTreeCount;
304 return Status;
305 }
306
307 BOOLEAN
308 BlMmTranslateVirtualAddress (
309 _In_ PVOID VirtualAddress,
310 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
311 )
312 {
313 /* Make sure arguments are present */
314 if (!(VirtualAddress) || !(PhysicalAddress))
315 {
316 return FALSE;
317 }
318
319 /* Do the architecture-specific translation */
320 return MmArchTranslateVirtualAddress(VirtualAddress, PhysicalAddress, NULL);
321 }
322
323 NTSTATUS
324 BlpMmInitialize (
325 _In_ PBL_MEMORY_DATA MemoryData,
326 _In_ BL_TRANSLATION_TYPE TranslationType,
327 _In_ PBL_LIBRARY_PARAMETERS LibraryParameters
328 )
329 {
330 NTSTATUS Status;
331
332 /* Take a reference */
333 MmDescriptorCallTreeCount = 1;
334
335 /* Only support valid translation types */
336 if ((TranslationType > BlPae) || (LibraryParameters->TranslationType > BlPae))
337 {
338 /* Bail out */
339 EfiPrintf(L"Invalid translation types present\r\n");
340 Status = STATUS_INVALID_PARAMETER;
341 goto Quickie;
342 }
343
344 /* Initialize memory descriptors */
345 MmMdInitialize(0, LibraryParameters);
346
347 /* Remember the page type we came in with */
348 MmOriginalTranslationType = TranslationType;
349
350 /* Initialize the physical page allocator */
351 Status = MmPaInitialize(MemoryData,
352 LibraryParameters->MinimumAllocationCount);
353 if (!NT_SUCCESS(Status))
354 {
355 goto Quickie;
356 }
357
358 /* Initialize the memory tracker */
359 Status = MmTrInitialize();
360 if (!NT_SUCCESS(Status))
361 {
362 EfiPrintf(L"TR Mm init failed: %lx\r\n", Status);
363 //MmArchDestroy();
364 //MmPaDestroy(1);
365 goto Quickie;
366 }
367
368 /* Initialize paging, large pages, self-mapping, PAE, if needed */
369 Status = MmArchInitialize(1,
370 MemoryData,
371 TranslationType,
372 LibraryParameters->TranslationType);
373 if (NT_SUCCESS(Status))
374 {
375 /* Save the newly active transation type */
376 MmTranslationType = LibraryParameters->TranslationType;
377
378 /* Initialize the heap allocator now */
379 Status = MmHaInitialize(LibraryParameters->MinimumHeapSize,
380 LibraryParameters->HeapAllocationAttributes);
381 }
382
383 /* If Phase 1 init failed, bail out */
384 if (!NT_SUCCESS(Status))
385 {
386 /* Kill everything set setup so far */
387 EfiPrintf(L"Phase 1 Mm init failed: %lx\r\n", Status);
388 //MmPaDestroy(0);
389 //MmTrDestroy();
390 //MmArchDestroy();
391 //MmPaDestroy(1);
392 goto Quickie;
393 }
394
395 /* Do we have too many descriptors? */
396 if (LibraryParameters->DescriptorCount > 512)
397 {
398 /* Switch to using a dynamic buffer instead */
399 EfiPrintf(L"Warning: too many descriptors\r\n");
400 Status = STATUS_NOT_IMPLEMENTED;
401 goto Quickie;
402 //MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
403 }
404
405 /* Remove memory that the BCD says is bad */
406 BlMmRemoveBadMemory();
407
408 /* Now map all the memory regions as needed */
409 Status = MmArchInitialize(2,
410 MemoryData,
411 TranslationType,
412 LibraryParameters->TranslationType);
413 if (NT_SUCCESS(Status))
414 {
415 /* Initialize the block allocator */
416 Status = MmBaInitialize();
417 }
418
419 /* Check if anything in phase 2 failed */
420 if (!NT_SUCCESS(Status))
421 {
422 /* Go back to static descriptors and kill the heap */
423 EfiPrintf(L"Phase 2 Mm init failed: %lx\r\n", Status);
424 //MmMdpSwitchToStaticDescriptors();
425 //HapInitializationStatus = 0;
426 //++MmDescriptorCallTreeCount;
427
428 /* Destroy the Phase 1 initialization */
429 //MmPaDestroy(0);
430 //MmTrDestroy();
431 //MmArchDestroy();
432 //MmPaDestroy(1);
433 }
434
435 Quickie:
436 /* Free the memory descriptors and return the initialization state */
437 MmMdFreeGlobalDescriptors();
438 --MmDescriptorCallTreeCount;
439 return Status;
440 }