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