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