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