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