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