]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Mem/Page.c
EmulatorPkg/PosixFileSystem: Add NULL check on memory allocation
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
... / ...
CommitLineData
1/** @file\r
2 UEFI Memory page management functions.\r
3\r
4Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "DxeMain.h"\r
10#include "Imem.h"\r
11#include "HeapGuard.h"\r
12\r
13//\r
14// Entry for tracking the memory regions for each memory type to coalesce similar memory types\r
15//\r
16typedef struct {\r
17 EFI_PHYSICAL_ADDRESS BaseAddress;\r
18 EFI_PHYSICAL_ADDRESS MaximumAddress;\r
19 UINT64 CurrentNumberOfPages;\r
20 UINT64 NumberOfPages;\r
21 UINTN InformationIndex;\r
22 BOOLEAN Special;\r
23 BOOLEAN Runtime;\r
24} EFI_MEMORY_TYPE_STATISTICS;\r
25\r
26//\r
27// MemoryMap - The current memory map\r
28//\r
29UINTN mMemoryMapKey = 0;\r
30\r
31#define MAX_MAP_DEPTH 6\r
32\r
33///\r
34/// mMapDepth - depth of new descriptor stack\r
35///\r
36UINTN mMapDepth = 0;\r
37///\r
38/// mMapStack - space to use as temp storage to build new map descriptors\r
39///\r
40MEMORY_MAP mMapStack[MAX_MAP_DEPTH];\r
41UINTN mFreeMapStack = 0;\r
42///\r
43/// This list maintain the free memory map list\r
44///\r
45LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
46BOOLEAN mMemoryTypeInformationInitialized = FALSE;\r
47\r
48EFI_MEMORY_TYPE_STATISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {\r
49 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType\r
50 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode\r
51 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData\r
52 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode\r
53 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData\r
54 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode\r
55 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData\r
56 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory\r
57 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory\r
58 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory\r
59 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS\r
60 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO\r
61 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace\r
62 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode\r
63 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiPersistentMemory\r
64 { 0, MAX_ALLOC_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType\r
65};\r
66\r
67EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;\r
68EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS;\r
69\r
70EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {\r
71 { EfiReservedMemoryType, 0 },\r
72 { EfiLoaderCode, 0 },\r
73 { EfiLoaderData, 0 },\r
74 { EfiBootServicesCode, 0 },\r
75 { EfiBootServicesData, 0 },\r
76 { EfiRuntimeServicesCode, 0 },\r
77 { EfiRuntimeServicesData, 0 },\r
78 { EfiConventionalMemory, 0 },\r
79 { EfiUnusableMemory, 0 },\r
80 { EfiACPIReclaimMemory, 0 },\r
81 { EfiACPIMemoryNVS, 0 },\r
82 { EfiMemoryMappedIO, 0 },\r
83 { EfiMemoryMappedIOPortSpace, 0 },\r
84 { EfiPalCode, 0 },\r
85 { EfiPersistentMemory, 0 },\r
86 { EfiMaxMemoryType, 0 }\r
87};\r
88//\r
89// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated\r
90// and ready to load the module in to specified address.or else, the memory is not ready and module will be loaded at a\r
91// address assigned by DXE core.\r
92//\r
93GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN gLoadFixedAddressCodeMemoryReady = FALSE;\r
94\r
95/**\r
96 Enter critical section by gaining lock on gMemoryLock.\r
97\r
98**/\r
99VOID\r
100CoreAcquireMemoryLock (\r
101 VOID\r
102 )\r
103{\r
104 CoreAcquireLock (&gMemoryLock);\r
105}\r
106\r
107/**\r
108 Exit critical section by releasing lock on gMemoryLock.\r
109\r
110**/\r
111VOID\r
112CoreReleaseMemoryLock (\r
113 VOID\r
114 )\r
115{\r
116 CoreReleaseLock (&gMemoryLock);\r
117}\r
118\r
119/**\r
120 Internal function. Removes a descriptor entry.\r
121\r
122 @param Entry The entry to remove\r
123\r
124**/\r
125VOID\r
126RemoveMemoryMapEntry (\r
127 IN OUT MEMORY_MAP *Entry\r
128 )\r
129{\r
130 RemoveEntryList (&Entry->Link);\r
131 Entry->Link.ForwardLink = NULL;\r
132\r
133 if (Entry->FromPages) {\r
134 //\r
135 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList\r
136 //\r
137 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
138 }\r
139}\r
140\r
141/**\r
142 Internal function. Adds a ranges to the memory map.\r
143 The range must not already exist in the map.\r
144\r
145 @param Type The type of memory range to add\r
146 @param Start The starting address in the memory range Must be\r
147 paged aligned\r
148 @param End The last address in the range Must be the last\r
149 byte of a page\r
150 @param Attribute The attributes of the memory range to add\r
151\r
152**/\r
153VOID\r
154CoreAddRange (\r
155 IN EFI_MEMORY_TYPE Type,\r
156 IN EFI_PHYSICAL_ADDRESS Start,\r
157 IN EFI_PHYSICAL_ADDRESS End,\r
158 IN UINT64 Attribute\r
159 )\r
160{\r
161 LIST_ENTRY *Link;\r
162 MEMORY_MAP *Entry;\r
163\r
164 ASSERT ((Start & EFI_PAGE_MASK) == 0);\r
165 ASSERT (End > Start);\r
166\r
167 ASSERT_LOCKED (&gMemoryLock);\r
168\r
169 DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));\r
170\r
171 //\r
172 // If memory of type EfiConventionalMemory is being added that includes the page\r
173 // starting at address 0, then zero the page starting at address 0. This has\r
174 // two benifits. It helps find NULL pointer bugs and it also maximizes\r
175 // compatibility with operating systems that may evaluate memory in this page\r
176 // for legacy data structures. If memory of any other type is added starting\r
177 // at address 0, then do not zero the page at address 0 because the page is being\r
178 // used for other purposes.\r
179 //\r
180 if ((Type == EfiConventionalMemory) && (Start == 0) && (End >= EFI_PAGE_SIZE - 1)) {\r
181 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) == 0) {\r
182 SetMem ((VOID *)(UINTN)Start, EFI_PAGE_SIZE, 0);\r
183 }\r
184 }\r
185\r
186 //\r
187 // Memory map being altered so updated key\r
188 //\r
189 mMemoryMapKey += 1;\r
190\r
191 //\r
192 // UEFI 2.0 added an event group for notificaiton on memory map changes.\r
193 // So we need to signal this Event Group every time the memory map changes.\r
194 // If we are in EFI 1.10 compatability mode no event groups will be\r
195 // found and nothing will happen we we call this function. These events\r
196 // will get signaled but since a lock is held around the call to this\r
197 // function the notificaiton events will only be called after this function\r
198 // returns and the lock is released.\r
199 //\r
200 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);\r
201\r
202 //\r
203 // Look for adjoining memory descriptor\r
204 //\r
205\r
206 // Two memory descriptors can only be merged if they have the same Type\r
207 // and the same Attribute\r
208 //\r
209\r
210 Link = gMemoryMap.ForwardLink;\r
211 while (Link != &gMemoryMap) {\r
212 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
213 Link = Link->ForwardLink;\r
214\r
215 if (Entry->Type != Type) {\r
216 continue;\r
217 }\r
218\r
219 if (Entry->Attribute != Attribute) {\r
220 continue;\r
221 }\r
222\r
223 if (Entry->End + 1 == Start) {\r
224 Start = Entry->Start;\r
225 RemoveMemoryMapEntry (Entry);\r
226 } else if (Entry->Start == End + 1) {\r
227 End = Entry->End;\r
228 RemoveMemoryMapEntry (Entry);\r
229 }\r
230 }\r
231\r
232 //\r
233 // Add descriptor\r
234 //\r
235\r
236 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;\r
237 mMapStack[mMapDepth].FromPages = FALSE;\r
238 mMapStack[mMapDepth].Type = Type;\r
239 mMapStack[mMapDepth].Start = Start;\r
240 mMapStack[mMapDepth].End = End;\r
241 mMapStack[mMapDepth].VirtualStart = 0;\r
242 mMapStack[mMapDepth].Attribute = Attribute;\r
243 InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);\r
244\r
245 mMapDepth += 1;\r
246 ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
247\r
248 return;\r
249}\r
250\r
251/**\r
252 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.\r
253 If the list is emtry, then allocate a new page to refuel the list.\r
254 Please Note this algorithm to allocate the memory map descriptor has a property\r
255 that the memory allocated for memory entries always grows, and will never really be freed\r
256 For example, if the current boot uses 2000 memory map entries at the maximum point, but\r
257 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950\r
258 memory map entries is still allocated from EfiBootServicesMemory.\r
259\r
260\r
261 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
262\r
263**/\r
264MEMORY_MAP *\r
265AllocateMemoryMapEntry (\r
266 VOID\r
267 )\r
268{\r
269 MEMORY_MAP *FreeDescriptorEntries;\r
270 MEMORY_MAP *Entry;\r
271 UINTN Index;\r
272\r
273 if (IsListEmpty (&mFreeMemoryMapEntryList)) {\r
274 //\r
275 // The list is empty, to allocate one page to refuel the list\r
276 //\r
277 FreeDescriptorEntries = CoreAllocatePoolPages (\r
278 EfiBootServicesData,\r
279 EFI_SIZE_TO_PAGES (DEFAULT_PAGE_ALLOCATION_GRANULARITY),\r
280 DEFAULT_PAGE_ALLOCATION_GRANULARITY,\r
281 FALSE\r
282 );\r
283 if (FreeDescriptorEntries != NULL) {\r
284 //\r
285 // Enque the free memmory map entries into the list\r
286 //\r
287 for (Index = 0; Index < DEFAULT_PAGE_ALLOCATION_GRANULARITY / sizeof (MEMORY_MAP); Index++) {\r
288 FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;\r
289 InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);\r
290 }\r
291 } else {\r
292 return NULL;\r
293 }\r
294 }\r
295\r
296 //\r
297 // dequeue the first descriptor from the list\r
298 //\r
299 Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
300 RemoveEntryList (&Entry->Link);\r
301\r
302 return Entry;\r
303}\r
304\r
305/**\r
306 Internal function. Moves any memory descriptors that are on the\r
307 temporary descriptor stack to heap.\r
308\r
309**/\r
310VOID\r
311CoreFreeMemoryMapStack (\r
312 VOID\r
313 )\r
314{\r
315 MEMORY_MAP *Entry;\r
316 MEMORY_MAP *Entry2;\r
317 LIST_ENTRY *Link2;\r
318\r
319 ASSERT_LOCKED (&gMemoryLock);\r
320\r
321 //\r
322 // If already freeing the map stack, then return\r
323 //\r
324 if (mFreeMapStack != 0) {\r
325 return;\r
326 }\r
327\r
328 //\r
329 // Move the temporary memory descriptor stack into pool\r
330 //\r
331 mFreeMapStack += 1;\r
332\r
333 while (mMapDepth != 0) {\r
334 //\r
335 // Deque an memory map entry from mFreeMemoryMapEntryList\r
336 //\r
337 Entry = AllocateMemoryMapEntry ();\r
338\r
339 ASSERT (Entry);\r
340\r
341 //\r
342 // Update to proper entry\r
343 //\r
344 mMapDepth -= 1;\r
345\r
346 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
347 //\r
348 // Move this entry to general memory\r
349 //\r
350 RemoveEntryList (&mMapStack[mMapDepth].Link);\r
351 mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
352\r
353 CopyMem (Entry, &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
354 Entry->FromPages = TRUE;\r
355\r
356 //\r
357 // Find insertion location\r
358 //\r
359 for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {\r
360 Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
361 if (Entry2->FromPages && (Entry2->Start > Entry->Start)) {\r
362 break;\r
363 }\r
364 }\r
365\r
366 InsertTailList (Link2, &Entry->Link);\r
367 } else {\r
368 //\r
369 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,\r
370 // so here no need to move it to memory.\r
371 //\r
372 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
373 }\r
374 }\r
375\r
376 mFreeMapStack -= 1;\r
377}\r
378\r
379/**\r
380 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.\r
381\r
382**/\r
383BOOLEAN\r
384PromoteMemoryResource (\r
385 VOID\r
386 )\r
387{\r
388 LIST_ENTRY *Link;\r
389 EFI_GCD_MAP_ENTRY *Entry;\r
390 BOOLEAN Promoted;\r
391 EFI_PHYSICAL_ADDRESS StartAddress;\r
392 EFI_PHYSICAL_ADDRESS EndAddress;\r
393 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
394\r
395 DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));\r
396\r
397 CoreAcquireGcdMemoryLock ();\r
398\r
399 Promoted = FALSE;\r
400 Link = mGcdMemorySpaceMap.ForwardLink;\r
401 while (Link != &mGcdMemorySpaceMap) {\r
402 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
403\r
404 if ((Entry->GcdMemoryType == EfiGcdMemoryTypeReserved) &&\r
405 (Entry->EndAddress < MAX_ALLOC_ADDRESS) &&\r
406 ((Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
407 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)))\r
408 {\r
409 //\r
410 // Update the GCD map\r
411 //\r
412 if ((Entry->Capabilities & EFI_MEMORY_MORE_RELIABLE) == EFI_MEMORY_MORE_RELIABLE) {\r
413 Entry->GcdMemoryType = EfiGcdMemoryTypeMoreReliable;\r
414 } else {\r
415 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;\r
416 }\r
417\r
418 Entry->Capabilities |= EFI_MEMORY_TESTED;\r
419 Entry->ImageHandle = gDxeCoreImageHandle;\r
420 Entry->DeviceHandle = NULL;\r
421\r
422 //\r
423 // Add to allocable system memory resource\r
424 //\r
425\r
426 CoreAddRange (\r
427 EfiConventionalMemory,\r
428 Entry->BaseAddress,\r
429 Entry->EndAddress,\r
430 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
431 );\r
432 CoreFreeMemoryMapStack ();\r
433\r
434 Promoted = TRUE;\r
435 }\r
436\r
437 Link = Link->ForwardLink;\r
438 }\r
439\r
440 CoreReleaseGcdMemoryLock ();\r
441\r
442 if (!Promoted) {\r
443 //\r
444 // If freed-memory guard is enabled, we could promote pages from\r
445 // guarded free pages.\r
446 //\r
447 Promoted = PromoteGuardedFreePages (&StartAddress, &EndAddress);\r
448 if (Promoted) {\r
449 CoreGetMemorySpaceDescriptor (StartAddress, &Descriptor);\r
450 CoreAddRange (\r
451 EfiConventionalMemory,\r
452 StartAddress,\r
453 EndAddress,\r
454 Descriptor.Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED |\r
455 EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
456 );\r
457 }\r
458 }\r
459\r
460 return Promoted;\r
461}\r
462\r
463/**\r
464 This function try to allocate Runtime code & Boot time code memory range. If LMFA enabled, 2 patchable PCD\r
465 PcdLoadFixAddressRuntimeCodePageNumber & PcdLoadFixAddressBootTimeCodePageNumber which are set by tools will record the\r
466 size of boot time and runtime code.\r
467\r
468**/\r
469VOID\r
470CoreLoadingFixedAddressHook (\r
471 VOID\r
472 )\r
473{\r
474 UINT32 RuntimeCodePageNumber;\r
475 UINT32 BootTimeCodePageNumber;\r
476 EFI_PHYSICAL_ADDRESS RuntimeCodeBase;\r
477 EFI_PHYSICAL_ADDRESS BootTimeCodeBase;\r
478 EFI_STATUS Status;\r
479\r
480 //\r
481 // Make sure these 2 areas are not initialzied.\r
482 //\r
483 if (!gLoadFixedAddressCodeMemoryReady) {\r
484 RuntimeCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);\r
485 BootTimeCodePageNumber = PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);\r
486 RuntimeCodeBase = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - EFI_PAGES_TO_SIZE (RuntimeCodePageNumber));\r
487 BootTimeCodeBase = (EFI_PHYSICAL_ADDRESS)(RuntimeCodeBase - EFI_PAGES_TO_SIZE (BootTimeCodePageNumber));\r
488 //\r
489 // Try to allocate runtime memory.\r
490 //\r
491 Status = CoreAllocatePages (\r
492 AllocateAddress,\r
493 EfiRuntimeServicesCode,\r
494 RuntimeCodePageNumber,\r
495 &RuntimeCodeBase\r
496 );\r
497 if (EFI_ERROR (Status)) {\r
498 //\r
499 // Runtime memory allocation failed\r
500 //\r
501 return;\r
502 }\r
503\r
504 //\r
505 // Try to allocate boot memory.\r
506 //\r
507 Status = CoreAllocatePages (\r
508 AllocateAddress,\r
509 EfiBootServicesCode,\r
510 BootTimeCodePageNumber,\r
511 &BootTimeCodeBase\r
512 );\r
513 if (EFI_ERROR (Status)) {\r
514 //\r
515 // boot memory allocation failed. Free Runtime code range and will try the allocation again when\r
516 // new memory range is installed.\r
517 //\r
518 CoreFreePages (\r
519 RuntimeCodeBase,\r
520 RuntimeCodePageNumber\r
521 );\r
522 return;\r
523 }\r
524\r
525 gLoadFixedAddressCodeMemoryReady = TRUE;\r
526 }\r
527\r
528 return;\r
529}\r
530\r
531/**\r
532 Called to initialize the memory map and add descriptors to\r
533 the current descriptor list.\r
534 The first descriptor that is added must be general usable\r
535 memory as the addition allocates heap.\r
536\r
537 @param Type The type of memory to add\r
538 @param Start The starting address in the memory range Must be\r
539 page aligned\r
540 @param NumberOfPages The number of pages in the range\r
541 @param Attribute Attributes of the memory to add\r
542\r
543 @return None. The range is added to the memory map\r
544\r
545**/\r
546VOID\r
547CoreAddMemoryDescriptor (\r
548 IN EFI_MEMORY_TYPE Type,\r
549 IN EFI_PHYSICAL_ADDRESS Start,\r
550 IN UINT64 NumberOfPages,\r
551 IN UINT64 Attribute\r
552 )\r
553{\r
554 EFI_PHYSICAL_ADDRESS End;\r
555 EFI_STATUS Status;\r
556 UINTN Index;\r
557 UINTN FreeIndex;\r
558\r
559 if ((Start & EFI_PAGE_MASK) != 0) {\r
560 return;\r
561 }\r
562\r
563 if ((Type >= EfiMaxMemoryType) && (Type < MEMORY_TYPE_OEM_RESERVED_MIN)) {\r
564 return;\r
565 }\r
566\r
567 CoreAcquireMemoryLock ();\r
568 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
569 CoreAddRange (Type, Start, End, Attribute);\r
570 CoreFreeMemoryMapStack ();\r
571 CoreReleaseMemoryLock ();\r
572\r
573 ApplyMemoryProtectionPolicy (\r
574 EfiMaxMemoryType,\r
575 Type,\r
576 Start,\r
577 LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT)\r
578 );\r
579\r
580 //\r
581 // If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type\r
582 //\r
583 if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {\r
584 CoreLoadingFixedAddressHook ();\r
585 }\r
586\r
587 //\r
588 // Check to see if the statistics for the different memory types have already been established\r
589 //\r
590 if (mMemoryTypeInformationInitialized) {\r
591 return;\r
592 }\r
593\r
594 //\r
595 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array\r
596 //\r
597 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
598 //\r
599 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
600 //\r
601 Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);\r
602 if ((UINT32)Type > EfiMaxMemoryType) {\r
603 continue;\r
604 }\r
605\r
606 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
607 //\r
608 // Allocate pages for the current memory type from the top of available memory\r
609 //\r
610 Status = CoreAllocatePages (\r
611 AllocateAnyPages,\r
612 Type,\r
613 gMemoryTypeInformation[Index].NumberOfPages,\r
614 &mMemoryTypeStatistics[Type].BaseAddress\r
615 );\r
616 if (EFI_ERROR (Status)) {\r
617 //\r
618 // If an error occurs allocating the pages for the current memory type, then\r
619 // free all the pages allocates for the previous memory types and return. This\r
620 // operation with be retied when/if more memory is added to the system\r
621 //\r
622 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {\r
623 //\r
624 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
625 //\r
626 Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[FreeIndex].Type);\r
627 if ((UINT32)Type > EfiMaxMemoryType) {\r
628 continue;\r
629 }\r
630\r
631 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {\r
632 CoreFreePages (\r
633 mMemoryTypeStatistics[Type].BaseAddress,\r
634 gMemoryTypeInformation[FreeIndex].NumberOfPages\r
635 );\r
636 mMemoryTypeStatistics[Type].BaseAddress = 0;\r
637 mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;\r
638 }\r
639 }\r
640\r
641 return;\r
642 }\r
643\r
644 //\r
645 // Compute the address at the top of the current statistics\r
646 //\r
647 mMemoryTypeStatistics[Type].MaximumAddress =\r
648 mMemoryTypeStatistics[Type].BaseAddress +\r
649 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
650\r
651 //\r
652 // If the current base address is the lowest address so far, then update the default\r
653 // maximum address\r
654 //\r
655 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {\r
656 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;\r
657 }\r
658 }\r
659 }\r
660\r
661 //\r
662 // There was enough system memory for all the the memory types were allocated. So,\r
663 // those memory areas can be freed for future allocations, and all future memory\r
664 // allocations can occur within their respective bins\r
665 //\r
666 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
667 //\r
668 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
669 //\r
670 Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);\r
671 if ((UINT32)Type > EfiMaxMemoryType) {\r
672 continue;\r
673 }\r
674\r
675 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
676 CoreFreePages (\r
677 mMemoryTypeStatistics[Type].BaseAddress,\r
678 gMemoryTypeInformation[Index].NumberOfPages\r
679 );\r
680 mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;\r
681 gMemoryTypeInformation[Index].NumberOfPages = 0;\r
682 }\r
683 }\r
684\r
685 //\r
686 // If the number of pages reserved for a memory type is 0, then all allocations for that type\r
687 // should be in the default range.\r
688 //\r
689 for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {\r
690 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
691 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {\r
692 mMemoryTypeStatistics[Type].InformationIndex = Index;\r
693 }\r
694 }\r
695\r
696 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;\r
697 if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {\r
698 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;\r
699 }\r
700 }\r
701\r
702 mMemoryTypeInformationInitialized = TRUE;\r
703}\r
704\r
705/**\r
706 Internal function. Converts a memory range to the specified type or attributes.\r
707 The range must exist in the memory map. Either ChangingType or\r
708 ChangingAttributes must be set, but not both.\r
709\r
710 @param Start The first address of the range Must be page\r
711 aligned\r
712 @param NumberOfPages The number of pages to convert\r
713 @param ChangingType Boolean indicating that type value should be changed\r
714 @param NewType The new type for the memory range\r
715 @param ChangingAttributes Boolean indicating that attributes value should be changed\r
716 @param NewAttributes The new attributes for the memory range\r
717\r
718 @retval EFI_INVALID_PARAMETER Invalid parameter\r
719 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified\r
720 range or convertion not allowed.\r
721 @retval EFI_SUCCESS Successfully converts the memory range to the\r
722 specified type.\r
723\r
724**/\r
725EFI_STATUS\r
726CoreConvertPagesEx (\r
727 IN UINT64 Start,\r
728 IN UINT64 NumberOfPages,\r
729 IN BOOLEAN ChangingType,\r
730 IN EFI_MEMORY_TYPE NewType,\r
731 IN BOOLEAN ChangingAttributes,\r
732 IN UINT64 NewAttributes\r
733 )\r
734{\r
735 UINT64 NumberOfBytes;\r
736 UINT64 End;\r
737 UINT64 RangeEnd;\r
738 UINT64 Attribute;\r
739 EFI_MEMORY_TYPE MemType;\r
740 LIST_ENTRY *Link;\r
741 MEMORY_MAP *Entry;\r
742\r
743 Entry = NULL;\r
744 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);\r
745 End = Start + NumberOfBytes - 1;\r
746\r
747 ASSERT (NumberOfPages);\r
748 ASSERT ((Start & EFI_PAGE_MASK) == 0);\r
749 ASSERT (End > Start);\r
750 ASSERT_LOCKED (&gMemoryLock);\r
751 ASSERT ((ChangingType == FALSE) || (ChangingAttributes == FALSE));\r
752\r
753 if ((NumberOfPages == 0) || ((Start & EFI_PAGE_MASK) != 0) || (Start >= End)) {\r
754 return EFI_INVALID_PARAMETER;\r
755 }\r
756\r
757 //\r
758 // Convert the entire range\r
759 //\r
760\r
761 while (Start < End) {\r
762 //\r
763 // Find the entry that the covers the range\r
764 //\r
765 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
766 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
767\r
768 if ((Entry->Start <= Start) && (Entry->End > Start)) {\r
769 break;\r
770 }\r
771 }\r
772\r
773 if (Link == &gMemoryMap) {\r
774 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));\r
775 return EFI_NOT_FOUND;\r
776 }\r
777\r
778 //\r
779 // If we are converting the type of the range from EfiConventionalMemory to\r
780 // another type, we have to ensure that the entire range is covered by a\r
781 // single entry.\r
782 //\r
783 if (ChangingType && (NewType != EfiConventionalMemory)) {\r
784 if (Entry->End < End) {\r
785 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: range %lx - %lx covers multiple entries\n", Start, End));\r
786 return EFI_NOT_FOUND;\r
787 }\r
788 }\r
789\r
790 //\r
791 // Convert range to the end, or to the end of the descriptor\r
792 // if that's all we've got\r
793 //\r
794 RangeEnd = End;\r
795\r
796 ASSERT (Entry != NULL);\r
797 if (Entry->End < End) {\r
798 RangeEnd = Entry->End;\r
799 }\r
800\r
801 if (ChangingType) {\r
802 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to type %d\n", Start, RangeEnd, NewType));\r
803 }\r
804\r
805 if (ChangingAttributes) {\r
806 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to attr %lx\n", Start, RangeEnd, NewAttributes));\r
807 }\r
808\r
809 if (ChangingType) {\r
810 //\r
811 // Debug code - verify conversion is allowed\r
812 //\r
813 if (!((NewType == EfiConventionalMemory) ? 1 : 0) ^ ((Entry->Type == EfiConventionalMemory) ? 1 : 0)) {\r
814 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types, "));\r
815 if (Entry->Type == EfiConventionalMemory) {\r
816 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to free have been freed\n"));\r
817 } else {\r
818 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "the pages to allocate have been allocated\n"));\r
819 }\r
820\r
821 return EFI_NOT_FOUND;\r
822 }\r
823\r
824 //\r
825 // Update counters for the number of pages allocated to each memory type\r
826 //\r
827 if ((UINT32)Entry->Type < EfiMaxMemoryType) {\r
828 if (((Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress) && (Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress)) ||\r
829 ((Start >= mDefaultBaseAddress) && (Start <= mDefaultMaximumAddress)))\r
830 {\r
831 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {\r
832 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;\r
833 } else {\r
834 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;\r
835 }\r
836 }\r
837 }\r
838\r
839 if ((UINT32)NewType < EfiMaxMemoryType) {\r
840 if (((Start >= mMemoryTypeStatistics[NewType].BaseAddress) && (Start <= mMemoryTypeStatistics[NewType].MaximumAddress)) ||\r
841 ((Start >= mDefaultBaseAddress) && (Start <= mDefaultMaximumAddress)))\r
842 {\r
843 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;\r
844 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {\r
845 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;\r
846 }\r
847 }\r
848 }\r
849 }\r
850\r
851 //\r
852 // Pull range out of descriptor\r
853 //\r
854 if (Entry->Start == Start) {\r
855 //\r
856 // Clip start\r
857 //\r
858 Entry->Start = RangeEnd + 1;\r
859 } else if (Entry->End == RangeEnd) {\r
860 //\r
861 // Clip end\r
862 //\r
863 Entry->End = Start - 1;\r
864 } else {\r
865 //\r
866 // Pull it out of the center, clip current\r
867 //\r
868\r
869 //\r
870 // Add a new one\r
871 //\r
872 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;\r
873 mMapStack[mMapDepth].FromPages = FALSE;\r
874 mMapStack[mMapDepth].Type = Entry->Type;\r
875 mMapStack[mMapDepth].Start = RangeEnd+1;\r
876 mMapStack[mMapDepth].End = Entry->End;\r
877\r
878 //\r
879 // Inherit Attribute from the Memory Descriptor that is being clipped\r
880 //\r
881 mMapStack[mMapDepth].Attribute = Entry->Attribute;\r
882\r
883 Entry->End = Start - 1;\r
884 ASSERT (Entry->Start < Entry->End);\r
885\r
886 Entry = &mMapStack[mMapDepth];\r
887 InsertTailList (&gMemoryMap, &Entry->Link);\r
888\r
889 mMapDepth += 1;\r
890 ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
891 }\r
892\r
893 //\r
894 // The new range inherits the same Attribute as the Entry\r
895 // it is being cut out of unless attributes are being changed\r
896 //\r
897 if (ChangingType) {\r
898 Attribute = Entry->Attribute;\r
899 MemType = NewType;\r
900 } else {\r
901 Attribute = NewAttributes;\r
902 MemType = Entry->Type;\r
903 }\r
904\r
905 //\r
906 // If the descriptor is empty, then remove it from the map\r
907 //\r
908 if (Entry->Start == Entry->End + 1) {\r
909 RemoveMemoryMapEntry (Entry);\r
910 Entry = NULL;\r
911 }\r
912\r
913 //\r
914 // Add our new range in. Don't do this for freed pages if freed-memory\r
915 // guard is enabled.\r
916 //\r
917 if (!IsHeapGuardEnabled (GUARD_HEAP_TYPE_FREED) ||\r
918 !ChangingType ||\r
919 (MemType != EfiConventionalMemory))\r
920 {\r
921 CoreAddRange (MemType, Start, RangeEnd, Attribute);\r
922 }\r
923\r
924 if (ChangingType && (MemType == EfiConventionalMemory)) {\r
925 //\r
926 // Avoid calling DEBUG_CLEAR_MEMORY() for an address of 0 because this\r
927 // macro will ASSERT() if address is 0. Instead, CoreAddRange() guarantees\r
928 // that the page starting at address 0 is always filled with zeros.\r
929 //\r
930 if (Start == 0) {\r
931 if (RangeEnd > EFI_PAGE_SIZE) {\r
932 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)EFI_PAGE_SIZE, (UINTN)(RangeEnd - EFI_PAGE_SIZE + 1));\r
933 }\r
934 } else {\r
935 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Start, (UINTN)(RangeEnd - Start + 1));\r
936 }\r
937 }\r
938\r
939 //\r
940 // Move any map descriptor stack to general pool\r
941 //\r
942 CoreFreeMemoryMapStack ();\r
943\r
944 //\r
945 // Bump the starting address, and convert the next range\r
946 //\r
947 Start = RangeEnd + 1;\r
948 }\r
949\r
950 //\r
951 // Converted the whole range, done\r
952 //\r
953\r
954 return EFI_SUCCESS;\r
955}\r
956\r
957/**\r
958 Internal function. Converts a memory range to the specified type.\r
959 The range must exist in the memory map.\r
960\r
961 @param Start The first address of the range Must be page\r
962 aligned\r
963 @param NumberOfPages The number of pages to convert\r
964 @param NewType The new type for the memory range\r
965\r
966 @retval EFI_INVALID_PARAMETER Invalid parameter\r
967 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified\r
968 range or convertion not allowed.\r
969 @retval EFI_SUCCESS Successfully converts the memory range to the\r
970 specified type.\r
971\r
972**/\r
973EFI_STATUS\r
974CoreConvertPages (\r
975 IN UINT64 Start,\r
976 IN UINT64 NumberOfPages,\r
977 IN EFI_MEMORY_TYPE NewType\r
978 )\r
979{\r
980 return CoreConvertPagesEx (Start, NumberOfPages, TRUE, NewType, FALSE, 0);\r
981}\r
982\r
983/**\r
984 Internal function. Converts a memory range to use new attributes.\r
985\r
986 @param Start The first address of the range Must be page\r
987 aligned\r
988 @param NumberOfPages The number of pages to convert\r
989 @param NewAttributes The new attributes value for the range.\r
990\r
991**/\r
992VOID\r
993CoreUpdateMemoryAttributes (\r
994 IN EFI_PHYSICAL_ADDRESS Start,\r
995 IN UINT64 NumberOfPages,\r
996 IN UINT64 NewAttributes\r
997 )\r
998{\r
999 CoreAcquireMemoryLock ();\r
1000\r
1001 //\r
1002 // Update the attributes to the new value\r
1003 //\r
1004 CoreConvertPagesEx (Start, NumberOfPages, FALSE, (EFI_MEMORY_TYPE)0, TRUE, NewAttributes);\r
1005\r
1006 CoreReleaseMemoryLock ();\r
1007}\r
1008\r
1009/**\r
1010 Internal function. Finds a consecutive free page range below\r
1011 the requested address.\r
1012\r
1013 @param MaxAddress The address that the range must be below\r
1014 @param MinAddress The address that the range must be above\r
1015 @param NumberOfPages Number of pages needed\r
1016 @param NewType The type of memory the range is going to be\r
1017 turned into\r
1018 @param Alignment Bits to align with\r
1019 @param NeedGuard Flag to indicate Guard page is needed or not\r
1020\r
1021 @return The base address of the range, or 0 if the range was not found\r
1022\r
1023**/\r
1024UINT64\r
1025CoreFindFreePagesI (\r
1026 IN UINT64 MaxAddress,\r
1027 IN UINT64 MinAddress,\r
1028 IN UINT64 NumberOfPages,\r
1029 IN EFI_MEMORY_TYPE NewType,\r
1030 IN UINTN Alignment,\r
1031 IN BOOLEAN NeedGuard\r
1032 )\r
1033{\r
1034 UINT64 NumberOfBytes;\r
1035 UINT64 Target;\r
1036 UINT64 DescStart;\r
1037 UINT64 DescEnd;\r
1038 UINT64 DescNumberOfBytes;\r
1039 LIST_ENTRY *Link;\r
1040 MEMORY_MAP *Entry;\r
1041\r
1042 if ((MaxAddress < EFI_PAGE_MASK) || (NumberOfPages == 0)) {\r
1043 return 0;\r
1044 }\r
1045\r
1046 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {\r
1047 //\r
1048 // If MaxAddress is not aligned to the end of a page\r
1049 //\r
1050\r
1051 //\r
1052 // Change MaxAddress to be 1 page lower\r
1053 //\r
1054 MaxAddress -= (EFI_PAGE_MASK + 1);\r
1055\r
1056 //\r
1057 // Set MaxAddress to a page boundary\r
1058 //\r
1059 MaxAddress &= ~(UINT64)EFI_PAGE_MASK;\r
1060\r
1061 //\r
1062 // Set MaxAddress to end of the page\r
1063 //\r
1064 MaxAddress |= EFI_PAGE_MASK;\r
1065 }\r
1066\r
1067 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);\r
1068 Target = 0;\r
1069\r
1070 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1071 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1072\r
1073 //\r
1074 // If it's not a free entry, don't bother with it\r
1075 //\r
1076 if (Entry->Type != EfiConventionalMemory) {\r
1077 continue;\r
1078 }\r
1079\r
1080 DescStart = Entry->Start;\r
1081 DescEnd = Entry->End;\r
1082\r
1083 //\r
1084 // If desc is past max allowed address or below min allowed address, skip it\r
1085 //\r
1086 if ((DescStart >= MaxAddress) || (DescEnd < MinAddress)) {\r
1087 continue;\r
1088 }\r
1089\r
1090 //\r
1091 // If desc ends past max allowed address, clip the end\r
1092 //\r
1093 if (DescEnd >= MaxAddress) {\r
1094 DescEnd = MaxAddress;\r
1095 }\r
1096\r
1097 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;\r
1098\r
1099 // Skip if DescEnd is less than DescStart after alignment clipping\r
1100 if (DescEnd < DescStart) {\r
1101 continue;\r
1102 }\r
1103\r
1104 //\r
1105 // Compute the number of bytes we can used from this\r
1106 // descriptor, and see it's enough to satisfy the request\r
1107 //\r
1108 DescNumberOfBytes = DescEnd - DescStart + 1;\r
1109\r
1110 if (DescNumberOfBytes >= NumberOfBytes) {\r
1111 //\r
1112 // If the start of the allocated range is below the min address allowed, skip it\r
1113 //\r
1114 if ((DescEnd - NumberOfBytes + 1) < MinAddress) {\r
1115 continue;\r
1116 }\r
1117\r
1118 //\r
1119 // If this is the best match so far remember it\r
1120 //\r
1121 if (DescEnd > Target) {\r
1122 if (NeedGuard) {\r
1123 DescEnd = AdjustMemoryS (\r
1124 DescEnd + 1 - DescNumberOfBytes,\r
1125 DescNumberOfBytes,\r
1126 NumberOfBytes\r
1127 );\r
1128 if (DescEnd == 0) {\r
1129 continue;\r
1130 }\r
1131 }\r
1132\r
1133 Target = DescEnd;\r
1134 }\r
1135 }\r
1136 }\r
1137\r
1138 //\r
1139 // If this is a grow down, adjust target to be the allocation base\r
1140 //\r
1141 Target -= NumberOfBytes - 1;\r
1142\r
1143 //\r
1144 // If we didn't find a match, return 0\r
1145 //\r
1146 if ((Target & EFI_PAGE_MASK) != 0) {\r
1147 return 0;\r
1148 }\r
1149\r
1150 return Target;\r
1151}\r
1152\r
1153/**\r
1154 Internal function. Finds a consecutive free page range below\r
1155 the requested address\r
1156\r
1157 @param MaxAddress The address that the range must be below\r
1158 @param NoPages Number of pages needed\r
1159 @param NewType The type of memory the range is going to be\r
1160 turned into\r
1161 @param Alignment Bits to align with\r
1162 @param NeedGuard Flag to indicate Guard page is needed or not\r
1163\r
1164 @return The base address of the range, or 0 if the range was not found.\r
1165\r
1166**/\r
1167UINT64\r
1168FindFreePages (\r
1169 IN UINT64 MaxAddress,\r
1170 IN UINT64 NoPages,\r
1171 IN EFI_MEMORY_TYPE NewType,\r
1172 IN UINTN Alignment,\r
1173 IN BOOLEAN NeedGuard\r
1174 )\r
1175{\r
1176 UINT64 Start;\r
1177\r
1178 //\r
1179 // Attempt to find free pages in the preferred bin based on the requested memory type\r
1180 //\r
1181 if (((UINT32)NewType < EfiMaxMemoryType) && (MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress)) {\r
1182 Start = CoreFindFreePagesI (\r
1183 mMemoryTypeStatistics[NewType].MaximumAddress,\r
1184 mMemoryTypeStatistics[NewType].BaseAddress,\r
1185 NoPages,\r
1186 NewType,\r
1187 Alignment,\r
1188 NeedGuard\r
1189 );\r
1190 if (Start != 0) {\r
1191 return Start;\r
1192 }\r
1193 }\r
1194\r
1195 //\r
1196 // Attempt to find free pages in the default allocation bin\r
1197 //\r
1198 if (MaxAddress >= mDefaultMaximumAddress) {\r
1199 Start = CoreFindFreePagesI (\r
1200 mDefaultMaximumAddress,\r
1201 0,\r
1202 NoPages,\r
1203 NewType,\r
1204 Alignment,\r
1205 NeedGuard\r
1206 );\r
1207 if (Start != 0) {\r
1208 if (Start < mDefaultBaseAddress) {\r
1209 mDefaultBaseAddress = Start;\r
1210 }\r
1211\r
1212 return Start;\r
1213 }\r
1214 }\r
1215\r
1216 //\r
1217 // The allocation did not succeed in any of the prefered bins even after\r
1218 // promoting resources. Attempt to find free pages anywhere is the requested\r
1219 // address range. If this allocation fails, then there are not enough\r
1220 // resources anywhere to satisfy the request.\r
1221 //\r
1222 Start = CoreFindFreePagesI (\r
1223 MaxAddress,\r
1224 0,\r
1225 NoPages,\r
1226 NewType,\r
1227 Alignment,\r
1228 NeedGuard\r
1229 );\r
1230 if (Start != 0) {\r
1231 return Start;\r
1232 }\r
1233\r
1234 //\r
1235 // If allocations from the preferred bins fail, then attempt to promote memory resources.\r
1236 //\r
1237 if (!PromoteMemoryResource ()) {\r
1238 return 0;\r
1239 }\r
1240\r
1241 //\r
1242 // If any memory resources were promoted, then re-attempt the allocation\r
1243 //\r
1244 return FindFreePages (MaxAddress, NoPages, NewType, Alignment, NeedGuard);\r
1245}\r
1246\r
1247/**\r
1248 Allocates pages from the memory map.\r
1249\r
1250 @param Type The type of allocation to perform\r
1251 @param MemoryType The type of memory to turn the allocated pages\r
1252 into\r
1253 @param NumberOfPages The number of pages to allocate\r
1254 @param Memory A pointer to receive the base allocated memory\r
1255 address\r
1256 @param NeedGuard Flag to indicate Guard page is needed or not\r
1257\r
1258 @return Status. On success, Memory is filled in with the base address allocated\r
1259 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in\r
1260 spec.\r
1261 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
1262 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
1263 @retval EFI_SUCCESS Pages successfully allocated.\r
1264\r
1265**/\r
1266EFI_STATUS\r
1267EFIAPI\r
1268CoreInternalAllocatePages (\r
1269 IN EFI_ALLOCATE_TYPE Type,\r
1270 IN EFI_MEMORY_TYPE MemoryType,\r
1271 IN UINTN NumberOfPages,\r
1272 IN OUT EFI_PHYSICAL_ADDRESS *Memory,\r
1273 IN BOOLEAN NeedGuard\r
1274 )\r
1275{\r
1276 EFI_STATUS Status;\r
1277 UINT64 Start;\r
1278 UINT64 NumberOfBytes;\r
1279 UINT64 End;\r
1280 UINT64 MaxAddress;\r
1281 UINTN Alignment;\r
1282 EFI_MEMORY_TYPE CheckType;\r
1283\r
1284 if ((UINT32)Type >= MaxAllocateType) {\r
1285 return EFI_INVALID_PARAMETER;\r
1286 }\r
1287\r
1288 if (((MemoryType >= EfiMaxMemoryType) && (MemoryType < MEMORY_TYPE_OEM_RESERVED_MIN)) ||\r
1289 (MemoryType == EfiConventionalMemory) || (MemoryType == EfiPersistentMemory))\r
1290 {\r
1291 return EFI_INVALID_PARAMETER;\r
1292 }\r
1293\r
1294 if (Memory == NULL) {\r
1295 return EFI_INVALID_PARAMETER;\r
1296 }\r
1297\r
1298 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
1299\r
1300 if ((MemoryType == EfiACPIReclaimMemory) ||\r
1301 (MemoryType == EfiACPIMemoryNVS) ||\r
1302 (MemoryType == EfiRuntimeServicesCode) ||\r
1303 (MemoryType == EfiRuntimeServicesData))\r
1304 {\r
1305 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
1306 }\r
1307\r
1308 if (Type == AllocateAddress) {\r
1309 if ((*Memory & (Alignment - 1)) != 0) {\r
1310 return EFI_NOT_FOUND;\r
1311 }\r
1312 }\r
1313\r
1314 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;\r
1315 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);\r
1316\r
1317 //\r
1318 // If this is for below a particular address, then\r
1319 //\r
1320 Start = *Memory;\r
1321\r
1322 //\r
1323 // The max address is the max natively addressable address for the processor\r
1324 //\r
1325 MaxAddress = MAX_ALLOC_ADDRESS;\r
1326\r
1327 //\r
1328 // Check for Type AllocateAddress,\r
1329 // if NumberOfPages is 0 or\r
1330 // if (NumberOfPages << EFI_PAGE_SHIFT) is above MAX_ALLOC_ADDRESS or\r
1331 // if (Start + NumberOfBytes) rolls over 0 or\r
1332 // if Start is above MAX_ALLOC_ADDRESS or\r
1333 // if End is above MAX_ALLOC_ADDRESS,\r
1334 // if Start..End overlaps any tracked MemoryTypeStatistics range\r
1335 // return EFI_NOT_FOUND.\r
1336 //\r
1337 if (Type == AllocateAddress) {\r
1338 if ((NumberOfPages == 0) ||\r
1339 (NumberOfPages > RShiftU64 (MaxAddress, EFI_PAGE_SHIFT)))\r
1340 {\r
1341 return EFI_NOT_FOUND;\r
1342 }\r
1343\r
1344 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);\r
1345 End = Start + NumberOfBytes - 1;\r
1346\r
1347 if ((Start >= End) ||\r
1348 (Start > MaxAddress) ||\r
1349 (End > MaxAddress))\r
1350 {\r
1351 return EFI_NOT_FOUND;\r
1352 }\r
1353\r
1354 //\r
1355 // A driver is allowed to call AllocatePages using an AllocateAddress type. This type of\r
1356 // AllocatePage request the exact physical address if it is not used. The existing code\r
1357 // will allow this request even in 'special' pages. The problem with this is that the\r
1358 // reason to have 'special' pages for OS hibernate/resume is defeated as memory is\r
1359 // fragmented.\r
1360 //\r
1361\r
1362 for (CheckType = (EFI_MEMORY_TYPE)0; CheckType < EfiMaxMemoryType; CheckType++) {\r
1363 if ((MemoryType != CheckType) &&\r
1364 mMemoryTypeStatistics[CheckType].Special &&\r
1365 (mMemoryTypeStatistics[CheckType].NumberOfPages > 0))\r
1366 {\r
1367 if ((Start >= mMemoryTypeStatistics[CheckType].BaseAddress) &&\r
1368 (Start <= mMemoryTypeStatistics[CheckType].MaximumAddress))\r
1369 {\r
1370 return EFI_NOT_FOUND;\r
1371 }\r
1372\r
1373 if ((End >= mMemoryTypeStatistics[CheckType].BaseAddress) &&\r
1374 (End <= mMemoryTypeStatistics[CheckType].MaximumAddress))\r
1375 {\r
1376 return EFI_NOT_FOUND;\r
1377 }\r
1378\r
1379 if ((Start < mMemoryTypeStatistics[CheckType].BaseAddress) &&\r
1380 (End > mMemoryTypeStatistics[CheckType].MaximumAddress))\r
1381 {\r
1382 return EFI_NOT_FOUND;\r
1383 }\r
1384 }\r
1385 }\r
1386 }\r
1387\r
1388 if (Type == AllocateMaxAddress) {\r
1389 MaxAddress = Start;\r
1390 }\r
1391\r
1392 CoreAcquireMemoryLock ();\r
1393\r
1394 //\r
1395 // If not a specific address, then find an address to allocate\r
1396 //\r
1397 if (Type != AllocateAddress) {\r
1398 Start = FindFreePages (\r
1399 MaxAddress,\r
1400 NumberOfPages,\r
1401 MemoryType,\r
1402 Alignment,\r
1403 NeedGuard\r
1404 );\r
1405 if (Start == 0) {\r
1406 Status = EFI_OUT_OF_RESOURCES;\r
1407 goto Done;\r
1408 }\r
1409 }\r
1410\r
1411 //\r
1412 // Convert pages from FreeMemory to the requested type\r
1413 //\r
1414 if (NeedGuard) {\r
1415 Status = CoreConvertPagesWithGuard (Start, NumberOfPages, MemoryType);\r
1416 } else {\r
1417 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);\r
1418 }\r
1419\r
1420Done:\r
1421 CoreReleaseMemoryLock ();\r
1422\r
1423 if (!EFI_ERROR (Status)) {\r
1424 if (NeedGuard) {\r
1425 SetGuardForMemory (Start, NumberOfPages);\r
1426 }\r
1427\r
1428 *Memory = Start;\r
1429 }\r
1430\r
1431 return Status;\r
1432}\r
1433\r
1434/**\r
1435 Allocates pages from the memory map.\r
1436\r
1437 @param Type The type of allocation to perform\r
1438 @param MemoryType The type of memory to turn the allocated pages\r
1439 into\r
1440 @param NumberOfPages The number of pages to allocate\r
1441 @param Memory A pointer to receive the base allocated memory\r
1442 address\r
1443\r
1444 @return Status. On success, Memory is filled in with the base address allocated\r
1445 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in\r
1446 spec.\r
1447 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
1448 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
1449 @retval EFI_SUCCESS Pages successfully allocated.\r
1450\r
1451**/\r
1452EFI_STATUS\r
1453EFIAPI\r
1454CoreAllocatePages (\r
1455 IN EFI_ALLOCATE_TYPE Type,\r
1456 IN EFI_MEMORY_TYPE MemoryType,\r
1457 IN UINTN NumberOfPages,\r
1458 OUT EFI_PHYSICAL_ADDRESS *Memory\r
1459 )\r
1460{\r
1461 EFI_STATUS Status;\r
1462 BOOLEAN NeedGuard;\r
1463\r
1464 NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;\r
1465 Status = CoreInternalAllocatePages (\r
1466 Type,\r
1467 MemoryType,\r
1468 NumberOfPages,\r
1469 Memory,\r
1470 NeedGuard\r
1471 );\r
1472 if (!EFI_ERROR (Status)) {\r
1473 CoreUpdateProfile (\r
1474 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),\r
1475 MemoryProfileActionAllocatePages,\r
1476 MemoryType,\r
1477 EFI_PAGES_TO_SIZE (NumberOfPages),\r
1478 (VOID *)(UINTN)*Memory,\r
1479 NULL\r
1480 );\r
1481 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);\r
1482 ApplyMemoryProtectionPolicy (\r
1483 EfiConventionalMemory,\r
1484 MemoryType,\r
1485 *Memory,\r
1486 EFI_PAGES_TO_SIZE (NumberOfPages)\r
1487 );\r
1488 }\r
1489\r
1490 return Status;\r
1491}\r
1492\r
1493/**\r
1494 Frees previous allocated pages.\r
1495\r
1496 @param Memory Base address of memory being freed\r
1497 @param NumberOfPages The number of pages to free\r
1498 @param MemoryType Pointer to memory type\r
1499\r
1500 @retval EFI_NOT_FOUND Could not find the entry that covers the range\r
1501 @retval EFI_INVALID_PARAMETER Address not aligned\r
1502 @return EFI_SUCCESS -Pages successfully freed.\r
1503\r
1504**/\r
1505EFI_STATUS\r
1506EFIAPI\r
1507CoreInternalFreePages (\r
1508 IN EFI_PHYSICAL_ADDRESS Memory,\r
1509 IN UINTN NumberOfPages,\r
1510 OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL\r
1511 )\r
1512{\r
1513 EFI_STATUS Status;\r
1514 LIST_ENTRY *Link;\r
1515 MEMORY_MAP *Entry;\r
1516 UINTN Alignment;\r
1517 BOOLEAN IsGuarded;\r
1518\r
1519 //\r
1520 // Free the range\r
1521 //\r
1522 CoreAcquireMemoryLock ();\r
1523\r
1524 //\r
1525 // Find the entry that the covers the range\r
1526 //\r
1527 IsGuarded = FALSE;\r
1528 Entry = NULL;\r
1529 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1530 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1531 if ((Entry->Start <= Memory) && (Entry->End > Memory)) {\r
1532 break;\r
1533 }\r
1534 }\r
1535\r
1536 if (Link == &gMemoryMap) {\r
1537 Status = EFI_NOT_FOUND;\r
1538 goto Done;\r
1539 }\r
1540\r
1541 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
1542\r
1543 ASSERT (Entry != NULL);\r
1544 if ((Entry->Type == EfiACPIReclaimMemory) ||\r
1545 (Entry->Type == EfiACPIMemoryNVS) ||\r
1546 (Entry->Type == EfiRuntimeServicesCode) ||\r
1547 (Entry->Type == EfiRuntimeServicesData))\r
1548 {\r
1549 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
1550 }\r
1551\r
1552 if ((Memory & (Alignment - 1)) != 0) {\r
1553 Status = EFI_INVALID_PARAMETER;\r
1554 goto Done;\r
1555 }\r
1556\r
1557 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;\r
1558 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);\r
1559\r
1560 if (MemoryType != NULL) {\r
1561 *MemoryType = Entry->Type;\r
1562 }\r
1563\r
1564 IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&\r
1565 IsMemoryGuarded (Memory);\r
1566 if (IsGuarded) {\r
1567 Status = CoreConvertPagesWithGuard (\r
1568 Memory,\r
1569 NumberOfPages,\r
1570 EfiConventionalMemory\r
1571 );\r
1572 } else {\r
1573 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
1574 }\r
1575\r
1576Done:\r
1577 CoreReleaseMemoryLock ();\r
1578 return Status;\r
1579}\r
1580\r
1581/**\r
1582 Frees previous allocated pages.\r
1583\r
1584 @param Memory Base address of memory being freed\r
1585 @param NumberOfPages The number of pages to free\r
1586\r
1587 @retval EFI_NOT_FOUND Could not find the entry that covers the range\r
1588 @retval EFI_INVALID_PARAMETER Address not aligned\r
1589 @return EFI_SUCCESS -Pages successfully freed.\r
1590\r
1591**/\r
1592EFI_STATUS\r
1593EFIAPI\r
1594CoreFreePages (\r
1595 IN EFI_PHYSICAL_ADDRESS Memory,\r
1596 IN UINTN NumberOfPages\r
1597 )\r
1598{\r
1599 EFI_STATUS Status;\r
1600 EFI_MEMORY_TYPE MemoryType;\r
1601\r
1602 Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);\r
1603 if (!EFI_ERROR (Status)) {\r
1604 GuardFreedPagesChecked (Memory, NumberOfPages);\r
1605 CoreUpdateProfile (\r
1606 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),\r
1607 MemoryProfileActionFreePages,\r
1608 MemoryType,\r
1609 EFI_PAGES_TO_SIZE (NumberOfPages),\r
1610 (VOID *)(UINTN)Memory,\r
1611 NULL\r
1612 );\r
1613 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);\r
1614 ApplyMemoryProtectionPolicy (\r
1615 MemoryType,\r
1616 EfiConventionalMemory,\r
1617 Memory,\r
1618 EFI_PAGES_TO_SIZE (NumberOfPages)\r
1619 );\r
1620 }\r
1621\r
1622 return Status;\r
1623}\r
1624\r
1625/**\r
1626 This function checks to see if the last memory map descriptor in a memory map\r
1627 can be merged with any of the other memory map descriptors in a memorymap.\r
1628 Memory descriptors may be merged if they are adjacent and have the same type\r
1629 and attributes.\r
1630\r
1631 @param MemoryMap A pointer to the start of the memory map.\r
1632 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.\r
1633 @param DescriptorSize The size, in bytes, of an individual\r
1634 EFI_MEMORY_DESCRIPTOR.\r
1635\r
1636 @return A pointer to the next available descriptor in MemoryMap\r
1637\r
1638**/\r
1639EFI_MEMORY_DESCRIPTOR *\r
1640MergeMemoryMapDescriptor (\r
1641 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1642 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,\r
1643 IN UINTN DescriptorSize\r
1644 )\r
1645{\r
1646 //\r
1647 // Traverse the array of descriptors in MemoryMap\r
1648 //\r
1649 for ( ; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {\r
1650 //\r
1651 // Check to see if the Type fields are identical.\r
1652 //\r
1653 if (MemoryMap->Type != MemoryMapDescriptor->Type) {\r
1654 continue;\r
1655 }\r
1656\r
1657 //\r
1658 // Check to see if the Attribute fields are identical.\r
1659 //\r
1660 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {\r
1661 continue;\r
1662 }\r
1663\r
1664 //\r
1665 // Check to see if MemoryMapDescriptor is immediately above MemoryMap\r
1666 //\r
1667 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {\r
1668 //\r
1669 // Merge MemoryMapDescriptor into MemoryMap\r
1670 //\r
1671 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;\r
1672\r
1673 //\r
1674 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array\r
1675 //\r
1676 return MemoryMapDescriptor;\r
1677 }\r
1678\r
1679 //\r
1680 // Check to see if MemoryMapDescriptor is immediately below MemoryMap\r
1681 //\r
1682 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {\r
1683 //\r
1684 // Merge MemoryMapDescriptor into MemoryMap\r
1685 //\r
1686 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;\r
1687 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;\r
1688 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;\r
1689\r
1690 //\r
1691 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array\r
1692 //\r
1693 return MemoryMapDescriptor;\r
1694 }\r
1695 }\r
1696\r
1697 //\r
1698 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.\r
1699 //\r
1700 // Return the slot immediately after MemoryMapDescriptor as the next available\r
1701 // slot in the MemoryMap array\r
1702 //\r
1703 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);\r
1704}\r
1705\r
1706/**\r
1707 This function returns a copy of the current memory map. The map is an array of\r
1708 memory descriptors, each of which describes a contiguous block of memory.\r
1709\r
1710 @param MemoryMapSize A pointer to the size, in bytes, of the\r
1711 MemoryMap buffer. On input, this is the size of\r
1712 the buffer allocated by the caller. On output,\r
1713 it is the size of the buffer returned by the\r
1714 firmware if the buffer was large enough, or the\r
1715 size of the buffer needed to contain the map if\r
1716 the buffer was too small.\r
1717 @param MemoryMap A pointer to the buffer in which firmware places\r
1718 the current memory map.\r
1719 @param MapKey A pointer to the location in which firmware\r
1720 returns the key for the current memory map.\r
1721 @param DescriptorSize A pointer to the location in which firmware\r
1722 returns the size, in bytes, of an individual\r
1723 EFI_MEMORY_DESCRIPTOR.\r
1724 @param DescriptorVersion A pointer to the location in which firmware\r
1725 returns the version number associated with the\r
1726 EFI_MEMORY_DESCRIPTOR.\r
1727\r
1728 @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
1729 buffer.\r
1730 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
1731 buffer size needed to hold the memory map is\r
1732 returned in MemoryMapSize.\r
1733 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1734\r
1735**/\r
1736EFI_STATUS\r
1737EFIAPI\r
1738CoreGetMemoryMap (\r
1739 IN OUT UINTN *MemoryMapSize,\r
1740 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1741 OUT UINTN *MapKey,\r
1742 OUT UINTN *DescriptorSize,\r
1743 OUT UINT32 *DescriptorVersion\r
1744 )\r
1745{\r
1746 EFI_STATUS Status;\r
1747 UINTN Size;\r
1748 UINTN BufferSize;\r
1749 UINTN NumberOfEntries;\r
1750 LIST_ENTRY *Link;\r
1751 MEMORY_MAP *Entry;\r
1752 EFI_GCD_MAP_ENTRY *GcdMapEntry;\r
1753 EFI_GCD_MAP_ENTRY MergeGcdMapEntry;\r
1754 EFI_MEMORY_TYPE Type;\r
1755 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;\r
1756 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
1757\r
1758 //\r
1759 // Make sure the parameters are valid\r
1760 //\r
1761 if (MemoryMapSize == NULL) {\r
1762 return EFI_INVALID_PARAMETER;\r
1763 }\r
1764\r
1765 CoreAcquireGcdMemoryLock ();\r
1766\r
1767 //\r
1768 // Count the number of Reserved and runtime MMIO entries\r
1769 // And, count the number of Persistent entries.\r
1770 //\r
1771 NumberOfEntries = 0;\r
1772 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
1773 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1774 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||\r
1775 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
1776 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
1777 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))\r
1778 {\r
1779 NumberOfEntries++;\r
1780 }\r
1781 }\r
1782\r
1783 Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
1784\r
1785 //\r
1786 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
1787 // prevent people from having pointer math bugs in their code.\r
1788 // now you have to use *DescriptorSize to make things work.\r
1789 //\r
1790 Size += sizeof (UINT64) - (Size % sizeof (UINT64));\r
1791\r
1792 if (DescriptorSize != NULL) {\r
1793 *DescriptorSize = Size;\r
1794 }\r
1795\r
1796 if (DescriptorVersion != NULL) {\r
1797 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
1798 }\r
1799\r
1800 CoreAcquireMemoryLock ();\r
1801\r
1802 //\r
1803 // Compute the buffer size needed to fit the entire map\r
1804 //\r
1805 BufferSize = Size * NumberOfEntries;\r
1806 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1807 BufferSize += Size;\r
1808 }\r
1809\r
1810 if (*MemoryMapSize < BufferSize) {\r
1811 Status = EFI_BUFFER_TOO_SMALL;\r
1812 goto Done;\r
1813 }\r
1814\r
1815 if (MemoryMap == NULL) {\r
1816 Status = EFI_INVALID_PARAMETER;\r
1817 goto Done;\r
1818 }\r
1819\r
1820 //\r
1821 // Build the map\r
1822 //\r
1823 ZeroMem (MemoryMap, BufferSize);\r
1824 MemoryMapStart = MemoryMap;\r
1825 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1826 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1827 ASSERT (Entry->VirtualStart == 0);\r
1828\r
1829 //\r
1830 // Convert internal map into an EFI_MEMORY_DESCRIPTOR\r
1831 //\r
1832 MemoryMap->Type = Entry->Type;\r
1833 MemoryMap->PhysicalStart = Entry->Start;\r
1834 MemoryMap->VirtualStart = Entry->VirtualStart;\r
1835 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
1836 //\r
1837 // If the memory type is EfiConventionalMemory, then determine if the range is part of a\r
1838 // memory type bin and needs to be converted to the same memory type as the rest of the\r
1839 // memory type bin in order to minimize EFI Memory Map changes across reboots. This\r
1840 // improves the chances for a successful S4 resume in the presence of minor page allocation\r
1841 // differences across reboots.\r
1842 //\r
1843 if (MemoryMap->Type == EfiConventionalMemory) {\r
1844 for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {\r
1845 if (mMemoryTypeStatistics[Type].Special &&\r
1846 (mMemoryTypeStatistics[Type].NumberOfPages > 0) &&\r
1847 (Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress) &&\r
1848 (Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress))\r
1849 {\r
1850 MemoryMap->Type = Type;\r
1851 }\r
1852 }\r
1853 }\r
1854\r
1855 MemoryMap->Attribute = Entry->Attribute;\r
1856 if (MemoryMap->Type < EfiMaxMemoryType) {\r
1857 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {\r
1858 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;\r
1859 }\r
1860 }\r
1861\r
1862 //\r
1863 // Check to see if the new Memory Map Descriptor can be merged with an\r
1864 // existing descriptor if they are adjacent and have the same attributes\r
1865 //\r
1866 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
1867 }\r
1868\r
1869 ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));\r
1870 GcdMapEntry = NULL;\r
1871 for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {\r
1872 if (Link != &mGcdMemorySpaceMap) {\r
1873 //\r
1874 // Merge adjacent same type and attribute GCD memory range\r
1875 //\r
1876 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1877\r
1878 if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&\r
1879 (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&\r
1880 (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&\r
1881 (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType))\r
1882 {\r
1883 MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;\r
1884 continue;\r
1885 }\r
1886 }\r
1887\r
1888 if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
1889 ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
1890 ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))\r
1891 {\r
1892 //\r
1893 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,\r
1894 // it will be recorded as page PhysicalStart and NumberOfPages.\r
1895 //\r
1896 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);\r
1897 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);\r
1898\r
1899 //\r
1900 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries\r
1901 //\r
1902 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;\r
1903 MemoryMap->VirtualStart = 0;\r
1904 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);\r
1905 MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |\r
1906 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));\r
1907\r
1908 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {\r
1909 MemoryMap->Type = EfiReservedMemoryType;\r
1910 } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
1911 if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {\r
1912 MemoryMap->Type = EfiMemoryMappedIOPortSpace;\r
1913 } else {\r
1914 MemoryMap->Type = EfiMemoryMappedIO;\r
1915 }\r
1916 }\r
1917\r
1918 //\r
1919 // Check to see if the new Memory Map Descriptor can be merged with an\r
1920 // existing descriptor if they are adjacent and have the same attributes\r
1921 //\r
1922 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
1923 }\r
1924\r
1925 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {\r
1926 //\r
1927 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,\r
1928 // it will be recorded as page PhysicalStart and NumberOfPages.\r
1929 //\r
1930 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);\r
1931 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);\r
1932\r
1933 //\r
1934 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries\r
1935 //\r
1936 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;\r
1937 MemoryMap->VirtualStart = 0;\r
1938 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);\r
1939 MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |\r
1940 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));\r
1941 MemoryMap->Type = EfiPersistentMemory;\r
1942\r
1943 //\r
1944 // Check to see if the new Memory Map Descriptor can be merged with an\r
1945 // existing descriptor if they are adjacent and have the same attributes\r
1946 //\r
1947 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
1948 }\r
1949\r
1950 if (Link == &mGcdMemorySpaceMap) {\r
1951 //\r
1952 // break loop when arrive at head.\r
1953 //\r
1954 break;\r
1955 }\r
1956\r
1957 if (GcdMapEntry != NULL) {\r
1958 //\r
1959 // Copy new GCD map entry for the following GCD range merge\r
1960 //\r
1961 CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));\r
1962 }\r
1963 }\r
1964\r
1965 //\r
1966 // Compute the size of the buffer actually used after all memory map descriptor merge operations\r
1967 //\r
1968 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);\r
1969\r
1970 //\r
1971 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really\r
1972 // set attributes and change memory paging attribute accordingly.\r
1973 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by\r
1974 // value from Capabilities in GCD memory map. This might cause\r
1975 // boot problems. Clearing all page-access permission related\r
1976 // capabilities can workaround it. Following code is supposed to\r
1977 // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute\r
1978 // is clarified in UEFI spec and adopted by both EDK-II Core and\r
1979 // all supported OSs.\r
1980 //\r
1981 MemoryMapEnd = MemoryMap;\r
1982 MemoryMap = MemoryMapStart;\r
1983 while (MemoryMap < MemoryMapEnd) {\r
1984 MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;\r
1985 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
1986 }\r
1987\r
1988 MergeMemoryMap (MemoryMapStart, &BufferSize, Size);\r
1989 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);\r
1990\r
1991 Status = EFI_SUCCESS;\r
1992\r
1993Done:\r
1994 //\r
1995 // Update the map key finally\r
1996 //\r
1997 if (MapKey != NULL) {\r
1998 *MapKey = mMemoryMapKey;\r
1999 }\r
2000\r
2001 CoreReleaseMemoryLock ();\r
2002\r
2003 CoreReleaseGcdMemoryLock ();\r
2004\r
2005 *MemoryMapSize = BufferSize;\r
2006\r
2007 DEBUG_CODE (\r
2008 DumpGuardedMemoryBitmap ();\r
2009 );\r
2010\r
2011 return Status;\r
2012}\r
2013\r
2014/**\r
2015 Internal function. Used by the pool functions to allocate pages\r
2016 to back pool allocation requests.\r
2017\r
2018 @param PoolType The type of memory for the new pool pages\r
2019 @param NumberOfPages No of pages to allocate\r
2020 @param Alignment Bits to align.\r
2021 @param NeedGuard Flag to indicate Guard page is needed or not\r
2022\r
2023 @return The allocated memory, or NULL\r
2024\r
2025**/\r
2026VOID *\r
2027CoreAllocatePoolPages (\r
2028 IN EFI_MEMORY_TYPE PoolType,\r
2029 IN UINTN NumberOfPages,\r
2030 IN UINTN Alignment,\r
2031 IN BOOLEAN NeedGuard\r
2032 )\r
2033{\r
2034 UINT64 Start;\r
2035\r
2036 //\r
2037 // Find the pages to convert\r
2038 //\r
2039 Start = FindFreePages (\r
2040 MAX_ALLOC_ADDRESS,\r
2041 NumberOfPages,\r
2042 PoolType,\r
2043 Alignment,\r
2044 NeedGuard\r
2045 );\r
2046\r
2047 //\r
2048 // Convert it to boot services data\r
2049 //\r
2050 if (Start == 0) {\r
2051 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));\r
2052 } else {\r
2053 if (NeedGuard) {\r
2054 CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);\r
2055 } else {\r
2056 CoreConvertPages (Start, NumberOfPages, PoolType);\r
2057 }\r
2058 }\r
2059\r
2060 return (VOID *)(UINTN)Start;\r
2061}\r
2062\r
2063/**\r
2064 Internal function. Frees pool pages allocated via AllocatePoolPages ()\r
2065\r
2066 @param Memory The base address to free\r
2067 @param NumberOfPages The number of pages to free\r
2068\r
2069**/\r
2070VOID\r
2071CoreFreePoolPages (\r
2072 IN EFI_PHYSICAL_ADDRESS Memory,\r
2073 IN UINTN NumberOfPages\r
2074 )\r
2075{\r
2076 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
2077}\r
2078\r
2079/**\r
2080 Make sure the memory map is following all the construction rules,\r
2081 it is the last time to check memory map error before exit boot services.\r
2082\r
2083 @param MapKey Memory map key\r
2084\r
2085 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction\r
2086 rules.\r
2087 @retval EFI_SUCCESS Valid memory map.\r
2088\r
2089**/\r
2090EFI_STATUS\r
2091CoreTerminateMemoryMap (\r
2092 IN UINTN MapKey\r
2093 )\r
2094{\r
2095 EFI_STATUS Status;\r
2096 LIST_ENTRY *Link;\r
2097 MEMORY_MAP *Entry;\r
2098\r
2099 Status = EFI_SUCCESS;\r
2100\r
2101 CoreAcquireMemoryLock ();\r
2102\r
2103 if (MapKey == mMemoryMapKey) {\r
2104 //\r
2105 // Make sure the memory map is following all the construction rules\r
2106 // This is the last chance we will be able to display any messages on\r
2107 // the console devices.\r
2108 //\r
2109\r
2110 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
2111 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
2112 if (Entry->Type < EfiMaxMemoryType) {\r
2113 if (mMemoryTypeStatistics[Entry->Type].Runtime) {\r
2114 ASSERT (Entry->Type != EfiACPIReclaimMemory);\r
2115 ASSERT (Entry->Type != EfiACPIMemoryNVS);\r
2116 if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {\r
2117 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
2118 Status = EFI_INVALID_PARAMETER;\r
2119 goto Done;\r
2120 }\r
2121\r
2122 if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {\r
2123 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
2124 Status = EFI_INVALID_PARAMETER;\r
2125 goto Done;\r
2126 }\r
2127 }\r
2128 }\r
2129 }\r
2130\r
2131 //\r
2132 // The map key they gave us matches what we expect. Fall through and\r
2133 // return success. In an ideal world we would clear out all of\r
2134 // EfiBootServicesCode and EfiBootServicesData. However this function\r
2135 // is not the last one called by ExitBootServices(), so we have to\r
2136 // preserve the memory contents.\r
2137 //\r
2138 } else {\r
2139 Status = EFI_INVALID_PARAMETER;\r
2140 }\r
2141\r
2142Done:\r
2143 CoreReleaseMemoryLock ();\r
2144\r
2145 return Status;\r
2146}\r