]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Pool.c
Fix K8 scan issues
[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 ASSERT (PoolIndex <= MAX_POOL_INDEX);
101 Status = EFI_SUCCESS;
102 if (PoolIndex == MAX_POOL_INDEX) {
103 Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1));
104 if (Hdr == NULL) {
105 return EFI_OUT_OF_RESOURCES;
106 }
107 } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {
108 Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);
109 RemoveEntryList (&Hdr->Link);
110 } else {
111 Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);
112 if (!EFI_ERROR (Status)) {
113 Hdr->Header.Size >>= 1;
114 Hdr->Header.Available = TRUE;
115 InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);
116 Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);
117 }
118 }
119
120 if (!EFI_ERROR (Status)) {
121 Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;
122 Hdr->Header.Available = FALSE;
123 }
124
125 *FreePoolHdr = Hdr;
126 return Status;
127 }
128
129 /**
130 Internal Function. Free a pool by specified PoolIndex.
131
132 @param FreePoolHdr The pool to free.
133
134 @retval EFI_SUCCESS Pool successfully freed.
135
136 **/
137 EFI_STATUS
138 InternalFreePoolByIndex (
139 IN FREE_POOL_HEADER *FreePoolHdr
140 )
141 {
142 UINTN PoolIndex;
143
144 ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);
145 ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);
146 ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);
147
148 PoolIndex = HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT;
149 FreePoolHdr->Header.Available = TRUE;
150 ASSERT (PoolIndex < MAX_POOL_INDEX);
151 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);
152 return EFI_SUCCESS;
153 }
154
155 /**
156 Allocate pool of a particular type.
157
158 @param PoolType Type of pool to allocate.
159 @param Size The amount of pool to allocate.
160 @param Buffer The address to return a pointer to the allocated
161 pool.
162
163 @retval EFI_INVALID_PARAMETER PoolType not valid.
164 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
165 @retval EFI_SUCCESS Pool successfully allocated.
166
167 **/
168 EFI_STATUS
169 EFIAPI
170 SmmAllocatePool (
171 IN EFI_MEMORY_TYPE PoolType,
172 IN UINTN Size,
173 OUT VOID **Buffer
174 )
175 {
176 POOL_HEADER *PoolHdr;
177 FREE_POOL_HEADER *FreePoolHdr;
178 EFI_STATUS Status;
179 EFI_PHYSICAL_ADDRESS Address;
180 UINTN PoolIndex;
181
182 if (PoolType != EfiRuntimeServicesCode &&
183 PoolType != EfiRuntimeServicesData) {
184 return EFI_INVALID_PARAMETER;
185 }
186
187 if (Size == 0) {
188 *Buffer = NULL;
189 return EFI_SUCCESS;
190 }
191
192 Size += sizeof (*PoolHdr);
193 if (Size > MAX_POOL_SIZE) {
194 Size = EFI_SIZE_TO_PAGES (Size);
195 Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
196 if (EFI_ERROR (Status)) {
197 return Status;
198 }
199
200 PoolHdr = (POOL_HEADER*)(UINTN)Address;
201 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
202 PoolHdr->Available = FALSE;
203 *Buffer = PoolHdr + 1;
204 return Status;
205 }
206
207 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
208 PoolIndex = HighBitSet32 ((UINT32)Size);
209 if ((Size & (Size - 1)) != 0) {
210 PoolIndex++;
211 }
212
213 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
214 *Buffer = &FreePoolHdr->Header + 1;
215 return Status;
216 }
217
218 /**
219 Frees pool.
220
221 @param Buffer The allocated pool entry to free.
222
223 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
224 @retval EFI_SUCCESS Pool successfully freed.
225
226 **/
227 EFI_STATUS
228 EFIAPI
229 SmmFreePool (
230 IN VOID *Buffer
231 )
232 {
233 FREE_POOL_HEADER *FreePoolHdr;
234
235 if (Buffer == NULL) {
236 return EFI_INVALID_PARAMETER;
237 }
238
239 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
240 ASSERT (!FreePoolHdr->Header.Available);
241
242 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
243 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
244 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
245 return SmmFreePages (
246 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
247 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
248 );
249 }
250 return InternalFreePoolByIndex (FreePoolHdr);
251 }