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