OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
MemoryMap.c
Go to the documentation of this file.
1
15#include <Uefi.h>
16
17#include <Guid/MemoryAttributesTable.h>
18#include <Library/BaseMemoryLib.h>
19#include <Library/BaseOverflowLib.h>
20#include <Library/DebugLib.h>
21#include <Library/MemoryAllocationLib.h>
22#include <Library/OcMemoryLib.h>
23#include <Library/UefiBootServicesTableLib.h>
24#include <Library/UefiLib.h>
25
27 {
28 "Reserved",
29 EfiReservedMemoryType
30 },
31 {
32 "LoaderCode",
33 EfiLoaderCode
34 },
35 {
36 "LoaderData",
37 EfiLoaderData
38 },
39 {
40 "BootServiceCode",
41 EfiBootServicesCode
42 },
43 {
44 "BootServiceData",
45 EfiBootServicesData
46 },
47 {
48 "RuntimeCode",
49 EfiRuntimeServicesCode
50 },
51 {
52 "RuntimeData",
53 EfiRuntimeServicesData
54 },
55 {
56 "Available",
57 EfiConventionalMemory
58 },
59 {
60 "Persistent",
61 EfiPersistentMemory
62 },
63 {
64 "UnusableMemory",
65 EfiUnusableMemory
66 },
67 {
68 "ACPIReclaimMemory",
69 EfiACPIReclaimMemory
70 },
71 {
72 "ACPIMemoryNVS",
73 EfiACPIMemoryNVS
74 },
75 {
76 "MemoryMappedIO",
77 EfiMemoryMappedIO
78 },
79 {
80 "MemoryMappedIOPortSpace",
81 EfiMemoryMappedIOPortSpace
82 },
83 {
84 "PalCode",
85 EfiPalCode
86 }
87};
88
89EFI_STATUS
91 IN CHAR8 *MemoryTypeDesc,
92 OUT EFI_MEMORY_TYPE *MemoryType
93 )
94{
95 UINTN Index;
96 EFI_STATUS Status = EFI_INVALID_PARAMETER;
97
98 if ((MemoryTypeDesc != NULL) && (MemoryType != NULL)) {
99 for (Index = 0; Index < OC_MEMORY_TYPE_DESC_COUNT; Index++) {
100 if (AsciiStrCmp (MemoryTypeDesc, OcMemoryTypeString[Index].Name) == 0) {
101 Status = EFI_SUCCESS;
102 *MemoryType = OcMemoryTypeString[Index].Type;
103 break;
104 }
105 }
106
107 if (EFI_ERROR (Status)) {
108 Status = EFI_NOT_FOUND;
109 }
110 }
111
112 return Status;
113}
114
115EFI_MEMORY_DESCRIPTOR *
117 OUT UINTN *MemoryMapSize,
118 OUT UINTN *DescriptorSize,
119 OUT UINTN *MapKey OPTIONAL,
120 OUT UINT32 *DescriptorVersion OPTIONAL,
121 OUT UINTN *OriginalMemoryMapSize OPTIONAL,
122 IN BOOLEAN IncludeSplitSpace
123 )
124{
125 EFI_MEMORY_DESCRIPTOR *MemoryMap;
126 EFI_STATUS Status;
127 UINTN MapKeyValue;
128 UINTN OriginalSize;
129 UINTN ExtraSize;
130 UINT32 DescriptorVersionValue;
131 BOOLEAN Result;
132
133 *MemoryMapSize = 0;
134 Status = gBS->GetMemoryMap (
135 MemoryMapSize,
136 NULL,
137 &MapKeyValue,
138 DescriptorSize,
139 &DescriptorVersionValue
140 );
141
142 if (Status != EFI_BUFFER_TOO_SMALL) {
143 return NULL;
144 }
145
146 if (IncludeSplitSpace) {
147 ExtraSize = OcCountSplitDescriptors () * *DescriptorSize;
148 } else {
149 ExtraSize = 0;
150 }
151
152 //
153 // Apple uses 1024 as constant, however it will grow by at least
154 // DescriptorSize.
155 //
156 Result = BaseOverflowAddUN (
157 *MemoryMapSize,
158 MAX (*DescriptorSize + ExtraSize, 1024 + ExtraSize),
159 MemoryMapSize
160 );
161
162 if (Result) {
163 return NULL;
164 }
165
166 OriginalSize = *MemoryMapSize;
167 MemoryMap = AllocatePool (OriginalSize);
168 if (MemoryMap == NULL) {
169 return NULL;
170 }
171
172 Status = gBS->GetMemoryMap (
173 MemoryMapSize,
174 MemoryMap,
175 &MapKeyValue,
176 DescriptorSize,
177 &DescriptorVersionValue
178 );
179
180 if (EFI_ERROR (Status)) {
181 FreePool (MemoryMap);
182 return NULL;
183 }
184
185 if (MapKey != NULL) {
186 *MapKey = MapKeyValue;
187 }
188
189 if (DescriptorVersion != NULL) {
190 *DescriptorVersion = DescriptorVersionValue;
191 }
192
193 if (OriginalMemoryMapSize != NULL) {
194 *OriginalMemoryMapSize = OriginalSize;
195 }
196
197 return MemoryMap;
198}
199
200EFI_STATUS
202 OUT UINTN *MemoryMapSize,
203 OUT EFI_MEMORY_DESCRIPTOR **MemoryMap,
204 OUT UINTN *MapKey,
205 OUT UINTN *DescriptorSize,
206 OUT UINT32 *DescriptorVersion,
207 IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL,
208 IN OUT EFI_PHYSICAL_ADDRESS *TopMemory OPTIONAL
209 )
210{
211 EFI_STATUS Status;
212 EFI_PHYSICAL_ADDRESS MemoryMapAlloc;
213
214 *MemoryMapSize = 0;
215 *MemoryMap = NULL;
216
217 if (GetMemoryMap == NULL) {
218 GetMemoryMap = gBS->GetMemoryMap;
219 }
220
221 Status = GetMemoryMap (
222 MemoryMapSize,
223 *MemoryMap,
224 MapKey,
225 DescriptorSize,
226 DescriptorVersion
227 );
228
229 if (Status != EFI_BUFFER_TOO_SMALL) {
230 DEBUG ((DEBUG_INFO, "OCMM: Insane GetMemoryMap %r\n", Status));
231 return Status;
232 }
233
234 do {
235 //
236 // This is done because extra allocations may increase memory map size.
237 //
238 *MemoryMapSize += 512;
239
240 //
241 // Requested to allocate from top via pages.
242 // This may be needed, because the pool memory may collide with the kernel.
243 //
244 if (TopMemory != NULL) {
245 MemoryMapAlloc = *TopMemory;
246 *TopMemory = EFI_SIZE_TO_PAGES (*MemoryMapSize);
247
248 Status = OcAllocatePagesFromTop (
249 EfiBootServicesData,
250 (UINTN)*TopMemory,
251 &MemoryMapAlloc,
252 GetMemoryMap,
253 NULL,
254 NULL
255 );
256
257 if (EFI_ERROR (Status)) {
258 DEBUG ((DEBUG_INFO, "OCMM: Temp memory map allocation from top failure - %r\n", Status));
259 *MemoryMap = NULL;
260 return Status;
261 }
262
263 *MemoryMap = (EFI_MEMORY_DESCRIPTOR *)(UINTN)MemoryMapAlloc;
264 } else {
265 *MemoryMap = AllocatePool (*MemoryMapSize);
266 if (*MemoryMap == NULL) {
267 DEBUG ((DEBUG_INFO, "OCMM: Temp memory map direct allocation failure\n"));
268 return EFI_OUT_OF_RESOURCES;
269 }
270 }
271
272 Status = GetMemoryMap (
273 MemoryMapSize,
274 *MemoryMap,
275 MapKey,
276 DescriptorSize,
277 DescriptorVersion
278 );
279
280 if (EFI_ERROR (Status)) {
281 if (TopMemory != NULL) {
282 gBS->FreePages (
283 (EFI_PHYSICAL_ADDRESS)((UINTN)*MemoryMap),
284 (UINTN)*TopMemory
285 );
286 } else {
287 FreePool (*MemoryMap);
288 }
289
290 *MemoryMap = NULL;
291 }
292 } while (Status == EFI_BUFFER_TOO_SMALL);
293
294 if (Status != EFI_SUCCESS) {
295 DEBUG ((DEBUG_INFO, "OCMM: Failed to obtain memory map - %r\n", Status));
296 }
297
298 return Status;
299}
300
301VOID
303 IN UINTN MemoryMapSize,
304 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
305 IN UINTN DescriptorSize
306 )
307{
308 EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
309 EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
310 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
311 EFI_MEMORY_DESCRIPTOR TempMemoryMap;
312
313 MemoryMapEntry = MemoryMap;
314 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
315 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
316 while (MemoryMapEntry < MemoryMapEnd) {
317 while (NextMemoryMapEntry < MemoryMapEnd) {
318 if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
319 CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
320 CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
321 CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
322 }
323
324 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
325 }
326
327 MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
328 NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
329 }
330}
331
332EFI_STATUS
334 IN OUT UINTN *MemoryMapSize,
335 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
336 IN UINTN DescriptorSize
337 )
338{
339 EFI_STATUS Status;
340 UINTN SizeFromDescToEnd;
341 UINT64 Bytes;
342 EFI_MEMORY_DESCRIPTOR *PrevDesc;
343 EFI_MEMORY_DESCRIPTOR *Desc;
344 BOOLEAN CanBeJoinedFree;
345 BOOLEAN CanBeJoinedRt;
346 BOOLEAN HasEntriesToRemove;
347
348 Status = EFI_NOT_FOUND;
349
350 if (*MemoryMapSize <= DescriptorSize) {
351 return Status;
352 }
353
354 PrevDesc = MemoryMap;
355 Desc = NEXT_MEMORY_DESCRIPTOR (PrevDesc, DescriptorSize);
356 SizeFromDescToEnd = *MemoryMapSize - DescriptorSize;
357 *MemoryMapSize = DescriptorSize;
358 HasEntriesToRemove = FALSE;
359
360 while (SizeFromDescToEnd > 0) {
361 Bytes = EFI_PAGES_TO_SIZE (PrevDesc->NumberOfPages);
362 CanBeJoinedFree = FALSE;
363 CanBeJoinedRt = FALSE;
364 if ( (Desc->Attribute == PrevDesc->Attribute)
365 && (PrevDesc->PhysicalStart + Bytes == Desc->PhysicalStart))
366 {
367 //
368 // It *should* be safe to join this with conventional memory, because the firmware should not use
369 // GetMemoryMap for allocation, and for the kernel it does not matter, since it joins them.
370 //
371 CanBeJoinedFree = (
372 Desc->Type == EfiBootServicesCode
373 || Desc->Type == EfiBootServicesData
374 || Desc->Type == EfiConventionalMemory
375 || Desc->Type == EfiLoaderCode
376 || Desc->Type == EfiLoaderData
377 ) && (
378 PrevDesc->Type == EfiBootServicesCode
379 || PrevDesc->Type == EfiBootServicesData
380 || PrevDesc->Type == EfiConventionalMemory
381 || PrevDesc->Type == EfiLoaderCode
382 || PrevDesc->Type == EfiLoaderData
383 );
384
385 CanBeJoinedRt = (
386 Desc->Type == EfiRuntimeServicesCode
387 && PrevDesc->Type == EfiRuntimeServicesCode
388 ) || (
389 Desc->Type == EfiRuntimeServicesData
390 && PrevDesc->Type == EfiRuntimeServicesData
391 );
392 }
393
394 if (CanBeJoinedFree) {
395 //
396 // Two entries are the same/similar - join them
397 //
398 PrevDesc->Type = EfiConventionalMemory;
399 PrevDesc->NumberOfPages += Desc->NumberOfPages;
400 HasEntriesToRemove = TRUE;
401 Status = EFI_SUCCESS;
402 } else if (CanBeJoinedRt) {
403 PrevDesc->NumberOfPages += Desc->NumberOfPages;
404 HasEntriesToRemove = TRUE;
405 Status = EFI_SUCCESS;
406 } else {
407 //
408 // Cannot be joined - we need to move to next
409 //
410 *MemoryMapSize += DescriptorSize;
411 PrevDesc = NEXT_MEMORY_DESCRIPTOR (PrevDesc, DescriptorSize);
412 if (HasEntriesToRemove) {
413 //
414 // Have entries between PrevDesc and Desc which are joined to PrevDesc,
415 // we need to copy [Desc, end of list] to PrevDesc + 1
416 //
417 CopyMem (PrevDesc, Desc, SizeFromDescToEnd);
418 Desc = PrevDesc;
419 HasEntriesToRemove = FALSE;
420 }
421 }
422
423 Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
424 SizeFromDescToEnd -= DescriptorSize;
425 }
426
427 //
428 // Handle last entries if they were merged.
429 //
430 if (HasEntriesToRemove) {
431 *MemoryMapSize += DescriptorSize;
432 }
433
434 return EFI_SUCCESS;
435}
436
437EFI_STATUS
439 IN OUT UINT32 *EntryCount,
440 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
441 IN UINTN DescriptorSize
442 )
443{
444 EFI_STATUS Status;
445 UINTN EntriesToGo;
446 EFI_MEMORY_DESCRIPTOR *PrevDesc;
447 EFI_MEMORY_DESCRIPTOR *Desc;
448 BOOLEAN IsDuplicate;
449 BOOLEAN HasEntriesToRemove;
450
451 Status = EFI_NOT_FOUND;
452
453 if (*EntryCount <= 1) {
454 return Status;
455 }
456
457 PrevDesc = MemoryMap;
458 Desc = NEXT_MEMORY_DESCRIPTOR (PrevDesc, DescriptorSize);
459 EntriesToGo = *EntryCount - 1;
460 *EntryCount = 1;
461 HasEntriesToRemove = FALSE;
462
463 while (EntriesToGo > 0) {
464 IsDuplicate = Desc->PhysicalStart == PrevDesc->PhysicalStart
465 && Desc->NumberOfPages == PrevDesc->NumberOfPages;
466
467 if (IsDuplicate) {
468 //
469 // Two entries are duplicate, remove them.
470 //
471 Status = EFI_SUCCESS;
472 HasEntriesToRemove = TRUE;
473 } else {
474 //
475 // Not duplicates - we need to move to next
476 //
477 ++(*EntryCount);
478 PrevDesc = NEXT_MEMORY_DESCRIPTOR (PrevDesc, DescriptorSize);
479 if (HasEntriesToRemove) {
480 //
481 // Have same entries between PrevDesc and Desc which are replaced by PrevDesc,
482 // we need to copy [Desc, end of list] to PrevDesc + 1.
483 //
484 CopyMem (PrevDesc, Desc, EntriesToGo * DescriptorSize);
485 Desc = PrevDesc;
486 HasEntriesToRemove = FALSE;
487 }
488 }
489
490 Desc = NEXT_MEMORY_DESCRIPTOR (Desc, DescriptorSize);
491 --EntriesToGo;
492 }
493
494 //
495 // Handle last entries if they were deduplicated.
496 //
497 if (HasEntriesToRemove) {
498 ++(*EntryCount);
499 }
500
501 return Status;
502}
503
504EFI_STATUS
506 IN UINTN MemoryMapSize,
507 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
508 IN UINTN DescriptorSize,
509 IN EFI_PHYSICAL_ADDRESS Address,
510 IN EFI_MEMORY_TYPE Type,
511 IN UINT64 SetAttributes,
512 IN UINT64 DropAttributes
513 )
514{
515 UINTN Index;
516 UINTN EntryCount;
517
518 EntryCount = MemoryMapSize / DescriptorSize;
519
520 for (Index = 0; Index < EntryCount; ++Index) {
521 if (AREA_WITHIN_DESCRIPTOR (MemoryMap, Address, 1)) {
522 MemoryMap->Type = Type;
523 MemoryMap->Attribute |= SetAttributes;
524 MemoryMap->Attribute &= ~DropAttributes;
525 return EFI_SUCCESS;
526 }
527
528 MemoryMap = NEXT_MEMORY_DESCRIPTOR (
529 MemoryMap,
530 DescriptorSize
531 );
532 }
533
534 return EFI_NOT_FOUND;
535}
EFI_MEMORY_DESCRIPTOR * OcGetCurrentMemoryMap(OUT UINTN *MemoryMapSize, OUT UINTN *DescriptorSize, OUT UINTN *MapKey OPTIONAL, OUT UINT32 *DescriptorVersion OPTIONAL, OUT UINTN *OriginalMemoryMapSize OPTIONAL, IN BOOLEAN IncludeSplitSpace)
Definition MemoryMap.c:116
EFI_STATUS OcDescToMemoryType(IN CHAR8 *MemoryTypeDesc, OUT EFI_MEMORY_TYPE *MemoryType)
Definition MemoryMap.c:90
EFI_STATUS OcGetCurrentMemoryMapAlloc(OUT UINTN *MemoryMapSize, OUT EFI_MEMORY_DESCRIPTOR **MemoryMap, OUT UINTN *MapKey, OUT UINTN *DescriptorSize, OUT UINT32 *DescriptorVersion, IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL, IN OUT EFI_PHYSICAL_ADDRESS *TopMemory OPTIONAL)
Definition MemoryMap.c:201
EFI_STATUS OcDeduplicateDescriptors(IN OUT UINT32 *EntryCount, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize)
Definition MemoryMap.c:438
EFI_STATUS OcShrinkMemoryMap(IN OUT UINTN *MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize)
Definition MemoryMap.c:333
VOID OcSortMemoryMap(IN UINTN MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize)
Definition MemoryMap.c:302
EFI_STATUS OcUpdateDescriptors(IN UINTN MemoryMapSize, IN EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize, IN EFI_PHYSICAL_ADDRESS Address, IN EFI_MEMORY_TYPE Type, IN UINT64 SetAttributes, IN UINT64 DropAttributes)
Definition MemoryMap.c:505
STATIC OC_MEMORY_TYPE_DESC OcMemoryTypeString[OC_MEMORY_TYPE_DESC_COUNT]
Definition MemoryMap.c:26
EFI_BOOT_SERVICES * gBS
#define AREA_WITHIN_DESCRIPTOR(Desc, Area, AreaSize)
Definition OcMemoryLib.h:39
EFI_STATUS OcAllocatePagesFromTop(IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN OUT EFI_PHYSICAL_ADDRESS *Memory, IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL, IN EFI_ALLOCATE_PAGES AllocatePages OPTIONAL, IN CHECK_ALLOCATION_RANGE CheckRange OPTIONAL)
Definition MemoryAlloc.c:27
UINTN OcCountSplitDescriptors(VOID)
#define OC_MEMORY_TYPE_DESC_COUNT
Definition OcMemoryLib.h:53
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
#define MAX(a, b)
Definition coder.h:59
EFI_MEMORY_TYPE Type
Definition OcMemoryLib.h:57