One more header fix
[mirror_edk2.git] / ArmPkg / Library / UncachedMemoryAllocationLib / UncachedMemoryAllocationLib.c
CommitLineData
2ef2b01e
A
1/** @file\r
2\r
3 Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
4 \r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this 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 <Library/BaseMemoryLib.h>\r
16#include <Library/DebugLib.h>\r
17#include <Library/UefiBootServicesTableLib.h>\r
18#include <Library/UncachedMemoryAllocationLib.h>\r
19#include <Library/PcdLib.h>\r
20#include <Library/ArmLib.h>\r
21#include <Protocol/Cpu.h>\r
22\r
23EFI_PHYSICAL_ADDRESS\r
24ConvertToPhysicalAddress (\r
25 IN VOID *VirtualAddress\r
26 )\r
27{\r
28 UINTN UncachedMemoryMask = (UINTN)PcdGet64(PcdArmUncachedMemoryMask);\r
29 UINTN PhysicalAddress;\r
30 \r
31 PhysicalAddress = (UINTN)VirtualAddress & ~UncachedMemoryMask;\r
32 \r
33 return (EFI_PHYSICAL_ADDRESS)PhysicalAddress;\r
34}\r
35\r
36VOID *\r
37ConvertToCachedAddress (\r
38 IN VOID *Address\r
39 )\r
40{\r
41 return (VOID *)(UINTN)ConvertToPhysicalAddress(Address);\r
42}\r
43\r
44VOID *\r
45ConvertToUncachedAddress (\r
46 IN VOID *Address\r
47 )\r
48{\r
49 UINTN UncachedMemoryMask = (UINTN)PcdGet64(PcdArmUncachedMemoryMask);\r
50 UINTN UncachedAddress;\r
51 \r
52 UncachedAddress = (UINTN)Address | UncachedMemoryMask;\r
53 \r
54 return (VOID *)UncachedAddress;\r
55}\r
56\r
57VOID\r
58FlushCache (\r
59 IN EFI_PHYSICAL_ADDRESS Address,\r
60 IN UINTN Size\r
61 )\r
62{\r
63 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
64 EFI_STATUS Status;\r
65 \r
66 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
67 ASSERT_EFI_ERROR(Status);\r
68 \r
69 Status = Cpu->FlushDataCache(Cpu, Address, Size, EfiCpuFlushTypeWriteBackInvalidate);\r
70 ASSERT_EFI_ERROR(Status);\r
71}\r
72\r
73VOID *\r
74UncachedInternalAllocatePages (\r
75 IN EFI_MEMORY_TYPE MemoryType, \r
76 IN UINTN Pages\r
77 )\r
78{\r
79 EFI_STATUS Status;\r
80 EFI_PHYSICAL_ADDRESS Memory; \r
81\r
82 if (Pages == 0) {\r
83 return NULL;\r
84 }\r
85\r
86 Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);\r
87 if (EFI_ERROR (Status)) {\r
88 Memory = 0;\r
89 }\r
90 \r
91 if (Memory != 0) {\r
92 FlushCache(Memory, EFI_PAGES_TO_SIZE(Pages));\r
93 Memory = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertToUncachedAddress((VOID *)(UINTN)Memory);\r
94 }\r
95 \r
96 return (VOID *) (UINTN) Memory;\r
97}\r
98\r
99VOID *\r
100EFIAPI\r
101UncachedAllocatePages (\r
102 IN UINTN Pages\r
103 )\r
104{\r
105 return UncachedInternalAllocatePages (EfiBootServicesData, Pages);\r
106}\r
107\r
108VOID *\r
109EFIAPI\r
110UncachedAllocateRuntimePages (\r
111 IN UINTN Pages\r
112 )\r
113{\r
114 return UncachedInternalAllocatePages (EfiRuntimeServicesData, Pages);\r
115}\r
116\r
117VOID *\r
118EFIAPI\r
119UncachedAllocateReservedPages (\r
120 IN UINTN Pages\r
121 )\r
122{\r
123 return UncachedInternalAllocatePages (EfiReservedMemoryType, Pages);\r
124}\r
125\r
126VOID\r
127EFIAPI\r
128UncachedFreePages (\r
129 IN VOID *Buffer,\r
130 IN UINTN Pages\r
131 )\r
132{\r
133 EFI_STATUS Status;\r
134\r
135 ASSERT (Pages != 0);\r
136 \r
137 Buffer = ConvertToCachedAddress(Buffer);\r
138 \r
139 Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
140 ASSERT_EFI_ERROR (Status);\r
141}\r
142\r
143VOID *\r
144UncachedInternalAllocateAlignedPages (\r
145 IN EFI_MEMORY_TYPE MemoryType, \r
146 IN UINTN Pages,\r
147 IN UINTN Alignment\r
148 )\r
149{\r
150 EFI_STATUS Status;\r
151 EFI_PHYSICAL_ADDRESS Memory;\r
152 UINTN AlignedMemory;\r
153 UINTN AlignmentMask;\r
154 UINTN UnalignedPages;\r
155 UINTN RealPages;\r
156\r
157 //\r
158 // Alignment must be a power of two or zero.\r
159 //\r
160 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
161 \r
162 if (Pages == 0) {\r
163 return NULL;\r
164 }\r
165 if (Alignment > EFI_PAGE_SIZE) {\r
166 //\r
167 // Caculate the total number of pages since alignment is larger than page size.\r
168 //\r
169 AlignmentMask = Alignment - 1;\r
170 RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
171 //\r
172 // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
173 //\r
174 ASSERT (RealPages > Pages);\r
175 \r
176 Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory);\r
177 if (EFI_ERROR (Status)) {\r
178 return NULL;\r
179 }\r
180 AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
181 UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
182 if (UnalignedPages > 0) {\r
183 //\r
184 // Free first unaligned page(s).\r
185 //\r
186 Status = gBS->FreePages (Memory, UnalignedPages);\r
187 ASSERT_EFI_ERROR (Status);\r
188 }\r
189 Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
190 UnalignedPages = RealPages - Pages - UnalignedPages;\r
191 if (UnalignedPages > 0) {\r
192 //\r
193 // Free last unaligned page(s).\r
194 //\r
195 Status = gBS->FreePages (Memory, UnalignedPages);\r
196 ASSERT_EFI_ERROR (Status);\r
197 }\r
198 } else {\r
199 //\r
200 // Do not over-allocate pages in this case.\r
201 //\r
202 Status = gBS->AllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory);\r
203 if (EFI_ERROR (Status)) {\r
204 return NULL;\r
205 }\r
206 AlignedMemory = (UINTN) Memory;\r
207 }\r
208 \r
209 if (AlignedMemory != 0) {\r
210 FlushCache(AlignedMemory, EFI_PAGES_TO_SIZE(Pages));\r
211 AlignedMemory = (UINTN)ConvertToUncachedAddress((VOID *)AlignedMemory);\r
212 }\r
213 \r
214 return (VOID *) AlignedMemory;\r
215}\r
216\r
217VOID *\r
218EFIAPI\r
219UncachedAllocateAlignedPages (\r
220 IN UINTN Pages,\r
221 IN UINTN Alignment\r
222 )\r
223{\r
224 return UncachedInternalAllocateAlignedPages (EfiBootServicesData, Pages, Alignment);\r
225}\r
226\r
227VOID *\r
228EFIAPI\r
229UncachedAllocateAlignedRuntimePages (\r
230 IN UINTN Pages,\r
231 IN UINTN Alignment\r
232 )\r
233{\r
234 return UncachedInternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment);\r
235}\r
236\r
237VOID *\r
238EFIAPI\r
239UncachedAllocateAlignedReservedPages (\r
240 IN UINTN Pages,\r
241 IN UINTN Alignment\r
242 )\r
243{\r
244 return UncachedInternalAllocateAlignedPages (EfiReservedMemoryType, Pages, Alignment);\r
245}\r
246\r
247VOID\r
248EFIAPI\r
249UncachedFreeAlignedPages (\r
250 IN VOID *Buffer,\r
251 IN UINTN Pages\r
252 )\r
253{\r
254 EFI_STATUS Status;\r
255\r
256 ASSERT (Pages != 0);\r
257 \r
258 Buffer = ConvertToCachedAddress(Buffer);\r
259 \r
260 Status = gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages);\r
261 ASSERT_EFI_ERROR (Status);\r
262}\r
263\r
264VOID *\r
265UncachedInternalAllocateAlignedPool (\r
266 IN EFI_MEMORY_TYPE PoolType,\r
267 IN UINTN AllocationSize,\r
268 IN UINTN Alignment\r
269 )\r
270{\r
271 VOID *RawAddress;\r
272 UINTN AlignedAddress;\r
273 UINTN AlignmentMask;\r
274 UINTN OverAllocationSize;\r
275 UINTN RealAllocationSize;\r
276 VOID **FreePointer;\r
277 UINTN DataCacheLineLength;\r
278 EFI_STATUS Status;\r
279\r
280 //\r
281 // Alignment must be a power of two or zero.\r
282 //\r
283 ASSERT ((Alignment & (Alignment - 1)) == 0);\r
284\r
285 DataCacheLineLength = ArmDataCacheLineLength();\r
286 \r
287 // Alignment must be at least cache-line aligned\r
288 if (Alignment < DataCacheLineLength) {\r
289 Alignment = DataCacheLineLength;\r
290 }\r
291 \r
292 if (Alignment == 0) {\r
293 AlignmentMask = Alignment;\r
294 } else {\r
295 AlignmentMask = Alignment - 1;\r
296 }\r
297 \r
298 //\r
299 // Calculate the extra memory size, over-allocate memory pool and get the aligned memory address. \r
300 //\r
301 OverAllocationSize = sizeof (RawAddress) + AlignmentMask;\r
302 RealAllocationSize = AllocationSize + OverAllocationSize;\r
303 //\r
304 // Make sure that AllocationSize plus OverAllocationSize does not overflow. \r
305 //\r
306 ASSERT (RealAllocationSize > AllocationSize); \r
307\r
308 Status = gBS->AllocatePool (PoolType, RealAllocationSize, &RawAddress);\r
309 if (EFI_ERROR (Status)) {\r
310 return NULL;\r
311 }\r
312\r
313 AlignedAddress = ((UINTN) RawAddress + OverAllocationSize) & ~AlignmentMask;\r
314 //\r
315 // Save the original memory address just before the aligned address.\r
316 //\r
317 FreePointer = (VOID **)(AlignedAddress - sizeof (RawAddress));\r
318 *FreePointer = RawAddress;\r
319\r
320 if (AlignedAddress != 0) {\r
321 FlushCache(AlignedAddress, AllocationSize);\r
322 AlignedAddress = (UINTN)ConvertToUncachedAddress((VOID *)AlignedAddress);\r
323 }\r
324\r
325 return (VOID *) AlignedAddress;\r
326}\r
327\r
328VOID *\r
329EFIAPI\r
330UncachedAllocateAlignedPool (\r
331 IN UINTN AllocationSize,\r
332 IN UINTN Alignment\r
333 )\r
334{\r
335 return UncachedInternalAllocateAlignedPool (EfiBootServicesData, AllocationSize, Alignment);\r
336}\r
337\r
338VOID *\r
339EFIAPI\r
340UncachedAllocateAlignedRuntimePool (\r
341 IN UINTN AllocationSize,\r
342 IN UINTN Alignment\r
343 )\r
344{\r
345 return UncachedInternalAllocateAlignedPool (EfiRuntimeServicesData, AllocationSize, Alignment);\r
346}\r
347\r
348VOID *\r
349EFIAPI\r
350UncachedAllocateAlignedReservedPool (\r
351 IN UINTN AllocationSize,\r
352 IN UINTN Alignment\r
353 )\r
354{\r
355 return UncachedInternalAllocateAlignedPool (EfiReservedMemoryType, AllocationSize, Alignment);\r
356}\r
357\r
358VOID *\r
359UncachedInternalAllocateAlignedZeroPool (\r
360 IN EFI_MEMORY_TYPE PoolType,\r
361 IN UINTN AllocationSize,\r
362 IN UINTN Alignment\r
363 )\r
364{\r
365 VOID *Memory;\r
366 Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
367 if (Memory != NULL) {\r
368 Memory = ZeroMem (Memory, AllocationSize);\r
369 }\r
370 return Memory;\r
371}\r
372\r
373VOID *\r
374EFIAPI\r
375UncachedAllocateAlignedZeroPool (\r
376 IN UINTN AllocationSize,\r
377 IN UINTN Alignment\r
378 )\r
379{\r
380 return UncachedInternalAllocateAlignedZeroPool (EfiBootServicesData, AllocationSize, Alignment);\r
381}\r
382\r
383VOID *\r
384EFIAPI\r
385UncachedAllocateAlignedRuntimeZeroPool (\r
386 IN UINTN AllocationSize,\r
387 IN UINTN Alignment\r
388 )\r
389{\r
390 return UncachedInternalAllocateAlignedZeroPool (EfiRuntimeServicesData, AllocationSize, Alignment);\r
391}\r
392\r
393VOID *\r
394EFIAPI\r
395UncachedAllocateAlignedReservedZeroPool (\r
396 IN UINTN AllocationSize,\r
397 IN UINTN Alignment\r
398 )\r
399{\r
400 return UncachedInternalAllocateAlignedZeroPool (EfiReservedMemoryType, AllocationSize, Alignment);\r
401}\r
402\r
403VOID *\r
404UncachedInternalAllocateAlignedCopyPool (\r
405 IN EFI_MEMORY_TYPE PoolType,\r
406 IN UINTN AllocationSize,\r
407 IN CONST VOID *Buffer,\r
408 IN UINTN Alignment\r
409 )\r
410{\r
411 VOID *Memory;\r
412 \r
413 ASSERT (Buffer != NULL);\r
414 ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));\r
415\r
416 Memory = UncachedInternalAllocateAlignedPool (PoolType, AllocationSize, Alignment);\r
417 if (Memory != NULL) {\r
418 Memory = CopyMem (Memory, Buffer, AllocationSize);\r
419 }\r
420 return Memory;\r
421}\r
422\r
423VOID *\r
424EFIAPI\r
425UncachedAllocateAlignedCopyPool (\r
426 IN UINTN AllocationSize,\r
427 IN CONST VOID *Buffer,\r
428 IN UINTN Alignment\r
429 )\r
430{\r
431 return UncachedInternalAllocateAlignedCopyPool (EfiBootServicesData, AllocationSize, Buffer, Alignment);\r
432}\r
433\r
434VOID *\r
435EFIAPI\r
436UncachedAllocateAlignedRuntimeCopyPool (\r
437 IN UINTN AllocationSize,\r
438 IN CONST VOID *Buffer,\r
439 IN UINTN Alignment\r
440 )\r
441{\r
442 return UncachedInternalAllocateAlignedCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer, Alignment);\r
443}\r
444\r
445VOID *\r
446EFIAPI\r
447UncachedAllocateAlignedReservedCopyPool (\r
448 IN UINTN AllocationSize,\r
449 IN CONST VOID *Buffer,\r
450 IN UINTN Alignment\r
451 )\r
452{\r
453 return UncachedInternalAllocateAlignedCopyPool (EfiReservedMemoryType, AllocationSize, Buffer, Alignment);\r
454}\r
455\r
456VOID\r
457EFIAPI\r
458UncachedFreeAlignedPool (\r
459 IN VOID *Buffer\r
460 )\r
461{\r
462 VOID *RawAddress;\r
463 VOID **FreePointer;\r
464 EFI_STATUS Status;\r
465\r
466 Buffer = ConvertToCachedAddress(Buffer);\r
467 \r
468 //\r
469 // Get the pre-saved original address in the over-allocate pool.\r
470 //\r
471 FreePointer = (VOID **)((UINTN) Buffer - sizeof (RawAddress));\r
472 RawAddress = *FreePointer;\r
473\r
474 Status = gBS->FreePool (RawAddress);\r
475 ASSERT_EFI_ERROR (Status);\r
476}\r
477\r
478VOID *\r
479UncachedInternalAllocatePool (\r
480 IN EFI_MEMORY_TYPE MemoryType, \r
481 IN UINTN AllocationSize\r
482 )\r
483{\r
484 UINTN CacheLineLength = ArmDataCacheLineLength();\r
485 return UncachedInternalAllocateAlignedPool(MemoryType, AllocationSize, CacheLineLength);\r
486}\r
487\r
488VOID *\r
489EFIAPI\r
490UncachedAllocatePool (\r
491 IN UINTN AllocationSize\r
492 )\r
493{\r
494 return UncachedInternalAllocatePool (EfiBootServicesData, AllocationSize);\r
495}\r
496\r
497VOID *\r
498EFIAPI\r
499UncachedAllocateRuntimePool (\r
500 IN UINTN AllocationSize\r
501 )\r
502{\r
503 return UncachedInternalAllocatePool (EfiRuntimeServicesData, AllocationSize);\r
504}\r
505\r
506VOID *\r
507EFIAPI\r
508UncachedAllocateReservedPool (\r
509 IN UINTN AllocationSize\r
510 )\r
511{\r
512 return UncachedInternalAllocatePool (EfiReservedMemoryType, AllocationSize);\r
513}\r
514\r
515VOID *\r
516UncachedInternalAllocateZeroPool (\r
517 IN EFI_MEMORY_TYPE PoolType, \r
518 IN UINTN AllocationSize\r
519 ) \r
520{\r
521 VOID *Memory;\r
522\r
523 Memory = UncachedInternalAllocatePool (PoolType, AllocationSize);\r
524 if (Memory != NULL) {\r
525 Memory = ZeroMem (Memory, AllocationSize);\r
526 }\r
527 return Memory;\r
528}\r
529\r
530VOID *\r
531EFIAPI\r
532UncachedAllocateZeroPool (\r
533 IN UINTN AllocationSize\r
534 )\r
535{\r
536 return UncachedInternalAllocateZeroPool (EfiBootServicesData, AllocationSize);\r
537}\r
538\r
539VOID *\r
540EFIAPI\r
541UncachedAllocateRuntimeZeroPool (\r
542 IN UINTN AllocationSize\r
543 )\r
544{\r
545 return UncachedInternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize);\r
546}\r
547\r
548VOID *\r
549EFIAPI\r
550UncachedAllocateReservedZeroPool (\r
551 IN UINTN AllocationSize\r
552 )\r
553{\r
554 return UncachedInternalAllocateZeroPool (EfiReservedMemoryType, AllocationSize);\r
555}\r
556\r
557VOID *\r
558UncachedInternalAllocateCopyPool (\r
559 IN EFI_MEMORY_TYPE PoolType, \r
560 IN UINTN AllocationSize,\r
561 IN CONST VOID *Buffer\r
562 ) \r
563{\r
564 VOID *Memory;\r
565\r
566 ASSERT (Buffer != NULL);\r
567 ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1));\r
568\r
569 Memory = UncachedInternalAllocatePool (PoolType, AllocationSize);\r
570 if (Memory != NULL) {\r
571 Memory = CopyMem (Memory, Buffer, AllocationSize);\r
572 }\r
573 return Memory;\r
574} \r
575\r
576VOID *\r
577EFIAPI\r
578UncachedAllocateCopyPool (\r
579 IN UINTN AllocationSize,\r
580 IN CONST VOID *Buffer\r
581 )\r
582{\r
583 return UncachedInternalAllocateCopyPool (EfiBootServicesData, AllocationSize, Buffer);\r
584}\r
585\r
586VOID *\r
587EFIAPI\r
588UncachedAllocateRuntimeCopyPool (\r
589 IN UINTN AllocationSize,\r
590 IN CONST VOID *Buffer\r
591 )\r
592{\r
593 return UncachedInternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);\r
594}\r
595\r
596VOID *\r
597EFIAPI\r
598UncachedAllocateReservedCopyPool (\r
599 IN UINTN AllocationSize,\r
600 IN CONST VOID *Buffer\r
601 )\r
602{\r
603 return UncachedInternalAllocateCopyPool (EfiReservedMemoryType, AllocationSize, Buffer);\r
604}\r
605\r
606VOID\r
607EFIAPI\r
608UncachedFreePool (\r
609 IN VOID *Buffer\r
610 )\r
611{\r
612 UncachedFreeAlignedPool(Buffer);\r
613}\r
614\r
615VOID\r
616EFIAPI\r
617UncachedSafeFreePool (\r
618 IN VOID *Buffer\r
619 )\r
620{\r
621 if (Buffer != NULL) {\r
622 UncachedFreePool (Buffer);\r
623 Buffer = NULL;\r
624 }\r
625}\r
626\r