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