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