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