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