[BOOTLIB]: Implement MmPaReserveSelfMapPages, MmPaReleaseSelfMapPages
[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 MmSelectMappingAddress (
133 _Out_ PVOID* MappingAddress,
134 _In_ ULONGLONG Size,
135 _In_ ULONG AllocationAttributes,
136 _In_ ULONG Flags,
137 _In_ PHYSICAL_ADDRESS PhysicalAddress
138 )
139 {
140 /* Are we in physical mode? */
141 if (MmTranslationType == BlNone)
142 {
143 /* Just return the physical address as the mapping address */
144 *MappingAddress = (PVOID)PhysicalAddress.LowPart;
145 return STATUS_SUCCESS;
146 }
147
148 /* Have to allocate physical pages */
149 EfiPrintf(L"VM Todo\r\n");
150 return STATUS_NOT_IMPLEMENTED;
151 }
152
153 NTSTATUS
154 MmMapPhysicalAddress (
155 _Inout_ PPHYSICAL_ADDRESS PhysicalAddress,
156 _Out_ PVOID VirtualAddress,
157 _Inout_ PULONGLONG Size,
158 _In_ ULONG CacheAttributes
159 )
160 {
161 ULONGLONG MappingSize;
162
163 /* Fail if any parameters are missing */
164 if (!(PhysicalAddress) || !(VirtualAddress) || !(Size))
165 {
166 return STATUS_INVALID_PARAMETER;
167 }
168
169 /* Fail if the size is over 32-bits */
170 MappingSize = *Size;
171 if (MappingSize > 0xFFFFFFFF)
172 {
173 return STATUS_INVALID_PARAMETER;
174 }
175
176 /* Nothing to do if we're in physical mode */
177 if (MmTranslationType == BlNone)
178 {
179 return STATUS_SUCCESS;
180 }
181
182 /* Can't use virtual memory in real mode */
183 if (CurrentExecutionContext->Mode == BlRealMode)
184 {
185 return STATUS_UNSUCCESSFUL;
186 }
187
188 EfiPrintf(L"VM todo\r\n");
189 return STATUS_NOT_IMPLEMENTED;
190 }
191
192 NTSTATUS
193 BlMmMapPhysicalAddressEx (
194 _In_ PVOID* VirtualAddress,
195 _In_ ULONG Flags,
196 _In_ ULONGLONG Size,
197 _In_ PHYSICAL_ADDRESS PhysicalAddress
198 )
199 {
200 NTSTATUS Status;
201 PVOID MappingAddress;
202 PHYSICAL_ADDRESS MappedAddress;
203 PVOID MappedBase;
204 ULONGLONG MapSize;
205 UCHAR CacheAttributes;
206
207 /* Increase call depth */
208 ++MmDescriptorCallTreeCount;
209
210 /* Check if any parameters are missing */
211 if (!(VirtualAddress) || !(Size))
212 {
213 Status = STATUS_INVALID_PARAMETER;
214 goto Quickie;
215 }
216
217 /* Check for fixed allocation without an actual address */
218 if ((Flags & BlMemoryFixed) &&
219 (PhysicalAddress.QuadPart == -1) &&
220 !(*VirtualAddress))
221 {
222 Status = STATUS_INVALID_PARAMETER;
223 goto Quickie;
224 }
225
226 /* Check for invalid requirement flag, if one is present */
227 if (((Flags & BlMemoryValidAllocationAttributes) != BlMemoryFixed) &&
228 ((Flags & BlMemoryValidAllocationAttributes) != BlMemoryNonFixed) &&
229 (Flags & BlMemoryValidAllocationAttributes))
230 {
231 Status = STATUS_INVALID_PARAMETER;
232 goto Quickie;
233 }
234
235 /* Check for invalid cache attribute flags */
236 if (((Flags & BlMemoryValidCacheAttributeMask) - 1) &
237 (Flags & BlMemoryValidCacheAttributeMask))
238 {
239 Status = STATUS_INVALID_PARAMETER;
240 goto Quickie;
241 }
242
243 /* Select an address to map this at */
244 Status = MmSelectMappingAddress(&MappingAddress,
245 Size,
246 Flags & BlMemoryValidAllocationAttributes,
247 Flags,
248 PhysicalAddress);
249 if (!NT_SUCCESS(Status))
250 {
251 goto Quickie;
252 }
253
254 /* Map the selected address, using the appropriate caching attributes */
255 MappedAddress = PhysicalAddress;
256 MapSize = Size;
257 CacheAttributes = ((Flags & BlMemoryValidCacheAttributeMask) != 0x20) ?
258 (Flags & BlMemoryValidCacheAttributeMask) : 0;
259 Status = MmMapPhysicalAddress(&MappedAddress,
260 &MappingAddress,
261 &MapSize,
262 CacheAttributes);
263 if (!NT_SUCCESS(Status))
264 {
265 goto Quickie;
266 }
267
268 /* Compute the final address where the mapping was made */
269 MappedBase = (PVOID)((ULONG_PTR)MappingAddress +
270 PhysicalAddress.LowPart -
271 MappedAddress.LowPart);
272
273 /* Check if we're in physical or virtual mode */
274 if (MmTranslationType != BlNone)
275 {
276 /* For virtual memory, there's more to do */
277 EfiPrintf(L"VM not supported for mapping\r\n");
278 Status = STATUS_NOT_IMPLEMENTED;
279 goto Quickie;
280 }
281
282 /* Return the mapped virtual address */
283 Status = STATUS_SUCCESS;
284 *VirtualAddress = MappedBase;
285
286 Quickie:
287 /* Cleanup descriptors and reduce depth */
288 MmMdFreeGlobalDescriptors();
289 --MmDescriptorCallTreeCount;
290 return Status;
291 }
292
293 NTSTATUS
294 MmUnmapVirtualAddress (
295 _Inout_ PVOID* VirtualAddress,
296 _Inout_ PULONGLONG Size
297 )
298 {
299 NTSTATUS Status;
300
301 /* Make sure parameters were passed in and are valid */
302 if ((VirtualAddress) && (Size) && (*Size <= 0xFFFFFFFF))
303 {
304 /* Nothing to do if translation isn't active */
305 if (MmTranslationType == BlNone)
306 {
307 Status = STATUS_SUCCESS;
308 }
309
310 /* TODO */
311 Status = STATUS_NOT_IMPLEMENTED;
312 }
313 else
314 {
315 /* Fail */
316 Status = STATUS_INVALID_PARAMETER;
317 }
318
319 /* All done */
320 return Status;
321 }
322
323 NTSTATUS
324 BlMmUnmapVirtualAddressEx (
325 _In_ PVOID VirtualAddress,
326 _In_ ULONGLONG Size
327 )
328 {
329 NTSTATUS Status;
330
331 /* Increment call depth */
332 ++MmDescriptorCallTreeCount;
333
334 /* Make sure all parameters are there */
335 if ((VirtualAddress) && (Size))
336 {
337 /* Unmap the virtual address */
338 Status = MmUnmapVirtualAddress(&VirtualAddress, &Size);
339
340 /* Check if we actually had a virtual mapping active */
341 if ((NT_SUCCESS(Status)) && (MmTranslationType != BlNone))
342 {
343 /* TODO */
344 EfiPrintf(L"unhandled virtual path\r\n");
345 Status = STATUS_NOT_IMPLEMENTED;
346 }
347 }
348 else
349 {
350 /* Fail */
351 Status = STATUS_INVALID_PARAMETER;
352 }
353
354 /* Cleanup descriptors and reduce depth */
355 MmMdFreeGlobalDescriptors();
356 --MmDescriptorCallTreeCount;
357 return Status;
358 }
359
360 BOOLEAN
361 BlMmTranslateVirtualAddress (
362 _In_ PVOID VirtualAddress,
363 _Out_ PPHYSICAL_ADDRESS PhysicalAddress
364 )
365 {
366 /* Make sure arguments are present */
367 if (!(VirtualAddress) || !(PhysicalAddress))
368 {
369 return FALSE;
370 }
371
372 /* Do the architecture-specific translation */
373 return MmArchTranslateVirtualAddress(VirtualAddress, PhysicalAddress, NULL);
374 }
375
376 NTSTATUS
377 BlpMmInitialize (
378 _In_ PBL_MEMORY_DATA MemoryData,
379 _In_ BL_TRANSLATION_TYPE TranslationType,
380 _In_ PBL_LIBRARY_PARAMETERS LibraryParameters
381 )
382 {
383 NTSTATUS Status;
384
385 /* Take a reference */
386 MmDescriptorCallTreeCount = 1;
387
388 /* Only support valid translation types */
389 if ((TranslationType > BlPae) || (LibraryParameters->TranslationType > BlPae))
390 {
391 /* Bail out */
392 EfiPrintf(L"Invalid translation types present\r\n");
393 Status = STATUS_INVALID_PARAMETER;
394 goto Quickie;
395 }
396
397 /* Initialize memory descriptors */
398 MmMdInitialize(0, LibraryParameters);
399
400 /* Remember the page type we came in with */
401 MmOriginalTranslationType = TranslationType;
402
403 /* Initialize the physical page allocator */
404 Status = MmPaInitialize(MemoryData,
405 LibraryParameters->MinimumAllocationCount);
406 if (!NT_SUCCESS(Status))
407 {
408 goto Quickie;
409 }
410
411 /* Initialize the memory tracker */
412 Status = MmTrInitialize();
413 if (!NT_SUCCESS(Status))
414 {
415 EfiPrintf(L"TR Mm init failed: %lx\r\n", Status);
416 //MmArchDestroy();
417 //MmPaDestroy(1);
418 goto Quickie;
419 }
420
421 /* Initialize paging, large pages, self-mapping, PAE, if needed */
422 Status = MmArchInitialize(1,
423 MemoryData,
424 TranslationType,
425 LibraryParameters->TranslationType);
426 if (NT_SUCCESS(Status))
427 {
428 /* Save the newly active transation type */
429 MmTranslationType = LibraryParameters->TranslationType;
430
431 /* Initialize the heap allocator now */
432 Status = MmHaInitialize(LibraryParameters->MinimumHeapSize,
433 LibraryParameters->HeapAllocationAttributes);
434 }
435
436 /* If Phase 1 init failed, bail out */
437 if (!NT_SUCCESS(Status))
438 {
439 /* Kill everything set setup so far */
440 EfiPrintf(L"Phase 1 Mm init failed: %lx\r\n", Status);
441 //MmPaDestroy(0);
442 //MmTrDestroy();
443 //MmArchDestroy();
444 //MmPaDestroy(1);
445 goto Quickie;
446 }
447
448 /* Do we have too many descriptors? */
449 if (LibraryParameters->DescriptorCount > 512)
450 {
451 /* Switch to using a dynamic buffer instead */
452 EfiPrintf(L"Warning: too many descriptors\r\n");
453 Status = STATUS_NOT_IMPLEMENTED;
454 goto Quickie;
455 //MmMdpSwitchToDynamicDescriptors(LibraryParameters->DescriptorCount);
456 }
457
458 /* Remove memory that the BCD says is bad */
459 BlMmRemoveBadMemory();
460
461 /* Now map all the memory regions as needed */
462 Status = MmArchInitialize(2,
463 MemoryData,
464 TranslationType,
465 LibraryParameters->TranslationType);
466 if (NT_SUCCESS(Status))
467 {
468 /* Initialize the block allocator */
469 Status = MmBaInitialize();
470 }
471
472 /* Check if anything in phase 2 failed */
473 if (!NT_SUCCESS(Status))
474 {
475 /* Go back to static descriptors and kill the heap */
476 EfiPrintf(L"Phase 2 Mm init failed: %lx\r\n", Status);
477 //MmMdpSwitchToStaticDescriptors();
478 //HapInitializationStatus = 0;
479 //++MmDescriptorCallTreeCount;
480
481 /* Destroy the Phase 1 initialization */
482 //MmPaDestroy(0);
483 //MmTrDestroy();
484 //MmArchDestroy();
485 //MmPaDestroy(1);
486 }
487
488 Quickie:
489 /* Free the memory descriptors and return the initialization state */
490 MmMdFreeGlobalDescriptors();
491 --MmDescriptorCallTreeCount;
492 return Status;
493 }