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