]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Gcd/Gcd.c
6518921516f38c7d5b58691f7eaf64f53ec6b721
[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 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "DxeMain.h"
12 #include "Gcd.h"
13 #include "Mem/HeapGuard.h"
14
15 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000
16
17 #define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
18 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
19 EFI_RESOURCE_ATTRIBUTE_TESTED | \
20 EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
21 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
22 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
23 EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
24 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
25 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
26 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
27 EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
28
29 #define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
30 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
31 EFI_RESOURCE_ATTRIBUTE_TESTED )
32
33 #define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
34 EFI_RESOURCE_ATTRIBUTE_INITIALIZED )
35
36 #define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)
37
38 //
39 // Module Variables
40 //
41 EFI_LOCK mGcdMemorySpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
42 EFI_LOCK mGcdIoSpaceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
43 LIST_ENTRY mGcdMemorySpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdMemorySpaceMap);
44 LIST_ENTRY mGcdIoSpaceMap = INITIALIZE_LIST_HEAD_VARIABLE (mGcdIoSpaceMap);
45
46 EFI_GCD_MAP_ENTRY mGcdMemorySpaceMapEntryTemplate = {
47 EFI_GCD_MAP_SIGNATURE,
48 {
49 NULL,
50 NULL
51 },
52 0,
53 0,
54 0,
55 0,
56 EfiGcdMemoryTypeNonExistent,
57 (EFI_GCD_IO_TYPE) 0,
58 NULL,
59 NULL
60 };
61
62 EFI_GCD_MAP_ENTRY mGcdIoSpaceMapEntryTemplate = {
63 EFI_GCD_MAP_SIGNATURE,
64 {
65 NULL,
66 NULL
67 },
68 0,
69 0,
70 0,
71 0,
72 (EFI_GCD_MEMORY_TYPE) 0,
73 EfiGcdIoTypeNonExistent,
74 NULL,
75 NULL
76 };
77
78 GCD_ATTRIBUTE_CONVERSION_ENTRY mAttributeConversionTable[] = {
79 { EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE, EFI_MEMORY_UC, TRUE },
80 { EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED, EFI_MEMORY_UCE, TRUE },
81 { EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE, EFI_MEMORY_WC, TRUE },
82 { EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE, EFI_MEMORY_WT, TRUE },
83 { EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE, EFI_MEMORY_WB, TRUE },
84 { EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE, EFI_MEMORY_RP, TRUE },
85 { EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE, EFI_MEMORY_WP, TRUE },
86 { EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE, EFI_MEMORY_XP, TRUE },
87 { EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE, EFI_MEMORY_RO, TRUE },
88 { EFI_RESOURCE_ATTRIBUTE_PRESENT, EFI_MEMORY_PRESENT, FALSE },
89 { EFI_RESOURCE_ATTRIBUTE_INITIALIZED, EFI_MEMORY_INITIALIZED, FALSE },
90 { EFI_RESOURCE_ATTRIBUTE_TESTED, EFI_MEMORY_TESTED, FALSE },
91 { EFI_RESOURCE_ATTRIBUTE_PERSISTABLE, EFI_MEMORY_NV, TRUE },
92 { EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE, EFI_MEMORY_MORE_RELIABLE, TRUE },
93 { 0, 0, FALSE }
94 };
95
96 ///
97 /// Lookup table used to print GCD Memory Space Map
98 ///
99 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdMemoryTypeNames[] = {
100 "NonExist ", // EfiGcdMemoryTypeNonExistent
101 "Reserved ", // EfiGcdMemoryTypeReserved
102 "SystemMem", // EfiGcdMemoryTypeSystemMemory
103 "MMIO ", // EfiGcdMemoryTypeMemoryMappedIo
104 "PersisMem", // EfiGcdMemoryTypePersistent
105 "MoreRelia", // EfiGcdMemoryTypeMoreReliable
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 (Status == EFI_SUCCESS && MemorySpaceMap != NULL);
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 (Status == EFI_SUCCESS && IoSpaceMap != NULL);
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 Validate resource descriptor HOB's attributes.
216
217 If Attributes includes some memory resource's settings, it should include
218 the corresponding capabilites also.
219
220 @param Attributes Resource descriptor HOB attributes.
221
222 **/
223 VOID
224 CoreValidateResourceDescriptorHobAttributes (
225 IN UINT64 Attributes
226 )
227 {
228 ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED) == 0) ||
229 ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE) != 0));
230 ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED) == 0) ||
231 ((Attributes & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE) != 0));
232 ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED) == 0) ||
233 ((Attributes & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE) != 0));
234 ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED) == 0) ||
235 ((Attributes & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE) != 0));
236 ASSERT (((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == 0) ||
237 ((Attributes & EFI_RESOURCE_ATTRIBUTE_PERSISTABLE) != 0));
238 }
239
240 /**
241 Acquire memory lock on mGcdMemorySpaceLock.
242
243 **/
244 VOID
245 CoreAcquireGcdMemoryLock (
246 VOID
247 )
248 {
249 CoreAcquireLock (&mGcdMemorySpaceLock);
250 }
251
252
253
254 /**
255 Release memory lock on mGcdMemorySpaceLock.
256
257 **/
258 VOID
259 CoreReleaseGcdMemoryLock (
260 VOID
261 )
262 {
263 CoreReleaseLock (&mGcdMemorySpaceLock);
264 }
265
266
267
268 /**
269 Acquire memory lock on mGcdIoSpaceLock.
270
271 **/
272 VOID
273 CoreAcquireGcdIoLock (
274 VOID
275 )
276 {
277 CoreAcquireLock (&mGcdIoSpaceLock);
278 }
279
280
281 /**
282 Release memory lock on mGcdIoSpaceLock.
283
284 **/
285 VOID
286 CoreReleaseGcdIoLock (
287 VOID
288 )
289 {
290 CoreReleaseLock (&mGcdIoSpaceLock);
291 }
292
293
294
295 //
296 // GCD Initialization Worker Functions
297 //
298 /**
299 Aligns a value to the specified boundary.
300
301 @param Value 64 bit value to align
302 @param Alignment Log base 2 of the boundary to align Value to
303 @param RoundUp TRUE if Value is to be rounded up to the nearest
304 aligned boundary. FALSE is Value is to be
305 rounded down to the nearest aligned boundary.
306
307 @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
308
309 **/
310 UINT64
311 AlignValue (
312 IN UINT64 Value,
313 IN UINTN Alignment,
314 IN BOOLEAN RoundUp
315 )
316 {
317 UINT64 AlignmentMask;
318
319 AlignmentMask = LShiftU64 (1, Alignment) - 1;
320 if (RoundUp) {
321 Value += AlignmentMask;
322 }
323 return Value & (~AlignmentMask);
324 }
325
326
327 /**
328 Aligns address to the page boundary.
329
330 @param Value 64 bit address to align
331
332 @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
333
334 **/
335 UINT64
336 PageAlignAddress (
337 IN UINT64 Value
338 )
339 {
340 return AlignValue (Value, EFI_PAGE_SHIFT, TRUE);
341 }
342
343
344 /**
345 Aligns length to the page boundary.
346
347 @param Value 64 bit length to align
348
349 @return A 64 bit value is the aligned to the value nearest Value with an alignment by Alignment.
350
351 **/
352 UINT64
353 PageAlignLength (
354 IN UINT64 Value
355 )
356 {
357 return AlignValue (Value, EFI_PAGE_SHIFT, FALSE);
358 }
359
360 //
361 // GCD Memory Space Worker Functions
362 //
363
364 /**
365 Allocate pool for two entries.
366
367 @param TopEntry An entry of GCD map
368 @param BottomEntry An entry of GCD map
369
370 @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.
371 @retval EFI_SUCCESS Both entries successfully allocated.
372
373 **/
374 EFI_STATUS
375 CoreAllocateGcdMapEntry (
376 IN OUT EFI_GCD_MAP_ENTRY **TopEntry,
377 IN OUT EFI_GCD_MAP_ENTRY **BottomEntry
378 )
379 {
380 //
381 // Set to mOnGuarding to TRUE before memory allocation. This will make sure
382 // that the entry memory is not "guarded" by HeapGuard. Otherwise it might
383 // cause problem when it's freed (if HeapGuard is enabled).
384 //
385 mOnGuarding = TRUE;
386 *TopEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
387 mOnGuarding = FALSE;
388 if (*TopEntry == NULL) {
389 return EFI_OUT_OF_RESOURCES;
390 }
391
392 mOnGuarding = TRUE;
393 *BottomEntry = AllocateZeroPool (sizeof (EFI_GCD_MAP_ENTRY));
394 mOnGuarding = FALSE;
395 if (*BottomEntry == NULL) {
396 CoreFreePool (*TopEntry);
397 return EFI_OUT_OF_RESOURCES;
398 }
399
400 return EFI_SUCCESS;
401 }
402
403
404 /**
405 Internal function. Inserts a new descriptor into a sorted list
406
407 @param Link The linked list to insert the range BaseAddress
408 and Length into
409 @param Entry A pointer to the entry that is inserted
410 @param BaseAddress The base address of the new range
411 @param Length The length of the new range in bytes
412 @param TopEntry Top pad entry to insert if needed.
413 @param BottomEntry Bottom pad entry to insert if needed.
414
415 @retval EFI_SUCCESS The new range was inserted into the linked list
416
417 **/
418 EFI_STATUS
419 CoreInsertGcdMapEntry (
420 IN LIST_ENTRY *Link,
421 IN EFI_GCD_MAP_ENTRY *Entry,
422 IN EFI_PHYSICAL_ADDRESS BaseAddress,
423 IN UINT64 Length,
424 IN EFI_GCD_MAP_ENTRY *TopEntry,
425 IN EFI_GCD_MAP_ENTRY *BottomEntry
426 )
427 {
428 ASSERT (Length != 0);
429
430 if (BaseAddress > Entry->BaseAddress) {
431 ASSERT (BottomEntry->Signature == 0);
432
433 CopyMem (BottomEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
434 Entry->BaseAddress = BaseAddress;
435 BottomEntry->EndAddress = BaseAddress - 1;
436 InsertTailList (Link, &BottomEntry->Link);
437 }
438
439 if ((BaseAddress + Length - 1) < Entry->EndAddress) {
440 ASSERT (TopEntry->Signature == 0);
441
442 CopyMem (TopEntry, Entry, sizeof (EFI_GCD_MAP_ENTRY));
443 TopEntry->BaseAddress = BaseAddress + Length;
444 Entry->EndAddress = BaseAddress + Length - 1;
445 InsertHeadList (Link, &TopEntry->Link);
446 }
447
448 return EFI_SUCCESS;
449 }
450
451
452 /**
453 Merge the Gcd region specified by Link and its adjacent entry.
454
455 @param Link Specify the entry to be merged (with its
456 adjacent entry).
457 @param Forward Direction (forward or backward).
458 @param Map Boundary.
459
460 @retval EFI_SUCCESS Successfully returned.
461 @retval EFI_UNSUPPORTED These adjacent regions could not merge.
462
463 **/
464 EFI_STATUS
465 CoreMergeGcdMapEntry (
466 IN LIST_ENTRY *Link,
467 IN BOOLEAN Forward,
468 IN LIST_ENTRY *Map
469 )
470 {
471 LIST_ENTRY *AdjacentLink;
472 EFI_GCD_MAP_ENTRY *Entry;
473 EFI_GCD_MAP_ENTRY *AdjacentEntry;
474
475 //
476 // Get adjacent entry
477 //
478 if (Forward) {
479 AdjacentLink = Link->ForwardLink;
480 } else {
481 AdjacentLink = Link->BackLink;
482 }
483
484 //
485 // If AdjacentLink is the head of the list, then no merge can be performed
486 //
487 if (AdjacentLink == Map) {
488 return EFI_SUCCESS;
489 }
490
491 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
492 AdjacentEntry = CR (AdjacentLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
493
494 if (Entry->Capabilities != AdjacentEntry->Capabilities) {
495 return EFI_UNSUPPORTED;
496 }
497 if (Entry->Attributes != AdjacentEntry->Attributes) {
498 return EFI_UNSUPPORTED;
499 }
500 if (Entry->GcdMemoryType != AdjacentEntry->GcdMemoryType) {
501 return EFI_UNSUPPORTED;
502 }
503 if (Entry->GcdIoType != AdjacentEntry->GcdIoType) {
504 return EFI_UNSUPPORTED;
505 }
506 if (Entry->ImageHandle != AdjacentEntry->ImageHandle) {
507 return EFI_UNSUPPORTED;
508 }
509 if (Entry->DeviceHandle != AdjacentEntry->DeviceHandle) {
510 return EFI_UNSUPPORTED;
511 }
512
513 if (Forward) {
514 Entry->EndAddress = AdjacentEntry->EndAddress;
515 } else {
516 Entry->BaseAddress = AdjacentEntry->BaseAddress;
517 }
518 RemoveEntryList (AdjacentLink);
519 CoreFreePool (AdjacentEntry);
520
521 return EFI_SUCCESS;
522 }
523
524
525 /**
526 Merge adjacent entries on total chain.
527
528 @param TopEntry Top entry of GCD map.
529 @param BottomEntry Bottom entry of GCD map.
530 @param StartLink Start link of the list for this loop.
531 @param EndLink End link of the list for this loop.
532 @param Map Boundary.
533
534 @retval EFI_SUCCESS GCD map successfully cleaned up.
535
536 **/
537 EFI_STATUS
538 CoreCleanupGcdMapEntry (
539 IN EFI_GCD_MAP_ENTRY *TopEntry,
540 IN EFI_GCD_MAP_ENTRY *BottomEntry,
541 IN LIST_ENTRY *StartLink,
542 IN LIST_ENTRY *EndLink,
543 IN LIST_ENTRY *Map
544 )
545 {
546 LIST_ENTRY *Link;
547
548 if (TopEntry->Signature == 0) {
549 CoreFreePool (TopEntry);
550 }
551 if (BottomEntry->Signature == 0) {
552 CoreFreePool (BottomEntry);
553 }
554
555 Link = StartLink;
556 while (Link != EndLink->ForwardLink) {
557 CoreMergeGcdMapEntry (Link, FALSE, Map);
558 Link = Link->ForwardLink;
559 }
560 CoreMergeGcdMapEntry (EndLink, TRUE, Map);
561
562 return EFI_SUCCESS;
563 }
564
565
566 /**
567 Search a segment of memory space in GCD map. The result is a range of GCD entry list.
568
569 @param BaseAddress The start address of the segment.
570 @param Length The length of the segment.
571 @param StartLink The first GCD entry involves this segment of
572 memory space.
573 @param EndLink The first GCD entry involves this segment of
574 memory space.
575 @param Map Points to the start entry to search.
576
577 @retval EFI_SUCCESS Successfully found the entry.
578 @retval EFI_NOT_FOUND Not found.
579
580 **/
581 EFI_STATUS
582 CoreSearchGcdMapEntry (
583 IN EFI_PHYSICAL_ADDRESS BaseAddress,
584 IN UINT64 Length,
585 OUT LIST_ENTRY **StartLink,
586 OUT LIST_ENTRY **EndLink,
587 IN LIST_ENTRY *Map
588 )
589 {
590 LIST_ENTRY *Link;
591 EFI_GCD_MAP_ENTRY *Entry;
592
593 ASSERT (Length != 0);
594
595 *StartLink = NULL;
596 *EndLink = NULL;
597
598 Link = Map->ForwardLink;
599 while (Link != Map) {
600 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
601 if (BaseAddress >= Entry->BaseAddress && BaseAddress <= Entry->EndAddress) {
602 *StartLink = Link;
603 }
604 if (*StartLink != NULL) {
605 if ((BaseAddress + Length - 1) >= Entry->BaseAddress &&
606 (BaseAddress + Length - 1) <= Entry->EndAddress ) {
607 *EndLink = Link;
608 return EFI_SUCCESS;
609 }
610 }
611 Link = Link->ForwardLink;
612 }
613
614 return EFI_NOT_FOUND;
615 }
616
617
618 /**
619 Count the amount of GCD map entries.
620
621 @param Map Points to the start entry to do the count loop.
622
623 @return The count.
624
625 **/
626 UINTN
627 CoreCountGcdMapEntry (
628 IN LIST_ENTRY *Map
629 )
630 {
631 UINTN Count;
632 LIST_ENTRY *Link;
633
634 Count = 0;
635 Link = Map->ForwardLink;
636 while (Link != Map) {
637 Count++;
638 Link = Link->ForwardLink;
639 }
640
641 return Count;
642 }
643
644
645
646 /**
647 Return the memory attribute specified by Attributes
648
649 @param Attributes A num with some attribute bits on.
650
651 @return The enum value of memory attribute.
652
653 **/
654 UINT64
655 ConverToCpuArchAttributes (
656 UINT64 Attributes
657 )
658 {
659 UINT64 CpuArchAttributes;
660
661 CpuArchAttributes = Attributes & EFI_MEMORY_ATTRIBUTE_MASK;
662
663 if ( (Attributes & EFI_MEMORY_UC) == EFI_MEMORY_UC) {
664 CpuArchAttributes |= EFI_MEMORY_UC;
665 } else if ( (Attributes & EFI_MEMORY_WC ) == EFI_MEMORY_WC) {
666 CpuArchAttributes |= EFI_MEMORY_WC;
667 } else if ( (Attributes & EFI_MEMORY_WT ) == EFI_MEMORY_WT) {
668 CpuArchAttributes |= EFI_MEMORY_WT;
669 } else if ( (Attributes & EFI_MEMORY_WB) == EFI_MEMORY_WB) {
670 CpuArchAttributes |= EFI_MEMORY_WB;
671 } else if ( (Attributes & EFI_MEMORY_UCE) == EFI_MEMORY_UCE) {
672 CpuArchAttributes |= EFI_MEMORY_UCE;
673 } else if ( (Attributes & EFI_MEMORY_WP) == EFI_MEMORY_WP) {
674 CpuArchAttributes |= EFI_MEMORY_WP;
675 }
676
677 return CpuArchAttributes;
678 }
679
680
681 /**
682 Do operation on a segment of memory space specified (add, free, remove, change attribute ...).
683
684 @param Operation The type of the operation
685 @param GcdMemoryType Additional information for the operation
686 @param GcdIoType Additional information for the operation
687 @param BaseAddress Start address of the segment
688 @param Length length of the segment
689 @param Capabilities The alterable attributes of a newly added entry
690 @param Attributes The attributes needs to be set
691
692 @retval EFI_INVALID_PARAMETER Length is 0 or address (length) not aligned when
693 setting attribute.
694 @retval EFI_SUCCESS Action successfully done.
695 @retval EFI_UNSUPPORTED Could not find the proper descriptor on this
696 segment or set an upsupported attribute.
697 @retval EFI_ACCESS_DENIED Operate on an space non-exist or is used for an
698 image.
699 @retval EFI_NOT_FOUND Free a non-using space or remove a non-exist
700 space, and so on.
701 @retval EFI_OUT_OF_RESOURCES No buffer could be allocated.
702 @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol
703 is not available yet.
704 **/
705 EFI_STATUS
706 CoreConvertSpace (
707 IN UINTN Operation,
708 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
709 IN EFI_GCD_IO_TYPE GcdIoType,
710 IN EFI_PHYSICAL_ADDRESS BaseAddress,
711 IN UINT64 Length,
712 IN UINT64 Capabilities,
713 IN UINT64 Attributes
714 )
715 {
716 EFI_STATUS Status;
717 LIST_ENTRY *Map;
718 LIST_ENTRY *Link;
719 EFI_GCD_MAP_ENTRY *Entry;
720 EFI_GCD_MAP_ENTRY *TopEntry;
721 EFI_GCD_MAP_ENTRY *BottomEntry;
722 LIST_ENTRY *StartLink;
723 LIST_ENTRY *EndLink;
724 UINT64 CpuArchAttributes;
725
726 if (Length == 0) {
727 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
728 return EFI_INVALID_PARAMETER;
729 }
730
731 Map = NULL;
732 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
733 CoreAcquireGcdMemoryLock ();
734 Map = &mGcdMemorySpaceMap;
735 } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
736 CoreAcquireGcdIoLock ();
737 Map = &mGcdIoSpaceMap;
738 } else {
739 ASSERT (FALSE);
740 }
741
742 //
743 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
744 //
745 Status = CoreSearchGcdMapEntry (BaseAddress, Length, &StartLink, &EndLink, Map);
746 if (EFI_ERROR (Status)) {
747 Status = EFI_UNSUPPORTED;
748
749 goto Done;
750 }
751 ASSERT (StartLink != NULL && EndLink != NULL);
752
753 //
754 // Verify that the list of descriptors are unallocated non-existent memory.
755 //
756 Link = StartLink;
757 while (Link != EndLink->ForwardLink) {
758 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
759 switch (Operation) {
760 //
761 // Add operations
762 //
763 case GCD_ADD_MEMORY_OPERATION:
764 if (Entry->GcdMemoryType != EfiGcdMemoryTypeNonExistent ||
765 Entry->ImageHandle != NULL ) {
766 Status = EFI_ACCESS_DENIED;
767 goto Done;
768 }
769 break;
770 case GCD_ADD_IO_OPERATION:
771 if (Entry->GcdIoType != EfiGcdIoTypeNonExistent ||
772 Entry->ImageHandle != NULL ) {
773 Status = EFI_ACCESS_DENIED;
774 goto Done;
775 }
776 break;
777 //
778 // Free operations
779 //
780 case GCD_FREE_MEMORY_OPERATION:
781 case GCD_FREE_IO_OPERATION:
782 if (Entry->ImageHandle == NULL) {
783 Status = EFI_NOT_FOUND;
784 goto Done;
785 }
786 break;
787 //
788 // Remove operations
789 //
790 case GCD_REMOVE_MEMORY_OPERATION:
791 if (Entry->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
792 Status = EFI_NOT_FOUND;
793 goto Done;
794 }
795 if (Entry->ImageHandle != NULL) {
796 Status = EFI_ACCESS_DENIED;
797 goto Done;
798 }
799 break;
800 case GCD_REMOVE_IO_OPERATION:
801 if (Entry->GcdIoType == EfiGcdIoTypeNonExistent) {
802 Status = EFI_NOT_FOUND;
803 goto Done;
804 }
805 if (Entry->ImageHandle != NULL) {
806 Status = EFI_ACCESS_DENIED;
807 goto Done;
808 }
809 break;
810 //
811 // Set attributes operation
812 //
813 case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
814 if ((Attributes & EFI_MEMORY_RUNTIME) != 0) {
815 if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
816 Status = EFI_INVALID_PARAMETER;
817 goto Done;
818 }
819 }
820 if ((Entry->Capabilities & Attributes) != Attributes) {
821 Status = EFI_UNSUPPORTED;
822 goto Done;
823 }
824 break;
825 //
826 // Set capabilities operation
827 //
828 case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
829 if ((BaseAddress & EFI_PAGE_MASK) != 0 || (Length & EFI_PAGE_MASK) != 0) {
830 Status = EFI_INVALID_PARAMETER;
831
832 goto Done;
833 }
834 //
835 // Current attributes must still be supported with new capabilities
836 //
837 if ((Capabilities & Entry->Attributes) != Entry->Attributes) {
838 Status = EFI_UNSUPPORTED;
839 goto Done;
840 }
841 break;
842 }
843 Link = Link->ForwardLink;
844 }
845
846 //
847 // Allocate work space to perform this operation
848 //
849 Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
850 if (EFI_ERROR (Status)) {
851 Status = EFI_OUT_OF_RESOURCES;
852 goto Done;
853 }
854 ASSERT (TopEntry != NULL && BottomEntry != NULL);
855
856 //
857 // Initialize CpuArchAttributes to suppress incorrect compiler/analyzer warnings.
858 //
859 CpuArchAttributes = 0;
860 if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
861 //
862 // Call CPU Arch Protocol to attempt to set attributes on the range
863 //
864 CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
865 //
866 // CPU arch attributes include page attributes and cache attributes.
867 // Only page attributes supports to be cleared, but not cache attributes.
868 // Caller is expected to use GetMemorySpaceDescriptor() to get the current
869 // attributes, AND/OR attributes, and then calls SetMemorySpaceAttributes()
870 // to set the new attributes.
871 // So 0 CPU arch attributes should not happen as memory should always have
872 // a cache attribute (no matter UC or WB, etc).
873 //
874 // Here, 0 CPU arch attributes will be filtered to be compatible with the
875 // case that caller just calls SetMemorySpaceAttributes() with none CPU
876 // arch attributes (for example, RUNTIME) as the purpose of the case is not
877 // to clear CPU arch attributes.
878 //
879 if (CpuArchAttributes != 0) {
880 if (gCpu == NULL) {
881 Status = EFI_NOT_AVAILABLE_YET;
882 } else {
883 Status = gCpu->SetMemoryAttributes (
884 gCpu,
885 BaseAddress,
886 Length,
887 CpuArchAttributes
888 );
889 }
890 if (EFI_ERROR (Status)) {
891 CoreFreePool (TopEntry);
892 CoreFreePool (BottomEntry);
893 goto Done;
894 }
895 }
896 }
897
898 //
899 // Convert/Insert the list of descriptors from StartLink to EndLink
900 //
901 Link = StartLink;
902 while (Link != EndLink->ForwardLink) {
903 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
904 CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);
905 switch (Operation) {
906 //
907 // Add operations
908 //
909 case GCD_ADD_MEMORY_OPERATION:
910 Entry->GcdMemoryType = GcdMemoryType;
911 if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
912 Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
913 } else {
914 Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME;
915 }
916 break;
917 case GCD_ADD_IO_OPERATION:
918 Entry->GcdIoType = GcdIoType;
919 break;
920 //
921 // Free operations
922 //
923 case GCD_FREE_MEMORY_OPERATION:
924 case GCD_FREE_IO_OPERATION:
925 Entry->ImageHandle = NULL;
926 Entry->DeviceHandle = NULL;
927 break;
928 //
929 // Remove operations
930 //
931 case GCD_REMOVE_MEMORY_OPERATION:
932 Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
933 Entry->Capabilities = 0;
934 break;
935 case GCD_REMOVE_IO_OPERATION:
936 Entry->GcdIoType = EfiGcdIoTypeNonExistent;
937 break;
938 //
939 // Set attributes operation
940 //
941 case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
942 if (CpuArchAttributes == 0) {
943 //
944 // Keep original CPU arch attributes when caller just calls
945 // SetMemorySpaceAttributes() with none CPU arch attributes (for example, RUNTIME).
946 //
947 Attributes |= (Entry->Attributes & (EFI_CACHE_ATTRIBUTE_MASK | EFI_MEMORY_ATTRIBUTE_MASK));
948 }
949 Entry->Attributes = Attributes;
950 break;
951 //
952 // Set capabilities operation
953 //
954 case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
955 Entry->Capabilities = Capabilities;
956 break;
957 }
958 Link = Link->ForwardLink;
959 }
960
961 //
962 // Cleanup
963 //
964 Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
965
966 Done:
967 DEBUG ((DEBUG_GCD, " Status = %r\n", Status));
968
969 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
970 CoreReleaseGcdMemoryLock ();
971 CoreDumpGcdMemorySpaceMap (FALSE);
972 }
973 if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
974 CoreReleaseGcdIoLock ();
975 CoreDumpGcdIoSpaceMap (FALSE);
976 }
977
978 return Status;
979 }
980
981
982 /**
983 Check whether an entry could be used to allocate space.
984
985 @param Operation Allocate memory or IO
986 @param Entry The entry to be tested
987 @param GcdMemoryType The desired memory type
988 @param GcdIoType The desired IO type
989
990 @retval EFI_NOT_FOUND The memory type does not match or there's an
991 image handle on the entry.
992 @retval EFI_UNSUPPORTED The operation unsupported.
993 @retval EFI_SUCCESS It's ok for this entry to be used to allocate
994 space.
995
996 **/
997 EFI_STATUS
998 CoreAllocateSpaceCheckEntry (
999 IN UINTN Operation,
1000 IN EFI_GCD_MAP_ENTRY *Entry,
1001 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1002 IN EFI_GCD_IO_TYPE GcdIoType
1003 )
1004 {
1005 if (Entry->ImageHandle != NULL) {
1006 return EFI_NOT_FOUND;
1007 }
1008 switch (Operation) {
1009 case GCD_ALLOCATE_MEMORY_OPERATION:
1010 if (Entry->GcdMemoryType != GcdMemoryType) {
1011 return EFI_NOT_FOUND;
1012 }
1013 break;
1014 case GCD_ALLOCATE_IO_OPERATION:
1015 if (Entry->GcdIoType != GcdIoType) {
1016 return EFI_NOT_FOUND;
1017 }
1018 break;
1019 default:
1020 return EFI_UNSUPPORTED;
1021 }
1022 return EFI_SUCCESS;
1023 }
1024
1025
1026 /**
1027 Allocate space on specified address and length.
1028
1029 @param Operation The type of operation (memory or IO)
1030 @param GcdAllocateType The type of allocate operation
1031 @param GcdMemoryType The desired memory type
1032 @param GcdIoType The desired IO type
1033 @param Alignment Align with 2^Alignment
1034 @param Length Length to allocate
1035 @param BaseAddress Base address to allocate
1036 @param ImageHandle The image handle consume the allocated space.
1037 @param DeviceHandle The device handle consume the allocated space.
1038
1039 @retval EFI_INVALID_PARAMETER Invalid parameter.
1040 @retval EFI_NOT_FOUND No descriptor for the desired space exists.
1041 @retval EFI_SUCCESS Space successfully allocated.
1042
1043 **/
1044 EFI_STATUS
1045 CoreAllocateSpace (
1046 IN UINTN Operation,
1047 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
1048 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1049 IN EFI_GCD_IO_TYPE GcdIoType,
1050 IN UINTN Alignment,
1051 IN UINT64 Length,
1052 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
1053 IN EFI_HANDLE ImageHandle,
1054 IN EFI_HANDLE DeviceHandle OPTIONAL
1055 )
1056 {
1057 EFI_STATUS Status;
1058 EFI_PHYSICAL_ADDRESS AlignmentMask;
1059 EFI_PHYSICAL_ADDRESS MaxAddress;
1060 LIST_ENTRY *Map;
1061 LIST_ENTRY *Link;
1062 LIST_ENTRY *SubLink;
1063 EFI_GCD_MAP_ENTRY *Entry;
1064 EFI_GCD_MAP_ENTRY *TopEntry;
1065 EFI_GCD_MAP_ENTRY *BottomEntry;
1066 LIST_ENTRY *StartLink;
1067 LIST_ENTRY *EndLink;
1068 BOOLEAN Found;
1069
1070 //
1071 // Make sure parameters are valid
1072 //
1073 if ((UINT32)GcdAllocateType >= EfiGcdMaxAllocateType) {
1074 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1075 return EFI_INVALID_PARAMETER;
1076 }
1077 if ((UINT32)GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
1078 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1079 return EFI_INVALID_PARAMETER;
1080 }
1081 if ((UINT32)GcdIoType >= EfiGcdIoTypeMaximum) {
1082 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1083 return EFI_INVALID_PARAMETER;
1084 }
1085 if (BaseAddress == NULL) {
1086 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1087 return EFI_INVALID_PARAMETER;
1088 }
1089 if (ImageHandle == NULL) {
1090 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1091 return EFI_INVALID_PARAMETER;
1092 }
1093 if (Alignment >= 64) {
1094 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_NOT_FOUND));
1095 return EFI_NOT_FOUND;
1096 }
1097 if (Length == 0) {
1098 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1099 return EFI_INVALID_PARAMETER;
1100 }
1101
1102 Map = NULL;
1103 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
1104 CoreAcquireGcdMemoryLock ();
1105 Map = &mGcdMemorySpaceMap;
1106 } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
1107 CoreAcquireGcdIoLock ();
1108 Map = &mGcdIoSpaceMap;
1109 } else {
1110 ASSERT (FALSE);
1111 }
1112
1113 Found = FALSE;
1114 StartLink = NULL;
1115 EndLink = NULL;
1116 //
1117 // Compute alignment bit mask
1118 //
1119 AlignmentMask = LShiftU64 (1, Alignment) - 1;
1120
1121 if (GcdAllocateType == EfiGcdAllocateAddress) {
1122 //
1123 // Verify that the BaseAddress passed in is aligned correctly
1124 //
1125 if ((*BaseAddress & AlignmentMask) != 0) {
1126 Status = EFI_NOT_FOUND;
1127 goto Done;
1128 }
1129
1130 //
1131 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
1132 //
1133 Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
1134 if (EFI_ERROR (Status)) {
1135 Status = EFI_NOT_FOUND;
1136 goto Done;
1137 }
1138 ASSERT (StartLink != NULL && EndLink != NULL);
1139
1140 //
1141 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1142 //
1143 Link = StartLink;
1144 while (Link != EndLink->ForwardLink) {
1145 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1146 Link = Link->ForwardLink;
1147 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
1148 if (EFI_ERROR (Status)) {
1149 goto Done;
1150 }
1151 }
1152 Found = TRUE;
1153 } else {
1154
1155 Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1156
1157 //
1158 // Compute the maximum address to use in the search algorithm
1159 //
1160 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp ||
1161 GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ) {
1162 MaxAddress = *BaseAddress;
1163 } else {
1164 MaxAddress = Entry->EndAddress;
1165 }
1166
1167 //
1168 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1169 //
1170 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
1171 GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
1172 Link = Map->BackLink;
1173 } else {
1174 Link = Map->ForwardLink;
1175 }
1176 while (Link != Map) {
1177 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1178
1179 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
1180 GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
1181 Link = Link->BackLink;
1182 } else {
1183 Link = Link->ForwardLink;
1184 }
1185
1186 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
1187 if (EFI_ERROR (Status)) {
1188 continue;
1189 }
1190
1191 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
1192 GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
1193 if ((Entry->BaseAddress + Length) > MaxAddress) {
1194 continue;
1195 }
1196 if (Length > (Entry->EndAddress + 1)) {
1197 Status = EFI_NOT_FOUND;
1198 goto Done;
1199 }
1200 if (Entry->EndAddress > MaxAddress) {
1201 *BaseAddress = MaxAddress;
1202 } else {
1203 *BaseAddress = Entry->EndAddress;
1204 }
1205 *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
1206 } else {
1207 *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
1208 if ((*BaseAddress + Length - 1) > MaxAddress) {
1209 Status = EFI_NOT_FOUND;
1210 goto Done;
1211 }
1212 }
1213
1214 //
1215 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
1216 //
1217 Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
1218 if (EFI_ERROR (Status)) {
1219 Status = EFI_NOT_FOUND;
1220 goto Done;
1221 }
1222 ASSERT (StartLink != NULL && EndLink != NULL);
1223
1224 Link = StartLink;
1225 //
1226 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1227 //
1228 Found = TRUE;
1229 SubLink = StartLink;
1230 while (SubLink != EndLink->ForwardLink) {
1231 Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1232 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
1233 if (EFI_ERROR (Status)) {
1234 Link = SubLink;
1235 Found = FALSE;
1236 break;
1237 }
1238 SubLink = SubLink->ForwardLink;
1239 }
1240 if (Found) {
1241 break;
1242 }
1243 }
1244 }
1245 if (!Found) {
1246 Status = EFI_NOT_FOUND;
1247 goto Done;
1248 }
1249
1250 //
1251 // Allocate work space to perform this operation
1252 //
1253 Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
1254 if (EFI_ERROR (Status)) {
1255 Status = EFI_OUT_OF_RESOURCES;
1256 goto Done;
1257 }
1258 ASSERT (TopEntry != NULL && BottomEntry != NULL);
1259
1260 //
1261 // Convert/Insert the list of descriptors from StartLink to EndLink
1262 //
1263 Link = StartLink;
1264 while (Link != EndLink->ForwardLink) {
1265 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1266 CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
1267 Entry->ImageHandle = ImageHandle;
1268 Entry->DeviceHandle = DeviceHandle;
1269 Link = Link->ForwardLink;
1270 }
1271
1272 //
1273 // Cleanup
1274 //
1275 Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
1276
1277 Done:
1278 DEBUG ((DEBUG_GCD, " Status = %r", Status));
1279 if (!EFI_ERROR (Status)) {
1280 DEBUG ((DEBUG_GCD, " (BaseAddress = %016lx)", *BaseAddress));
1281 }
1282 DEBUG ((DEBUG_GCD, "\n"));
1283
1284 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
1285 CoreReleaseGcdMemoryLock ();
1286 CoreDumpGcdMemorySpaceMap (FALSE);
1287 }
1288 if ((Operation & GCD_IO_SPACE_OPERATION) !=0) {
1289 CoreReleaseGcdIoLock ();
1290 CoreDumpGcdIoSpaceMap (FALSE);
1291 }
1292
1293 return Status;
1294 }
1295
1296
1297 /**
1298 Add a segment of memory to GCD map.
1299
1300 @param GcdMemoryType Memory type of the segment.
1301 @param BaseAddress Base address of the segment.
1302 @param Length Length of the segment.
1303 @param Capabilities alterable attributes of the segment.
1304
1305 @retval EFI_INVALID_PARAMETER Invalid parameters.
1306 @retval EFI_SUCCESS Successfully add a segment of memory space.
1307
1308 **/
1309 EFI_STATUS
1310 CoreInternalAddMemorySpace (
1311 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1312 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1313 IN UINT64 Length,
1314 IN UINT64 Capabilities
1315 )
1316 {
1317 DEBUG ((DEBUG_GCD, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1318 DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
1319 DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
1320
1321 //
1322 // Make sure parameters are valid
1323 //
1324 if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
1325 return EFI_INVALID_PARAMETER;
1326 }
1327
1328 return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
1329 }
1330
1331 //
1332 // GCD Core Services
1333 //
1334
1335 /**
1336 Allocates nonexistent memory, reserved memory, system memory, or memorymapped
1337 I/O resources from the global coherency domain of the processor.
1338
1339 @param GcdAllocateType The type of allocate operation
1340 @param GcdMemoryType The desired memory type
1341 @param Alignment Align with 2^Alignment
1342 @param Length Length to allocate
1343 @param BaseAddress Base address to allocate
1344 @param ImageHandle The image handle consume the allocated space.
1345 @param DeviceHandle The device handle consume the allocated space.
1346
1347 @retval EFI_INVALID_PARAMETER Invalid parameter.
1348 @retval EFI_NOT_FOUND No descriptor contains the desired space.
1349 @retval EFI_SUCCESS Memory space successfully allocated.
1350
1351 **/
1352 EFI_STATUS
1353 EFIAPI
1354 CoreAllocateMemorySpace (
1355 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
1356 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1357 IN UINTN Alignment,
1358 IN UINT64 Length,
1359 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
1360 IN EFI_HANDLE ImageHandle,
1361 IN EFI_HANDLE DeviceHandle OPTIONAL
1362 )
1363 {
1364 if (BaseAddress != NULL) {
1365 DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
1366 } else {
1367 DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=<NULL>,Length=%016lx)\n", Length));
1368 }
1369 DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
1370 DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
1371 DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
1372 DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
1373 DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
1374
1375 return CoreAllocateSpace (
1376 GCD_ALLOCATE_MEMORY_OPERATION,
1377 GcdAllocateType,
1378 GcdMemoryType,
1379 (EFI_GCD_IO_TYPE) 0,
1380 Alignment,
1381 Length,
1382 BaseAddress,
1383 ImageHandle,
1384 DeviceHandle
1385 );
1386 }
1387
1388
1389 /**
1390 Adds reserved memory, system memory, or memory-mapped I/O resources to the
1391 global coherency domain of the processor.
1392
1393 @param GcdMemoryType Memory type of the memory space.
1394 @param BaseAddress Base address of the memory space.
1395 @param Length Length of the memory space.
1396 @param Capabilities alterable attributes of the memory space.
1397
1398 @retval EFI_SUCCESS Merged this memory space into GCD map.
1399
1400 **/
1401 EFI_STATUS
1402 EFIAPI
1403 CoreAddMemorySpace (
1404 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1405 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1406 IN UINT64 Length,
1407 IN UINT64 Capabilities
1408 )
1409 {
1410 EFI_STATUS Status;
1411 EFI_PHYSICAL_ADDRESS PageBaseAddress;
1412 UINT64 PageLength;
1413
1414 Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);
1415
1416 if (!EFI_ERROR (Status) && ((GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
1417
1418 PageBaseAddress = PageAlignAddress (BaseAddress);
1419 PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress);
1420
1421 Status = CoreAllocateMemorySpace (
1422 EfiGcdAllocateAddress,
1423 GcdMemoryType,
1424 EFI_PAGE_SHIFT,
1425 PageLength,
1426 &PageBaseAddress,
1427 gDxeCoreImageHandle,
1428 NULL
1429 );
1430
1431 if (!EFI_ERROR (Status)) {
1432 CoreAddMemoryDescriptor (
1433 EfiConventionalMemory,
1434 PageBaseAddress,
1435 RShiftU64 (PageLength, EFI_PAGE_SHIFT),
1436 Capabilities
1437 );
1438 } else {
1439 for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
1440 Status = CoreAllocateMemorySpace (
1441 EfiGcdAllocateAddress,
1442 GcdMemoryType,
1443 EFI_PAGE_SHIFT,
1444 EFI_PAGE_SIZE,
1445 &PageBaseAddress,
1446 gDxeCoreImageHandle,
1447 NULL
1448 );
1449
1450 if (!EFI_ERROR (Status)) {
1451 CoreAddMemoryDescriptor (
1452 EfiConventionalMemory,
1453 PageBaseAddress,
1454 1,
1455 Capabilities
1456 );
1457 }
1458 }
1459 }
1460 }
1461 return Status;
1462 }
1463
1464
1465 /**
1466 Frees nonexistent memory, reserved memory, system memory, or memory-mapped
1467 I/O resources from the global coherency domain of the processor.
1468
1469 @param BaseAddress Base address of the memory space.
1470 @param Length Length of the memory space.
1471
1472 @retval EFI_SUCCESS Space successfully freed.
1473
1474 **/
1475 EFI_STATUS
1476 EFIAPI
1477 CoreFreeMemorySpace (
1478 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1479 IN UINT64 Length
1480 )
1481 {
1482 DEBUG ((DEBUG_GCD, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1483
1484 return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1485 }
1486
1487
1488 /**
1489 Removes reserved memory, system memory, or memory-mapped I/O resources from
1490 the global coherency domain of the processor.
1491
1492 @param BaseAddress Base address of the memory space.
1493 @param Length Length of the memory space.
1494
1495 @retval EFI_SUCCESS Successfully remove a segment of memory space.
1496
1497 **/
1498 EFI_STATUS
1499 EFIAPI
1500 CoreRemoveMemorySpace (
1501 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1502 IN UINT64 Length
1503 )
1504 {
1505 DEBUG ((DEBUG_GCD, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1506
1507 return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1508 }
1509
1510
1511 /**
1512 Build a memory descriptor according to an entry.
1513
1514 @param Descriptor The descriptor to be built
1515 @param Entry According to this entry
1516
1517 **/
1518 VOID
1519 BuildMemoryDescriptor (
1520 IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor,
1521 IN EFI_GCD_MAP_ENTRY *Entry
1522 )
1523 {
1524 Descriptor->BaseAddress = Entry->BaseAddress;
1525 Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
1526 Descriptor->Capabilities = Entry->Capabilities;
1527 Descriptor->Attributes = Entry->Attributes;
1528 Descriptor->GcdMemoryType = Entry->GcdMemoryType;
1529 Descriptor->ImageHandle = Entry->ImageHandle;
1530 Descriptor->DeviceHandle = Entry->DeviceHandle;
1531 }
1532
1533
1534 /**
1535 Retrieves the descriptor for a memory region containing a specified address.
1536
1537 @param BaseAddress Specified start address
1538 @param Descriptor Specified length
1539
1540 @retval EFI_INVALID_PARAMETER Invalid parameter
1541 @retval EFI_SUCCESS Successfully get memory space descriptor.
1542
1543 **/
1544 EFI_STATUS
1545 EFIAPI
1546 CoreGetMemorySpaceDescriptor (
1547 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1548 OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
1549 )
1550 {
1551 EFI_STATUS Status;
1552 LIST_ENTRY *StartLink;
1553 LIST_ENTRY *EndLink;
1554 EFI_GCD_MAP_ENTRY *Entry;
1555
1556 //
1557 // Make sure parameters are valid
1558 //
1559 if (Descriptor == NULL) {
1560 return EFI_INVALID_PARAMETER;
1561 }
1562
1563 CoreAcquireGcdMemoryLock ();
1564
1565 //
1566 // Search for the list of descriptors that contain BaseAddress
1567 //
1568 Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);
1569 if (EFI_ERROR (Status)) {
1570 Status = EFI_NOT_FOUND;
1571 } else {
1572 ASSERT (StartLink != NULL && EndLink != NULL);
1573 //
1574 // Copy the contents of the found descriptor into Descriptor
1575 //
1576 Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1577 BuildMemoryDescriptor (Descriptor, Entry);
1578 }
1579
1580 CoreReleaseGcdMemoryLock ();
1581
1582 return Status;
1583 }
1584
1585
1586 /**
1587 Modifies the attributes for a memory region in the global coherency domain of the
1588 processor.
1589
1590 @param BaseAddress Specified start address
1591 @param Length Specified length
1592 @param Attributes Specified attributes
1593
1594 @retval EFI_SUCCESS The attributes were set for the memory region.
1595 @retval EFI_INVALID_PARAMETER Length is zero.
1596 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
1597 resource range specified by BaseAddress and Length.
1598 @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
1599 range specified by BaseAddress and Length.
1600 @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
1601 BaseAddress and Length cannot be modified.
1602 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
1603 the memory resource range.
1604 @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
1605 not available yet.
1606
1607 **/
1608 EFI_STATUS
1609 EFIAPI
1610 CoreSetMemorySpaceAttributes (
1611 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1612 IN UINT64 Length,
1613 IN UINT64 Attributes
1614 )
1615 {
1616 DEBUG ((DEBUG_GCD, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1617 DEBUG ((DEBUG_GCD, " Attributes = %016lx\n", Attributes));
1618
1619 return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, Attributes);
1620 }
1621
1622
1623 /**
1624 Modifies the capabilities for a memory region in the global coherency domain of the
1625 processor.
1626
1627 @param BaseAddress The physical address that is the start address of a memory region.
1628 @param Length The size in bytes of the memory region.
1629 @param Capabilities The bit mask of capabilities that the memory region supports.
1630
1631 @retval EFI_SUCCESS The capabilities were set for the memory region.
1632 @retval EFI_INVALID_PARAMETER Length is zero.
1633 @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
1634 memory region attributes currently in use.
1635 @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
1636 BaseAddress and Length cannot be modified.
1637 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
1638 of the memory resource range.
1639 **/
1640 EFI_STATUS
1641 EFIAPI
1642 CoreSetMemorySpaceCapabilities (
1643 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1644 IN UINT64 Length,
1645 IN UINT64 Capabilities
1646 )
1647 {
1648 EFI_STATUS Status;
1649
1650 DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1651 DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
1652
1653 Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
1654 if (!EFI_ERROR(Status)) {
1655 CoreUpdateMemoryAttributes(BaseAddress, RShiftU64(Length, EFI_PAGE_SHIFT), Capabilities & (~EFI_MEMORY_RUNTIME));
1656 }
1657
1658 return Status;
1659 }
1660
1661
1662 /**
1663 Returns a map of the memory resources in the global coherency domain of the
1664 processor.
1665
1666 @param NumberOfDescriptors Number of descriptors.
1667 @param MemorySpaceMap Descriptor array
1668
1669 @retval EFI_INVALID_PARAMETER Invalid parameter
1670 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1671 @retval EFI_SUCCESS Successfully get memory space map.
1672
1673 **/
1674 EFI_STATUS
1675 EFIAPI
1676 CoreGetMemorySpaceMap (
1677 OUT UINTN *NumberOfDescriptors,
1678 OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
1679 )
1680 {
1681 LIST_ENTRY *Link;
1682 EFI_GCD_MAP_ENTRY *Entry;
1683 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor;
1684 UINTN DescriptorCount;
1685
1686 //
1687 // Make sure parameters are valid
1688 //
1689 if (NumberOfDescriptors == NULL) {
1690 return EFI_INVALID_PARAMETER;
1691 }
1692 if (MemorySpaceMap == NULL) {
1693 return EFI_INVALID_PARAMETER;
1694 }
1695
1696 *NumberOfDescriptors = 0;
1697 *MemorySpaceMap = NULL;
1698
1699 //
1700 // Take the lock, for entering the loop with the lock held.
1701 //
1702 CoreAcquireGcdMemoryLock ();
1703 while (TRUE) {
1704 //
1705 // Count descriptors. It might be done more than once because the
1706 // AllocatePool() called below has to be running outside the GCD lock.
1707 //
1708 DescriptorCount = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);
1709 if (DescriptorCount == *NumberOfDescriptors && *MemorySpaceMap != NULL) {
1710 //
1711 // Fill in the MemorySpaceMap if no memory space map change.
1712 //
1713 Descriptor = *MemorySpaceMap;
1714 Link = mGcdMemorySpaceMap.ForwardLink;
1715 while (Link != &mGcdMemorySpaceMap) {
1716 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1717 BuildMemoryDescriptor (Descriptor, Entry);
1718 Descriptor++;
1719 Link = Link->ForwardLink;
1720 }
1721 //
1722 // We're done; exit the loop with the lock held.
1723 //
1724 break;
1725 }
1726
1727 //
1728 // Release the lock before memory allocation, because it might cause
1729 // GCD lock conflict in one of calling path in AllocatPool().
1730 //
1731 CoreReleaseGcdMemoryLock ();
1732
1733 //
1734 // Allocate memory to store the MemorySpaceMap. Note it might be already
1735 // allocated if there's map descriptor change during memory allocation at
1736 // last time.
1737 //
1738 if (*MemorySpaceMap != NULL) {
1739 FreePool (*MemorySpaceMap);
1740 }
1741
1742 *MemorySpaceMap = AllocatePool (DescriptorCount *
1743 sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
1744 if (*MemorySpaceMap == NULL) {
1745 *NumberOfDescriptors = 0;
1746 return EFI_OUT_OF_RESOURCES;
1747 }
1748
1749 //
1750 // Save the descriptor count got before for another round of check to make
1751 // sure we won't miss any, since we have code running outside the GCD lock.
1752 //
1753 *NumberOfDescriptors = DescriptorCount;
1754 //
1755 // Re-acquire the lock, for the next iteration.
1756 //
1757 CoreAcquireGcdMemoryLock ();
1758 }
1759 //
1760 // We exited the loop with the lock held, release it.
1761 //
1762 CoreReleaseGcdMemoryLock ();
1763
1764 return EFI_SUCCESS;
1765 }
1766
1767
1768 /**
1769 Adds reserved I/O or I/O resources to the global coherency domain of the processor.
1770
1771 @param GcdIoType IO type of the segment.
1772 @param BaseAddress Base address of the segment.
1773 @param Length Length of the segment.
1774
1775 @retval EFI_SUCCESS Merged this segment into GCD map.
1776 @retval EFI_INVALID_PARAMETER Parameter not valid
1777
1778 **/
1779 EFI_STATUS
1780 EFIAPI
1781 CoreAddIoSpace (
1782 IN EFI_GCD_IO_TYPE GcdIoType,
1783 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1784 IN UINT64 Length
1785 )
1786 {
1787 DEBUG ((DEBUG_GCD, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1788 DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
1789
1790 //
1791 // Make sure parameters are valid
1792 //
1793 if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) {
1794 return EFI_INVALID_PARAMETER;
1795 }
1796 return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, GcdIoType, BaseAddress, Length, 0, 0);
1797 }
1798
1799
1800 /**
1801 Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
1802 domain of the processor.
1803
1804 @param GcdAllocateType The type of allocate operation
1805 @param GcdIoType The desired IO type
1806 @param Alignment Align with 2^Alignment
1807 @param Length Length to allocate
1808 @param BaseAddress Base address to allocate
1809 @param ImageHandle The image handle consume the allocated space.
1810 @param DeviceHandle The device handle consume the allocated space.
1811
1812 @retval EFI_INVALID_PARAMETER Invalid parameter.
1813 @retval EFI_NOT_FOUND No descriptor contains the desired space.
1814 @retval EFI_SUCCESS IO space successfully allocated.
1815
1816 **/
1817 EFI_STATUS
1818 EFIAPI
1819 CoreAllocateIoSpace (
1820 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
1821 IN EFI_GCD_IO_TYPE GcdIoType,
1822 IN UINTN Alignment,
1823 IN UINT64 Length,
1824 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
1825 IN EFI_HANDLE ImageHandle,
1826 IN EFI_HANDLE DeviceHandle OPTIONAL
1827 )
1828 {
1829 if (BaseAddress != NULL) {
1830 DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
1831 } else {
1832 DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=<NULL>,Length=%016lx)\n", Length));
1833 }
1834 DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
1835 DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
1836 DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
1837 DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
1838 DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
1839
1840 return CoreAllocateSpace (
1841 GCD_ALLOCATE_IO_OPERATION,
1842 GcdAllocateType,
1843 (EFI_GCD_MEMORY_TYPE) 0,
1844 GcdIoType,
1845 Alignment,
1846 Length,
1847 BaseAddress,
1848 ImageHandle,
1849 DeviceHandle
1850 );
1851 }
1852
1853
1854 /**
1855 Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
1856 domain of the processor.
1857
1858 @param BaseAddress Base address of the segment.
1859 @param Length Length of the segment.
1860
1861 @retval EFI_SUCCESS Space successfully freed.
1862
1863 **/
1864 EFI_STATUS
1865 EFIAPI
1866 CoreFreeIoSpace (
1867 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1868 IN UINT64 Length
1869 )
1870 {
1871 DEBUG ((DEBUG_GCD, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1872
1873 return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1874 }
1875
1876
1877 /**
1878 Removes reserved I/O or I/O resources from the global coherency domain of the
1879 processor.
1880
1881 @param BaseAddress Base address of the segment.
1882 @param Length Length of the segment.
1883
1884 @retval EFI_SUCCESS Successfully removed a segment of IO space.
1885
1886 **/
1887 EFI_STATUS
1888 EFIAPI
1889 CoreRemoveIoSpace (
1890 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1891 IN UINT64 Length
1892 )
1893 {
1894 DEBUG ((DEBUG_GCD, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1895
1896 return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1897 }
1898
1899
1900 /**
1901 Build a IO descriptor according to an entry.
1902
1903 @param Descriptor The descriptor to be built
1904 @param Entry According to this entry
1905
1906 **/
1907 VOID
1908 BuildIoDescriptor (
1909 IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor,
1910 IN EFI_GCD_MAP_ENTRY *Entry
1911 )
1912 {
1913 Descriptor->BaseAddress = Entry->BaseAddress;
1914 Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
1915 Descriptor->GcdIoType = Entry->GcdIoType;
1916 Descriptor->ImageHandle = Entry->ImageHandle;
1917 Descriptor->DeviceHandle = Entry->DeviceHandle;
1918 }
1919
1920
1921 /**
1922 Retrieves the descriptor for an I/O region containing a specified address.
1923
1924 @param BaseAddress Specified start address
1925 @param Descriptor Specified length
1926
1927 @retval EFI_INVALID_PARAMETER Descriptor is NULL.
1928 @retval EFI_SUCCESS Successfully get the IO space descriptor.
1929
1930 **/
1931 EFI_STATUS
1932 EFIAPI
1933 CoreGetIoSpaceDescriptor (
1934 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1935 OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
1936 )
1937 {
1938 EFI_STATUS Status;
1939 LIST_ENTRY *StartLink;
1940 LIST_ENTRY *EndLink;
1941 EFI_GCD_MAP_ENTRY *Entry;
1942
1943 //
1944 // Make sure parameters are valid
1945 //
1946 if (Descriptor == NULL) {
1947 return EFI_INVALID_PARAMETER;
1948 }
1949
1950 CoreAcquireGcdIoLock ();
1951
1952 //
1953 // Search for the list of descriptors that contain BaseAddress
1954 //
1955 Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);
1956 if (EFI_ERROR (Status)) {
1957 Status = EFI_NOT_FOUND;
1958 } else {
1959 ASSERT (StartLink != NULL && EndLink != NULL);
1960 //
1961 // Copy the contents of the found descriptor into Descriptor
1962 //
1963 Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1964 BuildIoDescriptor (Descriptor, Entry);
1965 }
1966
1967 CoreReleaseGcdIoLock ();
1968
1969 return Status;
1970 }
1971
1972
1973 /**
1974 Returns a map of the I/O resources in the global coherency domain of the processor.
1975
1976 @param NumberOfDescriptors Number of descriptors.
1977 @param IoSpaceMap Descriptor array
1978
1979 @retval EFI_INVALID_PARAMETER Invalid parameter
1980 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1981 @retval EFI_SUCCESS Successfully get IO space map.
1982
1983 **/
1984 EFI_STATUS
1985 EFIAPI
1986 CoreGetIoSpaceMap (
1987 OUT UINTN *NumberOfDescriptors,
1988 OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
1989 )
1990 {
1991 EFI_STATUS Status;
1992 LIST_ENTRY *Link;
1993 EFI_GCD_MAP_ENTRY *Entry;
1994 EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor;
1995
1996 //
1997 // Make sure parameters are valid
1998 //
1999 if (NumberOfDescriptors == NULL) {
2000 return EFI_INVALID_PARAMETER;
2001 }
2002 if (IoSpaceMap == NULL) {
2003 return EFI_INVALID_PARAMETER;
2004 }
2005
2006 CoreAcquireGcdIoLock ();
2007
2008 //
2009 // Count the number of descriptors
2010 //
2011 *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);
2012
2013 //
2014 // Allocate the IoSpaceMap
2015 //
2016 *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));
2017 if (*IoSpaceMap == NULL) {
2018 Status = EFI_OUT_OF_RESOURCES;
2019 goto Done;
2020 }
2021
2022 //
2023 // Fill in the IoSpaceMap
2024 //
2025 Descriptor = *IoSpaceMap;
2026 Link = mGcdIoSpaceMap.ForwardLink;
2027 while (Link != &mGcdIoSpaceMap) {
2028 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
2029 BuildIoDescriptor (Descriptor, Entry);
2030 Descriptor++;
2031 Link = Link->ForwardLink;
2032 }
2033 Status = EFI_SUCCESS;
2034
2035 Done:
2036 CoreReleaseGcdIoLock ();
2037 return Status;
2038 }
2039
2040
2041 /**
2042 Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
2043 capabilities mask
2044
2045 @param GcdMemoryType Type of resource in the GCD memory map.
2046 @param Attributes The attribute mask in the Resource Descriptor
2047 HOB.
2048
2049 @return The capabilities mask for an EFI Memory Descriptor.
2050
2051 **/
2052 UINT64
2053 CoreConvertResourceDescriptorHobAttributesToCapabilities (
2054 EFI_GCD_MEMORY_TYPE GcdMemoryType,
2055 UINT64 Attributes
2056 )
2057 {
2058 UINT64 Capabilities;
2059 GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion;
2060
2061 //
2062 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2063 //
2064 for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {
2065 if (Conversion->Memory || ((GcdMemoryType != EfiGcdMemoryTypeSystemMemory) && (GcdMemoryType != EfiGcdMemoryTypeMoreReliable))) {
2066 if (Attributes & Conversion->Attribute) {
2067 Capabilities |= Conversion->Capability;
2068 }
2069 }
2070 }
2071
2072 return Capabilities;
2073 }
2074
2075 /**
2076 Calculate total memory bin size neeeded.
2077
2078 @return The total memory bin size neeeded.
2079
2080 **/
2081 UINT64
2082 CalculateTotalMemoryBinSizeNeeded (
2083 VOID
2084 )
2085 {
2086 UINTN Index;
2087 UINT64 TotalSize;
2088
2089 //
2090 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
2091 //
2092 TotalSize = 0;
2093 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
2094 TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);
2095 }
2096
2097 return TotalSize;
2098 }
2099
2100 /**
2101 Find the largest region in the specified region that is not covered by an existing memory allocation
2102
2103 @param BaseAddress On input start of the region to check.
2104 On output start of the largest free region.
2105 @param Length On input size of region to check.
2106 On output size of the largest free region.
2107 @param MemoryHob Hob pointer for the first memory allocation pointer to check
2108 **/
2109 VOID
2110 FindLargestFreeRegion (
2111 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
2112 IN OUT UINT64 *Length,
2113 IN EFI_HOB_MEMORY_ALLOCATION *MemoryHob
2114 )
2115 {
2116 EFI_PHYSICAL_ADDRESS TopAddress;
2117 EFI_PHYSICAL_ADDRESS AllocatedTop;
2118 EFI_PHYSICAL_ADDRESS LowerBase;
2119 UINT64 LowerSize;
2120 EFI_PHYSICAL_ADDRESS UpperBase;
2121 UINT64 UpperSize;
2122
2123 TopAddress = *BaseAddress + *Length;
2124 while (MemoryHob != NULL) {
2125 AllocatedTop = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
2126
2127 if ((MemoryHob->AllocDescriptor.MemoryBaseAddress >= *BaseAddress) &&
2128 (AllocatedTop <= TopAddress)) {
2129 LowerBase = *BaseAddress;
2130 LowerSize = MemoryHob->AllocDescriptor.MemoryBaseAddress - *BaseAddress;
2131 UpperBase = AllocatedTop;
2132 UpperSize = TopAddress - AllocatedTop;
2133
2134 if (LowerSize != 0) {
2135 FindLargestFreeRegion (&LowerBase, &LowerSize, (EFI_HOB_MEMORY_ALLOCATION *) GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob)));
2136 }
2137 if (UpperSize != 0) {
2138 FindLargestFreeRegion (&UpperBase, &UpperSize, (EFI_HOB_MEMORY_ALLOCATION *) GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob)));
2139 }
2140
2141 if (UpperSize >= LowerSize) {
2142 *Length = UpperSize;
2143 *BaseAddress = UpperBase;
2144 } else {
2145 *Length = LowerSize;
2146 *BaseAddress = LowerBase;
2147 }
2148 return;
2149 }
2150 MemoryHob = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, GET_NEXT_HOB (MemoryHob));
2151 }
2152 }
2153
2154 /**
2155 External function. Initializes memory services based on the memory
2156 descriptor HOBs. This function is responsible for priming the memory
2157 map, so memory allocations and resource allocations can be made.
2158 The first part of this function can not depend on any memory services
2159 until at least one memory descriptor is provided to the memory services.
2160
2161 @param HobStart The start address of the HOB.
2162 @param MemoryBaseAddress Start address of memory region found to init DXE
2163 core.
2164 @param MemoryLength Length of memory region found to init DXE core.
2165
2166 @retval EFI_SUCCESS Memory services successfully initialized.
2167
2168 **/
2169 EFI_STATUS
2170 CoreInitializeMemoryServices (
2171 IN VOID **HobStart,
2172 OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
2173 OUT UINT64 *MemoryLength
2174 )
2175 {
2176 EFI_PEI_HOB_POINTERS Hob;
2177 EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
2178 UINTN DataSize;
2179 BOOLEAN Found;
2180 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
2181 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
2182 EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
2183 EFI_PHYSICAL_ADDRESS BaseAddress;
2184 UINT64 Length;
2185 UINT64 Attributes;
2186 UINT64 Capabilities;
2187 EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress;
2188 UINT64 TestedMemoryLength;
2189 EFI_PHYSICAL_ADDRESS HighAddress;
2190 EFI_HOB_GUID_TYPE *GuidHob;
2191 UINT32 ReservedCodePageNumber;
2192 UINT64 MinimalMemorySizeNeeded;
2193
2194 //
2195 // Point at the first HOB. This must be the PHIT HOB.
2196 //
2197 Hob.Raw = *HobStart;
2198 ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
2199
2200 //
2201 // Initialize the spin locks and maps in the memory services.
2202 // Also fill in the memory services into the EFI Boot Services Table
2203 //
2204 CoreInitializePool ();
2205
2206 //
2207 // Initialize Local Variables
2208 //
2209 PhitResourceHob = NULL;
2210 ResourceHob = NULL;
2211 BaseAddress = 0;
2212 Length = 0;
2213 Attributes = 0;
2214
2215 //
2216 // Cache the PHIT HOB for later use
2217 //
2218 PhitHob = Hob.HandoffInformationTable;
2219
2220 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
2221 ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
2222 ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
2223
2224 //
2225 // cache the Top address for loading modules at Fixed Address
2226 //
2227 gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
2228 + EFI_PAGES_TO_SIZE(ReservedCodePageNumber);
2229 }
2230 //
2231 // See if a Memory Type Information HOB is available
2232 //
2233 GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
2234 if (GuidHob != NULL) {
2235 EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
2236 DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
2237 if (EfiMemoryTypeInformation != NULL && DataSize > 0 && DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION)) {
2238 CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);
2239 }
2240 }
2241
2242 //
2243 // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
2244 //
2245 MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
2246
2247 //
2248 // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
2249 //
2250 Found = FALSE;
2251 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2252 //
2253 // Skip all HOBs except Resource Descriptor HOBs
2254 //
2255 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
2256 continue;
2257 }
2258
2259 //
2260 // Skip Resource Descriptor HOBs that do not describe tested system memory
2261 //
2262 ResourceHob = Hob.ResourceDescriptor;
2263 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
2264 continue;
2265 }
2266 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
2267 continue;
2268 }
2269
2270 //
2271 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
2272 //
2273 if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {
2274 continue;
2275 }
2276 if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
2277 continue;
2278 }
2279
2280 //
2281 // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
2282 //
2283 PhitResourceHob = ResourceHob;
2284 Found = TRUE;
2285
2286 //
2287 // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB
2288 //
2289 Attributes = PhitResourceHob->ResourceAttribute;
2290 BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
2291 Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
2292 FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
2293 if (Length < MinimalMemorySizeNeeded) {
2294 //
2295 // If that range is not large enough to intialize the DXE Core, then
2296 // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop
2297 //
2298 BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);
2299 Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);
2300 //This region is required to have no memory allocation inside it, skip check for entries in HOB List
2301 if (Length < MinimalMemorySizeNeeded) {
2302 //
2303 // If that range is not large enough to intialize the DXE Core, then
2304 // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List
2305 //
2306 BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
2307 Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));
2308 FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
2309 }
2310 }
2311 break;
2312 }
2313
2314 //
2315 // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
2316 //
2317 ASSERT (Found);
2318
2319 //
2320 // Take the range in the resource descriptor HOB for the memory region described
2321 // by the PHIT as higher priority if it is big enough. It can make the memory bin
2322 // allocated to be at the same memory region with PHIT that has more better compatibility
2323 // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.
2324 //
2325 if (Length < MinimalMemorySizeNeeded) {
2326 //
2327 // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
2328 // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB.
2329 // The max address must be within the physically addressible range for the processor.
2330 //
2331 HighAddress = MAX_ALLOC_ADDRESS;
2332 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2333 //
2334 // Skip the Resource Descriptor HOB that contains the PHIT
2335 //
2336 if (Hob.ResourceDescriptor == PhitResourceHob) {
2337 continue;
2338 }
2339 //
2340 // Skip all HOBs except Resource Descriptor HOBs
2341 //
2342 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
2343 continue;
2344 }
2345
2346 //
2347 // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ALLOC_ADDRESS
2348 //
2349 ResourceHob = Hob.ResourceDescriptor;
2350 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
2351 continue;
2352 }
2353 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
2354 continue;
2355 }
2356 if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) {
2357 continue;
2358 }
2359
2360 //
2361 // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB
2362 //
2363 if (HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS && ResourceHob->PhysicalStart <= HighAddress) {
2364 continue;
2365 }
2366
2367 //
2368 // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core
2369 //
2370 TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
2371 TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
2372 FindLargestFreeRegion (&TestedMemoryBaseAddress, &TestedMemoryLength, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));
2373 if (TestedMemoryLength < MinimalMemorySizeNeeded) {
2374 continue;
2375 }
2376
2377 //
2378 // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core
2379 //
2380 BaseAddress = TestedMemoryBaseAddress;
2381 Length = TestedMemoryLength;
2382 Attributes = ResourceHob->ResourceAttribute;
2383 HighAddress = ResourceHob->PhysicalStart;
2384 }
2385 }
2386
2387 DEBUG ((DEBUG_INFO, "CoreInitializeMemoryServices:\n"));
2388 DEBUG ((DEBUG_INFO, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded));
2389
2390 //
2391 // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
2392 //
2393 ASSERT (Length >= MinimalMemorySizeNeeded);
2394
2395 //
2396 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2397 //
2398 if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
2399 Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
2400 } else {
2401 Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
2402 }
2403
2404 //
2405 // Declare the very first memory region, so the EFI Memory Services are available.
2406 //
2407 CoreAddMemoryDescriptor (
2408 EfiConventionalMemory,
2409 BaseAddress,
2410 RShiftU64 (Length, EFI_PAGE_SHIFT),
2411 Capabilities
2412 );
2413
2414 *MemoryBaseAddress = BaseAddress;
2415 *MemoryLength = Length;
2416
2417 return EFI_SUCCESS;
2418 }
2419
2420
2421 /**
2422 External function. Initializes the GCD and memory services based on the memory
2423 descriptor HOBs. This function is responsible for priming the GCD map and the
2424 memory map, so memory allocations and resource allocations can be made. The
2425 HobStart will be relocated to a pool buffer.
2426
2427 @param HobStart The start address of the HOB
2428 @param MemoryBaseAddress Start address of memory region found to init DXE
2429 core.
2430 @param MemoryLength Length of memory region found to init DXE core.
2431
2432 @retval EFI_SUCCESS GCD services successfully initialized.
2433
2434 **/
2435 EFI_STATUS
2436 CoreInitializeGcdServices (
2437 IN OUT VOID **HobStart,
2438 IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
2439 IN UINT64 MemoryLength
2440 )
2441 {
2442 EFI_PEI_HOB_POINTERS Hob;
2443 VOID *NewHobList;
2444 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
2445 UINT8 SizeOfMemorySpace;
2446 UINT8 SizeOfIoSpace;
2447 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
2448 EFI_PHYSICAL_ADDRESS BaseAddress;
2449 UINT64 Length;
2450 EFI_STATUS Status;
2451 EFI_GCD_MAP_ENTRY *Entry;
2452 EFI_GCD_MEMORY_TYPE GcdMemoryType;
2453 EFI_GCD_IO_TYPE GcdIoType;
2454 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
2455 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
2456 EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
2457 UINTN NumberOfDescriptors;
2458 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
2459 UINTN Index;
2460 UINT64 Capabilities;
2461 EFI_HOB_CPU * CpuHob;
2462 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMapHobList;
2463
2464 //
2465 // Cache the PHIT HOB for later use
2466 //
2467 PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
2468
2469 //
2470 // Get the number of address lines in the I/O and Memory space for the CPU
2471 //
2472 CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);
2473 ASSERT (CpuHob != NULL);
2474 SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;
2475 SizeOfIoSpace = CpuHob->SizeOfIoSpace;
2476
2477 //
2478 // Initialize the GCD Memory Space Map
2479 //
2480 Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);
2481 ASSERT (Entry != NULL);
2482
2483 Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;
2484
2485 InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);
2486
2487 CoreDumpGcdMemorySpaceMap (TRUE);
2488
2489 //
2490 // Initialize the GCD I/O Space Map
2491 //
2492 Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);
2493 ASSERT (Entry != NULL);
2494
2495 Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;
2496
2497 InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);
2498
2499 CoreDumpGcdIoSpaceMap (TRUE);
2500
2501 //
2502 // Walk the HOB list and add all resource descriptors to the GCD
2503 //
2504 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2505
2506 GcdMemoryType = EfiGcdMemoryTypeNonExistent;
2507 GcdIoType = EfiGcdIoTypeNonExistent;
2508
2509 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
2510
2511 ResourceHob = Hob.ResourceDescriptor;
2512
2513 switch (ResourceHob->ResourceType) {
2514 case EFI_RESOURCE_SYSTEM_MEMORY:
2515 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
2516 if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
2517 GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
2518 } else {
2519 GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
2520 }
2521 }
2522 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
2523 GcdMemoryType = EfiGcdMemoryTypeReserved;
2524 }
2525 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
2526 GcdMemoryType = EfiGcdMemoryTypeReserved;
2527 }
2528 if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {
2529 GcdMemoryType = EfiGcdMemoryTypePersistent;
2530 }
2531 break;
2532 case EFI_RESOURCE_MEMORY_MAPPED_IO:
2533 case EFI_RESOURCE_FIRMWARE_DEVICE:
2534 GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;
2535 break;
2536 case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
2537 case EFI_RESOURCE_MEMORY_RESERVED:
2538 GcdMemoryType = EfiGcdMemoryTypeReserved;
2539 break;
2540 case EFI_RESOURCE_IO:
2541 GcdIoType = EfiGcdIoTypeIo;
2542 break;
2543 case EFI_RESOURCE_IO_RESERVED:
2544 GcdIoType = EfiGcdIoTypeReserved;
2545 break;
2546 }
2547
2548 if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {
2549 //
2550 // Validate the Resource HOB Attributes
2551 //
2552 CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);
2553
2554 //
2555 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2556 //
2557 Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (
2558 GcdMemoryType,
2559 ResourceHob->ResourceAttribute
2560 );
2561
2562 Status = CoreInternalAddMemorySpace (
2563 GcdMemoryType,
2564 ResourceHob->PhysicalStart,
2565 ResourceHob->ResourceLength,
2566 Capabilities
2567 );
2568 }
2569
2570 if (GcdIoType != EfiGcdIoTypeNonExistent) {
2571 Status = CoreAddIoSpace (
2572 GcdIoType,
2573 ResourceHob->PhysicalStart,
2574 ResourceHob->ResourceLength
2575 );
2576 }
2577 }
2578 }
2579
2580 //
2581 // Allocate first memory region from the GCD by the DXE core
2582 //
2583 Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);
2584 if (!EFI_ERROR (Status)) {
2585 ASSERT ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
2586 (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable));
2587 Status = CoreAllocateMemorySpace (
2588 EfiGcdAllocateAddress,
2589 Descriptor.GcdMemoryType,
2590 0,
2591 MemoryLength,
2592 &MemoryBaseAddress,
2593 gDxeCoreImageHandle,
2594 NULL
2595 );
2596 }
2597
2598 //
2599 // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
2600 // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs.
2601 //
2602 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2603 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
2604 MemoryHob = Hob.MemoryAllocation;
2605 BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
2606 Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
2607 if (!EFI_ERROR (Status)) {
2608 Status = CoreAllocateMemorySpace (
2609 EfiGcdAllocateAddress,
2610 Descriptor.GcdMemoryType,
2611 0,
2612 MemoryHob->AllocDescriptor.MemoryLength,
2613 &BaseAddress,
2614 gDxeCoreImageHandle,
2615 NULL
2616 );
2617 if (!EFI_ERROR (Status) &&
2618 ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
2619 (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
2620 CoreAddMemoryDescriptor (
2621 MemoryHob->AllocDescriptor.MemoryType,
2622 MemoryHob->AllocDescriptor.MemoryBaseAddress,
2623 RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),
2624 Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)
2625 );
2626 }
2627 }
2628 }
2629
2630 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
2631 FirmwareVolumeHob = Hob.FirmwareVolume;
2632 BaseAddress = FirmwareVolumeHob->BaseAddress;
2633 Status = CoreAllocateMemorySpace (
2634 EfiGcdAllocateAddress,
2635 EfiGcdMemoryTypeMemoryMappedIo,
2636 0,
2637 FirmwareVolumeHob->Length,
2638 &BaseAddress,
2639 gDxeCoreImageHandle,
2640 NULL
2641 );
2642 }
2643 }
2644
2645 //
2646 // Add and allocate the remaining unallocated system memory to the memory services.
2647 //
2648 Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
2649 ASSERT (Status == EFI_SUCCESS);
2650
2651 MemorySpaceMapHobList = NULL;
2652 for (Index = 0; Index < NumberOfDescriptors; Index++) {
2653 if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
2654 (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) {
2655 if (MemorySpaceMap[Index].ImageHandle == NULL) {
2656 BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);
2657 Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);
2658 if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) {
2659 continue;
2660 }
2661 if (((UINTN) MemorySpaceMap[Index].BaseAddress <= (UINTN) (*HobStart)) &&
2662 ((UINTN) (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN) PhitHob->EfiFreeMemoryBottom)) {
2663 //
2664 // Skip the memory space that covers HOB List, it should be processed
2665 // after HOB List relocation to avoid the resources allocated by others
2666 // to corrupt HOB List before its relocation.
2667 //
2668 MemorySpaceMapHobList = &MemorySpaceMap[Index];
2669 continue;
2670 }
2671 CoreAddMemoryDescriptor (
2672 EfiConventionalMemory,
2673 BaseAddress,
2674 RShiftU64 (Length, EFI_PAGE_SHIFT),
2675 MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)
2676 );
2677 Status = CoreAllocateMemorySpace (
2678 EfiGcdAllocateAddress,
2679 MemorySpaceMap[Index].GcdMemoryType,
2680 0,
2681 Length,
2682 &BaseAddress,
2683 gDxeCoreImageHandle,
2684 NULL
2685 );
2686 }
2687 }
2688 }
2689
2690 //
2691 // Relocate HOB List to an allocated pool buffer.
2692 // The relocation should be at after all the tested memory resources added
2693 // (except the memory space that covers HOB List) to the memory services,
2694 // because the memory resource found in CoreInitializeMemoryServices()
2695 // may have not enough remaining resource for HOB List.
2696 //
2697 NewHobList = AllocateCopyPool (
2698 (UINTN) PhitHob->EfiFreeMemoryBottom - (UINTN) (*HobStart),
2699 *HobStart
2700 );
2701 ASSERT (NewHobList != NULL);
2702
2703 *HobStart = NewHobList;
2704 gHobList = NewHobList;
2705
2706 if (MemorySpaceMapHobList != NULL) {
2707 //
2708 // Add and allocate the memory space that covers HOB List to the memory services
2709 // after HOB List relocation.
2710 //
2711 BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);
2712 Length = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);
2713 CoreAddMemoryDescriptor (
2714 EfiConventionalMemory,
2715 BaseAddress,
2716 RShiftU64 (Length, EFI_PAGE_SHIFT),
2717 MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME)
2718 );
2719 Status = CoreAllocateMemorySpace (
2720 EfiGcdAllocateAddress,
2721 MemorySpaceMapHobList->GcdMemoryType,
2722 0,
2723 Length,
2724 &BaseAddress,
2725 gDxeCoreImageHandle,
2726 NULL
2727 );
2728 }
2729
2730 CoreFreePool (MemorySpaceMap);
2731
2732 return EFI_SUCCESS;
2733 }