• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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[SmmPoolTypeMax][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   Convert a UEFI memory type to SMM pool type.
26 
27   @param[in]  MemoryType              Type of pool to allocate.
28 
29   @return SMM pool type
30 **/
31 SMM_POOL_TYPE
UefiMemoryTypeToSmmPoolType(IN EFI_MEMORY_TYPE MemoryType)32 UefiMemoryTypeToSmmPoolType (
33   IN  EFI_MEMORY_TYPE   MemoryType
34   )
35 {
36   ASSERT ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData));
37   switch (MemoryType) {
38   case EfiRuntimeServicesCode:
39     return SmmPoolTypeCode;
40   case EfiRuntimeServicesData:
41     return SmmPoolTypeData;
42   default:
43     return SmmPoolTypeMax;
44   }
45 }
46 
47 
48 /**
49   Called to initialize the memory service.
50 
51   @param   SmramRangeCount       Number of SMRAM Regions
52   @param   SmramRanges           Pointer to SMRAM Descriptors
53 
54 **/
55 VOID
SmmInitializeMemoryServices(IN UINTN SmramRangeCount,IN EFI_SMRAM_DESCRIPTOR * SmramRanges)56 SmmInitializeMemoryServices (
57   IN UINTN                 SmramRangeCount,
58   IN EFI_SMRAM_DESCRIPTOR  *SmramRanges
59   )
60 {
61   UINTN                  Index;
62   EFI_STATUS             Status;
63   UINTN                  SmmPoolTypeIndex;
64   EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;
65 
66   //
67   // Initialize Pool list
68   //
69   for (SmmPoolTypeIndex = 0; SmmPoolTypeIndex < SmmPoolTypeMax; SmmPoolTypeIndex++) {
70     for (Index = 0; Index < ARRAY_SIZE (mSmmPoolLists[SmmPoolTypeIndex]); Index++) {
71       InitializeListHead (&mSmmPoolLists[SmmPoolTypeIndex][Index]);
72     }
73   }
74 
75   Status = EfiGetSystemConfigurationTable (
76             &gLoadFixedAddressConfigurationTableGuid,
77            (VOID **) &LMFAConfigurationTable
78            );
79   if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {
80     gLoadModuleAtFixAddressSmramBase = LMFAConfigurationTable->SmramBase;
81   }
82 
83   //
84   // Add Free SMRAM regions
85   // Need add Free memory at first, to let gSmmMemoryMap record data
86   //
87   for (Index = 0; Index < SmramRangeCount; Index++) {
88     if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
89       continue;
90     }
91     SmmAddMemoryRegion (
92       SmramRanges[Index].CpuStart,
93       SmramRanges[Index].PhysicalSize,
94       EfiConventionalMemory,
95       SmramRanges[Index].RegionState
96       );
97   }
98 
99   //
100   // Add the allocated SMRAM regions
101   //
102   for (Index = 0; Index < SmramRangeCount; Index++) {
103     if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) == 0) {
104       continue;
105     }
106     SmmAddMemoryRegion (
107       SmramRanges[Index].CpuStart,
108       SmramRanges[Index].PhysicalSize,
109       EfiConventionalMemory,
110       SmramRanges[Index].RegionState
111       );
112   }
113 
114 }
115 
116 /**
117   Internal Function. Allocate a pool by specified PoolIndex.
118 
119   @param  PoolType              Type of pool to allocate.
120   @param  PoolIndex             Index which indicate the Pool size.
121   @param  FreePoolHdr           The returned Free pool.
122 
123   @retval EFI_OUT_OF_RESOURCES   Allocation failed.
124   @retval EFI_SUCCESS            Pool successfully allocated.
125 
126 **/
127 EFI_STATUS
InternalAllocPoolByIndex(IN EFI_MEMORY_TYPE PoolType,IN UINTN PoolIndex,OUT FREE_POOL_HEADER ** FreePoolHdr)128 InternalAllocPoolByIndex (
129   IN  EFI_MEMORY_TYPE   PoolType,
130   IN  UINTN             PoolIndex,
131   OUT FREE_POOL_HEADER  **FreePoolHdr
132   )
133 {
134   EFI_STATUS            Status;
135   FREE_POOL_HEADER      *Hdr;
136   EFI_PHYSICAL_ADDRESS  Address;
137   SMM_POOL_TYPE         SmmPoolType;
138 
139   SmmPoolType = UefiMemoryTypeToSmmPoolType(PoolType);
140 
141   ASSERT (PoolIndex <= MAX_POOL_INDEX);
142   Status = EFI_SUCCESS;
143   Hdr = NULL;
144   if (PoolIndex == MAX_POOL_INDEX) {
145     Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1), &Address);
146     if (EFI_ERROR (Status)) {
147       return EFI_OUT_OF_RESOURCES;
148     }
149     Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
150   } else if (!IsListEmpty (&mSmmPoolLists[SmmPoolType][PoolIndex])) {
151     Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[SmmPoolType][PoolIndex]), FREE_POOL_HEADER, Link);
152     RemoveEntryList (&Hdr->Link);
153   } else {
154     Status = InternalAllocPoolByIndex (PoolType, PoolIndex + 1, &Hdr);
155     if (!EFI_ERROR (Status)) {
156       Hdr->Header.Size >>= 1;
157       Hdr->Header.Available = TRUE;
158       Hdr->Header.Type = PoolType;
159       InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &Hdr->Link);
160       Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
161     }
162   }
163 
164   if (!EFI_ERROR (Status)) {
165     Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
166     Hdr->Header.Available = FALSE;
167     Hdr->Header.Type = PoolType;
168   }
169 
170   *FreePoolHdr = Hdr;
171   return Status;
172 }
173 
174 /**
175   Internal Function. Free a pool by specified PoolIndex.
176 
177   @param  FreePoolHdr           The pool to free.
178 
179   @retval EFI_SUCCESS           Pool successfully freed.
180 
181 **/
182 EFI_STATUS
InternalFreePoolByIndex(IN FREE_POOL_HEADER * FreePoolHdr)183 InternalFreePoolByIndex (
184   IN FREE_POOL_HEADER  *FreePoolHdr
185   )
186 {
187   UINTN                 PoolIndex;
188   SMM_POOL_TYPE         SmmPoolType;
189 
190   ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
191   ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
192   ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
193 
194   SmmPoolType = UefiMemoryTypeToSmmPoolType(FreePoolHdr->Header.Type);
195 
196   PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
197   FreePoolHdr->Header.Available = TRUE;
198   ASSERT (PoolIndex < MAX_POOL_INDEX);
199   InsertHeadList (&mSmmPoolLists[SmmPoolType][PoolIndex], &FreePoolHdr->Link);
200   return EFI_SUCCESS;
201 }
202 
203 /**
204   Allocate pool of a particular type.
205 
206   @param  PoolType               Type of pool to allocate.
207   @param  Size                   The amount of pool to allocate.
208   @param  Buffer                 The address to return a pointer to the allocated
209                                  pool.
210 
211   @retval EFI_INVALID_PARAMETER  PoolType not valid.
212   @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.
213   @retval EFI_SUCCESS            Pool successfully allocated.
214 
215 **/
216 EFI_STATUS
217 EFIAPI
SmmInternalAllocatePool(IN EFI_MEMORY_TYPE PoolType,IN UINTN Size,OUT VOID ** Buffer)218 SmmInternalAllocatePool (
219   IN   EFI_MEMORY_TYPE  PoolType,
220   IN   UINTN            Size,
221   OUT  VOID             **Buffer
222   )
223 {
224   POOL_HEADER           *PoolHdr;
225   FREE_POOL_HEADER      *FreePoolHdr;
226   EFI_STATUS            Status;
227   EFI_PHYSICAL_ADDRESS  Address;
228   UINTN                 PoolIndex;
229 
230   if (PoolType != EfiRuntimeServicesCode &&
231       PoolType != EfiRuntimeServicesData) {
232     return EFI_INVALID_PARAMETER;
233   }
234 
235   Size += sizeof (*PoolHdr);
236   if (Size > MAX_POOL_SIZE) {
237     Size = EFI_SIZE_TO_PAGES (Size);
238     Status = SmmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
239     if (EFI_ERROR (Status)) {
240       return Status;
241     }
242 
243     PoolHdr = (POOL_HEADER*)(UINTN)Address;
244     PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
245     PoolHdr->Available = FALSE;
246     PoolHdr->Type = PoolType;
247     *Buffer = PoolHdr + 1;
248     return Status;
249   }
250 
251   Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
252   PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
253   if ((Size & (Size - 1)) != 0) {
254     PoolIndex++;
255   }
256 
257   Status = InternalAllocPoolByIndex (PoolType, PoolIndex, &FreePoolHdr);
258   if (!EFI_ERROR(Status)) {
259     *Buffer = &FreePoolHdr->Header + 1;
260   }
261   return Status;
262 }
263 
264 /**
265   Allocate pool of a particular type.
266 
267   @param  PoolType               Type of pool to allocate.
268   @param  Size                   The amount of pool to allocate.
269   @param  Buffer                 The address to return a pointer to the allocated
270                                  pool.
271 
272   @retval EFI_INVALID_PARAMETER  PoolType not valid.
273   @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.
274   @retval EFI_SUCCESS            Pool successfully allocated.
275 
276 **/
277 EFI_STATUS
278 EFIAPI
SmmAllocatePool(IN EFI_MEMORY_TYPE PoolType,IN UINTN Size,OUT VOID ** Buffer)279 SmmAllocatePool (
280   IN   EFI_MEMORY_TYPE  PoolType,
281   IN   UINTN            Size,
282   OUT  VOID             **Buffer
283   )
284 {
285   EFI_STATUS  Status;
286 
287   Status = SmmInternalAllocatePool (PoolType, Size, Buffer);
288   if (!EFI_ERROR (Status)) {
289     SmmCoreUpdateProfile (
290       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
291       MemoryProfileActionAllocatePool,
292       PoolType,
293       Size,
294       *Buffer,
295       NULL
296       );
297   }
298   return Status;
299 }
300 
301 /**
302   Frees pool.
303 
304   @param  Buffer                 The allocated pool entry to free.
305 
306   @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.
307   @retval EFI_SUCCESS            Pool successfully freed.
308 
309 **/
310 EFI_STATUS
311 EFIAPI
SmmInternalFreePool(IN VOID * Buffer)312 SmmInternalFreePool (
313   IN VOID  *Buffer
314   )
315 {
316   FREE_POOL_HEADER  *FreePoolHdr;
317 
318   if (Buffer == NULL) {
319     return EFI_INVALID_PARAMETER;
320   }
321 
322   FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
323   ASSERT (!FreePoolHdr->Header.Available);
324 
325   if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
326     ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
327     ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
328     return SmmInternalFreePages (
329              (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
330              EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
331              );
332   }
333   return InternalFreePoolByIndex (FreePoolHdr);
334 }
335 
336 /**
337   Frees pool.
338 
339   @param  Buffer                 The allocated pool entry to free.
340 
341   @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.
342   @retval EFI_SUCCESS            Pool successfully freed.
343 
344 **/
345 EFI_STATUS
346 EFIAPI
SmmFreePool(IN VOID * Buffer)347 SmmFreePool (
348   IN VOID  *Buffer
349   )
350 {
351   EFI_STATUS  Status;
352 
353   Status = SmmInternalFreePool (Buffer);
354   if (!EFI_ERROR (Status)) {
355     SmmCoreUpdateProfile (
356       (EFI_PHYSICAL_ADDRESS) (UINTN) RETURN_ADDRESS (0),
357       MemoryProfileActionFreePool,
358       EfiMaxMemoryType,
359       0,
360       Buffer,
361       NULL
362       );
363   }
364   return Status;
365 }
366