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