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