]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/PiSmmCore/Pool.c
Add EfiCpuArchProtocol dependency for PiSmmIpl module. The reason to add this is...
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Pool.c
CommitLineData
e42e9404 1/** @file\r
2 SMM Memory pool management functions.\r
3\r
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials are licensed and made available \r
6 under the terms and conditions of the BSD License which accompanies this \r
7 distribution. The full text of the license may be found at \r
8 http://opensource.org/licenses/bsd-license.php \r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
12\r
13**/\r
14\r
15#include "PiSmmCore.h"\r
16\r
17//\r
18// MIN_POOL_SHIFT must not be less than 5\r
19//\r
20#define MIN_POOL_SHIFT 6\r
21#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)\r
22\r
23//\r
24// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1\r
25//\r
26#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)\r
27#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)\r
28\r
29//\r
30// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes\r
31//\r
32#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)\r
33\r
34typedef struct {\r
35 UINTN Size;\r
36 BOOLEAN Available;\r
37} POOL_HEADER;\r
38\r
39typedef struct {\r
40 POOL_HEADER Header;\r
41 LIST_ENTRY Link;\r
42} FREE_POOL_HEADER;\r
43\r
44LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX];\r
45\r
46/**\r
47 Called to initialize the memory service.\r
48\r
49 @param SmramRangeCount Number of SMRAM Regions\r
50 @param SmramRanges Pointer to SMRAM Descriptors\r
51\r
52**/\r
53VOID\r
54SmmInitializeMemoryServices (\r
55 IN UINTN SmramRangeCount,\r
56 IN EFI_SMRAM_DESCRIPTOR *SmramRanges\r
57 )\r
58{\r
59 UINTN Index;\r
60\r
61 //\r
62 // Initialize Pool list\r
63 //\r
64 for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {\r
65 InitializeListHead (&mSmmPoolLists[--Index]);\r
66 }\r
67\r
68 //\r
69 // Initialize free SMRAM regions\r
70 //\r
71 for (Index = 0; Index < SmramRangeCount; Index++) {\r
72 SmmAddMemoryRegion (\r
73 SmramRanges[Index].CpuStart,\r
74 SmramRanges[Index].PhysicalSize,\r
75 EfiConventionalMemory,\r
76 SmramRanges[Index].RegionState\r
77 );\r
78 }\r
79}\r
80\r
81/**\r
82 Internal Function. Allocate a pool by specified PoolIndex.\r
83\r
84 @param PoolIndex Index which indicate the Pool size.\r
85 @param FreePoolHdr The returned Free pool.\r
86\r
87 @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
88 @retval EFI_SUCCESS Pool successfully allocated.\r
89\r
90**/\r
91EFI_STATUS\r
92InternalAllocPoolByIndex (\r
93 IN UINTN PoolIndex,\r
94 OUT FREE_POOL_HEADER **FreePoolHdr\r
95 )\r
96{\r
97 EFI_STATUS Status;\r
98 FREE_POOL_HEADER *Hdr;\r
99\r
100 Status = EFI_SUCCESS;\r
101 if (PoolIndex == MAX_POOL_INDEX) {\r
102 Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1));\r
103 if (Hdr == NULL) {\r
104 Status = EFI_OUT_OF_RESOURCES;\r
105 }\r
106 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
107 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
108 RemoveEntryList (&Hdr->Link);\r
109 } else {\r
110 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
111 if (!EFI_ERROR (Status)) {\r
112 Hdr->Header.Size >>= 1;\r
113 Hdr->Header.Available = TRUE;\r
114 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
115 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
116 }\r
117 }\r
118\r
119 if (!EFI_ERROR (Status)) {\r
120 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
121 Hdr->Header.Available = FALSE;\r
122 }\r
123\r
124 *FreePoolHdr = Hdr;\r
125 return Status;\r
126}\r
127\r
128/**\r
129 Internal Function. Free a pool by specified PoolIndex.\r
130\r
131 @param FreePoolHdr The pool to free.\r
132\r
133 @retval EFI_SUCCESS Pool successfully freed.\r
134\r
135**/\r
136EFI_STATUS\r
137InternalFreePoolByIndex (\r
138 IN FREE_POOL_HEADER *FreePoolHdr\r
139 )\r
140{\r
141 UINTN PoolIndex;\r
142\r
143 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
144 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
145 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
146\r
147 PoolIndex = HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT;\r
148 FreePoolHdr->Header.Available = TRUE;\r
149 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
150 return EFI_SUCCESS;\r
151}\r
152\r
153/**\r
154 Allocate pool of a particular type.\r
155\r
156 @param PoolType Type of pool to allocate.\r
157 @param Size The amount of pool to allocate.\r
158 @param Buffer The address to return a pointer to the allocated\r
159 pool.\r
160\r
161 @retval EFI_INVALID_PARAMETER PoolType not valid.\r
162 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
163 @retval EFI_SUCCESS Pool successfully allocated.\r
164\r
165**/\r
166EFI_STATUS\r
167EFIAPI\r
168SmmAllocatePool (\r
169 IN EFI_MEMORY_TYPE PoolType,\r
170 IN UINTN Size,\r
171 OUT VOID **Buffer\r
172 )\r
173{\r
174 POOL_HEADER *PoolHdr;\r
175 FREE_POOL_HEADER *FreePoolHdr;\r
176 EFI_STATUS Status;\r
177 EFI_PHYSICAL_ADDRESS Address;\r
178 UINTN PoolIndex;\r
179\r
180 if (PoolType != EfiRuntimeServicesCode &&\r
181 PoolType != EfiRuntimeServicesData) {\r
182 return EFI_INVALID_PARAMETER;\r
183 }\r
184\r
185 if (Size == 0) {\r
186 *Buffer = NULL;\r
187 return EFI_SUCCESS;\r
188 }\r
189\r
190 Size += sizeof (*PoolHdr);\r
191 if (Size > MAX_POOL_SIZE) {\r
192 Size = EFI_SIZE_TO_PAGES (Size);\r
193 Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
194 if (EFI_ERROR (Status)) {\r
195 return Status;\r
196 }\r
197\r
198 PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
199 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
200 PoolHdr->Available = FALSE;\r
201 *Buffer = PoolHdr + 1;\r
202 return Status;\r
203 }\r
204\r
205 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
206 PoolIndex = HighBitSet32 ((UINT32)Size);\r
207 if ((Size & (Size - 1)) != 0) {\r
208 PoolIndex++;\r
209 }\r
210\r
211 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
212 *Buffer = &FreePoolHdr->Header + 1;\r
213 return Status;\r
214}\r
215\r
216/**\r
217 Frees pool.\r
218\r
219 @param Buffer The allocated pool entry to free.\r
220\r
221 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
222 @retval EFI_SUCCESS Pool successfully freed.\r
223\r
224**/\r
225EFI_STATUS\r
226EFIAPI\r
227SmmFreePool (\r
228 IN VOID *Buffer\r
229 )\r
230{\r
231 FREE_POOL_HEADER *FreePoolHdr;\r
232\r
233 if (Buffer == NULL) {\r
234 return EFI_INVALID_PARAMETER;\r
235 }\r
236\r
237 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
238 ASSERT (!FreePoolHdr->Header.Available);\r
239\r
240 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
241 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
242 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
243 return SmmFreePages (\r
244 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
245 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
246 );\r
247 }\r
248 return InternalFreePoolByIndex (FreePoolHdr);\r
249}\r