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