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