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