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