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