1 /** @file
2   SMM Memory pool management functions.
3 
4   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5   Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "StandaloneMmCore.h"
11 
12 LIST_ENTRY  mMmPoolLists[MAX_POOL_INDEX];
13 //
14 // To cache the MMRAM base since when Loading modules At fixed address feature is enabled,
15 // all module is assigned an offset relative the MMRAM base in build time.
16 //
17 GLOBAL_REMOVE_IF_UNREFERENCED  EFI_PHYSICAL_ADDRESS       gLoadModuleAtFixAddressMmramBase = 0;
18 
19 /**
20   Called to initialize the memory service.
21 
22   @param   MmramRangeCount       Number of MMRAM Regions
23   @param   MmramRanges           Pointer to MMRAM Descriptors
24 
25 **/
26 VOID
MmInitializeMemoryServices(IN UINTN MmramRangeCount,IN EFI_MMRAM_DESCRIPTOR * MmramRanges)27 MmInitializeMemoryServices (
28   IN UINTN                 MmramRangeCount,
29   IN EFI_MMRAM_DESCRIPTOR  *MmramRanges
30   )
31 {
32   UINTN                  Index;
33 
34   //
35   // Initialize Pool list
36   //
37   for (Index = sizeof (mMmPoolLists) / sizeof (*mMmPoolLists); Index > 0;) {
38     InitializeListHead (&mMmPoolLists[--Index]);
39   }
40 
41 
42   //
43   // Initialize free MMRAM regions
44   //
45   for (Index = 0; Index < MmramRangeCount; Index++) {
46     //
47     // BUGBUG: Add legacy MMRAM region is buggy.
48     //
49     if (MmramRanges[Index].CpuStart < BASE_1MB) {
50       continue;
51     }
52     DEBUG ((DEBUG_INFO, "MmAddMemoryRegion %d : 0x%016lx - 0x%016lx\n",
53 	    Index, MmramRanges[Index].CpuStart, MmramRanges[Index].PhysicalSize));
54     MmAddMemoryRegion (
55       MmramRanges[Index].CpuStart,
56       MmramRanges[Index].PhysicalSize,
57       EfiConventionalMemory,
58       MmramRanges[Index].RegionState
59       );
60   }
61 
62 }
63 
64 /**
65   Internal Function. Allocate a pool by specified PoolIndex.
66 
67   @param  PoolIndex             Index which indicate the Pool size.
68   @param  FreePoolHdr           The returned Free pool.
69 
70   @retval EFI_OUT_OF_RESOURCES   Allocation failed.
71   @retval EFI_SUCCESS            Pool successfully allocated.
72 
73 **/
74 EFI_STATUS
InternalAllocPoolByIndex(IN UINTN PoolIndex,OUT FREE_POOL_HEADER ** FreePoolHdr)75 InternalAllocPoolByIndex (
76   IN  UINTN             PoolIndex,
77   OUT FREE_POOL_HEADER  **FreePoolHdr
78   )
79 {
80   EFI_STATUS            Status;
81   FREE_POOL_HEADER      *Hdr;
82   EFI_PHYSICAL_ADDRESS  Address;
83 
84   ASSERT (PoolIndex <= MAX_POOL_INDEX);
85   Status = EFI_SUCCESS;
86   Hdr = NULL;
87   if (PoolIndex == MAX_POOL_INDEX) {
88     Status = MmInternalAllocatePages (
89 	             AllocateAnyPages,
90                EfiRuntimeServicesData,
91                EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1),
92                &Address
93                );
94     if (EFI_ERROR (Status)) {
95       return EFI_OUT_OF_RESOURCES;
96     }
97     Hdr = (FREE_POOL_HEADER *) (UINTN) Address;
98   } else if (!IsListEmpty (&mMmPoolLists[PoolIndex])) {
99     Hdr = BASE_CR (GetFirstNode (&mMmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
100     RemoveEntryList (&Hdr->Link);
101   } else {
102     Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
103     if (!EFI_ERROR (Status)) {
104       Hdr->Header.Size >>= 1;
105       Hdr->Header.Available = TRUE;
106       InsertHeadList (&mMmPoolLists[PoolIndex], &Hdr->Link);
107       Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
108     }
109   }
110 
111   if (!EFI_ERROR (Status)) {
112     Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
113     Hdr->Header.Available = FALSE;
114   }
115 
116   *FreePoolHdr = Hdr;
117   return Status;
118 }
119 
120 /**
121   Internal Function. Free a pool by specified PoolIndex.
122 
123   @param  FreePoolHdr           The pool to free.
124 
125   @retval EFI_SUCCESS           Pool successfully freed.
126 
127 **/
128 EFI_STATUS
InternalFreePoolByIndex(IN FREE_POOL_HEADER * FreePoolHdr)129 InternalFreePoolByIndex (
130   IN FREE_POOL_HEADER  *FreePoolHdr
131   )
132 {
133   UINTN  PoolIndex;
134 
135   ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
136   ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
137   ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
138 
139   PoolIndex = (UINTN) (HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT);
140   FreePoolHdr->Header.Available = TRUE;
141   ASSERT (PoolIndex < MAX_POOL_INDEX);
142   InsertHeadList (&mMmPoolLists[PoolIndex], &FreePoolHdr->Link);
143   return EFI_SUCCESS;
144 }
145 
146 /**
147   Allocate pool of a particular type.
148 
149   @param  PoolType               Type of pool to allocate.
150   @param  Size                   The amount of pool to allocate.
151   @param  Buffer                 The address to return a pointer to the allocated
152                                  pool.
153 
154   @retval EFI_INVALID_PARAMETER  PoolType not valid.
155   @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.
156   @retval EFI_SUCCESS            Pool successfully allocated.
157 
158 **/
159 EFI_STATUS
160 EFIAPI
MmInternalAllocatePool(IN EFI_MEMORY_TYPE PoolType,IN UINTN Size,OUT VOID ** Buffer)161 MmInternalAllocatePool (
162   IN   EFI_MEMORY_TYPE  PoolType,
163   IN   UINTN            Size,
164   OUT  VOID             **Buffer
165   )
166 {
167   POOL_HEADER           *PoolHdr;
168   FREE_POOL_HEADER      *FreePoolHdr;
169   EFI_STATUS            Status;
170   EFI_PHYSICAL_ADDRESS  Address;
171   UINTN                 PoolIndex;
172 
173   if (PoolType != EfiRuntimeServicesCode &&
174       PoolType != EfiRuntimeServicesData) {
175     return EFI_INVALID_PARAMETER;
176   }
177 
178   Size += sizeof (*PoolHdr);
179   if (Size > MAX_POOL_SIZE) {
180     Size = EFI_SIZE_TO_PAGES (Size);
181     Status = MmInternalAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
182     if (EFI_ERROR (Status)) {
183       return Status;
184     }
185 
186     PoolHdr = (POOL_HEADER*)(UINTN)Address;
187     PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
188     PoolHdr->Available = FALSE;
189     *Buffer = PoolHdr + 1;
190     return Status;
191   }
192 
193   Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
194   PoolIndex = (UINTN) HighBitSet32 ((UINT32)Size);
195   if ((Size & (Size - 1)) != 0) {
196     PoolIndex++;
197   }
198 
199   Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
200   if (!EFI_ERROR (Status)) {
201     *Buffer = &FreePoolHdr->Header + 1;
202   }
203   return Status;
204 }
205 
206 /**
207   Allocate pool of a particular type.
208 
209   @param  PoolType               Type of pool to allocate.
210   @param  Size                   The amount of pool to allocate.
211   @param  Buffer                 The address to return a pointer to the allocated
212                                  pool.
213 
214   @retval EFI_INVALID_PARAMETER  PoolType not valid.
215   @retval EFI_OUT_OF_RESOURCES   Size exceeds max pool size or allocation failed.
216   @retval EFI_SUCCESS            Pool successfully allocated.
217 
218 **/
219 EFI_STATUS
220 EFIAPI
MmAllocatePool(IN EFI_MEMORY_TYPE PoolType,IN UINTN Size,OUT VOID ** Buffer)221 MmAllocatePool (
222   IN   EFI_MEMORY_TYPE  PoolType,
223   IN   UINTN            Size,
224   OUT  VOID             **Buffer
225   )
226 {
227   EFI_STATUS  Status;
228 
229   Status = MmInternalAllocatePool (PoolType, Size, Buffer);
230   return Status;
231 }
232 
233 /**
234   Frees pool.
235 
236   @param  Buffer                 The allocated pool entry to free.
237 
238   @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.
239   @retval EFI_SUCCESS            Pool successfully freed.
240 
241 **/
242 EFI_STATUS
243 EFIAPI
MmInternalFreePool(IN VOID * Buffer)244 MmInternalFreePool (
245   IN VOID  *Buffer
246   )
247 {
248   FREE_POOL_HEADER  *FreePoolHdr;
249 
250   if (Buffer == NULL) {
251     return EFI_INVALID_PARAMETER;
252   }
253 
254   FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
255   ASSERT (!FreePoolHdr->Header.Available);
256 
257   if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
258     ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
259     ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
260     return MmInternalFreePages (
261              (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
262              EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
263              );
264   }
265   return InternalFreePoolByIndex (FreePoolHdr);
266 }
267 
268 /**
269   Frees pool.
270 
271   @param  Buffer                 The allocated pool entry to free.
272 
273   @retval EFI_INVALID_PARAMETER  Buffer is not a valid value.
274   @retval EFI_SUCCESS            Pool successfully freed.
275 
276 **/
277 EFI_STATUS
278 EFIAPI
MmFreePool(IN VOID * Buffer)279 MmFreePool (
280   IN VOID  *Buffer
281   )
282 {
283   EFI_STATUS  Status;
284 
285   Status = MmInternalFreePool (Buffer);
286   return Status;
287 }
288