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