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