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