]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Mem/Page.c
MdePkg: Add UEFI Unaccepted memory definition
[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
494f333a
SH
1420 if (EFI_ERROR (Status)) {\r
1421 //\r
1422 // If requested memory region is unavailable it may be untested memory\r
1423 // Attempt to promote memory resources, then re-attempt the allocation\r
1424 //\r
1425 if (PromoteMemoryResource ()) {\r
1426 if (NeedGuard) {\r
1427 Status = CoreConvertPagesWithGuard (Start, NumberOfPages, MemoryType);\r
1428 } else {\r
1429 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);\r
1430 }\r
1431 }\r
1432 }\r
1433\r
28a00297 1434Done:\r
1435 CoreReleaseMemoryLock ();\r
1436\r
1437 if (!EFI_ERROR (Status)) {\r
e63da9f0
JW
1438 if (NeedGuard) {\r
1439 SetGuardForMemory (Start, NumberOfPages);\r
1440 }\r
1436aea4 1441\r
28a00297 1442 *Memory = Start;\r
1443 }\r
1444\r
1445 return Status;\r
1446}\r
1447\r
84edd20b
SZ
1448/**\r
1449 Allocates pages from the memory map.\r
1450\r
1451 @param Type The type of allocation to perform\r
1452 @param MemoryType The type of memory to turn the allocated pages\r
1453 into\r
1454 @param NumberOfPages The number of pages to allocate\r
1455 @param Memory A pointer to receive the base allocated memory\r
1456 address\r
1457\r
1458 @return Status. On success, Memory is filled in with the base address allocated\r
1459 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in\r
1460 spec.\r
1461 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
1462 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
1463 @retval EFI_SUCCESS Pages successfully allocated.\r
1464\r
1465**/\r
1466EFI_STATUS\r
1467EFIAPI\r
1468CoreAllocatePages (\r
1469 IN EFI_ALLOCATE_TYPE Type,\r
1470 IN EFI_MEMORY_TYPE MemoryType,\r
1471 IN UINTN NumberOfPages,\r
1472 OUT EFI_PHYSICAL_ADDRESS *Memory\r
1473 )\r
1474{\r
1475 EFI_STATUS Status;\r
e63da9f0 1476 BOOLEAN NeedGuard;\r
84edd20b 1477\r
e63da9f0 1478 NeedGuard = IsPageTypeToGuard (MemoryType, Type) && !mOnGuarding;\r
1436aea4
MK
1479 Status = CoreInternalAllocatePages (\r
1480 Type,\r
1481 MemoryType,\r
1482 NumberOfPages,\r
1483 Memory,\r
1484 NeedGuard\r
1485 );\r
84edd20b 1486 if (!EFI_ERROR (Status)) {\r
1d60fe96 1487 CoreUpdateProfile (\r
1436aea4 1488 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),\r
1d60fe96
SZ
1489 MemoryProfileActionAllocatePages,\r
1490 MemoryType,\r
1491 EFI_PAGES_TO_SIZE (NumberOfPages),\r
1436aea4 1492 (VOID *)(UINTN)*Memory,\r
1d60fe96
SZ
1493 NULL\r
1494 );\r
74a88770 1495 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);\r
1436aea4
MK
1496 ApplyMemoryProtectionPolicy (\r
1497 EfiConventionalMemory,\r
1498 MemoryType,\r
1499 *Memory,\r
1500 EFI_PAGES_TO_SIZE (NumberOfPages)\r
1501 );\r
84edd20b 1502 }\r
1436aea4 1503\r
84edd20b
SZ
1504 return Status;\r
1505}\r
28a00297 1506\r
162ed594 1507/**\r
1508 Frees previous allocated pages.\r
1509\r
022c6d45 1510 @param Memory Base address of memory being freed\r
1511 @param NumberOfPages The number of pages to free\r
925f0d1a 1512 @param MemoryType Pointer to memory type\r
162ed594 1513\r
022c6d45 1514 @retval EFI_NOT_FOUND Could not find the entry that covers the range\r
1515 @retval EFI_INVALID_PARAMETER Address not aligned\r
162ed594 1516 @return EFI_SUCCESS -Pages successfully freed.\r
1517\r
1518**/\r
022c6d45 1519EFI_STATUS\r
28a00297 1520EFIAPI\r
84edd20b 1521CoreInternalFreePages (\r
1436aea4
MK
1522 IN EFI_PHYSICAL_ADDRESS Memory,\r
1523 IN UINTN NumberOfPages,\r
1524 OUT EFI_MEMORY_TYPE *MemoryType OPTIONAL\r
28a00297 1525 )\r
28a00297 1526{\r
1436aea4
MK
1527 EFI_STATUS Status;\r
1528 LIST_ENTRY *Link;\r
1529 MEMORY_MAP *Entry;\r
1530 UINTN Alignment;\r
1531 BOOLEAN IsGuarded;\r
28a00297 1532\r
1533 //\r
1534 // Free the range\r
1535 //\r
1536 CoreAcquireMemoryLock ();\r
1537\r
1538 //\r
1539 // Find the entry that the covers the range\r
1540 //\r
e63da9f0 1541 IsGuarded = FALSE;\r
1436aea4 1542 Entry = NULL;\r
28a00297 1543 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1436aea4
MK
1544 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1545 if ((Entry->Start <= Memory) && (Entry->End > Memory)) {\r
1546 break;\r
28a00297 1547 }\r
1548 }\r
1436aea4 1549\r
28a00297 1550 if (Link == &gMemoryMap) {\r
a5ca8fa7 1551 Status = EFI_NOT_FOUND;\r
1552 goto Done;\r
28a00297 1553 }\r
1554\r
d4731a98 1555 Alignment = DEFAULT_PAGE_ALLOCATION_GRANULARITY;\r
28a00297 1556\r
525aded9 1557 ASSERT (Entry != NULL);\r
1436aea4
MK
1558 if ((Entry->Type == EfiACPIReclaimMemory) ||\r
1559 (Entry->Type == EfiACPIMemoryNVS) ||\r
1560 (Entry->Type == EfiRuntimeServicesCode) ||\r
1561 (Entry->Type == EfiRuntimeServicesData))\r
1562 {\r
d4731a98 1563 Alignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;\r
28a00297 1564 }\r
1565\r
1566 if ((Memory & (Alignment - 1)) != 0) {\r
a5ca8fa7 1567 Status = EFI_INVALID_PARAMETER;\r
1568 goto Done;\r
28a00297 1569 }\r
1570\r
1571 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;\r
1572 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);\r
1573\r
925f0d1a
SZ
1574 if (MemoryType != NULL) {\r
1575 *MemoryType = Entry->Type;\r
1576 }\r
1577\r
e63da9f0
JW
1578 IsGuarded = IsPageTypeToGuard (Entry->Type, AllocateAnyPages) &&\r
1579 IsMemoryGuarded (Memory);\r
1580 if (IsGuarded) {\r
1436aea4
MK
1581 Status = CoreConvertPagesWithGuard (\r
1582 Memory,\r
1583 NumberOfPages,\r
1584 EfiConventionalMemory\r
1585 );\r
e63da9f0
JW
1586 } else {\r
1587 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
28a00297 1588 }\r
1589\r
a5ca8fa7 1590Done:\r
1591 CoreReleaseMemoryLock ();\r
28a00297 1592 return Status;\r
1593}\r
1594\r
84edd20b
SZ
1595/**\r
1596 Frees previous allocated pages.\r
1597\r
1598 @param Memory Base address of memory being freed\r
1599 @param NumberOfPages The number of pages to free\r
1600\r
1601 @retval EFI_NOT_FOUND Could not find the entry that covers the range\r
1602 @retval EFI_INVALID_PARAMETER Address not aligned\r
1603 @return EFI_SUCCESS -Pages successfully freed.\r
1604\r
1605**/\r
1606EFI_STATUS\r
1607EFIAPI\r
1608CoreFreePages (\r
1609 IN EFI_PHYSICAL_ADDRESS Memory,\r
1610 IN UINTN NumberOfPages\r
1611 )\r
1612{\r
1436aea4
MK
1613 EFI_STATUS Status;\r
1614 EFI_MEMORY_TYPE MemoryType;\r
736a692e 1615\r
925f0d1a 1616 Status = CoreInternalFreePages (Memory, NumberOfPages, &MemoryType);\r
736a692e 1617 if (!EFI_ERROR (Status)) {\r
63ebde8e 1618 GuardFreedPagesChecked (Memory, NumberOfPages);\r
1d60fe96 1619 CoreUpdateProfile (\r
1436aea4 1620 (EFI_PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),\r
1d60fe96
SZ
1621 MemoryProfileActionFreePages,\r
1622 MemoryType,\r
1623 EFI_PAGES_TO_SIZE (NumberOfPages),\r
1436aea4 1624 (VOID *)(UINTN)Memory,\r
1d60fe96
SZ
1625 NULL\r
1626 );\r
74a88770 1627 InstallMemoryAttributesTableOnMemoryAllocation (MemoryType);\r
1436aea4
MK
1628 ApplyMemoryProtectionPolicy (\r
1629 MemoryType,\r
1630 EfiConventionalMemory,\r
1631 Memory,\r
1632 EFI_PAGES_TO_SIZE (NumberOfPages)\r
1633 );\r
736a692e 1634 }\r
1436aea4 1635\r
736a692e
HT
1636 return Status;\r
1637}\r
84edd20b 1638\r
2345e7d4 1639/**\r
1640 This function checks to see if the last memory map descriptor in a memory map\r
1641 can be merged with any of the other memory map descriptors in a memorymap.\r
1642 Memory descriptors may be merged if they are adjacent and have the same type\r
1643 and attributes.\r
1644\r
1645 @param MemoryMap A pointer to the start of the memory map.\r
1646 @param MemoryMapDescriptor A pointer to the last descriptor in MemoryMap.\r
1647 @param DescriptorSize The size, in bytes, of an individual\r
1648 EFI_MEMORY_DESCRIPTOR.\r
1649\r
1650 @return A pointer to the next available descriptor in MemoryMap\r
1651\r
1652**/\r
1653EFI_MEMORY_DESCRIPTOR *\r
1654MergeMemoryMapDescriptor (\r
1655 IN EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1656 IN EFI_MEMORY_DESCRIPTOR *MemoryMapDescriptor,\r
1657 IN UINTN DescriptorSize\r
1658 )\r
1659{\r
1660 //\r
1661 // Traverse the array of descriptors in MemoryMap\r
1662 //\r
1436aea4 1663 for ( ; MemoryMap != MemoryMapDescriptor; MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize)) {\r
2345e7d4 1664 //\r
1665 // Check to see if the Type fields are identical.\r
1666 //\r
1667 if (MemoryMap->Type != MemoryMapDescriptor->Type) {\r
1668 continue;\r
1669 }\r
1670\r
1671 //\r
1672 // Check to see if the Attribute fields are identical.\r
1673 //\r
1674 if (MemoryMap->Attribute != MemoryMapDescriptor->Attribute) {\r
1675 continue;\r
1676 }\r
1677\r
1678 //\r
1679 // Check to see if MemoryMapDescriptor is immediately above MemoryMap\r
1680 //\r
d1102dba 1681 if (MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {\r
2345e7d4 1682 //\r
1683 // Merge MemoryMapDescriptor into MemoryMap\r
1684 //\r
1685 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;\r
1686\r
1687 //\r
1688 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array\r
1689 //\r
1690 return MemoryMapDescriptor;\r
1691 }\r
1692\r
1693 //\r
1694 // Check to see if MemoryMapDescriptor is immediately below MemoryMap\r
1695 //\r
1696 if (MemoryMap->PhysicalStart - EFI_PAGES_TO_SIZE ((UINTN)MemoryMapDescriptor->NumberOfPages) == MemoryMapDescriptor->PhysicalStart) {\r
1697 //\r
1698 // Merge MemoryMapDescriptor into MemoryMap\r
1699 //\r
1700 MemoryMap->PhysicalStart = MemoryMapDescriptor->PhysicalStart;\r
1701 MemoryMap->VirtualStart = MemoryMapDescriptor->VirtualStart;\r
1702 MemoryMap->NumberOfPages += MemoryMapDescriptor->NumberOfPages;\r
1703\r
1704 //\r
1705 // Return MemoryMapDescriptor as the next available slot int he MemoryMap array\r
1706 //\r
1707 return MemoryMapDescriptor;\r
1708 }\r
1709 }\r
1710\r
1711 //\r
1712 // MemoryMapDescrtiptor could not be merged with any descriptors in MemoryMap.\r
1713 //\r
d1102dba 1714 // Return the slot immediately after MemoryMapDescriptor as the next available\r
2345e7d4 1715 // slot in the MemoryMap array\r
1716 //\r
1717 return NEXT_MEMORY_DESCRIPTOR (MemoryMapDescriptor, DescriptorSize);\r
1718}\r
28a00297 1719\r
162ed594 1720/**\r
1721 This function returns a copy of the current memory map. The map is an array of\r
1722 memory descriptors, each of which describes a contiguous block of memory.\r
1723\r
022c6d45 1724 @param MemoryMapSize A pointer to the size, in bytes, of the\r
1725 MemoryMap buffer. On input, this is the size of\r
1726 the buffer allocated by the caller. On output,\r
1727 it is the size of the buffer returned by the\r
1728 firmware if the buffer was large enough, or the\r
1729 size of the buffer needed to contain the map if\r
1730 the buffer was too small.\r
1731 @param MemoryMap A pointer to the buffer in which firmware places\r
1732 the current memory map.\r
1733 @param MapKey A pointer to the location in which firmware\r
1734 returns the key for the current memory map.\r
1735 @param DescriptorSize A pointer to the location in which firmware\r
1736 returns the size, in bytes, of an individual\r
1737 EFI_MEMORY_DESCRIPTOR.\r
1738 @param DescriptorVersion A pointer to the location in which firmware\r
1739 returns the version number associated with the\r
1740 EFI_MEMORY_DESCRIPTOR.\r
1741\r
1742 @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
1743 buffer.\r
1744 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
1745 buffer size needed to hold the memory map is\r
1746 returned in MemoryMapSize.\r
162ed594 1747 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1748\r
1749**/\r
28a00297 1750EFI_STATUS\r
1751EFIAPI\r
1752CoreGetMemoryMap (\r
1753 IN OUT UINTN *MemoryMapSize,\r
1754 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1755 OUT UINTN *MapKey,\r
1756 OUT UINTN *DescriptorSize,\r
1757 OUT UINT32 *DescriptorVersion\r
1758 )\r
28a00297 1759{\r
1436aea4
MK
1760 EFI_STATUS Status;\r
1761 UINTN Size;\r
1762 UINTN BufferSize;\r
1763 UINTN NumberOfEntries;\r
1764 LIST_ENTRY *Link;\r
1765 MEMORY_MAP *Entry;\r
1766 EFI_GCD_MAP_ENTRY *GcdMapEntry;\r
1767 EFI_GCD_MAP_ENTRY MergeGcdMapEntry;\r
1768 EFI_MEMORY_TYPE Type;\r
1769 EFI_MEMORY_DESCRIPTOR *MemoryMapStart;\r
1770 EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;\r
28a00297 1771\r
1772 //\r
1773 // Make sure the parameters are valid\r
1774 //\r
1775 if (MemoryMapSize == NULL) {\r
1776 return EFI_INVALID_PARAMETER;\r
1777 }\r
022c6d45 1778\r
28a00297 1779 CoreAcquireGcdMemoryLock ();\r
022c6d45 1780\r
28a00297 1781 //\r
ba2c0527 1782 // Count the number of Reserved and runtime MMIO entries\r
a671a012 1783 // And, count the number of Persistent entries.\r
28a00297 1784 //\r
ba2c0527 1785 NumberOfEntries = 0;\r
28a00297 1786 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
1787 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
d1102dba 1788 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistent) ||\r
ba2c0527
LG
1789 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
1790 ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
1436aea4
MK
1791 ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))\r
1792 {\r
1793 NumberOfEntries++;\r
a671a012 1794 }\r
28a00297 1795 }\r
1796\r
1797 Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
1798\r
1799 //\r
1800 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
1801 // prevent people from having pointer math bugs in their code.\r
1802 // now you have to use *DescriptorSize to make things work.\r
1803 //\r
1436aea4 1804 Size += sizeof (UINT64) - (Size % sizeof (UINT64));\r
28a00297 1805\r
1806 if (DescriptorSize != NULL) {\r
1807 *DescriptorSize = Size;\r
1808 }\r
022c6d45 1809\r
28a00297 1810 if (DescriptorVersion != NULL) {\r
1811 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
1812 }\r
1813\r
1814 CoreAcquireMemoryLock ();\r
1815\r
1816 //\r
1817 // Compute the buffer size needed to fit the entire map\r
1818 //\r
ba2c0527 1819 BufferSize = Size * NumberOfEntries;\r
28a00297 1820 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1821 BufferSize += Size;\r
1822 }\r
1823\r
1824 if (*MemoryMapSize < BufferSize) {\r
1825 Status = EFI_BUFFER_TOO_SMALL;\r
1826 goto Done;\r
1827 }\r
1828\r
1829 if (MemoryMap == NULL) {\r
1830 Status = EFI_INVALID_PARAMETER;\r
1831 goto Done;\r
1832 }\r
1833\r
1834 //\r
1835 // Build the map\r
1836 //\r
383c303c 1837 ZeroMem (MemoryMap, BufferSize);\r
2345e7d4 1838 MemoryMapStart = MemoryMap;\r
28a00297 1839 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1840 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1841 ASSERT (Entry->VirtualStart == 0);\r
1842\r
b74350e9 1843 //\r
1844 // Convert internal map into an EFI_MEMORY_DESCRIPTOR\r
1845 //\r
1436aea4
MK
1846 MemoryMap->Type = Entry->Type;\r
1847 MemoryMap->PhysicalStart = Entry->Start;\r
1848 MemoryMap->VirtualStart = Entry->VirtualStart;\r
1849 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
b74350e9 1850 //\r
1851 // If the memory type is EfiConventionalMemory, then determine if the range is part of a\r
022c6d45 1852 // memory type bin and needs to be converted to the same memory type as the rest of the\r
1853 // memory type bin in order to minimize EFI Memory Map changes across reboots. This\r
b74350e9 1854 // improves the chances for a successful S4 resume in the presence of minor page allocation\r
1855 // differences across reboots.\r
1856 //\r
1857 if (MemoryMap->Type == EfiConventionalMemory) {\r
1436aea4 1858 for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {\r
b74350e9 1859 if (mMemoryTypeStatistics[Type].Special &&\r
1436aea4
MK
1860 (mMemoryTypeStatistics[Type].NumberOfPages > 0) &&\r
1861 (Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress) &&\r
1862 (Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress))\r
1863 {\r
b74350e9 1864 MemoryMap->Type = Type;\r
1865 }\r
1866 }\r
1867 }\r
1436aea4 1868\r
b74350e9 1869 MemoryMap->Attribute = Entry->Attribute;\r
10fe0d81
RN
1870 if (MemoryMap->Type < EfiMaxMemoryType) {\r
1871 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {\r
1872 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;\r
1873 }\r
28a00297 1874 }\r
022c6d45 1875\r
2345e7d4 1876 //\r
d1102dba 1877 // Check to see if the new Memory Map Descriptor can be merged with an\r
2345e7d4 1878 // existing descriptor if they are adjacent and have the same attributes\r
1879 //\r
1880 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
28a00297 1881 }\r
1882\r
46a65f18
LG
1883 ZeroMem (&MergeGcdMapEntry, sizeof (MergeGcdMapEntry));\r
1884 GcdMapEntry = NULL;\r
1885 for (Link = mGcdMemorySpaceMap.ForwardLink; ; Link = Link->ForwardLink) {\r
1886 if (Link != &mGcdMemorySpaceMap) {\r
1887 //\r
1888 // Merge adjacent same type and attribute GCD memory range\r
1889 //\r
1890 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
d1102dba
LG
1891\r
1892 if ((MergeGcdMapEntry.Capabilities == GcdMapEntry->Capabilities) &&\r
46a65f18
LG
1893 (MergeGcdMapEntry.Attributes == GcdMapEntry->Attributes) &&\r
1894 (MergeGcdMapEntry.GcdMemoryType == GcdMapEntry->GcdMemoryType) &&\r
1436aea4
MK
1895 (MergeGcdMapEntry.GcdIoType == GcdMapEntry->GcdIoType))\r
1896 {\r
1897 MergeGcdMapEntry.EndAddress = GcdMapEntry->EndAddress;\r
46a65f18
LG
1898 continue;\r
1899 }\r
1900 }\r
1901\r
1902 if ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
1903 ((MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
1436aea4
MK
1904 ((MergeGcdMapEntry.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME)))\r
1905 {\r
46a65f18 1906 //\r
d1102dba
LG
1907 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,\r
1908 // it will be recorded as page PhysicalStart and NumberOfPages.\r
46a65f18
LG
1909 //\r
1910 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);\r
1911 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);\r
d1102dba
LG
1912\r
1913 //\r
ba2c0527
LG
1914 // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries\r
1915 //\r
46a65f18 1916 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;\r
ba2c0527 1917 MemoryMap->VirtualStart = 0;\r
46a65f18 1918 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);\r
d1102dba 1919 MemoryMap->Attribute = (MergeGcdMapEntry.Attributes & ~EFI_MEMORY_PORT_IO) |\r
1436aea4 1920 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));\r
ba2c0527 1921\r
46a65f18 1922 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeReserved) {\r
ba2c0527 1923 MemoryMap->Type = EfiReservedMemoryType;\r
46a65f18
LG
1924 } else if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
1925 if ((MergeGcdMapEntry.Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {\r
ba2c0527
LG
1926 MemoryMap->Type = EfiMemoryMappedIOPortSpace;\r
1927 } else {\r
1928 MemoryMap->Type = EfiMemoryMappedIO;\r
28a00297 1929 }\r
28a00297 1930 }\r
ba2c0527
LG
1931\r
1932 //\r
d1102dba 1933 // Check to see if the new Memory Map Descriptor can be merged with an\r
ba2c0527
LG
1934 // existing descriptor if they are adjacent and have the same attributes\r
1935 //\r
1936 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
28a00297 1937 }\r
d1102dba 1938\r
35ac962b 1939 if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypePersistent) {\r
46a65f18 1940 //\r
d1102dba
LG
1941 // Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,\r
1942 // it will be recorded as page PhysicalStart and NumberOfPages.\r
46a65f18
LG
1943 //\r
1944 ASSERT ((MergeGcdMapEntry.BaseAddress & EFI_PAGE_MASK) == 0);\r
1945 ASSERT (((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1) & EFI_PAGE_MASK) == 0);\r
1946\r
d1102dba 1947 //\r
a671a012
LG
1948 // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries\r
1949 //\r
46a65f18 1950 MemoryMap->PhysicalStart = MergeGcdMapEntry.BaseAddress;\r
a671a012 1951 MemoryMap->VirtualStart = 0;\r
46a65f18 1952 MemoryMap->NumberOfPages = RShiftU64 ((MergeGcdMapEntry.EndAddress - MergeGcdMapEntry.BaseAddress + 1), EFI_PAGE_SHIFT);\r
d1102dba 1953 MemoryMap->Attribute = MergeGcdMapEntry.Attributes | EFI_MEMORY_NV |\r
1436aea4
MK
1954 (MergeGcdMapEntry.Capabilities & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));\r
1955 MemoryMap->Type = EfiPersistentMemory;\r
d1102dba 1956\r
a671a012 1957 //\r
d1102dba 1958 // Check to see if the new Memory Map Descriptor can be merged with an\r
a671a012
LG
1959 // existing descriptor if they are adjacent and have the same attributes\r
1960 //\r
1961 MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);\r
1962 }\r
1436aea4 1963\r
46a65f18
LG
1964 if (Link == &mGcdMemorySpaceMap) {\r
1965 //\r
1966 // break loop when arrive at head.\r
1967 //\r
1968 break;\r
1969 }\r
1436aea4 1970\r
46a65f18
LG
1971 if (GcdMapEntry != NULL) {\r
1972 //\r
1973 // Copy new GCD map entry for the following GCD range merge\r
1974 //\r
1975 CopyMem (&MergeGcdMapEntry, GcdMapEntry, sizeof (MergeGcdMapEntry));\r
1976 }\r
28a00297 1977 }\r
022c6d45 1978\r
2345e7d4 1979 //\r
1980 // Compute the size of the buffer actually used after all memory map descriptor merge operations\r
1981 //\r
1982 BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);\r
1983\r
e38451cd
JW
1984 //\r
1985 // Note: Some OSs will treat EFI_MEMORY_DESCRIPTOR.Attribute as really\r
1986 // set attributes and change memory paging attribute accordingly.\r
1987 // But current EFI_MEMORY_DESCRIPTOR.Attribute is assigned by\r
1988 // value from Capabilities in GCD memory map. This might cause\r
f1567720
MK
1989 // boot problems. Clearing all page-access permission related\r
1990 // capabilities can workaround it. Following code is supposed to\r
1991 // be removed once the usage of EFI_MEMORY_DESCRIPTOR.Attribute\r
1992 // is clarified in UEFI spec and adopted by both EDK-II Core and\r
1993 // all supported OSs.\r
e38451cd
JW
1994 //\r
1995 MemoryMapEnd = MemoryMap;\r
1436aea4 1996 MemoryMap = MemoryMapStart;\r
e38451cd 1997 while (MemoryMap < MemoryMapEnd) {\r
f1567720 1998 MemoryMap->Attribute &= ~(UINT64)EFI_MEMORY_ACCESS_MASK;\r
1436aea4 1999 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
e38451cd 2000 }\r
1436aea4 2001\r
646127c1
JW
2002 MergeMemoryMap (MemoryMapStart, &BufferSize, Size);\r
2003 MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMapStart + BufferSize);\r
e38451cd 2004\r
28a00297 2005 Status = EFI_SUCCESS;\r
2006\r
2007Done:\r
022c6d45 2008 //\r
2009 // Update the map key finally\r
2010 //\r
28a00297 2011 if (MapKey != NULL) {\r
2012 *MapKey = mMemoryMapKey;\r
2013 }\r
022c6d45 2014\r
e439df50 2015 CoreReleaseMemoryLock ();\r
2016\r
2017 CoreReleaseGcdMemoryLock ();\r
2018\r
28a00297 2019 *MemoryMapSize = BufferSize;\r
022c6d45 2020\r
e63da9f0 2021 DEBUG_CODE (\r
63ebde8e 2022 DumpGuardedMemoryBitmap ();\r
1436aea4 2023 );\r
e63da9f0 2024\r
28a00297 2025 return Status;\r
2026}\r
2027\r
162ed594 2028/**\r
28a00297 2029 Internal function. Used by the pool functions to allocate pages\r
2030 to back pool allocation requests.\r
2031\r
022c6d45 2032 @param PoolType The type of memory for the new pool pages\r
2033 @param NumberOfPages No of pages to allocate\r
2034 @param Alignment Bits to align.\r
e63da9f0 2035 @param NeedGuard Flag to indicate Guard page is needed or not\r
28a00297 2036\r
162ed594 2037 @return The allocated memory, or NULL\r
28a00297 2038\r
162ed594 2039**/\r
2040VOID *\r
2041CoreAllocatePoolPages (\r
1436aea4
MK
2042 IN EFI_MEMORY_TYPE PoolType,\r
2043 IN UINTN NumberOfPages,\r
2044 IN UINTN Alignment,\r
2045 IN BOOLEAN NeedGuard\r
162ed594 2046 )\r
28a00297 2047{\r
1436aea4 2048 UINT64 Start;\r
28a00297 2049\r
2050 //\r
2051 // Find the pages to convert\r
2052 //\r
1436aea4
MK
2053 Start = FindFreePages (\r
2054 MAX_ALLOC_ADDRESS,\r
2055 NumberOfPages,\r
2056 PoolType,\r
2057 Alignment,\r
2058 NeedGuard\r
2059 );\r
28a00297 2060\r
2061 //\r
2062 // Convert it to boot services data\r
2063 //\r
2064 if (Start == 0) {\r
7df7393f 2065 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", (UINT32)NumberOfPages));\r
28a00297 2066 } else {\r
e63da9f0
JW
2067 if (NeedGuard) {\r
2068 CoreConvertPagesWithGuard (Start, NumberOfPages, PoolType);\r
2069 } else {\r
2070 CoreConvertPages (Start, NumberOfPages, PoolType);\r
2071 }\r
28a00297 2072 }\r
2073\r
1436aea4 2074 return (VOID *)(UINTN)Start;\r
28a00297 2075}\r
2076\r
162ed594 2077/**\r
2078 Internal function. Frees pool pages allocated via AllocatePoolPages ()\r
2079\r
022c6d45 2080 @param Memory The base address to free\r
162ed594 2081 @param NumberOfPages The number of pages to free\r
2082\r
2083**/\r
28a00297 2084VOID\r
2085CoreFreePoolPages (\r
1436aea4
MK
2086 IN EFI_PHYSICAL_ADDRESS Memory,\r
2087 IN UINTN NumberOfPages\r
28a00297 2088 )\r
28a00297 2089{\r
2090 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
2091}\r
2092\r
162ed594 2093/**\r
2094 Make sure the memory map is following all the construction rules,\r
28a00297 2095 it is the last time to check memory map error before exit boot services.\r
2096\r
022c6d45 2097 @param MapKey Memory map key\r
28a00297 2098\r
022c6d45 2099 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction\r
2100 rules.\r
162ed594 2101 @retval EFI_SUCCESS Valid memory map.\r
28a00297 2102\r
162ed594 2103**/\r
2104EFI_STATUS\r
2105CoreTerminateMemoryMap (\r
1436aea4 2106 IN UINTN MapKey\r
162ed594 2107 )\r
28a00297 2108{\r
1436aea4
MK
2109 EFI_STATUS Status;\r
2110 LIST_ENTRY *Link;\r
2111 MEMORY_MAP *Entry;\r
28a00297 2112\r
2113 Status = EFI_SUCCESS;\r
2114\r
2115 CoreAcquireMemoryLock ();\r
2116\r
2117 if (MapKey == mMemoryMapKey) {\r
28a00297 2118 //\r
2119 // Make sure the memory map is following all the construction rules\r
2120 // This is the last chance we will be able to display any messages on\r
2121 // the console devices.\r
2122 //\r
2123\r
2124 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1436aea4 2125 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
7d17a6a1
AB
2126 if (Entry->Type < EfiMaxMemoryType) {\r
2127 if (mMemoryTypeStatistics[Entry->Type].Runtime) {\r
2128 ASSERT (Entry->Type != EfiACPIReclaimMemory);\r
2129 ASSERT (Entry->Type != EfiACPIMemoryNVS);\r
d4731a98 2130 if ((Entry->Start & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {\r
1436aea4 2131 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
7d17a6a1
AB
2132 Status = EFI_INVALID_PARAMETER;\r
2133 goto Done;\r
2134 }\r
1436aea4 2135\r
d4731a98 2136 if (((Entry->End + 1) & (RUNTIME_PAGE_ALLOCATION_GRANULARITY - 1)) != 0) {\r
1436aea4 2137 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
7d17a6a1
AB
2138 Status = EFI_INVALID_PARAMETER;\r
2139 goto Done;\r
2140 }\r
28a00297 2141 }\r
2142 }\r
2143 }\r
2144\r
2145 //\r
2146 // The map key they gave us matches what we expect. Fall through and\r
2147 // return success. In an ideal world we would clear out all of\r
2148 // EfiBootServicesCode and EfiBootServicesData. However this function\r
2149 // is not the last one called by ExitBootServices(), so we have to\r
2150 // preserve the memory contents.\r
2151 //\r
2152 } else {\r
2153 Status = EFI_INVALID_PARAMETER;\r
2154 }\r
2155\r
d45fd260 2156Done:\r
28a00297 2157 CoreReleaseMemoryLock ();\r
2158\r
2159 return Status;\r
2160}\r