31ddf9c3bb516e7dd34b92813f408d993c36aa7a
[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 - 2017, 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 if (Operation == GCD_SET_ATTRIBUTES_MEMORY_OPERATION) {
870 //
871 // Call CPU Arch Protocol to attempt to set attributes on the range
872 //
873 CpuArchAttributes = ConverToCpuArchAttributes (Attributes);
874 //
875 // CPU arch attributes include page attributes and cache attributes.
876 // Only page attributes supports to be cleared, but not cache attributes.
877 // Caller is expected to use GetMemorySpaceDescriptor() to get the current
878 // attributes, AND/OR attributes, and then calls SetMemorySpaceAttributes()
879 // to set the new attributes.
880 // So 0 CPU arch attributes should not happen as memory should always have
881 // a cache attribute (no matter UC or WB, etc).
882 //
883 // Here, 0 CPU arch attributes will be filtered to be compatible with the
884 // case that caller just calls SetMemorySpaceAttributes() with none CPU
885 // arch attributes (for example, RUNTIME) as the purpose of the case is not
886 // to clear CPU arch attributes.
887 //
888 if (CpuArchAttributes != 0) {
889 if (gCpu == NULL) {
890 Status = EFI_NOT_AVAILABLE_YET;
891 } else {
892 Status = gCpu->SetMemoryAttributes (
893 gCpu,
894 BaseAddress,
895 Length,
896 CpuArchAttributes
897 );
898 }
899 if (EFI_ERROR (Status)) {
900 CoreFreePool (TopEntry);
901 CoreFreePool (BottomEntry);
902 goto Done;
903 }
904 }
905 }
906
907 //
908 // Convert/Insert the list of descriptors from StartLink to EndLink
909 //
910 Link = StartLink;
911 while (Link != EndLink->ForwardLink) {
912 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
913 CoreInsertGcdMapEntry (Link, Entry, BaseAddress, Length, TopEntry, BottomEntry);
914 switch (Operation) {
915 //
916 // Add operations
917 //
918 case GCD_ADD_MEMORY_OPERATION:
919 Entry->GcdMemoryType = GcdMemoryType;
920 if (GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
921 Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME | EFI_MEMORY_PORT_IO;
922 } else {
923 Entry->Capabilities = Capabilities | EFI_MEMORY_RUNTIME;
924 }
925 break;
926 case GCD_ADD_IO_OPERATION:
927 Entry->GcdIoType = GcdIoType;
928 break;
929 //
930 // Free operations
931 //
932 case GCD_FREE_MEMORY_OPERATION:
933 case GCD_FREE_IO_OPERATION:
934 Entry->ImageHandle = NULL;
935 Entry->DeviceHandle = NULL;
936 break;
937 //
938 // Remove operations
939 //
940 case GCD_REMOVE_MEMORY_OPERATION:
941 Entry->GcdMemoryType = EfiGcdMemoryTypeNonExistent;
942 Entry->Capabilities = 0;
943 break;
944 case GCD_REMOVE_IO_OPERATION:
945 Entry->GcdIoType = EfiGcdIoTypeNonExistent;
946 break;
947 //
948 // Set attributes operation
949 //
950 case GCD_SET_ATTRIBUTES_MEMORY_OPERATION:
951 if (CpuArchAttributes == 0) {
952 //
953 // Keep original CPU arch attributes when caller just calls
954 // SetMemorySpaceAttributes() with none CPU arch attributes (for example, RUNTIME).
955 //
956 Attributes |= (Entry->Attributes & (EXCLUSIVE_MEMORY_ATTRIBUTES | NONEXCLUSIVE_MEMORY_ATTRIBUTES));
957 }
958 Entry->Attributes = Attributes;
959 break;
960 //
961 // Set capabilities operation
962 //
963 case GCD_SET_CAPABILITIES_MEMORY_OPERATION:
964 Entry->Capabilities = Capabilities;
965 break;
966 }
967 Link = Link->ForwardLink;
968 }
969
970 //
971 // Cleanup
972 //
973 Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
974
975 Done:
976 DEBUG ((DEBUG_GCD, " Status = %r\n", Status));
977
978 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
979 CoreReleaseGcdMemoryLock ();
980 CoreDumpGcdMemorySpaceMap (FALSE);
981 }
982 if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
983 CoreReleaseGcdIoLock ();
984 CoreDumpGcdIoSpaceMap (FALSE);
985 }
986
987 return Status;
988 }
989
990
991 /**
992 Check whether an entry could be used to allocate space.
993
994 @param Operation Allocate memory or IO
995 @param Entry The entry to be tested
996 @param GcdMemoryType The desired memory type
997 @param GcdIoType The desired IO type
998
999 @retval EFI_NOT_FOUND The memory type does not match or there's an
1000 image handle on the entry.
1001 @retval EFI_UNSUPPORTED The operation unsupported.
1002 @retval EFI_SUCCESS It's ok for this entry to be used to allocate
1003 space.
1004
1005 **/
1006 EFI_STATUS
1007 CoreAllocateSpaceCheckEntry (
1008 IN UINTN Operation,
1009 IN EFI_GCD_MAP_ENTRY *Entry,
1010 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1011 IN EFI_GCD_IO_TYPE GcdIoType
1012 )
1013 {
1014 if (Entry->ImageHandle != NULL) {
1015 return EFI_NOT_FOUND;
1016 }
1017 switch (Operation) {
1018 case GCD_ALLOCATE_MEMORY_OPERATION:
1019 if (Entry->GcdMemoryType != GcdMemoryType) {
1020 return EFI_NOT_FOUND;
1021 }
1022 break;
1023 case GCD_ALLOCATE_IO_OPERATION:
1024 if (Entry->GcdIoType != GcdIoType) {
1025 return EFI_NOT_FOUND;
1026 }
1027 break;
1028 default:
1029 return EFI_UNSUPPORTED;
1030 }
1031 return EFI_SUCCESS;
1032 }
1033
1034
1035 /**
1036 Allocate space on specified address and length.
1037
1038 @param Operation The type of operation (memory or IO)
1039 @param GcdAllocateType The type of allocate operation
1040 @param GcdMemoryType The desired memory type
1041 @param GcdIoType The desired IO type
1042 @param Alignment Align with 2^Alignment
1043 @param Length Length to allocate
1044 @param BaseAddress Base address to allocate
1045 @param ImageHandle The image handle consume the allocated space.
1046 @param DeviceHandle The device handle consume the allocated space.
1047
1048 @retval EFI_INVALID_PARAMETER Invalid parameter.
1049 @retval EFI_NOT_FOUND No descriptor for the desired space exists.
1050 @retval EFI_SUCCESS Space successfully allocated.
1051
1052 **/
1053 EFI_STATUS
1054 CoreAllocateSpace (
1055 IN UINTN Operation,
1056 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
1057 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1058 IN EFI_GCD_IO_TYPE GcdIoType,
1059 IN UINTN Alignment,
1060 IN UINT64 Length,
1061 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
1062 IN EFI_HANDLE ImageHandle,
1063 IN EFI_HANDLE DeviceHandle OPTIONAL
1064 )
1065 {
1066 EFI_STATUS Status;
1067 EFI_PHYSICAL_ADDRESS AlignmentMask;
1068 EFI_PHYSICAL_ADDRESS MaxAddress;
1069 LIST_ENTRY *Map;
1070 LIST_ENTRY *Link;
1071 LIST_ENTRY *SubLink;
1072 EFI_GCD_MAP_ENTRY *Entry;
1073 EFI_GCD_MAP_ENTRY *TopEntry;
1074 EFI_GCD_MAP_ENTRY *BottomEntry;
1075 LIST_ENTRY *StartLink;
1076 LIST_ENTRY *EndLink;
1077 BOOLEAN Found;
1078
1079 //
1080 // Make sure parameters are valid
1081 //
1082 if ((UINT32)GcdAllocateType >= EfiGcdMaxAllocateType) {
1083 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1084 return EFI_INVALID_PARAMETER;
1085 }
1086 if ((UINT32)GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
1087 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1088 return EFI_INVALID_PARAMETER;
1089 }
1090 if ((UINT32)GcdIoType >= EfiGcdIoTypeMaximum) {
1091 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1092 return EFI_INVALID_PARAMETER;
1093 }
1094 if (BaseAddress == NULL) {
1095 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1096 return EFI_INVALID_PARAMETER;
1097 }
1098 if (ImageHandle == NULL) {
1099 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1100 return EFI_INVALID_PARAMETER;
1101 }
1102 if (Alignment >= 64) {
1103 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_NOT_FOUND));
1104 return EFI_NOT_FOUND;
1105 }
1106 if (Length == 0) {
1107 DEBUG ((DEBUG_GCD, " Status = %r\n", EFI_INVALID_PARAMETER));
1108 return EFI_INVALID_PARAMETER;
1109 }
1110
1111 Map = NULL;
1112 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
1113 CoreAcquireGcdMemoryLock ();
1114 Map = &mGcdMemorySpaceMap;
1115 } else if ((Operation & GCD_IO_SPACE_OPERATION) != 0) {
1116 CoreAcquireGcdIoLock ();
1117 Map = &mGcdIoSpaceMap;
1118 } else {
1119 ASSERT (FALSE);
1120 }
1121
1122 Found = FALSE;
1123 StartLink = NULL;
1124 EndLink = NULL;
1125 //
1126 // Compute alignment bit mask
1127 //
1128 AlignmentMask = LShiftU64 (1, Alignment) - 1;
1129
1130 if (GcdAllocateType == EfiGcdAllocateAddress) {
1131 //
1132 // Verify that the BaseAddress passed in is aligned correctly
1133 //
1134 if ((*BaseAddress & AlignmentMask) != 0) {
1135 Status = EFI_NOT_FOUND;
1136 goto Done;
1137 }
1138
1139 //
1140 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
1141 //
1142 Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
1143 if (EFI_ERROR (Status)) {
1144 Status = EFI_NOT_FOUND;
1145 goto Done;
1146 }
1147 ASSERT (StartLink != NULL && EndLink != NULL);
1148
1149 //
1150 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1151 //
1152 Link = StartLink;
1153 while (Link != EndLink->ForwardLink) {
1154 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1155 Link = Link->ForwardLink;
1156 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
1157 if (EFI_ERROR (Status)) {
1158 goto Done;
1159 }
1160 }
1161 Found = TRUE;
1162 } else {
1163
1164 Entry = CR (Map->BackLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1165
1166 //
1167 // Compute the maximum address to use in the search algorithm
1168 //
1169 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchBottomUp ||
1170 GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ) {
1171 MaxAddress = *BaseAddress;
1172 } else {
1173 MaxAddress = Entry->EndAddress;
1174 }
1175
1176 //
1177 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1178 //
1179 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
1180 GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
1181 Link = Map->BackLink;
1182 } else {
1183 Link = Map->ForwardLink;
1184 }
1185 while (Link != Map) {
1186 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1187
1188 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
1189 GcdAllocateType == EfiGcdAllocateAnySearchTopDown ) {
1190 Link = Link->BackLink;
1191 } else {
1192 Link = Link->ForwardLink;
1193 }
1194
1195 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
1196 if (EFI_ERROR (Status)) {
1197 continue;
1198 }
1199
1200 if (GcdAllocateType == EfiGcdAllocateMaxAddressSearchTopDown ||
1201 GcdAllocateType == EfiGcdAllocateAnySearchTopDown) {
1202 if ((Entry->BaseAddress + Length) > MaxAddress) {
1203 continue;
1204 }
1205 if (Length > (Entry->EndAddress + 1)) {
1206 Status = EFI_NOT_FOUND;
1207 goto Done;
1208 }
1209 if (Entry->EndAddress > MaxAddress) {
1210 *BaseAddress = MaxAddress;
1211 } else {
1212 *BaseAddress = Entry->EndAddress;
1213 }
1214 *BaseAddress = (*BaseAddress + 1 - Length) & (~AlignmentMask);
1215 } else {
1216 *BaseAddress = (Entry->BaseAddress + AlignmentMask) & (~AlignmentMask);
1217 if ((*BaseAddress + Length - 1) > MaxAddress) {
1218 Status = EFI_NOT_FOUND;
1219 goto Done;
1220 }
1221 }
1222
1223 //
1224 // Search for the list of descriptors that cover the range BaseAddress to BaseAddress+Length
1225 //
1226 Status = CoreSearchGcdMapEntry (*BaseAddress, Length, &StartLink, &EndLink, Map);
1227 if (EFI_ERROR (Status)) {
1228 Status = EFI_NOT_FOUND;
1229 goto Done;
1230 }
1231 ASSERT (StartLink != NULL && EndLink != NULL);
1232
1233 Link = StartLink;
1234 //
1235 // Verify that the list of descriptors are unallocated memory matching GcdMemoryType.
1236 //
1237 Found = TRUE;
1238 SubLink = StartLink;
1239 while (SubLink != EndLink->ForwardLink) {
1240 Entry = CR (SubLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1241 Status = CoreAllocateSpaceCheckEntry (Operation, Entry, GcdMemoryType, GcdIoType);
1242 if (EFI_ERROR (Status)) {
1243 Link = SubLink;
1244 Found = FALSE;
1245 break;
1246 }
1247 SubLink = SubLink->ForwardLink;
1248 }
1249 if (Found) {
1250 break;
1251 }
1252 }
1253 }
1254 if (!Found) {
1255 Status = EFI_NOT_FOUND;
1256 goto Done;
1257 }
1258
1259 //
1260 // Allocate work space to perform this operation
1261 //
1262 Status = CoreAllocateGcdMapEntry (&TopEntry, &BottomEntry);
1263 if (EFI_ERROR (Status)) {
1264 Status = EFI_OUT_OF_RESOURCES;
1265 goto Done;
1266 }
1267 ASSERT (TopEntry != NULL && BottomEntry != NULL);
1268
1269 //
1270 // Convert/Insert the list of descriptors from StartLink to EndLink
1271 //
1272 Link = StartLink;
1273 while (Link != EndLink->ForwardLink) {
1274 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1275 CoreInsertGcdMapEntry (Link, Entry, *BaseAddress, Length, TopEntry, BottomEntry);
1276 Entry->ImageHandle = ImageHandle;
1277 Entry->DeviceHandle = DeviceHandle;
1278 Link = Link->ForwardLink;
1279 }
1280
1281 //
1282 // Cleanup
1283 //
1284 Status = CoreCleanupGcdMapEntry (TopEntry, BottomEntry, StartLink, EndLink, Map);
1285
1286 Done:
1287 DEBUG ((DEBUG_GCD, " Status = %r", Status));
1288 if (!EFI_ERROR (Status)) {
1289 DEBUG ((DEBUG_GCD, " (BaseAddress = %016lx)", *BaseAddress));
1290 }
1291 DEBUG ((DEBUG_GCD, "\n"));
1292
1293 if ((Operation & GCD_MEMORY_SPACE_OPERATION) != 0) {
1294 CoreReleaseGcdMemoryLock ();
1295 CoreDumpGcdMemorySpaceMap (FALSE);
1296 }
1297 if ((Operation & GCD_IO_SPACE_OPERATION) !=0) {
1298 CoreReleaseGcdIoLock ();
1299 CoreDumpGcdIoSpaceMap (FALSE);
1300 }
1301
1302 return Status;
1303 }
1304
1305
1306 /**
1307 Add a segment of memory to GCD map.
1308
1309 @param GcdMemoryType Memory type of the segment.
1310 @param BaseAddress Base address of the segment.
1311 @param Length Length of the segment.
1312 @param Capabilities alterable attributes of the segment.
1313
1314 @retval EFI_INVALID_PARAMETER Invalid parameters.
1315 @retval EFI_SUCCESS Successfully add a segment of memory space.
1316
1317 **/
1318 EFI_STATUS
1319 CoreInternalAddMemorySpace (
1320 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1321 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1322 IN UINT64 Length,
1323 IN UINT64 Capabilities
1324 )
1325 {
1326 DEBUG ((DEBUG_GCD, "GCD:AddMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1327 DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
1328 DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
1329
1330 //
1331 // Make sure parameters are valid
1332 //
1333 if (GcdMemoryType <= EfiGcdMemoryTypeNonExistent || GcdMemoryType >= EfiGcdMemoryTypeMaximum) {
1334 return EFI_INVALID_PARAMETER;
1335 }
1336
1337 return CoreConvertSpace (GCD_ADD_MEMORY_OPERATION, GcdMemoryType, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
1338 }
1339
1340 //
1341 // GCD Core Services
1342 //
1343
1344 /**
1345 Allocates nonexistent memory, reserved memory, system memory, or memorymapped
1346 I/O resources from the global coherency domain of the processor.
1347
1348 @param GcdAllocateType The type of allocate operation
1349 @param GcdMemoryType The desired memory type
1350 @param Alignment Align with 2^Alignment
1351 @param Length Length to allocate
1352 @param BaseAddress Base address to allocate
1353 @param ImageHandle The image handle consume the allocated space.
1354 @param DeviceHandle The device handle consume the allocated space.
1355
1356 @retval EFI_INVALID_PARAMETER Invalid parameter.
1357 @retval EFI_NOT_FOUND No descriptor contains the desired space.
1358 @retval EFI_SUCCESS Memory space successfully allocated.
1359
1360 **/
1361 EFI_STATUS
1362 EFIAPI
1363 CoreAllocateMemorySpace (
1364 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
1365 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1366 IN UINTN Alignment,
1367 IN UINT64 Length,
1368 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
1369 IN EFI_HANDLE ImageHandle,
1370 IN EFI_HANDLE DeviceHandle OPTIONAL
1371 )
1372 {
1373 if (BaseAddress != NULL) {
1374 DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
1375 } else {
1376 DEBUG ((DEBUG_GCD, "GCD:AllocateMemorySpace(Base=<NULL>,Length=%016lx)\n", Length));
1377 }
1378 DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
1379 DEBUG ((DEBUG_GCD, " GcdMemoryType = %a\n", mGcdMemoryTypeNames[MIN (GcdMemoryType, EfiGcdMemoryTypeMaximum)]));
1380 DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
1381 DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
1382 DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
1383
1384 return CoreAllocateSpace (
1385 GCD_ALLOCATE_MEMORY_OPERATION,
1386 GcdAllocateType,
1387 GcdMemoryType,
1388 (EFI_GCD_IO_TYPE) 0,
1389 Alignment,
1390 Length,
1391 BaseAddress,
1392 ImageHandle,
1393 DeviceHandle
1394 );
1395 }
1396
1397
1398 /**
1399 Adds reserved memory, system memory, or memory-mapped I/O resources to the
1400 global coherency domain of the processor.
1401
1402 @param GcdMemoryType Memory type of the memory space.
1403 @param BaseAddress Base address of the memory space.
1404 @param Length Length of the memory space.
1405 @param Capabilities alterable attributes of the memory space.
1406
1407 @retval EFI_SUCCESS Merged this memory space into GCD map.
1408
1409 **/
1410 EFI_STATUS
1411 EFIAPI
1412 CoreAddMemorySpace (
1413 IN EFI_GCD_MEMORY_TYPE GcdMemoryType,
1414 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1415 IN UINT64 Length,
1416 IN UINT64 Capabilities
1417 )
1418 {
1419 EFI_STATUS Status;
1420 EFI_PHYSICAL_ADDRESS PageBaseAddress;
1421 UINT64 PageLength;
1422
1423 Status = CoreInternalAddMemorySpace (GcdMemoryType, BaseAddress, Length, Capabilities);
1424
1425 if (!EFI_ERROR (Status) && ((GcdMemoryType == EfiGcdMemoryTypeSystemMemory) || (GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
1426
1427 PageBaseAddress = PageAlignAddress (BaseAddress);
1428 PageLength = PageAlignLength (BaseAddress + Length - PageBaseAddress);
1429
1430 Status = CoreAllocateMemorySpace (
1431 EfiGcdAllocateAddress,
1432 GcdMemoryType,
1433 EFI_PAGE_SHIFT,
1434 PageLength,
1435 &PageBaseAddress,
1436 gDxeCoreImageHandle,
1437 NULL
1438 );
1439
1440 if (!EFI_ERROR (Status)) {
1441 CoreAddMemoryDescriptor (
1442 EfiConventionalMemory,
1443 PageBaseAddress,
1444 RShiftU64 (PageLength, EFI_PAGE_SHIFT),
1445 Capabilities
1446 );
1447 } else {
1448 for (; PageLength != 0; PageLength -= EFI_PAGE_SIZE, PageBaseAddress += EFI_PAGE_SIZE) {
1449 Status = CoreAllocateMemorySpace (
1450 EfiGcdAllocateAddress,
1451 GcdMemoryType,
1452 EFI_PAGE_SHIFT,
1453 EFI_PAGE_SIZE,
1454 &PageBaseAddress,
1455 gDxeCoreImageHandle,
1456 NULL
1457 );
1458
1459 if (!EFI_ERROR (Status)) {
1460 CoreAddMemoryDescriptor (
1461 EfiConventionalMemory,
1462 PageBaseAddress,
1463 1,
1464 Capabilities
1465 );
1466 }
1467 }
1468 }
1469 }
1470 return Status;
1471 }
1472
1473
1474 /**
1475 Frees nonexistent memory, reserved memory, system memory, or memory-mapped
1476 I/O resources from the global coherency domain of the processor.
1477
1478 @param BaseAddress Base address of the memory space.
1479 @param Length Length of the memory space.
1480
1481 @retval EFI_SUCCESS Space successfully freed.
1482
1483 **/
1484 EFI_STATUS
1485 EFIAPI
1486 CoreFreeMemorySpace (
1487 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1488 IN UINT64 Length
1489 )
1490 {
1491 DEBUG ((DEBUG_GCD, "GCD:FreeMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1492
1493 return CoreConvertSpace (GCD_FREE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1494 }
1495
1496
1497 /**
1498 Removes reserved memory, system memory, or memory-mapped I/O resources from
1499 the global coherency domain of the processor.
1500
1501 @param BaseAddress Base address of the memory space.
1502 @param Length Length of the memory space.
1503
1504 @retval EFI_SUCCESS Successfully remove a segment of memory space.
1505
1506 **/
1507 EFI_STATUS
1508 EFIAPI
1509 CoreRemoveMemorySpace (
1510 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1511 IN UINT64 Length
1512 )
1513 {
1514 DEBUG ((DEBUG_GCD, "GCD:RemoveMemorySpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1515
1516 return CoreConvertSpace (GCD_REMOVE_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1517 }
1518
1519
1520 /**
1521 Build a memory descriptor according to an entry.
1522
1523 @param Descriptor The descriptor to be built
1524 @param Entry According to this entry
1525
1526 **/
1527 VOID
1528 BuildMemoryDescriptor (
1529 IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor,
1530 IN EFI_GCD_MAP_ENTRY *Entry
1531 )
1532 {
1533 Descriptor->BaseAddress = Entry->BaseAddress;
1534 Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
1535 Descriptor->Capabilities = Entry->Capabilities;
1536 Descriptor->Attributes = Entry->Attributes;
1537 Descriptor->GcdMemoryType = Entry->GcdMemoryType;
1538 Descriptor->ImageHandle = Entry->ImageHandle;
1539 Descriptor->DeviceHandle = Entry->DeviceHandle;
1540 }
1541
1542
1543 /**
1544 Retrieves the descriptor for a memory region containing a specified address.
1545
1546 @param BaseAddress Specified start address
1547 @param Descriptor Specified length
1548
1549 @retval EFI_INVALID_PARAMETER Invalid parameter
1550 @retval EFI_SUCCESS Successfully get memory space descriptor.
1551
1552 **/
1553 EFI_STATUS
1554 EFIAPI
1555 CoreGetMemorySpaceDescriptor (
1556 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1557 OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor
1558 )
1559 {
1560 EFI_STATUS Status;
1561 LIST_ENTRY *StartLink;
1562 LIST_ENTRY *EndLink;
1563 EFI_GCD_MAP_ENTRY *Entry;
1564
1565 //
1566 // Make sure parameters are valid
1567 //
1568 if (Descriptor == NULL) {
1569 return EFI_INVALID_PARAMETER;
1570 }
1571
1572 CoreAcquireGcdMemoryLock ();
1573
1574 //
1575 // Search for the list of descriptors that contain BaseAddress
1576 //
1577 Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdMemorySpaceMap);
1578 if (EFI_ERROR (Status)) {
1579 Status = EFI_NOT_FOUND;
1580 } else {
1581 ASSERT (StartLink != NULL && EndLink != NULL);
1582 //
1583 // Copy the contents of the found descriptor into Descriptor
1584 //
1585 Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1586 BuildMemoryDescriptor (Descriptor, Entry);
1587 }
1588
1589 CoreReleaseGcdMemoryLock ();
1590
1591 return Status;
1592 }
1593
1594
1595 /**
1596 Modifies the attributes for a memory region in the global coherency domain of the
1597 processor.
1598
1599 @param BaseAddress Specified start address
1600 @param Length Specified length
1601 @param Attributes Specified attributes
1602
1603 @retval EFI_SUCCESS The attributes were set for the memory region.
1604 @retval EFI_INVALID_PARAMETER Length is zero.
1605 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
1606 resource range specified by BaseAddress and Length.
1607 @retval EFI_UNSUPPORTED The bit mask of attributes is not support for the memory resource
1608 range specified by BaseAddress and Length.
1609 @retval EFI_ACCESS_DEFINED The attributes for the memory resource range specified by
1610 BaseAddress and Length cannot be modified.
1611 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
1612 the memory resource range.
1613 @retval EFI_NOT_AVAILABLE_YET The attributes cannot be set because CPU architectural protocol is
1614 not available yet.
1615
1616 **/
1617 EFI_STATUS
1618 EFIAPI
1619 CoreSetMemorySpaceAttributes (
1620 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1621 IN UINT64 Length,
1622 IN UINT64 Attributes
1623 )
1624 {
1625 DEBUG ((DEBUG_GCD, "GCD:SetMemorySpaceAttributes(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1626 DEBUG ((DEBUG_GCD, " Attributes = %016lx\n", Attributes));
1627
1628 return CoreConvertSpace (GCD_SET_ATTRIBUTES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, Attributes);
1629 }
1630
1631
1632 /**
1633 Modifies the capabilities for a memory region in the global coherency domain of the
1634 processor.
1635
1636 @param BaseAddress The physical address that is the start address of a memory region.
1637 @param Length The size in bytes of the memory region.
1638 @param Capabilities The bit mask of capabilities that the memory region supports.
1639
1640 @retval EFI_SUCCESS The capabilities were set for the memory region.
1641 @retval EFI_INVALID_PARAMETER Length is zero.
1642 @retval EFI_UNSUPPORTED The capabilities specified by Capabilities do not include the
1643 memory region attributes currently in use.
1644 @retval EFI_ACCESS_DENIED The capabilities for the memory resource range specified by
1645 BaseAddress and Length cannot be modified.
1646 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the capabilities
1647 of the memory resource range.
1648 **/
1649 EFI_STATUS
1650 EFIAPI
1651 CoreSetMemorySpaceCapabilities (
1652 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1653 IN UINT64 Length,
1654 IN UINT64 Capabilities
1655 )
1656 {
1657 EFI_STATUS Status;
1658
1659 DEBUG ((DEBUG_GCD, "GCD:CoreSetMemorySpaceCapabilities(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1660 DEBUG ((DEBUG_GCD, " Capabilities = %016lx\n", Capabilities));
1661
1662 Status = CoreConvertSpace (GCD_SET_CAPABILITIES_MEMORY_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, Capabilities, 0);
1663 if (!EFI_ERROR(Status)) {
1664 CoreUpdateMemoryAttributes(BaseAddress, RShiftU64(Length, EFI_PAGE_SHIFT), Capabilities & (~EFI_MEMORY_RUNTIME));
1665 }
1666
1667 return Status;
1668 }
1669
1670
1671 /**
1672 Returns a map of the memory resources in the global coherency domain of the
1673 processor.
1674
1675 @param NumberOfDescriptors Number of descriptors.
1676 @param MemorySpaceMap Descriptor array
1677
1678 @retval EFI_INVALID_PARAMETER Invalid parameter
1679 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1680 @retval EFI_SUCCESS Successfully get memory space map.
1681
1682 **/
1683 EFI_STATUS
1684 EFIAPI
1685 CoreGetMemorySpaceMap (
1686 OUT UINTN *NumberOfDescriptors,
1687 OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap
1688 )
1689 {
1690 EFI_STATUS Status;
1691 LIST_ENTRY *Link;
1692 EFI_GCD_MAP_ENTRY *Entry;
1693 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor;
1694
1695 //
1696 // Make sure parameters are valid
1697 //
1698 if (NumberOfDescriptors == NULL) {
1699 return EFI_INVALID_PARAMETER;
1700 }
1701 if (MemorySpaceMap == NULL) {
1702 return EFI_INVALID_PARAMETER;
1703 }
1704
1705 CoreAcquireGcdMemoryLock ();
1706
1707 //
1708 // Count the number of descriptors
1709 //
1710 *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);
1711
1712 //
1713 // Allocate the MemorySpaceMap
1714 //
1715 *MemorySpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
1716 if (*MemorySpaceMap == NULL) {
1717 Status = EFI_OUT_OF_RESOURCES;
1718 goto Done;
1719 }
1720
1721 //
1722 // Fill in the MemorySpaceMap
1723 //
1724 Descriptor = *MemorySpaceMap;
1725 Link = mGcdMemorySpaceMap.ForwardLink;
1726 while (Link != &mGcdMemorySpaceMap) {
1727 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1728 BuildMemoryDescriptor (Descriptor, Entry);
1729 Descriptor++;
1730 Link = Link->ForwardLink;
1731 }
1732 Status = EFI_SUCCESS;
1733
1734 Done:
1735 CoreReleaseGcdMemoryLock ();
1736 return Status;
1737 }
1738
1739
1740 /**
1741 Adds reserved I/O or I/O resources to the global coherency domain of the processor.
1742
1743 @param GcdIoType IO type of the segment.
1744 @param BaseAddress Base address of the segment.
1745 @param Length Length of the segment.
1746
1747 @retval EFI_SUCCESS Merged this segment into GCD map.
1748 @retval EFI_INVALID_PARAMETER Parameter not valid
1749
1750 **/
1751 EFI_STATUS
1752 EFIAPI
1753 CoreAddIoSpace (
1754 IN EFI_GCD_IO_TYPE GcdIoType,
1755 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1756 IN UINT64 Length
1757 )
1758 {
1759 DEBUG ((DEBUG_GCD, "GCD:AddIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1760 DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
1761
1762 //
1763 // Make sure parameters are valid
1764 //
1765 if (GcdIoType <= EfiGcdIoTypeNonExistent || GcdIoType >= EfiGcdIoTypeMaximum) {
1766 return EFI_INVALID_PARAMETER;
1767 }
1768 return CoreConvertSpace (GCD_ADD_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, GcdIoType, BaseAddress, Length, 0, 0);
1769 }
1770
1771
1772 /**
1773 Allocates nonexistent I/O, reserved I/O, or I/O resources from the global coherency
1774 domain of the processor.
1775
1776 @param GcdAllocateType The type of allocate operation
1777 @param GcdIoType The desired IO type
1778 @param Alignment Align with 2^Alignment
1779 @param Length Length to allocate
1780 @param BaseAddress Base address to allocate
1781 @param ImageHandle The image handle consume the allocated space.
1782 @param DeviceHandle The device handle consume the allocated space.
1783
1784 @retval EFI_INVALID_PARAMETER Invalid parameter.
1785 @retval EFI_NOT_FOUND No descriptor contains the desired space.
1786 @retval EFI_SUCCESS IO space successfully allocated.
1787
1788 **/
1789 EFI_STATUS
1790 EFIAPI
1791 CoreAllocateIoSpace (
1792 IN EFI_GCD_ALLOCATE_TYPE GcdAllocateType,
1793 IN EFI_GCD_IO_TYPE GcdIoType,
1794 IN UINTN Alignment,
1795 IN UINT64 Length,
1796 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
1797 IN EFI_HANDLE ImageHandle,
1798 IN EFI_HANDLE DeviceHandle OPTIONAL
1799 )
1800 {
1801 if (BaseAddress != NULL) {
1802 DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=%016lx,Length=%016lx)\n", *BaseAddress, Length));
1803 } else {
1804 DEBUG ((DEBUG_GCD, "GCD:AllocateIoSpace(Base=<NULL>,Length=%016lx)\n", Length));
1805 }
1806 DEBUG ((DEBUG_GCD, " GcdAllocateType = %a\n", mGcdAllocationTypeNames[MIN (GcdAllocateType, EfiGcdMaxAllocateType)]));
1807 DEBUG ((DEBUG_GCD, " GcdIoType = %a\n", mGcdIoTypeNames[MIN (GcdIoType, EfiGcdIoTypeMaximum)]));
1808 DEBUG ((DEBUG_GCD, " Alignment = %016lx\n", LShiftU64 (1, Alignment)));
1809 DEBUG ((DEBUG_GCD, " ImageHandle = %p\n", ImageHandle));
1810 DEBUG ((DEBUG_GCD, " DeviceHandle = %p\n", DeviceHandle));
1811
1812 return CoreAllocateSpace (
1813 GCD_ALLOCATE_IO_OPERATION,
1814 GcdAllocateType,
1815 (EFI_GCD_MEMORY_TYPE) 0,
1816 GcdIoType,
1817 Alignment,
1818 Length,
1819 BaseAddress,
1820 ImageHandle,
1821 DeviceHandle
1822 );
1823 }
1824
1825
1826 /**
1827 Frees nonexistent I/O, reserved I/O, or I/O resources from the global coherency
1828 domain of the processor.
1829
1830 @param BaseAddress Base address of the segment.
1831 @param Length Length of the segment.
1832
1833 @retval EFI_SUCCESS Space successfully freed.
1834
1835 **/
1836 EFI_STATUS
1837 EFIAPI
1838 CoreFreeIoSpace (
1839 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1840 IN UINT64 Length
1841 )
1842 {
1843 DEBUG ((DEBUG_GCD, "GCD:FreeIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1844
1845 return CoreConvertSpace (GCD_FREE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1846 }
1847
1848
1849 /**
1850 Removes reserved I/O or I/O resources from the global coherency domain of the
1851 processor.
1852
1853 @param BaseAddress Base address of the segment.
1854 @param Length Length of the segment.
1855
1856 @retval EFI_SUCCESS Successfully removed a segment of IO space.
1857
1858 **/
1859 EFI_STATUS
1860 EFIAPI
1861 CoreRemoveIoSpace (
1862 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1863 IN UINT64 Length
1864 )
1865 {
1866 DEBUG ((DEBUG_GCD, "GCD:RemoveIoSpace(Base=%016lx,Length=%016lx)\n", BaseAddress, Length));
1867
1868 return CoreConvertSpace (GCD_REMOVE_IO_OPERATION, (EFI_GCD_MEMORY_TYPE) 0, (EFI_GCD_IO_TYPE) 0, BaseAddress, Length, 0, 0);
1869 }
1870
1871
1872 /**
1873 Build a IO descriptor according to an entry.
1874
1875 @param Descriptor The descriptor to be built
1876 @param Entry According to this entry
1877
1878 **/
1879 VOID
1880 BuildIoDescriptor (
1881 IN EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor,
1882 IN EFI_GCD_MAP_ENTRY *Entry
1883 )
1884 {
1885 Descriptor->BaseAddress = Entry->BaseAddress;
1886 Descriptor->Length = Entry->EndAddress - Entry->BaseAddress + 1;
1887 Descriptor->GcdIoType = Entry->GcdIoType;
1888 Descriptor->ImageHandle = Entry->ImageHandle;
1889 Descriptor->DeviceHandle = Entry->DeviceHandle;
1890 }
1891
1892
1893 /**
1894 Retrieves the descriptor for an I/O region containing a specified address.
1895
1896 @param BaseAddress Specified start address
1897 @param Descriptor Specified length
1898
1899 @retval EFI_INVALID_PARAMETER Descriptor is NULL.
1900 @retval EFI_SUCCESS Successfully get the IO space descriptor.
1901
1902 **/
1903 EFI_STATUS
1904 EFIAPI
1905 CoreGetIoSpaceDescriptor (
1906 IN EFI_PHYSICAL_ADDRESS BaseAddress,
1907 OUT EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor
1908 )
1909 {
1910 EFI_STATUS Status;
1911 LIST_ENTRY *StartLink;
1912 LIST_ENTRY *EndLink;
1913 EFI_GCD_MAP_ENTRY *Entry;
1914
1915 //
1916 // Make sure parameters are valid
1917 //
1918 if (Descriptor == NULL) {
1919 return EFI_INVALID_PARAMETER;
1920 }
1921
1922 CoreAcquireGcdIoLock ();
1923
1924 //
1925 // Search for the list of descriptors that contain BaseAddress
1926 //
1927 Status = CoreSearchGcdMapEntry (BaseAddress, 1, &StartLink, &EndLink, &mGcdIoSpaceMap);
1928 if (EFI_ERROR (Status)) {
1929 Status = EFI_NOT_FOUND;
1930 } else {
1931 ASSERT (StartLink != NULL && EndLink != NULL);
1932 //
1933 // Copy the contents of the found descriptor into Descriptor
1934 //
1935 Entry = CR (StartLink, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
1936 BuildIoDescriptor (Descriptor, Entry);
1937 }
1938
1939 CoreReleaseGcdIoLock ();
1940
1941 return Status;
1942 }
1943
1944
1945 /**
1946 Returns a map of the I/O resources in the global coherency domain of the processor.
1947
1948 @param NumberOfDescriptors Number of descriptors.
1949 @param IoSpaceMap Descriptor array
1950
1951 @retval EFI_INVALID_PARAMETER Invalid parameter
1952 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
1953 @retval EFI_SUCCESS Successfully get IO space map.
1954
1955 **/
1956 EFI_STATUS
1957 EFIAPI
1958 CoreGetIoSpaceMap (
1959 OUT UINTN *NumberOfDescriptors,
1960 OUT EFI_GCD_IO_SPACE_DESCRIPTOR **IoSpaceMap
1961 )
1962 {
1963 EFI_STATUS Status;
1964 LIST_ENTRY *Link;
1965 EFI_GCD_MAP_ENTRY *Entry;
1966 EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor;
1967
1968 //
1969 // Make sure parameters are valid
1970 //
1971 if (NumberOfDescriptors == NULL) {
1972 return EFI_INVALID_PARAMETER;
1973 }
1974 if (IoSpaceMap == NULL) {
1975 return EFI_INVALID_PARAMETER;
1976 }
1977
1978 CoreAcquireGcdIoLock ();
1979
1980 //
1981 // Count the number of descriptors
1982 //
1983 *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdIoSpaceMap);
1984
1985 //
1986 // Allocate the IoSpaceMap
1987 //
1988 *IoSpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_IO_SPACE_DESCRIPTOR));
1989 if (*IoSpaceMap == NULL) {
1990 Status = EFI_OUT_OF_RESOURCES;
1991 goto Done;
1992 }
1993
1994 //
1995 // Fill in the IoSpaceMap
1996 //
1997 Descriptor = *IoSpaceMap;
1998 Link = mGcdIoSpaceMap.ForwardLink;
1999 while (Link != &mGcdIoSpaceMap) {
2000 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
2001 BuildIoDescriptor (Descriptor, Entry);
2002 Descriptor++;
2003 Link = Link->ForwardLink;
2004 }
2005 Status = EFI_SUCCESS;
2006
2007 Done:
2008 CoreReleaseGcdIoLock ();
2009 return Status;
2010 }
2011
2012
2013 /**
2014 Converts a Resource Descriptor HOB attributes mask to an EFI Memory Descriptor
2015 capabilities mask
2016
2017 @param GcdMemoryType Type of resource in the GCD memory map.
2018 @param Attributes The attribute mask in the Resource Descriptor
2019 HOB.
2020
2021 @return The capabilities mask for an EFI Memory Descriptor.
2022
2023 **/
2024 UINT64
2025 CoreConvertResourceDescriptorHobAttributesToCapabilities (
2026 EFI_GCD_MEMORY_TYPE GcdMemoryType,
2027 UINT64 Attributes
2028 )
2029 {
2030 UINT64 Capabilities;
2031 GCD_ATTRIBUTE_CONVERSION_ENTRY *Conversion;
2032
2033 //
2034 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2035 //
2036 for (Capabilities = 0, Conversion = mAttributeConversionTable; Conversion->Attribute != 0; Conversion++) {
2037 if (Conversion->Memory || ((GcdMemoryType != EfiGcdMemoryTypeSystemMemory) && (GcdMemoryType != EfiGcdMemoryTypeMoreReliable))) {
2038 if (Attributes & Conversion->Attribute) {
2039 Capabilities |= Conversion->Capability;
2040 }
2041 }
2042 }
2043
2044 return Capabilities;
2045 }
2046
2047 /**
2048 Calculate total memory bin size neeeded.
2049
2050 @return The total memory bin size neeeded.
2051
2052 **/
2053 UINT64
2054 CalculateTotalMemoryBinSizeNeeded (
2055 VOID
2056 )
2057 {
2058 UINTN Index;
2059 UINT64 TotalSize;
2060
2061 //
2062 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
2063 //
2064 TotalSize = 0;
2065 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
2066 TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);
2067 }
2068
2069 return TotalSize;
2070 }
2071
2072 /**
2073 External function. Initializes memory services based on the memory
2074 descriptor HOBs. This function is responsible for priming the memory
2075 map, so memory allocations and resource allocations can be made.
2076 The first part of this function can not depend on any memory services
2077 until at least one memory descriptor is provided to the memory services.
2078
2079 @param HobStart The start address of the HOB.
2080 @param MemoryBaseAddress Start address of memory region found to init DXE
2081 core.
2082 @param MemoryLength Length of memory region found to init DXE core.
2083
2084 @retval EFI_SUCCESS Memory services successfully initialized.
2085
2086 **/
2087 EFI_STATUS
2088 CoreInitializeMemoryServices (
2089 IN VOID **HobStart,
2090 OUT EFI_PHYSICAL_ADDRESS *MemoryBaseAddress,
2091 OUT UINT64 *MemoryLength
2092 )
2093 {
2094 EFI_PEI_HOB_POINTERS Hob;
2095 EFI_MEMORY_TYPE_INFORMATION *EfiMemoryTypeInformation;
2096 UINTN DataSize;
2097 BOOLEAN Found;
2098 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
2099 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
2100 EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
2101 EFI_PHYSICAL_ADDRESS BaseAddress;
2102 UINT64 Length;
2103 UINT64 Attributes;
2104 UINT64 Capabilities;
2105 EFI_PHYSICAL_ADDRESS TestedMemoryBaseAddress;
2106 UINT64 TestedMemoryLength;
2107 EFI_PHYSICAL_ADDRESS HighAddress;
2108 EFI_HOB_GUID_TYPE *GuidHob;
2109 UINT32 ReservedCodePageNumber;
2110 UINT64 MinimalMemorySizeNeeded;
2111
2112 //
2113 // Point at the first HOB. This must be the PHIT HOB.
2114 //
2115 Hob.Raw = *HobStart;
2116 ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
2117
2118 //
2119 // Initialize the spin locks and maps in the memory services.
2120 // Also fill in the memory services into the EFI Boot Services Table
2121 //
2122 CoreInitializePool ();
2123
2124 //
2125 // Initialize Local Variables
2126 //
2127 PhitResourceHob = NULL;
2128 ResourceHob = NULL;
2129 BaseAddress = 0;
2130 Length = 0;
2131 Attributes = 0;
2132
2133 //
2134 // Cache the PHIT HOB for later use
2135 //
2136 PhitHob = Hob.HandoffInformationTable;
2137
2138 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
2139 ReservedCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
2140 ReservedCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
2141
2142 //
2143 // cache the Top address for loading modules at Fixed Address
2144 //
2145 gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop
2146 + EFI_PAGES_TO_SIZE(ReservedCodePageNumber);
2147 }
2148 //
2149 // See if a Memory Type Information HOB is available
2150 //
2151 GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
2152 if (GuidHob != NULL) {
2153 EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
2154 DataSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
2155 if (EfiMemoryTypeInformation != NULL && DataSize > 0 && DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION)) {
2156 CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);
2157 }
2158 }
2159
2160 //
2161 // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
2162 //
2163 MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
2164
2165 //
2166 // Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
2167 //
2168 Found = FALSE;
2169 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2170 //
2171 // Skip all HOBs except Resource Descriptor HOBs
2172 //
2173 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
2174 continue;
2175 }
2176
2177 //
2178 // Skip Resource Descriptor HOBs that do not describe tested system memory
2179 //
2180 ResourceHob = Hob.ResourceDescriptor;
2181 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
2182 continue;
2183 }
2184 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
2185 continue;
2186 }
2187
2188 //
2189 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
2190 //
2191 if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {
2192 continue;
2193 }
2194 if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
2195 continue;
2196 }
2197
2198 //
2199 // Cache the resource descriptor HOB for the memory region described by the PHIT HOB
2200 //
2201 PhitResourceHob = ResourceHob;
2202 Found = TRUE;
2203
2204 //
2205 // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB
2206 //
2207 Attributes = PhitResourceHob->ResourceAttribute;
2208 BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);
2209 Length = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
2210 if (Length < MinimalMemorySizeNeeded) {
2211 //
2212 // If that range is not large enough to intialize the DXE Core, then
2213 // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop
2214 //
2215 BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);
2216 Length = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);
2217 if (Length < MinimalMemorySizeNeeded) {
2218 //
2219 // If that range is not large enough to intialize the DXE Core, then
2220 // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List
2221 //
2222 BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
2223 Length = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));
2224 }
2225 }
2226 break;
2227 }
2228
2229 //
2230 // Assert if a resource descriptor HOB for the memory region described by the PHIT was not found
2231 //
2232 ASSERT (Found);
2233
2234 //
2235 // Take the range in the resource descriptor HOB for the memory region described
2236 // by the PHIT as higher priority if it is big enough. It can make the memory bin
2237 // allocated to be at the same memory region with PHIT that has more better compatibility
2238 // to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.
2239 //
2240 if (Length < MinimalMemorySizeNeeded) {
2241 //
2242 // Search all the resource descriptor HOBs from the highest possible addresses down for a memory
2243 // region that is big enough to initialize the DXE core. Always skip the PHIT Resource HOB.
2244 // The max address must be within the physically addressible range for the processor.
2245 //
2246 HighAddress = MAX_ADDRESS;
2247 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2248 //
2249 // Skip the Resource Descriptor HOB that contains the PHIT
2250 //
2251 if (Hob.ResourceDescriptor == PhitResourceHob) {
2252 continue;
2253 }
2254 //
2255 // Skip all HOBs except Resource Descriptor HOBs
2256 //
2257 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
2258 continue;
2259 }
2260
2261 //
2262 // Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ADDRESS
2263 //
2264 ResourceHob = Hob.ResourceDescriptor;
2265 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
2266 continue;
2267 }
2268 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
2269 continue;
2270 }
2271 if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS) {
2272 continue;
2273 }
2274
2275 //
2276 // Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB
2277 //
2278 if (HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS && ResourceHob->PhysicalStart <= HighAddress) {
2279 continue;
2280 }
2281
2282 //
2283 // Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core
2284 //
2285 TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);
2286 TestedMemoryLength = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
2287 if (TestedMemoryLength < MinimalMemorySizeNeeded) {
2288 continue;
2289 }
2290
2291 //
2292 // Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core
2293 //
2294 BaseAddress = TestedMemoryBaseAddress;
2295 Length = TestedMemoryLength;
2296 Attributes = ResourceHob->ResourceAttribute;
2297 HighAddress = ResourceHob->PhysicalStart;
2298 }
2299 }
2300
2301 DEBUG ((EFI_D_INFO, "CoreInitializeMemoryServices:\n"));
2302 DEBUG ((EFI_D_INFO, " BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded));
2303
2304 //
2305 // If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().
2306 //
2307 ASSERT (Length >= MinimalMemorySizeNeeded);
2308
2309 //
2310 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2311 //
2312 if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
2313 Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
2314 } else {
2315 Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
2316 }
2317
2318 //
2319 // Declare the very first memory region, so the EFI Memory Services are available.
2320 //
2321 CoreAddMemoryDescriptor (
2322 EfiConventionalMemory,
2323 BaseAddress,
2324 RShiftU64 (Length, EFI_PAGE_SHIFT),
2325 Capabilities
2326 );
2327
2328 *MemoryBaseAddress = BaseAddress;
2329 *MemoryLength = Length;
2330
2331 return EFI_SUCCESS;
2332 }
2333
2334
2335 /**
2336 External function. Initializes the GCD and memory services based on the memory
2337 descriptor HOBs. This function is responsible for priming the GCD map and the
2338 memory map, so memory allocations and resource allocations can be made. The
2339 HobStart will be relocated to a pool buffer.
2340
2341 @param HobStart The start address of the HOB
2342 @param MemoryBaseAddress Start address of memory region found to init DXE
2343 core.
2344 @param MemoryLength Length of memory region found to init DXE core.
2345
2346 @retval EFI_SUCCESS GCD services successfully initialized.
2347
2348 **/
2349 EFI_STATUS
2350 CoreInitializeGcdServices (
2351 IN OUT VOID **HobStart,
2352 IN EFI_PHYSICAL_ADDRESS MemoryBaseAddress,
2353 IN UINT64 MemoryLength
2354 )
2355 {
2356 EFI_PEI_HOB_POINTERS Hob;
2357 VOID *NewHobList;
2358 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;
2359 UINT8 SizeOfMemorySpace;
2360 UINT8 SizeOfIoSpace;
2361 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
2362 EFI_PHYSICAL_ADDRESS BaseAddress;
2363 UINT64 Length;
2364 EFI_STATUS Status;
2365 EFI_GCD_MAP_ENTRY *Entry;
2366 EFI_GCD_MEMORY_TYPE GcdMemoryType;
2367 EFI_GCD_IO_TYPE GcdIoType;
2368 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
2369 EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
2370 EFI_HOB_FIRMWARE_VOLUME *FirmwareVolumeHob;
2371 UINTN NumberOfDescriptors;
2372 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
2373 UINTN Index;
2374 UINT64 Capabilities;
2375 EFI_HOB_CPU * CpuHob;
2376 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMapHobList;
2377
2378 //
2379 // Cache the PHIT HOB for later use
2380 //
2381 PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
2382
2383 //
2384 // Get the number of address lines in the I/O and Memory space for the CPU
2385 //
2386 CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);
2387 ASSERT (CpuHob != NULL);
2388 SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;
2389 SizeOfIoSpace = CpuHob->SizeOfIoSpace;
2390
2391 //
2392 // Initialize the GCD Memory Space Map
2393 //
2394 Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);
2395 ASSERT (Entry != NULL);
2396
2397 Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;
2398
2399 InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);
2400
2401 CoreDumpGcdMemorySpaceMap (TRUE);
2402
2403 //
2404 // Initialize the GCD I/O Space Map
2405 //
2406 Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);
2407 ASSERT (Entry != NULL);
2408
2409 Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;
2410
2411 InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);
2412
2413 CoreDumpGcdIoSpaceMap (TRUE);
2414
2415 //
2416 // Walk the HOB list and add all resource descriptors to the GCD
2417 //
2418 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2419
2420 GcdMemoryType = EfiGcdMemoryTypeNonExistent;
2421 GcdIoType = EfiGcdIoTypeNonExistent;
2422
2423 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
2424
2425 ResourceHob = Hob.ResourceDescriptor;
2426
2427 switch (ResourceHob->ResourceType) {
2428 case EFI_RESOURCE_SYSTEM_MEMORY:
2429 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {
2430 if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
2431 GcdMemoryType = EfiGcdMemoryTypeMoreReliable;
2432 } else {
2433 GcdMemoryType = EfiGcdMemoryTypeSystemMemory;
2434 }
2435 }
2436 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {
2437 GcdMemoryType = EfiGcdMemoryTypeReserved;
2438 }
2439 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {
2440 GcdMemoryType = EfiGcdMemoryTypeReserved;
2441 }
2442 if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {
2443 GcdMemoryType = EfiGcdMemoryTypePersistent;
2444 }
2445 break;
2446 case EFI_RESOURCE_MEMORY_MAPPED_IO:
2447 case EFI_RESOURCE_FIRMWARE_DEVICE:
2448 GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;
2449 break;
2450 case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:
2451 case EFI_RESOURCE_MEMORY_RESERVED:
2452 GcdMemoryType = EfiGcdMemoryTypeReserved;
2453 break;
2454 case EFI_RESOURCE_IO:
2455 GcdIoType = EfiGcdIoTypeIo;
2456 break;
2457 case EFI_RESOURCE_IO_RESERVED:
2458 GcdIoType = EfiGcdIoTypeReserved;
2459 break;
2460 }
2461
2462 if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {
2463 //
2464 // Validate the Resource HOB Attributes
2465 //
2466 CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);
2467
2468 //
2469 // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask
2470 //
2471 Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (
2472 GcdMemoryType,
2473 ResourceHob->ResourceAttribute
2474 );
2475
2476 Status = CoreInternalAddMemorySpace (
2477 GcdMemoryType,
2478 ResourceHob->PhysicalStart,
2479 ResourceHob->ResourceLength,
2480 Capabilities
2481 );
2482 }
2483
2484 if (GcdIoType != EfiGcdIoTypeNonExistent) {
2485 Status = CoreAddIoSpace (
2486 GcdIoType,
2487 ResourceHob->PhysicalStart,
2488 ResourceHob->ResourceLength
2489 );
2490 }
2491 }
2492 }
2493
2494 //
2495 // Allocate first memory region from the GCD by the DXE core
2496 //
2497 Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);
2498 if (!EFI_ERROR (Status)) {
2499 ASSERT ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
2500 (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable));
2501 Status = CoreAllocateMemorySpace (
2502 EfiGcdAllocateAddress,
2503 Descriptor.GcdMemoryType,
2504 0,
2505 MemoryLength,
2506 &MemoryBaseAddress,
2507 gDxeCoreImageHandle,
2508 NULL
2509 );
2510 }
2511
2512 //
2513 // Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,
2514 // and Firmware Volume HOBs. Also update the EFI Memory Map with the memory allocation HOBs.
2515 //
2516 for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
2517 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
2518 MemoryHob = Hob.MemoryAllocation;
2519 BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;
2520 Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
2521 if (!EFI_ERROR (Status)) {
2522 Status = CoreAllocateMemorySpace (
2523 EfiGcdAllocateAddress,
2524 Descriptor.GcdMemoryType,
2525 0,
2526 MemoryHob->AllocDescriptor.MemoryLength,
2527 &BaseAddress,
2528 gDxeCoreImageHandle,
2529 NULL
2530 );
2531 if (!EFI_ERROR (Status) &&
2532 ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
2533 (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable))) {
2534 CoreAddMemoryDescriptor (
2535 MemoryHob->AllocDescriptor.MemoryType,
2536 MemoryHob->AllocDescriptor.MemoryBaseAddress,
2537 RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),
2538 Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME)
2539 );
2540 }
2541 }
2542 }
2543
2544 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
2545 FirmwareVolumeHob = Hob.FirmwareVolume;
2546 BaseAddress = FirmwareVolumeHob->BaseAddress;
2547 Status = CoreAllocateMemorySpace (
2548 EfiGcdAllocateAddress,
2549 EfiGcdMemoryTypeMemoryMappedIo,
2550 0,
2551 FirmwareVolumeHob->Length,
2552 &BaseAddress,
2553 gDxeCoreImageHandle,
2554 NULL
2555 );
2556 }
2557 }
2558
2559 //
2560 // Add and allocate the remaining unallocated system memory to the memory services.
2561 //
2562 Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
2563 ASSERT (Status == EFI_SUCCESS);
2564
2565 MemorySpaceMapHobList = NULL;
2566 for (Index = 0; Index < NumberOfDescriptors; Index++) {
2567 if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||
2568 (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)) {
2569 if (MemorySpaceMap[Index].ImageHandle == NULL) {
2570 BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);
2571 Length = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);
2572 if (Length == 0 || MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress) {
2573 continue;
2574 }
2575 if (((UINTN) MemorySpaceMap[Index].BaseAddress <= (UINTN) (*HobStart)) &&
2576 ((UINTN) (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN) PhitHob->EfiFreeMemoryBottom)) {
2577 //
2578 // Skip the memory space that covers HOB List, it should be processed
2579 // after HOB List relocation to avoid the resources allocated by others
2580 // to corrupt HOB List before its relocation.
2581 //
2582 MemorySpaceMapHobList = &MemorySpaceMap[Index];
2583 continue;
2584 }
2585 CoreAddMemoryDescriptor (
2586 EfiConventionalMemory,
2587 BaseAddress,
2588 RShiftU64 (Length, EFI_PAGE_SHIFT),
2589 MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME)
2590 );
2591 Status = CoreAllocateMemorySpace (
2592 EfiGcdAllocateAddress,
2593 MemorySpaceMap[Index].GcdMemoryType,
2594 0,
2595 Length,
2596 &BaseAddress,
2597 gDxeCoreImageHandle,
2598 NULL
2599 );
2600 }
2601 }
2602 }
2603
2604 //
2605 // Relocate HOB List to an allocated pool buffer.
2606 // The relocation should be at after all the tested memory resources added
2607 // (except the memory space that covers HOB List) to the memory services,
2608 // because the memory resource found in CoreInitializeMemoryServices()
2609 // may have not enough remaining resource for HOB List.
2610 //
2611 NewHobList = AllocateCopyPool (
2612 (UINTN) PhitHob->EfiFreeMemoryBottom - (UINTN) (*HobStart),
2613 *HobStart
2614 );
2615 ASSERT (NewHobList != NULL);
2616
2617 *HobStart = NewHobList;
2618 gHobList = NewHobList;
2619
2620 if (MemorySpaceMapHobList != NULL) {
2621 //
2622 // Add and allocate the memory space that covers HOB List to the memory services
2623 // after HOB List relocation.
2624 //
2625 BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);
2626 Length = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);
2627 CoreAddMemoryDescriptor (
2628 EfiConventionalMemory,
2629 BaseAddress,
2630 RShiftU64 (Length, EFI_PAGE_SHIFT),
2631 MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME)
2632 );
2633 Status = CoreAllocateMemorySpace (
2634 EfiGcdAllocateAddress,
2635 MemorySpaceMapHobList->GcdMemoryType,
2636 0,
2637 Length,
2638 &BaseAddress,
2639 gDxeCoreImageHandle,
2640 NULL
2641 );
2642 }
2643
2644 CoreFreePool (MemorySpaceMap);
2645
2646 return EFI_SUCCESS;
2647 }