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