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