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