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