]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / SdBlockIoPei / SdHcMem.c
CommitLineData
48555339
FT
1/** @file\r
2\r
77af8668 3Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
48555339 4\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
48555339
FT
6\r
7**/\r
8\r
9#include "SdBlockIoPei.h"\r
10\r
11/**\r
12 Allocate a block of memory to be used by the buffer pool.\r
13\r
14 @param Pages How many pages to allocate.\r
15\r
16 @return The allocated memory block or NULL if failed.\r
17\r
18**/\r
19SD_PEIM_MEM_BLOCK *\r
20SdPeimAllocMemBlock (\r
1436aea4 21 IN UINTN Pages\r
48555339
FT
22 )\r
23{\r
1436aea4
MK
24 SD_PEIM_MEM_BLOCK *Block;\r
25 VOID *BufHost;\r
26 VOID *Mapping;\r
27 EFI_PHYSICAL_ADDRESS MappedAddr;\r
28 EFI_STATUS Status;\r
29 VOID *TempPtr;\r
48555339
FT
30\r
31 TempPtr = NULL;\r
32 Block = NULL;\r
33\r
1436aea4 34 Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_BLOCK), &TempPtr);\r
48555339
FT
35 if (EFI_ERROR (Status)) {\r
36 return NULL;\r
37 }\r
38\r
1436aea4 39 ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_BLOCK));\r
48555339
FT
40\r
41 //\r
42 // each bit in the bit array represents SD_PEIM_MEM_UNIT\r
43 // bytes of memory in the memory block.\r
44 //\r
45 ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
46\r
1436aea4
MK
47 Block = (SD_PEIM_MEM_BLOCK *)(UINTN)TempPtr;\r
48 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
49 Block->BitsLen = Block->BufLen / (SD_PEIM_MEM_UNIT * 8);\r
48555339
FT
50\r
51 Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);\r
52 if (EFI_ERROR (Status)) {\r
53 return NULL;\r
54 }\r
55\r
1436aea4 56 ZeroMem ((VOID *)(UINTN)TempPtr, Block->BitsLen);\r
48555339 57\r
1436aea4 58 Block->Bits = (UINT8 *)(UINTN)TempPtr;\r
48555339 59\r
77af8668 60 Status = IoMmuAllocateBuffer (\r
48555339 61 Pages,\r
77af8668
HW
62 &BufHost,\r
63 &MappedAddr,\r
64 &Mapping\r
48555339
FT
65 );\r
66 if (EFI_ERROR (Status)) {\r
67 return NULL;\r
68 }\r
69\r
1436aea4 70 ZeroMem ((VOID *)(UINTN)BufHost, EFI_PAGES_TO_SIZE (Pages));\r
48555339 71\r
1436aea4
MK
72 Block->BufHost = (UINT8 *)(UINTN)BufHost;\r
73 Block->Buf = (UINT8 *)(UINTN)MappedAddr;\r
77af8668
HW
74 Block->Mapping = Mapping;\r
75 Block->Next = NULL;\r
48555339
FT
76\r
77 return Block;\r
78}\r
79\r
80/**\r
81 Free the memory block from the memory pool.\r
82\r
83 @param Pool The memory pool to free the block from.\r
84 @param Block The memory block to free.\r
85\r
86**/\r
87VOID\r
88SdPeimFreeMemBlock (\r
1436aea4
MK
89 IN SD_PEIM_MEM_POOL *Pool,\r
90 IN SD_PEIM_MEM_BLOCK *Block\r
48555339
FT
91 )\r
92{\r
93 ASSERT ((Pool != NULL) && (Block != NULL));\r
77af8668
HW
94\r
95 IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);\r
48555339
FT
96}\r
97\r
98/**\r
99 Alloc some memory from the block.\r
100\r
101 @param Block The memory block to allocate memory from.\r
102 @param Units Number of memory units to allocate.\r
103\r
104 @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
105 the return value is NULL.\r
106\r
107**/\r
108VOID *\r
109SdPeimAllocMemFromBlock (\r
1436aea4
MK
110 IN SD_PEIM_MEM_BLOCK *Block,\r
111 IN UINTN Units\r
48555339
FT
112 )\r
113{\r
1436aea4
MK
114 UINTN Byte;\r
115 UINT8 Bit;\r
116 UINTN StartByte;\r
117 UINT8 StartBit;\r
118 UINTN Available;\r
119 UINTN Count;\r
48555339
FT
120\r
121 ASSERT ((Block != 0) && (Units != 0));\r
122\r
1436aea4
MK
123 StartByte = 0;\r
124 StartBit = 0;\r
125 Available = 0;\r
48555339
FT
126\r
127 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
128 //\r
129 // If current bit is zero, the corresponding memory unit is\r
130 // available, otherwise we need to restart our searching.\r
b854b075 131 // Available counts the consecutive number of zero bit.\r
48555339
FT
132 //\r
133 if (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
134 Available++;\r
135\r
136 if (Available >= Units) {\r
137 break;\r
138 }\r
139\r
140 SD_PEIM_NEXT_BIT (Byte, Bit);\r
48555339
FT
141 } else {\r
142 SD_PEIM_NEXT_BIT (Byte, Bit);\r
143\r
1436aea4
MK
144 Available = 0;\r
145 StartByte = Byte;\r
146 StartBit = Bit;\r
48555339
FT
147 }\r
148 }\r
149\r
150 if (Available < Units) {\r
151 return NULL;\r
152 }\r
153\r
154 //\r
155 // Mark the memory as allocated\r
156 //\r
1436aea4
MK
157 Byte = StartByte;\r
158 Bit = StartBit;\r
48555339
FT
159\r
160 for (Count = 0; Count < Units; Count++) {\r
161 ASSERT (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
162\r
1436aea4 163 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | (UINT8)SD_PEIM_MEM_BIT (Bit));\r
48555339
FT
164 SD_PEIM_NEXT_BIT (Byte, Bit);\r
165 }\r
166\r
167 return Block->Buf + (StartByte * 8 + StartBit) * SD_PEIM_MEM_UNIT;\r
168}\r
169\r
170/**\r
171 Insert the memory block to the pool's list of the blocks.\r
172\r
173 @param Head The head of the memory pool's block list.\r
174 @param Block The memory block to insert.\r
175\r
176**/\r
177VOID\r
178SdPeimInsertMemBlockToPool (\r
1436aea4
MK
179 IN SD_PEIM_MEM_BLOCK *Head,\r
180 IN SD_PEIM_MEM_BLOCK *Block\r
48555339
FT
181 )\r
182{\r
183 ASSERT ((Head != NULL) && (Block != NULL));\r
184 Block->Next = Head->Next;\r
185 Head->Next = Block;\r
186}\r
187\r
188/**\r
189 Is the memory block empty?\r
190\r
191 @param Block The memory block to check.\r
192\r
193 @retval TRUE The memory block is empty.\r
194 @retval FALSE The memory block isn't empty.\r
195\r
196**/\r
197BOOLEAN\r
198SdPeimIsMemBlockEmpty (\r
1436aea4 199 IN SD_PEIM_MEM_BLOCK *Block\r
48555339
FT
200 )\r
201{\r
1436aea4 202 UINTN Index;\r
48555339
FT
203\r
204 for (Index = 0; Index < Block->BitsLen; Index++) {\r
205 if (Block->Bits[Index] != 0) {\r
206 return FALSE;\r
207 }\r
208 }\r
209\r
210 return TRUE;\r
211}\r
212\r
48555339
FT
213/**\r
214 Initialize the memory management pool for the host controller.\r
215\r
216 @param Private The Sd Peim driver private data.\r
217\r
218 @retval EFI_SUCCESS The memory pool is initialized.\r
219 @retval Others Fail to init the memory pool.\r
220\r
221**/\r
222EFI_STATUS\r
223SdPeimInitMemPool (\r
224 IN SD_PEIM_HC_PRIVATE_DATA *Private\r
225 )\r
226{\r
1436aea4
MK
227 SD_PEIM_MEM_POOL *Pool;\r
228 EFI_STATUS Status;\r
229 VOID *TempPtr;\r
48555339
FT
230\r
231 TempPtr = NULL;\r
232 Pool = NULL;\r
233\r
234 Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_POOL), &TempPtr);\r
235 if (EFI_ERROR (Status)) {\r
236 return EFI_OUT_OF_RESOURCES;\r
237 }\r
238\r
1436aea4 239 ZeroMem ((VOID *)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_POOL));\r
48555339
FT
240\r
241 Pool = (SD_PEIM_MEM_POOL *)((UINTN)TempPtr);\r
242\r
243 Pool->Head = SdPeimAllocMemBlock (SD_PEIM_MEM_DEFAULT_PAGES);\r
244\r
245 if (Pool->Head == NULL) {\r
246 return EFI_OUT_OF_RESOURCES;\r
247 }\r
248\r
249 Private->Pool = Pool;\r
250 return EFI_SUCCESS;\r
251}\r
252\r
253/**\r
254 Release the memory management pool.\r
255\r
256 @param Pool The memory pool to free.\r
257\r
258 @retval EFI_DEVICE_ERROR Fail to free the memory pool.\r
259 @retval EFI_SUCCESS The memory pool is freed.\r
260\r
261**/\r
262EFI_STATUS\r
263SdPeimFreeMemPool (\r
1436aea4 264 IN SD_PEIM_MEM_POOL *Pool\r
48555339
FT
265 )\r
266{\r
1436aea4 267 SD_PEIM_MEM_BLOCK *Block;\r
48555339
FT
268\r
269 ASSERT (Pool->Head != NULL);\r
270\r
271 //\r
272 // Unlink all the memory blocks from the pool, then free them.\r
48555339
FT
273 //\r
274 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
275 SdPeimFreeMemBlock (Pool, Block);\r
276 }\r
277\r
278 SdPeimFreeMemBlock (Pool, Pool->Head);\r
279\r
280 return EFI_SUCCESS;\r
281}\r
282\r
283/**\r
284 Allocate some memory from the host controller's memory pool\r
285 which can be used to communicate with host controller.\r
286\r
287 @param Pool The host controller's memory pool.\r
288 @param Size Size of the memory to allocate.\r
289\r
290 @return The allocated memory or NULL.\r
291\r
292**/\r
293VOID *\r
294SdPeimAllocateMem (\r
1436aea4
MK
295 IN SD_PEIM_MEM_POOL *Pool,\r
296 IN UINTN Size\r
48555339
FT
297 )\r
298{\r
1436aea4
MK
299 SD_PEIM_MEM_BLOCK *Head;\r
300 SD_PEIM_MEM_BLOCK *Block;\r
301 SD_PEIM_MEM_BLOCK *NewBlock;\r
302 VOID *Mem;\r
303 UINTN AllocSize;\r
304 UINTN Pages;\r
48555339
FT
305\r
306 Mem = NULL;\r
307 AllocSize = SD_PEIM_MEM_ROUND (Size);\r
308 Head = Pool->Head;\r
309 ASSERT (Head != NULL);\r
310\r
311 //\r
312 // First check whether current memory blocks can satisfy the allocation.\r
313 //\r
314 for (Block = Head; Block != NULL; Block = Block->Next) {\r
315 Mem = SdPeimAllocMemFromBlock (Block, AllocSize / SD_PEIM_MEM_UNIT);\r
316\r
317 if (Mem != NULL) {\r
318 ZeroMem (Mem, Size);\r
319 break;\r
320 }\r
321 }\r
322\r
323 if (Mem != NULL) {\r
324 return Mem;\r
325 }\r
326\r
327 //\r
328 // Create a new memory block if there is not enough memory\r
329 // in the pool. If the allocation size is larger than the\r
330 // default page number, just allocate a large enough memory\r
331 // block. Otherwise allocate default pages.\r
332 //\r
333 if (AllocSize > EFI_PAGES_TO_SIZE (SD_PEIM_MEM_DEFAULT_PAGES)) {\r
334 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
335 } else {\r
336 Pages = SD_PEIM_MEM_DEFAULT_PAGES;\r
337 }\r
338\r
339 NewBlock = SdPeimAllocMemBlock (Pages);\r
340 if (NewBlock == NULL) {\r
341 return NULL;\r
342 }\r
343\r
344 //\r
345 // Add the new memory block to the pool, then allocate memory from it\r
346 //\r
347 SdPeimInsertMemBlockToPool (Head, NewBlock);\r
348 Mem = SdPeimAllocMemFromBlock (NewBlock, AllocSize / SD_PEIM_MEM_UNIT);\r
349\r
350 if (Mem != NULL) {\r
351 ZeroMem (Mem, Size);\r
352 }\r
353\r
354 return Mem;\r
355}\r
356\r
357/**\r
358 Free the allocated memory back to the memory pool.\r
359\r
360 @param Pool The memory pool of the host controller.\r
361 @param Mem The memory to free.\r
362 @param Size The size of the memory to free.\r
363\r
364**/\r
365VOID\r
366SdPeimFreeMem (\r
1436aea4
MK
367 IN SD_PEIM_MEM_POOL *Pool,\r
368 IN VOID *Mem,\r
369 IN UINTN Size\r
48555339
FT
370 )\r
371{\r
1436aea4
MK
372 SD_PEIM_MEM_BLOCK *Head;\r
373 SD_PEIM_MEM_BLOCK *Block;\r
374 UINT8 *ToFree;\r
375 UINTN AllocSize;\r
376 UINTN Byte;\r
377 UINTN Bit;\r
378 UINTN Count;\r
48555339
FT
379\r
380 Head = Pool->Head;\r
381 AllocSize = SD_PEIM_MEM_ROUND (Size);\r
1436aea4 382 ToFree = (UINT8 *)Mem;\r
48555339
FT
383\r
384 for (Block = Head; Block != NULL; Block = Block->Next) {\r
385 //\r
386 // scan the memory block list for the memory block that\r
387 // completely contains the memory to free.\r
388 //\r
389 if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
390 //\r
391 // compute the start byte and bit in the bit array\r
392 //\r
1436aea4
MK
393 Byte = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) / 8;\r
394 Bit = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) % 8;\r
48555339
FT
395\r
396 //\r
2048c585 397 // reset associated bits in bit array\r
48555339
FT
398 //\r
399 for (Count = 0; Count < (AllocSize / SD_PEIM_MEM_UNIT); Count++) {\r
400 ASSERT (SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
401\r
1436aea4 402 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ SD_PEIM_MEM_BIT (Bit));\r
48555339
FT
403 SD_PEIM_NEXT_BIT (Byte, Bit);\r
404 }\r
405\r
406 break;\r
407 }\r
408 }\r
409\r
410 //\r
411 // If Block == NULL, it means that the current memory isn't\r
412 // in the host controller's pool. This is critical because\r
413 // the caller has passed in a wrong memory point\r
414 //\r
415 ASSERT (Block != NULL);\r
416\r
417 //\r
418 // Release the current memory block if it is empty and not the head\r
419 //\r
420 if ((Block != Head) && SdPeimIsMemBlockEmpty (Block)) {\r
421 SdPeimFreeMemBlock (Pool, Block);\r
422 }\r
423\r
1436aea4 424 return;\r
48555339 425}\r