]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
Clean up DEC files:
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory pool management functions.\r
3\r
2c0f06f0 4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
e42e9404 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
3c447c27 45//\r
46// To cache the SMRAM base since when Loading modules At fixed address feature is enabled, \r
47// all module is assigned an offset relative the SMRAM base in build time.\r
48//\r
49GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;\r
e42e9404 50\r
51/**\r
52 Called to initialize the memory service.\r
53\r
54 @param SmramRangeCount Number of SMRAM Regions\r
55 @param SmramRanges Pointer to SMRAM Descriptors\r
56\r
57**/\r
58VOID\r
59SmmInitializeMemoryServices (\r
60 IN UINTN SmramRangeCount,\r
61 IN EFI_SMRAM_DESCRIPTOR *SmramRanges\r
62 )\r
63{\r
3c447c27 64 UINTN Index;\r
65 UINT64 SmmCodeSize;\r
66 UINTN CurrentSmramRangesIndex;\r
67 UINT64 MaxSize;\r
e42e9404 68\r
69 //\r
70 // Initialize Pool list\r
71 //\r
72 for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {\r
73 InitializeListHead (&mSmmPoolLists[--Index]);\r
74 }\r
3c447c27 75 CurrentSmramRangesIndex = 0;\r
76 //\r
77 // If Loadding Module At fixed Address feature is enabled, cache the SMRAM base here\r
78 //\r
79 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
80 //\r
81 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber\r
82 //\r
83 SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);\r
84 \r
85 //\r
86 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size\r
87 //\r
88 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {\r
2c0f06f0 89 //\r
90 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization\r
91 //\r
92 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
93 continue;\r
94 }\r
95\r
3c447c27 96 if (SmramRanges[Index].CpuStart >= BASE_1MB) {\r
97 if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) {\r
98 if (SmramRanges[Index].PhysicalSize >= MaxSize) {\r
99 MaxSize = SmramRanges[Index].PhysicalSize;\r
100 CurrentSmramRangesIndex = Index;\r
101 }\r
102 }\r
103 }\r
104 }\r
105 gLoadModuleAtFixAddressSmramBase = SmramRanges[CurrentSmramRangesIndex].CpuStart;\r
106 \r
107 //\r
108 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code\r
109 // A notable thing is that SMM core is already loaded into this range.\r
110 //\r
111 SmramRanges[CurrentSmramRangesIndex].CpuStart = SmramRanges[CurrentSmramRangesIndex].CpuStart + SmmCodeSize; \r
112 SmramRanges[CurrentSmramRangesIndex].PhysicalSize = SmramRanges[CurrentSmramRangesIndex].PhysicalSize - SmmCodeSize;\r
113 }\r
e42e9404 114 //\r
115 // Initialize free SMRAM regions\r
116 //\r
117 for (Index = 0; Index < SmramRangeCount; Index++) {\r
118 SmmAddMemoryRegion (\r
119 SmramRanges[Index].CpuStart,\r
120 SmramRanges[Index].PhysicalSize,\r
121 EfiConventionalMemory,\r
122 SmramRanges[Index].RegionState\r
123 );\r
124 }\r
3c447c27 125\r
e42e9404 126}\r
127\r
128/**\r
129 Internal Function. Allocate a pool by specified PoolIndex.\r
130\r
131 @param PoolIndex Index which indicate the Pool size.\r
132 @param FreePoolHdr The returned Free pool.\r
133\r
134 @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
135 @retval EFI_SUCCESS Pool successfully allocated.\r
136\r
137**/\r
138EFI_STATUS\r
139InternalAllocPoolByIndex (\r
140 IN UINTN PoolIndex,\r
141 OUT FREE_POOL_HEADER **FreePoolHdr\r
142 )\r
143{\r
144 EFI_STATUS Status;\r
145 FREE_POOL_HEADER *Hdr;\r
146\r
52c0d06b 147 ASSERT (PoolIndex <= MAX_POOL_INDEX);\r
e42e9404 148 Status = EFI_SUCCESS;\r
149 if (PoolIndex == MAX_POOL_INDEX) {\r
150 Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1));\r
151 if (Hdr == NULL) {\r
5b422a7b 152 return EFI_OUT_OF_RESOURCES;\r
e42e9404 153 }\r
154 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
155 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
156 RemoveEntryList (&Hdr->Link);\r
157 } else {\r
158 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
159 if (!EFI_ERROR (Status)) {\r
160 Hdr->Header.Size >>= 1;\r
161 Hdr->Header.Available = TRUE;\r
162 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
163 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
164 }\r
165 }\r
166\r
167 if (!EFI_ERROR (Status)) {\r
168 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
169 Hdr->Header.Available = FALSE;\r
170 }\r
171\r
172 *FreePoolHdr = Hdr;\r
173 return Status;\r
174}\r
175\r
176/**\r
177 Internal Function. Free a pool by specified PoolIndex.\r
178\r
179 @param FreePoolHdr The pool to free.\r
180\r
181 @retval EFI_SUCCESS Pool successfully freed.\r
182\r
183**/\r
184EFI_STATUS\r
185InternalFreePoolByIndex (\r
186 IN FREE_POOL_HEADER *FreePoolHdr\r
187 )\r
188{\r
189 UINTN PoolIndex;\r
190\r
191 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
192 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
193 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
194\r
fbe12b79 195 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);\r
e42e9404 196 FreePoolHdr->Header.Available = TRUE;\r
5b422a7b 197 ASSERT (PoolIndex < MAX_POOL_INDEX);\r
e42e9404 198 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
199 return EFI_SUCCESS;\r
200}\r
201\r
202/**\r
203 Allocate pool of a particular type.\r
204\r
205 @param PoolType Type of pool to allocate.\r
206 @param Size The amount of pool to allocate.\r
207 @param Buffer The address to return a pointer to the allocated\r
208 pool.\r
209\r
210 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
211 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
212 @retval EFI_SUCCESS Pool successfully allocated.\r
213\r
214**/\r
215EFI_STATUS\r
216EFIAPI\r
217SmmAllocatePool (\r
218 IN EFI_MEMORY_TYPE PoolType,\r
219 IN UINTN Size,\r
220 OUT VOID **Buffer\r
221 )\r
222{\r
223 POOL_HEADER *PoolHdr;\r
224 FREE_POOL_HEADER *FreePoolHdr;\r
225 EFI_STATUS Status;\r
226 EFI_PHYSICAL_ADDRESS Address;\r
227 UINTN PoolIndex;\r
228\r
229 if (PoolType != EfiRuntimeServicesCode &&\r
230 PoolType != EfiRuntimeServicesData) {\r
231 return EFI_INVALID_PARAMETER;\r
232 }\r
233\r
e42e9404 234 Size += sizeof (*PoolHdr);\r
235 if (Size > MAX_POOL_SIZE) {\r
236 Size = EFI_SIZE_TO_PAGES (Size);\r
237 Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
238 if (EFI_ERROR (Status)) {\r
239 return Status;\r
240 }\r
241\r
242 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
243 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
244 PoolHdr->Available = FALSE;\r
245 *Buffer = PoolHdr + 1;\r
246 return Status;\r
247 }\r
248\r
249 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
fbe12b79 250 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);\r
e42e9404 251 if ((Size & (Size - 1)) != 0) {\r
252 PoolIndex++;\r
253 }\r
254\r
255 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
256 *Buffer = &FreePoolHdr->Header + 1;\r
257 return Status;\r
258}\r
259\r
260/**\r
261 Frees pool.\r
262\r
263 @param Buffer The allocated pool entry to free.\r
264\r
265 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
266 @retval EFI_SUCCESS Pool successfully freed.\r
267\r
268**/\r
269EFI_STATUS\r
270EFIAPI\r
271SmmFreePool (\r
272 IN VOID *Buffer\r
273 )\r
274{\r
275 FREE_POOL_HEADER *FreePoolHdr;\r
276\r
277 if (Buffer == NULL) {\r
278 return EFI_INVALID_PARAMETER;\r
279 }\r
280\r
281 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
282 ASSERT (!FreePoolHdr->Header.Available);\r
283\r
284 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
285 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
286 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
287 return SmmFreePages (\r
288 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
289 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
290 );\r
291 }\r
292 return InternalFreePoolByIndex (FreePoolHdr);\r
293}\r