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