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