]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Pool.c
MdeModulePkg PiSmmCore: Update comments in InitializeMemoryServices
[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 = ARRAY_SIZE (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 // Add Free SMRAM regions
89 // Need add Free memory at first, to let gSmmMemoryMap record data
90 //
91 for (Index = 0; Index < SmramRangeCount; Index++) {
92 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
93 continue;
94 }
95 SmmAddMemoryRegion (
96 SmramRanges[Index].CpuStart,
97 SmramRanges[Index].PhysicalSize,
98 EfiConventionalMemory,
99 SmramRanges[Index].RegionState
100 );
101 }
102
103 //
104 // Add the allocated SMRAM regions
105 //
106 for (Index = 0; Index < SmramRangeCount; Index++) {
107 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {
108 continue;
109 }
110 SmmAddMemoryRegion (
111 SmramRanges[Index].CpuStart,
112 SmramRanges[Index].PhysicalSize,
113 EfiConventionalMemory,
114 SmramRanges[Index].RegionState
115 );
116 }
117
118 }
119
120 /**
121 Internal Function. Allocate a pool by specified PoolIndex.
122
123 @param PoolIndex Index which indicate the Pool size.
124 @param FreePoolHdr The returned Free pool.
125
126 @retval EFI_OUT_OF_RESOURCES Allocation failed.
127 @retval EFI_SUCCESS Pool successfully allocated.
128
129 **/
130 EFI_STATUS
131 InternalAllocPoolByIndex (
132 IN UINTN PoolIndex,
133 OUT FREE_POOL_HEADER **FreePoolHdr
134 )
135 {
136 EFI_STATUS Status;
137 FREE_POOL_HEADER *Hdr;
138 EFI_PHYSICAL_ADDRESS Address;
139
140 ASSERT (PoolIndex <= MAX_POOL_INDEX);
141 Status = EFI_SUCCESS;
142 Hdr = NULL;
143 if (PoolIndex == MAX_POOL_INDEX) {
144 Status = SmmInternalAllocatePages (AllocateAnyPages, EfiRuntimeServicesData, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);
145 if (EFI_ERROR (Status)) {
146 return EFI_OUT_OF_RESOURCES;
147 }
148 Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
149 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {
150 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
151 RemoveEntryList (&Hdr->Link);
152 } else {
153 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
154 if (!EFI_ERROR (Status)) {
155 Hdr->Header.Size >>= 1;
156 Hdr->Header.Available = TRUE;
157 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);
158 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
159 }
160 }
161
162 if (!EFI_ERROR (Status)) {
163 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
164 Hdr->Header.Available = FALSE;
165 }
166
167 *FreePoolHdr = Hdr;
168 return Status;
169 }
170
171 /**
172 Internal Function. Free a pool by specified PoolIndex.
173
174 @param FreePoolHdr The pool to free.
175
176 @retval EFI_SUCCESS Pool successfully freed.
177
178 **/
179 EFI_STATUS
180 InternalFreePoolByIndex (
181 IN FREE_POOL_HEADER *FreePoolHdr
182 )
183 {
184 UINTN PoolIndex;
185
186 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
187 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
188 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
189
190 PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
191 FreePoolHdr->Header.Available = TRUE;
192 ASSERT (PoolIndex < MAX_POOL_INDEX);
193 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);
194 return EFI_SUCCESS;
195 }
196
197 /**
198 Allocate pool of a particular type.
199
200 @param PoolType Type of pool to allocate.
201 @param Size The amount of pool to allocate.
202 @param Buffer The address to return a pointer to the allocated
203 pool.
204
205 @retval EFI_INVALID_PARAMETER PoolType not valid.
206 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
207 @retval EFI_SUCCESS Pool successfully allocated.
208
209 **/
210 EFI_STATUS
211 EFIAPI
212 SmmInternalAllocatePool (
213 IN EFI_MEMORY_TYPE PoolType,
214 IN UINTN Size,
215 OUT VOID **Buffer
216 )
217 {
218 POOL_HEADER *PoolHdr;
219 FREE_POOL_HEADER *FreePoolHdr;
220 EFI_STATUS Status;
221 EFI_PHYSICAL_ADDRESS Address;
222 UINTN PoolIndex;
223
224 if (PoolType != EfiRuntimeServicesCode &&
225 PoolType != EfiRuntimeServicesData) {
226 return EFI_INVALID_PARAMETER;
227 }
228
229 Size += sizeof (*PoolHdr);
230 if (Size > MAX_POOL_SIZE) {
231 Size = EFI_SIZE_TO_PAGES (Size);
232 Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
233 if (EFI_ERROR (Status)) {
234 return Status;
235 }
236
237 PoolHdr = (POOL_HEADER*)(UINTN)Address;
238 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
239 PoolHdr->Available = FALSE;
240 *Buffer = PoolHdr + 1;
241 return Status;
242 }
243
244 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
245 PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
246 if ((Size & (Size - 1)) != 0) {
247 PoolIndex++;
248 }
249
250 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
251 if (!EFI_ERROR(Status)) {
252 *Buffer = &FreePoolHdr->Header + 1;
253 }
254 return Status;
255 }
256
257 /**
258 Allocate pool of a particular type.
259
260 @param PoolType Type of pool to allocate.
261 @param Size The amount of pool to allocate.
262 @param Buffer The address to return a pointer to the allocated
263 pool.
264
265 @retval EFI_INVALID_PARAMETER PoolType not valid.
266 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
267 @retval EFI_SUCCESS Pool successfully allocated.
268
269 **/
270 EFI_STATUS
271 EFIAPI
272 SmmAllocatePool (
273 IN EFI_MEMORY_TYPE PoolType,
274 IN UINTN Size,
275 OUT VOID **Buffer
276 )
277 {
278 EFI_STATUS Status;
279
280 Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
281 if (!EFI_ERROR (Status)) {
282 SmmCoreUpdateProfile (
283 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
284 MemoryProfileActionAllocatePool,
285 PoolType,
286 Size,
287 *Buffer,
288 NULL
289 );
290 }
291 return Status;
292 }
293
294 /**
295 Frees pool.
296
297 @param Buffer The allocated pool entry to free.
298
299 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
300 @retval EFI_SUCCESS Pool successfully freed.
301
302 **/
303 EFI_STATUS
304 EFIAPI
305 SmmInternalFreePool (
306 IN VOID *Buffer
307 )
308 {
309 FREE_POOL_HEADER *FreePoolHdr;
310
311 if (Buffer == NULL) {
312 return EFI_INVALID_PARAMETER;
313 }
314
315 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
316 ASSERT (!FreePoolHdr->Header.Available);
317
318 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
319 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
320 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
321 return SmmInternalFreePages (
322 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
323 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
324 );
325 }
326 return InternalFreePoolByIndex (FreePoolHdr);
327 }
328
329 /**
330 Frees pool.
331
332 @param Buffer The allocated pool entry to free.
333
334 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
335 @retval EFI_SUCCESS Pool successfully freed.
336
337 **/
338 EFI_STATUS
339 EFIAPI
340 SmmFreePool (
341 IN VOID *Buffer
342 )
343 {
344 EFI_STATUS Status;
345
346 Status = SmmInternalFreePool (Buffer);
347 if (!EFI_ERROR (Status)) {
348 SmmCoreUpdateProfile (
349 (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
350 MemoryProfileActionFreePool,
351 EfiMaxMemoryType,
352 0,
353 Buffer,
354 NULL
355 );
356 }
357 return Status;
358 }