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