Don't align image address for TeImage, because TeImage section alignment is undefined.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Mem / Page.c
CommitLineData
504214c4 1/** @file\r
504214c4
LG
2 UEFI Memory page management functions.\r
3\r
23c98c94 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
28a00297 12\r
504214c4 13**/\r
28a00297 14\r
9c4ac31c 15#include "DxeMain.h"\r
28a00297 16\r
17#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)\r
18\r
19//\r
d45fd260 20// Entry for tracking the memory regions for each memory type to coalesce similar memory types\r
28a00297 21//\r
22typedef struct {\r
23 EFI_PHYSICAL_ADDRESS BaseAddress;\r
24 EFI_PHYSICAL_ADDRESS MaximumAddress;\r
25 UINT64 CurrentNumberOfPages;\r
b74350e9 26 UINT64 NumberOfPages;\r
28a00297 27 UINTN InformationIndex;\r
b74350e9 28 BOOLEAN Special;\r
29 BOOLEAN Runtime;\r
28a00297 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
e94a9ff7 49LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
50BOOLEAN mMemoryTypeInformationInitialized = FALSE;\r
28a00297 51\r
52EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {\r
b74350e9 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
28a00297 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
d9177625 90\r
162ed594 91/**\r
d9177625 92 Enter critical section by gaining lock on gMemoryLock.\r
162ed594 93\r
94**/\r
23c98c94 95VOID\r
d9177625 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
28a00297 111 VOID\r
d9177625 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
162ed594 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
022c6d45 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
28a00297 152\r
162ed594 153**/\r
28a00297 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
d9177625 160 )\r
161{\r
162 LIST_ENTRY *Link;\r
163 MEMORY_MAP *Entry;\r
28a00297 164\r
d9177625 165 ASSERT ((Start & EFI_PAGE_MASK) == 0);\r
166 ASSERT (End > Start) ;\r
162ed594 167\r
d9177625 168 ASSERT_LOCKED (&gMemoryLock);\r
28a00297 169\r
d9177625 170 DEBUG ((DEBUG_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));\r
162ed594 171\r
d9177625 172 //\r
173 // Memory map being altered so updated key\r
174 //\r
175 mMemoryMapKey += 1;\r
162ed594 176\r
d9177625 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
162ed594 187\r
d9177625 188 //\r
189 // Look for adjoining memory descriptor\r
190 //\r
28a00297 191\r
d9177625 192 // Two memory descriptors can only be merged if they have the same Type\r
193 // and the same Attribute\r
194 //\r
162ed594 195\r
d9177625 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
162ed594 200\r
d9177625 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
022c6d45 239\r
162ed594 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
28a00297 253MEMORY_MAP *\r
254AllocateMemoryMapEntry (\r
255 VOID\r
d9177625 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
022c6d45 287\r
162ed594 288\r
289/**\r
d9177625 290 Internal function. Moves any memory descriptors that are on the\r
291 temporary descriptor stack to heap.\r
162ed594 292\r
293**/\r
28a00297 294VOID\r
d9177625 295CoreFreeMemoryMapStack (\r
28a00297 296 VOID\r
297 )\r
28a00297 298{\r
d9177625 299 MEMORY_MAP *Entry;\r
300 MEMORY_MAP *Entry2;\r
301 LIST_ENTRY *Link2;\r
28a00297 302\r
d9177625 303 ASSERT_LOCKED (&gMemoryLock);\r
28a00297 304\r
d9177625 305 //\r
306 // If already freeing the map stack, then return\r
307 //\r
308 if (mFreeMapStack != 0) {\r
309 return ;\r
310 }\r
162ed594 311\r
d9177625 312 //\r
313 // Move the temporary memory descriptor stack into pool\r
314 //\r
315 mFreeMapStack += 1;\r
162ed594 316\r
d9177625 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
28a00297 361\r
d9177625 362 mFreeMapStack -= 1;\r
363}\r
162ed594 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
28a00297 369VOID\r
370PromoteMemoryResource (\r
371 VOID\r
372 )\r
28a00297 373{\r
374 LIST_ENTRY *Link;\r
375 EFI_GCD_MAP_ENTRY *Entry;\r
376\r
d45fd260 377 DEBUG ((DEBUG_PAGE, "Promote the memory resource\n"));\r
022c6d45 378\r
28a00297 379 CoreAcquireGcdMemoryLock ();\r
022c6d45 380\r
28a00297 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
022c6d45 400 //\r
28a00297 401\r
402 CoreAddRange (\r
022c6d45 403 EfiConventionalMemory,\r
404 Entry->BaseAddress,\r
405 Entry->EndAddress,\r
28a00297 406 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
407 );\r
408 CoreFreeMemoryMapStack ();\r
022c6d45 409\r
28a00297 410 }\r
411\r
412 Link = Link->ForwardLink;\r
413 }\r
022c6d45 414\r
28a00297 415 CoreReleaseGcdMemoryLock ();\r
022c6d45 416\r
28a00297 417 return;\r
418}\r
419\r
28a00297 420\r
162ed594 421/**\r
28a00297 422 Called to initialize the memory map and add descriptors to\r
423 the current descriptor list.\r
28a00297 424 The first descriptor that is added must be general usable\r
425 memory as the addition allocates heap.\r
426\r
022c6d45 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
28a00297 432\r
162ed594 433 @return None. The range is added to the memory map\r
28a00297 434\r
162ed594 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
28a00297 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
022c6d45 456\r
28a00297 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
022c6d45 494 // If an error occurs allocating the pages for the current memory type, then\r
28a00297 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
022c6d45 509 mMemoryTypeStatistics[Type].BaseAddress,\r
28a00297 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
022c6d45 522 mMemoryTypeStatistics[Type].MaximumAddress =\r
523 mMemoryTypeStatistics[Type].BaseAddress +\r
28a00297 524 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
525\r
526 //\r
022c6d45 527 // If the current base address is the lowest address so far, then update the default\r
28a00297 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
022c6d45 552 mMemoryTypeStatistics[Type].BaseAddress,\r
28a00297 553 gMemoryTypeInformation[Index].NumberOfPages\r
554 );\r
b74350e9 555 mMemoryTypeStatistics[Type].NumberOfPages = gMemoryTypeInformation[Index].NumberOfPages;\r
28a00297 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
162ed594 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
022c6d45 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
162ed594 588\r
022c6d45 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
162ed594 593 specified type.\r
594\r
595**/\r
28a00297 596EFI_STATUS\r
597CoreConvertPages (\r
598 IN UINT64 Start,\r
599 IN UINT64 NumberOfPages,\r
600 IN EFI_MEMORY_TYPE NewType\r
601 )\r
28a00297 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
71f68914 620 if (NumberOfPages == 0 || ((Start & EFI_PAGE_MASK) != 0) || (Start > (Start + NumberOfBytes))) {\r
28a00297 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
162ed594 642 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));\r
28a00297 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
162ed594 655 DEBUG ((DEBUG_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType));\r
28a00297 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
d45fd260 661 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "ConvertPages: Incompatible memory types\n"));\r
28a00297 662 return EFI_NOT_FOUND;\r
022c6d45 663 }\r
28a00297 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
022c6d45 669 if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress &&\r
28a00297 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
022c6d45 682 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages >\r
28a00297 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
022c6d45 693\r
28a00297 694 //\r
695 // Clip start\r
696 //\r
697 Entry->Start = RangeEnd + 1;\r
698\r
699 } else if (Entry->End == RangeEnd) {\r
022c6d45 700\r
28a00297 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
022c6d45 711\r
28a00297 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
022c6d45 737 // The new range inherits the same Attribute as the Entry\r
28a00297 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
022c6d45 749\r
28a00297 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
162ed594 774\r
775/**\r
776 Internal function. Finds a consecutive free page range below\r
777 the requested address.\r
778\r
022c6d45 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
162ed594 784\r
785 @return The base address of the range, or 0 if the range was not found\r
786\r
787**/\r
28a00297 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
28a00297 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
022c6d45 809\r
28a00297 810 //\r
811 // If MaxAddress is not aligned to the end of a page\r
812 //\r
022c6d45 813\r
28a00297 814 //\r
815 // Change MaxAddress to be 1 page lower\r
816 //\r
817 MaxAddress -= (EFI_PAGE_MASK + 1);\r
022c6d45 818\r
28a00297 819 //\r
820 // Set MaxAddress to a page boundary\r
821 //\r
822 MaxAddress &= ~EFI_PAGE_MASK;\r
022c6d45 823\r
28a00297 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
022c6d45 835\r
28a00297 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
022c6d45 863 // Compute the number of bytes we can used from this\r
28a00297 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
022c6d45 877 }\r
28a00297 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
162ed594 894\r
895/**\r
896 Internal function. Finds a consecutive free page range below\r
897 the requested address\r
898\r
022c6d45 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
162ed594 904\r
905 @return The base address of the range, or 0 if the range was not found.\r
906\r
907**/\r
28a00297 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
28a00297 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
71f68914 930 if (Start == 0) {\r
28a00297 931 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);\r
71f68914 932 if (Start == 0) {\r
28a00297 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
162ed594 950\r
951/**\r
952 Allocates pages from the memory map.\r
953\r
022c6d45 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
162ed594 960\r
961 @return Status. On success, Memory is filled in with the base address allocated\r
022c6d45 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
162ed594 966 @retval EFI_SUCCESS Pages successfully allocated.\r
967\r
968**/\r
28a00297 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
28a00297 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
022c6d45 1012 // If this is for below a particular address, then\r
28a00297 1013 //\r
1014 Start = *Memory;\r
022c6d45 1015\r
28a00297 1016 //\r
1017 // The max address is the max natively addressable address for the processor\r
1018 //\r
1019 MaxAddress = EFI_MAX_ADDRESS;\r
022c6d45 1020\r
28a00297 1021 if (Type == AllocateMaxAddress) {\r
1022 MaxAddress = Start;\r
1023 }\r
1024\r
1025 CoreAcquireMemoryLock ();\r
022c6d45 1026\r
28a00297 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
162ed594 1054/**\r
1055 Frees previous allocated pages.\r
1056\r
022c6d45 1057 @param Memory Base address of memory being freed\r
1058 @param NumberOfPages The number of pages to free\r
162ed594 1059\r
022c6d45 1060 @retval EFI_NOT_FOUND Could not find the entry that covers the range\r
1061 @retval EFI_INVALID_PARAMETER Address not aligned\r
162ed594 1062 @return EFI_SUCCESS -Pages successfully freed.\r
1063\r
1064**/\r
022c6d45 1065EFI_STATUS\r
28a00297 1066EFIAPI\r
1067CoreFreePages (\r
1068 IN EFI_PHYSICAL_ADDRESS Memory,\r
1069 IN UINTN NumberOfPages\r
1070 )\r
28a00297 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
022c6d45 1130\r
28a00297 1131 return Status;\r
1132}\r
1133\r
1134\r
162ed594 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
022c6d45 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
162ed594 1162 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1163\r
1164**/\r
28a00297 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
28a00297 1174{\r
1175 EFI_STATUS Status;\r
022c6d45 1176 UINTN Size;\r
1177 UINTN BufferSize;\r
28a00297 1178 UINTN NumberOfRuntimeEntries;\r
1179 LIST_ENTRY *Link;\r
022c6d45 1180 MEMORY_MAP *Entry;\r
1181 EFI_GCD_MAP_ENTRY *GcdMapEntry;\r
b74350e9 1182 EFI_MEMORY_TYPE Type;\r
28a00297 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
022c6d45 1190\r
28a00297 1191 CoreAcquireGcdMemoryLock ();\r
022c6d45 1192\r
28a00297 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
022c6d45 1219\r
28a00297 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
383c303c 1247 ZeroMem (MemoryMap, BufferSize);\r
28a00297 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
b74350e9 1252 //\r
1253 // Convert internal map into an EFI_MEMORY_DESCRIPTOR\r
1254 //\r
28a00297 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
b74350e9 1259 //\r
1260 // If the memory type is EfiConventionalMemory, then determine if the range is part of a\r
022c6d45 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
b74350e9 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
e94a9ff7 1271 Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {\r
b74350e9 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
28a00297 1279 }\r
022c6d45 1280\r
28a00297 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
022c6d45 1289\r
28a00297 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
022c6d45 1309\r
28a00297 1310 Status = EFI_SUCCESS;\r
1311\r
1312Done:\r
1313\r
1314 CoreReleaseMemoryLock ();\r
022c6d45 1315\r
28a00297 1316 CoreReleaseGcdMemoryLock ();\r
022c6d45 1317\r
1318 //\r
1319 // Update the map key finally\r
1320 //\r
28a00297 1321 if (MapKey != NULL) {\r
1322 *MapKey = mMemoryMapKey;\r
1323 }\r
022c6d45 1324\r
28a00297 1325 *MemoryMapSize = BufferSize;\r
022c6d45 1326\r
28a00297 1327 return Status;\r
1328}\r
1329\r
28a00297 1330\r
162ed594 1331/**\r
28a00297 1332 Internal function. Used by the pool functions to allocate pages\r
1333 to back pool allocation requests.\r
1334\r
022c6d45 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
28a00297 1338\r
162ed594 1339 @return The allocated memory, or NULL\r
28a00297 1340\r
162ed594 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
28a00297 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
162ed594 1360 DEBUG ((DEBUG_ERROR | DEBUG_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages));\r
28a00297 1361 } else {\r
1362 CoreConvertPages (Start, NumberOfPages, PoolType);\r
1363 }\r
1364\r
e94a9ff7 1365 return (VOID *)(UINTN) Start;\r
28a00297 1366}\r
1367\r
162ed594 1368\r
1369/**\r
1370 Internal function. Frees pool pages allocated via AllocatePoolPages ()\r
1371\r
022c6d45 1372 @param Memory The base address to free\r
162ed594 1373 @param NumberOfPages The number of pages to free\r
1374\r
1375**/\r
28a00297 1376VOID\r
1377CoreFreePoolPages (\r
1378 IN EFI_PHYSICAL_ADDRESS Memory,\r
1379 IN UINTN NumberOfPages\r
1380 )\r
28a00297 1381{\r
1382 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
1383}\r
1384\r
1385\r
28a00297 1386\r
162ed594 1387/**\r
1388 Make sure the memory map is following all the construction rules,\r
28a00297 1389 it is the last time to check memory map error before exit boot services.\r
1390\r
022c6d45 1391 @param MapKey Memory map key\r
28a00297 1392\r
022c6d45 1393 @retval EFI_INVALID_PARAMETER Memory map not consistent with construction\r
1394 rules.\r
162ed594 1395 @retval EFI_SUCCESS Valid memory map.\r
28a00297 1396\r
162ed594 1397**/\r
1398EFI_STATUS\r
1399CoreTerminateMemoryMap (\r
1400 IN UINTN MapKey\r
1401 )\r
28a00297 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
022c6d45 1421 if (Entry->Attribute & EFI_MEMORY_RUNTIME) {\r
28a00297 1422 if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {\r
d45fd260 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
28a00297 1426 }\r
1427 if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
d45fd260 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
28a00297 1431 }\r
1432 if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
d45fd260 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
28a00297 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
d45fd260 1451Done:\r
28a00297 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
162ed594 1464\r