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