]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Pool.c
Update PI SMM Core to ignore memory ranges from SMRAM Descriptors that are already...
[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 return 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 ASSERT (PoolIndex < MAX_POOL_INDEX);
150 InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);
151 return EFI_SUCCESS;
152 }
153
154 /**
155 Allocate pool of a particular type.
156
157 @param PoolType Type of pool to allocate.
158 @param Size The amount of pool to allocate.
159 @param Buffer The address to return a pointer to the allocated
160 pool.
161
162 @retval EFI_INVALID_PARAMETER PoolType not valid.
163 @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.
164 @retval EFI_SUCCESS Pool successfully allocated.
165
166 **/
167 EFI_STATUS
168 EFIAPI
169 SmmAllocatePool (
170 IN EFI_MEMORY_TYPE PoolType,
171 IN UINTN Size,
172 OUT VOID **Buffer
173 )
174 {
175 POOL_HEADER *PoolHdr;
176 FREE_POOL_HEADER *FreePoolHdr;
177 EFI_STATUS Status;
178 EFI_PHYSICAL_ADDRESS Address;
179 UINTN PoolIndex;
180
181 if (PoolType != EfiRuntimeServicesCode &&
182 PoolType != EfiRuntimeServicesData) {
183 return EFI_INVALID_PARAMETER;
184 }
185
186 if (Size == 0) {
187 *Buffer = NULL;
188 return EFI_SUCCESS;
189 }
190
191 Size += sizeof (*PoolHdr);
192 if (Size > MAX_POOL_SIZE) {
193 Size = EFI_SIZE_TO_PAGES (Size);
194 Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);
195 if (EFI_ERROR (Status)) {
196 return Status;
197 }
198
199 PoolHdr = (POOL_HEADER*)(UINTN)Address;
200 PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);
201 PoolHdr->Available = FALSE;
202 *Buffer = PoolHdr + 1;
203 return Status;
204 }
205
206 Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;
207 PoolIndex = HighBitSet32 ((UINT32)Size);
208 if ((Size & (Size - 1)) != 0) {
209 PoolIndex++;
210 }
211
212 Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);
213 *Buffer = &FreePoolHdr->Header + 1;
214 return Status;
215 }
216
217 /**
218 Frees pool.
219
220 @param Buffer The allocated pool entry to free.
221
222 @retval EFI_INVALID_PARAMETER Buffer is not a valid value.
223 @retval EFI_SUCCESS Pool successfully freed.
224
225 **/
226 EFI_STATUS
227 EFIAPI
228 SmmFreePool (
229 IN VOID *Buffer
230 )
231 {
232 FREE_POOL_HEADER *FreePoolHdr;
233
234 if (Buffer == NULL) {
235 return EFI_INVALID_PARAMETER;
236 }
237
238 FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);
239 ASSERT (!FreePoolHdr->Header.Available);
240
241 if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {
242 ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);
243 ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);
244 return SmmFreePages (
245 (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,
246 EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)
247 );
248 }
249 return InternalFreePoolByIndex (FreePoolHdr);
250 }