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