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