]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
Update PI SMM Core to ignore memory ranges from SMRAM Descriptors that are already...
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory pool management functions.\r
3\r
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
9\r
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
12\r
13**/\r
14\r
15#include "PiSmmCore.h"\r
16\r
17//\r
18// MIN_POOL_SHIFT must not be less than 5\r
19//\r
20#define MIN_POOL_SHIFT 6\r
21#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)\r
22\r
23//\r
24// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1\r
25//\r
26#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)\r
27#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)\r
28\r
29//\r
30// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes\r
31//\r
32#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)\r
33\r
34typedef struct {\r
35 UINTN Size;\r
36 BOOLEAN Available;\r
37} POOL_HEADER;\r
38\r
39typedef struct {\r
40 POOL_HEADER Header;\r
41 LIST_ENTRY Link;\r
42} FREE_POOL_HEADER;\r
43\r
44LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX];\r
45\r
46/**\r
47 Called to initialize the memory service.\r
48\r
49 @param SmramRangeCount Number of SMRAM Regions\r
50 @param SmramRanges Pointer to SMRAM Descriptors\r
51\r
52**/\r
53VOID\r
54SmmInitializeMemoryServices (\r
55 IN UINTN SmramRangeCount,\r
56 IN EFI_SMRAM_DESCRIPTOR *SmramRanges\r
57 )\r
58{\r
59 UINTN Index;\r
60\r
61 //\r
62 // Initialize Pool list\r
63 //\r
64 for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {\r
65 InitializeListHead (&mSmmPoolLists[--Index]);\r
66 }\r
67\r
68 //\r
69 // Initialize free SMRAM regions\r
70 //\r
71 for (Index = 0; Index < SmramRangeCount; Index++) {\r
72 SmmAddMemoryRegion (\r
73 SmramRanges[Index].CpuStart,\r
74 SmramRanges[Index].PhysicalSize,\r
75 EfiConventionalMemory,\r
76 SmramRanges[Index].RegionState\r
77 );\r
78 }\r
79}\r
80\r
81/**\r
82 Internal Function. Allocate a pool by specified PoolIndex.\r
83\r
84 @param PoolIndex Index which indicate the Pool size.\r
85 @param FreePoolHdr The returned Free pool.\r
86\r
87 @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
88 @retval EFI_SUCCESS Pool successfully allocated.\r
89\r
90**/\r
91EFI_STATUS\r
92InternalAllocPoolByIndex (\r
93 IN UINTN PoolIndex,\r
94 OUT FREE_POOL_HEADER **FreePoolHdr\r
95 )\r
96{\r
97 EFI_STATUS Status;\r
98 FREE_POOL_HEADER *Hdr;\r
99\r
100 Status = EFI_SUCCESS;\r
101 if (PoolIndex == MAX_POOL_INDEX) {\r
102 Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1));\r
103 if (Hdr == NULL) {\r
5b422a7b 104 return EFI_OUT_OF_RESOURCES;\r
e42e9404 105 }\r
106 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
107 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
108 RemoveEntryList (&Hdr->Link);\r
109 } else {\r
110 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
111 if (!EFI_ERROR (Status)) {\r
112 Hdr->Header.Size >>= 1;\r
113 Hdr->Header.Available = TRUE;\r
114 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
115 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
116 }\r
117 }\r
118\r
119 if (!EFI_ERROR (Status)) {\r
120 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
121 Hdr->Header.Available = FALSE;\r
122 }\r
123\r
124 *FreePoolHdr = Hdr;\r
125 return Status;\r
126}\r
127\r
128/**\r
129 Internal Function. Free a pool by specified PoolIndex.\r
130\r
131 @param FreePoolHdr The pool to free.\r
132\r
133 @retval EFI_SUCCESS Pool successfully freed.\r
134\r
135**/\r
136EFI_STATUS\r
137InternalFreePoolByIndex (\r
138 IN FREE_POOL_HEADER *FreePoolHdr\r
139 )\r
140{\r
141 UINTN PoolIndex;\r
142\r
143 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
144 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
145 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
146\r
147 PoolIndex = HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT;\r
148 FreePoolHdr->Header.Available = TRUE;\r
5b422a7b 149 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
e42e9404 150 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
151 return EFI_SUCCESS;\r
152}\r
153\r
154/**\r
155 Allocate pool of a particular type.\r
156\r
157 @param PoolType Type of pool to allocate.\r
158 @param Size The amount of pool to allocate.\r
159 @param Buffer The address to return a pointer to the allocated\r
160 pool.\r
161\r
162 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
163 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
164 @retval EFI_SUCCESS Pool successfully allocated.\r
165\r
166**/\r
167EFI_STATUS\r
168EFIAPI\r
169SmmAllocatePool (\r
170 IN EFI_MEMORY_TYPE PoolType,\r
171 IN UINTN Size,\r
172 OUT VOID **Buffer\r
173 )\r
174{\r
175 POOL_HEADER *PoolHdr;\r
176 FREE_POOL_HEADER *FreePoolHdr;\r
177 EFI_STATUS Status;\r
178 EFI_PHYSICAL_ADDRESS Address;\r
179 UINTN PoolIndex;\r
180\r
181 if (PoolType != EfiRuntimeServicesCode &&\r
182 PoolType != EfiRuntimeServicesData) {\r
183 return EFI_INVALID_PARAMETER;\r
184 }\r
185\r
186 if (Size == 0) {\r
187 *Buffer = NULL;\r
188 return EFI_SUCCESS;\r
189 }\r
190\r
191 Size += sizeof (*PoolHdr);\r
192 if (Size > MAX_POOL_SIZE) {\r
193 Size = EFI_SIZE_TO_PAGES (Size);\r
194 Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
195 if (EFI_ERROR (Status)) {\r
196 return Status;\r
197 }\r
198\r
199 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
200 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
201 PoolHdr->Available = FALSE;\r
202 *Buffer = PoolHdr + 1;\r
203 return Status;\r
204 }\r
205\r
206 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
207 PoolIndex = HighBitSet32 ((UINT32)Size);\r
208 if ((Size & (Size - 1)) != 0) {\r
209 PoolIndex++;\r
210 }\r
211\r
212 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
213 *Buffer = &FreePoolHdr->Header + 1;\r
214 return Status;\r
215}\r
216\r
217/**\r
218 Frees pool.\r
219\r
220 @param Buffer The allocated pool entry to free.\r
221\r
222 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
223 @retval EFI_SUCCESS Pool successfully freed.\r
224\r
225**/\r
226EFI_STATUS\r
227EFIAPI\r
228SmmFreePool (\r
229 IN VOID *Buffer\r
230 )\r
231{\r
232 FREE_POOL_HEADER *FreePoolHdr;\r
233\r
234 if (Buffer == NULL) {\r
235 return EFI_INVALID_PARAMETER;\r
236 }\r
237\r
238 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
239 ASSERT (!FreePoolHdr->Header.Available);\r
240\r
241 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
242 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
243 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
244 return SmmFreePages (\r
245 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
246 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
247 );\r
248 }\r
249 return InternalFreePoolByIndex (FreePoolHdr);\r
250}\r