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