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