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