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