]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Page.c
MdeModulePkg: remove PE/COFF header workaround for ELILO on IPF
[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
285a682c 454\r
285a682c 455\r
e42e9404 456/**\r
457 Internal Function. Allocate n pages from given free page node.\r
458\r
459 @param Pages The free page node.\r
460 @param NumberOfPages Number of pages to be allocated.\r
461 @param MaxAddress Request to allocate memory below this address.\r
462\r
463 @return Memory address of allocated pages.\r
464\r
465**/\r
466UINTN\r
467InternalAllocPagesOnOneNode (\r
468 IN OUT FREE_PAGE_LIST *Pages,\r
469 IN UINTN NumberOfPages,\r
470 IN UINTN MaxAddress\r
471 )\r
472{\r
473 UINTN Top;\r
474 UINTN Bottom;\r
475 FREE_PAGE_LIST *Node;\r
476\r
477 Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);\r
478 if (Top > Pages->NumberOfPages) {\r
479 Top = Pages->NumberOfPages;\r
480 }\r
481 Bottom = Top - NumberOfPages;\r
482\r
483 if (Top < Pages->NumberOfPages) {\r
484 Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));\r
485 Node->NumberOfPages = Pages->NumberOfPages - Top;\r
486 InsertHeadList (&Pages->Link, &Node->Link);\r
487 }\r
488\r
489 if (Bottom > 0) {\r
490 Pages->NumberOfPages = Bottom;\r
491 } else {\r
492 RemoveEntryList (&Pages->Link);\r
493 }\r
494\r
495 return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);\r
496}\r
497\r
498/**\r
499 Internal Function. Allocate n pages from free page list below MaxAddress.\r
500\r
501 @param FreePageList The free page node.\r
502 @param NumberOfPages Number of pages to be allocated.\r
503 @param MaxAddress Request to allocate memory below this address.\r
504\r
505 @return Memory address of allocated pages.\r
506\r
507**/\r
508UINTN\r
509InternalAllocMaxAddress (\r
510 IN OUT LIST_ENTRY *FreePageList,\r
511 IN UINTN NumberOfPages,\r
512 IN UINTN MaxAddress\r
513 )\r
514{\r
515 LIST_ENTRY *Node;\r
516 FREE_PAGE_LIST *Pages;\r
517\r
518 for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {\r
519 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
520 if (Pages->NumberOfPages >= NumberOfPages &&\r
521 (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {\r
522 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);\r
523 }\r
524 }\r
525 return (UINTN)(-1);\r
526}\r
527\r
528/**\r
529 Internal Function. Allocate n pages from free page list at given address.\r
530\r
531 @param FreePageList The free page node.\r
532 @param NumberOfPages Number of pages to be allocated.\r
533 @param MaxAddress Request to allocate memory below this address.\r
534\r
535 @return Memory address of allocated pages.\r
536\r
537**/\r
538UINTN\r
539InternalAllocAddress (\r
540 IN OUT LIST_ENTRY *FreePageList,\r
541 IN UINTN NumberOfPages,\r
542 IN UINTN Address\r
543 )\r
544{\r
545 UINTN EndAddress;\r
546 LIST_ENTRY *Node;\r
547 FREE_PAGE_LIST *Pages;\r
548\r
549 if ((Address & EFI_PAGE_MASK) != 0) {\r
550 return ~Address;\r
551 }\r
552\r
553 EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);\r
554 for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {\r
555 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
556 if ((UINTN)Pages <= Address) {\r
557 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {\r
558 break;\r
559 }\r
560 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);\r
561 }\r
562 }\r
563 return ~Address;\r
564}\r
565\r
566/**\r
567 Allocates pages from the memory map.\r
568\r
285a682c
JY
569 @param[in] Type The type of allocation to perform.\r
570 @param[in] MemoryType The type of memory to turn the allocated pages\r
571 into.\r
572 @param[in] NumberOfPages The number of pages to allocate.\r
573 @param[out] Memory A pointer to receive the base allocated memory\r
574 address.\r
575 @param[in] AddRegion If this memory is new added region.\r
e63da9f0
JW
576 @param[in] NeedGuard Flag to indicate Guard page is needed\r
577 or not\r
e42e9404 578\r
579 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
580 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
581 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
582 @retval EFI_SUCCESS Pages successfully allocated.\r
583\r
584**/\r
585EFI_STATUS\r
285a682c 586SmmInternalAllocatePagesEx (\r
e42e9404 587 IN EFI_ALLOCATE_TYPE Type,\r
588 IN EFI_MEMORY_TYPE MemoryType,\r
589 IN UINTN NumberOfPages,\r
285a682c 590 OUT EFI_PHYSICAL_ADDRESS *Memory,\r
e63da9f0
JW
591 IN BOOLEAN AddRegion,\r
592 IN BOOLEAN NeedGuard\r
e42e9404 593 )\r
594{\r
595 UINTN RequestedAddress;\r
596\r
597 if (MemoryType != EfiRuntimeServicesCode &&\r
598 MemoryType != EfiRuntimeServicesData) {\r
599 return EFI_INVALID_PARAMETER;\r
600 }\r
601\r
602 if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {\r
603 return EFI_OUT_OF_RESOURCES;\r
604 }\r
605\r
606 //\r
607 // We don't track memory type in SMM\r
608 //\r
609 RequestedAddress = (UINTN)*Memory;\r
610 switch (Type) {\r
611 case AllocateAnyPages:\r
612 RequestedAddress = (UINTN)(-1);\r
613 case AllocateMaxAddress:\r
e63da9f0
JW
614 if (NeedGuard) {\r
615 *Memory = InternalAllocMaxAddressWithGuard (\r
616 &mSmmMemoryMap,\r
617 NumberOfPages,\r
618 RequestedAddress,\r
619 MemoryType\r
620 );\r
621 if (*Memory == (UINTN)-1) {\r
622 return EFI_OUT_OF_RESOURCES;\r
623 } else {\r
624 ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);\r
625 return EFI_SUCCESS;\r
626 }\r
627 }\r
628\r
e42e9404 629 *Memory = InternalAllocMaxAddress (\r
630 &mSmmMemoryMap,\r
631 NumberOfPages,\r
632 RequestedAddress\r
633 );\r
634 if (*Memory == (UINTN)-1) {\r
635 return EFI_OUT_OF_RESOURCES;\r
285a682c 636 }\r
e42e9404 637 break;\r
638 case AllocateAddress:\r
639 *Memory = InternalAllocAddress (\r
640 &mSmmMemoryMap,\r
641 NumberOfPages,\r
642 RequestedAddress\r
643 );\r
644 if (*Memory != RequestedAddress) {\r
645 return EFI_NOT_FOUND;\r
646 }\r
647 break;\r
648 default:\r
649 return EFI_INVALID_PARAMETER;\r
650 }\r
285a682c
JY
651\r
652 //\r
653 // Update SmmMemoryMap here.\r
654 //\r
655 ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);\r
656 if (!AddRegion) {\r
657 CoreFreeMemoryMapStack();\r
658 }\r
659\r
e42e9404 660 return EFI_SUCCESS;\r
661}\r
662\r
285a682c
JY
663/**\r
664 Allocates pages from the memory map.\r
665\r
666 @param[in] Type The type of allocation to perform.\r
667 @param[in] MemoryType The type of memory to turn the allocated pages\r
668 into.\r
669 @param[in] NumberOfPages The number of pages to allocate.\r
670 @param[out] Memory A pointer to receive the base allocated memory\r
671 address.\r
e63da9f0
JW
672 @param[in] NeedGuard Flag to indicate Guard page is needed\r
673 or not\r
285a682c
JY
674\r
675 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
676 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
677 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
678 @retval EFI_SUCCESS Pages successfully allocated.\r
679\r
680**/\r
681EFI_STATUS\r
682EFIAPI\r
683SmmInternalAllocatePages (\r
684 IN EFI_ALLOCATE_TYPE Type,\r
685 IN EFI_MEMORY_TYPE MemoryType,\r
686 IN UINTN NumberOfPages,\r
e63da9f0
JW
687 OUT EFI_PHYSICAL_ADDRESS *Memory,\r
688 IN BOOLEAN NeedGuard\r
285a682c
JY
689 )\r
690{\r
e63da9f0
JW
691 return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory,\r
692 FALSE, NeedGuard);\r
285a682c
JY
693}\r
694\r
84edd20b
SZ
695/**\r
696 Allocates pages from the memory map.\r
697\r
698 @param Type The type of allocation to perform.\r
699 @param MemoryType The type of memory to turn the allocated pages\r
700 into.\r
701 @param NumberOfPages The number of pages to allocate.\r
702 @param Memory A pointer to receive the base allocated memory\r
703 address.\r
704\r
705 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
706 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
707 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
708 @retval EFI_SUCCESS Pages successfully allocated.\r
709\r
710**/\r
711EFI_STATUS\r
712EFIAPI\r
713SmmAllocatePages (\r
714 IN EFI_ALLOCATE_TYPE Type,\r
715 IN EFI_MEMORY_TYPE MemoryType,\r
716 IN UINTN NumberOfPages,\r
717 OUT EFI_PHYSICAL_ADDRESS *Memory\r
718 )\r
719{\r
720 EFI_STATUS Status;\r
e63da9f0 721 BOOLEAN NeedGuard;\r
84edd20b 722\r
e63da9f0
JW
723 NeedGuard = IsPageTypeToGuard (MemoryType, Type);\r
724 Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,\r
725 NeedGuard);\r
84edd20b 726 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
727 SmmCoreUpdateProfile (\r
728 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
729 MemoryProfileActionAllocatePages,\r
730 MemoryType,\r
731 EFI_PAGES_TO_SIZE (NumberOfPages),\r
732 (VOID *) (UINTN) *Memory,\r
733 NULL\r
734 );\r
84edd20b
SZ
735 }\r
736 return Status;\r
737}\r
738\r
e42e9404 739/**\r
740 Internal Function. Merge two adjacent nodes.\r
741\r
742 @param First The first of two nodes to merge.\r
743\r
744 @return Pointer to node after merge (if success) or pointer to next node (if fail).\r
745\r
746**/\r
747FREE_PAGE_LIST *\r
748InternalMergeNodes (\r
749 IN FREE_PAGE_LIST *First\r
750 )\r
751{\r
752 FREE_PAGE_LIST *Next;\r
753\r
754 Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);\r
755 ASSERT (\r
756 TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);\r
757\r
758 if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {\r
759 First->NumberOfPages += Next->NumberOfPages;\r
760 RemoveEntryList (&Next->Link);\r
761 Next = First;\r
762 }\r
763 return Next;\r
764}\r
765\r
766/**\r
767 Frees previous allocated pages.\r
768\r
285a682c
JY
769 @param[in] Memory Base address of memory being freed.\r
770 @param[in] NumberOfPages The number of pages to free.\r
771 @param[in] AddRegion If this memory is new added region.\r
e42e9404 772\r
773 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 774 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
e42e9404 775 @return EFI_SUCCESS Pages successfully freed.\r
776\r
777**/\r
778EFI_STATUS\r
285a682c 779SmmInternalFreePagesEx (\r
e42e9404 780 IN EFI_PHYSICAL_ADDRESS Memory,\r
285a682c
JY
781 IN UINTN NumberOfPages,\r
782 IN BOOLEAN AddRegion\r
e42e9404 783 )\r
784{\r
785 LIST_ENTRY *Node;\r
786 FREE_PAGE_LIST *Pages;\r
787\r
ddfae264 788 if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {\r
e42e9404 789 return EFI_INVALID_PARAMETER;\r
790 }\r
791\r
792 Pages = NULL;\r
793 Node = mSmmMemoryMap.ForwardLink;\r
794 while (Node != &mSmmMemoryMap) {\r
795 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
796 if (Memory < (UINTN)Pages) {\r
797 break;\r
798 }\r
799 Node = Node->ForwardLink;\r
800 }\r
801\r
802 if (Node != &mSmmMemoryMap &&\r
803 Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {\r
804 return EFI_INVALID_PARAMETER;\r
805 }\r
806\r
807 if (Node->BackLink != &mSmmMemoryMap) {\r
808 Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);\r
809 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {\r
810 return EFI_INVALID_PARAMETER;\r
811 }\r
812 }\r
813\r
814 Pages = (FREE_PAGE_LIST*)(UINTN)Memory;\r
815 Pages->NumberOfPages = NumberOfPages;\r
816 InsertTailList (Node, &Pages->Link);\r
817\r
818 if (Pages->Link.BackLink != &mSmmMemoryMap) {\r
819 Pages = InternalMergeNodes (\r
820 BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)\r
821 );\r
822 }\r
823\r
824 if (Node != &mSmmMemoryMap) {\r
825 InternalMergeNodes (Pages);\r
826 }\r
827\r
285a682c
JY
828 //\r
829 // Update SmmMemoryMap here.\r
830 //\r
831 ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);\r
832 if (!AddRegion) {\r
833 CoreFreeMemoryMapStack();\r
834 }\r
835\r
e42e9404 836 return EFI_SUCCESS;\r
837}\r
838\r
285a682c
JY
839/**\r
840 Frees previous allocated pages.\r
841\r
842 @param[in] Memory Base address of memory being freed.\r
843 @param[in] NumberOfPages The number of pages to free.\r
e63da9f0 844 @param[in] IsGuarded Is the memory to free guarded or not.\r
285a682c
JY
845\r
846 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 847 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
285a682c
JY
848 @return EFI_SUCCESS Pages successfully freed.\r
849\r
850**/\r
851EFI_STATUS\r
852EFIAPI\r
853SmmInternalFreePages (\r
854 IN EFI_PHYSICAL_ADDRESS Memory,\r
e63da9f0
JW
855 IN UINTN NumberOfPages,\r
856 IN BOOLEAN IsGuarded\r
285a682c
JY
857 )\r
858{\r
e63da9f0
JW
859 if (IsGuarded) {\r
860 return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);\r
861 }\r
285a682c
JY
862 return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);\r
863}\r
864\r
f965b772
ED
865/**\r
866 Check whether the input range is in memory map.\r
867\r
868 @param Memory Base address of memory being inputed.\r
869 @param NumberOfPages The number of pages.\r
870\r
871 @retval TRUE In memory map.\r
872 @retval FALSE Not in memory map.\r
873\r
874**/\r
875BOOLEAN\r
876InMemMap (\r
877 IN EFI_PHYSICAL_ADDRESS Memory,\r
878 IN UINTN NumberOfPages\r
879 )\r
880{\r
881 LIST_ENTRY *Link;\r
882 MEMORY_MAP *Entry;\r
883 EFI_PHYSICAL_ADDRESS Last;\r
884\r
885 Last = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1;\r
886\r
887 Link = gMemoryMap.ForwardLink;\r
888 while (Link != &gMemoryMap) {\r
889 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
890 Link = Link->ForwardLink;\r
891\r
892 if ((Entry->Start <= Memory) && (Entry->End >= Last)) {\r
893 return TRUE;\r
894 }\r
895 }\r
896\r
897 return FALSE;\r
898}\r
899\r
84edd20b
SZ
900/**\r
901 Frees previous allocated pages.\r
902\r
903 @param Memory Base address of memory being freed.\r
904 @param NumberOfPages The number of pages to free.\r
905\r
906 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 907 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
84edd20b
SZ
908 @return EFI_SUCCESS Pages successfully freed.\r
909\r
910**/\r
911EFI_STATUS\r
912EFIAPI\r
913SmmFreePages (\r
914 IN EFI_PHYSICAL_ADDRESS Memory,\r
915 IN UINTN NumberOfPages\r
916 )\r
917{\r
918 EFI_STATUS Status;\r
e63da9f0 919 BOOLEAN IsGuarded;\r
84edd20b 920\r
f965b772
ED
921 if (!InMemMap(Memory, NumberOfPages)) {\r
922 return EFI_NOT_FOUND;\r
923 }\r
924\r
e63da9f0
JW
925 IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);\r
926 Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);\r
84edd20b 927 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
928 SmmCoreUpdateProfile (\r
929 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
930 MemoryProfileActionFreePages,\r
931 EfiMaxMemoryType,\r
932 EFI_PAGES_TO_SIZE (NumberOfPages),\r
933 (VOID *) (UINTN) Memory,\r
934 NULL\r
935 );\r
84edd20b
SZ
936 }\r
937 return Status;\r
938}\r
939\r
e42e9404 940/**\r
941 Add free SMRAM region for use by memory service.\r
942\r
943 @param MemBase Base address of memory region.\r
944 @param MemLength Length of the memory region.\r
945 @param Type Memory type.\r
946 @param Attributes Memory region state.\r
947\r
948**/\r
949VOID\r
950SmmAddMemoryRegion (\r
951 IN EFI_PHYSICAL_ADDRESS MemBase,\r
952 IN UINT64 MemLength,\r
953 IN EFI_MEMORY_TYPE Type,\r
954 IN UINT64 Attributes\r
955 )\r
956{\r
957 UINTN AlignedMemBase;\r
958\r
3df4b6e7 959 //\r
285a682c 960 // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization\r
3df4b6e7 961 //\r
962 if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
285a682c
JY
963 Type = EfiRuntimeServicesData;\r
964 } else {\r
965 Type = EfiConventionalMemory;\r
3df4b6e7 966 }\r
285a682c
JY
967\r
968 DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));\r
969 DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));\r
970 DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));\r
971 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));\r
972 DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));\r
973\r
3df4b6e7 974 //\r
975 // Align range on an EFI_PAGE_SIZE boundary\r
285a682c 976 //\r
e42e9404 977 AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;\r
978 MemLength -= AlignedMemBase - MemBase;\r
285a682c
JY
979 if (Type == EfiConventionalMemory) {\r
980 SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
981 } else {\r
982 ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
983 }\r
984\r
985 CoreFreeMemoryMapStack ();\r
986}\r
987\r
988/**\r
989 This function returns a copy of the current memory map. The map is an array of\r
990 memory descriptors, each of which describes a contiguous block of memory.\r
991\r
992 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
993 MemoryMap buffer. On input, this is the size of\r
994 the buffer allocated by the caller. On output,\r
995 it is the size of the buffer returned by the\r
996 firmware if the buffer was large enough, or the\r
997 size of the buffer needed to contain the map if\r
998 the buffer was too small.\r
999 @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
1000 the current memory map.\r
1001 @param[out] MapKey A pointer to the location in which firmware\r
1002 returns the key for the current memory map.\r
1003 @param[out] DescriptorSize A pointer to the location in which firmware\r
1004 returns the size, in bytes, of an individual\r
1005 EFI_MEMORY_DESCRIPTOR.\r
1006 @param[out] DescriptorVersion A pointer to the location in which firmware\r
1007 returns the version number associated with the\r
1008 EFI_MEMORY_DESCRIPTOR.\r
1009\r
1010 @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
1011 buffer.\r
1012 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
1013 buffer size needed to hold the memory map is\r
1014 returned in MemoryMapSize.\r
1015 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1016\r
1017**/\r
1018EFI_STATUS\r
1019EFIAPI\r
1020SmmCoreGetMemoryMap (\r
1021 IN OUT UINTN *MemoryMapSize,\r
1022 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1023 OUT UINTN *MapKey,\r
1024 OUT UINTN *DescriptorSize,\r
1025 OUT UINT32 *DescriptorVersion\r
1026 )\r
1027{\r
1028 UINTN Count;\r
1029 LIST_ENTRY *Link;\r
1030 MEMORY_MAP *Entry;\r
1031 UINTN Size;\r
1032 UINTN BufferSize;\r
1033\r
1034 Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
1035\r
1036 //\r
1037 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
1038 // prevent people from having pointer math bugs in their code.\r
1039 // now you have to use *DescriptorSize to make things work.\r
1040 //\r
1041 Size += sizeof(UINT64) - (Size % sizeof (UINT64));\r
1042\r
1043 if (DescriptorSize != NULL) {\r
1044 *DescriptorSize = Size;\r
1045 }\r
1046\r
1047 if (DescriptorVersion != NULL) {\r
1048 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
1049 }\r
1050\r
1051 Count = GetSmmMemoryMapEntryCount ();\r
1052 BufferSize = Size * Count;\r
1053 if (*MemoryMapSize < BufferSize) {\r
1054 *MemoryMapSize = BufferSize;\r
1055 return EFI_BUFFER_TOO_SMALL;\r
1056 }\r
1057\r
1058 *MemoryMapSize = BufferSize;\r
1059 if (MemoryMap == NULL) {\r
1060 return EFI_INVALID_PARAMETER;\r
1061 }\r
1062\r
1063 ZeroMem (MemoryMap, BufferSize);\r
1064 Link = gMemoryMap.ForwardLink;\r
1065 while (Link != &gMemoryMap) {\r
1066 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1067 Link = Link->ForwardLink;\r
1068\r
1069 MemoryMap->Type = Entry->Type;\r
1070 MemoryMap->PhysicalStart = Entry->Start;\r
1071 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
1072\r
1073 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
1074 }\r
1075\r
1076 return EFI_SUCCESS;\r
e42e9404 1077}\r