]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Core/Dxe/Mem/Page.c
Make EdkModulePkg pass Intel IPF compiler with /W4 /WX switches, solving warning...
[mirror_edk2.git] / EdkModulePkg / Core / Dxe / Mem / Page.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 page.c\r
15\r
16Abstract:\r
17\r
18 EFI Memory page management\r
19\r
20\r
21Revision History\r
22\r
23--*/\r
24\r
25#include <DxeMain.h>\r
26\r
27#define EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT (EFI_PAGE_SIZE)\r
28\r
29//\r
30// Entry for tracking the memory regions for each memory type to help cooalese like memory types\r
31//\r
32typedef struct {\r
33 EFI_PHYSICAL_ADDRESS BaseAddress;\r
34 EFI_PHYSICAL_ADDRESS MaximumAddress;\r
35 UINT64 CurrentNumberOfPages;\r
36 UINTN InformationIndex;\r
37} EFI_MEMORY_TYPE_STAISTICS;\r
38\r
39//\r
40// MemoryMap - The current memory map\r
41//\r
42UINTN mMemoryMapKey = 0;\r
43\r
44//\r
45// mMapStack - space to use as temp storage to build new map descriptors\r
46// mMapDepth - depth of new descriptor stack\r
47//\r
48\r
49#define MAX_MAP_DEPTH 6\r
50UINTN mMapDepth = 0;\r
51MEMORY_MAP mMapStack[MAX_MAP_DEPTH];\r
52UINTN mFreeMapStack = 0;\r
53\r
54BOOLEAN mMemoryTypeInformationInitialized = FALSE;\r
55\r
56EFI_MEMORY_TYPE_STAISTICS mMemoryTypeStatistics[EfiMaxMemoryType + 1] = {\r
57 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiReservedMemoryType\r
58 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiLoaderCode\r
59 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiLoaderData\r
60 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiBootServicesCode\r
61 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiBootServicesData\r
62 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiRuntimeServicesCode\r
63 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiRuntimeServicesData\r
64 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiConventionalMemory\r
65 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiUnusableMemory\r
66 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiACPIReclaimMemory\r
67 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiACPIMemoryNVS\r
68 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiMemoryMappedIO\r
69 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiMemoryMappedIOPortSpace\r
70 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType }, // EfiPalCode\r
71 { 0, EFI_MAX_ADDRESS, 0, EfiMaxMemoryType } // EfiMaxMemoryType\r
72};\r
73\r
74EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = EFI_MAX_ADDRESS;\r
75\r
76EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {\r
77 { EfiReservedMemoryType, 0 },\r
78 { EfiLoaderCode, 0 },\r
79 { EfiLoaderData, 0 },\r
80 { EfiBootServicesCode, 0 },\r
81 { EfiBootServicesData, 0 },\r
82 { EfiRuntimeServicesCode, 0 },\r
83 { EfiRuntimeServicesData, 0 },\r
84 { EfiConventionalMemory, 0 },\r
85 { EfiUnusableMemory, 0 },\r
86 { EfiACPIReclaimMemory, 0 },\r
87 { EfiACPIMemoryNVS, 0 },\r
88 { EfiMemoryMappedIO, 0 },\r
89 { EfiMemoryMappedIOPortSpace, 0 },\r
90 { EfiPalCode, 0 },\r
91 { EfiMaxMemoryType, 0 }\r
92};\r
93\r
94//\r
95// Internal prototypes\r
96//\r
92dda53e 97STATIC\r
878ddf1f 98VOID \r
99PromoteMemoryResource (\r
100 VOID\r
101);\r
102\r
103STATIC\r
104VOID\r
105CoreAddRange (\r
106 IN EFI_MEMORY_TYPE Type,\r
107 IN EFI_PHYSICAL_ADDRESS Start,\r
108 IN EFI_PHYSICAL_ADDRESS End,\r
109 IN UINT64 Attribute\r
110 );\r
111\r
112STATIC\r
113VOID\r
114CoreFreeMemoryMapStack (\r
115 VOID\r
116 );\r
117\r
118STATIC\r
119EFI_STATUS\r
120CoreConvertPages (\r
121 IN UINT64 Start,\r
122 IN UINT64 NumberOfPages,\r
123 IN EFI_MEMORY_TYPE NewType\r
124 );\r
125\r
126STATIC\r
127VOID\r
128RemoveMemoryMapEntry (\r
129 MEMORY_MAP *Entry\r
130 );\r
131\r
132VOID\r
133CoreAcquireMemoryLock (\r
134 VOID\r
135 )\r
136/*++\r
137\r
138Routine Description:\r
139\r
140 Enter critical section by gaining lock on gMemoryLock\r
141\r
142Arguments:\r
143\r
144 None\r
145\r
146Returns:\r
147\r
148 None\r
149\r
150--*/\r
151{\r
152 CoreAcquireLock (&gMemoryLock);\r
153}\r
154\r
155\r
156VOID\r
157CoreReleaseMemoryLock (\r
158 VOID\r
159 )\r
160/*++\r
161\r
162Routine Description:\r
163\r
164 Exit critical section by releasing lock on gMemoryLock\r
165\r
166Arguments:\r
167\r
168 None\r
169\r
170Returns:\r
171\r
172 None\r
173\r
174--*/\r
175{\r
176 CoreReleaseLock (&gMemoryLock);\r
177}\r
178\r
92dda53e 179STATIC\r
878ddf1f 180VOID\r
181PromoteMemoryResource (\r
182 VOID\r
183 )\r
184/*++\r
185\r
186Routine Description:\r
187\r
188 Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable.\r
189\r
190Arguments:\r
191\r
192 None\r
193\r
194Returns:\r
195\r
196 None\r
197\r
198--*/\r
199{\r
200 LIST_ENTRY *Link;\r
201 EFI_GCD_MAP_ENTRY *Entry;\r
202\r
203 DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "Promote the memory resource\n"));\r
204 \r
205 CoreAcquireGcdMemoryLock ();\r
206 \r
207 Link = mGcdMemorySpaceMap.ForwardLink;\r
208 while (Link != &mGcdMemorySpaceMap) {\r
209\r
210 Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
211\r
212 if (Entry->GcdMemoryType == EfiGcdMemoryTypeReserved &&\r
213 Entry->EndAddress < EFI_MAX_ADDRESS &&\r
214 (Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==\r
215 (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)) {\r
216 //\r
217 // Update the GCD map\r
218 //\r
219 Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory;\r
220 Entry->Capabilities |= EFI_MEMORY_TESTED;\r
221 Entry->ImageHandle = gDxeCoreImageHandle;\r
222 Entry->DeviceHandle = NULL;\r
223\r
224 //\r
225 // Add to allocable system memory resource\r
226 // \r
227\r
228 CoreAddRange (\r
229 EfiConventionalMemory, \r
230 Entry->BaseAddress, \r
231 Entry->EndAddress, \r
232 Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)\r
233 );\r
234 CoreFreeMemoryMapStack ();\r
235 \r
236 }\r
237\r
238 Link = Link->ForwardLink;\r
239 }\r
240 \r
241 CoreReleaseGcdMemoryLock ();\r
242 \r
243 return;\r
244}\r
245\r
246VOID\r
247CoreAddMemoryDescriptor (\r
248 IN EFI_MEMORY_TYPE Type,\r
249 IN EFI_PHYSICAL_ADDRESS Start,\r
250 IN UINT64 NumberOfPages,\r
251 IN UINT64 Attribute\r
252 )\r
253/*++\r
254\r
255Routine Description:\r
256\r
257 Called to initialize the memory map and add descriptors to\r
258 the current descriptor list.\r
259\r
260 The first descriptor that is added must be general usable\r
261 memory as the addition allocates heap.\r
262\r
263Arguments:\r
264\r
265 Type - The type of memory to add\r
266\r
267 Start - The starting address in the memory range\r
268 Must be page aligned\r
269\r
270 NumberOfPages - The number of pages in the range\r
271\r
272 Attribute - Attributes of the memory to add\r
273\r
274Returns:\r
275\r
276 None. The range is added to the memory map\r
277\r
278--*/\r
279{\r
280 EFI_PHYSICAL_ADDRESS End;\r
281 EFI_STATUS Status;\r
282 UINTN Index;\r
283 UINTN FreeIndex;\r
284\r
285 if ((Start & EFI_PAGE_MASK) != 0) {\r
286 return;\r
287 }\r
288\r
289 if (Type >= EfiMaxMemoryType && Type <= 0x7fffffff) {\r
290 return;\r
291 }\r
292 \r
293 CoreAcquireMemoryLock ();\r
294 End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
295 CoreAddRange (Type, Start, End, Attribute);\r
296 CoreFreeMemoryMapStack ();\r
297 CoreReleaseMemoryLock ();\r
298\r
299 //\r
300 // Check to see if the statistics for the different memory types have already been established\r
301 //\r
302 if (mMemoryTypeInformationInitialized) {\r
303 return;\r
304 }\r
305\r
306 //\r
307 // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array\r
308 //\r
309 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
310 //\r
311 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
312 //\r
1cc8ee78 313 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
878ddf1f 314 if (Type < 0 || Type > EfiMaxMemoryType) {\r
315 continue;\r
316 }\r
317\r
318 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
319 //\r
320 // Allocate pages for the current memory type from the top of available memory\r
321 //\r
322 Status = CoreAllocatePages (\r
323 AllocateAnyPages,\r
324 Type,\r
325 gMemoryTypeInformation[Index].NumberOfPages,\r
326 &mMemoryTypeStatistics[Type].BaseAddress\r
327 );\r
328 if (EFI_ERROR (Status)) {\r
329 //\r
330 // If an error occurs allocating the pages for the current memory type, then \r
331 // free all the pages allocates for the previous memory types and return. This\r
332 // operation with be retied when/if more memory is added to the system\r
333 //\r
334 for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {\r
335 //\r
336 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
337 //\r
1cc8ee78 338 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[FreeIndex].Type);\r
878ddf1f 339 if (Type < 0 || Type > EfiMaxMemoryType) {\r
340 continue;\r
341 }\r
342\r
343 if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {\r
344 CoreFreePages (\r
345 mMemoryTypeStatistics[Type].BaseAddress, \r
346 gMemoryTypeInformation[FreeIndex].NumberOfPages\r
347 );\r
348 mMemoryTypeStatistics[Type].BaseAddress = 0;\r
349 mMemoryTypeStatistics[Type].MaximumAddress = EFI_MAX_ADDRESS;\r
350 }\r
351 }\r
352 return;\r
353 }\r
354\r
355 //\r
356 // Compute the address at the top of the current statistics\r
357 //\r
358 mMemoryTypeStatistics[Type].MaximumAddress = \r
359 mMemoryTypeStatistics[Type].BaseAddress + \r
360 LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;\r
361\r
362 //\r
363 // If the current base address is the lowest address so far, then update the default \r
364 // maximum address\r
365 //\r
366 if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {\r
367 mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;\r
368 }\r
369 }\r
370 }\r
371\r
372 //\r
373 // There was enough system memory for all the the memory types were allocated. So,\r
374 // those memory areas can be freed for future allocations, and all future memory\r
375 // allocations can occur within their respective bins\r
376 //\r
377 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
378 //\r
379 // Make sure the memory type in the gMemoryTypeInformation[] array is valid\r
380 //\r
1cc8ee78 381 Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);\r
878ddf1f 382 if (Type < 0 || Type > EfiMaxMemoryType) {\r
383 continue;\r
384 }\r
385\r
386 if (gMemoryTypeInformation[Index].NumberOfPages != 0) {\r
387 CoreFreePages (\r
388 mMemoryTypeStatistics[Type].BaseAddress, \r
389 gMemoryTypeInformation[Index].NumberOfPages\r
390 );\r
391 gMemoryTypeInformation[Index].NumberOfPages = 0;\r
392 }\r
393 }\r
394\r
395 //\r
396 // If the number of pages reserved for a memory type is 0, then all allocations for that type\r
397 // should be in the default range.\r
398 //\r
1cc8ee78 399 for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {\r
878ddf1f 400 for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {\r
401 if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {\r
402 mMemoryTypeStatistics[Type].InformationIndex = Index;\r
403 }\r
404 }\r
405 mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;\r
406 if (mMemoryTypeStatistics[Type].MaximumAddress == EFI_MAX_ADDRESS) {\r
407 mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;\r
408 }\r
409 }\r
410\r
411 mMemoryTypeInformationInitialized = TRUE;\r
412}\r
413\r
414\r
415STATIC\r
416VOID\r
417CoreAddRange (\r
418 IN EFI_MEMORY_TYPE Type,\r
419 IN EFI_PHYSICAL_ADDRESS Start,\r
420 IN EFI_PHYSICAL_ADDRESS End,\r
421 IN UINT64 Attribute\r
422 )\r
423/*++\r
424\r
425Routine Description:\r
426\r
427 Internal function. Adds a ranges to the memory map.\r
428 The range must not already exist in the map.\r
429\r
430Arguments:\r
431\r
432 Type - The type of memory range to add\r
433\r
434 Start - The starting address in the memory range\r
435 Must be paged aligned\r
436\r
437 End - The last address in the range\r
438 Must be the last byte of a page\r
439\r
440 Attribute - The attributes of the memory range to add\r
441\r
442Returns:\r
443\r
444 None. The range is added to the memory map\r
445\r
446--*/\r
447{\r
448 LIST_ENTRY *Link;\r
449 MEMORY_MAP *Entry;\r
450\r
451 ASSERT ((Start & EFI_PAGE_MASK) == 0);\r
452 ASSERT (End > Start) ;\r
453\r
454 ASSERT_LOCKED (&gMemoryLock);\r
455 \r
456 DEBUG ((EFI_D_PAGE, "AddRange: %lx-%lx to %d\n", Start, End, Type));\r
457\r
458 //\r
459 // Memory map being altered so updated key\r
460 //\r
461 mMemoryMapKey += 1;\r
462\r
463 //\r
464 // UEFI 2.0 added an event group for notificaiton on memory map changes.\r
465 // So we need to signal this Event Group every time the memory map changes.\r
466 // If we are in EFI 1.10 compatability mode no event groups will be \r
467 // found and nothing will happen we we call this function. These events\r
468 // will get signaled but since a lock is held around the call to this \r
469 // function the notificaiton events will only be called after this funciton\r
470 // returns and the lock is released.\r
471 //\r
472 CoreNotifySignalList (&gEfiEventMemoryMapChangeGuid);\r
473\r
474 //\r
475 // Look for adjoining memory descriptor\r
476 //\r
477 \r
478 // Two memory descriptors can only be merged if they have the same Type\r
479 // and the same Attribute\r
480 //\r
481\r
482 Link = gMemoryMap.ForwardLink;\r
483 while (Link != &gMemoryMap) {\r
484 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
485 Link = Link->ForwardLink;\r
486\r
487 if (Entry->Type != Type) {\r
488 continue;\r
489 }\r
490\r
491 if (Entry->Attribute != Attribute) {\r
492 continue;\r
493 }\r
494\r
495 if (Entry->End + 1 == Start) {\r
496 \r
497 Start = Entry->Start;\r
498 RemoveMemoryMapEntry (Entry);\r
499\r
500 } else if (Entry->Start == End + 1) {\r
501 \r
502 End = Entry->End;\r
503 RemoveMemoryMapEntry (Entry);\r
504 }\r
505 }\r
506\r
507 //\r
508 // Add descriptor \r
509 //\r
510\r
511 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;\r
512 mMapStack[mMapDepth].FromPool = FALSE;\r
513 mMapStack[mMapDepth].Type = Type;\r
514 mMapStack[mMapDepth].Start = Start;\r
515 mMapStack[mMapDepth].End = End;\r
516 mMapStack[mMapDepth].VirtualStart = 0;\r
517 mMapStack[mMapDepth].Attribute = Attribute;\r
518 InsertTailList (&gMemoryMap, &mMapStack[mMapDepth].Link);\r
519\r
520 mMapDepth += 1;\r
521 ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
522\r
523 return ;\r
524}\r
525\r
526STATIC\r
527VOID\r
528CoreFreeMemoryMapStack (\r
529 VOID\r
530 )\r
531/*++\r
532\r
533Routine Description:\r
534\r
535 Internal function. Moves any memory descriptors that are on the\r
536 temporary descriptor stack to heap.\r
537\r
538Arguments:\r
539\r
540 None\r
541\r
542Returns:\r
543\r
544 None\r
545\r
546--*/\r
547{\r
548 MEMORY_MAP *Entry;\r
549 MEMORY_MAP *Entry2;\r
550 LIST_ENTRY *Link2;\r
551\r
552 ASSERT_LOCKED (&gMemoryLock);\r
553\r
554 //\r
555 // If already freeing the map stack, then return\r
556 //\r
557 if (mFreeMapStack) {\r
558 return ;\r
559 }\r
560\r
561 //\r
562 // Move the temporary memory descriptor stack into pool\r
563 //\r
564 mFreeMapStack += 1;\r
565\r
566 while (mMapDepth) {\r
567\r
568 //\r
569 // Allocate memory for a entry\r
570 //\r
571 Entry = CoreAllocatePoolI (EfiRuntimeServicesData, sizeof(MEMORY_MAP));\r
572 \r
573 ASSERT (Entry);\r
574\r
575 //\r
576 // Update to proper entry\r
577 //\r
578 mMapDepth -= 1;\r
579\r
580 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
581\r
582 //\r
583 // Move this entry to general pool\r
584 //\r
585 RemoveEntryList (&mMapStack[mMapDepth].Link);\r
586 mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
587\r
588 CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
589 Entry->FromPool = TRUE;\r
590\r
591 //\r
592 // Find insertion location\r
593 //\r
594 for (Link2 = gMemoryMap.ForwardLink; Link2 != &gMemoryMap; Link2 = Link2->ForwardLink) {\r
595 Entry2 = CR (Link2, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
596 if (Entry2->FromPool && Entry2->Start > Entry->Start) {\r
597 break;\r
598 }\r
599 }\r
600\r
601 InsertTailList (Link2, &Entry->Link);\r
602\r
603 } else {\r
604\r
605 //\r
606 // It was removed, don't move it\r
607 //\r
608 CoreFreePoolI (Entry);\r
609\r
610 }\r
611 }\r
612\r
613 mFreeMapStack -= 1;\r
614}\r
615\r
616STATIC\r
617VOID\r
618RemoveMemoryMapEntry (\r
619 MEMORY_MAP *Entry\r
620 )\r
621/*++\r
622\r
623Routine Description:\r
624\r
625 Internal function. Removes a descriptor entry.\r
626\r
627Arguments:\r
628\r
629 Entry - The entry to remove\r
630\r
631Returns:\r
632\r
633 None\r
634\r
635--*/\r
636{\r
637 RemoveEntryList (&Entry->Link);\r
638 Entry->Link.ForwardLink = NULL;\r
639\r
640 if (Entry->FromPool) {\r
641 CoreFreePoolI (Entry);\r
642 }\r
643}\r
644\r
645\r
646STATIC\r
647EFI_STATUS\r
648CoreConvertPages (\r
649 IN UINT64 Start,\r
650 IN UINT64 NumberOfPages,\r
651 IN EFI_MEMORY_TYPE NewType\r
652 )\r
653/*++\r
654\r
655Routine Description:\r
656\r
657 Internal function. Converts a memory range to the specified type.\r
658 The range must exist in the memory map.\r
659\r
660Arguments:\r
661\r
662 Start - The first address of the range\r
663 Must be page aligned\r
664\r
665 NumberOfPages - The number of pages to convert\r
666\r
667 NewType - The new type for the memory range\r
668\r
669Returns:\r
670\r
671 EFI_INVALID_PARAMETER - Invalid parameter\r
672 \r
673 EFI_NOT_FOUND - Could not find a descriptor cover the specified range \r
674 or convertion not allowed.\r
675 \r
676 EFI_SUCCESS - Successfully converts the memory range to the specified type.\r
677\r
678--*/\r
679{\r
680\r
681 UINT64 NumberOfBytes;\r
682 UINT64 End;\r
683 UINT64 RangeEnd;\r
684 UINT64 Attribute;\r
685 LIST_ENTRY *Link;\r
686 MEMORY_MAP *Entry;\r
687\r
688 Entry = NULL;\r
689 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);\r
690 End = Start + NumberOfBytes - 1;\r
691\r
692 ASSERT (NumberOfPages);\r
693 ASSERT ((Start & EFI_PAGE_MASK) == 0);\r
694 ASSERT (End > Start) ;\r
695 ASSERT_LOCKED (&gMemoryLock);\r
696\r
697 if (NumberOfPages == 0 || (Start & EFI_PAGE_MASK ) || (Start > (Start + NumberOfBytes))) {\r
698 return EFI_INVALID_PARAMETER;\r
699 }\r
700\r
701 //\r
702 // Convert the entire range\r
703 //\r
704\r
705 while (Start < End) {\r
706\r
707 //\r
708 // Find the entry that the covers the range\r
709 //\r
710 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
711 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
712\r
713 if (Entry->Start <= Start && Entry->End > Start) {\r
714 break;\r
715 }\r
716 }\r
717\r
718 if (Link == &gMemoryMap) {\r
719 DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "ConvertPages: failed to find range %lx - %lx\n", Start, End));\r
720 return EFI_NOT_FOUND;\r
721 }\r
722\r
723 //\r
724 // Convert range to the end, or to the end of the descriptor\r
725 // if that's all we've got\r
726 //\r
727 RangeEnd = End;\r
728 if (Entry->End < End) {\r
729 RangeEnd = Entry->End;\r
730 }\r
731\r
732 DEBUG ((EFI_D_PAGE, "ConvertRange: %lx-%lx to %d\n", Start, RangeEnd, NewType));\r
733\r
734 //\r
735 // Debug code - verify conversion is allowed\r
736 //\r
737 if (!(NewType == EfiConventionalMemory ? 1 : 0) ^ (Entry->Type == EfiConventionalMemory ? 1 : 0)) {\r
738 DEBUG ((EFI_D_ERROR , "ConvertPages: Incompatible memory types\n"));\r
739 return EFI_NOT_FOUND;\r
740 } \r
741\r
742 //\r
743 // Update counters for the number of pages allocated to each memory type\r
744 //\r
745 if (Entry->Type >= 0 && Entry->Type < EfiMaxMemoryType) {\r
746 if (Start >= mMemoryTypeStatistics[Entry->Type].BaseAddress && \r
747 Start <= mMemoryTypeStatistics[Entry->Type].MaximumAddress) {\r
748 if (NumberOfPages > mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages) {\r
749 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages = 0;\r
750 } else {\r
751 mMemoryTypeStatistics[Entry->Type].CurrentNumberOfPages -= NumberOfPages;\r
752 }\r
753 }\r
754 }\r
755\r
756 if (NewType >= 0 && NewType < EfiMaxMemoryType) {\r
757 if (Start >= mMemoryTypeStatistics[NewType].BaseAddress && Start <= mMemoryTypeStatistics[NewType].MaximumAddress) {\r
758 mMemoryTypeStatistics[NewType].CurrentNumberOfPages += NumberOfPages;\r
759 if (mMemoryTypeStatistics[NewType].CurrentNumberOfPages > \r
760 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages) {\r
761 gMemoryTypeInformation[mMemoryTypeStatistics[NewType].InformationIndex].NumberOfPages = (UINT32)mMemoryTypeStatistics[NewType].CurrentNumberOfPages;\r
762 }\r
763 }\r
764 }\r
765\r
766 //\r
767 // Pull range out of descriptor\r
768 //\r
769 if (Entry->Start == Start) {\r
770 \r
771 //\r
772 // Clip start\r
773 //\r
774 Entry->Start = RangeEnd + 1;\r
775\r
776 } else if (Entry->End == RangeEnd) {\r
777 \r
778 //\r
779 // Clip end\r
780 //\r
781 Entry->End = Start - 1;\r
782\r
783 } else {\r
784\r
785 //\r
786 // Pull it out of the center, clip current\r
787 //\r
788 \r
789 //\r
790 // Add a new one\r
791 //\r
792 mMapStack[mMapDepth].Signature = MEMORY_MAP_SIGNATURE;\r
793 mMapStack[mMapDepth].FromPool = FALSE;\r
794 mMapStack[mMapDepth].Type = Entry->Type;\r
795 mMapStack[mMapDepth].Start = RangeEnd+1;\r
796 mMapStack[mMapDepth].End = Entry->End;\r
797\r
798 //\r
799 // Inherit Attribute from the Memory Descriptor that is being clipped\r
800 //\r
801 mMapStack[mMapDepth].Attribute = Entry->Attribute;\r
802\r
803 Entry->End = Start - 1;\r
804 ASSERT (Entry->Start < Entry->End);\r
805\r
806 Entry = &mMapStack[mMapDepth];\r
807 InsertTailList (&gMemoryMap, &Entry->Link);\r
808\r
809 mMapDepth += 1;\r
810 ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
811 }\r
812\r
813 //\r
814 // The new range inherits the same Attribute as the Entry \r
815 //it is being cut out of\r
816 //\r
817 Attribute = Entry->Attribute;\r
818\r
819 //\r
820 // If the descriptor is empty, then remove it from the map\r
821 //\r
822 if (Entry->Start == Entry->End + 1) {\r
823 RemoveMemoryMapEntry (Entry);\r
824 Entry = NULL;\r
825 }\r
826 \r
827 //\r
828 // Add our new range in\r
829 //\r
830 CoreAddRange (NewType, Start, RangeEnd, Attribute);\r
831\r
832 //\r
833 // Move any map descriptor stack to general pool\r
834 //\r
835 CoreFreeMemoryMapStack ();\r
836\r
837 //\r
838 // Bump the starting address, and convert the next range\r
839 //\r
840 Start = RangeEnd + 1;\r
841 }\r
842\r
843 //\r
844 // Converted the whole range, done\r
845 //\r
846\r
847 return EFI_SUCCESS;\r
848}\r
849\r
850\r
851STATIC\r
852UINT64\r
853CoreFindFreePagesI (\r
854 IN UINT64 MaxAddress,\r
855 IN UINT64 NumberOfPages,\r
856 IN EFI_MEMORY_TYPE NewType,\r
857 IN UINTN Alignment\r
858 )\r
859/*++\r
860\r
861Routine Description:\r
862\r
863 Internal function. Finds a consecutive free page range below\r
864 the requested address.\r
865\r
866Arguments:\r
867\r
868 MaxAddress - The address that the range must be below\r
869\r
870 NumberOfPages - Number of pages needed\r
871\r
872 NewType - The type of memory the range is going to be turned into\r
873\r
874 Alignment - Bits to align with\r
875\r
876Returns:\r
877\r
878 The base address of the range, or 0 if the range was not found\r
879\r
880--*/\r
881{\r
882 UINT64 NumberOfBytes;\r
883 UINT64 Target;\r
884 UINT64 DescStart;\r
885 UINT64 DescEnd;\r
886 UINT64 DescNumberOfBytes;\r
887 LIST_ENTRY *Link;\r
888 MEMORY_MAP *Entry;\r
889\r
890 if ((MaxAddress < EFI_PAGE_MASK) ||(NumberOfPages == 0)) {\r
891 return 0;\r
892 }\r
893\r
894 if ((MaxAddress & EFI_PAGE_MASK) != EFI_PAGE_MASK) {\r
895 \r
896 //\r
897 // If MaxAddress is not aligned to the end of a page\r
898 //\r
899 \r
900 //\r
901 // Change MaxAddress to be 1 page lower\r
902 //\r
903 MaxAddress -= (EFI_PAGE_MASK + 1);\r
904 \r
905 //\r
906 // Set MaxAddress to a page boundary\r
907 //\r
908 MaxAddress &= ~EFI_PAGE_MASK;\r
909 \r
910 //\r
911 // Set MaxAddress to end of the page\r
912 //\r
913 MaxAddress |= EFI_PAGE_MASK;\r
914 }\r
915\r
916 NumberOfBytes = LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT);\r
917 Target = 0;\r
918\r
919 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
920 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
921 \r
922 //\r
923 // If it's not a free entry, don't bother with it\r
924 //\r
925 if (Entry->Type != EfiConventionalMemory) {\r
926 continue;\r
927 }\r
928\r
929 DescStart = Entry->Start;\r
930 DescEnd = Entry->End;\r
931\r
932 //\r
933 // If desc is past max allowed address, skip it\r
934 //\r
935 if (DescStart >= MaxAddress) {\r
936 continue;\r
937 }\r
938\r
939 //\r
940 // If desc ends past max allowed address, clip the end\r
941 //\r
942 if (DescEnd >= MaxAddress) {\r
943 DescEnd = MaxAddress;\r
944 }\r
945\r
946 DescEnd = ((DescEnd + 1) & (~(Alignment - 1))) - 1;\r
947\r
948 //\r
949 // Compute the number of bytes we can used from this \r
950 // descriptor, and see it's enough to satisfy the request\r
951 //\r
952 DescNumberOfBytes = DescEnd - DescStart + 1;\r
953\r
954 if (DescNumberOfBytes >= NumberOfBytes) {\r
955\r
956 //\r
957 // If this is the best match so far remember it\r
958 //\r
959 if (DescEnd > Target) {\r
960 Target = DescEnd;\r
961 }\r
962 }\r
963 } \r
964\r
965 //\r
966 // If this is a grow down, adjust target to be the allocation base\r
967 //\r
968 Target -= NumberOfBytes - 1;\r
969\r
970 //\r
971 // If we didn't find a match, return 0\r
972 //\r
973 if ((Target & EFI_PAGE_MASK) != 0) {\r
974 return 0;\r
975 }\r
976\r
977 return Target;\r
978}\r
979\r
980STATIC\r
981UINT64\r
982FindFreePages (\r
983 IN UINT64 MaxAddress,\r
984 IN UINT64 NoPages,\r
985 IN EFI_MEMORY_TYPE NewType,\r
986 IN UINTN Alignment\r
987 )\r
988/*++\r
989\r
990Routine Description:\r
991\r
992 Internal function. Finds a consecutive free page range below\r
993 the requested address\r
994\r
995Arguments:\r
996\r
997 MaxAddress - The address that the range must be below\r
998\r
999 NoPages - Number of pages needed\r
1000\r
1001 NewType - The type of memory the range is going to be turned into\r
1002\r
1003 Alignment - Bits to align with\r
1004\r
1005Returns:\r
1006\r
1007 The base address of the range, or 0 if the range was not found.\r
1008\r
1009--*/\r
1010{\r
1011 UINT64 NewMaxAddress;\r
1012 UINT64 Start;\r
1013\r
1014 NewMaxAddress = MaxAddress;\r
1015\r
1016 if (NewType >= 0 && NewType < EfiMaxMemoryType && NewMaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {\r
1017 NewMaxAddress = mMemoryTypeStatistics[NewType].MaximumAddress;\r
1018 } else {\r
1019 if (NewMaxAddress > mDefaultMaximumAddress) {\r
1020 NewMaxAddress = mDefaultMaximumAddress;\r
1021 }\r
1022 }\r
1023\r
1024 Start = CoreFindFreePagesI (NewMaxAddress, NoPages, NewType, Alignment);\r
1025 if (!Start) {\r
1026 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);\r
1027 if (!Start) {\r
1028 //\r
1029 // Here means there may be no enough memory to use, so try to go through\r
1030 // all the memory descript to promote the untested memory directly\r
1031 //\r
1032 PromoteMemoryResource ();\r
1033\r
1034 //\r
1035 // Allocate memory again after the memory resource re-arranged\r
1036 //\r
1037 Start = CoreFindFreePagesI (MaxAddress, NoPages, NewType, Alignment);\r
1038 }\r
1039 }\r
1040\r
1041 return Start;\r
1042}\r
1043\r
1044\r
1045EFI_STATUS\r
1046EFIAPI\r
1047CoreAllocatePages (\r
1048 IN EFI_ALLOCATE_TYPE Type,\r
1049 IN EFI_MEMORY_TYPE MemoryType,\r
1050 IN UINTN NumberOfPages,\r
1051 IN OUT EFI_PHYSICAL_ADDRESS *Memory\r
1052 )\r
1053/*++\r
1054\r
1055Routine Description:\r
1056\r
1057 Allocates pages from the memory map.\r
1058\r
1059Arguments:\r
1060\r
1061 Type - The type of allocation to perform\r
1062\r
1063 MemoryType - The type of memory to turn the allocated pages into\r
1064\r
1065 NumberOfPages - The number of pages to allocate\r
1066\r
1067 Memory - A pointer to receive the base allocated memory address\r
1068\r
1069Returns:\r
1070\r
1071 Status. On success, Memory is filled in with the base address allocated\r
1072\r
1073 EFI_INVALID_PARAMETER - Parameters violate checking rules defined in spec.\r
1074 \r
1075 EFI_NOT_FOUND - Could not allocate pages match the requirement.\r
1076 \r
1077 EFI_OUT_OF_RESOURCES - No enough pages to allocate.\r
1078 \r
1079 EFI_SUCCESS - Pages successfully allocated.\r
1080\r
1081--*/\r
1082{\r
1083 EFI_STATUS Status;\r
1084 UINT64 Start;\r
1085 UINT64 MaxAddress;\r
1086 UINTN Alignment;\r
1087\r
1088 if (Type < AllocateAnyPages || Type >= (UINTN) MaxAllocateType) {\r
1089 return EFI_INVALID_PARAMETER;\r
1090 }\r
1091\r
1092 if ((MemoryType >= EfiMaxMemoryType && MemoryType <= 0x7fffffff) ||\r
1093 MemoryType == EfiConventionalMemory) {\r
1094 return EFI_INVALID_PARAMETER;\r
1095 }\r
1096\r
1097 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;\r
1098\r
1099 if (MemoryType == EfiACPIReclaimMemory ||\r
1100 MemoryType == EfiACPIMemoryNVS ||\r
1101 MemoryType == EfiRuntimeServicesCode ||\r
1102 MemoryType == EfiRuntimeServicesData) {\r
1103\r
1104 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
1105 }\r
1106\r
1107 if (Type == AllocateAddress) {\r
1108 if ((*Memory & (Alignment - 1)) != 0) {\r
1109 return EFI_NOT_FOUND;\r
1110 }\r
1111 }\r
1112\r
1113 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;\r
1114 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);\r
1115\r
1116 //\r
1117 // If this is for below a particular address, then \r
1118 //\r
1119 Start = *Memory;\r
1120 \r
1121 //\r
1122 // The max address is the max natively addressable address for the processor\r
1123 //\r
1124 MaxAddress = EFI_MAX_ADDRESS;\r
1125 \r
1126 if (Type == AllocateMaxAddress) {\r
1127 MaxAddress = Start;\r
1128 }\r
1129\r
1130 CoreAcquireMemoryLock ();\r
1131 \r
1132 //\r
1133 // If not a specific address, then find an address to allocate\r
1134 //\r
1135 if (Type != AllocateAddress) {\r
1136 Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);\r
1137 if (Start == 0) {\r
1138 Status = EFI_OUT_OF_RESOURCES;\r
1139 goto Done;\r
1140 }\r
1141 }\r
1142\r
1143 //\r
1144 // Convert pages from FreeMemory to the requested type\r
1145 //\r
1146 Status = CoreConvertPages (Start, NumberOfPages, MemoryType);\r
1147\r
1148Done:\r
1149 CoreReleaseMemoryLock ();\r
1150\r
1151 if (!EFI_ERROR (Status)) {\r
1152 *Memory = Start;\r
1153 }\r
1154\r
1155 return Status;\r
1156}\r
1157\r
1158\r
1159\r
1160\r
1161EFI_STATUS \r
1162EFIAPI\r
1163CoreFreePages (\r
1164 IN EFI_PHYSICAL_ADDRESS Memory,\r
1165 IN UINTN NumberOfPages\r
1166 )\r
1167/*++\r
1168\r
1169Routine Description:\r
1170\r
1171 Frees previous allocated pages.\r
1172\r
1173Arguments:\r
1174\r
1175 Memory - Base address of memory being freed\r
1176\r
1177 NumberOfPages - The number of pages to free\r
1178\r
1179Returns:\r
1180\r
1181 EFI_NOT_FOUND - Could not find the entry that covers the range\r
1182 \r
1183 EFI_INVALID_PARAMETER - Address not aligned\r
1184 \r
1185 EFI_SUCCESS -Pages successfully freed.\r
1186\r
1187--*/\r
1188{\r
1189 EFI_STATUS Status;\r
1190 LIST_ENTRY *Link;\r
1191 MEMORY_MAP *Entry;\r
1192 UINTN Alignment;\r
1193\r
1194 //\r
1195 // Free the range\r
1196 //\r
1197 CoreAcquireMemoryLock ();\r
1198\r
1199 //\r
1200 // Find the entry that the covers the range\r
1201 //\r
1202 Entry = NULL;\r
1203 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1204 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1205 if (Entry->Start <= Memory && Entry->End > Memory) {\r
1206 break;\r
1207 }\r
1208 }\r
1209 if (Link == &gMemoryMap) {\r
1210 CoreReleaseMemoryLock ();\r
1211 return EFI_NOT_FOUND;\r
1212 }\r
1213\r
1214 Alignment = EFI_DEFAULT_PAGE_ALLOCATION_ALIGNMENT;\r
1215\r
1216 if (Entry->Type == EfiACPIReclaimMemory ||\r
1217 Entry->Type == EfiACPIMemoryNVS ||\r
1218 Entry->Type == EfiRuntimeServicesCode ||\r
1219 Entry->Type == EfiRuntimeServicesData) {\r
1220\r
1221 Alignment = EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT;\r
1222\r
1223 }\r
1224\r
1225 if ((Memory & (Alignment - 1)) != 0) {\r
1226 CoreReleaseMemoryLock ();\r
1227 return EFI_INVALID_PARAMETER;\r
1228 }\r
1229\r
1230 NumberOfPages += EFI_SIZE_TO_PAGES (Alignment) - 1;\r
1231 NumberOfPages &= ~(EFI_SIZE_TO_PAGES (Alignment) - 1);\r
1232\r
1233 Status = CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
1234\r
1235 CoreReleaseMemoryLock ();\r
1236\r
1237 if (EFI_ERROR (Status)) {\r
1238 return Status;\r
1239 }\r
1240\r
1241 //\r
1242 // Destroy the contents\r
1243 //\r
1244 if (Memory < EFI_MAX_ADDRESS) {\r
1245 DEBUG_CLEAR_MEMORY ((VOID *)(UINTN)Memory, NumberOfPages << EFI_PAGE_SHIFT);\r
1246 }\r
1247 \r
1248 return Status;\r
1249}\r
1250\r
1251\r
1252\r
1253EFI_STATUS\r
1254EFIAPI\r
1255CoreGetMemoryMap (\r
1256 IN OUT UINTN *MemoryMapSize,\r
1257 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1258 OUT UINTN *MapKey,\r
1259 OUT UINTN *DescriptorSize,\r
1260 OUT UINT32 *DescriptorVersion\r
1261 )\r
1262/*++\r
1263\r
1264Routine Description:\r
1265\r
1266 This function returns a copy of the current memory map. The map is an array of \r
1267 memory descriptors, each of which describes a contiguous block of memory.\r
1268\r
1269Arguments:\r
1270\r
1271 MemoryMapSize - A pointer to the size, in bytes, of the MemoryMap buffer. On\r
1272 input, this is the size of the buffer allocated by the caller. \r
1273 On output, it is the size of the buffer returned by the firmware \r
1274 if the buffer was large enough, or the size of the buffer needed \r
1275 to contain the map if the buffer was too small.\r
1276 MemoryMap - A pointer to the buffer in which firmware places the current memory map.\r
1277 MapKey - A pointer to the location in which firmware returns the key for the\r
1278 current memory map.\r
1279 DescriptorSize - A pointer to the location in which firmware returns the size, in\r
1280 bytes, of an individual EFI_MEMORY_DESCRIPTOR.\r
1281 DescriptorVersion - A pointer to the location in which firmware returns the version\r
1282 number associated with the EFI_MEMORY_DESCRIPTOR.\r
1283\r
1284Returns:\r
1285\r
1286 EFI_SUCCESS - The memory map was returned in the MemoryMap buffer. \r
1287 EFI_BUFFER_TOO_SMALL - The MemoryMap buffer was too small. The current buffer size\r
1288 needed to hold the memory map is returned in MemoryMapSize.\r
1289 EFI_INVALID_PARAMETER - One of the parameters has an invalid value. \r
1290\r
1291--*/\r
1292{\r
1293 EFI_STATUS Status;\r
1294 UINTN Size; \r
1295 UINTN BufferSize; \r
1296 UINTN NumberOfRuntimeEntries;\r
1297 LIST_ENTRY *Link;\r
1298 MEMORY_MAP *Entry; \r
1299 EFI_GCD_MAP_ENTRY *GcdMapEntry; \r
1300\r
1301 //\r
1302 // Make sure the parameters are valid\r
1303 //\r
1304 if (MemoryMapSize == NULL) {\r
1305 return EFI_INVALID_PARAMETER;\r
1306 }\r
1307 \r
1308 CoreAcquireGcdMemoryLock ();\r
1309 \r
1310 //\r
1311 // Count the number of Reserved and MMIO entries that are marked for runtime use\r
1312 //\r
1313 NumberOfRuntimeEntries = 0;\r
1314 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
1315 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1316 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
1317 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {\r
1318 if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {\r
1319 NumberOfRuntimeEntries++;\r
1320 }\r
1321 }\r
1322 }\r
1323\r
1324 Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
1325\r
1326 //\r
1327 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
1328 // prevent people from having pointer math bugs in their code.\r
1329 // now you have to use *DescriptorSize to make things work.\r
1330 //\r
1331 Size += sizeof(UINT64) - (Size % sizeof (UINT64));\r
1332\r
1333 if (DescriptorSize != NULL) {\r
1334 *DescriptorSize = Size;\r
1335 }\r
1336 \r
1337 if (DescriptorVersion != NULL) {\r
1338 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
1339 }\r
1340\r
1341 CoreAcquireMemoryLock ();\r
1342\r
1343 //\r
1344 // Compute the buffer size needed to fit the entire map\r
1345 //\r
1346 BufferSize = Size * NumberOfRuntimeEntries;\r
1347 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1348 BufferSize += Size;\r
1349 }\r
1350\r
1351 if (*MemoryMapSize < BufferSize) {\r
1352 Status = EFI_BUFFER_TOO_SMALL;\r
1353 goto Done;\r
1354 }\r
1355\r
1356 if (MemoryMap == NULL) {\r
1357 Status = EFI_INVALID_PARAMETER;\r
1358 goto Done;\r
1359 }\r
1360\r
1361 //\r
1362 // Build the map\r
1363 //\r
1364 ZeroMem (MemoryMap, Size);\r
1365 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1366 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1367 ASSERT (Entry->VirtualStart == 0);\r
1368\r
1369 MemoryMap->Type = Entry->Type;\r
1370 MemoryMap->PhysicalStart = Entry->Start;\r
1371 MemoryMap->VirtualStart = Entry->VirtualStart;\r
1372 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
1373 \r
1374 switch (Entry->Type) {\r
1375 case EfiRuntimeServicesCode:\r
1376 case EfiRuntimeServicesData:\r
1377 case EfiPalCode:\r
1378 MemoryMap->Attribute = Entry->Attribute | EFI_MEMORY_RUNTIME;\r
1379 break;\r
1380\r
1381 default:\r
1382 MemoryMap->Attribute = Entry->Attribute;\r
1383 break;\r
1384 }\r
1385 \r
1386 MemoryMap = NextMemoryDescriptor (MemoryMap, Size);\r
1387 }\r
1388\r
1389 for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {\r
1390 GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
1391 if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||\r
1392 (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) {\r
1393 if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) {\r
1394 \r
1395 MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;\r
1396 MemoryMap->VirtualStart = 0;\r
3114b334 1397 MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);\r
878ddf1f 1398 MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;\r
1399\r
1400 if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {\r
1401 MemoryMap->Type = EfiReservedMemoryType;\r
1402 } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
1403 if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {\r
1404 MemoryMap->Type = EfiMemoryMappedIOPortSpace;\r
1405 } else {\r
1406 MemoryMap->Type = EfiMemoryMappedIO;\r
1407 }\r
1408 }\r
1409\r
1410 MemoryMap = NextMemoryDescriptor (MemoryMap, Size);\r
1411 }\r
1412 }\r
1413 }\r
1414 \r
1415 Status = EFI_SUCCESS;\r
1416\r
1417Done:\r
1418\r
1419 CoreReleaseMemoryLock ();\r
1420 \r
1421 CoreReleaseGcdMemoryLock ();\r
1422 \r
1423 // \r
1424 // Update the map key finally \r
1425 // \r
1426 if (MapKey != NULL) {\r
1427 *MapKey = mMemoryMapKey;\r
1428 }\r
1429 \r
1430 *MemoryMapSize = BufferSize;\r
1431 \r
1432 return Status;\r
1433}\r
1434\r
1435VOID *\r
1436CoreAllocatePoolPages (\r
1437 IN EFI_MEMORY_TYPE PoolType,\r
1438 IN UINTN NumberOfPages,\r
1439 IN UINTN Alignment\r
1440 )\r
1441/*++\r
1442\r
1443Routine Description:\r
1444\r
1445 Internal function. Used by the pool functions to allocate pages\r
1446 to back pool allocation requests.\r
1447\r
1448Arguments:\r
1449\r
1450 PoolType - The type of memory for the new pool pages\r
1451\r
1452 NumberOfPages - No of pages to allocate\r
1453\r
1454 Alignment - Bits to align.\r
1455\r
1456Returns:\r
1457\r
1458 The allocated memory, or NULL\r
1459\r
1460--*/\r
1461{\r
878ddf1f 1462 UINT64 Start;\r
1463\r
1464 //\r
1465 // Find the pages to convert\r
1466 //\r
1467 Start = FindFreePages (EFI_MAX_ADDRESS, NumberOfPages, PoolType, Alignment);\r
1468\r
1469 //\r
1470 // Convert it to boot services data\r
1471 //\r
1472 if (Start == 0) {\r
1473 DEBUG ((EFI_D_ERROR | EFI_D_PAGE, "AllocatePoolPages: failed to allocate %d pages\n", NumberOfPages));\r
1474 } else {\r
1cc8ee78 1475 CoreConvertPages (Start, NumberOfPages, PoolType);\r
878ddf1f 1476 }\r
1477\r
1478 return (VOID *)(UINTN)Start;\r
1479}\r
1480\r
1481VOID\r
1482CoreFreePoolPages (\r
1483 IN EFI_PHYSICAL_ADDRESS Memory,\r
1484 IN UINTN NumberOfPages\r
1485 )\r
1486/*++\r
1487\r
1488Routine Description:\r
1489\r
1490 Internal function. Frees pool pages allocated via AllocatePoolPages ()\r
1491\r
1492Arguments:\r
1493\r
1494 Memory - The base address to free\r
1495\r
1496 NumberOfPages - The number of pages to free\r
1497\r
1498Returns:\r
1499\r
1500 None\r
1501\r
1502--*/\r
1503{\r
1504 CoreConvertPages (Memory, NumberOfPages, EfiConventionalMemory);\r
1505}\r
1506\r
1507\r
1508EFI_STATUS\r
1509CoreTerminateMemoryMap (\r
1510 IN UINTN MapKey\r
1511 )\r
1512/*++\r
1513\r
1514Routine Description:\r
1515\r
1516 Make sure the memory map is following all the construction rules, \r
1517 it is the last time to check memory map error before exit boot services.\r
1518\r
1519Arguments:\r
1520\r
1521 MapKey - Memory map key\r
1522\r
1523Returns:\r
1524\r
1525 EFI_INVALID_PARAMETER - Memory map not consistent with construction rules.\r
1526 \r
1527 EFI_SUCCESS - Valid memory map.\r
1528\r
1529--*/\r
1530{\r
1531 EFI_STATUS Status;\r
1532 LIST_ENTRY *Link;\r
1533 MEMORY_MAP *Entry;\r
1534\r
1535 Status = EFI_SUCCESS;\r
1536\r
1537 CoreAcquireMemoryLock ();\r
1538\r
1539 if (MapKey == mMemoryMapKey) {\r
1540\r
1541 //\r
1542 // Make sure the memory map is following all the construction rules\r
1543 // This is the last chance we will be able to display any messages on\r
1544 // the console devices.\r
1545 //\r
1546\r
1547 for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {\r
1548 Entry = CR(Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1549 if (Entry->Attribute & EFI_MEMORY_RUNTIME) { \r
1550 if (Entry->Type == EfiACPIReclaimMemory || Entry->Type == EfiACPIMemoryNVS) {\r
1551 DEBUG((EFI_D_ERROR, "ExitBootServices: ACPI memory entry has RUNTIME attribute set.\n"));\r
1552 CoreReleaseMemoryLock ();\r
1553 return EFI_INVALID_PARAMETER;\r
1554 }\r
1555 if (Entry->Start & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
1556 DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
1557 CoreReleaseMemoryLock ();\r
1558 return EFI_INVALID_PARAMETER;\r
1559 }\r
1560 if ((Entry->End + 1) & (EFI_ACPI_RUNTIME_PAGE_ALLOCATION_ALIGNMENT - 1)) {\r
1561 DEBUG((EFI_D_ERROR, "ExitBootServices: A RUNTIME memory entry is not on a proper alignment.\n"));\r
1562 CoreReleaseMemoryLock ();\r
1563 return EFI_INVALID_PARAMETER;\r
1564 }\r
1565 }\r
1566 }\r
1567\r
1568 //\r
1569 // The map key they gave us matches what we expect. Fall through and\r
1570 // return success. In an ideal world we would clear out all of\r
1571 // EfiBootServicesCode and EfiBootServicesData. However this function\r
1572 // is not the last one called by ExitBootServices(), so we have to\r
1573 // preserve the memory contents.\r
1574 //\r
1575 } else {\r
1576 Status = EFI_INVALID_PARAMETER;\r
1577 }\r
1578\r
1579 CoreReleaseMemoryLock ();\r
1580\r
1581 return Status;\r
1582}\r
1583\r
1584\r
1585\r
1586\r
1587\r
1588\r
1589\r
1590\r