]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Page.c
MdeModulePkg/DxeCore: switch to MdePkg allocation granularity macros
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Page.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory page management functions.\r
3\r
e524f680 4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
285a682c
JY
5 This program and the accompanying materials are licensed and made available\r
6 under the terms and conditions of the BSD License which accompanies this\r
7 distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
e42e9404 9\r
285a682c
JY
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
e42e9404 12\r
13**/\r
14\r
15#include "PiSmmCore.h"\r
285a682c 16#include <Library/SmmServicesTableLib.h>\r
e42e9404 17\r
18#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)\r
19\r
e42e9404 20LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);\r
21\r
285a682c
JY
22//\r
23// For GetMemoryMap()\r
24//\r
25\r
26#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')\r
27typedef struct {\r
28 UINTN Signature;\r
29 LIST_ENTRY Link;\r
30\r
31 BOOLEAN FromStack;\r
32 EFI_MEMORY_TYPE Type;\r
33 UINT64 Start;\r
34 UINT64 End;\r
35\r
36} MEMORY_MAP;\r
37\r
38LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);\r
39\r
40\r
41#define MAX_MAP_DEPTH 6\r
42\r
43///\r
44/// mMapDepth - depth of new descriptor stack\r
45///\r
46UINTN mMapDepth = 0;\r
47///\r
48/// mMapStack - space to use as temp storage to build new map descriptors\r
49///\r
50MEMORY_MAP mMapStack[MAX_MAP_DEPTH];\r
51UINTN mFreeMapStack = 0;\r
52///\r
53/// This list maintain the free memory map list\r
54///\r
55LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
56\r
57/**\r
58 Allocates pages from the memory map.\r
59\r
60 @param[in] Type The type of allocation to perform.\r
61 @param[in] MemoryType The type of memory to turn the allocated pages\r
62 into.\r
63 @param[in] NumberOfPages The number of pages to allocate.\r
64 @param[out] Memory A pointer to receive the base allocated memory\r
65 address.\r
66 @param[in] AddRegion If this memory is new added region.\r
67\r
68 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
69 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
70 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
71 @retval EFI_SUCCESS Pages successfully allocated.\r
72\r
73**/\r
74EFI_STATUS\r
75SmmInternalAllocatePagesEx (\r
76 IN EFI_ALLOCATE_TYPE Type,\r
77 IN EFI_MEMORY_TYPE MemoryType,\r
78 IN UINTN NumberOfPages,\r
79 OUT EFI_PHYSICAL_ADDRESS *Memory,\r
80 IN BOOLEAN AddRegion\r
81 );\r
82\r
83/**\r
84 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.\r
85 If the list is emtry, then allocate a new page to refuel the list.\r
86 Please Note this algorithm to allocate the memory map descriptor has a property\r
87 that the memory allocated for memory entries always grows, and will never really be freed.\r
88\r
89 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
90\r
91**/\r
92MEMORY_MAP *\r
93AllocateMemoryMapEntry (\r
94 VOID\r
95 )\r
96{\r
97 EFI_PHYSICAL_ADDRESS Mem;\r
98 EFI_STATUS Status;\r
99 MEMORY_MAP* FreeDescriptorEntries;\r
100 MEMORY_MAP* Entry;\r
101 UINTN Index;\r
102\r
103 //DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));\r
104\r
105 if (IsListEmpty (&mFreeMemoryMapEntryList)) {\r
106 //DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));\r
107 //\r
108 // The list is empty, to allocate one page to refuel the list\r
109 //\r
110 Status = SmmInternalAllocatePagesEx (\r
111 AllocateAnyPages,\r
112 EfiRuntimeServicesData,\r
113 EFI_SIZE_TO_PAGES(DEFAULT_PAGE_ALLOCATION),\r
114 &Mem,\r
115 TRUE\r
116 );\r
117 ASSERT_EFI_ERROR (Status);\r
118 if(!EFI_ERROR (Status)) {\r
119 FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem;\r
120 //DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));\r
121 //\r
122 // Enque the free memmory map entries into the list\r
123 //\r
124 for (Index = 0; Index< DEFAULT_PAGE_ALLOCATION / sizeof(MEMORY_MAP); Index++) {\r
125 FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;\r
126 InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);\r
127 }\r
128 } else {\r
129 return NULL;\r
130 }\r
131 }\r
132 //\r
133 // dequeue the first descriptor from the list\r
134 //\r
135 Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
136 RemoveEntryList (&Entry->Link);\r
137\r
138 return Entry;\r
139}\r
140\r
141\r
142/**\r
143 Internal function. Moves any memory descriptors that are on the\r
144 temporary descriptor stack to heap.\r
145\r
146**/\r
147VOID\r
148CoreFreeMemoryMapStack (\r
149 VOID\r
150 )\r
151{\r
152 MEMORY_MAP *Entry;\r
153\r
154 //\r
155 // If already freeing the map stack, then return\r
156 //\r
157 if (mFreeMapStack != 0) {\r
158 ASSERT (FALSE);\r
159 return ;\r
160 }\r
161\r
162 //\r
163 // Move the temporary memory descriptor stack into pool\r
164 //\r
165 mFreeMapStack += 1;\r
166\r
167 while (mMapDepth != 0) {\r
168 //\r
169 // Deque an memory map entry from mFreeMemoryMapEntryList\r
170 //\r
171 Entry = AllocateMemoryMapEntry ();\r
172 ASSERT (Entry);\r
173\r
174 //\r
175 // Update to proper entry\r
176 //\r
177 mMapDepth -= 1;\r
178\r
179 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
180\r
181 CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
182 Entry->FromStack = FALSE;\r
183\r
184 //\r
185 // Move this entry to general memory\r
186 //\r
187 InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link);\r
188 RemoveEntryList (&mMapStack[mMapDepth].Link);\r
189 mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
190 }\r
191 }\r
192\r
193 mFreeMapStack -= 1;\r
194}\r
195\r
196/**\r
197 Insert new entry from memory map.\r
198\r
199 @param[in] Link The old memory map entry to be linked.\r
200 @param[in] Start The start address of new memory map entry.\r
201 @param[in] End The end address of new memory map entry.\r
202 @param[in] Type The type of new memory map entry.\r
203 @param[in] Next If new entry is inserted to the next of old entry.\r
204 @param[in] AddRegion If this memory is new added region.\r
205**/\r
206VOID\r
207InsertNewEntry (\r
208 IN LIST_ENTRY *Link,\r
209 IN UINT64 Start,\r
210 IN UINT64 End,\r
211 IN EFI_MEMORY_TYPE Type,\r
212 IN BOOLEAN Next,\r
213 IN BOOLEAN AddRegion\r
214 )\r
215{\r
216 MEMORY_MAP *Entry;\r
217\r
218 Entry = &mMapStack[mMapDepth];\r
219 mMapDepth += 1;\r
220 ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
221 Entry->FromStack = TRUE;\r
222\r
223 Entry->Signature = MEMORY_MAP_SIGNATURE;\r
224 Entry->Type = Type;\r
225 Entry->Start = Start;\r
226 Entry->End = End;\r
227 if (Next) {\r
228 InsertHeadList (Link, &Entry->Link);\r
229 } else {\r
230 InsertTailList (Link, &Entry->Link);\r
231 }\r
232}\r
233\r
234/**\r
235 Remove old entry from memory map.\r
236\r
237 @param[in] Entry Memory map entry to be removed.\r
238**/\r
239VOID\r
240RemoveOldEntry (\r
241 IN MEMORY_MAP *Entry\r
242 )\r
243{\r
244 RemoveEntryList (&Entry->Link);\r
245 if (!Entry->FromStack) {\r
246 InsertTailList (&mFreeMemoryMapEntryList, &Entry->Link);\r
247 }\r
248}\r
249\r
250/**\r
251 Update SMM memory map entry.\r
252\r
253 @param[in] Type The type of allocation to perform.\r
254 @param[in] Memory The base of memory address.\r
255 @param[in] NumberOfPages The number of pages to allocate.\r
256 @param[in] AddRegion If this memory is new added region.\r
257**/\r
258VOID\r
259ConvertSmmMemoryMapEntry (\r
260 IN EFI_MEMORY_TYPE Type,\r
261 IN EFI_PHYSICAL_ADDRESS Memory,\r
262 IN UINTN NumberOfPages,\r
263 IN BOOLEAN AddRegion\r
264 )\r
265{\r
266 LIST_ENTRY *Link;\r
267 MEMORY_MAP *Entry;\r
268 MEMORY_MAP *NextEntry;\r
269 LIST_ENTRY *NextLink;\r
270 MEMORY_MAP *PreviousEntry;\r
271 LIST_ENTRY *PreviousLink;\r
272 EFI_PHYSICAL_ADDRESS Start;\r
273 EFI_PHYSICAL_ADDRESS End;\r
274\r
275 Start = Memory;\r
276 End = Memory + EFI_PAGES_TO_SIZE(NumberOfPages) - 1;\r
277\r
278 //\r
279 // Exclude memory region\r
280 //\r
281 Link = gMemoryMap.ForwardLink;\r
282 while (Link != &gMemoryMap) {\r
283 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
284 Link = Link->ForwardLink;\r
285\r
286 //\r
287 // ---------------------------------------------------\r
288 // | +----------+ +------+ +------+ +------+ |\r
289 // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---\r
290 // +----------+ ^ +------+ +------+ +------+\r
291 // |\r
292 // +------+\r
293 // |EntryX|\r
294 // +------+\r
295 //\r
296 if (Entry->Start > End) {\r
297 if ((Entry->Start == End + 1) && (Entry->Type == Type)) {\r
298 Entry->Start = Start;\r
299 return ;\r
300 }\r
301 InsertNewEntry (\r
302 &Entry->Link,\r
303 Start,\r
304 End,\r
305 Type,\r
306 FALSE,\r
307 AddRegion\r
308 );\r
309 return ;\r
310 }\r
311\r
312 if ((Entry->Start <= Start) && (Entry->End >= End)) {\r
313 if (Entry->Type != Type) {\r
314 if (Entry->Start < Start) {\r
315 //\r
316 // ---------------------------------------------------\r
317 // | +----------+ +------+ +------+ +------+ |\r
318 // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---\r
319 // +----------+ +------+ ^ +------+ +------+\r
320 // |\r
321 // +------+\r
322 // |EntryA|\r
323 // +------+\r
324 //\r
325 InsertNewEntry (\r
326 &Entry->Link,\r
327 Entry->Start,\r
328 Start - 1,\r
329 Entry->Type,\r
330 FALSE,\r
331 AddRegion\r
332 );\r
333 }\r
334 if (Entry->End > End) {\r
335 //\r
336 // ---------------------------------------------------\r
337 // | +----------+ +------+ +------+ +------+ |\r
338 // ---|gMemoryMep|---|Entry1|---|EntryX|---|Entry3|---\r
339 // +----------+ +------+ +------+ ^ +------+\r
340 // |\r
341 // +------+\r
342 // |EntryZ|\r
343 // +------+\r
344 //\r
345 InsertNewEntry (\r
346 &Entry->Link,\r
347 End + 1,\r
348 Entry->End,\r
349 Entry->Type,\r
350 TRUE,\r
351 AddRegion\r
352 );\r
353 }\r
354 //\r
355 // Update this node\r
356 //\r
357 Entry->Start = Start;\r
358 Entry->End = End;\r
359 Entry->Type = Type;\r
360\r
361 //\r
362 // Check adjacent\r
363 //\r
364 NextLink = Entry->Link.ForwardLink;\r
365 if (NextLink != &gMemoryMap) {\r
366 NextEntry = CR (NextLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
367 //\r
368 // ---------------------------------------------------\r
369 // | +----------+ +------+ +-----------------+ |\r
370 // ---|gMemoryMep|---|Entry1|---|EntryX Entry3|---\r
371 // +----------+ +------+ +-----------------+\r
372 //\r
373 if ((Entry->Type == NextEntry->Type) && (Entry->End + 1 == NextEntry->Start)) {\r
374 Entry->End = NextEntry->End;\r
375 RemoveOldEntry (NextEntry);\r
376 }\r
377 }\r
378 PreviousLink = Entry->Link.BackLink;\r
379 if (PreviousLink != &gMemoryMap) {\r
380 PreviousEntry = CR (PreviousLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
381 //\r
382 // ---------------------------------------------------\r
383 // | +----------+ +-----------------+ +------+ |\r
384 // ---|gMemoryMep|---|Entry1 EntryX|---|Entry3|---\r
385 // +----------+ +-----------------+ +------+\r
386 //\r
387 if ((PreviousEntry->Type == Entry->Type) && (PreviousEntry->End + 1 == Entry->Start)) {\r
388 PreviousEntry->End = Entry->End;\r
389 RemoveOldEntry (Entry);\r
390 }\r
391 }\r
392 }\r
393 return ;\r
394 }\r
395 }\r
396\r
397 //\r
398 // ---------------------------------------------------\r
399 // | +----------+ +------+ +------+ +------+ |\r
400 // ---|gMemoryMep|---|Entry1|---|Entry2|---|Entry3|---\r
401 // +----------+ +------+ +------+ +------+ ^\r
402 // |\r
403 // +------+\r
404 // |EntryX|\r
405 // +------+\r
406 //\r
407 Link = gMemoryMap.BackLink;\r
408 if (Link != &gMemoryMap) {\r
409 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
410 if ((Entry->End + 1 == Start) && (Entry->Type == Type)) {\r
411 Entry->End = End;\r
412 return ;\r
413 }\r
414 }\r
415 InsertNewEntry (\r
416 &gMemoryMap,\r
417 Start,\r
418 End,\r
419 Type,\r
420 FALSE,\r
421 AddRegion\r
422 );\r
423 return ;\r
424}\r
425\r
426/**\r
427 Return the count of Smm memory map entry.\r
428\r
429 @return The count of Smm memory map entry.\r
430**/\r
431UINTN\r
432GetSmmMemoryMapEntryCount (\r
433 VOID\r
434 )\r
435{\r
436 LIST_ENTRY *Link;\r
437 UINTN Count;\r
438\r
439 Count = 0;\r
440 Link = gMemoryMap.ForwardLink;\r
441 while (Link != &gMemoryMap) {\r
442 Link = Link->ForwardLink;\r
443 Count++;\r
444 }\r
445 return Count;\r
446}\r
447\r
448/**\r
449 Dump Smm memory map entry.\r
450**/\r
451VOID\r
452DumpSmmMemoryMapEntry (\r
453 VOID\r
454 )\r
455{\r
456 LIST_ENTRY *Link;\r
457 MEMORY_MAP *Entry;\r
458 EFI_PHYSICAL_ADDRESS Last;\r
459\r
460 Last = 0;\r
461 DEBUG ((DEBUG_INFO, "DumpSmmMemoryMapEntry:\n"));\r
462 Link = gMemoryMap.ForwardLink;\r
463 while (Link != &gMemoryMap) {\r
464 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
465 Link = Link->ForwardLink;\r
466\r
467 if ((Last != 0) && (Last != (UINT64)-1)) {\r
468 if (Last + 1 != Entry->Start) {\r
469 Last = (UINT64)-1;\r
470 } else {\r
471 Last = Entry->End;\r
472 }\r
473 } else if (Last == 0) {\r
474 Last = Entry->End;\r
475 }\r
476\r
477 DEBUG ((DEBUG_INFO, "Entry (Link - 0x%x)\n", &Entry->Link));\r
478 DEBUG ((DEBUG_INFO, " Signature - 0x%x\n", Entry->Signature));\r
479 DEBUG ((DEBUG_INFO, " Link.ForwardLink - 0x%x\n", Entry->Link.ForwardLink));\r
480 DEBUG ((DEBUG_INFO, " Link.BackLink - 0x%x\n", Entry->Link.BackLink));\r
481 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Entry->Type));\r
482 DEBUG ((DEBUG_INFO, " Start - 0x%016lx\n", Entry->Start));\r
483 DEBUG ((DEBUG_INFO, " End - 0x%016lx\n", Entry->End));\r
484 }\r
485\r
486 ASSERT (Last != (UINT64)-1);\r
487}\r
488\r
489/**\r
490 Dump Smm memory map.\r
491**/\r
492VOID\r
493DumpSmmMemoryMap (\r
494 VOID\r
495 )\r
496{\r
497 LIST_ENTRY *Node;\r
498 FREE_PAGE_LIST *Pages;\r
499\r
500 DEBUG ((DEBUG_INFO, "DumpSmmMemoryMap\n"));\r
501\r
502 Pages = NULL;\r
503 Node = mSmmMemoryMap.ForwardLink;\r
504 while (Node != &mSmmMemoryMap) {\r
505 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
506 DEBUG ((DEBUG_INFO, "Pages - 0x%x\n", Pages));\r
507 DEBUG ((DEBUG_INFO, "Pages->NumberOfPages - 0x%x\n", Pages->NumberOfPages));\r
508 Node = Node->ForwardLink;\r
509 }\r
510}\r
511\r
512/**\r
513 Check if a Smm base~length is in Smm memory map.\r
514\r
515 @param[in] Base The base address of Smm memory to be checked.\r
516 @param[in] Length THe length of Smm memory to be checked.\r
517\r
518 @retval TRUE Smm base~length is in smm memory map.\r
519 @retval FALSE Smm base~length is in smm memory map.\r
520**/\r
521BOOLEAN\r
522SmmMemoryMapConsistencyCheckRange (\r
523 IN EFI_PHYSICAL_ADDRESS Base,\r
524 IN UINTN Length\r
525 )\r
526{\r
527 LIST_ENTRY *Link;\r
528 MEMORY_MAP *Entry;\r
529 BOOLEAN Result;\r
530\r
531 Result = FALSE;\r
532 Link = gMemoryMap.ForwardLink;\r
533 while (Link != &gMemoryMap) {\r
534 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
535 Link = Link->ForwardLink;\r
536\r
537 if (Entry->Type != EfiConventionalMemory) {\r
538 continue;\r
539 }\r
540 if (Entry->Start == Base && Entry->End == Base + Length - 1) {\r
541 Result = TRUE;\r
542 break;\r
543 }\r
544 }\r
545\r
546 return Result;\r
547}\r
548\r
549/**\r
550 Check the consistency of Smm memory map.\r
551**/\r
552VOID\r
553SmmMemoryMapConsistencyCheck (\r
554 VOID\r
555 )\r
556{\r
557 LIST_ENTRY *Node;\r
558 FREE_PAGE_LIST *Pages;\r
559 BOOLEAN Result;\r
560\r
561 Pages = NULL;\r
562 Node = mSmmMemoryMap.ForwardLink;\r
563 while (Node != &mSmmMemoryMap) {\r
564 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
565 Result = SmmMemoryMapConsistencyCheckRange ((EFI_PHYSICAL_ADDRESS)(UINTN)Pages, (UINTN)EFI_PAGES_TO_SIZE(Pages->NumberOfPages));\r
566 ASSERT (Result);\r
567 Node = Node->ForwardLink;\r
568 }\r
569}\r
570\r
e42e9404 571/**\r
572 Internal Function. Allocate n pages from given free page node.\r
573\r
574 @param Pages The free page node.\r
575 @param NumberOfPages Number of pages to be allocated.\r
576 @param MaxAddress Request to allocate memory below this address.\r
577\r
578 @return Memory address of allocated pages.\r
579\r
580**/\r
581UINTN\r
582InternalAllocPagesOnOneNode (\r
583 IN OUT FREE_PAGE_LIST *Pages,\r
584 IN UINTN NumberOfPages,\r
585 IN UINTN MaxAddress\r
586 )\r
587{\r
588 UINTN Top;\r
589 UINTN Bottom;\r
590 FREE_PAGE_LIST *Node;\r
591\r
592 Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);\r
593 if (Top > Pages->NumberOfPages) {\r
594 Top = Pages->NumberOfPages;\r
595 }\r
596 Bottom = Top - NumberOfPages;\r
597\r
598 if (Top < Pages->NumberOfPages) {\r
599 Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));\r
600 Node->NumberOfPages = Pages->NumberOfPages - Top;\r
601 InsertHeadList (&Pages->Link, &Node->Link);\r
602 }\r
603\r
604 if (Bottom > 0) {\r
605 Pages->NumberOfPages = Bottom;\r
606 } else {\r
607 RemoveEntryList (&Pages->Link);\r
608 }\r
609\r
610 return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);\r
611}\r
612\r
613/**\r
614 Internal Function. Allocate n pages from free page list below MaxAddress.\r
615\r
616 @param FreePageList The free page node.\r
617 @param NumberOfPages Number of pages to be allocated.\r
618 @param MaxAddress Request to allocate memory below this address.\r
619\r
620 @return Memory address of allocated pages.\r
621\r
622**/\r
623UINTN\r
624InternalAllocMaxAddress (\r
625 IN OUT LIST_ENTRY *FreePageList,\r
626 IN UINTN NumberOfPages,\r
627 IN UINTN MaxAddress\r
628 )\r
629{\r
630 LIST_ENTRY *Node;\r
631 FREE_PAGE_LIST *Pages;\r
632\r
633 for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {\r
634 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
635 if (Pages->NumberOfPages >= NumberOfPages &&\r
636 (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {\r
637 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);\r
638 }\r
639 }\r
640 return (UINTN)(-1);\r
641}\r
642\r
643/**\r
644 Internal Function. Allocate n pages from free page list at given address.\r
645\r
646 @param FreePageList The free page node.\r
647 @param NumberOfPages Number of pages to be allocated.\r
648 @param MaxAddress Request to allocate memory below this address.\r
649\r
650 @return Memory address of allocated pages.\r
651\r
652**/\r
653UINTN\r
654InternalAllocAddress (\r
655 IN OUT LIST_ENTRY *FreePageList,\r
656 IN UINTN NumberOfPages,\r
657 IN UINTN Address\r
658 )\r
659{\r
660 UINTN EndAddress;\r
661 LIST_ENTRY *Node;\r
662 FREE_PAGE_LIST *Pages;\r
663\r
664 if ((Address & EFI_PAGE_MASK) != 0) {\r
665 return ~Address;\r
666 }\r
667\r
668 EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);\r
669 for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {\r
670 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
671 if ((UINTN)Pages <= Address) {\r
672 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {\r
673 break;\r
674 }\r
675 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);\r
676 }\r
677 }\r
678 return ~Address;\r
679}\r
680\r
681/**\r
682 Allocates pages from the memory map.\r
683\r
285a682c
JY
684 @param[in] Type The type of allocation to perform.\r
685 @param[in] MemoryType The type of memory to turn the allocated pages\r
686 into.\r
687 @param[in] NumberOfPages The number of pages to allocate.\r
688 @param[out] Memory A pointer to receive the base allocated memory\r
689 address.\r
690 @param[in] AddRegion If this memory is new added region.\r
e42e9404 691\r
692 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
693 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
694 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
695 @retval EFI_SUCCESS Pages successfully allocated.\r
696\r
697**/\r
698EFI_STATUS\r
285a682c 699SmmInternalAllocatePagesEx (\r
e42e9404 700 IN EFI_ALLOCATE_TYPE Type,\r
701 IN EFI_MEMORY_TYPE MemoryType,\r
702 IN UINTN NumberOfPages,\r
285a682c
JY
703 OUT EFI_PHYSICAL_ADDRESS *Memory,\r
704 IN BOOLEAN AddRegion\r
e42e9404 705 )\r
706{\r
707 UINTN RequestedAddress;\r
708\r
709 if (MemoryType != EfiRuntimeServicesCode &&\r
710 MemoryType != EfiRuntimeServicesData) {\r
711 return EFI_INVALID_PARAMETER;\r
712 }\r
713\r
714 if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {\r
715 return EFI_OUT_OF_RESOURCES;\r
716 }\r
717\r
718 //\r
719 // We don't track memory type in SMM\r
720 //\r
721 RequestedAddress = (UINTN)*Memory;\r
722 switch (Type) {\r
723 case AllocateAnyPages:\r
724 RequestedAddress = (UINTN)(-1);\r
725 case AllocateMaxAddress:\r
726 *Memory = InternalAllocMaxAddress (\r
727 &mSmmMemoryMap,\r
728 NumberOfPages,\r
729 RequestedAddress\r
730 );\r
731 if (*Memory == (UINTN)-1) {\r
732 return EFI_OUT_OF_RESOURCES;\r
285a682c 733 }\r
e42e9404 734 break;\r
735 case AllocateAddress:\r
736 *Memory = InternalAllocAddress (\r
737 &mSmmMemoryMap,\r
738 NumberOfPages,\r
739 RequestedAddress\r
740 );\r
741 if (*Memory != RequestedAddress) {\r
742 return EFI_NOT_FOUND;\r
743 }\r
744 break;\r
745 default:\r
746 return EFI_INVALID_PARAMETER;\r
747 }\r
285a682c
JY
748\r
749 //\r
750 // Update SmmMemoryMap here.\r
751 //\r
752 ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);\r
753 if (!AddRegion) {\r
754 CoreFreeMemoryMapStack();\r
755 }\r
756\r
e42e9404 757 return EFI_SUCCESS;\r
758}\r
759\r
285a682c
JY
760/**\r
761 Allocates pages from the memory map.\r
762\r
763 @param[in] Type The type of allocation to perform.\r
764 @param[in] MemoryType The type of memory to turn the allocated pages\r
765 into.\r
766 @param[in] NumberOfPages The number of pages to allocate.\r
767 @param[out] Memory A pointer to receive the base allocated memory\r
768 address.\r
769\r
770 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
771 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
772 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
773 @retval EFI_SUCCESS Pages successfully allocated.\r
774\r
775**/\r
776EFI_STATUS\r
777EFIAPI\r
778SmmInternalAllocatePages (\r
779 IN EFI_ALLOCATE_TYPE Type,\r
780 IN EFI_MEMORY_TYPE MemoryType,\r
781 IN UINTN NumberOfPages,\r
782 OUT EFI_PHYSICAL_ADDRESS *Memory\r
783 )\r
784{\r
785 return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory, FALSE);\r
786}\r
787\r
84edd20b
SZ
788/**\r
789 Allocates pages from the memory map.\r
790\r
791 @param Type The type of allocation to perform.\r
792 @param MemoryType The type of memory to turn the allocated pages\r
793 into.\r
794 @param NumberOfPages The number of pages to allocate.\r
795 @param Memory A pointer to receive the base allocated memory\r
796 address.\r
797\r
798 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
799 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
800 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
801 @retval EFI_SUCCESS Pages successfully allocated.\r
802\r
803**/\r
804EFI_STATUS\r
805EFIAPI\r
806SmmAllocatePages (\r
807 IN EFI_ALLOCATE_TYPE Type,\r
808 IN EFI_MEMORY_TYPE MemoryType,\r
809 IN UINTN NumberOfPages,\r
810 OUT EFI_PHYSICAL_ADDRESS *Memory\r
811 )\r
812{\r
813 EFI_STATUS Status;\r
814\r
815 Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory);\r
816 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
817 SmmCoreUpdateProfile (\r
818 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
819 MemoryProfileActionAllocatePages,\r
820 MemoryType,\r
821 EFI_PAGES_TO_SIZE (NumberOfPages),\r
822 (VOID *) (UINTN) *Memory,\r
823 NULL\r
824 );\r
84edd20b
SZ
825 }\r
826 return Status;\r
827}\r
828\r
e42e9404 829/**\r
830 Internal Function. Merge two adjacent nodes.\r
831\r
832 @param First The first of two nodes to merge.\r
833\r
834 @return Pointer to node after merge (if success) or pointer to next node (if fail).\r
835\r
836**/\r
837FREE_PAGE_LIST *\r
838InternalMergeNodes (\r
839 IN FREE_PAGE_LIST *First\r
840 )\r
841{\r
842 FREE_PAGE_LIST *Next;\r
843\r
844 Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);\r
845 ASSERT (\r
846 TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);\r
847\r
848 if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {\r
849 First->NumberOfPages += Next->NumberOfPages;\r
850 RemoveEntryList (&Next->Link);\r
851 Next = First;\r
852 }\r
853 return Next;\r
854}\r
855\r
856/**\r
857 Frees previous allocated pages.\r
858\r
285a682c
JY
859 @param[in] Memory Base address of memory being freed.\r
860 @param[in] NumberOfPages The number of pages to free.\r
861 @param[in] AddRegion If this memory is new added region.\r
e42e9404 862\r
863 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 864 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
e42e9404 865 @return EFI_SUCCESS Pages successfully freed.\r
866\r
867**/\r
868EFI_STATUS\r
285a682c 869SmmInternalFreePagesEx (\r
e42e9404 870 IN EFI_PHYSICAL_ADDRESS Memory,\r
285a682c
JY
871 IN UINTN NumberOfPages,\r
872 IN BOOLEAN AddRegion\r
e42e9404 873 )\r
874{\r
875 LIST_ENTRY *Node;\r
876 FREE_PAGE_LIST *Pages;\r
877\r
ddfae264 878 if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {\r
e42e9404 879 return EFI_INVALID_PARAMETER;\r
880 }\r
881\r
882 Pages = NULL;\r
883 Node = mSmmMemoryMap.ForwardLink;\r
884 while (Node != &mSmmMemoryMap) {\r
885 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
886 if (Memory < (UINTN)Pages) {\r
887 break;\r
888 }\r
889 Node = Node->ForwardLink;\r
890 }\r
891\r
892 if (Node != &mSmmMemoryMap &&\r
893 Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {\r
894 return EFI_INVALID_PARAMETER;\r
895 }\r
896\r
897 if (Node->BackLink != &mSmmMemoryMap) {\r
898 Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);\r
899 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {\r
900 return EFI_INVALID_PARAMETER;\r
901 }\r
902 }\r
903\r
904 Pages = (FREE_PAGE_LIST*)(UINTN)Memory;\r
905 Pages->NumberOfPages = NumberOfPages;\r
906 InsertTailList (Node, &Pages->Link);\r
907\r
908 if (Pages->Link.BackLink != &mSmmMemoryMap) {\r
909 Pages = InternalMergeNodes (\r
910 BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)\r
911 );\r
912 }\r
913\r
914 if (Node != &mSmmMemoryMap) {\r
915 InternalMergeNodes (Pages);\r
916 }\r
917\r
285a682c
JY
918 //\r
919 // Update SmmMemoryMap here.\r
920 //\r
921 ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);\r
922 if (!AddRegion) {\r
923 CoreFreeMemoryMapStack();\r
924 }\r
925\r
e42e9404 926 return EFI_SUCCESS;\r
927}\r
928\r
285a682c
JY
929/**\r
930 Frees previous allocated pages.\r
931\r
932 @param[in] Memory Base address of memory being freed.\r
933 @param[in] NumberOfPages The number of pages to free.\r
934\r
935 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 936 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
285a682c
JY
937 @return EFI_SUCCESS Pages successfully freed.\r
938\r
939**/\r
940EFI_STATUS\r
941EFIAPI\r
942SmmInternalFreePages (\r
943 IN EFI_PHYSICAL_ADDRESS Memory,\r
944 IN UINTN NumberOfPages\r
945 )\r
946{\r
947 return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);\r
948}\r
949\r
84edd20b
SZ
950/**\r
951 Frees previous allocated pages.\r
952\r
953 @param Memory Base address of memory being freed.\r
954 @param NumberOfPages The number of pages to free.\r
955\r
956 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 957 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
84edd20b
SZ
958 @return EFI_SUCCESS Pages successfully freed.\r
959\r
960**/\r
961EFI_STATUS\r
962EFIAPI\r
963SmmFreePages (\r
964 IN EFI_PHYSICAL_ADDRESS Memory,\r
965 IN UINTN NumberOfPages\r
966 )\r
967{\r
968 EFI_STATUS Status;\r
969\r
970 Status = SmmInternalFreePages (Memory, NumberOfPages);\r
971 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
972 SmmCoreUpdateProfile (\r
973 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
974 MemoryProfileActionFreePages,\r
975 EfiMaxMemoryType,\r
976 EFI_PAGES_TO_SIZE (NumberOfPages),\r
977 (VOID *) (UINTN) Memory,\r
978 NULL\r
979 );\r
84edd20b
SZ
980 }\r
981 return Status;\r
982}\r
983\r
e42e9404 984/**\r
985 Add free SMRAM region for use by memory service.\r
986\r
987 @param MemBase Base address of memory region.\r
988 @param MemLength Length of the memory region.\r
989 @param Type Memory type.\r
990 @param Attributes Memory region state.\r
991\r
992**/\r
993VOID\r
994SmmAddMemoryRegion (\r
995 IN EFI_PHYSICAL_ADDRESS MemBase,\r
996 IN UINT64 MemLength,\r
997 IN EFI_MEMORY_TYPE Type,\r
998 IN UINT64 Attributes\r
999 )\r
1000{\r
1001 UINTN AlignedMemBase;\r
1002\r
3df4b6e7 1003 //\r
285a682c 1004 // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization\r
3df4b6e7 1005 //\r
1006 if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
285a682c
JY
1007 Type = EfiRuntimeServicesData;\r
1008 } else {\r
1009 Type = EfiConventionalMemory;\r
3df4b6e7 1010 }\r
285a682c
JY
1011\r
1012 DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));\r
1013 DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));\r
1014 DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));\r
1015 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));\r
1016 DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));\r
1017\r
3df4b6e7 1018 //\r
1019 // Align range on an EFI_PAGE_SIZE boundary\r
285a682c 1020 //\r
e42e9404 1021 AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;\r
1022 MemLength -= AlignedMemBase - MemBase;\r
285a682c
JY
1023 if (Type == EfiConventionalMemory) {\r
1024 SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
1025 } else {\r
1026 ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
1027 }\r
1028\r
1029 CoreFreeMemoryMapStack ();\r
1030}\r
1031\r
1032/**\r
1033 This function returns a copy of the current memory map. The map is an array of\r
1034 memory descriptors, each of which describes a contiguous block of memory.\r
1035\r
1036 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
1037 MemoryMap buffer. On input, this is the size of\r
1038 the buffer allocated by the caller. On output,\r
1039 it is the size of the buffer returned by the\r
1040 firmware if the buffer was large enough, or the\r
1041 size of the buffer needed to contain the map if\r
1042 the buffer was too small.\r
1043 @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
1044 the current memory map.\r
1045 @param[out] MapKey A pointer to the location in which firmware\r
1046 returns the key for the current memory map.\r
1047 @param[out] DescriptorSize A pointer to the location in which firmware\r
1048 returns the size, in bytes, of an individual\r
1049 EFI_MEMORY_DESCRIPTOR.\r
1050 @param[out] DescriptorVersion A pointer to the location in which firmware\r
1051 returns the version number associated with the\r
1052 EFI_MEMORY_DESCRIPTOR.\r
1053\r
1054 @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
1055 buffer.\r
1056 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
1057 buffer size needed to hold the memory map is\r
1058 returned in MemoryMapSize.\r
1059 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1060\r
1061**/\r
1062EFI_STATUS\r
1063EFIAPI\r
1064SmmCoreGetMemoryMap (\r
1065 IN OUT UINTN *MemoryMapSize,\r
1066 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1067 OUT UINTN *MapKey,\r
1068 OUT UINTN *DescriptorSize,\r
1069 OUT UINT32 *DescriptorVersion\r
1070 )\r
1071{\r
1072 UINTN Count;\r
1073 LIST_ENTRY *Link;\r
1074 MEMORY_MAP *Entry;\r
1075 UINTN Size;\r
1076 UINTN BufferSize;\r
1077\r
1078 Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
1079\r
1080 //\r
1081 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
1082 // prevent people from having pointer math bugs in their code.\r
1083 // now you have to use *DescriptorSize to make things work.\r
1084 //\r
1085 Size += sizeof(UINT64) - (Size % sizeof (UINT64));\r
1086\r
1087 if (DescriptorSize != NULL) {\r
1088 *DescriptorSize = Size;\r
1089 }\r
1090\r
1091 if (DescriptorVersion != NULL) {\r
1092 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
1093 }\r
1094\r
1095 Count = GetSmmMemoryMapEntryCount ();\r
1096 BufferSize = Size * Count;\r
1097 if (*MemoryMapSize < BufferSize) {\r
1098 *MemoryMapSize = BufferSize;\r
1099 return EFI_BUFFER_TOO_SMALL;\r
1100 }\r
1101\r
1102 *MemoryMapSize = BufferSize;\r
1103 if (MemoryMap == NULL) {\r
1104 return EFI_INVALID_PARAMETER;\r
1105 }\r
1106\r
1107 ZeroMem (MemoryMap, BufferSize);\r
1108 Link = gMemoryMap.ForwardLink;\r
1109 while (Link != &gMemoryMap) {\r
1110 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1111 Link = Link->ForwardLink;\r
1112\r
1113 MemoryMap->Type = Entry->Type;\r
1114 MemoryMap->PhysicalStart = Entry->Start;\r
1115 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
1116\r
1117 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
1118 }\r
1119\r
1120 return EFI_SUCCESS;\r
e42e9404 1121}\r