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