]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg: Fix typos in comments and variables
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
1 /** @file
2 SMM Memory pool management functions.
3
4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PiSmmCore.h"
16
17 LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX];
18 //
19 // To cache the SMRAM base since when Loading modules At fixed address feature is enabled,
20 // all module is assigned an offset relative the SMRAM base in build time.
21 //
22 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS gLoadModuleAtFixAddressSmramBase = 0;
23
24 /**
25 Called to initialize the memory service.
26
27 @param SmramRangeCount Number of SMRAM Regions
28 @param SmramRanges Pointer to SMRAM Descriptors
29
30 **/
31 VOID
32 SmmInitializeMemoryServices (
33 IN UINTN SmramRangeCount,
34 IN EFI_SMRAM_DESCRIPTOR *SmramRanges
35 )
36 {
37 UINTN Index;
38 UINT64 SmmCodeSize;
39 UINTN CurrentSmramRangesIndex;
40 UINT64 MaxSize;
41
42 //
43 // Initialize Pool list
44 //
45 for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {
46 InitializeListHead (&mSmmPoolLists[--Index]);
47 }
48 CurrentSmramRangesIndex = 0;
49 //
50 // If Loading Module At fixed Address feature is enabled, cache the SMRAM base here
51 //
52 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
53 //
54 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
55 //
56 SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
57
58 //
59 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
60 //
61 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {
62 //
63 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
64 //
65 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
66 continue;
67 }
68
69 if (SmramRanges[Index].CpuStart >= BASE_1MB) {
70 if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize - 1) <= MAX_ADDRESS) {
71 if (SmramRanges[Index].PhysicalSize >= MaxSize) {
72 MaxSize = SmramRanges[Index].PhysicalSize;
73 CurrentSmramRangesIndex = Index;
74 }
75 }
76 }
77 }
78 gLoadModuleAtFixAddressSmramBase = SmramRanges[CurrentSmramRangesIndex].CpuStart;
79
80 //
81 // cut out a memory range from this SMRAM range with the size SmmCodeSize to hold SMM driver code
82 // A notable thing is that SMM core is already loaded into this range.
83 //
84 SmramRanges[CurrentSmramRangesIndex].CpuStart = SmramRanges[CurrentSmramRangesIndex].CpuStart + SmmCodeSize;
85 SmramRanges[CurrentSmramRangesIndex].PhysicalSize = SmramRanges[CurrentSmramRangesIndex].PhysicalSize - SmmCodeSize;
86 }
87 //
88 // Initialize free SMRAM regions
89 //
90 for (Index = 0; Index < SmramRangeCount; Index++) {
91 SmmAddMemoryRegion (
92 SmramRanges[Index].CpuStart,
93 SmramRanges[Index].PhysicalSize,
94 EfiConventionalMemory,
95 SmramRanges[Index].RegionState
96 );
97 }
98
99 }
100
101 /**
102 Internal Function. Allocate a pool by specified PoolIndex.
103
104 @param PoolIndex Index which indicate the Pool size.
105 @param FreePoolHdr The returned Free pool.
106
107 @retval EFI_OUT_OF_RESOURCES Allocation failed.
108 @retval EFI_SUCCESS Pool successfully allocated.
109
110 **/
111 EFI_STATUS
112 InternalAllocPoolByIndex (
113 IN UINTN PoolIndex,
114 OUT FREE_POOL_HEADER **FreePoolHdr
115 )
116 {
117 EFI_STATUS Status;
118 FREE_POOL_HEADER *Hdr;
119 EFI_PHYSICAL_ADDRESS Address;
120
121 ASSERT (PoolIndex <= MAX_POOL_INDEX);
122 Status = EFI_SUCCESS;
123 Hdr = NULL;
124 if (PoolIndex == MAX_POOL_INDEX) {
125 Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);
126 if (EFI_ERROR (Status)) {
127 return EFI_OUT_OF_RESOURCES;
128 }
129 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
130 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {
131 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
132 RemoveEntryList (&Hdr->Link);
133 } else {
134 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
135 if (!EFI_ERROR (Status)) {
136 Hdr->Header.Size >>= 1;
137 Hdr->Header.Available = TRUE;
138 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);
139 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
140 }
141 }
142
143 if (!EFI_ERROR (Status)) {
144 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
145 Hdr->Header.Available = FALSE;
146 }
147
148 *FreePoolHdr = Hdr;
149 return Status;
150 }
151
152 /**
153 Internal Function. Free a pool by specified PoolIndex.
154
155 @param FreePoolHdr The pool to free.
156
157 @retval EFI_SUCCESS Pool successfully freed.
158
159 **/
160 EFI_STATUS
161 InternalFreePoolByIndex (
162 IN FREE_POOL_HEADER *FreePoolHdr
163 )
164 {
165 UINTN PoolIndex;
166
167 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
168 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
169 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
170
171 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
172 FreePoolHdr->Header.Available = TRUE;
173 ASSERT (PoolIndex < MAX_POOL_INDEX);
174 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);
175 return EFI_SUCCESS;
176 }
177
178 /**
179 Allocate pool of a particular type.
180
181 @param PoolType Type of pool to allocate.
182 @param Size The amount of pool to allocate.
183 @param Buffer The address to return a pointer to the allocated
184 pool.
185
186 @retval EFI_INVALID_PARAMETER PoolType not valid.
187 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
188 @retval EFI_SUCCESS Pool successfully allocated.
189
190 **/
191 EFI_STATUS
192 EFIAPI
193 SmmInternalAllocatePool (
194 IN EFI_MEMORY_TYPE PoolType,
195 IN UINTN Size,
196 OUT VOID **Buffer
197 )
198 {
199 POOL_HEADER *PoolHdr;
200 FREE_POOL_HEADER *FreePoolHdr;
201 EFI_STATUS Status;
202 EFI_PHYSICAL_ADDRESS Address;
203 UINTN PoolIndex;
204
205 if (PoolType != EfiRuntimeServicesCode &&
206 PoolType != EfiRuntimeServicesData) {
207 return EFI_INVALID_PARAMETER;
208 }
209
210 Size += sizeof (*PoolHdr);
211 if (Size > MAX_POOL_SIZE) {
212 Size = EFI_SIZE_TO_PAGES (Size);
213 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
214 if (EFI_ERROR (Status)) {
215 return Status;
216 }
217
218 PoolHdr = (POOL_HEADER*)(UINTN)Address;
219 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
220 PoolHdr->Available = FALSE;
221 *Buffer = PoolHdr + 1;
222 return Status;
223 }
224
225 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
226 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
227 if ((Size & (Size - 1)) != 0) {
228 PoolIndex++;
229 }
230
231 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
232 if (!EFI_ERROR(Status)) {
233 *Buffer = &FreePoolHdr->Header + 1;
234 }
235 return Status;
236 }
237
238 /**
239 Allocate pool of a particular type.
240
241 @param PoolType Type of pool to allocate.
242 @param Size The amount of pool to allocate.
243 @param Buffer The address to return a pointer to the allocated
244 pool.
245
246 @retval EFI_INVALID_PARAMETER PoolType not valid.
247 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
248 @retval EFI_SUCCESS Pool successfully allocated.
249
250 **/
251 EFI_STATUS
252 EFIAPI
253 SmmAllocatePool (
254 IN EFI_MEMORY_TYPE PoolType,
255 IN UINTN Size,
256 OUT VOID **Buffer
257 )
258 {
259 EFI_STATUS Status;
260
261 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
262 if (!EFI_ERROR (Status)) {
263 SmmCoreUpdateProfile (
264 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
265 MemoryProfileActionAllocatePool,
266 PoolType,
267 Size,
268 *Buffer,
269 NULL
270 );
271 }
272 return Status;
273 }
274
275 /**
276 Frees pool.
277
278 @param Buffer The allocated pool entry to free.
279
280 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
281 @retval EFI_SUCCESS Pool successfully freed.
282
283 **/
284 EFI_STATUS
285 EFIAPI
286 SmmInternalFreePool (
287 IN VOID *Buffer
288 )
289 {
290 FREE_POOL_HEADER *FreePoolHdr;
291
292 if (Buffer == NULL) {
293 return EFI_INVALID_PARAMETER;
294 }
295
296 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
297 ASSERT (!FreePoolHdr->Header.Available);
298
299 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
300 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
301 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
302 return SmmInternalFreePages (
303 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
304 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
305 );
306 }
307 return InternalFreePoolByIndex (FreePoolHdr);
308 }
309
310 /**
311 Frees pool.
312
313 @param Buffer The allocated pool entry to free.
314
315 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
316 @retval EFI_SUCCESS Pool successfully freed.
317
318 **/
319 EFI_STATUS
320 EFIAPI
321 SmmFreePool (
322 IN VOID *Buffer
323 )
324 {
325 EFI_STATUS Status;
326
327 Status = SmmInternalFreePool (Buffer);
328 if (!EFI_ERROR (Status)) {
329 SmmCoreUpdateProfile (
330 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
331 MemoryProfileActionFreePool,
332 EfiMaxMemoryType,
333 0,
334 Buffer,
335 NULL
336 );
337 }
338 return Status;
339 }