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