]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Mem/Page.c
Don't align image address for TeImage, because TeImage section alignment is undefined.
[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 - 2008, Intel Corporation. <BR>\r
5All rights reserved. This 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\r
17#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)\r
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_STAISTICS;\r
31\r
32//\r
33// MemoryMap - The current memory map\r
34//\r
35UINTN mMemoryMapKey = 0;\r
36\r
37//\r
38// mMapStack - space to use as temp storage to build new map descriptors\r
39// mMapDepth - depth of new descriptor stack\r
40//\r
41\r
42#define MAX_MAP_DEPTH 6\r
43UINTN mMapDepth = 0;\r
44MEMORY_MAP mMapStack[MAX_MAP_DEPTH];\r
45UINTN mFreeMapStack = 0;\r
46//\r
47// This list maintain the free memory map list\r
48//\r
49LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
50BOOLEAN mMemoryTypeInformationInitialized = FALSE;\r
51\r
52EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {\r
53 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiReservedMemoryType\r
54 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderCode\r
55 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiLoaderData\r
56 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesCode\r
57 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiBootServicesData\r
58 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesCode\r
59 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiRuntimeServicesData\r
60 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiConventionalMemory\r
61 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiUnusableMemory\r
62 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIReclaimMemory\r
63 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, FALSE }, // EfiACPIMemoryNVS\r
64 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIO\r
65 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE }, // EfiMemoryMappedIOPortSpace\r
66 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, TRUE, TRUE }, // EfiPalCode\r
67 { 0, EFI_MAX_ADDRESS, 0, 0, EfiMaxMemoryType, FALSE, FALSE } // EfiMaxMemoryType\r
68};\r
69\r
70EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS;\r
71\r
72EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {\r
73 { EfiReservedMemoryType, 0 },\r
74 { EfiLoaderCode, 0 },\r
75 { EfiLoaderData, 0 },\r
76 { EfiBootServicesCode, 0 },\r
77 { EfiBootServicesData, 0 },\r
78 { EfiRuntimeServicesCode, 0 },\r
79 { EfiRuntimeServicesData, 0 },\r
80 { EfiConventionalMemory, 0 },\r
81 { EfiUnusableMemory, 0 },\r
82 { EfiACPIReclaimMemory, 0 },\r
83 { EfiACPIMemoryNVS, 0 },\r
84 { EfiMemoryMappedIO, 0 },\r
85 { EfiMemoryMappedIOPortSpace, 0 },\r
86 { EfiPalCode, 0 },\r
87 { EfiMaxMemoryType, 0 }\r
88};\r
89\r
90\r
91/**\r
92 Enter critical section by gaining lock on gMemoryLock.\r
93\r
94**/\r
95VOID\r
96CoreAcquireMemoryLock (\r
97 VOID\r
98 )\r
99{\r
100 CoreAcquireLock (&gMemoryLock);\r
101}\r
102\r
103\r
104\r
105/**\r
106 Exit critical section by releasing lock on gMemoryLock.\r
107\r
108**/\r
109VOID\r
110CoreReleaseMemoryLock (\r
111 VOID\r
112 )\r
113{\r
114 CoreReleaseLock (&gMemoryLock);\r
115}\r
116\r
117\r
118\r
119\r
120/**\r
121 Internal function. Removes a descriptor entry.\r
122\r
123 @param Entry The entry to remove\r
124\r
125**/\r
126VOID\r
127RemoveMemoryMapEntry (\r
128 IN OUT MEMORY_MAP *Entry\r
129 )\r
130{\r
131 RemoveEntryList (&Entry->Link);\r
132 Entry->Link.ForwardLink = NULL;\r
133\r
134 if (Entry->FromPages) {\r
135 //\r
136 // Insert the free memory map descriptor to the end of mFreeMemoryMapEntryList\r
137 //\r
138 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
139 }\r
140}\r
141\r
142/**\r
143 Internal function. Adds a ranges to the memory map.\r
144 The range must not already exist in the map.\r
145\r
146 @param Type The type of memory range to add\r
147 @param Start The starting address in the memory range Must be\r
148 paged aligned\r
149 @param End The last address in the range Must be the last\r
150 byte of a page\r
151 @param Attribute The attributes of the memory range to add\r
152\r
153**/\r
154VOID\r
155CoreAddRange (\r
156 IN EFI_MEMORY_TYPE Type,\r
157 IN EFI_PHYSICAL_ADDRESS Start,\r
158 IN EFI_PHYSICAL_ADDRESS End,\r
159 IN UINT64 Attribute\r
160 )\r
161{\r
162 LIST_ENTRY *Link;\r
163 MEMORY_MAP *Entry;\r
164\r
165 ASSERT ((Start & EFI_PAGE_MASK) == 0);\r
166 ASSERT (End > Start) ;\r
167\r
168 ASSERT_LOCKED (&gMemoryLock);\r
169\r
170 DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));\r
171\r
172 //\r
173 // Memory map being altered so updated key\r
174 //\r
175 mMemoryMapKey += 1;\r
176\r
177 //\r
178 // UEFI 2.0 added an event group for notificaiton on memory map changes.\r
179 // So we need to signal this Event Group every time the memory map changes.\r
180 // If we are in EFI 1.10 compatability mode no event groups will be\r
181 // found and nothing will happen we we call this function. These events\r
182 // will get signaled but since a lock is held around the call to this\r
183 // function the notificaiton events will only be called after this funciton\r
184 // returns and the lock is released.\r
185 //\r
186 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);\r
187\r
188 //\r
189 // Look for adjoining memory descriptor\r
190 //\r
191\r
192 // Two memory descriptors can only be merged if they have the same Type\r
193 // and the same Attribute\r
194 //\r
195\r
196 Link = gMemoryMap.ForwardLink;\r
197 while (Link != &gMemoryMap) {\r
198 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
199 Link = Link->ForwardLink;\r
200\r
201 if (Entry->Type != Type) {\r
202 continue;\r
203 }\r
204\r
205 if (Entry->Attribute != Attribute) {\r
206 continue;\r
207 }\r
208\r
209 if (Entry->End + 1 == Start) {\r
210\r
211 Start = Entry->Start;\r
212 RemoveMemoryMapEntry (Entry);\r
213\r
214 } else if (Entry->Start == End + 1) {\r
215\r
216 End = Entry->End;\r
217 RemoveMemoryMapEntry (Entry);\r
218 }\r
219 }\r
220\r
221 //\r
222 // Add descriptor\r
223 //\r
224\r
225 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;\r
226 mMapStack[mMapDepth].FromPages = FALSE;\r
227 mMapStack[mMapDepth].Type = Type;\r
228 mMapStack[mMapDepth].Start = Start;\r
229 mMapStack[mMapDepth].End = End;\r
230 mMapStack[mMapDepth].VirtualStart = 0;\r
231 mMapStack[mMapDepth].Attribute = Attribute;\r
232 InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);\r
233\r
234 mMapDepth += 1;\r
235 ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
236\r
237 return ;\r
238}\r
239\r
240/**\r
241 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.\r
242 If the list is emtry, then allocate a new page to refuel the list.\r
243 Please Note this algorithm to allocate the memory map descriptor has a property\r
244 that the memory allocated for memory entries always grows, and will never really be freed\r
245 For example, if the current boot uses 2000 memory map entries at the maximum point, but\r
246 ends up with only 50 at the time the OS is booted, then the memory associated with the 1950\r
247 memory map entries is still allocated from EfiBootServicesMemory.\r
248\r
249\r
250 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
251\r
252**/\r
253MEMORY_MAP *\r
254AllocateMemoryMapEntry (\r
255 VOID\r
256 )\r
257{\r
258 MEMORY_MAP* FreeDescriptorEntries;\r
259 MEMORY_MAP* Entry;\r
260 UINTN Index;\r
261\r
262 if (IsListEmpty (&mFreeMemoryMapEntryList)) {\r
263 //\r
264 // The list is empty, to allocate one page to refuel the list\r
265 //\r
266 FreeDescriptorEntries = CoreAllocatePoolPages (EfiBootServicesData, EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION), DEFAULT_PAGE_ALLOCATION);\r
267 if(FreeDescriptorEntries != NULL) {\r
268 //\r
269 // Enque the free memmory map entries into the list\r
270 //\r
271 for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) {\r
272 FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;\r
273 InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);\r
274 }\r
275 } else {\r
276 return NULL;\r
277 }\r
278 }\r
279 //\r
280 // dequeue the first descriptor from the list\r
281 //\r
282 Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
283 RemoveEntryList (&Entry->Link);\r
284\r
285 return Entry;\r
286}\r
287\r
288\r
289/**\r
290 Internal function. Moves any memory descriptors that are on the\r
291 temporary descriptor stack to heap.\r
292\r
293**/\r
294VOID\r
295CoreFreeMemoryMapStack (\r
296 VOID\r
297 )\r
298{\r
299 MEMORY_MAP *Entry;\r
300 MEMORY_MAP *Entry2;\r
301 LIST_ENTRY *Link2;\r
302\r
303 ASSERT_LOCKED (&gMemoryLock);\r
304\r
305 //\r
306 // If already freeing the map stack, then return\r
307 //\r
308 if (mFreeMapStack != 0) {\r
309 return ;\r
310 }\r
311\r
312 //\r
313 // Move the temporary memory descriptor stack into pool\r
314 //\r
315 mFreeMapStack += 1;\r
316\r
317 while (mMapDepth != 0) {\r
318 //\r
319 // Deque an memory map entry from mFreeMemoryMapEntryList\r
320 //\r
321 Entry = AllocateMemoryMapEntry ();\r
322\r
323 ASSERT (Entry);\r
324\r
325 //\r
326 // Update to proper entry\r
327 //\r
328 mMapDepth -= 1;\r
329\r
330 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
331\r
332 //\r
333 // Move this entry to general memory\r
334 //\r
335 RemoveEntryList (&mMapStack[mMapDepth].Link);\r
336 mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
337\r
338 CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
339 Entry->FromPages = TRUE;\r
340\r
341 //\r
342 // Find insertion location\r
343 //\r
344 for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {\r
345 Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
346 if (Entry2->FromPages && Entry2->Start > Entry->Start) {\r
347 break;\r
348 }\r
349 }\r
350\r
351 InsertTailList (Link2, &Entry->Link);\r
352\r
353 } else {\r
354 //\r
355 // This item of mMapStack[mMapDepth] has already been dequeued from gMemoryMap list,\r
356 // so here no need to move it to memory.\r
357 //\r
358 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
359 }\r
360 }\r
361\r
362 mFreeMapStack -= 1;\r
363}\r
364\r
365/**\r
366 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.\r
367\r
368**/\r
369VOID\r
370PromoteMemoryResource (\r
371 VOID\r
372 )\r
373{\r
374 LIST_ENTRY *Link;\r
375 EFI_GCD_MAP_ENTRY *Entry;\r
376\r
377 DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));\r
378\r
379 CoreAcquireGcdMemoryLock ();\r
380\r
381 Link = mGcdMemorySpaceMap.ForwardLink;\r
382 while (Link != &mGcdMemorySpaceMap) {\r
383\r
384 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
385\r
386 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
387 Entry->EndAddress < EFI_MAX_ADDRESS &&\r
388 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
389 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {\r
390 //\r
391 // Update the GCD map\r
392 //\r
393 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;\r
394 Entry->Capabilities |= EFI_MEMORY_TESTED;\r
395 Entry->ImageHandle = gDxeCoreImageHandle;\r
396 Entry->DeviceHandle = NULL;\r
397\r
398 //\r
399 // Add to allocable system memory resource\r
400 //\r
401\r
402 CoreAddRange (\r
403 EfiConventionalMemory,\r
404 Entry->BaseAddress,\r
405 Entry->EndAddress,\r
406 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
407 );\r
408 CoreFreeMemoryMapStack ();\r
409\r
410 }\r
411\r
412 Link = Link->ForwardLink;\r
413 }\r
414\r
415 CoreReleaseGcdMemoryLock ();\r
416\r
417 return;\r
418}\r
419\r
420\r
421/**\r
422 Called to initialize the memory map and add descriptors to\r
423 the current descriptor list.\r
424 The first descriptor that is added must be general usable\r
425 memory as the addition allocates heap.\r
426\r
427 @param Type The type of memory to add\r
428 @param Start The starting address in the memory range Must be\r
429 page aligned\r
430 @param NumberOfPages The number of pages in the range\r
431 @param Attribute Attributes of the memory to add\r
432\r
433 @return None. The range is added to the memory map\r
434\r
435**/\r
436VOID\r
437CoreAddMemoryDescriptor (\r
438 IN EFI_MEMORY_TYPE Type,\r
439 IN EFI_PHYSICAL_ADDRESS Start,\r
440 IN UINT64 NumberOfPages,\r
441 IN UINT64 Attribute\r
442 )\r
443{\r
444 EFI_PHYSICAL_ADDRESS End;\r
445 EFI_STATUS Status;\r
446 UINTN Index;\r
447 UINTN FreeIndex;\r
448\r
449 if ((Start & EFI_PAGE_MASK) != 0) {\r
450 return;\r
451 }\r
452\r
453 if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {\r
454 return;\r
455 }\r
456\r
457 CoreAcquireMemoryLock ();\r
458 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
459 CoreAddRange (Type, Start, End, Attribute);\r
460 CoreFreeMemoryMapStack ();\r
461 CoreReleaseMemoryLock ();\r
462\r
463 //\r
464 // Check to see if the statistics for the different memory types have already been established\r
465 //\r
466 if (mMemoryTypeInformationInitialized) {\r
467 return;\r
468 }\r
469\r
470 //\r
471 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array\r
472 //\r
473 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
474 //\r
475 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
476 //\r
477 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
478 if (Type < 0 || Type > EfiMaxMemoryType) {\r
479 continue;\r
480 }\r
481\r
482 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
483 //\r
484 // Allocate pages for the current memory type from the top of available memory\r
485 //\r
486 Status = CoreAllocatePages (\r
487 AllocateAnyPages,\r
488 Type,\r
489 gMemoryTypeInformation[Index].NumberOfPages,\r
490 &mMemoryTypeStatistics[Type].BaseAddress\r
491 );\r
492 if (EFI_ERROR (Status)) {\r
493 //\r
494 // If an error occurs allocating the pages for the current memory type, then\r
495 // free all the pages allocates for the previous memory types and return. This\r
496 // operation with be retied when/if more memory is added to the system\r
497 //\r
498 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {\r
499 //\r
500 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
501 //\r
502 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);\r
503 if (Type < 0 || Type > EfiMaxMemoryType) {\r
504 continue;\r
505 }\r
506\r
507 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {\r
508 CoreFreePages (\r
509 mMemoryTypeStatistics[Type].BaseAddress,\r
510 gMemoryTypeInformation[FreeIndex].NumberOfPages\r
511 );\r
512 mMemoryTypeStatistics[Type].BaseAddress = 0;\r
513 mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS;\r
514 }\r
515 }\r
516 return;\r
517 }\r
518\r
519 //\r
520 // Compute the address at the top of the current statistics\r
521 //\r
522 mMemoryTypeStatistics[Type].MaximumAddress =\r
523 mMemoryTypeStatistics[Type].BaseAddress +\r
524 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
525\r
526 //\r
527 // If the current base address is the lowest address so far, then update the default\r
528 // maximum address\r
529 //\r
530 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {\r
531 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;\r
532 }\r
533 }\r
534 }\r
535\r
536 //\r
537 // There was enough system memory for all the the memory types were allocated. So,\r
538 // those memory areas can be freed for future allocations, and all future memory\r
539 // allocations can occur within their respective bins\r
540 //\r
541 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
542 //\r
543 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
544 //\r
545 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
546 if (Type < 0 || Type > EfiMaxMemoryType) {\r
547 continue;\r
548 }\r
549\r
550 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
551 CoreFreePages (\r
552 mMemoryTypeStatistics[Type].BaseAddress,\r
553 gMemoryTypeInformation[Index].NumberOfPages\r
554 );\r
555 mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;\r
556 gMemoryTypeInformation[Index].NumberOfPages = 0;\r
557 }\r
558 }\r
559\r
560 //\r
561 // If the number of pages reserved for a memory type is 0, then all allocations for that type\r
562 // should be in the default range.\r
563 //\r
564 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {\r
565 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
566 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {\r
567 mMemoryTypeStatistics[Type].InformationIndex = Index;\r
568 }\r
569 }\r
570 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;\r
571 if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) {\r
572 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;\r
573 }\r
574 }\r
575\r
576 mMemoryTypeInformationInitialized = TRUE;\r
577}\r
578\r
579\r
580/**\r
581 Internal function. Converts a memory range to the specified type.\r
582 The range must exist in the memory map.\r
583\r
584 @param Start The first address of the range Must be page\r
585 aligned\r
586 @param NumberOfPages The number of pages to convert\r
587 @param NewType The new type for the memory range\r
588\r
589 @retval EFI_INVALID_PARAMETER Invalid parameter\r
590 @retval EFI_NOT_FOUND Could not find a descriptor cover the specified\r
591 range or convertion not allowed.\r
592 @retval EFI_SUCCESS Successfully converts the memory range to the\r
593 specified type.\r
594\r
595**/\r
596EFI_STATUS\r
597CoreConvertPages (\r
598 IN UINT64 Start,\r
599 IN UINT64 NumberOfPages,\r
600 IN EFI_MEMORY_TYPE NewType\r
601 )\r
602{\r
603\r
604 UINT64 NumberOfBytes;\r
605 UINT64 End;\r
606 UINT64 RangeEnd;\r
607 UINT64 Attribute;\r
608 LIST_ENTRY *Link;\r
609 MEMORY_MAP *Entry;\r
610\r
611 Entry = NULL;\r
612 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);\r
613 End = Start + NumberOfBytes - 1;\r
614\r
615 ASSERT (NumberOfPages);\r
616 ASSERT ((Start & EFI_PAGE_MASK) == 0);\r
617 ASSERT (End > Start) ;\r
618 ASSERT_LOCKED (&gMemoryLock);\r
619\r
620 if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start > (Start + NumberOfBytes))) {\r
621 return EFI_INVALID_PARAMETER;\r
622 }\r
623\r
624 //\r
625 // Convert the entire range\r
626 //\r
627\r
628 while (Start < End) {\r
629\r
630 //\r
631 // Find the entry that the covers the range\r
632 //\r
633 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
634 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
635\r
636 if (Entry->Start <= Start && Entry->End > Start) {\r
637 break;\r
638 }\r
639 }\r
640\r
641 if (Link == &gMemoryMap) {\r
642 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));\r
643 return EFI_NOT_FOUND;\r
644 }\r
645\r
646 //\r
647 // Convert range to the end, or to the end of the descriptor\r
648 // if that's all we've got\r
649 //\r
650 RangeEnd = End;\r
651 if (Entry->End < End) {\r
652 RangeEnd = Entry->End;\r
653 }\r
654\r
655 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType));\r
656\r
657 //\r
658 // Debug code - verify conversion is allowed\r
659 //\r
660 if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {\r
661 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types\n"));\r
662 return EFI_NOT_FOUND;\r
663 }\r
664\r
665 //\r
666 // Update counters for the number of pages allocated to each memory type\r
667 //\r
668 if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {\r
669 if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress &&\r
670 Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) {\r
671 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {\r
672 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;\r
673 } else {\r
674 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;\r
675 }\r
676 }\r
677 }\r
678\r
679 if (NewType >= 0 && NewType < EfiMaxMemoryType) {\r
680 if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) {\r
681 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;\r
682 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages >\r
683 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {\r
684 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;\r
685 }\r
686 }\r
687 }\r
688\r
689 //\r
690 // Pull range out of descriptor\r
691 //\r
692 if (Entry->Start == Start) {\r
693\r
694 //\r
695 // Clip start\r
696 //\r
697 Entry->Start = RangeEnd + 1;\r
698\r
699 } else if (Entry->End == RangeEnd) {\r
700\r
701 //\r
702 // Clip end\r
703 //\r
704 Entry->End = Start - 1;\r
705\r
706 } else {\r
707\r
708 //\r
709 // Pull it out of the center, clip current\r
710 //\r
711\r
712 //\r
713 // Add a new one\r
714 //\r
715 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;\r
716 mMapStack[mMapDepth].FromPages = FALSE;\r
717 mMapStack[mMapDepth].Type = Entry->Type;\r
718 mMapStack[mMapDepth].Start = RangeEnd+1;\r
719 mMapStack[mMapDepth].End = Entry->End;\r
720\r
721 //\r
722 // Inherit Attribute from the Memory Descriptor that is being clipped\r
723 //\r
724 mMapStack[mMapDepth].Attribute = Entry->Attribute;\r
725\r
726 Entry->End = Start - 1;\r
727 ASSERT (Entry->Start < Entry->End);\r
728\r
729 Entry = &mMapStack[mMapDepth];\r
730 InsertTailList (&gMemoryMap, &Entry->Link);\r
731\r
732 mMapDepth += 1;\r
733 ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
734 }\r
735\r
736 //\r
737 // The new range inherits the same Attribute as the Entry\r
738 //it is being cut out of\r
739 //\r
740 Attribute = Entry->Attribute;\r
741\r
742 //\r
743 // If the descriptor is empty, then remove it from the map\r
744 //\r
745 if (Entry->Start == Entry->End + 1) {\r
746 RemoveMemoryMapEntry (Entry);\r
747 Entry = NULL;\r
748 }\r
749\r
750 //\r
751 // Add our new range in\r
752 //\r
753 CoreAddRange (NewType, Start, RangeEnd, Attribute);\r
754\r
755 //\r
756 // Move any map descriptor stack to general pool\r
757 //\r
758 CoreFreeMemoryMapStack ();\r
759\r
760 //\r
761 // Bump the starting address, and convert the next range\r
762 //\r
763 Start = RangeEnd + 1;\r
764 }\r
765\r
766 //\r
767 // Converted the whole range, done\r
768 //\r
769\r
770 return EFI_SUCCESS;\r
771}\r
772\r
773\r
774\r
775/**\r
776 Internal function. Finds a consecutive free page range below\r
777 the requested address.\r
778\r
779 @param MaxAddress The address that the range must be below\r
780 @param NumberOfPages Number of pages needed\r
781 @param NewType The type of memory the range is going to be\r
782 turned into\r
783 @param Alignment Bits to align with\r
784\r
785 @return The base address of the range, or 0 if the range was not found\r
786\r
787**/\r
788UINT64\r
789CoreFindFreePagesI (\r
790 IN UINT64 MaxAddress,\r
791 IN UINT64 NumberOfPages,\r
792 IN EFI_MEMORY_TYPE NewType,\r
793 IN UINTN Alignment\r
794 )\r
795{\r
796 UINT64 NumberOfBytes;\r
797 UINT64 Target;\r
798 UINT64 DescStart;\r
799 UINT64 DescEnd;\r
800 UINT64 DescNumberOfBytes;\r
801 LIST_ENTRY *Link;\r
802 MEMORY_MAP *Entry;\r
803\r
804 if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {\r
805 return 0;\r
806 }\r
807\r
808 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {\r
809\r
810 //\r
811 // If MaxAddress is not aligned to the end of a page\r
812 //\r
813\r
814 //\r
815 // Change MaxAddress to be 1 page lower\r
816 //\r
817 MaxAddress -= (EFI_PAGE_MASK + 1);\r
818\r
819 //\r
820 // Set MaxAddress to a page boundary\r
821 //\r
822 MaxAddress &= ~EFI_PAGE_MASK;\r
823\r
824 //\r
825 // Set MaxAddress to end of the page\r
826 //\r
827 MaxAddress |= EFI_PAGE_MASK;\r
828 }\r
829\r
830 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);\r
831 Target = 0;\r
832\r
833 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
834 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
835\r
836 //\r
837 // If it's not a free entry, don't bother with it\r
838 //\r
839 if (Entry->Type != EfiConventionalMemory) {\r
840 continue;\r
841 }\r
842\r
843 DescStart = Entry->Start;\r
844 DescEnd = Entry->End;\r
845\r
846 //\r
847 // If desc is past max allowed address, skip it\r
848 //\r
849 if (DescStart >= MaxAddress) {\r
850 continue;\r
851 }\r
852\r
853 //\r
854 // If desc ends past max allowed address, clip the end\r
855 //\r
856 if (DescEnd >= MaxAddress) {\r
857 DescEnd = MaxAddress;\r
858 }\r
859\r
860 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;\r
861\r
862 //\r
863 // Compute the number of bytes we can used from this\r
864 // descriptor, and see it's enough to satisfy the request\r
865 //\r
866 DescNumberOfBytes = DescEnd - DescStart + 1;\r
867\r
868 if (DescNumberOfBytes >= NumberOfBytes) {\r
869\r
870 //\r
871 // If this is the best match so far remember it\r
872 //\r
873 if (DescEnd > Target) {\r
874 Target = DescEnd;\r
875 }\r
876 }\r
877 }\r
878\r
879 //\r
880 // If this is a grow down, adjust target to be the allocation base\r
881 //\r
882 Target -= NumberOfBytes - 1;\r
883\r
884 //\r
885 // If we didn't find a match, return 0\r
886 //\r
887 if ((Target & EFI_PAGE_MASK) != 0) {\r
888 return 0;\r
889 }\r
890\r
891 return Target;\r
892}\r
893\r
894\r
895/**\r
896 Internal function. Finds a consecutive free page range below\r
897 the requested address\r
898\r
899 @param MaxAddress The address that the range must be below\r
900 @param NoPages Number of pages needed\r
901 @param NewType The type of memory the range is going to be\r
902 turned into\r
903 @param Alignment Bits to align with\r
904\r
905 @return The base address of the range, or 0 if the range was not found.\r
906\r
907**/\r
908UINT64\r
909FindFreePages (\r
910 IN UINT64 MaxAddress,\r
911 IN UINT64 NoPages,\r
912 IN EFI_MEMORY_TYPE NewType,\r
913 IN UINTN Alignment\r
914 )\r
915{\r
916 UINT64 NewMaxAddress;\r
917 UINT64 Start;\r
918\r
919 NewMaxAddress = MaxAddress;\r
920\r
921 if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {\r
922 NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress;\r
923 } else {\r
924 if (NewMaxAddress > mDefaultMaximumAddress) {\r
925 NewMaxAddress = mDefaultMaximumAddress;\r
926 }\r
927 }\r
928\r
929 Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);\r
930 if (Start == 0) {\r
931 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);\r
932 if (Start == 0) {\r
933 //\r
934 // Here means there may be no enough memory to use, so try to go through\r
935 // all the memory descript to promote the untested memory directly\r
936 //\r
937 PromoteMemoryResource ();\r
938\r
939 //\r
940 // Allocate memory again after the memory resource re-arranged\r
941 //\r
942 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);\r
943 }\r
944 }\r
945\r
946 return Start;\r
947}\r
948\r
949\r
950\r
951/**\r
952 Allocates pages from the memory map.\r
953\r
954 @param Type The type of allocation to perform\r
955 @param MemoryType The type of memory to turn the allocated pages\r
956 into\r
957 @param NumberOfPages The number of pages to allocate\r
958 @param Memory A pointer to receive the base allocated memory\r
959 address\r
960\r
961 @return Status. On success, Memory is filled in with the base address allocated\r
962 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in\r
963 spec.\r
964 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
965 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
966 @retval EFI_SUCCESS Pages successfully allocated.\r
967\r
968**/\r
969EFI_STATUS\r
970EFIAPI\r
971CoreAllocatePages (\r
972 IN EFI_ALLOCATE_TYPE Type,\r
973 IN EFI_MEMORY_TYPE MemoryType,\r
974 IN UINTN NumberOfPages,\r
975 IN OUT EFI_PHYSICAL_ADDRESS *Memory\r
976 )\r
977{\r
978 EFI_STATUS Status;\r
979 UINT64 Start;\r
980 UINT64 MaxAddress;\r
981 UINTN Alignment;\r
982\r
983 if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) {\r
984 return EFI_INVALID_PARAMETER;\r
985 }\r
986\r
987 if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) ||\r
988 MemoryType == EfiConventionalMemory) {\r
989 return EFI_INVALID_PARAMETER;\r
990 }\r
991\r
992 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;\r
993\r
994 if (MemoryType == EfiACPIReclaimMemory ||\r
995 MemoryType == EfiACPIMemoryNVS ||\r
996 MemoryType == EfiRuntimeServicesCode ||\r
997 MemoryType == EfiRuntimeServicesData) {\r
998\r
999 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
1000 }\r
1001\r
1002 if (Type == AllocateAddress) {\r
1003 if ((*Memory & (Alignment - 1)) != 0) {\r
1004 return EFI_NOT_FOUND;\r
1005 }\r
1006 }\r
1007\r
1008 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;\r
1009 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);\r
1010\r
1011 //\r
1012 // If this is for below a particular address, then\r
1013 //\r
1014 Start = *Memory;\r
1015\r
1016 //\r
1017 // The max address is the max natively addressable address for the processor\r
1018 //\r
1019 MaxAddress = EFI_MAX_ADDRESS;\r
1020\r
1021 if (Type == AllocateMaxAddress) {\r
1022 MaxAddress = Start;\r
1023 }\r
1024\r
1025 CoreAcquireMemoryLock ();\r
1026\r
1027 //\r
1028 // If not a specific address, then find an address to allocate\r
1029 //\r
1030 if (Type != AllocateAddress) {\r
1031 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);\r
1032 if (Start == 0) {\r
1033 Status = EFI_OUT_OF_RESOURCES;\r
1034 goto Done;\r
1035 }\r
1036 }\r
1037\r
1038 //\r
1039 // Convert pages from FreeMemory to the requested type\r
1040 //\r
1041 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);\r
1042\r
1043Done:\r
1044 CoreReleaseMemoryLock ();\r
1045\r
1046 if (!EFI_ERROR (Status)) {\r
1047 *Memory = Start;\r
1048 }\r
1049\r
1050 return Status;\r
1051}\r
1052\r
1053\r
1054/**\r
1055 Frees previous allocated pages.\r
1056\r
1057 @param Memory Base address of memory being freed\r
1058 @param NumberOfPages The number of pages to free\r
1059\r
1060 @retval EFI_NOT_FOUND Could not find the entry that covers the range\r
1061 @retval EFI_INVALID_PARAMETER Address not aligned\r
1062 @return EFI_SUCCESS -Pages successfully freed.\r
1063\r
1064**/\r
1065EFI_STATUS\r
1066EFIAPI\r
1067CoreFreePages (\r
1068 IN EFI_PHYSICAL_ADDRESS Memory,\r
1069 IN UINTN NumberOfPages\r
1070 )\r
1071{\r
1072 EFI_STATUS Status;\r
1073 LIST_ENTRY *Link;\r
1074 MEMORY_MAP *Entry;\r
1075 UINTN Alignment;\r
1076\r
1077 //\r
1078 // Free the range\r
1079 //\r
1080 CoreAcquireMemoryLock ();\r
1081\r
1082 //\r
1083 // Find the entry that the covers the range\r
1084 //\r
1085 Entry = NULL;\r
1086 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1087 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1088 if (Entry->Start <= Memory && Entry->End > Memory) {\r
1089 break;\r
1090 }\r
1091 }\r
1092 if (Link == &gMemoryMap) {\r
1093 CoreReleaseMemoryLock ();\r
1094 return EFI_NOT_FOUND;\r
1095 }\r
1096\r
1097 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;\r
1098\r
1099 if (Entry->Type == EfiACPIReclaimMemory ||\r
1100 Entry->Type == EfiACPIMemoryNVS ||\r
1101 Entry->Type == EfiRuntimeServicesCode ||\r
1102 Entry->Type == EfiRuntimeServicesData) {\r
1103\r
1104 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
1105\r
1106 }\r
1107\r
1108 if ((Memory & (Alignment - 1)) != 0) {\r
1109 CoreReleaseMemoryLock ();\r
1110 return EFI_INVALID_PARAMETER;\r
1111 }\r
1112\r
1113 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;\r
1114 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);\r
1115\r
1116 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
1117\r
1118 CoreReleaseMemoryLock ();\r
1119\r
1120 if (EFI_ERROR (Status)) {\r
1121 return Status;\r
1122 }\r
1123\r
1124 //\r
1125 // Destroy the contents\r
1126 //\r
1127 if (Memory < EFI_MAX_ADDRESS) {\r
1128 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);\r
1129 }\r
1130\r
1131 return Status;\r
1132}\r
1133\r
1134\r
1135/**\r
1136 This function returns a copy of the current memory map. The map is an array of\r
1137 memory descriptors, each of which describes a contiguous block of memory.\r
1138\r
1139 @param MemoryMapSize A pointer to the size, in bytes, of the\r
1140 MemoryMap buffer. On input, this is the size of\r
1141 the buffer allocated by the caller. On output,\r
1142 it is the size of the buffer returned by the\r
1143 firmware if the buffer was large enough, or the\r
1144 size of the buffer needed to contain the map if\r
1145 the buffer was too small.\r
1146 @param MemoryMap A pointer to the buffer in which firmware places\r
1147 the current memory map.\r
1148 @param MapKey A pointer to the location in which firmware\r
1149 returns the key for the current memory map.\r
1150 @param DescriptorSize A pointer to the location in which firmware\r
1151 returns the size, in bytes, of an individual\r
1152 EFI_MEMORY_DESCRIPTOR.\r
1153 @param DescriptorVersion A pointer to the location in which firmware\r
1154 returns the version number associated with the\r
1155 EFI_MEMORY_DESCRIPTOR.\r
1156\r
1157 @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
1158 buffer.\r
1159 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
1160 buffer size needed to hold the memory map is\r
1161 returned in MemoryMapSize.\r
1162 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1163\r
1164**/\r
1165EFI_STATUS\r
1166EFIAPI\r
1167CoreGetMemoryMap (\r
1168 IN OUT UINTN *MemoryMapSize,\r
1169 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1170 OUT UINTN *MapKey,\r
1171 OUT UINTN *DescriptorSize,\r
1172 OUT UINT32 *DescriptorVersion\r
1173 )\r
1174{\r
1175 EFI_STATUS Status;\r
1176 UINTN Size;\r
1177 UINTN BufferSize;\r
1178 UINTN NumberOfRuntimeEntries;\r
1179 LIST_ENTRY *Link;\r
1180 MEMORY_MAP *Entry;\r
1181 EFI_GCD_MAP_ENTRY *GcdMapEntry;\r
1182 EFI_MEMORY_TYPE Type;\r
1183\r
1184 //\r
1185 // Make sure the parameters are valid\r
1186 //\r
1187 if (MemoryMapSize == NULL) {\r
1188 return EFI_INVALID_PARAMETER;\r
1189 }\r
1190\r
1191 CoreAcquireGcdMemoryLock ();\r
1192\r
1193 //\r
1194 // Count the number of Reserved and MMIO entries that are marked for runtime use\r
1195 //\r
1196 NumberOfRuntimeEntries = 0;\r
1197 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
1198 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1199 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
1200 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {\r
1201 if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {\r
1202 NumberOfRuntimeEntries++;\r
1203 }\r
1204 }\r
1205 }\r
1206\r
1207 Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
1208\r
1209 //\r
1210 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
1211 // prevent people from having pointer math bugs in their code.\r
1212 // now you have to use *DescriptorSize to make things work.\r
1213 //\r
1214 Size += sizeof(UINT64) - (Size % sizeof (UINT64));\r
1215\r
1216 if (DescriptorSize != NULL) {\r
1217 *DescriptorSize = Size;\r
1218 }\r
1219\r
1220 if (DescriptorVersion != NULL) {\r
1221 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
1222 }\r
1223\r
1224 CoreAcquireMemoryLock ();\r
1225\r
1226 //\r
1227 // Compute the buffer size needed to fit the entire map\r
1228 //\r
1229 BufferSize = Size * NumberOfRuntimeEntries;\r
1230 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1231 BufferSize += Size;\r
1232 }\r
1233\r
1234 if (*MemoryMapSize < BufferSize) {\r
1235 Status = EFI_BUFFER_TOO_SMALL;\r
1236 goto Done;\r
1237 }\r
1238\r
1239 if (MemoryMap == NULL) {\r
1240 Status = EFI_INVALID_PARAMETER;\r
1241 goto Done;\r
1242 }\r
1243\r
1244 //\r
1245 // Build the map\r
1246 //\r
1247 ZeroMem (MemoryMap, BufferSize);\r
1248 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1249 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1250 ASSERT (Entry->VirtualStart == 0);\r
1251\r
1252 //\r
1253 // Convert internal map into an EFI_MEMORY_DESCRIPTOR\r
1254 //\r
1255 MemoryMap->Type = Entry->Type;\r
1256 MemoryMap->PhysicalStart = Entry->Start;\r
1257 MemoryMap->VirtualStart = Entry->VirtualStart;\r
1258 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
1259 //\r
1260 // If the memory type is EfiConventionalMemory, then determine if the range is part of a\r
1261 // memory type bin and needs to be converted to the same memory type as the rest of the\r
1262 // memory type bin in order to minimize EFI Memory Map changes across reboots. This\r
1263 // improves the chances for a successful S4 resume in the presence of minor page allocation\r
1264 // differences across reboots.\r
1265 //\r
1266 if (MemoryMap->Type == EfiConventionalMemory) {\r
1267 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {\r
1268 if (mMemoryTypeStatistics[Type].Special &&\r
1269 mMemoryTypeStatistics[Type].NumberOfPages > 0 &&\r
1270 Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&\r
1271 Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {\r
1272 MemoryMap->Type = Type;\r
1273 }\r
1274 }\r
1275 }\r
1276 MemoryMap->Attribute = Entry->Attribute;\r
1277 if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {\r
1278 MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;\r
1279 }\r
1280\r
1281 MemoryMap = NextMemoryDescriptor (MemoryMap, Size);\r
1282 }\r
1283\r
1284 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
1285 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1286 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
1287 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {\r
1288 if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {\r
1289\r
1290 MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;\r
1291 MemoryMap->VirtualStart = 0;\r
1292 MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);\r
1293 MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;\r
1294\r
1295 if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {\r
1296 MemoryMap->Type = EfiReservedMemoryType;\r
1297 } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
1298 if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {\r
1299 MemoryMap->Type = EfiMemoryMappedIOPortSpace;\r
1300 } else {\r
1301 MemoryMap->Type = EfiMemoryMappedIO;\r
1302 }\r
1303 }\r
1304\r
1305 MemoryMap = NextMemoryDescriptor (MemoryMap, Size);\r
1306 }\r
1307 }\r
1308 }\r
1309\r
1310 Status = EFI_SUCCESS;\r
1311\r
1312Done:\r
1313\r
1314 CoreReleaseMemoryLock ();\r
1315\r
1316 CoreReleaseGcdMemoryLock ();\r
1317\r
1318 //\r
1319 // Update the map key finally\r
1320 //\r
1321 if (MapKey != NULL) {\r
1322 *MapKey = mMemoryMapKey;\r
1323 }\r
1324\r
1325 *MemoryMapSize = BufferSize;\r
1326\r
1327 return Status;\r
1328}\r
1329\r
1330\r
1331/**\r
1332 Internal function. Used by the pool functions to allocate pages\r
1333 to back pool allocation requests.\r
1334\r
1335 @param PoolType The type of memory for the new pool pages\r
1336 @param NumberOfPages No of pages to allocate\r
1337 @param Alignment Bits to align.\r
1338\r
1339 @return The allocated memory, or NULL\r
1340\r
1341**/\r
1342VOID *\r
1343CoreAllocatePoolPages (\r
1344 IN EFI_MEMORY_TYPE PoolType,\r
1345 IN UINTN NumberOfPages,\r
1346 IN UINTN Alignment\r
1347 )\r
1348{\r
1349 UINT64 Start;\r
1350\r
1351 //\r
1352 // Find the pages to convert\r
1353 //\r
1354 Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment);\r
1355\r
1356 //\r
1357 // Convert it to boot services data\r
1358 //\r
1359 if (Start == 0) {\r
1360 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages));\r
1361 } else {\r
1362 CoreConvertPages (Start, NumberOfPages, PoolType);\r
1363 }\r
1364\r
1365 return (VOID *)(UINTN) Start;\r
1366}\r
1367\r
1368\r
1369/**\r
1370 Internal function. Frees pool pages allocated via AllocatePoolPages ()\r
1371\r
1372 @param Memory The base address to free\r
1373 @param NumberOfPages The number of pages to free\r
1374\r
1375**/\r
1376VOID\r
1377CoreFreePoolPages (\r
1378 IN EFI_PHYSICAL_ADDRESS Memory,\r
1379 IN UINTN NumberOfPages\r
1380 )\r
1381{\r
1382 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
1383}\r
1384\r
1385\r
1386\r
1387/**\r
1388 Make sure the memory map is following all the construction rules,\r
1389 it is the last time to check memory map error before exit boot services.\r
1390\r
1391 @param MapKey Memory map key\r
1392\r
1393 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction\r
1394 rules.\r
1395 @retval EFI_SUCCESS Valid memory map.\r
1396\r
1397**/\r
1398EFI_STATUS\r
1399CoreTerminateMemoryMap (\r
1400 IN UINTN MapKey\r
1401 )\r
1402{\r
1403 EFI_STATUS Status;\r
1404 LIST_ENTRY *Link;\r
1405 MEMORY_MAP *Entry;\r
1406\r
1407 Status = EFI_SUCCESS;\r
1408\r
1409 CoreAcquireMemoryLock ();\r
1410\r
1411 if (MapKey == mMemoryMapKey) {\r
1412\r
1413 //\r
1414 // Make sure the memory map is following all the construction rules\r
1415 // This is the last chance we will be able to display any messages on\r
1416 // the console devices.\r
1417 //\r
1418\r
1419 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1420 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1421 if (Entry->Attribute & EFI_MEMORY_RUNTIME) {\r
1422 if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {\r
1423 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));\r
1424 Status = EFI_INVALID_PARAMETER;\r
1425 goto Done;\r
1426 }\r
1427 if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
1428 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
1429 Status = EFI_INVALID_PARAMETER;\r
1430 goto Done;\r
1431 }\r
1432 if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
1433 DEBUG((DEBUG_ERROR | DEBUG_PAGE, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
1434 Status = EFI_INVALID_PARAMETER;\r
1435 goto Done;\r
1436 }\r
1437 }\r
1438 }\r
1439\r
1440 //\r
1441 // The map key they gave us matches what we expect. Fall through and\r
1442 // return success. In an ideal world we would clear out all of\r
1443 // EfiBootServicesCode and EfiBootServicesData. However this function\r
1444 // is not the last one called by ExitBootServices(), so we have to\r
1445 // preserve the memory contents.\r
1446 //\r
1447 } else {\r
1448 Status = EFI_INVALID_PARAMETER;\r
1449 }\r
1450\r
1451Done:\r
1452 CoreReleaseMemoryLock ();\r
1453\r
1454 return Status;\r
1455}\r
1456\r
1457\r
1458\r
1459\r
1460\r
1461\r
1462\r
1463\r
1464\r