2 The file contains the GCD related services in the EFI Boot Services Table.
3 The GCD services are used to manage the memory and I/O regions that
4 are accessible to the CPU that is executing the DXE core.
6 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "Mem/HeapGuard.h"
15 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
17 #define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
18 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
19 EFI_RESOURCE_ATTRIBUTE_TESTED | \
20 EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
21 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
22 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
23 EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
24 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
25 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
26 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
27 EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
29 #define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
30 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
31 EFI_RESOURCE_ATTRIBUTE_TESTED )
33 #define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
34 EFI_RESOURCE_ATTRIBUTE_INITIALIZED )
36 #define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
38 #define EXCLUSIVE_MEMORY_ATTRIBUTES (EFI_MEMORY_UC | EFI_MEMORY_WC | \
39 EFI_MEMORY_WT | EFI_MEMORY_WB | \
40 EFI_MEMORY_WP | EFI_MEMORY_UCE)
42 #define NONEXCLUSIVE_MEMORY_ATTRIBUTES (EFI_MEMORY_XP | EFI_MEMORY_RP | \
48 EFI_LOCK mGcdMemorySpaceLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY
);
49 EFI_LOCK mGcdIoSpaceLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY
);
50 LIST_ENTRY mGcdMemorySpaceMap
= INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap
);
51 LIST_ENTRY mGcdIoSpaceMap
= INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap
);
53 EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate
= {
54 EFI_GCD_MAP_SIGNATURE
,
63 EfiGcdMemoryTypeNonExistent
,
69 EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate
= {
70 EFI_GCD_MAP_SIGNATURE
,
79 (EFI_GCD_MEMORY_TYPE
) 0,
80 EfiGcdIoTypeNonExistent
,
85 GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable
[] = {
86 { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE
, EFI_MEMORY_UC
, TRUE
},
87 { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED
, EFI_MEMORY_UCE
, TRUE
},
88 { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE
, EFI_MEMORY_WC
, TRUE
},
89 { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE
, EFI_MEMORY_WT
, TRUE
},
90 { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE
, EFI_MEMORY_WB
, TRUE
},
91 { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE
, EFI_MEMORY_RP
, TRUE
},
92 { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE
, EFI_MEMORY_WP
, TRUE
},
93 { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE
, EFI_MEMORY_XP
, TRUE
},
94 { EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE
, EFI_MEMORY_RO
, TRUE
},
95 { EFI_RESOURCE_ATTRIBUTE_PRESENT
, EFI_MEMORY_PRESENT
, FALSE
},
96 { EFI_RESOURCE_ATTRIBUTE_INITIALIZED
, EFI_MEMORY_INITIALIZED
, FALSE
},
97 { EFI_RESOURCE_ATTRIBUTE_TESTED
, EFI_MEMORY_TESTED
, FALSE
},
98 { EFI_RESOURCE_ATTRIBUTE_PERSISTABLE
, EFI_MEMORY_NV
, TRUE
},
99 { EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE
, EFI_MEMORY_MORE_RELIABLE
, TRUE
},
104 /// Lookup table used to print GCD Memory Space Map
106 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mGcdMemoryTypeNames
[] = {
107 "NonExist ", // EfiGcdMemoryTypeNonExistent
108 "Reserved ", // EfiGcdMemoryTypeReserved
109 "SystemMem", // EfiGcdMemoryTypeSystemMemory
110 "MMIO ", // EfiGcdMemoryTypeMemoryMappedIo
111 "PersisMem", // EfiGcdMemoryTypePersistent
112 "MoreRelia", // EfiGcdMemoryTypeMoreReliable
113 "Unknown " // EfiGcdMemoryTypeMaximum
117 /// Lookup table used to print GCD I/O Space Map
119 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mGcdIoTypeNames
[] = {
120 "NonExist", // EfiGcdIoTypeNonExistent
121 "Reserved", // EfiGcdIoTypeReserved
122 "I/O ", // EfiGcdIoTypeIo
123 "Unknown " // EfiGcdIoTypeMaximum
127 /// Lookup table used to print GCD Allocation Types
129 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8
*mGcdAllocationTypeNames
[] = {
130 "AnySearchBottomUp ", // EfiGcdAllocateAnySearchBottomUp
131 "MaxAddressSearchBottomUp ", // EfiGcdAllocateMaxAddressSearchBottomUp
132 "AtAddress ", // EfiGcdAllocateAddress
133 "AnySearchTopDown ", // EfiGcdAllocateAnySearchTopDown
134 "MaxAddressSearchTopDown ", // EfiGcdAllocateMaxAddressSearchTopDown
135 "Unknown " // EfiGcdMaxAllocateType
139 Dump the entire contents if the GCD Memory Space Map using DEBUG() macros when
140 PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
142 @param InitialMap TRUE if the initial GCD Memory Map is being dumped. Otherwise, FALSE.
147 CoreDumpGcdMemorySpaceMap (
153 UINTN NumberOfDescriptors
;
154 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
;
157 Status
= CoreGetMemorySpaceMap (&NumberOfDescriptors
, &MemorySpaceMap
);
158 ASSERT (Status
== EFI_SUCCESS
&& MemorySpaceMap
!= NULL
);
161 DEBUG ((DEBUG_GCD
, "GCD:Initial GCD Memory Space Map\n"));
163 DEBUG ((DEBUG_GCD
, "GCDMemType Range Capabilities Attributes \n"));
164 DEBUG ((DEBUG_GCD
, "========== ================================= ================ ================\n"));
165 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
166 DEBUG ((DEBUG_GCD
, "%a %016lx-%016lx %016lx %016lx%c\n",
167 mGcdMemoryTypeNames
[MIN (MemorySpaceMap
[Index
].GcdMemoryType
, EfiGcdMemoryTypeMaximum
)],
168 MemorySpaceMap
[Index
].BaseAddress
,
169 MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
- 1,
170 MemorySpaceMap
[Index
].Capabilities
,
171 MemorySpaceMap
[Index
].Attributes
,
172 MemorySpaceMap
[Index
].ImageHandle
== NULL
? ' ' : '*'
175 DEBUG ((DEBUG_GCD
, "\n"));
176 FreePool (MemorySpaceMap
);
181 Dump the entire contents if the GCD I/O Space Map using DEBUG() macros when
182 PcdDebugPrintErrorLevel has the DEBUG_GCD bit set.
184 @param InitialMap TRUE if the initial GCD I/O Map is being dumped. Otherwise, FALSE.
189 CoreDumpGcdIoSpaceMap (
195 UINTN NumberOfDescriptors
;
196 EFI_GCD_IO_SPACE_DESCRIPTOR
*IoSpaceMap
;
199 Status
= CoreGetIoSpaceMap (&NumberOfDescriptors
, &IoSpaceMap
);
200 ASSERT (Status
== EFI_SUCCESS
&& IoSpaceMap
!= NULL
);
203 DEBUG ((DEBUG_GCD
, "GCD:Initial GCD I/O Space Map\n"));
206 DEBUG ((DEBUG_GCD
, "GCDIoType Range \n"));
207 DEBUG ((DEBUG_GCD
, "========== =================================\n"));
208 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
209 DEBUG ((DEBUG_GCD
, "%a %016lx-%016lx%c\n",
210 mGcdIoTypeNames
[MIN (IoSpaceMap
[Index
].GcdIoType
, EfiGcdIoTypeMaximum
)],
211 IoSpaceMap
[Index
].BaseAddress
,
212 IoSpaceMap
[Index
].BaseAddress
+ IoSpaceMap
[Index
].Length
- 1,
213 IoSpaceMap
[Index
].ImageHandle
== NULL
? ' ' : '*'
216 DEBUG ((DEBUG_GCD
, "\n"));
217 FreePool (IoSpaceMap
);
222 Validate resource descriptor HOB's attributes.
224 If Attributes includes some memory resource's settings, it should include
225 the corresponding capabilites also.
227 @param Attributes Resource descriptor HOB attributes.
231 CoreValidateResourceDescriptorHobAttributes (
235 ASSERT (((Attributes
& EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
) == 0) ||
236 ((Attributes
& EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE
) != 0));
237 ASSERT (((Attributes
& EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
) == 0) ||
238 ((Attributes
& EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE
) != 0));
239 ASSERT (((Attributes
& EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
) == 0) ||
240 ((Attributes
& EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE
) != 0));
241 ASSERT (((Attributes
& EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED
) == 0) ||
242 ((Attributes
& EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE
) != 0));
243 ASSERT (((Attributes
& EFI_RESOURCE_ATTRIBUTE_PERSISTENT
) == 0) ||
244 ((Attributes
& EFI_RESOURCE_ATTRIBUTE_PERSISTABLE
) != 0));
248 Acquire memory lock on mGcdMemorySpaceLock.
252 CoreAcquireGcdMemoryLock (
256 CoreAcquireLock (&mGcdMemorySpaceLock
);
262 Release memory lock on mGcdMemorySpaceLock.
266 CoreReleaseGcdMemoryLock (
270 CoreReleaseLock (&mGcdMemorySpaceLock
);
276 Acquire memory lock on mGcdIoSpaceLock.
280 CoreAcquireGcdIoLock (
284 CoreAcquireLock (&mGcdIoSpaceLock
);
289 Release memory lock on mGcdIoSpaceLock.
293 CoreReleaseGcdIoLock (
297 CoreReleaseLock (&mGcdIoSpaceLock
);
303 // GCD Initialization Worker Functions
306 Aligns a value to the specified boundary.
308 @param Value 64 bit value to align
309 @param Alignment Log base 2 of the boundary to align Value to
310 @param RoundUp TRUE if Value is to be rounded up to the nearest
311 aligned boundary. FALSE is Value is to be
312 rounded down to the nearest aligned boundary.
314 @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
324 UINT64 AlignmentMask
;
326 AlignmentMask
= LShiftU64 (1, Alignment
) - 1;
328 Value
+= AlignmentMask
;
330 return Value
& (~AlignmentMask
);
335 Aligns address to the page boundary.
337 @param Value 64 bit address to align
339 @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
347 return AlignValue (Value
, EFI_PAGE_SHIFT
, TRUE
);
352 Aligns length to the page boundary.
354 @param Value 64 bit length to align
356 @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
364 return AlignValue (Value
, EFI_PAGE_SHIFT
, FALSE
);
368 // GCD Memory Space Worker Functions
372 Allocate pool for two entries.
374 @param TopEntry An entry of GCD map
375 @param BottomEntry An entry of GCD map
377 @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
378 @retval EFI_SUCCESS Both entries successfully allocated.
382 CoreAllocateGcdMapEntry (
383 IN OUT EFI_GCD_MAP_ENTRY
**TopEntry
,
384 IN OUT EFI_GCD_MAP_ENTRY
**BottomEntry
388 // Set to mOnGuarding to TRUE before memory allocation. This will make sure
389 // that the entry memory is not "guarded" by HeapGuard. Otherwise it might
390 // cause problem when it's freed (if HeapGuard is enabled).
393 *TopEntry
= AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY
));
395 if (*TopEntry
== NULL
) {
396 return EFI_OUT_OF_RESOURCES
;
400 *BottomEntry
= AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY
));
402 if (*BottomEntry
== NULL
) {
403 CoreFreePool (*TopEntry
);
404 return EFI_OUT_OF_RESOURCES
;
412 Internal function. Inserts a new descriptor into a sorted list
414 @param Link The linked list to insert the range BaseAddress
416 @param Entry A pointer to the entry that is inserted
417 @param BaseAddress The base address of the new range
418 @param Length The length of the new range in bytes
419 @param TopEntry Top pad entry to insert if needed.
420 @param BottomEntry Bottom pad entry to insert if needed.
422 @retval EFI_SUCCESS The new range was inserted into the linked list
426 CoreInsertGcdMapEntry (
428 IN EFI_GCD_MAP_ENTRY
*Entry
,
429 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
431 IN EFI_GCD_MAP_ENTRY
*TopEntry
,
432 IN EFI_GCD_MAP_ENTRY
*BottomEntry
435 ASSERT (Length
!= 0);
437 if (BaseAddress
> Entry
->BaseAddress
) {
438 ASSERT (BottomEntry
->Signature
== 0);
440 CopyMem (BottomEntry
, Entry
, sizeof (EFI_GCD_MAP_ENTRY
));
441 Entry
->BaseAddress
= BaseAddress
;
442 BottomEntry
->EndAddress
= BaseAddress
- 1;
443 InsertTailList (Link
, &BottomEntry
->Link
);
446 if ((BaseAddress
+ Length
- 1) < Entry
->EndAddress
) {
447 ASSERT (TopEntry
->Signature
== 0);
449 CopyMem (TopEntry
, Entry
, sizeof (EFI_GCD_MAP_ENTRY
));
450 TopEntry
->BaseAddress
= BaseAddress
+ Length
;
451 Entry
->EndAddress
= BaseAddress
+ Length
- 1;
452 InsertHeadList (Link
, &TopEntry
->Link
);
460 Merge the Gcd region specified by Link and its adjacent entry.
462 @param Link Specify the entry to be merged (with its
464 @param Forward Direction (forward or backward).
467 @retval EFI_SUCCESS Successfully returned.
468 @retval EFI_UNSUPPORTED These adjacent regions could not merge.
472 CoreMergeGcdMapEntry (
478 LIST_ENTRY
*AdjacentLink
;
479 EFI_GCD_MAP_ENTRY
*Entry
;
480 EFI_GCD_MAP_ENTRY
*AdjacentEntry
;
483 // Get adjacent entry
486 AdjacentLink
= Link
->ForwardLink
;
488 AdjacentLink
= Link
->BackLink
;
492 // If AdjacentLink is the head of the list, then no merge can be performed
494 if (AdjacentLink
== Map
) {
498 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
499 AdjacentEntry
= CR (AdjacentLink
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
501 if (Entry
->Capabilities
!= AdjacentEntry
->Capabilities
) {
502 return EFI_UNSUPPORTED
;
504 if (Entry
->Attributes
!= AdjacentEntry
->Attributes
) {
505 return EFI_UNSUPPORTED
;
507 if (Entry
->GcdMemoryType
!= AdjacentEntry
->GcdMemoryType
) {
508 return EFI_UNSUPPORTED
;
510 if (Entry
->GcdIoType
!= AdjacentEntry
->GcdIoType
) {
511 return EFI_UNSUPPORTED
;
513 if (Entry
->ImageHandle
!= AdjacentEntry
->ImageHandle
) {
514 return EFI_UNSUPPORTED
;
516 if (Entry
->DeviceHandle
!= AdjacentEntry
->DeviceHandle
) {
517 return EFI_UNSUPPORTED
;
521 Entry
->EndAddress
= AdjacentEntry
->EndAddress
;
523 Entry
->BaseAddress
= AdjacentEntry
->BaseAddress
;
525 RemoveEntryList (AdjacentLink
);
526 CoreFreePool (AdjacentEntry
);
533 Merge adjacent entries on total chain.
535 @param TopEntry Top entry of GCD map.
536 @param BottomEntry Bottom entry of GCD map.
537 @param StartLink Start link of the list for this loop.
538 @param EndLink End link of the list for this loop.
541 @retval EFI_SUCCESS GCD map successfully cleaned up.
545 CoreCleanupGcdMapEntry (
546 IN EFI_GCD_MAP_ENTRY
*TopEntry
,
547 IN EFI_GCD_MAP_ENTRY
*BottomEntry
,
548 IN LIST_ENTRY
*StartLink
,
549 IN LIST_ENTRY
*EndLink
,
555 if (TopEntry
->Signature
== 0) {
556 CoreFreePool (TopEntry
);
558 if (BottomEntry
->Signature
== 0) {
559 CoreFreePool (BottomEntry
);
563 while (Link
!= EndLink
->ForwardLink
) {
564 CoreMergeGcdMapEntry (Link
, FALSE
, Map
);
565 Link
= Link
->ForwardLink
;
567 CoreMergeGcdMapEntry (EndLink
, TRUE
, Map
);
574 Search a segment of memory space in GCD map. The result is a range of GCD entry list.
576 @param BaseAddress The start address of the segment.
577 @param Length The length of the segment.
578 @param StartLink The first GCD entry involves this segment of
580 @param EndLink The first GCD entry involves this segment of
582 @param Map Points to the start entry to search.
584 @retval EFI_SUCCESS Successfully found the entry.
585 @retval EFI_NOT_FOUND Not found.
589 CoreSearchGcdMapEntry (
590 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
592 OUT LIST_ENTRY
**StartLink
,
593 OUT LIST_ENTRY
**EndLink
,
598 EFI_GCD_MAP_ENTRY
*Entry
;
600 ASSERT (Length
!= 0);
605 Link
= Map
->ForwardLink
;
606 while (Link
!= Map
) {
607 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
608 if (BaseAddress
>= Entry
->BaseAddress
&& BaseAddress
<= Entry
->EndAddress
) {
611 if (*StartLink
!= NULL
) {
612 if ((BaseAddress
+ Length
- 1) >= Entry
->BaseAddress
&&
613 (BaseAddress
+ Length
- 1) <= Entry
->EndAddress
) {
618 Link
= Link
->ForwardLink
;
621 return EFI_NOT_FOUND
;
626 Count the amount of GCD map entries.
628 @param Map Points to the start entry to do the count loop.
634 CoreCountGcdMapEntry (
642 Link
= Map
->ForwardLink
;
643 while (Link
!= Map
) {
645 Link
= Link
->ForwardLink
;
654 Return the memory attribute specified by Attributes
656 @param Attributes A num with some attribute bits on.
658 @return The enum value of memory attribute.
662 ConverToCpuArchAttributes (
666 UINT64 CpuArchAttributes
;
668 CpuArchAttributes
= Attributes
& NONEXCLUSIVE_MEMORY_ATTRIBUTES
;
670 if ( (Attributes
& EFI_MEMORY_UC
) == EFI_MEMORY_UC
) {
671 CpuArchAttributes
|= EFI_MEMORY_UC
;
672 } else if ( (Attributes
& EFI_MEMORY_WC
) == EFI_MEMORY_WC
) {
673 CpuArchAttributes
|= EFI_MEMORY_WC
;
674 } else if ( (Attributes
& EFI_MEMORY_WT
) == EFI_MEMORY_WT
) {
675 CpuArchAttributes
|= EFI_MEMORY_WT
;
676 } else if ( (Attributes
& EFI_MEMORY_WB
) == EFI_MEMORY_WB
) {
677 CpuArchAttributes
|= EFI_MEMORY_WB
;
678 } else if ( (Attributes
& EFI_MEMORY_UCE
) == EFI_MEMORY_UCE
) {
679 CpuArchAttributes
|= EFI_MEMORY_UCE
;
680 } else if ( (Attributes
& EFI_MEMORY_WP
) == EFI_MEMORY_WP
) {
681 CpuArchAttributes
|= EFI_MEMORY_WP
;
684 return CpuArchAttributes
;
689 Do operation on a segment of memory space specified (add, free, remove, change attribute ...).
691 @param Operation The type of the operation
692 @param GcdMemoryType Additional information for the operation
693 @param GcdIoType Additional information for the operation
694 @param BaseAddress Start address of the segment
695 @param Length length of the segment
696 @param Capabilities The alterable attributes of a newly added entry
697 @param Attributes The attributes needs to be set
699 @retval EFI_INVALID_PARAMETER Length is 0 or address (length) not aligned when
701 @retval EFI_SUCCESS Action successfully done.
702 @retval EFI_UNSUPPORTED Could not find the proper descriptor on this
703 segment or set an upsupported attribute.
704 @retval EFI_ACCESS_DENIED Operate on an space non-exist or is used for an
706 @retval EFI_NOT_FOUND Free a non-using space or remove a non-exist
708 @retval EFI_OUT_OF_RESOURCES No buffer could be allocated.
709 @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol
710 is not available yet.
715 IN EFI_GCD_MEMORY_TYPE GcdMemoryType
,
716 IN EFI_GCD_IO_TYPE GcdIoType
,
717 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
719 IN UINT64 Capabilities
,
726 EFI_GCD_MAP_ENTRY
*Entry
;
727 EFI_GCD_MAP_ENTRY
*TopEntry
;
728 EFI_GCD_MAP_ENTRY
*BottomEntry
;
729 LIST_ENTRY
*StartLink
;
731 UINT64 CpuArchAttributes
;
734 DEBUG ((DEBUG_GCD
, " Status = %r\n", EFI_INVALID_PARAMETER
));
735 return EFI_INVALID_PARAMETER
;
739 if ((Operation
& GCD_MEMORY_SPACE_OPERATION
) != 0) {
740 CoreAcquireGcdMemoryLock ();
741 Map
= &mGcdMemorySpaceMap
;
742 } else if ((Operation
& GCD_IO_SPACE_OPERATION
) != 0) {
743 CoreAcquireGcdIoLock ();
744 Map
= &mGcdIoSpaceMap
;
750 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
752 Status
= CoreSearchGcdMapEntry (BaseAddress
, Length
, &StartLink
, &EndLink
, Map
);
753 if (EFI_ERROR (Status
)) {
754 Status
= EFI_UNSUPPORTED
;
758 ASSERT (StartLink
!= NULL
&& EndLink
!= NULL
);
761 // Verify that the list of descriptors are unallocated non-existent memory.
764 while (Link
!= EndLink
->ForwardLink
) {
765 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
770 case GCD_ADD_MEMORY_OPERATION
:
771 if (Entry
->GcdMemoryType
!= EfiGcdMemoryTypeNonExistent
||
772 Entry
->ImageHandle
!= NULL
) {
773 Status
= EFI_ACCESS_DENIED
;
777 case GCD_ADD_IO_OPERATION
:
778 if (Entry
->GcdIoType
!= EfiGcdIoTypeNonExistent
||
779 Entry
->ImageHandle
!= NULL
) {
780 Status
= EFI_ACCESS_DENIED
;
787 case GCD_FREE_MEMORY_OPERATION
:
788 case GCD_FREE_IO_OPERATION
:
789 if (Entry
->ImageHandle
== NULL
) {
790 Status
= EFI_NOT_FOUND
;
797 case GCD_REMOVE_MEMORY_OPERATION
:
798 if (Entry
->GcdMemoryType
== EfiGcdMemoryTypeNonExistent
) {
799 Status
= EFI_NOT_FOUND
;
802 if (Entry
->ImageHandle
!= NULL
) {
803 Status
= EFI_ACCESS_DENIED
;
807 case GCD_REMOVE_IO_OPERATION
:
808 if (Entry
->GcdIoType
== EfiGcdIoTypeNonExistent
) {
809 Status
= EFI_NOT_FOUND
;
812 if (Entry
->ImageHandle
!= NULL
) {
813 Status
= EFI_ACCESS_DENIED
;
818 // Set attributes operation
820 case GCD_SET_ATTRIBUTES_MEMORY_OPERATION
:
821 if ((Attributes
& EFI_MEMORY_RUNTIME
) != 0) {
822 if ((BaseAddress
& EFI_PAGE_MASK
) != 0 || (Length
& EFI_PAGE_MASK
) != 0) {
823 Status
= EFI_INVALID_PARAMETER
;
827 if ((Entry
->Capabilities
& Attributes
) != Attributes
) {
828 Status
= EFI_UNSUPPORTED
;
833 // Set capabilities operation
835 case GCD_SET_CAPABILITIES_MEMORY_OPERATION
:
836 if ((BaseAddress
& EFI_PAGE_MASK
) != 0 || (Length
& EFI_PAGE_MASK
) != 0) {
837 Status
= EFI_INVALID_PARAMETER
;
842 // Current attributes must still be supported with new capabilities
844 if ((Capabilities
& Entry
->Attributes
) != Entry
->Attributes
) {
845 Status
= EFI_UNSUPPORTED
;
850 Link
= Link
->ForwardLink
;
854 // Allocate work space to perform this operation
856 Status
= CoreAllocateGcdMapEntry (&TopEntry
, &BottomEntry
);
857 if (EFI_ERROR (Status
)) {
858 Status
= EFI_OUT_OF_RESOURCES
;
861 ASSERT (TopEntry
!= NULL
&& BottomEntry
!= NULL
);
864 // Initialize CpuArchAttributes to suppress incorrect compiler/analyzer warnings.
866 CpuArchAttributes
= 0;
867 if (Operation
== GCD_SET_ATTRIBUTES_MEMORY_OPERATION
) {
869 // Call CPU Arch Protocol to attempt to set attributes on the range
871 CpuArchAttributes
= ConverToCpuArchAttributes (Attributes
);
873 // CPU arch attributes include page attributes and cache attributes.
874 // Only page attributes supports to be cleared, but not cache attributes.
875 // Caller is expected to use GetMemorySpaceDescriptor() to get the current
876 // attributes, AND/OR attributes, and then calls SetMemorySpaceAttributes()
877 // to set the new attributes.
878 // So 0 CPU arch attributes should not happen as memory should always have
879 // a cache attribute (no matter UC or WB, etc).
881 // Here, 0 CPU arch attributes will be filtered to be compatible with the
882 // case that caller just calls SetMemorySpaceAttributes() with none CPU
883 // arch attributes (for example, RUNTIME) as the purpose of the case is not
884 // to clear CPU arch attributes.
886 if (CpuArchAttributes
!= 0) {
888 Status
= EFI_NOT_AVAILABLE_YET
;
890 Status
= gCpu
->SetMemoryAttributes (
897 if (EFI_ERROR (Status
)) {
898 CoreFreePool (TopEntry
);
899 CoreFreePool (BottomEntry
);
906 // Convert/Insert the list of descriptors from StartLink to EndLink
909 while (Link
!= EndLink
->ForwardLink
) {
910 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
911 CoreInsertGcdMapEntry (Link
, Entry
, BaseAddress
, Length
, TopEntry
, BottomEntry
);
916 case GCD_ADD_MEMORY_OPERATION
:
917 Entry
->GcdMemoryType
= GcdMemoryType
;
918 if (GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
) {
919 Entry
->Capabilities
= Capabilities
| EFI_MEMORY_RUNTIME
| EFI_MEMORY_PORT_IO
;
921 Entry
->Capabilities
= Capabilities
| EFI_MEMORY_RUNTIME
;
924 case GCD_ADD_IO_OPERATION
:
925 Entry
->GcdIoType
= GcdIoType
;
930 case GCD_FREE_MEMORY_OPERATION
:
931 case GCD_FREE_IO_OPERATION
:
932 Entry
->ImageHandle
= NULL
;
933 Entry
->DeviceHandle
= NULL
;
938 case GCD_REMOVE_MEMORY_OPERATION
:
939 Entry
->GcdMemoryType
= EfiGcdMemoryTypeNonExistent
;
940 Entry
->Capabilities
= 0;
942 case GCD_REMOVE_IO_OPERATION
:
943 Entry
->GcdIoType
= EfiGcdIoTypeNonExistent
;
946 // Set attributes operation
948 case GCD_SET_ATTRIBUTES_MEMORY_OPERATION
:
949 if (CpuArchAttributes
== 0) {
951 // Keep original CPU arch attributes when caller just calls
952 // SetMemorySpaceAttributes() with none CPU arch attributes (for example, RUNTIME).
954 Attributes
|= (Entry
->Attributes
& (EXCLUSIVE_MEMORY_ATTRIBUTES
| NONEXCLUSIVE_MEMORY_ATTRIBUTES
));
956 Entry
->Attributes
= Attributes
;
959 // Set capabilities operation
961 case GCD_SET_CAPABILITIES_MEMORY_OPERATION
:
962 Entry
->Capabilities
= Capabilities
;
965 Link
= Link
->ForwardLink
;
971 Status
= CoreCleanupGcdMapEntry (TopEntry
, BottomEntry
, StartLink
, EndLink
, Map
);
974 DEBUG ((DEBUG_GCD
, " Status = %r\n", Status
));
976 if ((Operation
& GCD_MEMORY_SPACE_OPERATION
) != 0) {
977 CoreReleaseGcdMemoryLock ();
978 CoreDumpGcdMemorySpaceMap (FALSE
);
980 if ((Operation
& GCD_IO_SPACE_OPERATION
) != 0) {
981 CoreReleaseGcdIoLock ();
982 CoreDumpGcdIoSpaceMap (FALSE
);
990 Check whether an entry could be used to allocate space.
992 @param Operation Allocate memory or IO
993 @param Entry The entry to be tested
994 @param GcdMemoryType The desired memory type
995 @param GcdIoType The desired IO type
997 @retval EFI_NOT_FOUND The memory type does not match or there's an
998 image handle on the entry.
999 @retval EFI_UNSUPPORTED The operation unsupported.
1000 @retval EFI_SUCCESS It's ok for this entry to be used to allocate
1005 CoreAllocateSpaceCheckEntry (
1007 IN EFI_GCD_MAP_ENTRY
*Entry
,
1008 IN EFI_GCD_MEMORY_TYPE GcdMemoryType
,
1009 IN EFI_GCD_IO_TYPE GcdIoType
1012 if (Entry
->ImageHandle
!= NULL
) {
1013 return EFI_NOT_FOUND
;
1015 switch (Operation
) {
1016 case GCD_ALLOCATE_MEMORY_OPERATION
:
1017 if (Entry
->GcdMemoryType
!= GcdMemoryType
) {
1018 return EFI_NOT_FOUND
;
1021 case GCD_ALLOCATE_IO_OPERATION
:
1022 if (Entry
->GcdIoType
!= GcdIoType
) {
1023 return EFI_NOT_FOUND
;
1027 return EFI_UNSUPPORTED
;
1034 Allocate space on specified address and length.
1036 @param Operation The type of operation (memory or IO)
1037 @param GcdAllocateType The type of allocate operation
1038 @param GcdMemoryType The desired memory type
1039 @param GcdIoType The desired IO type
1040 @param Alignment Align with 2^Alignment
1041 @param Length Length to allocate
1042 @param BaseAddress Base address to allocate
1043 @param ImageHandle The image handle consume the allocated space.
1044 @param DeviceHandle The device handle consume the allocated space.
1046 @retval EFI_INVALID_PARAMETER Invalid parameter.
1047 @retval EFI_NOT_FOUND No descriptor for the desired space exists.
1048 @retval EFI_SUCCESS Space successfully allocated.
1054 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType
,
1055 IN EFI_GCD_MEMORY_TYPE GcdMemoryType
,
1056 IN EFI_GCD_IO_TYPE GcdIoType
,
1059 IN OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
1060 IN EFI_HANDLE ImageHandle
,
1061 IN EFI_HANDLE DeviceHandle OPTIONAL
1065 EFI_PHYSICAL_ADDRESS AlignmentMask
;
1066 EFI_PHYSICAL_ADDRESS MaxAddress
;
1069 LIST_ENTRY
*SubLink
;
1070 EFI_GCD_MAP_ENTRY
*Entry
;
1071 EFI_GCD_MAP_ENTRY
*TopEntry
;
1072 EFI_GCD_MAP_ENTRY
*BottomEntry
;
1073 LIST_ENTRY
*StartLink
;
1074 LIST_ENTRY
*EndLink
;
1078 // Make sure parameters are valid
1080 if ((UINT32
)GcdAllocateType
>= EfiGcdMaxAllocateType
) {
1081 DEBUG ((DEBUG_GCD
, " Status = %r\n", EFI_INVALID_PARAMETER
));
1082 return EFI_INVALID_PARAMETER
;
1084 if ((UINT32
)GcdMemoryType
>= EfiGcdMemoryTypeMaximum
) {
1085 DEBUG ((DEBUG_GCD
, " Status = %r\n", EFI_INVALID_PARAMETER
));
1086 return EFI_INVALID_PARAMETER
;
1088 if ((UINT32
)GcdIoType
>= EfiGcdIoTypeMaximum
) {
1089 DEBUG ((DEBUG_GCD
, " Status = %r\n", EFI_INVALID_PARAMETER
));
1090 return EFI_INVALID_PARAMETER
;
1092 if (BaseAddress
== NULL
) {
1093 DEBUG ((DEBUG_GCD
, " Status = %r\n", EFI_INVALID_PARAMETER
));
1094 return EFI_INVALID_PARAMETER
;
1096 if (ImageHandle
== NULL
) {
1097 DEBUG ((DEBUG_GCD
, " Status = %r\n", EFI_INVALID_PARAMETER
));
1098 return EFI_INVALID_PARAMETER
;
1100 if (Alignment
>= 64) {
1101 DEBUG ((DEBUG_GCD
, " Status = %r\n", EFI_NOT_FOUND
));
1102 return EFI_NOT_FOUND
;
1105 DEBUG ((DEBUG_GCD
, " Status = %r\n", EFI_INVALID_PARAMETER
));
1106 return EFI_INVALID_PARAMETER
;
1110 if ((Operation
& GCD_MEMORY_SPACE_OPERATION
) != 0) {
1111 CoreAcquireGcdMemoryLock ();
1112 Map
= &mGcdMemorySpaceMap
;
1113 } else if ((Operation
& GCD_IO_SPACE_OPERATION
) != 0) {
1114 CoreAcquireGcdIoLock ();
1115 Map
= &mGcdIoSpaceMap
;
1124 // Compute alignment bit mask
1126 AlignmentMask
= LShiftU64 (1, Alignment
) - 1;
1128 if (GcdAllocateType
== EfiGcdAllocateAddress
) {
1130 // Verify that the BaseAddress passed in is aligned correctly
1132 if ((*BaseAddress
& AlignmentMask
) != 0) {
1133 Status
= EFI_NOT_FOUND
;
1138 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
1140 Status
= CoreSearchGcdMapEntry (*BaseAddress
, Length
, &StartLink
, &EndLink
, Map
);
1141 if (EFI_ERROR (Status
)) {
1142 Status
= EFI_NOT_FOUND
;
1145 ASSERT (StartLink
!= NULL
&& EndLink
!= NULL
);
1148 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1151 while (Link
!= EndLink
->ForwardLink
) {
1152 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1153 Link
= Link
->ForwardLink
;
1154 Status
= CoreAllocateSpaceCheckEntry (Operation
, Entry
, GcdMemoryType
, GcdIoType
);
1155 if (EFI_ERROR (Status
)) {
1162 Entry
= CR (Map
->BackLink
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1165 // Compute the maximum address to use in the search algorithm
1167 if (GcdAllocateType
== EfiGcdAllocateMaxAddressSearchBottomUp
||
1168 GcdAllocateType
== EfiGcdAllocateMaxAddressSearchTopDown
) {
1169 MaxAddress
= *BaseAddress
;
1171 MaxAddress
= Entry
->EndAddress
;
1175 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1177 if (GcdAllocateType
== EfiGcdAllocateMaxAddressSearchTopDown
||
1178 GcdAllocateType
== EfiGcdAllocateAnySearchTopDown
) {
1179 Link
= Map
->BackLink
;
1181 Link
= Map
->ForwardLink
;
1183 while (Link
!= Map
) {
1184 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1186 if (GcdAllocateType
== EfiGcdAllocateMaxAddressSearchTopDown
||
1187 GcdAllocateType
== EfiGcdAllocateAnySearchTopDown
) {
1188 Link
= Link
->BackLink
;
1190 Link
= Link
->ForwardLink
;
1193 Status
= CoreAllocateSpaceCheckEntry (Operation
, Entry
, GcdMemoryType
, GcdIoType
);
1194 if (EFI_ERROR (Status
)) {
1198 if (GcdAllocateType
== EfiGcdAllocateMaxAddressSearchTopDown
||
1199 GcdAllocateType
== EfiGcdAllocateAnySearchTopDown
) {
1200 if ((Entry
->BaseAddress
+ Length
) > MaxAddress
) {
1203 if (Length
> (Entry
->EndAddress
+ 1)) {
1204 Status
= EFI_NOT_FOUND
;
1207 if (Entry
->EndAddress
> MaxAddress
) {
1208 *BaseAddress
= MaxAddress
;
1210 *BaseAddress
= Entry
->EndAddress
;
1212 *BaseAddress
= (*BaseAddress
+ 1 - Length
) & (~AlignmentMask
);
1214 *BaseAddress
= (Entry
->BaseAddress
+ AlignmentMask
) & (~AlignmentMask
);
1215 if ((*BaseAddress
+ Length
- 1) > MaxAddress
) {
1216 Status
= EFI_NOT_FOUND
;
1222 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
1224 Status
= CoreSearchGcdMapEntry (*BaseAddress
, Length
, &StartLink
, &EndLink
, Map
);
1225 if (EFI_ERROR (Status
)) {
1226 Status
= EFI_NOT_FOUND
;
1229 ASSERT (StartLink
!= NULL
&& EndLink
!= NULL
);
1233 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1236 SubLink
= StartLink
;
1237 while (SubLink
!= EndLink
->ForwardLink
) {
1238 Entry
= CR (SubLink
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1239 Status
= CoreAllocateSpaceCheckEntry (Operation
, Entry
, GcdMemoryType
, GcdIoType
);
1240 if (EFI_ERROR (Status
)) {
1245 SubLink
= SubLink
->ForwardLink
;
1253 Status
= EFI_NOT_FOUND
;
1258 // Allocate work space to perform this operation
1260 Status
= CoreAllocateGcdMapEntry (&TopEntry
, &BottomEntry
);
1261 if (EFI_ERROR (Status
)) {
1262 Status
= EFI_OUT_OF_RESOURCES
;
1265 ASSERT (TopEntry
!= NULL
&& BottomEntry
!= NULL
);
1268 // Convert/Insert the list of descriptors from StartLink to EndLink
1271 while (Link
!= EndLink
->ForwardLink
) {
1272 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1273 CoreInsertGcdMapEntry (Link
, Entry
, *BaseAddress
, Length
, TopEntry
, BottomEntry
);
1274 Entry
->ImageHandle
= ImageHandle
;
1275 Entry
->DeviceHandle
= DeviceHandle
;
1276 Link
= Link
->ForwardLink
;
1282 Status
= CoreCleanupGcdMapEntry (TopEntry
, BottomEntry
, StartLink
, EndLink
, Map
);
1285 DEBUG ((DEBUG_GCD
, " Status = %r", Status
));
1286 if (!EFI_ERROR (Status
)) {
1287 DEBUG ((DEBUG_GCD
, " (BaseAddress = %016lx)", *BaseAddress
));
1289 DEBUG ((DEBUG_GCD
, "\n"));
1291 if ((Operation
& GCD_MEMORY_SPACE_OPERATION
) != 0) {
1292 CoreReleaseGcdMemoryLock ();
1293 CoreDumpGcdMemorySpaceMap (FALSE
);
1295 if ((Operation
& GCD_IO_SPACE_OPERATION
) !=0) {
1296 CoreReleaseGcdIoLock ();
1297 CoreDumpGcdIoSpaceMap (FALSE
);
1305 Add a segment of memory to GCD map.
1307 @param GcdMemoryType Memory type of the segment.
1308 @param BaseAddress Base address of the segment.
1309 @param Length Length of the segment.
1310 @param Capabilities alterable attributes of the segment.
1312 @retval EFI_INVALID_PARAMETER Invalid parameters.
1313 @retval EFI_SUCCESS Successfully add a segment of memory space.
1317 CoreInternalAddMemorySpace (
1318 IN EFI_GCD_MEMORY_TYPE GcdMemoryType
,
1319 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1321 IN UINT64 Capabilities
1324 DEBUG ((DEBUG_GCD
, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress
, Length
));
1325 DEBUG ((DEBUG_GCD
, " GcdMemoryType = %a\n", mGcdMemoryTypeNames
[MIN (GcdMemoryType
, EfiGcdMemoryTypeMaximum
)]));
1326 DEBUG ((DEBUG_GCD
, " Capabilities = %016lx\n", Capabilities
));
1329 // Make sure parameters are valid
1331 if (GcdMemoryType
<= EfiGcdMemoryTypeNonExistent
|| GcdMemoryType
>= EfiGcdMemoryTypeMaximum
) {
1332 return EFI_INVALID_PARAMETER
;
1335 return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION
, GcdMemoryType
, (EFI_GCD_IO_TYPE
) 0, BaseAddress
, Length
, Capabilities
, 0);
1339 // GCD Core Services
1343 Allocates nonexistent memory, reserved memory, system memory, or memorymapped
1344 I/O resources from the global coherency domain of the processor.
1346 @param GcdAllocateType The type of allocate operation
1347 @param GcdMemoryType The desired memory type
1348 @param Alignment Align with 2^Alignment
1349 @param Length Length to allocate
1350 @param BaseAddress Base address to allocate
1351 @param ImageHandle The image handle consume the allocated space.
1352 @param DeviceHandle The device handle consume the allocated space.
1354 @retval EFI_INVALID_PARAMETER Invalid parameter.
1355 @retval EFI_NOT_FOUND No descriptor contains the desired space.
1356 @retval EFI_SUCCESS Memory space successfully allocated.
1361 CoreAllocateMemorySpace (
1362 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType
,
1363 IN EFI_GCD_MEMORY_TYPE GcdMemoryType
,
1366 IN OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
1367 IN EFI_HANDLE ImageHandle
,
1368 IN EFI_HANDLE DeviceHandle OPTIONAL
1371 if (BaseAddress
!= NULL
) {
1372 DEBUG ((DEBUG_GCD
, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress
, Length
));
1374 DEBUG ((DEBUG_GCD
, "GCD:AllocateMemorySpace(Base=<NULL>,Length=%016lx)\n", Length
));
1376 DEBUG ((DEBUG_GCD
, " GcdAllocateType = %a\n", mGcdAllocationTypeNames
[MIN (GcdAllocateType
, EfiGcdMaxAllocateType
)]));
1377 DEBUG ((DEBUG_GCD
, " GcdMemoryType = %a\n", mGcdMemoryTypeNames
[MIN (GcdMemoryType
, EfiGcdMemoryTypeMaximum
)]));
1378 DEBUG ((DEBUG_GCD
, " Alignment = %016lx\n", LShiftU64 (1, Alignment
)));
1379 DEBUG ((DEBUG_GCD
, " ImageHandle = %p\n", ImageHandle
));
1380 DEBUG ((DEBUG_GCD
, " DeviceHandle = %p\n", DeviceHandle
));
1382 return CoreAllocateSpace (
1383 GCD_ALLOCATE_MEMORY_OPERATION
,
1386 (EFI_GCD_IO_TYPE
) 0,
1397 Adds reserved memory, system memory, or memory-mapped I/O resources to the
1398 global coherency domain of the processor.
1400 @param GcdMemoryType Memory type of the memory space.
1401 @param BaseAddress Base address of the memory space.
1402 @param Length Length of the memory space.
1403 @param Capabilities alterable attributes of the memory space.
1405 @retval EFI_SUCCESS Merged this memory space into GCD map.
1410 CoreAddMemorySpace (
1411 IN EFI_GCD_MEMORY_TYPE GcdMemoryType
,
1412 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1414 IN UINT64 Capabilities
1418 EFI_PHYSICAL_ADDRESS PageBaseAddress
;
1421 Status
= CoreInternalAddMemorySpace (GcdMemoryType
, BaseAddress
, Length
, Capabilities
);
1423 if (!EFI_ERROR (Status
) && ((GcdMemoryType
== EfiGcdMemoryTypeSystemMemory
) || (GcdMemoryType
== EfiGcdMemoryTypeMoreReliable
))) {
1425 PageBaseAddress
= PageAlignAddress (BaseAddress
);
1426 PageLength
= PageAlignLength (BaseAddress
+ Length
- PageBaseAddress
);
1428 Status
= CoreAllocateMemorySpace (
1429 EfiGcdAllocateAddress
,
1434 gDxeCoreImageHandle
,
1438 if (!EFI_ERROR (Status
)) {
1439 CoreAddMemoryDescriptor (
1440 EfiConventionalMemory
,
1442 RShiftU64 (PageLength
, EFI_PAGE_SHIFT
),
1446 for (; PageLength
!= 0; PageLength
-= EFI_PAGE_SIZE
, PageBaseAddress
+= EFI_PAGE_SIZE
) {
1447 Status
= CoreAllocateMemorySpace (
1448 EfiGcdAllocateAddress
,
1453 gDxeCoreImageHandle
,
1457 if (!EFI_ERROR (Status
)) {
1458 CoreAddMemoryDescriptor (
1459 EfiConventionalMemory
,
1473 Frees nonexistent memory, reserved memory, system memory, or memory-mapped
1474 I/O resources from the global coherency domain of the processor.
1476 @param BaseAddress Base address of the memory space.
1477 @param Length Length of the memory space.
1479 @retval EFI_SUCCESS Space successfully freed.
1484 CoreFreeMemorySpace (
1485 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1489 DEBUG ((DEBUG_GCD
, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress
, Length
));
1491 return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION
, (EFI_GCD_MEMORY_TYPE
) 0, (EFI_GCD_IO_TYPE
) 0, BaseAddress
, Length
, 0, 0);
1496 Removes reserved memory, system memory, or memory-mapped I/O resources from
1497 the global coherency domain of the processor.
1499 @param BaseAddress Base address of the memory space.
1500 @param Length Length of the memory space.
1502 @retval EFI_SUCCESS Successfully remove a segment of memory space.
1507 CoreRemoveMemorySpace (
1508 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1512 DEBUG ((DEBUG_GCD
, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress
, Length
));
1514 return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION
, (EFI_GCD_MEMORY_TYPE
) 0, (EFI_GCD_IO_TYPE
) 0, BaseAddress
, Length
, 0, 0);
1519 Build a memory descriptor according to an entry.
1521 @param Descriptor The descriptor to be built
1522 @param Entry According to this entry
1526 BuildMemoryDescriptor (
1527 IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Descriptor
,
1528 IN EFI_GCD_MAP_ENTRY
*Entry
1531 Descriptor
->BaseAddress
= Entry
->BaseAddress
;
1532 Descriptor
->Length
= Entry
->EndAddress
- Entry
->BaseAddress
+ 1;
1533 Descriptor
->Capabilities
= Entry
->Capabilities
;
1534 Descriptor
->Attributes
= Entry
->Attributes
;
1535 Descriptor
->GcdMemoryType
= Entry
->GcdMemoryType
;
1536 Descriptor
->ImageHandle
= Entry
->ImageHandle
;
1537 Descriptor
->DeviceHandle
= Entry
->DeviceHandle
;
1542 Retrieves the descriptor for a memory region containing a specified address.
1544 @param BaseAddress Specified start address
1545 @param Descriptor Specified length
1547 @retval EFI_INVALID_PARAMETER Invalid parameter
1548 @retval EFI_SUCCESS Successfully get memory space descriptor.
1553 CoreGetMemorySpaceDescriptor (
1554 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1555 OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Descriptor
1559 LIST_ENTRY
*StartLink
;
1560 LIST_ENTRY
*EndLink
;
1561 EFI_GCD_MAP_ENTRY
*Entry
;
1564 // Make sure parameters are valid
1566 if (Descriptor
== NULL
) {
1567 return EFI_INVALID_PARAMETER
;
1570 CoreAcquireGcdMemoryLock ();
1573 // Search for the list of descriptors that contain BaseAddress
1575 Status
= CoreSearchGcdMapEntry (BaseAddress
, 1, &StartLink
, &EndLink
, &mGcdMemorySpaceMap
);
1576 if (EFI_ERROR (Status
)) {
1577 Status
= EFI_NOT_FOUND
;
1579 ASSERT (StartLink
!= NULL
&& EndLink
!= NULL
);
1581 // Copy the contents of the found descriptor into Descriptor
1583 Entry
= CR (StartLink
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1584 BuildMemoryDescriptor (Descriptor
, Entry
);
1587 CoreReleaseGcdMemoryLock ();
1594 Modifies the attributes for a memory region in the global coherency domain of the
1597 @param BaseAddress Specified start address
1598 @param Length Specified length
1599 @param Attributes Specified attributes
1601 @retval EFI_SUCCESS The attributes were set for the memory region.
1602 @retval EFI_INVALID_PARAMETER Length is zero.
1603 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
1604 resource range specified by BaseAddress and Length.
1605 @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
1606 range specified by BaseAddress and Length.
1607 @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
1608 BaseAddress and Length cannot be modified.
1609 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
1610 the memory resource range.
1611 @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
1617 CoreSetMemorySpaceAttributes (
1618 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1620 IN UINT64 Attributes
1623 DEBUG ((DEBUG_GCD
, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress
, Length
));
1624 DEBUG ((DEBUG_GCD
, " Attributes = %016lx\n", Attributes
));
1626 return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION
, (EFI_GCD_MEMORY_TYPE
) 0, (EFI_GCD_IO_TYPE
) 0, BaseAddress
, Length
, 0, Attributes
);
1631 Modifies the capabilities for a memory region in the global coherency domain of the
1634 @param BaseAddress The physical address that is the start address of a memory region.
1635 @param Length The size in bytes of the memory region.
1636 @param Capabilities The bit mask of capabilities that the memory region supports.
1638 @retval EFI_SUCCESS The capabilities were set for the memory region.
1639 @retval EFI_INVALID_PARAMETER Length is zero.
1640 @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
1641 memory region attributes currently in use.
1642 @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
1643 BaseAddress and Length cannot be modified.
1644 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
1645 of the memory resource range.
1649 CoreSetMemorySpaceCapabilities (
1650 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1652 IN UINT64 Capabilities
1657 DEBUG ((DEBUG_GCD
, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress
, Length
));
1658 DEBUG ((DEBUG_GCD
, " Capabilities = %016lx\n", Capabilities
));
1660 Status
= CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION
, (EFI_GCD_MEMORY_TYPE
) 0, (EFI_GCD_IO_TYPE
) 0, BaseAddress
, Length
, Capabilities
, 0);
1661 if (!EFI_ERROR(Status
)) {
1662 CoreUpdateMemoryAttributes(BaseAddress
, RShiftU64(Length
, EFI_PAGE_SHIFT
), Capabilities
& (~EFI_MEMORY_RUNTIME
));
1670 Returns a map of the memory resources in the global coherency domain of the
1673 @param NumberOfDescriptors Number of descriptors.
1674 @param MemorySpaceMap Descriptor array
1676 @retval EFI_INVALID_PARAMETER Invalid parameter
1677 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1678 @retval EFI_SUCCESS Successfully get memory space map.
1683 CoreGetMemorySpaceMap (
1684 OUT UINTN
*NumberOfDescriptors
,
1685 OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR
**MemorySpaceMap
1689 EFI_GCD_MAP_ENTRY
*Entry
;
1690 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Descriptor
;
1691 UINTN DescriptorCount
;
1694 // Make sure parameters are valid
1696 if (NumberOfDescriptors
== NULL
) {
1697 return EFI_INVALID_PARAMETER
;
1699 if (MemorySpaceMap
== NULL
) {
1700 return EFI_INVALID_PARAMETER
;
1703 *NumberOfDescriptors
= 0;
1704 *MemorySpaceMap
= NULL
;
1707 // Take the lock, for entering the loop with the lock held.
1709 CoreAcquireGcdMemoryLock ();
1712 // Count descriptors. It might be done more than once because the
1713 // AllocatePool() called below has to be running outside the GCD lock.
1715 DescriptorCount
= CoreCountGcdMapEntry (&mGcdMemorySpaceMap
);
1716 if (DescriptorCount
== *NumberOfDescriptors
&& *MemorySpaceMap
!= NULL
) {
1718 // Fill in the MemorySpaceMap if no memory space map change.
1720 Descriptor
= *MemorySpaceMap
;
1721 Link
= mGcdMemorySpaceMap
.ForwardLink
;
1722 while (Link
!= &mGcdMemorySpaceMap
) {
1723 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1724 BuildMemoryDescriptor (Descriptor
, Entry
);
1726 Link
= Link
->ForwardLink
;
1729 // We're done; exit the loop with the lock held.
1735 // Release the lock before memory allocation, because it might cause
1736 // GCD lock conflict in one of calling path in AllocatPool().
1738 CoreReleaseGcdMemoryLock ();
1741 // Allocate memory to store the MemorySpaceMap. Note it might be already
1742 // allocated if there's map descriptor change during memory allocation at
1745 if (*MemorySpaceMap
!= NULL
) {
1746 FreePool (*MemorySpaceMap
);
1749 *MemorySpaceMap
= AllocatePool (DescriptorCount
*
1750 sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR
));
1751 if (*MemorySpaceMap
== NULL
) {
1752 *NumberOfDescriptors
= 0;
1753 return EFI_OUT_OF_RESOURCES
;
1757 // Save the descriptor count got before for another round of check to make
1758 // sure we won't miss any, since we have code running outside the GCD lock.
1760 *NumberOfDescriptors
= DescriptorCount
;
1762 // Re-acquire the lock, for the next iteration.
1764 CoreAcquireGcdMemoryLock ();
1767 // We exited the loop with the lock held, release it.
1769 CoreReleaseGcdMemoryLock ();
1776 Adds reserved I/O or I/O resources to the global coherency domain of the processor.
1778 @param GcdIoType IO type of the segment.
1779 @param BaseAddress Base address of the segment.
1780 @param Length Length of the segment.
1782 @retval EFI_SUCCESS Merged this segment into GCD map.
1783 @retval EFI_INVALID_PARAMETER Parameter not valid
1789 IN EFI_GCD_IO_TYPE GcdIoType
,
1790 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1794 DEBUG ((DEBUG_GCD
, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress
, Length
));
1795 DEBUG ((DEBUG_GCD
, " GcdIoType = %a\n", mGcdIoTypeNames
[MIN (GcdIoType
, EfiGcdIoTypeMaximum
)]));
1798 // Make sure parameters are valid
1800 if (GcdIoType
<= EfiGcdIoTypeNonExistent
|| GcdIoType
>= EfiGcdIoTypeMaximum
) {
1801 return EFI_INVALID_PARAMETER
;
1803 return CoreConvertSpace (GCD_ADD_IO_OPERATION
, (EFI_GCD_MEMORY_TYPE
) 0, GcdIoType
, BaseAddress
, Length
, 0, 0);
1808 Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
1809 domain of the processor.
1811 @param GcdAllocateType The type of allocate operation
1812 @param GcdIoType The desired IO type
1813 @param Alignment Align with 2^Alignment
1814 @param Length Length to allocate
1815 @param BaseAddress Base address to allocate
1816 @param ImageHandle The image handle consume the allocated space.
1817 @param DeviceHandle The device handle consume the allocated space.
1819 @retval EFI_INVALID_PARAMETER Invalid parameter.
1820 @retval EFI_NOT_FOUND No descriptor contains the desired space.
1821 @retval EFI_SUCCESS IO space successfully allocated.
1826 CoreAllocateIoSpace (
1827 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType
,
1828 IN EFI_GCD_IO_TYPE GcdIoType
,
1831 IN OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
1832 IN EFI_HANDLE ImageHandle
,
1833 IN EFI_HANDLE DeviceHandle OPTIONAL
1836 if (BaseAddress
!= NULL
) {
1837 DEBUG ((DEBUG_GCD
, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress
, Length
));
1839 DEBUG ((DEBUG_GCD
, "GCD:AllocateIoSpace(Base=<NULL>,Length=%016lx)\n", Length
));
1841 DEBUG ((DEBUG_GCD
, " GcdAllocateType = %a\n", mGcdAllocationTypeNames
[MIN (GcdAllocateType
, EfiGcdMaxAllocateType
)]));
1842 DEBUG ((DEBUG_GCD
, " GcdIoType = %a\n", mGcdIoTypeNames
[MIN (GcdIoType
, EfiGcdIoTypeMaximum
)]));
1843 DEBUG ((DEBUG_GCD
, " Alignment = %016lx\n", LShiftU64 (1, Alignment
)));
1844 DEBUG ((DEBUG_GCD
, " ImageHandle = %p\n", ImageHandle
));
1845 DEBUG ((DEBUG_GCD
, " DeviceHandle = %p\n", DeviceHandle
));
1847 return CoreAllocateSpace (
1848 GCD_ALLOCATE_IO_OPERATION
,
1850 (EFI_GCD_MEMORY_TYPE
) 0,
1862 Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
1863 domain of the processor.
1865 @param BaseAddress Base address of the segment.
1866 @param Length Length of the segment.
1868 @retval EFI_SUCCESS Space successfully freed.
1874 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1878 DEBUG ((DEBUG_GCD
, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress
, Length
));
1880 return CoreConvertSpace (GCD_FREE_IO_OPERATION
, (EFI_GCD_MEMORY_TYPE
) 0, (EFI_GCD_IO_TYPE
) 0, BaseAddress
, Length
, 0, 0);
1885 Removes reserved I/O or I/O resources from the global coherency domain of the
1888 @param BaseAddress Base address of the segment.
1889 @param Length Length of the segment.
1891 @retval EFI_SUCCESS Successfully removed a segment of IO space.
1897 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1901 DEBUG ((DEBUG_GCD
, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress
, Length
));
1903 return CoreConvertSpace (GCD_REMOVE_IO_OPERATION
, (EFI_GCD_MEMORY_TYPE
) 0, (EFI_GCD_IO_TYPE
) 0, BaseAddress
, Length
, 0, 0);
1908 Build a IO descriptor according to an entry.
1910 @param Descriptor The descriptor to be built
1911 @param Entry According to this entry
1916 IN EFI_GCD_IO_SPACE_DESCRIPTOR
*Descriptor
,
1917 IN EFI_GCD_MAP_ENTRY
*Entry
1920 Descriptor
->BaseAddress
= Entry
->BaseAddress
;
1921 Descriptor
->Length
= Entry
->EndAddress
- Entry
->BaseAddress
+ 1;
1922 Descriptor
->GcdIoType
= Entry
->GcdIoType
;
1923 Descriptor
->ImageHandle
= Entry
->ImageHandle
;
1924 Descriptor
->DeviceHandle
= Entry
->DeviceHandle
;
1929 Retrieves the descriptor for an I/O region containing a specified address.
1931 @param BaseAddress Specified start address
1932 @param Descriptor Specified length
1934 @retval EFI_INVALID_PARAMETER Descriptor is NULL.
1935 @retval EFI_SUCCESS Successfully get the IO space descriptor.
1940 CoreGetIoSpaceDescriptor (
1941 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1942 OUT EFI_GCD_IO_SPACE_DESCRIPTOR
*Descriptor
1946 LIST_ENTRY
*StartLink
;
1947 LIST_ENTRY
*EndLink
;
1948 EFI_GCD_MAP_ENTRY
*Entry
;
1951 // Make sure parameters are valid
1953 if (Descriptor
== NULL
) {
1954 return EFI_INVALID_PARAMETER
;
1957 CoreAcquireGcdIoLock ();
1960 // Search for the list of descriptors that contain BaseAddress
1962 Status
= CoreSearchGcdMapEntry (BaseAddress
, 1, &StartLink
, &EndLink
, &mGcdIoSpaceMap
);
1963 if (EFI_ERROR (Status
)) {
1964 Status
= EFI_NOT_FOUND
;
1966 ASSERT (StartLink
!= NULL
&& EndLink
!= NULL
);
1968 // Copy the contents of the found descriptor into Descriptor
1970 Entry
= CR (StartLink
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
1971 BuildIoDescriptor (Descriptor
, Entry
);
1974 CoreReleaseGcdIoLock ();
1981 Returns a map of the I/O resources in the global coherency domain of the processor.
1983 @param NumberOfDescriptors Number of descriptors.
1984 @param IoSpaceMap Descriptor array
1986 @retval EFI_INVALID_PARAMETER Invalid parameter
1987 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1988 @retval EFI_SUCCESS Successfully get IO space map.
1994 OUT UINTN
*NumberOfDescriptors
,
1995 OUT EFI_GCD_IO_SPACE_DESCRIPTOR
**IoSpaceMap
2000 EFI_GCD_MAP_ENTRY
*Entry
;
2001 EFI_GCD_IO_SPACE_DESCRIPTOR
*Descriptor
;
2004 // Make sure parameters are valid
2006 if (NumberOfDescriptors
== NULL
) {
2007 return EFI_INVALID_PARAMETER
;
2009 if (IoSpaceMap
== NULL
) {
2010 return EFI_INVALID_PARAMETER
;
2013 CoreAcquireGcdIoLock ();
2016 // Count the number of descriptors
2018 *NumberOfDescriptors
= CoreCountGcdMapEntry (&mGcdIoSpaceMap
);
2021 // Allocate the IoSpaceMap
2023 *IoSpaceMap
= AllocatePool (*NumberOfDescriptors
* sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR
));
2024 if (*IoSpaceMap
== NULL
) {
2025 Status
= EFI_OUT_OF_RESOURCES
;
2030 // Fill in the IoSpaceMap
2032 Descriptor
= *IoSpaceMap
;
2033 Link
= mGcdIoSpaceMap
.ForwardLink
;
2034 while (Link
!= &mGcdIoSpaceMap
) {
2035 Entry
= CR (Link
, EFI_GCD_MAP_ENTRY
, Link
, EFI_GCD_MAP_SIGNATURE
);
2036 BuildIoDescriptor (Descriptor
, Entry
);
2038 Link
= Link
->ForwardLink
;
2040 Status
= EFI_SUCCESS
;
2043 CoreReleaseGcdIoLock ();
2049 Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
2052 @param GcdMemoryType Type of resource in the GCD memory map.
2053 @param Attributes The attribute mask in the Resource Descriptor
2056 @return The capabilities mask for an EFI Memory Descriptor.
2060 CoreConvertResourceDescriptorHobAttributesToCapabilities (
2061 EFI_GCD_MEMORY_TYPE GcdMemoryType
,
2065 UINT64 Capabilities
;
2066 GCD_ATTRIBUTE_CONVERSION_ENTRY
*Conversion
;
2069 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2071 for (Capabilities
= 0, Conversion
= mAttributeConversionTable
; Conversion
->Attribute
!= 0; Conversion
++) {
2072 if (Conversion
->Memory
|| ((GcdMemoryType
!= EfiGcdMemoryTypeSystemMemory
) && (GcdMemoryType
!= EfiGcdMemoryTypeMoreReliable
))) {
2073 if (Attributes
& Conversion
->Attribute
) {
2074 Capabilities
|= Conversion
->Capability
;
2079 return Capabilities
;
2083 Calculate total memory bin size neeeded.
2085 @return The total memory bin size neeeded.
2089 CalculateTotalMemoryBinSizeNeeded (
2097 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
2100 for (Index
= 0; gMemoryTypeInformation
[Index
].Type
!= EfiMaxMemoryType
; Index
++) {
2101 TotalSize
+= LShiftU64 (gMemoryTypeInformation
[Index
].NumberOfPages
, EFI_PAGE_SHIFT
);
2108 External function. Initializes memory services based on the memory
2109 descriptor HOBs. This function is responsible for priming the memory
2110 map, so memory allocations and resource allocations can be made.
2111 The first part of this function can not depend on any memory services
2112 until at least one memory descriptor is provided to the memory services.
2114 @param HobStart The start address of the HOB.
2115 @param MemoryBaseAddress Start address of memory region found to init DXE
2117 @param MemoryLength Length of memory region found to init DXE core.
2119 @retval EFI_SUCCESS Memory services successfully initialized.
2123 CoreInitializeMemoryServices (
2125 OUT EFI_PHYSICAL_ADDRESS
*MemoryBaseAddress
,
2126 OUT UINT64
*MemoryLength
2129 EFI_PEI_HOB_POINTERS Hob
;
2130 EFI_MEMORY_TYPE_INFORMATION
*EfiMemoryTypeInformation
;
2133 EFI_HOB_HANDOFF_INFO_TABLE
*PhitHob
;
2134 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
2135 EFI_HOB_RESOURCE_DESCRIPTOR
*PhitResourceHob
;
2136 EFI_PHYSICAL_ADDRESS BaseAddress
;
2139 UINT64 Capabilities
;
2140 EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress
;
2141 UINT64 TestedMemoryLength
;
2142 EFI_PHYSICAL_ADDRESS HighAddress
;
2143 EFI_HOB_GUID_TYPE
*GuidHob
;
2144 UINT32 ReservedCodePageNumber
;
2145 UINT64 MinimalMemorySizeNeeded
;
2148 // Point at the first HOB. This must be the PHIT HOB.
2150 Hob
.Raw
= *HobStart
;
2151 ASSERT (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_HANDOFF
);
2154 // Initialize the spin locks and maps in the memory services.
2155 // Also fill in the memory services into the EFI Boot Services Table
2157 CoreInitializePool ();
2160 // Initialize Local Variables
2162 PhitResourceHob
= NULL
;
2169 // Cache the PHIT HOB for later use
2171 PhitHob
= Hob
.HandoffInformationTable
;
2173 if (PcdGet64(PcdLoadModuleAtFixAddressEnable
) != 0) {
2174 ReservedCodePageNumber
= PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber
);
2175 ReservedCodePageNumber
+= PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber
);
2178 // cache the Top address for loading modules at Fixed Address
2180 gLoadModuleAtFixAddressConfigurationTable
.DxeCodeTopAddress
= PhitHob
->EfiMemoryTop
2181 + EFI_PAGES_TO_SIZE(ReservedCodePageNumber
);
2184 // See if a Memory Type Information HOB is available
2186 GuidHob
= GetFirstGuidHob (&gEfiMemoryTypeInformationGuid
);
2187 if (GuidHob
!= NULL
) {
2188 EfiMemoryTypeInformation
= GET_GUID_HOB_DATA (GuidHob
);
2189 DataSize
= GET_GUID_HOB_DATA_SIZE (GuidHob
);
2190 if (EfiMemoryTypeInformation
!= NULL
&& DataSize
> 0 && DataSize
<= (EfiMaxMemoryType
+ 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION
)) {
2191 CopyMem (&gMemoryTypeInformation
, EfiMemoryTypeInformation
, DataSize
);
2196 // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
2198 MinimalMemorySizeNeeded
= MINIMUM_INITIAL_MEMORY_SIZE
+ CalculateTotalMemoryBinSizeNeeded ();
2201 // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
2204 for (Hob
.Raw
= *HobStart
; !END_OF_HOB_LIST(Hob
); Hob
.Raw
= GET_NEXT_HOB(Hob
)) {
2206 // Skip all HOBs except Resource Descriptor HOBs
2208 if (GET_HOB_TYPE (Hob
) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
2213 // Skip Resource Descriptor HOBs that do not describe tested system memory
2215 ResourceHob
= Hob
.ResourceDescriptor
;
2216 if (ResourceHob
->ResourceType
!= EFI_RESOURCE_SYSTEM_MEMORY
) {
2219 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) != TESTED_MEMORY_ATTRIBUTES
) {
2224 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
2226 if (PhitHob
->EfiFreeMemoryBottom
< ResourceHob
->PhysicalStart
) {
2229 if (PhitHob
->EfiFreeMemoryTop
> (ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
)) {
2234 // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
2236 PhitResourceHob
= ResourceHob
;
2240 // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB
2242 Attributes
= PhitResourceHob
->ResourceAttribute
;
2243 BaseAddress
= PageAlignAddress (PhitHob
->EfiMemoryTop
);
2244 Length
= PageAlignLength (ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
- BaseAddress
);
2245 if (Length
< MinimalMemorySizeNeeded
) {
2247 // If that range is not large enough to intialize the DXE Core, then
2248 // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop
2250 BaseAddress
= PageAlignAddress (PhitHob
->EfiFreeMemoryBottom
);
2251 Length
= PageAlignLength (PhitHob
->EfiFreeMemoryTop
- BaseAddress
);
2252 if (Length
< MinimalMemorySizeNeeded
) {
2254 // If that range is not large enough to intialize the DXE Core, then
2255 // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List
2257 BaseAddress
= PageAlignAddress (ResourceHob
->PhysicalStart
);
2258 Length
= PageAlignLength ((UINT64
)((UINTN
)*HobStart
- BaseAddress
));
2265 // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
2270 // Take the range in the resource descriptor HOB for the memory region described
2271 // by the PHIT as higher priority if it is big enough. It can make the memory bin
2272 // allocated to be at the same memory region with PHIT that has more better compatibility
2273 // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.
2275 if (Length
< MinimalMemorySizeNeeded
) {
2277 // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
2278 // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB.
2279 // The max address must be within the physically addressible range for the processor.
2281 HighAddress
= MAX_ALLOC_ADDRESS
;
2282 for (Hob
.Raw
= *HobStart
; !END_OF_HOB_LIST(Hob
); Hob
.Raw
= GET_NEXT_HOB(Hob
)) {
2284 // Skip the Resource Descriptor HOB that contains the PHIT
2286 if (Hob
.ResourceDescriptor
== PhitResourceHob
) {
2290 // Skip all HOBs except Resource Descriptor HOBs
2292 if (GET_HOB_TYPE (Hob
) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
2297 // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ALLOC_ADDRESS
2299 ResourceHob
= Hob
.ResourceDescriptor
;
2300 if (ResourceHob
->ResourceType
!= EFI_RESOURCE_SYSTEM_MEMORY
) {
2303 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) != TESTED_MEMORY_ATTRIBUTES
) {
2306 if ((ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
) > (EFI_PHYSICAL_ADDRESS
)MAX_ALLOC_ADDRESS
) {
2311 // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB
2313 if (HighAddress
!= (EFI_PHYSICAL_ADDRESS
)MAX_ALLOC_ADDRESS
&& ResourceHob
->PhysicalStart
<= HighAddress
) {
2318 // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core
2320 TestedMemoryBaseAddress
= PageAlignAddress (ResourceHob
->PhysicalStart
);
2321 TestedMemoryLength
= PageAlignLength (ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
- TestedMemoryBaseAddress
);
2322 if (TestedMemoryLength
< MinimalMemorySizeNeeded
) {
2327 // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core
2329 BaseAddress
= TestedMemoryBaseAddress
;
2330 Length
= TestedMemoryLength
;
2331 Attributes
= ResourceHob
->ResourceAttribute
;
2332 HighAddress
= ResourceHob
->PhysicalStart
;
2336 DEBUG ((EFI_D_INFO
, "CoreInitializeMemoryServices:\n"));
2337 DEBUG ((EFI_D_INFO
, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress
, Length
, MinimalMemorySizeNeeded
));
2340 // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
2342 ASSERT (Length
>= MinimalMemorySizeNeeded
);
2345 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2347 if ((Attributes
& EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE
) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE
) {
2348 Capabilities
= CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable
, Attributes
);
2350 Capabilities
= CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory
, Attributes
);
2354 // Declare the very first memory region, so the EFI Memory Services are available.
2356 CoreAddMemoryDescriptor (
2357 EfiConventionalMemory
,
2359 RShiftU64 (Length
, EFI_PAGE_SHIFT
),
2363 *MemoryBaseAddress
= BaseAddress
;
2364 *MemoryLength
= Length
;
2371 External function. Initializes the GCD and memory services based on the memory
2372 descriptor HOBs. This function is responsible for priming the GCD map and the
2373 memory map, so memory allocations and resource allocations can be made. The
2374 HobStart will be relocated to a pool buffer.
2376 @param HobStart The start address of the HOB
2377 @param MemoryBaseAddress Start address of memory region found to init DXE
2379 @param MemoryLength Length of memory region found to init DXE core.
2381 @retval EFI_SUCCESS GCD services successfully initialized.
2385 CoreInitializeGcdServices (
2386 IN OUT VOID
**HobStart
,
2387 IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress
,
2388 IN UINT64 MemoryLength
2391 EFI_PEI_HOB_POINTERS Hob
;
2393 EFI_HOB_HANDOFF_INFO_TABLE
*PhitHob
;
2394 UINT8 SizeOfMemorySpace
;
2395 UINT8 SizeOfIoSpace
;
2396 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
2397 EFI_PHYSICAL_ADDRESS BaseAddress
;
2400 EFI_GCD_MAP_ENTRY
*Entry
;
2401 EFI_GCD_MEMORY_TYPE GcdMemoryType
;
2402 EFI_GCD_IO_TYPE GcdIoType
;
2403 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
2404 EFI_HOB_MEMORY_ALLOCATION
*MemoryHob
;
2405 EFI_HOB_FIRMWARE_VOLUME
*FirmwareVolumeHob
;
2406 UINTN NumberOfDescriptors
;
2407 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
;
2409 UINT64 Capabilities
;
2410 EFI_HOB_CPU
* CpuHob
;
2411 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMapHobList
;
2414 // Cache the PHIT HOB for later use
2416 PhitHob
= (EFI_HOB_HANDOFF_INFO_TABLE
*)(*HobStart
);
2419 // Get the number of address lines in the I/O and Memory space for the CPU
2421 CpuHob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
2422 ASSERT (CpuHob
!= NULL
);
2423 SizeOfMemorySpace
= CpuHob
->SizeOfMemorySpace
;
2424 SizeOfIoSpace
= CpuHob
->SizeOfIoSpace
;
2427 // Initialize the GCD Memory Space Map
2429 Entry
= AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY
), &mGcdMemorySpaceMapEntryTemplate
);
2430 ASSERT (Entry
!= NULL
);
2432 Entry
->EndAddress
= LShiftU64 (1, SizeOfMemorySpace
) - 1;
2434 InsertHeadList (&mGcdMemorySpaceMap
, &Entry
->Link
);
2436 CoreDumpGcdMemorySpaceMap (TRUE
);
2439 // Initialize the GCD I/O Space Map
2441 Entry
= AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY
), &mGcdIoSpaceMapEntryTemplate
);
2442 ASSERT (Entry
!= NULL
);
2444 Entry
->EndAddress
= LShiftU64 (1, SizeOfIoSpace
) - 1;
2446 InsertHeadList (&mGcdIoSpaceMap
, &Entry
->Link
);
2448 CoreDumpGcdIoSpaceMap (TRUE
);
2451 // Walk the HOB list and add all resource descriptors to the GCD
2453 for (Hob
.Raw
= *HobStart
; !END_OF_HOB_LIST(Hob
); Hob
.Raw
= GET_NEXT_HOB(Hob
)) {
2455 GcdMemoryType
= EfiGcdMemoryTypeNonExistent
;
2456 GcdIoType
= EfiGcdIoTypeNonExistent
;
2458 if (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
2460 ResourceHob
= Hob
.ResourceDescriptor
;
2462 switch (ResourceHob
->ResourceType
) {
2463 case EFI_RESOURCE_SYSTEM_MEMORY
:
2464 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == TESTED_MEMORY_ATTRIBUTES
) {
2465 if ((ResourceHob
->ResourceAttribute
& EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE
) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE
) {
2466 GcdMemoryType
= EfiGcdMemoryTypeMoreReliable
;
2468 GcdMemoryType
= EfiGcdMemoryTypeSystemMemory
;
2471 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == INITIALIZED_MEMORY_ATTRIBUTES
) {
2472 GcdMemoryType
= EfiGcdMemoryTypeReserved
;
2474 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) == PRESENT_MEMORY_ATTRIBUTES
) {
2475 GcdMemoryType
= EfiGcdMemoryTypeReserved
;
2477 if ((ResourceHob
->ResourceAttribute
& EFI_RESOURCE_ATTRIBUTE_PERSISTENT
) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT
) {
2478 GcdMemoryType
= EfiGcdMemoryTypePersistent
;
2481 case EFI_RESOURCE_MEMORY_MAPPED_IO
:
2482 case EFI_RESOURCE_FIRMWARE_DEVICE
:
2483 GcdMemoryType
= EfiGcdMemoryTypeMemoryMappedIo
;
2485 case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT
:
2486 case EFI_RESOURCE_MEMORY_RESERVED
:
2487 GcdMemoryType
= EfiGcdMemoryTypeReserved
;
2489 case EFI_RESOURCE_IO
:
2490 GcdIoType
= EfiGcdIoTypeIo
;
2492 case EFI_RESOURCE_IO_RESERVED
:
2493 GcdIoType
= EfiGcdIoTypeReserved
;
2497 if (GcdMemoryType
!= EfiGcdMemoryTypeNonExistent
) {
2499 // Validate the Resource HOB Attributes
2501 CoreValidateResourceDescriptorHobAttributes (ResourceHob
->ResourceAttribute
);
2504 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2506 Capabilities
= CoreConvertResourceDescriptorHobAttributesToCapabilities (
2508 ResourceHob
->ResourceAttribute
2511 Status
= CoreInternalAddMemorySpace (
2513 ResourceHob
->PhysicalStart
,
2514 ResourceHob
->ResourceLength
,
2519 if (GcdIoType
!= EfiGcdIoTypeNonExistent
) {
2520 Status
= CoreAddIoSpace (
2522 ResourceHob
->PhysicalStart
,
2523 ResourceHob
->ResourceLength
2530 // Allocate first memory region from the GCD by the DXE core
2532 Status
= CoreGetMemorySpaceDescriptor (MemoryBaseAddress
, &Descriptor
);
2533 if (!EFI_ERROR (Status
)) {
2534 ASSERT ((Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeSystemMemory
) ||
2535 (Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeMoreReliable
));
2536 Status
= CoreAllocateMemorySpace (
2537 EfiGcdAllocateAddress
,
2538 Descriptor
.GcdMemoryType
,
2542 gDxeCoreImageHandle
,
2548 // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
2549 // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs.
2551 for (Hob
.Raw
= *HobStart
; !END_OF_HOB_LIST(Hob
); Hob
.Raw
= GET_NEXT_HOB(Hob
)) {
2552 if (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
2553 MemoryHob
= Hob
.MemoryAllocation
;
2554 BaseAddress
= MemoryHob
->AllocDescriptor
.MemoryBaseAddress
;
2555 Status
= CoreGetMemorySpaceDescriptor (BaseAddress
, &Descriptor
);
2556 if (!EFI_ERROR (Status
)) {
2557 Status
= CoreAllocateMemorySpace (
2558 EfiGcdAllocateAddress
,
2559 Descriptor
.GcdMemoryType
,
2561 MemoryHob
->AllocDescriptor
.MemoryLength
,
2563 gDxeCoreImageHandle
,
2566 if (!EFI_ERROR (Status
) &&
2567 ((Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeSystemMemory
) ||
2568 (Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeMoreReliable
))) {
2569 CoreAddMemoryDescriptor (
2570 MemoryHob
->AllocDescriptor
.MemoryType
,
2571 MemoryHob
->AllocDescriptor
.MemoryBaseAddress
,
2572 RShiftU64 (MemoryHob
->AllocDescriptor
.MemoryLength
, EFI_PAGE_SHIFT
),
2573 Descriptor
.Capabilities
& (~EFI_MEMORY_RUNTIME
)
2579 if (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_FV
) {
2580 FirmwareVolumeHob
= Hob
.FirmwareVolume
;
2581 BaseAddress
= FirmwareVolumeHob
->BaseAddress
;
2582 Status
= CoreAllocateMemorySpace (
2583 EfiGcdAllocateAddress
,
2584 EfiGcdMemoryTypeMemoryMappedIo
,
2586 FirmwareVolumeHob
->Length
,
2588 gDxeCoreImageHandle
,
2595 // Add and allocate the remaining unallocated system memory to the memory services.
2597 Status
= CoreGetMemorySpaceMap (&NumberOfDescriptors
, &MemorySpaceMap
);
2598 ASSERT (Status
== EFI_SUCCESS
);
2600 MemorySpaceMapHobList
= NULL
;
2601 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
2602 if ((MemorySpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeSystemMemory
) ||
2603 (MemorySpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeMoreReliable
)) {
2604 if (MemorySpaceMap
[Index
].ImageHandle
== NULL
) {
2605 BaseAddress
= PageAlignAddress (MemorySpaceMap
[Index
].BaseAddress
);
2606 Length
= PageAlignLength (MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
- BaseAddress
);
2607 if (Length
== 0 || MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
< BaseAddress
) {
2610 if (((UINTN
) MemorySpaceMap
[Index
].BaseAddress
<= (UINTN
) (*HobStart
)) &&
2611 ((UINTN
) (MemorySpaceMap
[Index
].BaseAddress
+ MemorySpaceMap
[Index
].Length
) >= (UINTN
) PhitHob
->EfiFreeMemoryBottom
)) {
2613 // Skip the memory space that covers HOB List, it should be processed
2614 // after HOB List relocation to avoid the resources allocated by others
2615 // to corrupt HOB List before its relocation.
2617 MemorySpaceMapHobList
= &MemorySpaceMap
[Index
];
2620 CoreAddMemoryDescriptor (
2621 EfiConventionalMemory
,
2623 RShiftU64 (Length
, EFI_PAGE_SHIFT
),
2624 MemorySpaceMap
[Index
].Capabilities
& (~EFI_MEMORY_RUNTIME
)
2626 Status
= CoreAllocateMemorySpace (
2627 EfiGcdAllocateAddress
,
2628 MemorySpaceMap
[Index
].GcdMemoryType
,
2632 gDxeCoreImageHandle
,
2640 // Relocate HOB List to an allocated pool buffer.
2641 // The relocation should be at after all the tested memory resources added
2642 // (except the memory space that covers HOB List) to the memory services,
2643 // because the memory resource found in CoreInitializeMemoryServices()
2644 // may have not enough remaining resource for HOB List.
2646 NewHobList
= AllocateCopyPool (
2647 (UINTN
) PhitHob
->EfiFreeMemoryBottom
- (UINTN
) (*HobStart
),
2650 ASSERT (NewHobList
!= NULL
);
2652 *HobStart
= NewHobList
;
2653 gHobList
= NewHobList
;
2655 if (MemorySpaceMapHobList
!= NULL
) {
2657 // Add and allocate the memory space that covers HOB List to the memory services
2658 // after HOB List relocation.
2660 BaseAddress
= PageAlignAddress (MemorySpaceMapHobList
->BaseAddress
);
2661 Length
= PageAlignLength (MemorySpaceMapHobList
->BaseAddress
+ MemorySpaceMapHobList
->Length
- BaseAddress
);
2662 CoreAddMemoryDescriptor (
2663 EfiConventionalMemory
,
2665 RShiftU64 (Length
, EFI_PAGE_SHIFT
),
2666 MemorySpaceMapHobList
->Capabilities
& (~EFI_MEMORY_RUNTIME
)
2668 Status
= CoreAllocateMemorySpace (
2669 EfiGcdAllocateAddress
,
2670 MemorySpaceMapHobList
->GcdMemoryType
,
2674 gDxeCoreImageHandle
,
2679 CoreFreePool (MemorySpaceMap
);