]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Gcd/Gcd.c
Add more code robustness check for modules under MdeModulePkg.
[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 - 2010, 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 } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
587 CoreAcquireGcdIoLock ();
588 Map = &mGcdIoSpaceMap;
589 } else {
590 ASSERT (FALSE);
591 }
592
593 //
594 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
595 //
596 Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);
597 if (EFI_ERROR (Status)) {
598 Status = EFI_UNSUPPORTED;
599
600 goto Done;
601 }
602 ASSERT (StartLink != NULL && EndLink != NULL);
603
604 //
605 // Verify that the list of descriptors are unallocated non-existent memory.
606 //
607 Link = StartLink;
608 while (Link != EndLink->ForwardLink) {
609 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
610 switch (Operation) {
611 //
612 // Add operations
613 //
614 case GCD_ADD_MEMORY_OPERATION:
615 if (Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent ||
616 Entry->ImageHandle != NULL ) {
617 Status = EFI_ACCESS_DENIED;
618 goto Done;
619 }
620 break;
621 case GCD_ADD_IO_OPERATION:
622 if (Entry->GcdIoType != EfiGcdIoTypeNonExistent ||
623 Entry->ImageHandle != NULL ) {
624 Status = EFI_ACCESS_DENIED;
625 goto Done;
626 }
627 break;
628 //
629 // Free operations
630 //
631 case GCD_FREE_MEMORY_OPERATION:
632 case GCD_FREE_IO_OPERATION:
633 if (Entry->ImageHandle == NULL) {
634 Status = EFI_NOT_FOUND;
635 goto Done;
636 }
637 break;
638 //
639 // Remove operations
640 //
641 case GCD_REMOVE_MEMORY_OPERATION:
642 if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
643 Status = EFI_NOT_FOUND;
644 goto Done;
645 }
646 if (Entry->ImageHandle != NULL) {
647 Status = EFI_ACCESS_DENIED;
648 goto Done;
649 }
650 break;
651 case GCD_REMOVE_IO_OPERATION:
652 if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {
653 Status = EFI_NOT_FOUND;
654 goto Done;
655 }
656 if (Entry->ImageHandle != NULL) {
657 Status = EFI_ACCESS_DENIED;
658 goto Done;
659 }
660 break;
661 //
662 // Set attribute operations
663 //
664 case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
665 if ((Attributes & EFI_MEMORY_RUNTIME) != 0) {
666 if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
667 Status = EFI_INVALID_PARAMETER;
668 goto Done;
669 }
670 }
671 if ((Entry->Capabilities & Attributes) != Attributes) {
672 Status = EFI_UNSUPPORTED;
673 goto Done;
674 }
675 break;
676 }
677 Link = Link->ForwardLink;
678 }
679
680 //
681 // Allocate work space to perform this operation
682 //
683 Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
684 if (EFI_ERROR (Status)) {
685 Status = EFI_OUT_OF_RESOURCES;
686 goto Done;
687 }
688 ASSERT (TopEntry != NULL && BottomEntry != NULL);
689
690 if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
691 //
692 // Call CPU Arch Protocol to attempt to set attributes on the range
693 //
694 CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
695 if ( CpuArchAttributes != INVALID_CPU_ARCH_ATTRIBUTES ) {
696 Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);
697 if (EFI_ERROR (Status) || CpuArch == NULL) {
698 Status = EFI_ACCESS_DENIED;
699 goto Done;
700 }
701
702 Status = CpuArch->SetMemoryAttributes (
703 CpuArch,
704 BaseAddress,
705 Length,
706 CpuArchAttributes
707 );
708 if (EFI_ERROR (Status)) {
709 goto Done;
710 }
711 }
712
713 }
714
715 //
716 // Convert/Insert the list of descriptors from StartLink to EndLink
717 //
718 Link = StartLink;
719 while (Link != EndLink->ForwardLink) {
720 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
721 CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);
722 switch (Operation) {
723 //
724 // Add operations
725 //
726 case GCD_ADD_MEMORY_OPERATION:
727 Entry->GcdMemoryType = GcdMemoryType;
728 if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
729 Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
730 } else {
731 Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME;
732 }
733 break;
734 case GCD_ADD_IO_OPERATION:
735 Entry->GcdIoType = GcdIoType;
736 break;
737 //
738 // Free operations
739 //
740 case GCD_FREE_MEMORY_OPERATION:
741 case GCD_FREE_IO_OPERATION:
742 Entry->ImageHandle = NULL;
743 Entry->DeviceHandle = NULL;
744 break;
745 //
746 // Remove operations
747 //
748 case GCD_REMOVE_MEMORY_OPERATION:
749 Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
750 Entry->Capabilities = 0;
751 break;
752 case GCD_REMOVE_IO_OPERATION:
753 Entry->GcdIoType = EfiGcdIoTypeNonExistent;
754 break;
755 //
756 // Set attribute operations
757 //
758 case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
759 Entry->Attributes = Attributes;
760 break;
761 }
762 Link = Link->ForwardLink;
763 }
764
765 //
766 // Cleanup
767 //
768 Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
769
770 Done:
771 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
772 CoreReleaseGcdMemoryLock ();
773 }
774 if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
775 CoreReleaseGcdIoLock ();
776 }
777
778 return Status;
779 }
780
781
782 /**
783 Check whether an entry could be used to allocate space.
784
785 @param Operation Allocate memory or IO
786 @param Entry The entry to be tested
787 @param GcdMemoryType The desired memory type
788 @param GcdIoType The desired IO type
789
790 @retval EFI_NOT_FOUND The memory type does not match or there's an
791 image handle on the entry.
792 @retval EFI_UNSUPPORTED The operation unsupported.
793 @retval EFI_SUCCESS It's ok for this entry to be used to allocate
794 space.
795
796 **/
797 EFI_STATUS
798 CoreAllocateSpaceCheckEntry (
799 IN UINTN Operation,
800 IN EFI_GCD_MAP_ENTRY *Entry,
801 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
802 IN EFI_GCD_IO_TYPE GcdIoType
803 )
804 {
805 if (Entry->ImageHandle != NULL) {
806 return EFI_NOT_FOUND;
807 }
808 switch (Operation) {
809 case GCD_ALLOCATE_MEMORY_OPERATION:
810 if (Entry->GcdMemoryType != GcdMemoryType) {
811 return EFI_NOT_FOUND;
812 }
813 break;
814 case GCD_ALLOCATE_IO_OPERATION:
815 if (Entry->GcdIoType != GcdIoType) {
816 return EFI_NOT_FOUND;
817 }
818 break;
819 default:
820 return EFI_UNSUPPORTED;
821 }
822 return EFI_SUCCESS;
823 }
824
825
826 /**
827 Allocate space on specified address and length.
828
829 @param Operation The type of operation (memory or IO)
830 @param GcdAllocateType The type of allocate operation
831 @param GcdMemoryType The desired memory type
832 @param GcdIoType The desired IO type
833 @param Alignment Align with 2^Alignment
834 @param Length Length to allocate
835 @param BaseAddress Base address to allocate
836 @param ImageHandle The image handle consume the allocated space.
837 @param DeviceHandle The device handle consume the allocated space.
838
839 @retval EFI_INVALID_PARAMETER Invalid parameter.
840 @retval EFI_NOT_FOUND No descriptor for the desired space exists.
841 @retval EFI_SUCCESS Space successfully allocated.
842
843 **/
844 EFI_STATUS
845 CoreAllocateSpace (
846 IN UINTN Operation,
847 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
848 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
849 IN EFI_GCD_IO_TYPE GcdIoType,
850 IN UINTN Alignment,
851 IN UINT64 Length,
852 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
853 IN EFI_HANDLE ImageHandle,
854 IN EFI_HANDLE DeviceHandle OPTIONAL
855 )
856 {
857 EFI_STATUS Status;
858 EFI_PHYSICAL_ADDRESS AlignmentMask;
859 EFI_PHYSICAL_ADDRESS MaxAddress;
860 LIST_ENTRY *Map;
861 LIST_ENTRY *Link;
862 LIST_ENTRY *SubLink;
863 EFI_GCD_MAP_ENTRY *Entry;
864 EFI_GCD_MAP_ENTRY *TopEntry;
865 EFI_GCD_MAP_ENTRY *BottomEntry;
866 LIST_ENTRY *StartLink;
867 LIST_ENTRY *EndLink;
868 BOOLEAN Found;
869
870 //
871 // Make sure parameters are valid
872 //
873 if (GcdAllocateType < 0 || GcdAllocateType >= EfiGcdMaxAllocateType) {
874 return EFI_INVALID_PARAMETER;
875 }
876 if (GcdMemoryType < 0 || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
877 return EFI_INVALID_PARAMETER;
878 }
879 if (GcdIoType < 0 || GcdIoType >= EfiGcdIoTypeMaximum) {
880 return EFI_INVALID_PARAMETER;
881 }
882 if (BaseAddress == NULL) {
883 return EFI_INVALID_PARAMETER;
884 }
885 if (ImageHandle == NULL) {
886 return EFI_INVALID_PARAMETER;
887 }
888 if (Alignment >= 64) {
889 return EFI_NOT_FOUND;
890 }
891 if (Length == 0) {
892 return EFI_INVALID_PARAMETER;
893 }
894
895 Map = NULL;
896 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
897 CoreAcquireGcdMemoryLock ();
898 Map = &mGcdMemorySpaceMap;
899 } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
900 CoreAcquireGcdIoLock ();
901 Map = &mGcdIoSpaceMap;
902 } else {
903 ASSERT (FALSE);
904 }
905
906 Found = FALSE;
907 StartLink = NULL;
908 EndLink = NULL;
909 //
910 // Compute alignment bit mask
911 //
912 AlignmentMask = LShiftU64 (1, Alignment) - 1;
913
914 if (GcdAllocateType == EfiGcdAllocateAddress) {
915 //
916 // Verify that the BaseAddress passed in is aligned correctly
917 //
918 if ((*BaseAddress & AlignmentMask) != 0) {
919 Status = EFI_NOT_FOUND;
920 goto Done;
921 }
922
923 //
924 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
925 //
926 Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
927 if (EFI_ERROR (Status)) {
928 Status = EFI_NOT_FOUND;
929 goto Done;
930 }
931 ASSERT (StartLink != NULL && EndLink != NULL);
932
933 //
934 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
935 //
936 Link = StartLink;
937 while (Link != EndLink->ForwardLink) {
938 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
939 Link = Link->ForwardLink;
940 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
941 if (EFI_ERROR (Status)) {
942 goto Done;
943 }
944 }
945 Found = TRUE;
946 } else {
947
948 Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
949
950 //
951 // Compute the maximum address to use in the search algorithm
952 //
953 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp ||
954 GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ) {
955 MaxAddress = *BaseAddress;
956 } else {
957 MaxAddress = Entry->EndAddress;
958 }
959
960 //
961 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
962 //
963 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
964 GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
965 Link = Map->BackLink;
966 } else {
967 Link = Map->ForwardLink;
968 }
969 while (Link != Map) {
970 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
971
972 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
973 GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
974 Link = Link->BackLink;
975 } else {
976 Link = Link->ForwardLink;
977 }
978
979 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
980 if (EFI_ERROR (Status)) {
981 continue;
982 }
983
984 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
985 GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
986 if ((Entry->BaseAddress + Length) > MaxAddress) {
987 continue;
988 }
989 if (Length > (Entry->EndAddress + 1)) {
990 Status = EFI_NOT_FOUND;
991 goto Done;
992 }
993 if (Entry->EndAddress > MaxAddress) {
994 *BaseAddress = MaxAddress;
995 } else {
996 *BaseAddress = Entry->EndAddress;
997 }
998 *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
999 } else {
1000 *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
1001 if ((*BaseAddress + Length - 1) > MaxAddress) {
1002 Status = EFI_NOT_FOUND;
1003 goto Done;
1004 }
1005 }
1006
1007 //
1008 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
1009 //
1010 Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
1011 if (EFI_ERROR (Status)) {
1012 Status = EFI_NOT_FOUND;
1013 goto Done;
1014 }
1015 ASSERT (StartLink != NULL && EndLink != NULL);
1016
1017 Link = StartLink;
1018 //
1019 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1020 //
1021 Found = TRUE;
1022 SubLink = StartLink;
1023 while (SubLink != EndLink->ForwardLink) {
1024 Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1025 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
1026 if (EFI_ERROR (Status)) {
1027 Link = SubLink;
1028 Found = FALSE;
1029 break;
1030 }
1031 SubLink = SubLink->ForwardLink;
1032 }
1033 if (Found) {
1034 break;
1035 }
1036 }
1037 }
1038 if (!Found) {
1039 Status = EFI_NOT_FOUND;
1040 goto Done;
1041 }
1042
1043 //
1044 // Allocate work space to perform this operation
1045 //
1046 Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
1047 if (EFI_ERROR (Status)) {
1048 Status = EFI_OUT_OF_RESOURCES;
1049 goto Done;
1050 }
1051 ASSERT (TopEntry != NULL && BottomEntry != NULL);
1052
1053 //
1054 // Convert/Insert the list of descriptors from StartLink to EndLink
1055 //
1056 Link = StartLink;
1057 while (Link != EndLink->ForwardLink) {
1058 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1059 CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
1060 Entry->ImageHandle = ImageHandle;
1061 Entry->DeviceHandle = DeviceHandle;
1062 Link = Link->ForwardLink;
1063 }
1064
1065 //
1066 // Cleanup
1067 //
1068 Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
1069
1070 Done:
1071 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
1072 CoreReleaseGcdMemoryLock ();
1073 }
1074 if ((Operation & GCD_IO_SPACE_OPERATION) !=0) {
1075 CoreReleaseGcdIoLock ();
1076 }
1077
1078 return Status;
1079 }
1080
1081
1082 /**
1083 Add a segment of memory to GCD map.
1084
1085 @param GcdMemoryType Memory type of the segment.
1086 @param BaseAddress Base address of the segment.
1087 @param Length Length of the segment.
1088 @param Capabilities alterable attributes of the segment.
1089
1090 @retval EFI_INVALID_PARAMETER Invalid parameters.
1091 @retval EFI_SUCCESS Successfully add a segment of memory space.
1092
1093 **/
1094 EFI_STATUS
1095 CoreInternalAddMemorySpace (
1096 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1097 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1098 IN UINT64 Length,
1099 IN UINT64 Capabilities
1100 )
1101 {
1102 //
1103 // Make sure parameters are valid
1104 //
1105 if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
1106 return EFI_INVALID_PARAMETER;
1107 }
1108
1109 return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
1110 }
1111
1112 //
1113 // GCD Core Services
1114 //
1115
1116 /**
1117 Allocates nonexistent memory, reserved memory, system memory, or memorymapped
1118 I/O resources from the global coherency domain of the processor.
1119
1120 @param GcdAllocateType The type of allocate operation
1121 @param GcdMemoryType The desired memory type
1122 @param Alignment Align with 2^Alignment
1123 @param Length Length to allocate
1124 @param BaseAddress Base address to allocate
1125 @param ImageHandle The image handle consume the allocated space.
1126 @param DeviceHandle The device handle consume the allocated space.
1127
1128 @retval EFI_INVALID_PARAMETER Invalid parameter.
1129 @retval EFI_NOT_FOUND No descriptor contains the desired space.
1130 @retval EFI_SUCCESS Memory space successfully allocated.
1131
1132 **/
1133 EFI_STATUS
1134 EFIAPI
1135 CoreAllocateMemorySpace (
1136 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
1137 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1138 IN UINTN Alignment,
1139 IN UINT64 Length,
1140 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
1141 IN EFI_HANDLE ImageHandle,
1142 IN EFI_HANDLE DeviceHandle OPTIONAL
1143 )
1144 {
1145 return CoreAllocateSpace (
1146 GCD_ALLOCATE_MEMORY_OPERATION,
1147 GcdAllocateType,
1148 GcdMemoryType,
1149 (EFI_GCD_IO_TYPE) 0,
1150 Alignment,
1151 Length,
1152 BaseAddress,
1153 ImageHandle,
1154 DeviceHandle
1155 );
1156 }
1157
1158
1159 /**
1160 Adds reserved memory, system memory, or memory-mapped I/O resources to the
1161 global coherency domain of the processor.
1162
1163 @param GcdMemoryType Memory type of the memory space.
1164 @param BaseAddress Base address of the memory space.
1165 @param Length Length of the memory space.
1166 @param Capabilities alterable attributes of the memory space.
1167
1168 @retval EFI_SUCCESS Merged this memory space into GCD map.
1169
1170 **/
1171 EFI_STATUS
1172 EFIAPI
1173 CoreAddMemorySpace (
1174 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1175 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1176 IN UINT64 Length,
1177 IN UINT64 Capabilities
1178 )
1179 {
1180 EFI_STATUS Status;
1181 EFI_PHYSICAL_ADDRESS PageBaseAddress;
1182 UINT64 PageLength;
1183
1184 Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);
1185
1186 if (!EFI_ERROR (Status) && GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
1187
1188 PageBaseAddress = PageAlignLength (BaseAddress);
1189 PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress);
1190
1191 Status = CoreAllocateMemorySpace (
1192 EfiGcdAllocateAddress,
1193 GcdMemoryType,
1194 EFI_PAGE_SHIFT,
1195 PageLength,
1196 &PageBaseAddress,
1197 gDxeCoreImageHandle,
1198 NULL
1199 );
1200
1201 if (!EFI_ERROR (Status)) {
1202 CoreAddMemoryDescriptor (
1203 EfiConventionalMemory,
1204 PageBaseAddress,
1205 RShiftU64 (PageLength, EFI_PAGE_SHIFT),
1206 Capabilities
1207 );
1208 } else {
1209 for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
1210 Status = CoreAllocateMemorySpace (
1211 EfiGcdAllocateAddress,
1212 GcdMemoryType,
1213 EFI_PAGE_SHIFT,
1214 EFI_PAGE_SIZE,
1215 &PageBaseAddress,
1216 gDxeCoreImageHandle,
1217 NULL
1218 );
1219
1220 if (!EFI_ERROR (Status)) {
1221 CoreAddMemoryDescriptor (
1222 EfiConventionalMemory,
1223 PageBaseAddress,
1224 1,
1225 Capabilities
1226 );
1227 }
1228 }
1229 }
1230 }
1231 return Status;
1232 }
1233
1234
1235 /**
1236 Frees nonexistent memory, reserved memory, system memory, or memory-mapped
1237 I/O resources from the global coherency domain of the processor.
1238
1239 @param BaseAddress Base address of the memory space.
1240 @param Length Length of the memory space.
1241
1242 @retval EFI_SUCCESS Space successfully freed.
1243
1244 **/
1245 EFI_STATUS
1246 EFIAPI
1247 CoreFreeMemorySpace (
1248 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1249 IN UINT64 Length
1250 )
1251 {
1252 return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1253 }
1254
1255
1256 /**
1257 Removes reserved memory, system memory, or memory-mapped I/O resources from
1258 the global coherency domain of the processor.
1259
1260 @param BaseAddress Base address of the memory space.
1261 @param Length Length of the memory space.
1262
1263 @retval EFI_SUCCESS Successfully remove a segment of memory space.
1264
1265 **/
1266 EFI_STATUS
1267 EFIAPI
1268 CoreRemoveMemorySpace (
1269 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1270 IN UINT64 Length
1271 )
1272 {
1273 return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1274 }
1275
1276
1277 /**
1278 Build a memory descriptor according to an entry.
1279
1280 @param Descriptor The descriptor to be built
1281 @param Entry According to this entry
1282
1283 **/
1284 VOID
1285 BuildMemoryDescriptor (
1286 IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor,
1287 IN EFI_GCD_MAP_ENTRY *Entry
1288 )
1289 {
1290 Descriptor->BaseAddress = Entry->BaseAddress;
1291 Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
1292 Descriptor->Capabilities = Entry->Capabilities;
1293 Descriptor->Attributes = Entry->Attributes;
1294 Descriptor->GcdMemoryType = Entry->GcdMemoryType;
1295 Descriptor->ImageHandle = Entry->ImageHandle;
1296 Descriptor->DeviceHandle = Entry->DeviceHandle;
1297 }
1298
1299
1300 /**
1301 Retrieves the descriptor for a memory region containing a specified address.
1302
1303 @param BaseAddress Specified start address
1304 @param Descriptor Specified length
1305
1306 @retval EFI_INVALID_PARAMETER Invalid parameter
1307 @retval EFI_SUCCESS Successfully get memory space descriptor.
1308
1309 **/
1310 EFI_STATUS
1311 EFIAPI
1312 CoreGetMemorySpaceDescriptor (
1313 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1314 OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
1315 )
1316 {
1317 EFI_STATUS Status;
1318 LIST_ENTRY *StartLink;
1319 LIST_ENTRY *EndLink;
1320 EFI_GCD_MAP_ENTRY *Entry;
1321
1322 //
1323 // Make sure parameters are valid
1324 //
1325 if (Descriptor == NULL) {
1326 return EFI_INVALID_PARAMETER;
1327 }
1328
1329 CoreAcquireGcdMemoryLock ();
1330
1331 //
1332 // Search for the list of descriptors that contain BaseAddress
1333 //
1334 Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);
1335 if (EFI_ERROR (Status)) {
1336 Status = EFI_NOT_FOUND;
1337 } else {
1338 ASSERT (StartLink != NULL && EndLink != NULL);
1339 //
1340 // Copy the contents of the found descriptor into Descriptor
1341 //
1342 Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1343 BuildMemoryDescriptor (Descriptor, Entry);
1344 }
1345
1346 CoreReleaseGcdMemoryLock ();
1347
1348 return Status;
1349 }
1350
1351
1352 /**
1353 Modifies the attributes for a memory region in the global coherency domain of the
1354 processor.
1355
1356 @param BaseAddress Specified start address
1357 @param Length Specified length
1358 @param Attributes Specified attributes
1359
1360 @retval EFI_SUCCESS Successfully set attribute of a segment of
1361 memory space.
1362
1363 **/
1364 EFI_STATUS
1365 EFIAPI
1366 CoreSetMemorySpaceAttributes (
1367 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1368 IN UINT64 Length,
1369 IN UINT64 Attributes
1370 )
1371 {
1372 return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, Attributes);
1373 }
1374
1375
1376 /**
1377 Returns a map of the memory resources in the global coherency domain of the
1378 processor.
1379
1380 @param NumberOfDescriptors Number of descriptors.
1381 @param MemorySpaceMap Descriptor array
1382
1383 @retval EFI_INVALID_PARAMETER Invalid parameter
1384 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1385 @retval EFI_SUCCESS Successfully get memory space map.
1386
1387 **/
1388 EFI_STATUS
1389 EFIAPI
1390 CoreGetMemorySpaceMap (
1391 OUT UINTN *NumberOfDescriptors,
1392 OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
1393 )
1394 {
1395 EFI_STATUS Status;
1396 LIST_ENTRY *Link;
1397 EFI_GCD_MAP_ENTRY *Entry;
1398 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor;
1399
1400 //
1401 // Make sure parameters are valid
1402 //
1403 if (NumberOfDescriptors == NULL) {
1404 return EFI_INVALID_PARAMETER;
1405 }
1406 if (MemorySpaceMap == NULL) {
1407 return EFI_INVALID_PARAMETER;
1408 }
1409
1410 CoreAcquireGcdMemoryLock ();
1411
1412 //
1413 // Count the number of descriptors
1414 //
1415 *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);
1416
1417 //
1418 // Allocate the MemorySpaceMap
1419 //
1420 *MemorySpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
1421 if (*MemorySpaceMap == NULL) {
1422 Status = EFI_OUT_OF_RESOURCES;
1423 goto Done;
1424 }
1425
1426 //
1427 // Fill in the MemorySpaceMap
1428 //
1429 Descriptor = *MemorySpaceMap;
1430 Link = mGcdMemorySpaceMap.ForwardLink;
1431 while (Link != &mGcdMemorySpaceMap) {
1432 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1433 BuildMemoryDescriptor (Descriptor, Entry);
1434 Descriptor++;
1435 Link = Link->ForwardLink;
1436 }
1437 Status = EFI_SUCCESS;
1438
1439 Done:
1440 CoreReleaseGcdMemoryLock ();
1441 return Status;
1442 }
1443
1444
1445 /**
1446 Adds reserved I/O or I/O resources to the global coherency domain of the processor.
1447
1448 @param GcdIoType IO type of the segment.
1449 @param BaseAddress Base address of the segment.
1450 @param Length Length of the segment.
1451
1452 @retval EFI_SUCCESS Merged this segment into GCD map.
1453 @retval EFI_INVALID_PARAMETER Parameter not valid
1454
1455 **/
1456 EFI_STATUS
1457 EFIAPI
1458 CoreAddIoSpace (
1459 IN EFI_GCD_IO_TYPE GcdIoType,
1460 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1461 IN UINT64 Length
1462 )
1463 {
1464 //
1465 // Make sure parameters are valid
1466 //
1467 if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) {
1468 return EFI_INVALID_PARAMETER;
1469 }
1470 return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, GcdIoType, BaseAddress, Length, 0, 0);
1471 }
1472
1473
1474 /**
1475 Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
1476 domain of the processor.
1477
1478 @param GcdAllocateType The type of allocate operation
1479 @param GcdIoType The desired IO type
1480 @param Alignment Align with 2^Alignment
1481 @param Length Length to allocate
1482 @param BaseAddress Base address to allocate
1483 @param ImageHandle The image handle consume the allocated space.
1484 @param DeviceHandle The device handle consume the allocated space.
1485
1486 @retval EFI_INVALID_PARAMETER Invalid parameter.
1487 @retval EFI_NOT_FOUND No descriptor contains the desired space.
1488 @retval EFI_SUCCESS IO space successfully allocated.
1489
1490 **/
1491 EFI_STATUS
1492 EFIAPI
1493 CoreAllocateIoSpace (
1494 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
1495 IN EFI_GCD_IO_TYPE GcdIoType,
1496 IN UINTN Alignment,
1497 IN UINT64 Length,
1498 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
1499 IN EFI_HANDLE ImageHandle,
1500 IN EFI_HANDLE DeviceHandle OPTIONAL
1501 )
1502 {
1503 return CoreAllocateSpace (
1504 GCD_ALLOCATE_IO_OPERATION,
1505 GcdAllocateType,
1506 (EFI_GCD_MEMORY_TYPE) 0,
1507 GcdIoType,
1508 Alignment,
1509 Length,
1510 BaseAddress,
1511 ImageHandle,
1512 DeviceHandle
1513 );
1514 }
1515
1516
1517 /**
1518 Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
1519 domain of the processor.
1520
1521 @param BaseAddress Base address of the segment.
1522 @param Length Length of the segment.
1523
1524 @retval EFI_SUCCESS Space successfully freed.
1525
1526 **/
1527 EFI_STATUS
1528 EFIAPI
1529 CoreFreeIoSpace (
1530 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1531 IN UINT64 Length
1532 )
1533 {
1534 return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1535 }
1536
1537
1538 /**
1539 Removes reserved I/O or I/O resources from the global coherency domain of the
1540 processor.
1541
1542 @param BaseAddress Base address of the segment.
1543 @param Length Length of the segment.
1544
1545 @retval EFI_SUCCESS Successfully removed a segment of IO space.
1546
1547 **/
1548 EFI_STATUS
1549 EFIAPI
1550 CoreRemoveIoSpace (
1551 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1552 IN UINT64 Length
1553 )
1554 {
1555 return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1556 }
1557
1558
1559 /**
1560 Build a IO descriptor according to an entry.
1561
1562 @param Descriptor The descriptor to be built
1563 @param Entry According to this entry
1564
1565 **/
1566 VOID
1567 BuildIoDescriptor (
1568 IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor,
1569 IN EFI_GCD_MAP_ENTRY *Entry
1570 )
1571 {
1572 Descriptor->BaseAddress = Entry->BaseAddress;
1573 Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
1574 Descriptor->GcdIoType = Entry->GcdIoType;
1575 Descriptor->ImageHandle = Entry->ImageHandle;
1576 Descriptor->DeviceHandle = Entry->DeviceHandle;
1577 }
1578
1579
1580 /**
1581 Retrieves the descriptor for an I/O region containing a specified address.
1582
1583 @param BaseAddress Specified start address
1584 @param Descriptor Specified length
1585
1586 @retval EFI_INVALID_PARAMETER Descriptor is NULL.
1587 @retval EFI_SUCCESS Successfully get the IO space descriptor.
1588
1589 **/
1590 EFI_STATUS
1591 EFIAPI
1592 CoreGetIoSpaceDescriptor (
1593 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1594 OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
1595 )
1596 {
1597 EFI_STATUS Status;
1598 LIST_ENTRY *StartLink;
1599 LIST_ENTRY *EndLink;
1600 EFI_GCD_MAP_ENTRY *Entry;
1601
1602 //
1603 // Make sure parameters are valid
1604 //
1605 if (Descriptor == NULL) {
1606 return EFI_INVALID_PARAMETER;
1607 }
1608
1609 CoreAcquireGcdIoLock ();
1610
1611 //
1612 // Search for the list of descriptors that contain BaseAddress
1613 //
1614 Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);
1615 if (EFI_ERROR (Status)) {
1616 Status = EFI_NOT_FOUND;
1617 } else {
1618 ASSERT (StartLink != NULL && EndLink != NULL);
1619 //
1620 // Copy the contents of the found descriptor into Descriptor
1621 //
1622 Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1623 BuildIoDescriptor (Descriptor, Entry);
1624 }
1625
1626 CoreReleaseGcdIoLock ();
1627
1628 return Status;
1629 }
1630
1631
1632 /**
1633 Returns a map of the I/O resources in the global coherency domain of the processor.
1634
1635 @param NumberOfDescriptors Number of descriptors.
1636 @param IoSpaceMap Descriptor array
1637
1638 @retval EFI_INVALID_PARAMETER Invalid parameter
1639 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1640 @retval EFI_SUCCESS Successfully get IO space map.
1641
1642 **/
1643 EFI_STATUS
1644 EFIAPI
1645 CoreGetIoSpaceMap (
1646 OUT UINTN *NumberOfDescriptors,
1647 OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
1648 )
1649 {
1650 EFI_STATUS Status;
1651 LIST_ENTRY *Link;
1652 EFI_GCD_MAP_ENTRY *Entry;
1653 EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor;
1654
1655 //
1656 // Make sure parameters are valid
1657 //
1658 if (NumberOfDescriptors == NULL) {
1659 return EFI_INVALID_PARAMETER;
1660 }
1661 if (IoSpaceMap == NULL) {
1662 return EFI_INVALID_PARAMETER;
1663 }
1664
1665 CoreAcquireGcdIoLock ();
1666
1667 //
1668 // Count the number of descriptors
1669 //
1670 *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);
1671
1672 //
1673 // Allocate the IoSpaceMap
1674 //
1675 *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));
1676 if (*IoSpaceMap == NULL) {
1677 Status = EFI_OUT_OF_RESOURCES;
1678 goto Done;
1679 }
1680
1681 //
1682 // Fill in the IoSpaceMap
1683 //
1684 Descriptor = *IoSpaceMap;
1685 Link = mGcdIoSpaceMap.ForwardLink;
1686 while (Link != &mGcdIoSpaceMap) {
1687 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1688 BuildIoDescriptor (Descriptor, Entry);
1689 Descriptor++;
1690 Link = Link->ForwardLink;
1691 }
1692 Status = EFI_SUCCESS;
1693
1694 Done:
1695 CoreReleaseGcdIoLock ();
1696 return Status;
1697 }
1698
1699
1700 /**
1701 Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
1702 capabilities mask
1703
1704 @param GcdMemoryType Type of resource in the GCD memory map.
1705 @param Attributes The attribute mask in the Resource Descriptor
1706 HOB.
1707
1708 @return The capabilities mask for an EFI Memory Descriptor.
1709
1710 **/
1711 UINT64
1712 CoreConvertResourceDescriptorHobAttributesToCapabilities (
1713 EFI_GCD_MEMORY_TYPE GcdMemoryType,
1714 UINT64 Attributes
1715 )
1716 {
1717 UINT64 Capabilities;
1718 GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion;
1719
1720 //
1721 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
1722 //
1723 for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {
1724 if (Conversion->Memory || (GcdMemoryType != EfiGcdMemoryTypeSystemMemory)) {
1725 if (Attributes & Conversion->Attribute) {
1726 Capabilities |= Conversion->Capability;
1727 }
1728 }
1729 }
1730
1731 return Capabilities;
1732 }
1733
1734
1735 /**
1736 External function. Initializes memory services based on the memory
1737 descriptor HOBs. This function is responsible for priming the memory
1738 map, so memory allocations and resource allocations can be made.
1739 The first part of this function can not depend on any memory services
1740 until at least one memory descriptor is provided to the memory services.
1741
1742 @param HobStart The start address of the HOB.
1743 @param MemoryBaseAddress Start address of memory region found to init DXE
1744 core.
1745 @param MemoryLength Length of memory region found to init DXE core.
1746
1747 @retval EFI_SUCCESS Memory services successfully initialized.
1748
1749 **/
1750 EFI_STATUS
1751 CoreInitializeMemoryServices (
1752 IN VOID **HobStart,
1753 OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
1754 OUT UINT64 *MemoryLength
1755 )
1756 {
1757 EFI_PEI_HOB_POINTERS Hob;
1758 EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
1759 UINTN DataSize;
1760 BOOLEAN Found;
1761 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
1762 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
1763 EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
1764 EFI_PHYSICAL_ADDRESS BaseAddress;
1765 UINT64 Length;
1766 UINT64 Attributes;
1767 UINT64 Capabilities;
1768 EFI_PHYSICAL_ADDRESS MaxMemoryBaseAddress;
1769 UINT64 MaxMemoryLength;
1770 UINT64 MaxMemoryAttributes;
1771 EFI_PHYSICAL_ADDRESS MaxAddress;
1772 EFI_PHYSICAL_ADDRESS HighAddress;
1773 EFI_HOB_RESOURCE_DESCRIPTOR *MaxResourceHob;
1774 EFI_HOB_GUID_TYPE *GuidHob;
1775 UINT32 ReservedCodePageNumber;
1776
1777 //
1778 // Point at the first HOB. This must be the PHIT HOB.
1779 //
1780 Hob.Raw = *HobStart;
1781 ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
1782
1783 //
1784 // Initialize the spin locks and maps in the memory services.
1785 // Also fill in the memory services into the EFI Boot Services Table
1786 //
1787 CoreInitializePool ();
1788
1789 //
1790 // Initialize Local Variables
1791 //
1792 PhitResourceHob = NULL;
1793 MaxResourceHob = NULL;
1794 ResourceHob = NULL;
1795 BaseAddress = 0;
1796 Length = 0;
1797 Attributes = 0;
1798 MaxMemoryBaseAddress = 0;
1799 MaxMemoryLength = 0;
1800 MaxMemoryAttributes = 0;
1801
1802 //
1803 // Cache the PHIT HOB for later use
1804 //
1805 PhitHob = Hob.HandoffInformationTable;
1806
1807 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
1808 ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
1809 ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
1810
1811 //
1812 // cache the Top address for loading modules at Fixed Address
1813 //
1814 gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
1815 + EFI_PAGES_TO_SIZE(ReservedCodePageNumber);
1816 }
1817 //
1818 // See if a Memory Type Information HOB is available
1819 //
1820 GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
1821 if (GuidHob != NULL) {
1822 EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
1823 DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
1824 if (EfiMemoryTypeInformation != NULL && DataSize > 0 && DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION)) {
1825 CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);
1826 }
1827 }
1828
1829 //
1830 // Find the Resource Descriptor HOB that contains range FreeMemoryBaseAddress..FreeMemoryLength
1831 //
1832 Length = 0;
1833 Found = FALSE;
1834 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
1835
1836 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
1837
1838 ResourceHob = Hob.ResourceDescriptor;
1839
1840 if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
1841 (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES ) {
1842
1843 if (PhitHob->EfiFreeMemoryBottom >= ResourceHob->PhysicalStart &&
1844 PhitHob->EfiFreeMemoryTop <= (ResourceHob->PhysicalStart + ResourceHob->ResourceLength) ) {
1845
1846 //
1847 // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
1848 //
1849 PhitResourceHob = ResourceHob;
1850 Found = TRUE;
1851
1852 Attributes = PhitResourceHob->ResourceAttribute;
1853 BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
1854 Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
1855 if (Length < MINIMUM_INITIAL_MEMORY_SIZE) {
1856 BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);
1857 Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);
1858 if (Length < MINIMUM_INITIAL_MEMORY_SIZE) {
1859 BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
1860 Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));
1861 }
1862 }
1863 break;
1864 }
1865 }
1866 }
1867 }
1868
1869 //
1870 // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
1871 //
1872 ASSERT (Found);
1873
1874 //
1875 // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
1876 // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB.
1877 // The max address must be within the physically addressible range for the processor.
1878 //
1879 MaxMemoryLength = 0;
1880 MaxAddress = MAX_ADDRESS;
1881 do {
1882 HighAddress = 0;
1883 Found = FALSE;
1884 //
1885 // Search for a tested memory region that is below MaxAddress
1886 //
1887 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
1888
1889 //
1890 // See if this is a resource descriptor HOB that does not contain the PHIT.
1891 //
1892 if (Hob.ResourceDescriptor != PhitResourceHob && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
1893
1894 ResourceHob = Hob.ResourceDescriptor;
1895 //
1896 // See if this resource descrior HOB describes tested system memory below MaxAddress
1897 //
1898 if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY &&
1899 (ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES &&
1900 ResourceHob->PhysicalStart + ResourceHob->ResourceLength <= MaxAddress) {
1901 //
1902 // See if this is the highest tested system memory region below MaxAddress
1903 //
1904 if (ResourceHob->PhysicalStart > HighAddress) {
1905
1906 MaxResourceHob = ResourceHob;
1907 HighAddress = MaxResourceHob->PhysicalStart;
1908 Found = TRUE;
1909 }
1910 }
1911 }
1912 }
1913 if (Found) {
1914 //
1915 // Compute the size of the tested memory region below MaxAddrees
1916 //
1917 MaxMemoryBaseAddress = PageAlignAddress (MaxResourceHob->PhysicalStart);
1918 MaxMemoryLength = PageAlignLength (MaxResourceHob->PhysicalStart + MaxResourceHob->ResourceLength - MaxMemoryBaseAddress);
1919 MaxMemoryAttributes = MaxResourceHob->ResourceAttribute;
1920 }
1921 MaxAddress = ResourceHob->PhysicalStart;
1922 } while (Found && MaxMemoryLength < MINIMUM_INITIAL_MEMORY_SIZE);
1923
1924 if ((Length < MINIMUM_INITIAL_MEMORY_SIZE) ||
1925 (MaxMemoryBaseAddress > BaseAddress && MaxMemoryLength >= MINIMUM_INITIAL_MEMORY_SIZE)) {
1926 BaseAddress = MaxMemoryBaseAddress;
1927 Length = MaxMemoryLength;
1928 Attributes = MaxMemoryAttributes;
1929 }
1930
1931 //
1932 // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
1933 //
1934 ASSERT (Length >= MINIMUM_INITIAL_MEMORY_SIZE);
1935
1936 //
1937 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
1938 //
1939 Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
1940
1941 //
1942 // Declare the very first memory region, so the EFI Memory Services are available.
1943 //
1944 CoreAddMemoryDescriptor (
1945 EfiConventionalMemory,
1946 BaseAddress,
1947 RShiftU64 (Length, EFI_PAGE_SHIFT),
1948 Capabilities
1949 );
1950
1951 *MemoryBaseAddress = BaseAddress;
1952 *MemoryLength = Length;
1953
1954 return EFI_SUCCESS;
1955 }
1956
1957
1958 /**
1959 External function. Initializes the GCD and memory services based on the memory
1960 descriptor HOBs. This function is responsible for priming the GCD map and the
1961 memory map, so memory allocations and resource allocations can be made. The
1962 HobStart will be relocated to a pool buffer.
1963
1964 @param HobStart The start address of the HOB
1965 @param MemoryBaseAddress Start address of memory region found to init DXE
1966 core.
1967 @param MemoryLength Length of memory region found to init DXE core.
1968
1969 @retval EFI_SUCCESS GCD services successfully initialized.
1970
1971 **/
1972 EFI_STATUS
1973 CoreInitializeGcdServices (
1974 IN OUT VOID **HobStart,
1975 IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
1976 IN UINT64 MemoryLength
1977 )
1978 {
1979 EFI_PEI_HOB_POINTERS Hob;
1980 VOID *NewHobList;
1981 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
1982 UINT8 SizeOfMemorySpace;
1983 UINT8 SizeOfIoSpace;
1984 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
1985 EFI_PHYSICAL_ADDRESS BaseAddress;
1986 UINT64 Length;
1987 EFI_STATUS Status;
1988 EFI_GCD_MAP_ENTRY *Entry;
1989 EFI_GCD_MEMORY_TYPE GcdMemoryType;
1990 EFI_GCD_IO_TYPE GcdIoType;
1991 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
1992 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
1993 EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
1994 UINTN NumberOfDescriptors;
1995 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
1996 UINTN Index;
1997 UINT64 Capabilities;
1998 EFI_HOB_CPU * CpuHob;
1999
2000 //
2001 // Cache the PHIT HOB for later use
2002 //
2003 PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
2004
2005 //
2006 // Get the number of address lines in the I/O and Memory space for the CPU
2007 //
2008 CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);
2009 ASSERT (CpuHob != NULL);
2010 SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;
2011 SizeOfIoSpace = CpuHob->SizeOfIoSpace;
2012
2013 //
2014 // Initialize the GCD Memory Space Map
2015 //
2016 Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);
2017 ASSERT (Entry != NULL);
2018
2019 Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;
2020
2021 InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);
2022
2023 //
2024 // Initialize the GCD I/O Space Map
2025 //
2026 Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);
2027 ASSERT (Entry != NULL);
2028
2029 Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;
2030
2031 InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);
2032
2033 //
2034 // Walk the HOB list and add all resource descriptors to the GCD
2035 //
2036 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2037
2038 GcdMemoryType = EfiGcdMemoryTypeNonExistent;
2039 GcdIoType = EfiGcdIoTypeNonExistent;
2040
2041 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
2042
2043 ResourceHob = Hob.ResourceDescriptor;
2044
2045 switch (ResourceHob->ResourceType) {
2046 case EFI_RESOURCE_SYSTEM_MEMORY:
2047 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
2048 GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
2049 }
2050 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
2051 GcdMemoryType = EfiGcdMemoryTypeReserved;
2052 }
2053 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
2054 GcdMemoryType = EfiGcdMemoryTypeReserved;
2055 }
2056 break;
2057 case EFI_RESOURCE_MEMORY_MAPPED_IO:
2058 case EFI_RESOURCE_FIRMWARE_DEVICE:
2059 GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;
2060 break;
2061 case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
2062 case EFI_RESOURCE_MEMORY_RESERVED:
2063 GcdMemoryType = EfiGcdMemoryTypeReserved;
2064 break;
2065 case EFI_RESOURCE_IO:
2066 GcdIoType = EfiGcdIoTypeIo;
2067 break;
2068 case EFI_RESOURCE_IO_RESERVED:
2069 GcdIoType = EfiGcdIoTypeReserved;
2070 break;
2071 }
2072
2073 if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {
2074 //
2075 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2076 //
2077 Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (
2078 GcdMemoryType,
2079 ResourceHob->ResourceAttribute
2080 );
2081
2082 Status = CoreInternalAddMemorySpace (
2083 GcdMemoryType,
2084 ResourceHob->PhysicalStart,
2085 ResourceHob->ResourceLength,
2086 Capabilities
2087 );
2088 }
2089
2090 if (GcdIoType != EfiGcdIoTypeNonExistent) {
2091 Status = CoreAddIoSpace (
2092 GcdIoType,
2093 ResourceHob->PhysicalStart,
2094 ResourceHob->ResourceLength
2095 );
2096 }
2097 }
2098 }
2099
2100 //
2101 // Allocate first memory region from the GCD by the DXE core
2102 //
2103 Status = CoreAllocateMemorySpace (
2104 EfiGcdAllocateAddress,
2105 EfiGcdMemoryTypeSystemMemory,
2106 0,
2107 MemoryLength,
2108 &MemoryBaseAddress,
2109 gDxeCoreImageHandle,
2110 NULL
2111 );
2112
2113 //
2114 // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
2115 // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs.
2116 //
2117 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2118 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
2119 MemoryHob = Hob.MemoryAllocation;
2120 BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
2121 Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
2122 if (!EFI_ERROR (Status)) {
2123 Status = CoreAllocateMemorySpace (
2124 EfiGcdAllocateAddress,
2125 Descriptor.GcdMemoryType,
2126 0,
2127 MemoryHob->AllocDescriptor.MemoryLength,
2128 &BaseAddress,
2129 gDxeCoreImageHandle,
2130 NULL
2131 );
2132 if (!EFI_ERROR (Status) && Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
2133 CoreAddMemoryDescriptor (
2134 MemoryHob->AllocDescriptor.MemoryType,
2135 MemoryHob->AllocDescriptor.MemoryBaseAddress,
2136 RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),
2137 Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)
2138 );
2139 }
2140 }
2141 }
2142
2143 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
2144 FirmwareVolumeHob = Hob.FirmwareVolume;
2145 BaseAddress = FirmwareVolumeHob->BaseAddress;
2146 Status = CoreAllocateMemorySpace (
2147 EfiGcdAllocateAddress,
2148 EfiGcdMemoryTypeMemoryMappedIo,
2149 0,
2150 FirmwareVolumeHob->Length,
2151 &BaseAddress,
2152 gDxeCoreImageHandle,
2153 NULL
2154 );
2155 }
2156 }
2157
2158 //
2159 // Relocate HOB List to an allocated pool buffer.
2160 //
2161 NewHobList = AllocateCopyPool (
2162 (UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart),
2163 *HobStart
2164 );
2165 ASSERT (NewHobList != NULL);
2166
2167 *HobStart = NewHobList;
2168 gHobList = NewHobList;
2169
2170 //
2171 // Add and allocate the remaining unallocated system memory to the memory services.
2172 //
2173 Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
2174 ASSERT (Status == EFI_SUCCESS);
2175
2176 for (Index = 0; Index < NumberOfDescriptors; Index++) {
2177 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
2178 if (MemorySpaceMap[Index].ImageHandle == NULL) {
2179 BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);
2180 Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);
2181 if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) {
2182 continue;
2183 }
2184 CoreAddMemoryDescriptor (
2185 EfiConventionalMemory,
2186 BaseAddress,
2187 RShiftU64 (Length, EFI_PAGE_SHIFT),
2188 MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)
2189 );
2190 Status = CoreAllocateMemorySpace (
2191 EfiGcdAllocateAddress,
2192 EfiGcdMemoryTypeSystemMemory,
2193 0,
2194 Length,
2195 &BaseAddress,
2196 gDxeCoreImageHandle,
2197 NULL
2198 );
2199 }
2200 }
2201 }
2202 CoreFreePool (MemorySpaceMap);
2203
2204 return EFI_SUCCESS;
2205 }