]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Page.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
9d510e61 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
e42e9404 6\r
7**/\r
8\r
9#include "PiSmmCore.h"\r
285a682c 10#include <Library/SmmServicesTableLib.h>\r
e42e9404 11\r
12#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)\r
13\r
e42e9404 14LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);\r
15\r
285a682c
JY
16//\r
17// For GetMemoryMap()\r
18//\r
19\r
20#define MEMORY_MAP_SIGNATURE SIGNATURE_32('m','m','a','p')\r
21typedef struct {\r
22 UINTN Signature;\r
23 LIST_ENTRY Link;\r
24\r
25 BOOLEAN FromStack;\r
26 EFI_MEMORY_TYPE Type;\r
27 UINT64 Start;\r
28 UINT64 End;\r
29\r
30} MEMORY_MAP;\r
31\r
32LIST_ENTRY gMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (gMemoryMap);\r
33\r
34\r
35#define MAX_MAP_DEPTH 6\r
36\r
37///\r
38/// mMapDepth - depth of new descriptor stack\r
39///\r
40UINTN mMapDepth = 0;\r
41///\r
42/// mMapStack - space to use as temp storage to build new map descriptors\r
43///\r
44MEMORY_MAP mMapStack[MAX_MAP_DEPTH];\r
45UINTN mFreeMapStack = 0;\r
46///\r
47/// This list maintain the free memory map list\r
48///\r
49LIST_ENTRY mFreeMemoryMapEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mFreeMemoryMapEntryList);\r
50\r
51/**\r
52 Allocates pages from the memory map.\r
53\r
54 @param[in] Type The type of allocation to perform.\r
55 @param[in] MemoryType The type of memory to turn the allocated pages\r
56 into.\r
57 @param[in] NumberOfPages The number of pages to allocate.\r
58 @param[out] Memory A pointer to receive the base allocated memory\r
59 address.\r
60 @param[in] AddRegion If this memory is new added region.\r
e63da9f0
JW
61 @param[in] NeedGuard Flag to indicate Guard page is needed\r
62 or not\r
285a682c
JY
63\r
64 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
65 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
66 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
67 @retval EFI_SUCCESS Pages successfully allocated.\r
68\r
69**/\r
70EFI_STATUS\r
71SmmInternalAllocatePagesEx (\r
72 IN EFI_ALLOCATE_TYPE Type,\r
73 IN EFI_MEMORY_TYPE MemoryType,\r
74 IN UINTN NumberOfPages,\r
75 OUT EFI_PHYSICAL_ADDRESS *Memory,\r
e63da9f0
JW
76 IN BOOLEAN AddRegion,\r
77 IN BOOLEAN NeedGuard\r
285a682c
JY
78 );\r
79\r
80/**\r
81 Internal function. Deque a descriptor entry from the mFreeMemoryMapEntryList.\r
82 If the list is emtry, then allocate a new page to refuel the list.\r
83 Please Note this algorithm to allocate the memory map descriptor has a property\r
84 that the memory allocated for memory entries always grows, and will never really be freed.\r
85\r
86 @return The Memory map descriptor dequed from the mFreeMemoryMapEntryList\r
87\r
88**/\r
89MEMORY_MAP *\r
90AllocateMemoryMapEntry (\r
91 VOID\r
92 )\r
93{\r
94 EFI_PHYSICAL_ADDRESS Mem;\r
95 EFI_STATUS Status;\r
96 MEMORY_MAP* FreeDescriptorEntries;\r
97 MEMORY_MAP* Entry;\r
98 UINTN Index;\r
99\r
100 //DEBUG((DEBUG_INFO, "AllocateMemoryMapEntry\n"));\r
101\r
102 if (IsListEmpty (&mFreeMemoryMapEntryList)) {\r
103 //DEBUG((DEBUG_INFO, "mFreeMemoryMapEntryList is empty\n"));\r
104 //\r
105 // The list is empty, to allocate one page to refuel the list\r
106 //\r
107 Status = SmmInternalAllocatePagesEx (\r
108 AllocateAnyPages,\r
109 EfiRuntimeServicesData,\r
115d9753 110 EFI_SIZE_TO_PAGES (RUNTIME_PAGE_ALLOCATION_GRANULARITY),\r
285a682c 111 &Mem,\r
e63da9f0
JW
112 TRUE,\r
113 FALSE\r
285a682c
JY
114 );\r
115 ASSERT_EFI_ERROR (Status);\r
116 if(!EFI_ERROR (Status)) {\r
117 FreeDescriptorEntries = (MEMORY_MAP *)(UINTN)Mem;\r
118 //DEBUG((DEBUG_INFO, "New FreeDescriptorEntries - 0x%x\n", FreeDescriptorEntries));\r
119 //\r
120 // Enque the free memmory map entries into the list\r
121 //\r
115d9753 122 for (Index = 0; Index< RUNTIME_PAGE_ALLOCATION_GRANULARITY / sizeof(MEMORY_MAP); Index++) {\r
285a682c
JY
123 FreeDescriptorEntries[Index].Signature = MEMORY_MAP_SIGNATURE;\r
124 InsertTailList (&mFreeMemoryMapEntryList, &FreeDescriptorEntries[Index].Link);\r
125 }\r
126 } else {\r
127 return NULL;\r
128 }\r
129 }\r
130 //\r
131 // dequeue the first descriptor from the list\r
132 //\r
133 Entry = CR (mFreeMemoryMapEntryList.ForwardLink, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
134 RemoveEntryList (&Entry->Link);\r
135\r
136 return Entry;\r
137}\r
138\r
139\r
140/**\r
141 Internal function. Moves any memory descriptors that are on the\r
142 temporary descriptor stack to heap.\r
143\r
144**/\r
145VOID\r
146CoreFreeMemoryMapStack (\r
147 VOID\r
148 )\r
149{\r
150 MEMORY_MAP *Entry;\r
151\r
152 //\r
153 // If already freeing the map stack, then return\r
154 //\r
155 if (mFreeMapStack != 0) {\r
156 ASSERT (FALSE);\r
157 return ;\r
158 }\r
159\r
160 //\r
161 // Move the temporary memory descriptor stack into pool\r
162 //\r
163 mFreeMapStack += 1;\r
164\r
165 while (mMapDepth != 0) {\r
166 //\r
167 // Deque an memory map entry from mFreeMemoryMapEntryList\r
168 //\r
169 Entry = AllocateMemoryMapEntry ();\r
170 ASSERT (Entry);\r
171\r
172 //\r
173 // Update to proper entry\r
174 //\r
175 mMapDepth -= 1;\r
176\r
177 if (mMapStack[mMapDepth].Link.ForwardLink != NULL) {\r
178\r
179 CopyMem (Entry , &mMapStack[mMapDepth], sizeof (MEMORY_MAP));\r
180 Entry->FromStack = FALSE;\r
181\r
182 //\r
183 // Move this entry to general memory\r
184 //\r
185 InsertTailList (&mMapStack[mMapDepth].Link, &Entry->Link);\r
186 RemoveEntryList (&mMapStack[mMapDepth].Link);\r
187 mMapStack[mMapDepth].Link.ForwardLink = NULL;\r
188 }\r
189 }\r
190\r
191 mFreeMapStack -= 1;\r
192}\r
193\r
194/**\r
195 Insert new entry from memory map.\r
196\r
197 @param[in] Link The old memory map entry to be linked.\r
198 @param[in] Start The start address of new memory map entry.\r
199 @param[in] End The end address of new memory map entry.\r
200 @param[in] Type The type of new memory map entry.\r
201 @param[in] Next If new entry is inserted to the next of old entry.\r
202 @param[in] AddRegion If this memory is new added region.\r
203**/\r
204VOID\r
205InsertNewEntry (\r
206 IN LIST_ENTRY *Link,\r
207 IN UINT64 Start,\r
208 IN UINT64 End,\r
209 IN EFI_MEMORY_TYPE Type,\r
210 IN BOOLEAN Next,\r
211 IN BOOLEAN AddRegion\r
212 )\r
213{\r
214 MEMORY_MAP *Entry;\r
215\r
216 Entry = &mMapStack[mMapDepth];\r
217 mMapDepth += 1;\r
218 ASSERT (mMapDepth < MAX_MAP_DEPTH);\r
219 Entry->FromStack = TRUE;\r
220\r
221 Entry->Signature = MEMORY_MAP_SIGNATURE;\r
222 Entry->Type = Type;\r
223 Entry->Start = Start;\r
224 Entry->End = End;\r
225 if (Next) {\r
226 InsertHeadList (Link, &Entry->Link);\r
227 } else {\r
228 InsertTailList (Link, &Entry->Link);\r
229 }\r
230}\r
231\r
232/**\r
233 Remove old entry from memory map.\r
234\r
235 @param[in] Entry Memory map entry to be removed.\r
236**/\r
237VOID\r
238RemoveOldEntry (\r
239 IN MEMORY_MAP *Entry\r
240 )\r
241{\r
242 RemoveEntryList (&Entry->Link);\r
e434be3c
SZ
243 Entry->Link.ForwardLink = NULL;\r
244\r
285a682c
JY
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
285a682c 448\r
285a682c 449\r
e42e9404 450/**\r
451 Internal Function. Allocate n pages from given free page node.\r
452\r
453 @param Pages The free page node.\r
454 @param NumberOfPages Number of pages to be allocated.\r
455 @param MaxAddress Request to allocate memory below this address.\r
456\r
457 @return Memory address of allocated pages.\r
458\r
459**/\r
460UINTN\r
461InternalAllocPagesOnOneNode (\r
462 IN OUT FREE_PAGE_LIST *Pages,\r
463 IN UINTN NumberOfPages,\r
464 IN UINTN MaxAddress\r
465 )\r
466{\r
467 UINTN Top;\r
468 UINTN Bottom;\r
469 FREE_PAGE_LIST *Node;\r
470\r
471 Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);\r
472 if (Top > Pages->NumberOfPages) {\r
473 Top = Pages->NumberOfPages;\r
474 }\r
475 Bottom = Top - NumberOfPages;\r
476\r
477 if (Top < Pages->NumberOfPages) {\r
478 Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));\r
479 Node->NumberOfPages = Pages->NumberOfPages - Top;\r
480 InsertHeadList (&Pages->Link, &Node->Link);\r
481 }\r
482\r
483 if (Bottom > 0) {\r
484 Pages->NumberOfPages = Bottom;\r
485 } else {\r
486 RemoveEntryList (&Pages->Link);\r
487 }\r
488\r
489 return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);\r
490}\r
491\r
492/**\r
493 Internal Function. Allocate n pages from free page list below MaxAddress.\r
494\r
495 @param FreePageList The free page node.\r
496 @param NumberOfPages Number of pages to be allocated.\r
497 @param MaxAddress Request to allocate memory below this address.\r
498\r
499 @return Memory address of allocated pages.\r
500\r
501**/\r
502UINTN\r
503InternalAllocMaxAddress (\r
504 IN OUT LIST_ENTRY *FreePageList,\r
505 IN UINTN NumberOfPages,\r
506 IN UINTN MaxAddress\r
507 )\r
508{\r
509 LIST_ENTRY *Node;\r
510 FREE_PAGE_LIST *Pages;\r
511\r
512 for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {\r
513 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
514 if (Pages->NumberOfPages >= NumberOfPages &&\r
515 (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {\r
516 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);\r
517 }\r
518 }\r
519 return (UINTN)(-1);\r
520}\r
521\r
522/**\r
523 Internal Function. Allocate n pages from free page list at given address.\r
524\r
525 @param FreePageList The free page node.\r
526 @param NumberOfPages Number of pages to be allocated.\r
527 @param MaxAddress Request to allocate memory below this address.\r
528\r
529 @return Memory address of allocated pages.\r
530\r
531**/\r
532UINTN\r
533InternalAllocAddress (\r
534 IN OUT LIST_ENTRY *FreePageList,\r
535 IN UINTN NumberOfPages,\r
536 IN UINTN Address\r
537 )\r
538{\r
539 UINTN EndAddress;\r
540 LIST_ENTRY *Node;\r
541 FREE_PAGE_LIST *Pages;\r
542\r
543 if ((Address & EFI_PAGE_MASK) != 0) {\r
544 return ~Address;\r
545 }\r
546\r
547 EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);\r
548 for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {\r
549 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
550 if ((UINTN)Pages <= Address) {\r
551 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {\r
552 break;\r
553 }\r
554 return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);\r
555 }\r
556 }\r
557 return ~Address;\r
558}\r
559\r
560/**\r
561 Allocates pages from the memory map.\r
562\r
285a682c
JY
563 @param[in] Type The type of allocation to perform.\r
564 @param[in] MemoryType The type of memory to turn the allocated pages\r
565 into.\r
566 @param[in] NumberOfPages The number of pages to allocate.\r
567 @param[out] Memory A pointer to receive the base allocated memory\r
568 address.\r
569 @param[in] AddRegion If this memory is new added region.\r
e63da9f0
JW
570 @param[in] NeedGuard Flag to indicate Guard page is needed\r
571 or not\r
e42e9404 572\r
573 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
574 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
575 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
576 @retval EFI_SUCCESS Pages successfully allocated.\r
577\r
578**/\r
579EFI_STATUS\r
285a682c 580SmmInternalAllocatePagesEx (\r
e42e9404 581 IN EFI_ALLOCATE_TYPE Type,\r
582 IN EFI_MEMORY_TYPE MemoryType,\r
583 IN UINTN NumberOfPages,\r
285a682c 584 OUT EFI_PHYSICAL_ADDRESS *Memory,\r
e63da9f0
JW
585 IN BOOLEAN AddRegion,\r
586 IN BOOLEAN NeedGuard\r
e42e9404 587 )\r
588{\r
589 UINTN RequestedAddress;\r
590\r
591 if (MemoryType != EfiRuntimeServicesCode &&\r
592 MemoryType != EfiRuntimeServicesData) {\r
593 return EFI_INVALID_PARAMETER;\r
594 }\r
595\r
596 if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {\r
597 return EFI_OUT_OF_RESOURCES;\r
598 }\r
599\r
600 //\r
601 // We don't track memory type in SMM\r
602 //\r
603 RequestedAddress = (UINTN)*Memory;\r
604 switch (Type) {\r
605 case AllocateAnyPages:\r
606 RequestedAddress = (UINTN)(-1);\r
607 case AllocateMaxAddress:\r
e63da9f0
JW
608 if (NeedGuard) {\r
609 *Memory = InternalAllocMaxAddressWithGuard (\r
610 &mSmmMemoryMap,\r
611 NumberOfPages,\r
612 RequestedAddress,\r
613 MemoryType\r
614 );\r
615 if (*Memory == (UINTN)-1) {\r
616 return EFI_OUT_OF_RESOURCES;\r
617 } else {\r
618 ASSERT (VerifyMemoryGuard (*Memory, NumberOfPages) == TRUE);\r
619 return EFI_SUCCESS;\r
620 }\r
621 }\r
622\r
e42e9404 623 *Memory = InternalAllocMaxAddress (\r
624 &mSmmMemoryMap,\r
625 NumberOfPages,\r
626 RequestedAddress\r
627 );\r
628 if (*Memory == (UINTN)-1) {\r
629 return EFI_OUT_OF_RESOURCES;\r
285a682c 630 }\r
e42e9404 631 break;\r
632 case AllocateAddress:\r
633 *Memory = InternalAllocAddress (\r
634 &mSmmMemoryMap,\r
635 NumberOfPages,\r
636 RequestedAddress\r
637 );\r
638 if (*Memory != RequestedAddress) {\r
639 return EFI_NOT_FOUND;\r
640 }\r
641 break;\r
642 default:\r
643 return EFI_INVALID_PARAMETER;\r
644 }\r
285a682c
JY
645\r
646 //\r
647 // Update SmmMemoryMap here.\r
648 //\r
649 ConvertSmmMemoryMapEntry (MemoryType, *Memory, NumberOfPages, AddRegion);\r
650 if (!AddRegion) {\r
651 CoreFreeMemoryMapStack();\r
652 }\r
653\r
e42e9404 654 return EFI_SUCCESS;\r
655}\r
656\r
285a682c
JY
657/**\r
658 Allocates pages from the memory map.\r
659\r
660 @param[in] Type The type of allocation to perform.\r
661 @param[in] MemoryType The type of memory to turn the allocated pages\r
662 into.\r
663 @param[in] NumberOfPages The number of pages to allocate.\r
664 @param[out] Memory A pointer to receive the base allocated memory\r
665 address.\r
e63da9f0
JW
666 @param[in] NeedGuard Flag to indicate Guard page is needed\r
667 or not\r
285a682c
JY
668\r
669 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
670 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
671 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
672 @retval EFI_SUCCESS Pages successfully allocated.\r
673\r
674**/\r
675EFI_STATUS\r
676EFIAPI\r
677SmmInternalAllocatePages (\r
678 IN EFI_ALLOCATE_TYPE Type,\r
679 IN EFI_MEMORY_TYPE MemoryType,\r
680 IN UINTN NumberOfPages,\r
e63da9f0
JW
681 OUT EFI_PHYSICAL_ADDRESS *Memory,\r
682 IN BOOLEAN NeedGuard\r
285a682c
JY
683 )\r
684{\r
e63da9f0
JW
685 return SmmInternalAllocatePagesEx (Type, MemoryType, NumberOfPages, Memory,\r
686 FALSE, NeedGuard);\r
285a682c
JY
687}\r
688\r
84edd20b
SZ
689/**\r
690 Allocates pages from the memory map.\r
691\r
692 @param Type The type of allocation to perform.\r
693 @param MemoryType The type of memory to turn the allocated pages\r
694 into.\r
695 @param NumberOfPages The number of pages to allocate.\r
696 @param Memory A pointer to receive the base allocated memory\r
697 address.\r
698\r
699 @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
700 @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
701 @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
702 @retval EFI_SUCCESS Pages successfully allocated.\r
703\r
704**/\r
705EFI_STATUS\r
706EFIAPI\r
707SmmAllocatePages (\r
708 IN EFI_ALLOCATE_TYPE Type,\r
709 IN EFI_MEMORY_TYPE MemoryType,\r
710 IN UINTN NumberOfPages,\r
711 OUT EFI_PHYSICAL_ADDRESS *Memory\r
712 )\r
713{\r
714 EFI_STATUS Status;\r
e63da9f0 715 BOOLEAN NeedGuard;\r
84edd20b 716\r
e63da9f0
JW
717 NeedGuard = IsPageTypeToGuard (MemoryType, Type);\r
718 Status = SmmInternalAllocatePages (Type, MemoryType, NumberOfPages, Memory,\r
719 NeedGuard);\r
84edd20b 720 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
721 SmmCoreUpdateProfile (\r
722 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
723 MemoryProfileActionAllocatePages,\r
724 MemoryType,\r
725 EFI_PAGES_TO_SIZE (NumberOfPages),\r
726 (VOID *) (UINTN) *Memory,\r
727 NULL\r
728 );\r
84edd20b
SZ
729 }\r
730 return Status;\r
731}\r
732\r
e42e9404 733/**\r
734 Internal Function. Merge two adjacent nodes.\r
735\r
736 @param First The first of two nodes to merge.\r
737\r
738 @return Pointer to node after merge (if success) or pointer to next node (if fail).\r
739\r
740**/\r
741FREE_PAGE_LIST *\r
742InternalMergeNodes (\r
743 IN FREE_PAGE_LIST *First\r
744 )\r
745{\r
746 FREE_PAGE_LIST *Next;\r
747\r
748 Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);\r
749 ASSERT (\r
750 TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);\r
751\r
752 if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {\r
753 First->NumberOfPages += Next->NumberOfPages;\r
754 RemoveEntryList (&Next->Link);\r
755 Next = First;\r
756 }\r
757 return Next;\r
758}\r
759\r
760/**\r
761 Frees previous allocated pages.\r
762\r
285a682c
JY
763 @param[in] Memory Base address of memory being freed.\r
764 @param[in] NumberOfPages The number of pages to free.\r
765 @param[in] AddRegion If this memory is new added region.\r
e42e9404 766\r
767 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 768 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
e42e9404 769 @return EFI_SUCCESS Pages successfully freed.\r
770\r
771**/\r
772EFI_STATUS\r
285a682c 773SmmInternalFreePagesEx (\r
e42e9404 774 IN EFI_PHYSICAL_ADDRESS Memory,\r
285a682c
JY
775 IN UINTN NumberOfPages,\r
776 IN BOOLEAN AddRegion\r
e42e9404 777 )\r
778{\r
779 LIST_ENTRY *Node;\r
780 FREE_PAGE_LIST *Pages;\r
781\r
ddfae264 782 if (((Memory & EFI_PAGE_MASK) != 0) || (Memory == 0) || (NumberOfPages == 0)) {\r
e42e9404 783 return EFI_INVALID_PARAMETER;\r
784 }\r
785\r
786 Pages = NULL;\r
787 Node = mSmmMemoryMap.ForwardLink;\r
788 while (Node != &mSmmMemoryMap) {\r
789 Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
790 if (Memory < (UINTN)Pages) {\r
791 break;\r
792 }\r
793 Node = Node->ForwardLink;\r
794 }\r
795\r
796 if (Node != &mSmmMemoryMap &&\r
797 Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {\r
798 return EFI_INVALID_PARAMETER;\r
799 }\r
800\r
801 if (Node->BackLink != &mSmmMemoryMap) {\r
802 Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);\r
803 if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {\r
804 return EFI_INVALID_PARAMETER;\r
805 }\r
806 }\r
807\r
808 Pages = (FREE_PAGE_LIST*)(UINTN)Memory;\r
809 Pages->NumberOfPages = NumberOfPages;\r
810 InsertTailList (Node, &Pages->Link);\r
811\r
812 if (Pages->Link.BackLink != &mSmmMemoryMap) {\r
813 Pages = InternalMergeNodes (\r
814 BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)\r
815 );\r
816 }\r
817\r
818 if (Node != &mSmmMemoryMap) {\r
819 InternalMergeNodes (Pages);\r
820 }\r
821\r
285a682c
JY
822 //\r
823 // Update SmmMemoryMap here.\r
824 //\r
825 ConvertSmmMemoryMapEntry (EfiConventionalMemory, Memory, NumberOfPages, AddRegion);\r
826 if (!AddRegion) {\r
827 CoreFreeMemoryMapStack();\r
828 }\r
829\r
e42e9404 830 return EFI_SUCCESS;\r
831}\r
832\r
285a682c
JY
833/**\r
834 Frees previous allocated pages.\r
835\r
836 @param[in] Memory Base address of memory being freed.\r
837 @param[in] NumberOfPages The number of pages to free.\r
e63da9f0 838 @param[in] IsGuarded Is the memory to free guarded or not.\r
285a682c
JY
839\r
840 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 841 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
285a682c
JY
842 @return EFI_SUCCESS Pages successfully freed.\r
843\r
844**/\r
845EFI_STATUS\r
846EFIAPI\r
847SmmInternalFreePages (\r
848 IN EFI_PHYSICAL_ADDRESS Memory,\r
e63da9f0
JW
849 IN UINTN NumberOfPages,\r
850 IN BOOLEAN IsGuarded\r
285a682c
JY
851 )\r
852{\r
e63da9f0
JW
853 if (IsGuarded) {\r
854 return SmmInternalFreePagesExWithGuard (Memory, NumberOfPages, FALSE);\r
855 }\r
285a682c
JY
856 return SmmInternalFreePagesEx (Memory, NumberOfPages, FALSE);\r
857}\r
858\r
f965b772
ED
859/**\r
860 Check whether the input range is in memory map.\r
861\r
862 @param Memory Base address of memory being inputed.\r
863 @param NumberOfPages The number of pages.\r
864\r
865 @retval TRUE In memory map.\r
866 @retval FALSE Not in memory map.\r
867\r
868**/\r
869BOOLEAN\r
870InMemMap (\r
871 IN EFI_PHYSICAL_ADDRESS Memory,\r
872 IN UINTN NumberOfPages\r
873 )\r
874{\r
875 LIST_ENTRY *Link;\r
876 MEMORY_MAP *Entry;\r
877 EFI_PHYSICAL_ADDRESS Last;\r
878\r
879 Last = Memory + EFI_PAGES_TO_SIZE (NumberOfPages) - 1;\r
880\r
881 Link = gMemoryMap.ForwardLink;\r
882 while (Link != &gMemoryMap) {\r
883 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
884 Link = Link->ForwardLink;\r
885\r
886 if ((Entry->Start <= Memory) && (Entry->End >= Last)) {\r
887 return TRUE;\r
888 }\r
889 }\r
890\r
891 return FALSE;\r
892}\r
893\r
84edd20b
SZ
894/**\r
895 Frees previous allocated pages.\r
896\r
897 @param Memory Base address of memory being freed.\r
898 @param NumberOfPages The number of pages to free.\r
899\r
900 @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
ddfae264 901 @retval EFI_INVALID_PARAMETER Address not aligned, Address is zero or NumberOfPages is zero.\r
84edd20b
SZ
902 @return EFI_SUCCESS Pages successfully freed.\r
903\r
904**/\r
905EFI_STATUS\r
906EFIAPI\r
907SmmFreePages (\r
908 IN EFI_PHYSICAL_ADDRESS Memory,\r
909 IN UINTN NumberOfPages\r
910 )\r
911{\r
912 EFI_STATUS Status;\r
e63da9f0 913 BOOLEAN IsGuarded;\r
84edd20b 914\r
f965b772
ED
915 if (!InMemMap(Memory, NumberOfPages)) {\r
916 return EFI_NOT_FOUND;\r
917 }\r
918\r
e63da9f0
JW
919 IsGuarded = IsHeapGuardEnabled () && IsMemoryGuarded (Memory);\r
920 Status = SmmInternalFreePages (Memory, NumberOfPages, IsGuarded);\r
84edd20b 921 if (!EFI_ERROR (Status)) {\r
e524f680
SZ
922 SmmCoreUpdateProfile (\r
923 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),\r
924 MemoryProfileActionFreePages,\r
925 EfiMaxMemoryType,\r
926 EFI_PAGES_TO_SIZE (NumberOfPages),\r
927 (VOID *) (UINTN) Memory,\r
928 NULL\r
929 );\r
84edd20b
SZ
930 }\r
931 return Status;\r
932}\r
933\r
e42e9404 934/**\r
935 Add free SMRAM region for use by memory service.\r
936\r
937 @param MemBase Base address of memory region.\r
938 @param MemLength Length of the memory region.\r
939 @param Type Memory type.\r
940 @param Attributes Memory region state.\r
941\r
942**/\r
943VOID\r
944SmmAddMemoryRegion (\r
945 IN EFI_PHYSICAL_ADDRESS MemBase,\r
946 IN UINT64 MemLength,\r
947 IN EFI_MEMORY_TYPE Type,\r
948 IN UINT64 Attributes\r
949 )\r
950{\r
951 UINTN AlignedMemBase;\r
952\r
3df4b6e7 953 //\r
285a682c 954 // Add EfiRuntimeServicesData for memory regions that is already allocated, needs testing, or needs ECC initialization\r
3df4b6e7 955 //\r
956 if ((Attributes & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
285a682c
JY
957 Type = EfiRuntimeServicesData;\r
958 } else {\r
959 Type = EfiConventionalMemory;\r
3df4b6e7 960 }\r
285a682c
JY
961\r
962 DEBUG ((DEBUG_INFO, "SmmAddMemoryRegion\n"));\r
963 DEBUG ((DEBUG_INFO, " MemBase - 0x%lx\n", MemBase));\r
964 DEBUG ((DEBUG_INFO, " MemLength - 0x%lx\n", MemLength));\r
965 DEBUG ((DEBUG_INFO, " Type - 0x%x\n", Type));\r
966 DEBUG ((DEBUG_INFO, " Attributes - 0x%lx\n", Attributes));\r
967\r
3df4b6e7 968 //\r
969 // Align range on an EFI_PAGE_SIZE boundary\r
285a682c 970 //\r
e42e9404 971 AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;\r
972 MemLength -= AlignedMemBase - MemBase;\r
285a682c
JY
973 if (Type == EfiConventionalMemory) {\r
974 SmmInternalFreePagesEx (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
975 } else {\r
976 ConvertSmmMemoryMapEntry (EfiRuntimeServicesData, AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength), TRUE);\r
977 }\r
978\r
979 CoreFreeMemoryMapStack ();\r
980}\r
981\r
982/**\r
983 This function returns a copy of the current memory map. The map is an array of\r
984 memory descriptors, each of which describes a contiguous block of memory.\r
985\r
986 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the\r
987 MemoryMap buffer. On input, this is the size of\r
988 the buffer allocated by the caller. On output,\r
989 it is the size of the buffer returned by the\r
990 firmware if the buffer was large enough, or the\r
991 size of the buffer needed to contain the map if\r
992 the buffer was too small.\r
993 @param[in, out] MemoryMap A pointer to the buffer in which firmware places\r
994 the current memory map.\r
995 @param[out] MapKey A pointer to the location in which firmware\r
996 returns the key for the current memory map.\r
997 @param[out] DescriptorSize A pointer to the location in which firmware\r
998 returns the size, in bytes, of an individual\r
999 EFI_MEMORY_DESCRIPTOR.\r
1000 @param[out] DescriptorVersion A pointer to the location in which firmware\r
1001 returns the version number associated with the\r
1002 EFI_MEMORY_DESCRIPTOR.\r
1003\r
1004 @retval EFI_SUCCESS The memory map was returned in the MemoryMap\r
1005 buffer.\r
1006 @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current\r
1007 buffer size needed to hold the memory map is\r
1008 returned in MemoryMapSize.\r
1009 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1010\r
1011**/\r
1012EFI_STATUS\r
1013EFIAPI\r
1014SmmCoreGetMemoryMap (\r
1015 IN OUT UINTN *MemoryMapSize,\r
1016 IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,\r
1017 OUT UINTN *MapKey,\r
1018 OUT UINTN *DescriptorSize,\r
1019 OUT UINT32 *DescriptorVersion\r
1020 )\r
1021{\r
1022 UINTN Count;\r
1023 LIST_ENTRY *Link;\r
1024 MEMORY_MAP *Entry;\r
1025 UINTN Size;\r
1026 UINTN BufferSize;\r
1027\r
1028 Size = sizeof (EFI_MEMORY_DESCRIPTOR);\r
1029\r
1030 //\r
1031 // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will\r
1032 // prevent people from having pointer math bugs in their code.\r
1033 // now you have to use *DescriptorSize to make things work.\r
1034 //\r
1035 Size += sizeof(UINT64) - (Size % sizeof (UINT64));\r
1036\r
1037 if (DescriptorSize != NULL) {\r
1038 *DescriptorSize = Size;\r
1039 }\r
1040\r
1041 if (DescriptorVersion != NULL) {\r
1042 *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;\r
1043 }\r
1044\r
1045 Count = GetSmmMemoryMapEntryCount ();\r
1046 BufferSize = Size * Count;\r
1047 if (*MemoryMapSize < BufferSize) {\r
1048 *MemoryMapSize = BufferSize;\r
1049 return EFI_BUFFER_TOO_SMALL;\r
1050 }\r
1051\r
1052 *MemoryMapSize = BufferSize;\r
1053 if (MemoryMap == NULL) {\r
1054 return EFI_INVALID_PARAMETER;\r
1055 }\r
1056\r
1057 ZeroMem (MemoryMap, BufferSize);\r
1058 Link = gMemoryMap.ForwardLink;\r
1059 while (Link != &gMemoryMap) {\r
1060 Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);\r
1061 Link = Link->ForwardLink;\r
1062\r
1063 MemoryMap->Type = Entry->Type;\r
1064 MemoryMap->PhysicalStart = Entry->Start;\r
1065 MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);\r
1066\r
1067 MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size);\r
1068 }\r
1069\r
1070 return EFI_SUCCESS;\r
e42e9404 1071}\r