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