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