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