Clean up DxeCore to remove duplicate memory allocation & device path utility services...
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Core / Dxe / Gcd / Gcd.c
1 /** @file\r
2   The file contains the GCD related services in the EFI Boot Services Table.\r
3   The GCD services are used to manage the memory and I/O regions that\r
4   are accessible to the CPU that is executing the DXE core.\r
5 \r
6 Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
7 All rights reserved. This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution.  The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11 \r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14 \r
15 **/\r
16 \r
17 #include "DxeMain.h"\r
18 \r
19 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000\r
20 \r
21 #define MEMORY_ATTRIBUTE_MASK         (EFI_RESOURCE_ATTRIBUTE_PRESENT             | \\r
22                                        EFI_RESOURCE_ATTRIBUTE_INITIALIZED         | \\r
23                                        EFI_RESOURCE_ATTRIBUTE_TESTED              | \\r
24                                        EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED      | \\r
25                                        EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED     | \\r
26                                        EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \\r
27                                        EFI_RESOURCE_ATTRIBUTE_16_BIT_IO           | \\r
28                                        EFI_RESOURCE_ATTRIBUTE_32_BIT_IO           | \\r
29                                        EFI_RESOURCE_ATTRIBUTE_64_BIT_IO           )\r
30 \r
31 #define TESTED_MEMORY_ATTRIBUTES      (EFI_RESOURCE_ATTRIBUTE_PRESENT     | \\r
32                                        EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \\r
33                                        EFI_RESOURCE_ATTRIBUTE_TESTED      )\r
34 \r
35 #define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT     | \\r
36                                        EFI_RESOURCE_ATTRIBUTE_INITIALIZED )\r
37 \r
38 #define PRESENT_MEMORY_ATTRIBUTES     (EFI_RESOURCE_ATTRIBUTE_PRESENT)\r
39 \r
40 #define INVALID_CPU_ARCH_ATTRIBUTES   0xffffffff\r
41 \r
42 //\r
43 // Module Variables\r
44 //\r
45 EFI_LOCK           mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
46 EFI_LOCK           mGcdIoSpaceLock     = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
47 LIST_ENTRY         mGcdMemorySpaceMap  = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap);\r
48 LIST_ENTRY         mGcdIoSpaceMap      = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap);\r
49 \r
50 EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = {\r
51   EFI_GCD_MAP_SIGNATURE,\r
52   {\r
53     NULL,\r
54     NULL\r
55   },\r
56   0,\r
57   0,\r
58   0,\r
59   0,\r
60   EfiGcdMemoryTypeNonExistent,\r
61   (EFI_GCD_IO_TYPE) 0,\r
62   NULL,\r
63   NULL\r
64 };\r
65 \r
66 EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {\r
67   EFI_GCD_MAP_SIGNATURE,\r
68   {\r
69     NULL,\r
70     NULL\r
71   },\r
72   0,\r
73   0,\r
74   0,\r
75   0,\r
76   (EFI_GCD_MEMORY_TYPE) 0,\r
77   EfiGcdIoTypeNonExistent,\r
78   NULL,\r
79   NULL\r
80 };\r
81 \r
82 GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {\r
83   { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE,             EFI_MEMORY_UC,          TRUE  },\r
84   { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED,       EFI_MEMORY_UCE,         TRUE  },\r
85   { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE,       EFI_MEMORY_WC,          TRUE  },\r
86   { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT,          TRUE  },\r
87   { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE,    EFI_MEMORY_WB,          TRUE  },\r
88   { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED,          EFI_MEMORY_RP,          TRUE  },\r
89   { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED,         EFI_MEMORY_WP,          TRUE  },\r
90   { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED,     EFI_MEMORY_XP,          TRUE  },\r
91   { EFI_RESOURCE_ATTRIBUTE_PRESENT,                 EFI_MEMORY_PRESENT,     FALSE },\r
92   { EFI_RESOURCE_ATTRIBUTE_INITIALIZED,             EFI_MEMORY_INITIALIZED, FALSE },\r
93   { EFI_RESOURCE_ATTRIBUTE_TESTED,                  EFI_MEMORY_TESTED,      FALSE },\r
94   { 0,                                              0,                      FALSE }\r
95 };\r
96 \r
97 \r
98 /**\r
99   Acquire memory lock on mGcdMemorySpaceLock.\r
100 \r
101 **/\r
102 VOID\r
103 CoreAcquireGcdMemoryLock (\r
104   VOID\r
105   )\r
106 {\r
107   CoreAcquireLock (&mGcdMemorySpaceLock);\r
108 }\r
109 \r
110 \r
111 \r
112 /**\r
113   Release memory lock on mGcdMemorySpaceLock.\r
114 \r
115 **/\r
116 VOID\r
117 CoreReleaseGcdMemoryLock (\r
118   VOID\r
119   )\r
120 {\r
121   CoreReleaseLock (&mGcdMemorySpaceLock);\r
122 }\r
123 \r
124 \r
125 \r
126 /**\r
127   Acquire memory lock on mGcdIoSpaceLock.\r
128 \r
129 **/\r
130 VOID\r
131 CoreAcquireGcdIoLock (\r
132   VOID\r
133   )\r
134 {\r
135   CoreAcquireLock (&mGcdIoSpaceLock);\r
136 }\r
137 \r
138 \r
139 /**\r
140   Release memory lock on mGcdIoSpaceLock.\r
141 \r
142 **/\r
143 VOID\r
144 CoreReleaseGcdIoLock (\r
145   VOID\r
146   )\r
147 {\r
148   CoreReleaseLock (&mGcdIoSpaceLock);\r
149 }\r
150 \r
151 \r
152 \r
153 //\r
154 // GCD Initialization Worker Functions\r
155 //\r
156 /**\r
157   Aligns a value to the specified boundary.\r
158 \r
159   @param  Value                  64 bit value to align\r
160   @param  Alignment              Log base 2 of the boundary to align Value to\r
161   @param  RoundUp                TRUE if Value is to be rounded up to the nearest\r
162                                  aligned boundary.  FALSE is Value is to be\r
163                                  rounded down to the nearest aligned boundary.\r
164 \r
165   @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.\r
166 \r
167 **/\r
168 UINT64\r
169 AlignValue (\r
170   IN UINT64   Value,\r
171   IN UINTN    Alignment,\r
172   IN BOOLEAN  RoundUp\r
173   )\r
174 {\r
175   UINT64  AlignmentMask;\r
176 \r
177   AlignmentMask = LShiftU64 (1, Alignment) - 1;\r
178   if (RoundUp) {\r
179     Value += AlignmentMask;\r
180   }\r
181   return Value & (~AlignmentMask);\r
182 }\r
183 \r
184 \r
185 /**\r
186   Aligns address to the page boundary.\r
187 \r
188   @param  Value                  64 bit address to align\r
189 \r
190   @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.\r
191 \r
192 **/\r
193 UINT64\r
194 PageAlignAddress (\r
195   IN UINT64 Value\r
196   )\r
197 {\r
198   return AlignValue (Value, EFI_PAGE_SHIFT, TRUE);\r
199 }\r
200 \r
201 \r
202 /**\r
203   Aligns length to the page boundary.\r
204 \r
205   @param  Value                  64 bit length to align\r
206 \r
207   @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.\r
208 \r
209 **/\r
210 UINT64\r
211 PageAlignLength (\r
212   IN UINT64 Value\r
213   )\r
214 {\r
215   return AlignValue (Value, EFI_PAGE_SHIFT, FALSE);\r
216 }\r
217 \r
218 //\r
219 // GCD Memory Space Worker Functions\r
220 //\r
221 \r
222 /**\r
223   Allocate pool for two entries.\r
224 \r
225   @param  TopEntry               An entry of GCD map\r
226   @param  BottomEntry            An entry of GCD map\r
227 \r
228   @retval EFI_OUT_OF_RESOURCES   No enough buffer to be allocated.\r
229   @retval EFI_SUCCESS            Both entries successfully allocated.\r
230 \r
231 **/\r
232 EFI_STATUS\r
233 CoreAllocateGcdMapEntry (\r
234   IN OUT EFI_GCD_MAP_ENTRY  **TopEntry,\r
235   IN OUT EFI_GCD_MAP_ENTRY  **BottomEntry\r
236   )\r
237 {\r
238   *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));\r
239   if (*TopEntry == NULL) {\r
240     return EFI_OUT_OF_RESOURCES;\r
241   }\r
242 \r
243   *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));\r
244   if (*BottomEntry == NULL) {\r
245     CoreFreePool (*TopEntry);\r
246     return EFI_OUT_OF_RESOURCES;\r
247   }\r
248 \r
249   return EFI_SUCCESS;\r
250 }\r
251 \r
252 \r
253 /**\r
254   Internal function.  Inserts a new descriptor into a sorted list\r
255 \r
256   @param  Link                   The linked list to insert the range BaseAddress\r
257                                  and Length into\r
258   @param  Entry                  A pointer to the entry that is inserted\r
259   @param  BaseAddress            The base address of the new range\r
260   @param  Length                 The length of the new range in bytes\r
261   @param  TopEntry               Top pad entry to insert if needed.\r
262   @param  BottomEntry            Bottom pad entry to insert if needed.\r
263 \r
264   @retval EFI_SUCCESS            The new range was inserted into the linked list\r
265 \r
266 **/\r
267 EFI_STATUS\r
268 CoreInsertGcdMapEntry (\r
269   IN LIST_ENTRY           *Link,\r
270   IN EFI_GCD_MAP_ENTRY     *Entry,\r
271   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
272   IN UINT64                Length,\r
273   IN EFI_GCD_MAP_ENTRY     *TopEntry,\r
274   IN EFI_GCD_MAP_ENTRY     *BottomEntry\r
275   )\r
276 {\r
277   ASSERT (Length != 0);\r
278   ASSERT (TopEntry->Signature == 0);\r
279   ASSERT (BottomEntry->Signature == 0);\r
280 \r
281   if (BaseAddress > Entry->BaseAddress) {\r
282     CopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));\r
283     Entry->BaseAddress      = BaseAddress;\r
284     BottomEntry->EndAddress = BaseAddress - 1;\r
285     InsertTailList (Link, &BottomEntry->Link);\r
286   }\r
287 \r
288   if ((BaseAddress + Length - 1) < Entry->EndAddress) {\r
289     CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));\r
290     TopEntry->BaseAddress = BaseAddress + Length;\r
291     Entry->EndAddress     = BaseAddress + Length - 1;\r
292     InsertHeadList (Link, &TopEntry->Link);\r
293   }\r
294 \r
295   return EFI_SUCCESS;\r
296 }\r
297 \r
298 \r
299 /**\r
300   Merge the Gcd region specified by Link and its adjacent entry.\r
301 \r
302   @param  Link                   Specify the entry to be merged (with its\r
303                                  adjacent entry).\r
304   @param  Forward                Direction (forward or backward).\r
305   @param  Map                    Boundary.\r
306 \r
307   @retval EFI_SUCCESS            Successfully returned.\r
308   @retval EFI_UNSUPPORTED        These adjacent regions could not merge.\r
309 \r
310 **/\r
311 EFI_STATUS\r
312 CoreMergeGcdMapEntry (\r
313   IN LIST_ENTRY      *Link,\r
314   IN BOOLEAN         Forward,\r
315   IN LIST_ENTRY      *Map\r
316   )\r
317 {\r
318   LIST_ENTRY         *AdjacentLink;\r
319   EFI_GCD_MAP_ENTRY  *Entry;\r
320   EFI_GCD_MAP_ENTRY  *AdjacentEntry;\r
321 \r
322   //\r
323   // Get adjacent entry\r
324   //\r
325   if (Forward) {\r
326     AdjacentLink = Link->ForwardLink;\r
327   } else {\r
328     AdjacentLink = Link->BackLink;\r
329   }\r
330 \r
331   //\r
332   // If AdjacentLink is the head of the list, then no merge can be performed\r
333   //\r
334   if (AdjacentLink == Map) {\r
335     return EFI_SUCCESS;\r
336   }\r
337 \r
338   Entry         = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
339   AdjacentEntry = CR (AdjacentLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
340 \r
341   if (Entry->Capabilities != AdjacentEntry->Capabilities) {\r
342     return EFI_UNSUPPORTED;\r
343   }\r
344   if (Entry->Attributes != AdjacentEntry->Attributes) {\r
345     return EFI_UNSUPPORTED;\r
346   }\r
347   if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) {\r
348     return EFI_UNSUPPORTED;\r
349   }\r
350   if (Entry->GcdIoType != AdjacentEntry->GcdIoType) {\r
351     return EFI_UNSUPPORTED;\r
352   }\r
353   if (Entry->ImageHandle != AdjacentEntry->ImageHandle) {\r
354     return EFI_UNSUPPORTED;\r
355   }\r
356   if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) {\r
357     return EFI_UNSUPPORTED;\r
358   }\r
359 \r
360   if (Forward) {\r
361     Entry->EndAddress  = AdjacentEntry->EndAddress;\r
362   } else {\r
363     Entry->BaseAddress = AdjacentEntry->BaseAddress;\r
364   }\r
365   RemoveEntryList (AdjacentLink);\r
366   CoreFreePool (AdjacentEntry);\r
367 \r
368   return EFI_SUCCESS;\r
369 }\r
370 \r
371 \r
372 /**\r
373   Merge adjacent entries on total chain.\r
374 \r
375   @param  TopEntry               Top entry of GCD map.\r
376   @param  BottomEntry            Bottom entry of GCD map.\r
377   @param  StartLink              Start link of the list for this loop.\r
378   @param  EndLink                End link of the list for this loop.\r
379   @param  Map                    Boundary.\r
380 \r
381   @retval EFI_SUCCESS            GCD map successfully cleaned up.\r
382 \r
383 **/\r
384 EFI_STATUS\r
385 CoreCleanupGcdMapEntry (\r
386   IN EFI_GCD_MAP_ENTRY  *TopEntry,\r
387   IN EFI_GCD_MAP_ENTRY  *BottomEntry,\r
388   IN LIST_ENTRY         *StartLink,\r
389   IN LIST_ENTRY         *EndLink,\r
390   IN LIST_ENTRY         *Map\r
391   )\r
392 {\r
393   LIST_ENTRY  *Link;\r
394 \r
395   if (TopEntry->Signature == 0) {\r
396     CoreFreePool (TopEntry);\r
397   }\r
398   if (BottomEntry->Signature == 0) {\r
399     CoreFreePool (BottomEntry);\r
400   }\r
401 \r
402   Link = StartLink;\r
403   while (Link != EndLink->ForwardLink) {\r
404     CoreMergeGcdMapEntry (Link, FALSE, Map);\r
405     Link = Link->ForwardLink;\r
406   }\r
407   CoreMergeGcdMapEntry (EndLink, TRUE, Map);\r
408 \r
409   return EFI_SUCCESS;\r
410 }\r
411 \r
412 \r
413 /**\r
414   Search a segment of memory space in GCD map. The result is a range of GCD entry list.\r
415 \r
416   @param  BaseAddress            The start address of the segment.\r
417   @param  Length                 The length of the segment.\r
418   @param  StartLink              The first GCD entry involves this segment of\r
419                                  memory space.\r
420   @param  EndLink                The first GCD entry involves this segment of\r
421                                  memory space.\r
422   @param  Map                    Points to the start entry to search.\r
423 \r
424   @retval EFI_SUCCESS            Successfully found the entry.\r
425   @retval EFI_NOT_FOUND          Not found.\r
426 \r
427 **/\r
428 EFI_STATUS\r
429 CoreSearchGcdMapEntry (\r
430   IN  EFI_PHYSICAL_ADDRESS  BaseAddress,\r
431   IN  UINT64                Length,\r
432   OUT LIST_ENTRY            **StartLink,\r
433   OUT LIST_ENTRY            **EndLink,\r
434   IN  LIST_ENTRY            *Map\r
435   )\r
436 {\r
437   LIST_ENTRY         *Link;\r
438   EFI_GCD_MAP_ENTRY  *Entry;\r
439 \r
440   ASSERT (Length != 0);\r
441 \r
442   *StartLink = NULL;\r
443   *EndLink   = NULL;\r
444 \r
445   Link = Map->ForwardLink;\r
446   while (Link != Map) {\r
447     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
448     if (BaseAddress >= Entry->BaseAddress && BaseAddress <= Entry->EndAddress) {\r
449       *StartLink = Link;\r
450     }\r
451     if (*StartLink != NULL) {\r
452       if ((BaseAddress + Length - 1) >= Entry->BaseAddress &&\r
453           (BaseAddress + Length - 1) <= Entry->EndAddress     ) {\r
454         *EndLink = Link;\r
455         return EFI_SUCCESS;\r
456       }\r
457     }\r
458     Link = Link->ForwardLink;\r
459   }\r
460 \r
461   return EFI_NOT_FOUND;\r
462 }\r
463 \r
464 \r
465 /**\r
466   Count the amount of GCD map entries.\r
467 \r
468   @param  Map                    Points to the start entry to do the count loop.\r
469 \r
470   @return The count.\r
471 \r
472 **/\r
473 UINTN\r
474 CoreCountGcdMapEntry (\r
475   IN LIST_ENTRY  *Map\r
476   )\r
477 {\r
478   UINTN           Count;\r
479   LIST_ENTRY      *Link;\r
480 \r
481   Count = 0;\r
482   Link = Map->ForwardLink;\r
483   while (Link != Map) {\r
484     Count++;\r
485     Link = Link->ForwardLink;\r
486   }\r
487 \r
488   return Count;\r
489 }\r
490 \r
491 \r
492 \r
493 /**\r
494   Return the memory attribute specified by Attributes\r
495 \r
496   @param  Attributes             A num with some attribute bits on.\r
497 \r
498   @return The enum value of memory attribute.\r
499 \r
500 **/\r
501 UINT64\r
502 ConverToCpuArchAttributes (\r
503   UINT64 Attributes\r
504   )\r
505 {\r
506   if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {\r
507     return EFI_MEMORY_UC;\r
508   }\r
509 \r
510   if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) {\r
511     return EFI_MEMORY_WC;\r
512   }\r
513 \r
514   if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) {\r
515     return EFI_MEMORY_WT;\r
516   }\r
517 \r
518   if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) {\r
519     return EFI_MEMORY_WB;\r
520   }\r
521 \r
522   if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) {\r
523     return EFI_MEMORY_WP;\r
524   }\r
525 \r
526   return INVALID_CPU_ARCH_ATTRIBUTES;\r
527 \r
528 }\r
529 \r
530 \r
531 /**\r
532   Do operation on a segment of memory space specified (add, free, remove, change attribute ...).\r
533 \r
534   @param  Operation              The type of the operation\r
535   @param  GcdMemoryType          Additional information for the operation\r
536   @param  GcdIoType              Additional information for the operation\r
537   @param  BaseAddress            Start address of the segment\r
538   @param  Length                 length of the segment\r
539   @param  Capabilities           The alterable attributes of a newly added entry\r
540   @param  Attributes             The attributes needs to be set\r
541 \r
542   @retval EFI_INVALID_PARAMETER  Length is 0 or address (length) not aligned when\r
543                                  setting attribute.\r
544   @retval EFI_SUCCESS            Action successfully done.\r
545   @retval EFI_UNSUPPORTED        Could not find the proper descriptor on this\r
546                                  segment or  set an upsupported attribute.\r
547   @retval EFI_ACCESS_DENIED      Operate on an space non-exist or is used for an\r
548                                  image.\r
549   @retval EFI_NOT_FOUND          Free a non-using space or remove a non-exist\r
550                                  space, and so on.\r
551   @retval EFI_OUT_OF_RESOURCES   No buffer could be allocated.\r
552 \r
553 **/\r
554 EFI_STATUS\r
555 CoreConvertSpace (\r
556   IN UINTN                 Operation,\r
557   IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,\r
558   IN EFI_GCD_IO_TYPE       GcdIoType,\r
559   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
560   IN UINT64                Length,\r
561   IN UINT64                Capabilities,\r
562   IN UINT64                Attributes\r
563   )\r
564 {\r
565   EFI_STATUS         Status;\r
566   LIST_ENTRY         *Map;\r
567   LIST_ENTRY         *Link;\r
568   EFI_GCD_MAP_ENTRY  *Entry;\r
569   EFI_GCD_MAP_ENTRY  *TopEntry;\r
570   EFI_GCD_MAP_ENTRY  *BottomEntry;\r
571   LIST_ENTRY         *StartLink;\r
572   LIST_ENTRY         *EndLink;\r
573 \r
574   EFI_CPU_ARCH_PROTOCOL           *CpuArch;\r
575   UINT64                          CpuArchAttributes;\r
576 \r
577   if (Length == 0) {\r
578     return EFI_INVALID_PARAMETER;\r
579   }\r
580 \r
581   Map = NULL;\r
582   if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {\r
583     CoreAcquireGcdMemoryLock ();\r
584     Map = &mGcdMemorySpaceMap;\r
585   }\r
586   if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {\r
587     CoreAcquireGcdIoLock ();\r
588     Map = &mGcdIoSpaceMap;\r
589   }\r
590 \r
591   //\r
592   // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length\r
593   //\r
594   Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);\r
595   if (EFI_ERROR (Status)) {\r
596     Status = EFI_UNSUPPORTED;\r
597 \r
598     goto Done;\r
599   }\r
600 \r
601   //\r
602   // Verify that the list of descriptors are unallocated non-existent memory.\r
603   //\r
604   Link = StartLink;\r
605   while (Link != EndLink->ForwardLink) {\r
606     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
607     switch (Operation) {\r
608     //\r
609     // Add operations\r
610     //\r
611     case GCD_ADD_MEMORY_OPERATION:\r
612       if (Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent ||\r
613           Entry->ImageHandle   != NULL                           ) {\r
614         Status = EFI_ACCESS_DENIED;\r
615         goto Done;\r
616       }\r
617       break;\r
618     case GCD_ADD_IO_OPERATION:\r
619       if (Entry->GcdIoType   != EfiGcdIoTypeNonExistent ||\r
620           Entry->ImageHandle != NULL                       ) {\r
621         Status = EFI_ACCESS_DENIED;\r
622         goto Done;\r
623       }\r
624       break;\r
625     //\r
626     // Free operations\r
627     //\r
628     case GCD_FREE_MEMORY_OPERATION:\r
629     case GCD_FREE_IO_OPERATION:\r
630       if (Entry->ImageHandle == NULL) {\r
631         Status = EFI_NOT_FOUND;\r
632         goto Done;\r
633       }\r
634       break;\r
635     //\r
636     // Remove operations\r
637     //\r
638     case GCD_REMOVE_MEMORY_OPERATION:\r
639       if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
640         Status = EFI_NOT_FOUND;\r
641         goto Done;\r
642       }\r
643       if (Entry->ImageHandle != NULL) {\r
644         Status = EFI_ACCESS_DENIED;\r
645         goto Done;\r
646       }\r
647       break;\r
648     case GCD_REMOVE_IO_OPERATION:\r
649       if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {\r
650         Status = EFI_NOT_FOUND;\r
651         goto Done;\r
652       }\r
653       if (Entry->ImageHandle != NULL) {\r
654         Status = EFI_ACCESS_DENIED;\r
655         goto Done;\r
656       }\r
657       break;\r
658     //\r
659     // Set attribute operations\r
660     //\r
661     case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:\r
662       if ((Attributes & EFI_MEMORY_RUNTIME) != 0) {\r
663         if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {\r
664           Status = EFI_INVALID_PARAMETER;\r
665           goto Done;\r
666         }\r
667       }\r
668       if ((Entry->Capabilities & Attributes) != Attributes) {\r
669         Status = EFI_UNSUPPORTED;\r
670         goto Done;\r
671       }\r
672       break;\r
673     }\r
674     Link = Link->ForwardLink;\r
675   }\r
676 \r
677   //\r
678   // Allocate work space to perform this operation\r
679   //\r
680   Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);\r
681   if (EFI_ERROR (Status)) {\r
682     Status = EFI_OUT_OF_RESOURCES;\r
683     goto Done;\r
684   }\r
685 \r
686   if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {\r
687     //\r
688     // Call CPU Arch Protocol to attempt to set attributes on the range\r
689     //\r
690     CpuArchAttributes = ConverToCpuArchAttributes (Attributes);\r
691     if ( CpuArchAttributes != INVALID_CPU_ARCH_ATTRIBUTES ) {\r
692       Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);\r
693       if (EFI_ERROR (Status)) {\r
694         Status = EFI_ACCESS_DENIED;\r
695         goto Done;\r
696       }\r
697 \r
698       Status = CpuArch->SetMemoryAttributes (\r
699                           CpuArch,\r
700                           BaseAddress,\r
701                           Length,\r
702                           CpuArchAttributes\r
703                           );\r
704       if (EFI_ERROR (Status)) {\r
705         goto Done;\r
706       }\r
707     }\r
708 \r
709   }\r
710 \r
711   //\r
712   // Convert/Insert the list of descriptors from StartLink to EndLink\r
713   //\r
714   Link = StartLink;\r
715   while (Link != EndLink->ForwardLink) {\r
716     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
717     CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);\r
718     switch (Operation) {\r
719     //\r
720     // Add operations\r
721     //\r
722     case GCD_ADD_MEMORY_OPERATION:\r
723       Entry->GcdMemoryType = GcdMemoryType;\r
724       if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
725         Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;\r
726       } else {\r
727         Entry->Capabilities  = Capabilities | EFI_MEMORY_RUNTIME;\r
728       }\r
729       break;\r
730     case GCD_ADD_IO_OPERATION:\r
731       Entry->GcdIoType = GcdIoType;\r
732       break;\r
733     //\r
734     // Free operations\r
735     //\r
736     case GCD_FREE_MEMORY_OPERATION:\r
737     case GCD_FREE_IO_OPERATION:\r
738       Entry->ImageHandle  = NULL;\r
739       Entry->DeviceHandle = NULL;\r
740       break;\r
741     //\r
742     // Remove operations\r
743     //\r
744     case GCD_REMOVE_MEMORY_OPERATION:\r
745       Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;\r
746       Entry->Capabilities  = 0;\r
747       break;\r
748     case GCD_REMOVE_IO_OPERATION:\r
749       Entry->GcdIoType = EfiGcdIoTypeNonExistent;\r
750       break;\r
751     //\r
752     // Set attribute operations\r
753     //\r
754     case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:\r
755       Entry->Attributes = Attributes;\r
756       break;\r
757     }\r
758     Link = Link->ForwardLink;\r
759   }\r
760 \r
761   //\r
762   // Cleanup\r
763   //\r
764   Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);\r
765 \r
766 Done:\r
767   if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {\r
768     CoreReleaseGcdMemoryLock ();\r
769   }\r
770   if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {\r
771     CoreReleaseGcdIoLock ();\r
772   }\r
773 \r
774   return Status;\r
775 }\r
776 \r
777 \r
778 /**\r
779   Check whether an entry could be used to allocate space.\r
780 \r
781   @param  Operation              Allocate memory or IO\r
782   @param  Entry                  The entry to be tested\r
783   @param  GcdMemoryType          The desired memory type\r
784   @param  GcdIoType              The desired IO type\r
785 \r
786   @retval EFI_NOT_FOUND          The memory type does not match or there's an\r
787                                  image handle on the entry.\r
788   @retval EFI_UNSUPPORTED        The operation unsupported.\r
789   @retval EFI_SUCCESS            It's ok for this entry to be used to allocate\r
790                                  space.\r
791 \r
792 **/\r
793 EFI_STATUS\r
794 CoreAllocateSpaceCheckEntry (\r
795   IN UINTN                Operation,\r
796   IN EFI_GCD_MAP_ENTRY    *Entry,\r
797   IN EFI_GCD_MEMORY_TYPE  GcdMemoryType,\r
798   IN EFI_GCD_IO_TYPE      GcdIoType\r
799   )\r
800 {\r
801   if (Entry->ImageHandle != NULL) {\r
802     return EFI_NOT_FOUND;\r
803   }\r
804   switch (Operation) {\r
805   case GCD_ALLOCATE_MEMORY_OPERATION:\r
806     if (Entry->GcdMemoryType != GcdMemoryType) {\r
807       return EFI_NOT_FOUND;\r
808     }\r
809     break;\r
810   case GCD_ALLOCATE_IO_OPERATION:\r
811     if (Entry->GcdIoType != GcdIoType) {\r
812       return EFI_NOT_FOUND;\r
813     }\r
814     break;\r
815   default:\r
816     return EFI_UNSUPPORTED;\r
817   }\r
818   return EFI_SUCCESS;\r
819 }\r
820 \r
821 \r
822 /**\r
823   Allocate space on specified address and length.\r
824 \r
825   @param  Operation              The type of operation (memory or IO)\r
826   @param  GcdAllocateType        The type of allocate operation\r
827   @param  GcdMemoryType          The desired memory type\r
828   @param  GcdIoType              The desired IO type\r
829   @param  Alignment              Align with 2^Alignment\r
830   @param  Length                 Length to allocate\r
831   @param  BaseAddress            Base address to allocate\r
832   @param  ImageHandle            The image handle consume the allocated space.\r
833   @param  DeviceHandle           The device handle consume the allocated space.\r
834 \r
835   @retval EFI_INVALID_PARAMETER  Invalid parameter.\r
836   @retval EFI_NOT_FOUND          No descriptor for the desired space exists.\r
837   @retval EFI_SUCCESS            Space successfully allocated.\r
838 \r
839 **/\r
840 EFI_STATUS\r
841 CoreAllocateSpace (\r
842   IN     UINTN                  Operation,\r
843   IN     EFI_GCD_ALLOCATE_TYPE  GcdAllocateType,\r
844   IN     EFI_GCD_MEMORY_TYPE    GcdMemoryType,\r
845   IN     EFI_GCD_IO_TYPE        GcdIoType,\r
846   IN     UINTN                  Alignment,\r
847   IN     UINT64                 Length,\r
848   IN OUT EFI_PHYSICAL_ADDRESS   *BaseAddress,\r
849   IN     EFI_HANDLE             ImageHandle,\r
850   IN     EFI_HANDLE             DeviceHandle OPTIONAL\r
851   )\r
852 {\r
853   EFI_STATUS            Status;\r
854   EFI_PHYSICAL_ADDRESS  AlignmentMask;\r
855   EFI_PHYSICAL_ADDRESS  MaxAddress;\r
856   LIST_ENTRY            *Map;\r
857   LIST_ENTRY            *Link;\r
858   LIST_ENTRY            *SubLink;\r
859   EFI_GCD_MAP_ENTRY     *Entry;\r
860   EFI_GCD_MAP_ENTRY     *TopEntry;\r
861   EFI_GCD_MAP_ENTRY     *BottomEntry;\r
862   LIST_ENTRY            *StartLink;\r
863   LIST_ENTRY            *EndLink;\r
864   BOOLEAN               Found;\r
865 \r
866   //\r
867   // Make sure parameters are valid\r
868   //\r
869   if (GcdAllocateType < 0 || GcdAllocateType >= EfiGcdMaxAllocateType) {\r
870     return EFI_INVALID_PARAMETER;\r
871   }\r
872   if (GcdMemoryType < 0 || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {\r
873     return EFI_INVALID_PARAMETER;\r
874   }\r
875   if (GcdIoType < 0 || GcdIoType >= EfiGcdIoTypeMaximum) {\r
876     return EFI_INVALID_PARAMETER;\r
877   }\r
878   if (BaseAddress == NULL) {\r
879     return EFI_INVALID_PARAMETER;\r
880   }\r
881   if (ImageHandle == NULL) {\r
882     return EFI_INVALID_PARAMETER;\r
883   }\r
884   if (Alignment >= 64) {\r
885     return EFI_NOT_FOUND;\r
886   }\r
887   if (Length == 0) {\r
888     return EFI_INVALID_PARAMETER;\r
889   }\r
890 \r
891   Map = NULL;\r
892   if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {\r
893     CoreAcquireGcdMemoryLock ();\r
894     Map = &mGcdMemorySpaceMap;\r
895   }\r
896   if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {\r
897     CoreAcquireGcdIoLock ();\r
898     Map = &mGcdIoSpaceMap;\r
899   }\r
900 \r
901   Found     = FALSE;\r
902   StartLink = NULL;\r
903   EndLink   = NULL;\r
904   //\r
905   // Compute alignment bit mask\r
906   //\r
907   AlignmentMask = LShiftU64 (1, Alignment) - 1;\r
908 \r
909   if (GcdAllocateType == EfiGcdAllocateAddress) {\r
910     //\r
911     // Verify that the BaseAddress passed in is aligned correctly\r
912     //\r
913     if ((*BaseAddress & AlignmentMask) != 0) {\r
914       Status = EFI_NOT_FOUND;\r
915       goto Done;\r
916     }\r
917 \r
918     //\r
919     // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length\r
920     //\r
921     Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);\r
922     if (EFI_ERROR (Status)) {\r
923       Status = EFI_NOT_FOUND;\r
924       goto Done;\r
925     }\r
926 \r
927     //\r
928     // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.\r
929     //\r
930     Link = StartLink;\r
931     while (Link != EndLink->ForwardLink) {\r
932       Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
933       Link = Link->ForwardLink;\r
934       Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);\r
935       if (EFI_ERROR (Status)) {\r
936         goto Done;\r
937       }\r
938     }\r
939     Found = TRUE;\r
940   } else {\r
941 \r
942     Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
943 \r
944     //\r
945     // Compute the maximum address to use in the search algorithm\r
946     //\r
947     if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp ||\r
948         GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown     ) {\r
949       MaxAddress = *BaseAddress;\r
950     } else {\r
951       MaxAddress = Entry->EndAddress;\r
952     }\r
953 \r
954     //\r
955     // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.\r
956     //\r
957     if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||\r
958         GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {\r
959       Link = Map->BackLink;\r
960     } else {\r
961       Link = Map->ForwardLink;\r
962     }\r
963     while (Link != Map) {\r
964       Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
965 \r
966       if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||\r
967           GcdAllocateType == EfiGcdAllocateAnySearchTopDown           ) {\r
968         Link = Link->BackLink;\r
969       } else {\r
970         Link = Link->ForwardLink;\r
971       }\r
972 \r
973       Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);\r
974       if (EFI_ERROR (Status)) {\r
975         continue;\r
976       }\r
977 \r
978       if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||\r
979           GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {\r
980         if ((Entry->BaseAddress + Length) > MaxAddress) {\r
981           continue;\r
982         }\r
983         if (Length > (Entry->EndAddress + 1)) {\r
984           Status = EFI_NOT_FOUND;\r
985           goto Done;\r
986         }\r
987         if (Entry->EndAddress > MaxAddress) {\r
988           *BaseAddress = MaxAddress;\r
989         } else {\r
990           *BaseAddress = Entry->EndAddress;\r
991         }\r
992         *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);\r
993       } else {\r
994         *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);\r
995         if ((*BaseAddress + Length - 1) > MaxAddress) {\r
996           Status = EFI_NOT_FOUND;\r
997           goto Done;\r
998         }\r
999       }\r
1000 \r
1001       //\r
1002       // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length\r
1003       //\r
1004       Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);\r
1005       if (EFI_ERROR (Status)) {\r
1006         Status = EFI_NOT_FOUND;\r
1007         goto Done;\r
1008       }\r
1009 \r
1010       Link = StartLink;\r
1011       //\r
1012       // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.\r
1013       //\r
1014       Found = TRUE;\r
1015       SubLink = StartLink;\r
1016       while (SubLink != EndLink->ForwardLink) {\r
1017         Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1018         Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);\r
1019         if (EFI_ERROR (Status)) {\r
1020           Link = SubLink;\r
1021           Found = FALSE;\r
1022           break;\r
1023         }\r
1024         SubLink = SubLink->ForwardLink;\r
1025       }\r
1026       if (Found) {\r
1027         break;\r
1028       }\r
1029     }\r
1030   }\r
1031   if (!Found) {\r
1032     Status = EFI_NOT_FOUND;\r
1033     goto Done;\r
1034   }\r
1035 \r
1036   //\r
1037   // Allocate work space to perform this operation\r
1038   //\r
1039   Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);\r
1040   if (EFI_ERROR (Status)) {\r
1041     Status = EFI_OUT_OF_RESOURCES;\r
1042     goto Done;\r
1043   }\r
1044 \r
1045   //\r
1046   // Convert/Insert the list of descriptors from StartLink to EndLink\r
1047   //\r
1048   Link = StartLink;\r
1049   while (Link != EndLink->ForwardLink) {\r
1050     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1051     CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);\r
1052     Entry->ImageHandle  = ImageHandle;\r
1053     Entry->DeviceHandle = DeviceHandle;\r
1054     Link = Link->ForwardLink;\r
1055   }\r
1056 \r
1057   //\r
1058   // Cleanup\r
1059   //\r
1060   Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);\r
1061 \r
1062 Done:\r
1063   if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {\r
1064     CoreReleaseGcdMemoryLock ();\r
1065   }\r
1066   if ((Operation & GCD_IO_SPACE_OPERATION) !=0) {\r
1067     CoreReleaseGcdIoLock ();\r
1068   }\r
1069 \r
1070   return Status;\r
1071 }\r
1072 \r
1073 \r
1074 /**\r
1075   Add a segment of memory to GCD map.\r
1076 \r
1077   @param  GcdMemoryType          Memory type of the segment.\r
1078   @param  BaseAddress            Base address of the segment.\r
1079   @param  Length                 Length of the segment.\r
1080   @param  Capabilities           alterable attributes of the segment.\r
1081 \r
1082   @retval EFI_INVALID_PARAMETER  Invalid parameters.\r
1083   @retval EFI_SUCCESS            Successfully add a segment of memory space.\r
1084 \r
1085 **/\r
1086 EFI_STATUS\r
1087 CoreInternalAddMemorySpace (\r
1088   IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,\r
1089   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
1090   IN UINT64                Length,\r
1091   IN UINT64                Capabilities\r
1092   )\r
1093 {\r
1094   //\r
1095   // Make sure parameters are valid\r
1096   //\r
1097   if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {\r
1098     return EFI_INVALID_PARAMETER;\r
1099   }\r
1100 \r
1101   return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);\r
1102 }\r
1103 \r
1104 //\r
1105 // GCD Core Services\r
1106 //\r
1107 \r
1108 /**\r
1109   Allocates nonexistent memory, reserved memory, system memory, or memorymapped\r
1110   I/O resources from the global coherency domain of the processor.\r
1111 \r
1112   @param  GcdAllocateType        The type of allocate operation\r
1113   @param  GcdMemoryType          The desired memory type\r
1114   @param  Alignment              Align with 2^Alignment\r
1115   @param  Length                 Length to allocate\r
1116   @param  BaseAddress            Base address to allocate\r
1117   @param  ImageHandle            The image handle consume the allocated space.\r
1118   @param  DeviceHandle           The device handle consume the allocated space.\r
1119 \r
1120   @retval EFI_INVALID_PARAMETER  Invalid parameter.\r
1121   @retval EFI_NOT_FOUND          No descriptor contains the desired space.\r
1122   @retval EFI_SUCCESS            Memory space successfully allocated.\r
1123 \r
1124 **/\r
1125 EFI_STATUS\r
1126 CoreAllocateMemorySpace (\r
1127   IN     EFI_GCD_ALLOCATE_TYPE  GcdAllocateType,\r
1128   IN     EFI_GCD_MEMORY_TYPE    GcdMemoryType,\r
1129   IN     UINTN                  Alignment,\r
1130   IN     UINT64                 Length,\r
1131   IN OUT EFI_PHYSICAL_ADDRESS   *BaseAddress,\r
1132   IN     EFI_HANDLE             ImageHandle,\r
1133   IN     EFI_HANDLE             DeviceHandle OPTIONAL\r
1134   )\r
1135 {\r
1136   return CoreAllocateSpace (\r
1137            GCD_ALLOCATE_MEMORY_OPERATION,\r
1138            GcdAllocateType,\r
1139            GcdMemoryType,\r
1140            (EFI_GCD_IO_TYPE) 0,\r
1141            Alignment,\r
1142            Length,\r
1143            BaseAddress,\r
1144            ImageHandle,\r
1145            DeviceHandle\r
1146            );\r
1147 }\r
1148 \r
1149 \r
1150 /**\r
1151   Adds reserved memory, system memory, or memory-mapped I/O resources to the\r
1152   global coherency domain of the processor.\r
1153 \r
1154   @param  GcdMemoryType          Memory type of the memory space.\r
1155   @param  BaseAddress            Base address of the memory space.\r
1156   @param  Length                 Length of the memory space.\r
1157   @param  Capabilities           alterable attributes of the memory space.\r
1158 \r
1159   @retval EFI_SUCCESS            Merged this memory space into GCD map.\r
1160 \r
1161 **/\r
1162 EFI_STATUS\r
1163 CoreAddMemorySpace (\r
1164   IN EFI_GCD_MEMORY_TYPE   GcdMemoryType,\r
1165   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
1166   IN UINT64                Length,\r
1167   IN UINT64                Capabilities\r
1168   )\r
1169 {\r
1170   EFI_STATUS            Status;\r
1171   EFI_PHYSICAL_ADDRESS  PageBaseAddress;\r
1172   UINT64                PageLength;\r
1173 \r
1174   Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);\r
1175 \r
1176   if (!EFI_ERROR (Status) && GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {\r
1177 \r
1178     PageBaseAddress = PageAlignLength (BaseAddress);\r
1179     PageLength      = PageAlignLength (BaseAddress + Length - PageBaseAddress);\r
1180 \r
1181     Status = CoreAllocateMemorySpace (\r
1182                EfiGcdAllocateAddress,\r
1183                GcdMemoryType,\r
1184                EFI_PAGE_SHIFT,\r
1185                PageLength,\r
1186                &PageBaseAddress,\r
1187                gDxeCoreImageHandle,\r
1188                NULL\r
1189                );\r
1190 \r
1191     if (!EFI_ERROR (Status)) {\r
1192       CoreAddMemoryDescriptor (\r
1193         EfiConventionalMemory,\r
1194         PageBaseAddress,\r
1195         RShiftU64 (PageLength, EFI_PAGE_SHIFT),\r
1196         Capabilities\r
1197         );\r
1198     } else {\r
1199       for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {\r
1200         Status = CoreAllocateMemorySpace (\r
1201                    EfiGcdAllocateAddress,\r
1202                    GcdMemoryType,\r
1203                    EFI_PAGE_SHIFT,\r
1204                    EFI_PAGE_SIZE,\r
1205                    &PageBaseAddress,\r
1206                    gDxeCoreImageHandle,\r
1207                    NULL\r
1208                    );\r
1209 \r
1210         if (!EFI_ERROR (Status)) {\r
1211           CoreAddMemoryDescriptor (\r
1212             EfiConventionalMemory,\r
1213             PageBaseAddress,\r
1214             1,\r
1215             Capabilities\r
1216             );\r
1217         }\r
1218       }\r
1219     }\r
1220   }\r
1221   return Status;\r
1222 }\r
1223 \r
1224 \r
1225 /**\r
1226   Frees nonexistent memory, reserved memory, system memory, or memory-mapped\r
1227   I/O resources from the global coherency domain of the processor.\r
1228 \r
1229   @param  BaseAddress            Base address of the memory space.\r
1230   @param  Length                 Length of the memory space.\r
1231 \r
1232   @retval EFI_SUCCESS            Space successfully freed.\r
1233 \r
1234 **/\r
1235 EFI_STATUS\r
1236 CoreFreeMemorySpace (\r
1237   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
1238   IN UINT64                Length\r
1239   )\r
1240 {\r
1241   return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);\r
1242 }\r
1243 \r
1244 \r
1245 /**\r
1246   Removes reserved memory, system memory, or memory-mapped I/O resources from\r
1247   the global coherency domain of the processor.\r
1248 \r
1249   @param  BaseAddress            Base address of the memory space.\r
1250   @param  Length                 Length of the memory space.\r
1251 \r
1252   @retval EFI_SUCCESS            Successfully remove a segment of memory space.\r
1253 \r
1254 **/\r
1255 EFI_STATUS\r
1256 CoreRemoveMemorySpace (\r
1257   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
1258   IN UINT64                Length\r
1259   )\r
1260 {\r
1261   return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);\r
1262 }\r
1263 \r
1264 \r
1265 /**\r
1266   Build a memory descriptor according to an entry.\r
1267 \r
1268   @param  Descriptor             The descriptor to be built\r
1269   @param  Entry                  According to this entry\r
1270 \r
1271 **/\r
1272 VOID\r
1273 BuildMemoryDescriptor (\r
1274   IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor,\r
1275   IN EFI_GCD_MAP_ENTRY                *Entry\r
1276   )\r
1277 {\r
1278   Descriptor->BaseAddress   = Entry->BaseAddress;\r
1279   Descriptor->Length        = Entry->EndAddress - Entry->BaseAddress + 1;\r
1280   Descriptor->Capabilities  = Entry->Capabilities;\r
1281   Descriptor->Attributes    = Entry->Attributes;\r
1282   Descriptor->GcdMemoryType = Entry->GcdMemoryType;\r
1283   Descriptor->ImageHandle   = Entry->ImageHandle;\r
1284   Descriptor->DeviceHandle  = Entry->DeviceHandle;\r
1285 }\r
1286 \r
1287 \r
1288 /**\r
1289   Retrieves the descriptor for a memory region containing a specified address.\r
1290 \r
1291   @param  BaseAddress            Specified start address\r
1292   @param  Descriptor             Specified length\r
1293 \r
1294   @retval EFI_INVALID_PARAMETER  Invalid parameter\r
1295   @retval EFI_SUCCESS            Successfully get memory space descriptor.\r
1296 \r
1297 **/\r
1298 EFI_STATUS\r
1299 CoreGetMemorySpaceDescriptor (\r
1300   IN  EFI_PHYSICAL_ADDRESS             BaseAddress,\r
1301   OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor\r
1302   )\r
1303 {\r
1304   EFI_STATUS         Status;\r
1305   LIST_ENTRY         *StartLink;\r
1306   LIST_ENTRY         *EndLink;\r
1307   EFI_GCD_MAP_ENTRY  *Entry;\r
1308 \r
1309   //\r
1310   // Make sure parameters are valid\r
1311   //\r
1312   if (Descriptor == NULL) {\r
1313     return EFI_INVALID_PARAMETER;\r
1314   }\r
1315 \r
1316   CoreAcquireGcdMemoryLock ();\r
1317 \r
1318   //\r
1319   // Search for the list of descriptors that contain BaseAddress\r
1320   //\r
1321   Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);\r
1322   if (EFI_ERROR (Status)) {\r
1323     Status = EFI_NOT_FOUND;\r
1324   } else {\r
1325     //\r
1326     // Copy the contents of the found descriptor into Descriptor\r
1327     //\r
1328     Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1329     BuildMemoryDescriptor (Descriptor, Entry);\r
1330   }\r
1331 \r
1332   CoreReleaseGcdMemoryLock ();\r
1333 \r
1334   return Status;\r
1335 }\r
1336 \r
1337 \r
1338 /**\r
1339   Modifies the attributes for a memory region in the global coherency domain of the\r
1340   processor.\r
1341 \r
1342   @param  BaseAddress            Specified start address\r
1343   @param  Length                 Specified length\r
1344   @param  Attributes             Specified attributes\r
1345 \r
1346   @retval EFI_SUCCESS            Successfully set attribute of a segment of\r
1347                                  memory space.\r
1348 \r
1349 **/\r
1350 EFI_STATUS\r
1351 CoreSetMemorySpaceAttributes (\r
1352   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
1353   IN UINT64                Length,\r
1354   IN UINT64                Attributes\r
1355   )\r
1356 {\r
1357   return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, Attributes);\r
1358 }\r
1359 \r
1360 \r
1361 /**\r
1362   Returns a map of the memory resources in the global coherency domain of the\r
1363   processor.\r
1364 \r
1365   @param  NumberOfDescriptors    Number of descriptors.\r
1366   @param  MemorySpaceMap         Descriptor array\r
1367 \r
1368   @retval EFI_INVALID_PARAMETER  Invalid parameter\r
1369   @retval EFI_OUT_OF_RESOURCES   No enough buffer to allocate\r
1370   @retval EFI_SUCCESS            Successfully get memory space map.\r
1371 \r
1372 **/\r
1373 EFI_STATUS\r
1374 CoreGetMemorySpaceMap (\r
1375   OUT UINTN                            *NumberOfDescriptors,\r
1376   OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  **MemorySpaceMap\r
1377   )\r
1378 {\r
1379   EFI_STATUS                       Status;\r
1380   LIST_ENTRY                       *Link;\r
1381   EFI_GCD_MAP_ENTRY                *Entry;\r
1382   EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *Descriptor;\r
1383 \r
1384   //\r
1385   // Make sure parameters are valid\r
1386   //\r
1387   if (NumberOfDescriptors == NULL) {\r
1388     return EFI_INVALID_PARAMETER;\r
1389   }\r
1390   if (MemorySpaceMap == NULL) {\r
1391     return EFI_INVALID_PARAMETER;\r
1392   }\r
1393 \r
1394   CoreAcquireGcdMemoryLock ();\r
1395 \r
1396   //\r
1397   // Count the number of descriptors\r
1398   //\r
1399   *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);\r
1400 \r
1401   //\r
1402   // Allocate the MemorySpaceMap\r
1403   //\r
1404   *MemorySpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
1405   if (*MemorySpaceMap == NULL) {\r
1406     Status = EFI_OUT_OF_RESOURCES;\r
1407     goto Done;\r
1408   }\r
1409 \r
1410   //\r
1411   // Fill in the MemorySpaceMap\r
1412   //\r
1413   Descriptor = *MemorySpaceMap;\r
1414   Link = mGcdMemorySpaceMap.ForwardLink;\r
1415   while (Link != &mGcdMemorySpaceMap) {\r
1416     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1417     BuildMemoryDescriptor (Descriptor, Entry);\r
1418     Descriptor++;\r
1419     Link = Link->ForwardLink;\r
1420   }\r
1421   Status = EFI_SUCCESS;\r
1422 \r
1423 Done:\r
1424   CoreReleaseGcdMemoryLock ();\r
1425   return Status;\r
1426 }\r
1427 \r
1428 \r
1429 /**\r
1430   Adds reserved I/O or I/O resources to the global coherency domain of the processor.\r
1431 \r
1432   @param  GcdIoType              IO type of the segment.\r
1433   @param  BaseAddress            Base address of the segment.\r
1434   @param  Length                 Length of the segment.\r
1435 \r
1436   @retval EFI_SUCCESS            Merged this segment into GCD map.\r
1437   @retval EFI_INVALID_PARAMETER  Parameter not valid\r
1438 \r
1439 **/\r
1440 EFI_STATUS\r
1441 CoreAddIoSpace (\r
1442   IN EFI_GCD_IO_TYPE       GcdIoType,\r
1443   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
1444   IN UINT64                Length\r
1445   )\r
1446 {\r
1447   //\r
1448   // Make sure parameters are valid\r
1449   //\r
1450   if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) {\r
1451     return EFI_INVALID_PARAMETER;\r
1452   }\r
1453   return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, GcdIoType, BaseAddress, Length, 0, 0);\r
1454 }\r
1455 \r
1456 \r
1457 /**\r
1458   Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency\r
1459   domain of the processor.\r
1460 \r
1461   @param  GcdAllocateType        The type of allocate operation\r
1462   @param  GcdIoType              The desired IO type\r
1463   @param  Alignment              Align with 2^Alignment\r
1464   @param  Length                 Length to allocate\r
1465   @param  BaseAddress            Base address to allocate\r
1466   @param  ImageHandle            The image handle consume the allocated space.\r
1467   @param  DeviceHandle           The device handle consume the allocated space.\r
1468 \r
1469   @retval EFI_INVALID_PARAMETER  Invalid parameter.\r
1470   @retval EFI_NOT_FOUND          No descriptor contains the desired space.\r
1471   @retval EFI_SUCCESS            IO space successfully allocated.\r
1472 \r
1473 **/\r
1474 EFI_STATUS\r
1475 CoreAllocateIoSpace (\r
1476   IN     EFI_GCD_ALLOCATE_TYPE  GcdAllocateType,\r
1477   IN     EFI_GCD_IO_TYPE        GcdIoType,\r
1478   IN     UINTN                  Alignment,\r
1479   IN     UINT64                 Length,\r
1480   IN OUT EFI_PHYSICAL_ADDRESS   *BaseAddress,\r
1481   IN     EFI_HANDLE             ImageHandle,\r
1482   IN     EFI_HANDLE             DeviceHandle OPTIONAL\r
1483   )\r
1484 {\r
1485   return CoreAllocateSpace (\r
1486            GCD_ALLOCATE_IO_OPERATION,\r
1487            GcdAllocateType,\r
1488            (EFI_GCD_MEMORY_TYPE) 0,\r
1489            GcdIoType,\r
1490            Alignment,\r
1491            Length,\r
1492            BaseAddress,\r
1493            ImageHandle,\r
1494            DeviceHandle\r
1495            );\r
1496 }\r
1497 \r
1498 \r
1499 /**\r
1500   Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency\r
1501   domain of the processor.\r
1502 \r
1503   @param  BaseAddress            Base address of the segment.\r
1504   @param  Length                 Length of the segment.\r
1505 \r
1506   @retval EFI_SUCCESS            Space successfully freed.\r
1507 \r
1508 **/\r
1509 EFI_STATUS\r
1510 CoreFreeIoSpace (\r
1511   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
1512   IN UINT64                Length\r
1513   )\r
1514 {\r
1515   return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);\r
1516 }\r
1517 \r
1518 \r
1519 /**\r
1520   Removes reserved I/O or I/O resources from the global coherency domain of the\r
1521   processor.\r
1522 \r
1523   @param  BaseAddress            Base address of the segment.\r
1524   @param  Length                 Length of the segment.\r
1525 \r
1526   @retval EFI_SUCCESS            Successfully removed a segment of IO space.\r
1527 \r
1528 **/\r
1529 EFI_STATUS\r
1530 CoreRemoveIoSpace (\r
1531   IN EFI_PHYSICAL_ADDRESS  BaseAddress,\r
1532   IN UINT64                Length\r
1533   )\r
1534 {\r
1535   return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);\r
1536 }\r
1537 \r
1538 \r
1539 /**\r
1540   Build a IO descriptor according to an entry.\r
1541 \r
1542   @param  Descriptor             The descriptor to be built\r
1543   @param  Entry                  According to this entry\r
1544 \r
1545 **/\r
1546 VOID\r
1547 BuildIoDescriptor (\r
1548   IN EFI_GCD_IO_SPACE_DESCRIPTOR  *Descriptor,\r
1549   IN EFI_GCD_MAP_ENTRY            *Entry\r
1550   )\r
1551 {\r
1552   Descriptor->BaseAddress  = Entry->BaseAddress;\r
1553   Descriptor->Length       = Entry->EndAddress - Entry->BaseAddress + 1;\r
1554   Descriptor->GcdIoType    = Entry->GcdIoType;\r
1555   Descriptor->ImageHandle  = Entry->ImageHandle;\r
1556   Descriptor->DeviceHandle = Entry->DeviceHandle;\r
1557 }\r
1558 \r
1559 \r
1560 /**\r
1561   Retrieves the descriptor for an I/O region containing a specified address.\r
1562 \r
1563   @param  BaseAddress            Specified start address\r
1564   @param  Descriptor             Specified length\r
1565 \r
1566   @retval EFI_INVALID_PARAMETER  Descriptor is NULL.\r
1567   @retval EFI_SUCCESS            Successfully get the IO space descriptor.\r
1568 \r
1569 **/\r
1570 EFI_STATUS\r
1571 CoreGetIoSpaceDescriptor (\r
1572   IN  EFI_PHYSICAL_ADDRESS         BaseAddress,\r
1573   OUT EFI_GCD_IO_SPACE_DESCRIPTOR  *Descriptor\r
1574   )\r
1575 {\r
1576   EFI_STATUS         Status;\r
1577   LIST_ENTRY         *StartLink;\r
1578   LIST_ENTRY         *EndLink;\r
1579   EFI_GCD_MAP_ENTRY  *Entry;\r
1580 \r
1581   //\r
1582   // Make sure parameters are valid\r
1583   //\r
1584   if (Descriptor == NULL) {\r
1585     return EFI_INVALID_PARAMETER;\r
1586   }\r
1587 \r
1588   CoreAcquireGcdIoLock ();\r
1589 \r
1590   //\r
1591   // Search for the list of descriptors that contain BaseAddress\r
1592   //\r
1593   Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);\r
1594   if (EFI_ERROR (Status)) {\r
1595     Status = EFI_NOT_FOUND;\r
1596   } else {\r
1597     //\r
1598     // Copy the contents of the found descriptor into Descriptor\r
1599     //\r
1600     Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1601     BuildIoDescriptor (Descriptor, Entry);\r
1602   }\r
1603 \r
1604   CoreReleaseGcdIoLock ();\r
1605 \r
1606   return Status;\r
1607 }\r
1608 \r
1609 \r
1610 /**\r
1611   Returns a map of the I/O resources in the global coherency domain of the processor.\r
1612 \r
1613   @param  NumberOfDescriptors    Number of descriptors.\r
1614   @param  IoSpaceMap             Descriptor array\r
1615 \r
1616   @retval EFI_INVALID_PARAMETER  Invalid parameter\r
1617   @retval EFI_OUT_OF_RESOURCES   No enough buffer to allocate\r
1618   @retval EFI_SUCCESS            Successfully get IO space map.\r
1619 \r
1620 **/\r
1621 EFI_STATUS\r
1622 CoreGetIoSpaceMap (\r
1623   OUT UINTN                        *NumberOfDescriptors,\r
1624   OUT EFI_GCD_IO_SPACE_DESCRIPTOR  **IoSpaceMap\r
1625   )\r
1626 {\r
1627   EFI_STATUS                   Status;\r
1628   LIST_ENTRY                   *Link;\r
1629   EFI_GCD_MAP_ENTRY            *Entry;\r
1630   EFI_GCD_IO_SPACE_DESCRIPTOR  *Descriptor;\r
1631 \r
1632   //\r
1633   // Make sure parameters are valid\r
1634   //\r
1635   if (NumberOfDescriptors == NULL) {\r
1636     return EFI_INVALID_PARAMETER;\r
1637   }\r
1638   if (IoSpaceMap == NULL) {\r
1639     return EFI_INVALID_PARAMETER;\r
1640   }\r
1641 \r
1642   CoreAcquireGcdIoLock ();\r
1643 \r
1644   //\r
1645   // Count the number of descriptors\r
1646   //\r
1647   *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);\r
1648 \r
1649   //\r
1650   // Allocate the IoSpaceMap\r
1651   //\r
1652   *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));\r
1653   if (*IoSpaceMap == NULL) {\r
1654     Status = EFI_OUT_OF_RESOURCES;\r
1655     goto Done;\r
1656   }\r
1657 \r
1658   //\r
1659   // Fill in the IoSpaceMap\r
1660   //\r
1661   Descriptor = *IoSpaceMap;\r
1662   Link = mGcdIoSpaceMap.ForwardLink;\r
1663   while (Link != &mGcdIoSpaceMap) {\r
1664     Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1665     BuildIoDescriptor (Descriptor, Entry);\r
1666     Descriptor++;\r
1667     Link = Link->ForwardLink;\r
1668   }\r
1669   Status = EFI_SUCCESS;\r
1670 \r
1671 Done:\r
1672   CoreReleaseGcdIoLock ();\r
1673   return Status;\r
1674 }\r
1675 \r
1676 \r
1677 /**\r
1678   Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor\r
1679   capabilities mask\r
1680 \r
1681   @param  GcdMemoryType          Type of resource in the GCD memory map.\r
1682   @param  Attributes             The attribute mask in the Resource Descriptor\r
1683                                  HOB.\r
1684 \r
1685   @return The capabilities mask for an EFI Memory Descriptor.\r
1686 \r
1687 **/\r
1688 UINT64\r
1689 CoreConvertResourceDescriptorHobAttributesToCapabilities (\r
1690   EFI_GCD_MEMORY_TYPE  GcdMemoryType,\r
1691   UINT64               Attributes\r
1692   )\r
1693 {\r
1694   UINT64                          Capabilities;\r
1695   GCD_ATTRIBUTE_CONVERSION_ENTRY  *Conversion;\r
1696 \r
1697   //\r
1698   // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask\r
1699   //\r
1700   for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {\r
1701     if (Conversion->Memory || (GcdMemoryType != EfiGcdMemoryTypeSystemMemory)) {\r
1702       if (Attributes & Conversion->Attribute) {\r
1703         Capabilities |= Conversion->Capability;\r
1704       }\r
1705     }\r
1706   }\r
1707 \r
1708   return Capabilities;\r
1709 }\r
1710 \r
1711 \r
1712 /**\r
1713   External function. Initializes the GCD and memory services based on the memory\r
1714   descriptor HOBs.  This function is responsible for priming the GCD map and the\r
1715   memory map, so memory allocations and resource allocations can be made.  The first\r
1716   part of this function can not depend on any memory services until at least one\r
1717   memory descriptor is provided to the memory services.  Then the memory services\r
1718   can be used to intialize the GCD map.\r
1719 \r
1720   @param  HobStart               The start address of the HOB.\r
1721   @param  MemoryBaseAddress      Start address of memory region found to init DXE\r
1722                                  core.\r
1723   @param  MemoryLength           Length of memory region found to init DXE core.\r
1724 \r
1725   @retval EFI_SUCCESS            Memory services successfully initialized.\r
1726 \r
1727 **/\r
1728 EFI_STATUS\r
1729 CoreInitializeMemoryServices (\r
1730   IN  VOID                  **HobStart,\r
1731   OUT EFI_PHYSICAL_ADDRESS  *MemoryBaseAddress,\r
1732   OUT UINT64                *MemoryLength\r
1733   )\r
1734 {\r
1735   EFI_PEI_HOB_POINTERS               Hob;\r
1736   EFI_MEMORY_TYPE_INFORMATION        *EfiMemoryTypeInformation;\r
1737   UINTN                              DataSize;\r
1738   BOOLEAN                            Found;\r
1739   EFI_HOB_HANDOFF_INFO_TABLE         *PhitHob;\r
1740   EFI_HOB_RESOURCE_DESCRIPTOR        *ResourceHob;\r
1741   EFI_HOB_RESOURCE_DESCRIPTOR        *PhitResourceHob;\r
1742   EFI_PHYSICAL_ADDRESS               BaseAddress;\r
1743   UINT64                             Length;\r
1744   UINT64                             Attributes;\r
1745   UINT64                             Capabilities;\r
1746   EFI_PHYSICAL_ADDRESS               MaxMemoryBaseAddress;\r
1747   UINT64                             MaxMemoryLength;\r
1748   UINT64                             MaxMemoryAttributes;\r
1749   EFI_PHYSICAL_ADDRESS               MaxAddress;\r
1750   EFI_PHYSICAL_ADDRESS               HighAddress;\r
1751   EFI_HOB_RESOURCE_DESCRIPTOR        *MaxResourceHob;\r
1752   EFI_HOB_GUID_TYPE                  *GuidHob;\r
1753 \r
1754   //\r
1755   // Point at the first HOB.  This must be the PHIT HOB.\r
1756   //\r
1757   Hob.Raw = *HobStart;\r
1758   ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);\r
1759 \r
1760   //\r
1761   // Initialize the spin locks and maps in the memory services.\r
1762   // Also fill in the memory services into the EFI Boot Services Table\r
1763   //\r
1764   CoreInitializePool ();\r
1765 \r
1766   //\r
1767   // Initialize Local Variables\r
1768   //\r
1769   PhitResourceHob       = NULL;\r
1770   MaxResourceHob        = NULL;\r
1771   ResourceHob           = NULL;\r
1772   BaseAddress           = 0;\r
1773   Length                = 0;\r
1774   Attributes            = 0;\r
1775   MaxMemoryBaseAddress  = 0;\r
1776   MaxMemoryLength       = 0;\r
1777   MaxMemoryAttributes   = 0;\r
1778 \r
1779   //\r
1780   // Cache the PHIT HOB for later use\r
1781   //\r
1782   PhitHob = Hob.HandoffInformationTable;\r
1783 \r
1784   //\r
1785   // See if a Memory Type Information HOB is available\r
1786   //\r
1787   GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);\r
1788   if (GuidHob != NULL) {\r
1789     EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);\r
1790     DataSize                 = GET_GUID_HOB_DATA_SIZE (GuidHob);\r
1791     if (EfiMemoryTypeInformation != NULL && DataSize > 0 && DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION)) {\r
1792       CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);\r
1793     }\r
1794   }\r
1795 \r
1796   //\r
1797   // Find the Resource Descriptor HOB that contains range FreeMemoryBaseAddress..FreeMemoryLength\r
1798   //\r
1799   Length = 0;\r
1800   Found  = FALSE;\r
1801   for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {\r
1802 \r
1803     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
1804 \r
1805       ResourceHob = Hob.ResourceDescriptor;\r
1806 \r
1807       if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY                                       &&\r
1808           (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES    ) {\r
1809 \r
1810         if (PhitHob->EfiFreeMemoryBottom >= ResourceHob->PhysicalStart                         &&\r
1811             PhitHob->EfiFreeMemoryTop    <= (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)    ) {\r
1812 \r
1813           //\r
1814           // Cache the resource descriptor HOB for the memory region described by the PHIT HOB\r
1815           //\r
1816           PhitResourceHob = ResourceHob;\r
1817           Found = TRUE;\r
1818 \r
1819           Attributes  = PhitResourceHob->ResourceAttribute;\r
1820           BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);\r
1821           Length      = PageAlignLength  (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);\r
1822           if (Length < MINIMUM_INITIAL_MEMORY_SIZE) {\r
1823             BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);\r
1824             Length      = PageAlignLength  (PhitHob->EfiFreeMemoryTop - BaseAddress);\r
1825             if (Length < MINIMUM_INITIAL_MEMORY_SIZE) {\r
1826               BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);\r
1827               Length      = PageAlignLength  ((UINT64)((UINTN)*HobStart - BaseAddress));\r
1828             }\r
1829           }\r
1830           break;\r
1831         }\r
1832       }\r
1833     }\r
1834   }\r
1835 \r
1836   //\r
1837   // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found\r
1838   //\r
1839   ASSERT (Found);\r
1840 \r
1841   //\r
1842   // Search all the resource descriptor HOBs from the highest possible addresses down for a memory\r
1843   // region that is big enough to initialize the DXE core.  Always skip the PHIT Resource HOB.\r
1844   // The max address must be within the physically addressible range for the processor.\r
1845   //\r
1846   MaxMemoryLength = 0;\r
1847   MaxAddress      = EFI_MAX_ADDRESS;\r
1848   do {\r
1849     HighAddress = 0;\r
1850     Found       = FALSE;\r
1851     //\r
1852     // Search for a tested memory region that is below MaxAddress\r
1853     //\r
1854     for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {\r
1855 \r
1856       //\r
1857       // See if this is a resource descriptor HOB that does not contain the PHIT.\r
1858       //\r
1859       if (Hob.ResourceDescriptor != PhitResourceHob && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
1860 \r
1861         ResourceHob = Hob.ResourceDescriptor;\r
1862         //\r
1863         // See if this resource descrior HOB describes tested system memory below MaxAddress\r
1864         //\r
1865         if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&\r
1866            (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES &&\r
1867             ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MaxAddress) {\r
1868           //\r
1869           // See if this is the highest tested system memory region below MaxAddress\r
1870           //\r
1871           if (ResourceHob->PhysicalStart > HighAddress) {\r
1872 \r
1873             MaxResourceHob = ResourceHob;\r
1874             HighAddress = MaxResourceHob->PhysicalStart;\r
1875             Found = TRUE;\r
1876           }\r
1877         }\r
1878       }\r
1879     }\r
1880     if (Found) {\r
1881       //\r
1882       // Compute the size of the tested memory region below MaxAddrees\r
1883       //\r
1884       MaxMemoryBaseAddress = PageAlignAddress (MaxResourceHob->PhysicalStart);\r
1885       MaxMemoryLength      = PageAlignLength  (MaxResourceHob->PhysicalStart + MaxResourceHob->ResourceLength - MaxMemoryBaseAddress);\r
1886       MaxMemoryAttributes  = MaxResourceHob->ResourceAttribute;\r
1887     }\r
1888     MaxAddress = ResourceHob->PhysicalStart;\r
1889   } while (Found && MaxMemoryLength < MINIMUM_INITIAL_MEMORY_SIZE);\r
1890 \r
1891   if ((Length < MINIMUM_INITIAL_MEMORY_SIZE) ||\r
1892       (MaxMemoryBaseAddress > BaseAddress && MaxMemoryLength >= MINIMUM_INITIAL_MEMORY_SIZE)) {\r
1893     BaseAddress = MaxMemoryBaseAddress;\r
1894     Length      = MaxMemoryLength;\r
1895     Attributes  = MaxMemoryAttributes;\r
1896   }\r
1897 \r
1898   //\r
1899   // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().\r
1900   //\r
1901   ASSERT (Length >= MINIMUM_INITIAL_MEMORY_SIZE);\r
1902 \r
1903   //\r
1904   // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask\r
1905   //\r
1906   Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);\r
1907 \r
1908   //\r
1909   // Declare the very first memory region, so the EFI Memory Services are available.\r
1910   //\r
1911   CoreAddMemoryDescriptor (\r
1912     EfiConventionalMemory,\r
1913     BaseAddress,\r
1914     RShiftU64 (Length, EFI_PAGE_SHIFT),\r
1915     Capabilities\r
1916     );\r
1917 \r
1918   *MemoryBaseAddress = BaseAddress;\r
1919   *MemoryLength      = Length;\r
1920 \r
1921   return EFI_SUCCESS;\r
1922 }\r
1923 \r
1924 \r
1925 /**\r
1926   External function. Initializes the GCD and memory services based on the memory\r
1927   descriptor HOBs.  This function is responsible for priming the GCD map and the\r
1928   memory map, so memory allocations and resource allocations can be made.  The first\r
1929   part of this function can not depend on any memory services until at least one\r
1930   memory descriptor is provided to the memory services.  Then the memory services\r
1931   can be used to intialize the GCD map. The HobStart will be relocated to a pool\r
1932   buffer.\r
1933 \r
1934   @param  HobStart               The start address of the HOB\r
1935   @param  MemoryBaseAddress      Start address of memory region found to init DXE\r
1936                                  core.\r
1937   @param  MemoryLength           Length of memory region found to init DXE core.\r
1938 \r
1939   @retval EFI_SUCCESS            GCD services successfully initialized.\r
1940 \r
1941 **/\r
1942 EFI_STATUS\r
1943 CoreInitializeGcdServices (\r
1944   IN OUT VOID              **HobStart,\r
1945   IN EFI_PHYSICAL_ADDRESS  MemoryBaseAddress,\r
1946   IN UINT64                MemoryLength\r
1947   )\r
1948 {\r
1949   EFI_PEI_HOB_POINTERS               Hob;\r
1950   VOID                               *NewHobList;\r
1951   EFI_HOB_HANDOFF_INFO_TABLE         *PhitHob;\r
1952   UINT8                              SizeOfMemorySpace;\r
1953   UINT8                              SizeOfIoSpace;\r
1954   EFI_HOB_RESOURCE_DESCRIPTOR        *ResourceHob;\r
1955   EFI_PHYSICAL_ADDRESS               BaseAddress;\r
1956   UINT64                             Length;\r
1957   EFI_STATUS                         Status;\r
1958   EFI_GCD_MAP_ENTRY                  *Entry;\r
1959   EFI_GCD_MEMORY_TYPE                GcdMemoryType;\r
1960   EFI_GCD_IO_TYPE                    GcdIoType;\r
1961   EFI_GCD_MEMORY_SPACE_DESCRIPTOR    Descriptor;\r
1962   EFI_HOB_MEMORY_ALLOCATION          *MemoryHob;\r
1963   EFI_HOB_FIRMWARE_VOLUME            *FirmwareVolumeHob;\r
1964   UINTN                              NumberOfDescriptors;\r
1965   EFI_GCD_MEMORY_SPACE_DESCRIPTOR    *MemorySpaceMap;\r
1966   UINTN                              Index;\r
1967   UINT64                             Capabilities;\r
1968   EFI_HOB_CPU *                      CpuHob;\r
1969 \r
1970   //\r
1971   // Cache the PHIT HOB for later use\r
1972   //\r
1973   PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);\r
1974 \r
1975   //\r
1976   // Get the number of address lines in the I/O and Memory space for the CPU\r
1977   //\r
1978   CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
1979   ASSERT (CpuHob != NULL);\r
1980   SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;\r
1981   SizeOfIoSpace     = CpuHob->SizeOfIoSpace;\r
1982 \r
1983   //\r
1984   // Initialize the GCD Memory Space Map\r
1985   //\r
1986   Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);\r
1987   ASSERT (Entry != NULL);\r
1988 \r
1989   Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;\r
1990 \r
1991   InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);\r
1992 \r
1993   //\r
1994   // Initialize the GCD I/O Space Map\r
1995   //\r
1996   Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);\r
1997   ASSERT (Entry != NULL);\r
1998 \r
1999   Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;\r
2000 \r
2001   InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);\r
2002 \r
2003   //\r
2004   // Walk the HOB list and add all resource descriptors to the GCD\r
2005   //\r
2006   for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {\r
2007 \r
2008     GcdMemoryType = EfiGcdMemoryTypeNonExistent;\r
2009     GcdIoType     = EfiGcdIoTypeNonExistent;\r
2010 \r
2011     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
2012 \r
2013       ResourceHob = Hob.ResourceDescriptor;\r
2014 \r
2015       switch (ResourceHob->ResourceType) {\r
2016       case EFI_RESOURCE_SYSTEM_MEMORY:\r
2017         if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {\r
2018           GcdMemoryType = EfiGcdMemoryTypeSystemMemory;\r
2019         }\r
2020         if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {\r
2021           GcdMemoryType = EfiGcdMemoryTypeReserved;\r
2022         }\r
2023         if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {\r
2024           GcdMemoryType = EfiGcdMemoryTypeReserved;\r
2025         }\r
2026         break;\r
2027       case EFI_RESOURCE_MEMORY_MAPPED_IO:\r
2028       case EFI_RESOURCE_FIRMWARE_DEVICE:\r
2029         GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;\r
2030         break;\r
2031       case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:\r
2032       case EFI_RESOURCE_MEMORY_RESERVED:\r
2033         GcdMemoryType = EfiGcdMemoryTypeReserved;\r
2034         break;\r
2035       case EFI_RESOURCE_IO:\r
2036         GcdIoType = EfiGcdIoTypeIo;\r
2037         break;\r
2038       case EFI_RESOURCE_IO_RESERVED:\r
2039         GcdIoType = EfiGcdIoTypeReserved;\r
2040         break;\r
2041       }\r
2042 \r
2043       if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {\r
2044         //\r
2045         // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask\r
2046         //\r
2047         Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (\r
2048                          GcdMemoryType,\r
2049                          ResourceHob->ResourceAttribute\r
2050                          );\r
2051 \r
2052         Status = CoreInternalAddMemorySpace (\r
2053                    GcdMemoryType,\r
2054                    ResourceHob->PhysicalStart,\r
2055                    ResourceHob->ResourceLength,\r
2056                    Capabilities\r
2057                    );\r
2058       }\r
2059 \r
2060       if (GcdIoType != EfiGcdIoTypeNonExistent) {\r
2061         Status = CoreAddIoSpace (\r
2062                    GcdIoType,\r
2063                    ResourceHob->PhysicalStart,\r
2064                    ResourceHob->ResourceLength\r
2065                    );\r
2066       }\r
2067     }\r
2068   }\r
2069 \r
2070   //\r
2071   // Allocate first memory region from the GCD by the DXE core\r
2072   //\r
2073   Status = CoreAllocateMemorySpace (\r
2074              EfiGcdAllocateAddress,\r
2075              EfiGcdMemoryTypeSystemMemory,\r
2076              0,\r
2077              MemoryLength,\r
2078              &MemoryBaseAddress,\r
2079              gDxeCoreImageHandle,\r
2080              NULL\r
2081              );\r
2082 \r
2083   //\r
2084   // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,\r
2085   // and Firmware Volume HOBs.  Also update the EFI Memory Map with the memory allocation HOBs.\r
2086   //\r
2087   for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {\r
2088     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {\r
2089       MemoryHob = Hob.MemoryAllocation;\r
2090       BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;\r
2091       Status = CoreGetMemorySpaceDescriptor  (BaseAddress, &Descriptor);\r
2092       if (!EFI_ERROR (Status)) {\r
2093         Status = CoreAllocateMemorySpace (\r
2094                    EfiGcdAllocateAddress,\r
2095                    Descriptor.GcdMemoryType,\r
2096                    0,\r
2097                    MemoryHob->AllocDescriptor.MemoryLength,\r
2098                    &BaseAddress,\r
2099                    gDxeCoreImageHandle,\r
2100                    NULL\r
2101                    );\r
2102         if (!EFI_ERROR (Status) && Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {\r
2103           CoreAddMemoryDescriptor (\r
2104             MemoryHob->AllocDescriptor.MemoryType,\r
2105             MemoryHob->AllocDescriptor.MemoryBaseAddress,\r
2106             RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),\r
2107             Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)\r
2108             );\r
2109         }\r
2110       }\r
2111     }\r
2112 \r
2113     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {\r
2114       FirmwareVolumeHob = Hob.FirmwareVolume;\r
2115       BaseAddress = FirmwareVolumeHob->BaseAddress;\r
2116       Status = CoreAllocateMemorySpace (\r
2117                  EfiGcdAllocateAddress,\r
2118                  EfiGcdMemoryTypeMemoryMappedIo,\r
2119                  0,\r
2120                  FirmwareVolumeHob->Length,\r
2121                  &BaseAddress,\r
2122                  gDxeCoreImageHandle,\r
2123                  NULL\r
2124                  );\r
2125     }\r
2126   }\r
2127 \r
2128   //\r
2129   // Relocate HOB List to an allocated pool buffer.\r
2130   //\r
2131   NewHobList = AllocateCopyPool (\r
2132                  (UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart),\r
2133                  *HobStart\r
2134                  );\r
2135   ASSERT (NewHobList != NULL);\r
2136 \r
2137   *HobStart = NewHobList;\r
2138   gHobList  = NewHobList;\r
2139 \r
2140   //\r
2141   // Add and allocate the remaining unallocated system memory to the memory services.\r
2142   //\r
2143   Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
2144   for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
2145     if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {\r
2146       if (MemorySpaceMap[Index].ImageHandle == NULL) {\r
2147         BaseAddress  = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);\r
2148         Length       = PageAlignLength  (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);\r
2149         if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) {\r
2150           continue;\r
2151         }\r
2152         CoreAddMemoryDescriptor (\r
2153           EfiConventionalMemory,\r
2154           BaseAddress,\r
2155           RShiftU64 (Length, EFI_PAGE_SHIFT),\r
2156           MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)\r
2157           );\r
2158         Status = CoreAllocateMemorySpace (\r
2159                    EfiGcdAllocateAddress,\r
2160                    EfiGcdMemoryTypeSystemMemory,\r
2161                    0,\r
2162                    Length,\r
2163                    &BaseAddress,\r
2164                    gDxeCoreImageHandle,\r
2165                    NULL\r
2166                    );\r
2167       }\r
2168     }\r
2169   }\r
2170   CoreFreePool (MemorySpaceMap);\r
2171 \r
2172   return EFI_SUCCESS;\r
2173 }\r