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