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