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