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