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