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