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