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